Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): CLI refactor #102

Merged
merged 8 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
708 changes: 390 additions & 318 deletions Cargo.lock

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions crates/svm-rs/src/bin/svm-bin/install.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::print;
use clap::Parser;
use dialoguer::Input;
use semver::Version;

#[derive(Debug, Clone, Parser)]
pub struct InstallArgs {
#[clap(long, short)]
pub versions: Vec<String>,
}

impl InstallArgs {
pub async fn run(self) -> anyhow::Result<()> {
let all_versions = svm_lib::all_versions().await?;

for version in self.versions {
let installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;
let version = Version::parse(&version)?;

if installed_versions.contains(&version) {
println!("Solc {version} is already installed");
let input: String = Input::new()
.with_prompt("Would you like to set it as the global version?")
.with_initial_text("Y")
.default("N".into())
.interact_text()?;
if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
}
} else if all_versions.contains(&version) {
let spinner = print::installing_version(&version);
svm_lib::install(&version).await?;
spinner.finish_with_message(format!("Downloaded Solc: {version}"));
if current_version.is_none() {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
}
} else {
print::unsupported_version(&version);
}
}

Ok(())
}
}
29 changes: 29 additions & 0 deletions crates/svm-rs/src/bin/svm-bin/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::collections::HashSet;

use crate::print;
use clap::Parser;
use semver::Version;

#[derive(Debug, Parser)]
pub struct ListArgs;

impl ListArgs {
pub async fn run(self) -> anyhow::Result<()> {
let all_versions = svm_lib::all_versions().await?;
let installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;

let a: HashSet<Version> = all_versions.iter().cloned().collect();
let b: HashSet<Version> = installed_versions.iter().cloned().collect();
let c = &a - &b;

let mut available_versions = c.iter().cloned().collect::<Vec<Version>>();
available_versions.sort();

print::current_version(current_version);
print::installed_versions(installed_versions);
print::available_versions(available_versions);

Ok(())
}
}
156 changes: 20 additions & 136 deletions crates/svm-rs/src/bin/svm-bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
use clap::Parser;
use dialoguer::Input;
use semver::Version;
//! Main svm-rs binary entry point.

use std::collections::HashSet;
mod install;
mod list;
pub mod print;
mod remove;
mod usev;
mod utils;

mod print;
use clap::Parser;
use install::InstallArgs;
use list::ListArgs;
use remove::RemoveArgs;
use usev::UseArgs;

#[derive(Debug, Parser)]
#[clap(name = "solc-vm", about = "Solc version manager")]
enum SolcVm {
#[clap(about = "List all versions of Solc")]
List,
List(ListArgs),
#[clap(about = "Install Solc versions")]
Install { versions: Vec<String> },
Install(InstallArgs),
#[clap(about = "Use a Solc version")]
Use { version: String },
Use(UseArgs), // { version: String },
#[clap(about = "Remove a Solc version")]
Remove { version: String },
Remove(RemoveArgs), // { version: String },
}

#[tokio::main]
Expand All @@ -26,133 +33,10 @@ async fn main() -> anyhow::Result<()> {
svm_lib::setup_data_dir()?;

match opt {
SolcVm::List => {
handle_list().await?;
}
SolcVm::Install { versions } => {
for v in versions {
handle_install(Version::parse(&v)?).await?;
}
}
SolcVm::Use { version } => {
handle_use(Version::parse(&version)?).await?;
}
SolcVm::Remove { version } => match version.as_str() {
"ALL" | "all" => {
for v in svm_lib::installed_versions().unwrap_or_default() {
svm_lib::remove_version(&v)?;
}
svm_lib::unset_global_version()?;
}
_ => handle_remove(Version::parse(&version)?)?,
},
}

Ok(())
}

async fn handle_list() -> anyhow::Result<()> {
let all_versions = svm_lib::all_versions().await?;
let installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;

let a: HashSet<Version> = all_versions.iter().cloned().collect();
let b: HashSet<Version> = installed_versions.iter().cloned().collect();
let c = &a - &b;

let mut available_versions = c.iter().cloned().collect::<Vec<Version>>();
available_versions.sort();

print::current_version(current_version);
print::installed_versions(installed_versions);
print::available_versions(available_versions);

Ok(())
}

async fn handle_install(version: Version) -> anyhow::Result<()> {
let all_versions = svm_lib::all_versions().await?;
let installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;

if installed_versions.contains(&version) {
println!("Solc {version} is already installed");
let input: String = Input::new()
.with_prompt("Would you like to set it as the global version?")
.with_initial_text("Y")
.default("N".into())
.interact_text()?;
if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
}
} else if all_versions.contains(&version) {
let spinner = print::installing_version(&version);
svm_lib::install(&version).await?;
spinner.finish_with_message(format!("Downloaded Solc: {version}"));
if current_version.is_none() {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
}
} else {
print::unsupported_version(&version);
}

