From 3a4a1cfa89bd43c822ea2ac04e53aae8b178326e Mon Sep 17 00:00:00 2001 From: Guille Date: Tue, 30 Jul 2024 14:03:42 +0200 Subject: [PATCH] feat: Automatically exec legacy JS CLI commands for full backward compatibility (#366) This PR tries to automatically execute the CLI commands that are suggested after somebody tries to run a JS commands. --- src/js_command_match/contract/call.rs | 2 +- src/js_command_match/contract/view.rs | 10 ++-- src/js_command_match/deprecated.rs | 30 ++++++++++++ src/js_command_match/mod.rs | 40 ++++++++-------- src/js_command_match/validators.rs | 12 ----- src/main.rs | 66 ++++++++++----------------- 6 files changed, 78 insertions(+), 82 deletions(-) create mode 100644 src/js_command_match/deprecated.rs delete mode 100644 src/js_command_match/validators.rs diff --git a/src/js_command_match/contract/call.rs b/src/js_command_match/contract/call.rs index 24598f97..98d1845c 100644 --- a/src/js_command_match/contract/call.rs +++ b/src/js_command_match/contract/call.rs @@ -9,7 +9,7 @@ use crate::js_command_match::constants::{ pub struct CallArgs { contract_name: String, method_name: String, - #[clap(default_value = "")] + #[clap(default_value = "{}")] args: String, #[clap(long, aliases = USE_ACCOUNT_ALIASES)] use_account: String, diff --git a/src/js_command_match/contract/view.rs b/src/js_command_match/contract/view.rs index a9733db8..045da08a 100644 --- a/src/js_command_match/contract/view.rs +++ b/src/js_command_match/contract/view.rs @@ -5,7 +5,7 @@ use crate::js_command_match::constants::NETWORK_ID_ALIASES; pub struct ViewArgs { contract_name: String, method_name: String, - #[clap(default_value = "")] + #[clap(default_value = "{}")] args: String, #[clap(long, aliases = NETWORK_ID_ALIASES)] network_id: Option, @@ -21,7 +21,7 @@ impl ViewArgs { "as-read-only".to_string(), self.contract_name.to_owned(), self.method_name.to_owned(), - "text-args".to_string(), + "json-args".to_string(), self.args.to_owned(), "network-config".to_string(), network_id, @@ -45,15 +45,15 @@ mod tests { for (input, expected_output) in [ ( format!("near view counter.near-examples.testnet get '{args}'"), - format!("contract call-function as-read-only counter.near-examples.testnet get text-args '{args}' network-config testnet now") + format!("contract call-function as-read-only counter.near-examples.testnet get json-args '{args}' network-config testnet now") ), ( format!("near view counter.near-examples.testnet get '{args}' --{} testnet", NETWORK_ID_ALIASES[0]), - format!("contract call-function as-read-only counter.near-examples.testnet get text-args '{args}' network-config testnet now") + format!("contract call-function as-read-only counter.near-examples.testnet get json-args '{args}' network-config testnet now") ), ( format!("near view counter.near-examples.testnet get '{args}' --{} mainnet", NETWORK_ID_ALIASES[1]), - format!("contract call-function as-read-only counter.near-examples.testnet get text-args '{args}' network-config mainnet now") + format!("contract call-function as-read-only counter.near-examples.testnet get json-args '{args}' network-config mainnet now") ), ] { let input_cmd = shell_words::split(&input).expect("Input command must be a valid shell command"); diff --git a/src/js_command_match/deprecated.rs b/src/js_command_match/deprecated.rs new file mode 100644 index 00000000..73f76b75 --- /dev/null +++ b/src/js_command_match/deprecated.rs @@ -0,0 +1,30 @@ +use color_eyre::owo_colors::OwoColorize; + +#[derive(Debug, Clone, clap::Parser)] +/// This is a legacy `validators` command. Once you run it with the specified arguments, new syntax command will be suggested. +pub struct ValidatorsArgs { + #[clap(allow_hyphen_values = true, num_args = 0..)] + _unknown_args: Vec, +} + +#[derive(Debug, Clone, clap::Parser)] +pub struct StakeArgs { + #[clap(allow_hyphen_values = true, num_args = 0..)] + _unknown_args: Vec, +} + +const DEPRECATED: &str = "The command you tried to run has been moved into its own CLI extension called near-validator.\nPlease, follow the installation instructions here: https://github.com/near-cli-rs/near-validator-cli-rs/blob/master/README.md"; + +impl ValidatorsArgs { + pub fn to_cli_args(&self, _network_config: String) -> Vec { + eprintln!("\n{}\n", DEPRECATED.to_string().yellow()); + vec!["near-validator".to_string()] + } +} + +impl StakeArgs { + pub fn to_cli_args(&self, _network_config: String) -> Vec { + eprintln!("\n{}\n", DEPRECATED.to_string().yellow()); + vec!["near-validator".to_string()] + } +} diff --git a/src/js_command_match/mod.rs b/src/js_command_match/mod.rs index 528fa00b..186313da 100644 --- a/src/js_command_match/mod.rs +++ b/src/js_command_match/mod.rs @@ -2,9 +2,9 @@ mod constants; mod account; mod contract; +mod deprecated; mod keys; mod transactions; -mod validators; #[derive(Debug, Clone, clap::Parser)] /// Legacy CLI commands are only supported at best-effort @@ -32,39 +32,37 @@ pub enum JsCmd { Send(self::transactions::send::SendArgs), TxStatus(self::transactions::status::TxStatusArgs), + Validators(self::deprecated::ValidatorsArgs), #[clap(alias("validator-stake"))] - Stake(self::validators::StakeArgs), - Validators(self::validators::ValidatorsArgs), + Stake(self::deprecated::StakeArgs), } impl JsCmd { - pub fn rust_command_generation(&self) -> Result<(Vec, String), String> { + pub fn rust_command_generation(&self) -> Vec { let network = std::env::var("NEAR_NETWORK") .or_else(|_| std::env::var("NEAR_ENV")) .unwrap_or_else(|_| "testnet".to_owned()); - let message = "The command you tried to run is deprecated in the new NEAR CLI, but we tried our best to match the old command with the new syntax, try it instead:".to_string(); - let validator_extension_message = "The command you tried to run has been moved into its own CLI extension called near-validator.\nPlease, follow the installation instructions here: https://github.com/near-cli-rs/near-validator-cli-rs/blob/master/README.md".to_string(); match self { - Self::CreateAccount(args) => Ok((args.to_cli_args(network), message)), - Self::DeleteAccount(args) => Ok((args.to_cli_args(network), message)), - Self::Login(args) => Ok((args.to_cli_args(network), message)), - Self::State(args) => Ok((args.to_cli_args(network), message)), + Self::CreateAccount(args) => args.to_cli_args(network), + Self::DeleteAccount(args) => args.to_cli_args(network), + Self::Login(args) => args.to_cli_args(network), + Self::State(args) => args.to_cli_args(network), - Self::Call(args) => Ok((args.to_cli_args(network), message)), - Self::Deploy(args) => Ok((args.to_cli_args(network), message)), - Self::ViewState(args) => Ok((args.to_cli_args(network), message)), - Self::View(args) => Ok((args.to_cli_args(network), message)), + Self::Call(args) => args.to_cli_args(network), + Self::Deploy(args) => args.to_cli_args(network), + Self::ViewState(args) => args.to_cli_args(network), + Self::View(args) => args.to_cli_args(network), - Self::AddKey(args) => Ok((args.to_cli_args(network), message)), - Self::DeleteKey(args) => Ok((args.to_cli_args(network), message)), - Self::ListKeys(args) => Ok((args.to_cli_args(network), message)), + Self::AddKey(args) => args.to_cli_args(network), + Self::DeleteKey(args) => args.to_cli_args(network), + Self::ListKeys(args) => args.to_cli_args(network), - Self::Send(args) => Ok((args.to_cli_args(network), message)), - Self::TxStatus(args) => Ok((args.to_cli_args(network), message)), + Self::Send(args) => args.to_cli_args(network), + Self::TxStatus(args) => args.to_cli_args(network), - Self::Stake(_args) => Ok((vec![], validator_extension_message)), - Self::Validators(_args) => Ok((vec![], validator_extension_message)), + Self::Validators(args) => args.to_cli_args(network), + Self::Stake(args) => args.to_cli_args(network), } } } diff --git a/src/js_command_match/validators.rs b/src/js_command_match/validators.rs deleted file mode 100644 index eb4c9fa8..00000000 --- a/src/js_command_match/validators.rs +++ /dev/null @@ -1,12 +0,0 @@ -#[derive(Debug, Clone, clap::Parser)] -/// This is a legacy `validators` command. Once you run it with the specified arguments, new syntax command will be suggested. -pub struct ValidatorsArgs { - #[clap(allow_hyphen_values = true, num_args = 0..)] - _unknown_args: Vec, -} - -#[derive(Debug, Clone, clap::Parser)] -pub struct StakeArgs { - #[clap(allow_hyphen_values = true, num_args = 0..)] - _unknown_args: Vec, -} diff --git a/src/main.rs b/src/main.rs index 7793ae93..ed20561d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,55 +84,35 @@ fn main() -> crate::common::CliResult { let cli = match Cmd::try_parse() { Ok(cli) => cli, - Err(error) => { - match error.kind() { - clap::error::ErrorKind::DisplayHelp | clap::error::ErrorKind::DisplayVersion => {} - _ => match crate::js_command_match::JsCmd::try_parse() { + Err(cmd_error) => match cmd_error.kind() { + clap::error::ErrorKind::DisplayHelp | clap::error::ErrorKind::DisplayVersion => { + cmd_error.exit() + } + _ => { + match crate::js_command_match::JsCmd::try_parse() { Ok(js_cmd) => { - match js_cmd.rust_command_generation() { - Ok((vec_cmd, success_message)) => { - eprintln!("{success_message}"); - eprintln!(); - eprintln!( - " {}", - shell_words::join( - std::iter::once(near_cli_exec_path).chain(vec_cmd) - ) - .yellow() - ); - } - Err(err) => { - eprintln!("{}", err); - } - } - std::process::exit(1); + let vec_cmd = js_cmd.rust_command_generation(); + let cmd = std::iter::once(near_cli_exec_path.to_owned()).chain(vec_cmd); + Parser::parse_from(cmd) } - Err(error) => { - if let clap::error::ErrorKind::DisplayHelp = error.kind() { - error.exit(); + Err(js_cmd_error) => { + // js and rust both don't understand the subcommand + if cmd_error.kind() == clap::error::ErrorKind::InvalidSubcommand + && js_cmd_error.kind() == clap::error::ErrorKind::InvalidSubcommand + { + return crate::common::try_external_subcommand_execution(cmd_error); } - if let Some(cmd) = std::env::args().nth(1) { - match cmd.as_str() { - "add-credentials" | "add-key" | "call" | "create" - | "create-account" | "delete" | "delete-account" | "delete-key" - | "deploy" | "generate-key" | "import-account" | "keys" - | "list-keys" | "login" | "send" | "send-near" | "stake" - | "state" | "storage" | "tx-status" | "validator-stake" - | "validators" | "view" | "view-storage" => error.exit(), - _ => {} - } + + // js understand the subcommand + if js_cmd_error.kind() != clap::error::ErrorKind::InvalidSubcommand { + js_cmd_error.exit(); } - } - }, - } - if let clap::error::ErrorKind::UnknownArgument - | clap::error::ErrorKind::InvalidSubcommand = error.kind() - { - return crate::common::try_external_subcommand_execution(error); + cmd_error.exit(); + } + } } - error.exit(); - } + }, }; if cli.teach_me { let env_filter = EnvFilter::from_default_env()