Skip to content

Commit

Permalink
feat: Automatically exec legacy JS CLI commands for full backward com…
Browse files Browse the repository at this point in the history
…patibility (#366)

This PR tries to automatically execute the CLI commands that are
suggested after somebody tries to run a JS commands.
  • Loading branch information
gagdiez authored Jul 30, 2024
1 parent ea828e9 commit 3a4a1cf
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 82 deletions.
2 changes: 1 addition & 1 deletion src/js_command_match/contract/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 5 additions & 5 deletions src/js_command_match/contract/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
Expand All @@ -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,
Expand All @@ -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");
Expand Down
30 changes: 30 additions & 0 deletions src/js_command_match/deprecated.rs
Original file line number Diff line number Diff line change
@@ -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<String>,
}

#[derive(Debug, Clone, clap::Parser)]
pub struct StakeArgs {
#[clap(allow_hyphen_values = true, num_args = 0..)]
_unknown_args: Vec<String>,
}

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<String> {
eprintln!("\n{}\n", DEPRECATED.to_string().yellow());
vec!["near-validator".to_string()]
}
}

impl StakeArgs {
pub fn to_cli_args(&self, _network_config: String) -> Vec<String> {
eprintln!("\n{}\n", DEPRECATED.to_string().yellow());
vec!["near-validator".to_string()]
}
}
40 changes: 19 additions & 21 deletions src/js_command_match/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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), String> {
pub fn rust_command_generation(&self) -> Vec<String> {
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),
}
}
}
12 changes: 0 additions & 12 deletions src/js_command_match/validators.rs

This file was deleted.

66 changes: 23 additions & 43 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 3a4a1cf

Please sign in to comment.