Ok(())
}

async fn handle_use(version: Version) -> anyhow::Result<()> {
let all_versions = svm_lib::all_versions().await?;
let installed_versions = svm_lib::installed_versions().unwrap_or_default();

if installed_versions.contains(&version) {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
} else if all_versions.contains(&version) {
println!("Solc {version} is not installed");
let input: String = Input::new()
.with_prompt("Would you like to install it?")
.with_initial_text("Y")
.default("N".into())
.interact_text()?;
if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") {
handle_install(version).await?;
}
} else {
print::unsupported_version(&version);
}

Ok(())
}

fn handle_remove(version: Version) -> anyhow::Result<()> {
let mut installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;

if installed_versions.contains(&version) {
let input: String = Input::new()
.with_prompt("Are you sure?")
.with_initial_text("Y")
.default("N".into())
.interact_text()?;
if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") {
svm_lib::remove_version(&version)?;
if let Some(v) = current_version {
if version == v {
if let Some(i) = installed_versions.iter().position(|x| *x == v) {
installed_versions.remove(i);
if let Some(new_version) = installed_versions.pop() {
svm_lib::use_version(&new_version)?;
print::set_global_version(&new_version);
} else {
svm_lib::unset_global_version()?;
}
}
}
}
}
} else {
print::version_not_found(&version);
SolcVm::List(cmd) => utils::block_on(cmd.run())?,
SolcVm::Install(cmd) => utils::block_on(cmd.run())?,
SolcVm::Use(cmd) => utils::block_on(cmd.run())?,
SolcVm::Remove(cmd) => utils::block_on(cmd.run())?,
}

Ok(())
Expand Down
55 changes: 55 additions & 0 deletions crates/svm-rs/src/bin/svm-bin/remove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::print;
use clap::Parser;
use dialoguer::Input;
use semver::Version;

#[derive(Debug, Clone, Parser)]
pub struct RemoveArgs {
#[clap(long, short)]
// TODO: Serde helper for parsing Version(?)
pub version: String,
}

impl RemoveArgs {
pub async fn run(self) -> anyhow::Result<()> {
if self.version.to_ascii_lowercase() == "all" {
for v in svm_lib::installed_versions().unwrap_or_default() {
svm_lib::remove_version(&v)?;
}
svm_lib::unset_global_version()?;
return Ok(());
} else {
let mut installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;
let version = Version::parse(&self.version)?;

if installed_versions.contains(&version) {
let input: String = Input::new()
.with_prompt("Are you sure?")
.with_initial_text("Y")
.default("N".into())
.interact_text()?;
if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") {
svm_lib::remove_version(&version)?;
if let Some(v) = current_version {
if version == v {
if let Some(i) = installed_versions.iter().position(|x| *x == v) {
installed_versions.remove(i);
if let Some(new_version) = installed_versions.pop() {
svm_lib::use_version(&new_version)?;
print::set_global_version(&new_version);
} else {
svm_lib::unset_global_version()?;
}
}
}
}
}
} else {
print::version_not_found(&version);
}
}

Ok(())
}
}
44 changes: 44 additions & 0 deletions crates/svm-rs/src/bin/svm-bin/usev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::print;
use clap::Parser;
use dialoguer::Input;
use semver::Version;

#[derive(Debug, Clone, Parser)]
pub struct UseArgs {
#[clap(long, short)]
pub version: String,
}

impl UseArgs {
pub async fn run(self) -> anyhow::Result<()> {
let version = Version::parse(&self.version)?;
let all_versions = svm_lib::all_versions().await?;
let installed_versions = svm_lib::installed_versions().unwrap_or_default();
let current_version = svm_lib::current_version()?;

if installed_versions.contains(&version) {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
} else if all_versions.contains(&version) {
println!("Solc {version} is not installed");
let input: String = Input::new()
.with_prompt("Would you like to install it?")
.with_initial_text("Y")
.default("N".into())
.interact_text()?;
if matches!(input.as_str(), "y" | "Y" | "yes" | "Yes") {
let spinner = print::installing_version(&version);
svm_lib::install(&version).await?;
spinner.finish_with_message(format!("Downloaded Solc: {version}"));
if current_version.is_none() {
svm_lib::use_version(&version)?;
print::set_global_version(&version);
}
}
} else {
print::unsupported_version(&version);
}

Ok(())
}
}
8 changes: 8 additions & 0 deletions crates/svm-rs/src/bin/svm-bin/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use std::future::Future;

/// Runs the `future` in a new [`tokio::runtime::Runtime`]
#[allow(unused)]
pub fn block_on<F: Future>(future: F) -> F::Output {
let rt = tokio::runtime::Runtime::new().expect("could not start tokio rt");
rt.block_on(future)
}
Loading
Loading