diff --git a/rs/cli/src/commands/api_boundary_nodes/add.rs b/rs/cli/src/commands/api_boundary_nodes/add.rs index e2fd78a08..05e6d3242 100644 --- a/rs/cli/src/commands/api_boundary_nodes/add.rs +++ b/rs/cli/src/commands/api_boundary_nodes/add.rs @@ -3,7 +3,8 @@ use ic_types::PrincipalId; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, ic_admin::{self}, submitter::{SubmissionParameters, Submitter}, @@ -51,5 +52,5 @@ impl ExecutableCommand for Add { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/api_boundary_nodes/mod.rs b/rs/cli/src/commands/api_boundary_nodes/mod.rs index 30627f38e..5196ee157 100644 --- a/rs/cli/src/commands/api_boundary_nodes/mod.rs +++ b/rs/cli/src/commands/api_boundary_nodes/mod.rs @@ -3,7 +3,7 @@ use clap::Args; use remove::Remove; use update::Update; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; mod add; mod remove; diff --git a/rs/cli/src/commands/api_boundary_nodes/remove.rs b/rs/cli/src/commands/api_boundary_nodes/remove.rs index f3f1c003d..01c810e96 100644 --- a/rs/cli/src/commands/api_boundary_nodes/remove.rs +++ b/rs/cli/src/commands/api_boundary_nodes/remove.rs @@ -3,7 +3,8 @@ use ic_types::PrincipalId; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, ic_admin::{self}, submitter::{SubmissionParameters, Submitter}, @@ -44,5 +45,5 @@ impl ExecutableCommand for Remove { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/api_boundary_nodes/update.rs b/rs/cli/src/commands/api_boundary_nodes/update.rs index 4c5056ada..534316ce4 100644 --- a/rs/cli/src/commands/api_boundary_nodes/update.rs +++ b/rs/cli/src/commands/api_boundary_nodes/update.rs @@ -3,7 +3,8 @@ use ic_types::PrincipalId; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, ic_admin::{self}, submitter::{SubmissionParameters, Submitter}, @@ -50,5 +51,5 @@ impl ExecutableCommand for Update { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/completions.rs b/rs/cli/src/commands/completions.rs deleted file mode 100644 index 0dc360a43..000000000 --- a/rs/cli/src/commands/completions.rs +++ /dev/null @@ -1,26 +0,0 @@ -use clap::{Args, CommandFactory}; -use clap_complete::{generate, Shell}; - -use super::ExecutableCommand; - -#[derive(Args, Debug)] -pub struct Completions { - #[clap(long, short, default_value_t = Shell::Bash)] - shell: Shell, -} - -impl ExecutableCommand for Completions { - fn require_auth(&self) -> super::AuthRequirement { - super::AuthRequirement::Anonymous - } - - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} - - async fn execute(&self, _ctx: crate::ctx::DreContext) -> anyhow::Result<()> { - let mut command = super::Args::command(); - - generate(self.shell, &mut command, "dre", &mut std::io::stdout()); - - Ok(()) - } -} diff --git a/rs/cli/src/commands/der_to_principal.rs b/rs/cli/src/commands/der_to_principal.rs index 41890688b..f4f56525f 100644 --- a/rs/cli/src/commands/der_to_principal.rs +++ b/rs/cli/src/commands/der_to_principal.rs @@ -2,7 +2,8 @@ use std::path::PathBuf; use clap::Args; -use super::{AuthRequirement, ExecutableCommand}; +use crate::auth::AuthRequirement; +use crate::exe::{ExecutableCommand, args::GlobalArgs}; #[derive(Args, Debug)] pub struct DerToPrincipal { @@ -21,5 +22,5 @@ impl ExecutableCommand for DerToPrincipal { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/firewall.rs b/rs/cli/src/commands/firewall.rs index fb50568d8..8598d55de 100644 --- a/rs/cli/src/commands/firewall.rs +++ b/rs/cli/src/commands/firewall.rs @@ -13,15 +13,15 @@ use serde::{Deserialize, Serialize}; use tempfile::NamedTempFile; use crate::{ + auth::AuthRequirement, ctx::DreContext, + exe::{ExecutableCommand, args::GlobalArgs}, forum::ForumPostKind, ic_admin::{IcAdminProposal, IcAdminProposalCommand, IcAdminProposalOptions}, proposal_executors::{ProducesProposalResult, ProposalResponseWithId, RunnableViaIcAdmin}, submitter::{SubmissionParameters, Submitter}, }; -use super::{AuthRequirement, ExecutableCommand}; - #[derive(Args, Debug)] pub struct Firewall { #[clap(long, default_value = Some("Proposal to modify firewall rules"))] @@ -43,7 +43,7 @@ impl ExecutableCommand for Firewall { AuthRequirement::Neuron } - async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { + async fn execute(&self, ctx: DreContext) -> anyhow::Result<()> { let registry = ctx.registry().await; let firewall_ruleset = registry.firewall_rule_set(self.rules_scope.clone()).await?; @@ -120,7 +120,7 @@ impl ExecutableCommand for Firewall { } } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } #[derive(Deserialize)] diff --git a/rs/cli/src/commands/get.rs b/rs/cli/src/commands/get.rs index a6615f9a2..b950eb61b 100644 --- a/rs/cli/src/commands/get.rs +++ b/rs/cli/src/commands/get.rs @@ -1,6 +1,7 @@ use clap::Args; -use super::{AuthRequirement, ExecutableCommand}; +use crate::auth::AuthRequirement; +use crate::exe::{args::GlobalArgs, ExecutableCommand}; #[derive(Args, Debug)] pub struct Get { @@ -18,5 +19,5 @@ impl ExecutableCommand for Get { ctx.get(&self.args).await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/governance/mod.rs b/rs/cli/src/commands/governance/mod.rs index 9e86de69a..0890d10c8 100644 --- a/rs/cli/src/commands/governance/mod.rs +++ b/rs/cli/src/commands/governance/mod.rs @@ -3,6 +3,8 @@ mod propose; use propose::Propose; +use crate::exe::impl_executable_command_for_enums; + #[derive(Args, Debug)] /// Commands and actions related to governance. pub struct Governance { @@ -10,4 +12,4 @@ pub struct Governance { pub subcommands: Subcommands, } -super::impl_executable_command_for_enums! { Governance, Propose } +impl_executable_command_for_enums! { Governance, Propose } diff --git a/rs/cli/src/commands/governance/propose/mod.rs b/rs/cli/src/commands/governance/propose/mod.rs index 79845d72d..73b491b11 100644 --- a/rs/cli/src/commands/governance/propose/mod.rs +++ b/rs/cli/src/commands/governance/propose/mod.rs @@ -1,10 +1,10 @@ use clap::Args; mod motion; -use crate::commands::impl_executable_command_for_enums; - use motion::Motion; +use crate::exe::impl_executable_command_for_enums; + #[derive(Args, Debug)] /// Creation of proposals. pub struct Propose { diff --git a/rs/cli/src/commands/governance/propose/motion.rs b/rs/cli/src/commands/governance/propose/motion.rs index 0e214d17b..1b745f7d8 100644 --- a/rs/cli/src/commands/governance/propose/motion.rs +++ b/rs/cli/src/commands/governance/propose/motion.rs @@ -6,7 +6,8 @@ use tokio::io::AsyncReadExt; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, util::{extract_title_and_text, utf8}, @@ -90,5 +91,7 @@ impl ExecutableCommand for Motion { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) { + let _ = _args; + } } diff --git a/rs/cli/src/commands/hostos/mod.rs b/rs/cli/src/commands/hostos/mod.rs index b6fdca127..4453a6598 100644 --- a/rs/cli/src/commands/hostos/mod.rs +++ b/rs/cli/src/commands/hostos/mod.rs @@ -2,6 +2,8 @@ use clap::Args; use rollout::Rollout; use rollout_from_node_group::RolloutFromNodeGroup; +use crate::exe::impl_executable_command_for_enums; + mod rollout; pub mod rollout_from_node_group; @@ -11,4 +13,4 @@ pub struct HostOs { pub subcommands: Subcommands, } -super::impl_executable_command_for_enums! { HostOs, Rollout, RolloutFromNodeGroup } +impl_executable_command_for_enums! { HostOs, Rollout, RolloutFromNodeGroup } diff --git a/rs/cli/src/commands/hostos/rollout.rs b/rs/cli/src/commands/hostos/rollout.rs index 1ad062cdf..98e59f1af 100644 --- a/rs/cli/src/commands/hostos/rollout.rs +++ b/rs/cli/src/commands/hostos/rollout.rs @@ -3,7 +3,8 @@ use ic_types::PrincipalId; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -34,5 +35,5 @@ impl ExecutableCommand for Rollout { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/hostos/rollout_from_node_group.rs b/rs/cli/src/commands/hostos/rollout_from_node_group.rs index 3bbbebd5c..7d093f6bc 100644 --- a/rs/cli/src/commands/hostos/rollout_from_node_group.rs +++ b/rs/cli/src/commands/hostos/rollout_from_node_group.rs @@ -4,7 +4,8 @@ use clap::{Args, ValueEnum}; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, operations::hostos_rollout::{NodeGroupUpdate, NumberOfNodes}, submitter::{SubmissionParameters, Submitter}, @@ -104,5 +105,5 @@ impl ExecutableCommand for RolloutFromNodeGroup { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/main_command.rs b/rs/cli/src/commands/main_command.rs new file mode 100644 index 000000000..20906565c --- /dev/null +++ b/rs/cli/src/commands/main_command.rs @@ -0,0 +1,58 @@ +use super::api_boundary_nodes::ApiBoundaryNodes; +use super::der_to_principal::DerToPrincipal; +use super::firewall::Firewall; +use super::get::Get; +use super::governance::Governance; +use super::hostos::HostOs; +use super::network::Network; +use super::neuron::Neuron; +use super::node_metrics::NodeMetrics; +use super::nodes::Nodes; +use super::proposals::Proposals; +use super::propose::Propose; +use super::qualify::Qualify; +use super::registry::Registry; +use super::update_authorized_subnets::UpdateAuthorizedSubnets; +use super::update_unassigned_nodes::UpdateUnassignedNodes; +use super::upgrade::Upgrade; +use super::version::Version; +use super::vote::Vote; +use crate::commands::subnet::Subnet; +use crate::exe::impl_executable_command_for_enums; +use clap::Parser; +use clap::{Args, CommandFactory}; +use clap_complete::{generate, Shell}; + +#[derive(Parser, Debug)] +#[clap(version = env!("CARGO_PKG_VERSION"), about, author)] +pub struct MainCommand { + #[clap(flatten)] + pub global_args: GlobalArgs, + + #[clap(subcommand)] + pub subcommands: Subcommands, +} + +impl_executable_command_for_enums! { MainCommand, DerToPrincipal, Network, Subnet, Get, Propose, UpdateUnassignedNodes, Version, NodeMetrics, HostOs, Nodes, ApiBoundaryNodes, Vote, Registry, Firewall, Upgrade, Proposals, Completions, Qualify, UpdateAuthorizedSubnets, Neuron, Governance } + +#[derive(Args, Debug)] +pub struct Completions { + #[clap(long, short, default_value_t = Shell::Bash)] + shell: Shell, +} + +impl ExecutableCommand for Completions { + fn require_auth(&self) -> AuthRequirement { + AuthRequirement::Anonymous + } + + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} + + async fn execute(&self, _ctx: crate::ctx::DreContext) -> anyhow::Result<()> { + let mut command = MainCommand::command(); + + generate(self.shell, &mut command, "dre", &mut std::io::stdout()); + + Ok(()) + } +} diff --git a/rs/cli/src/commands/mod.rs b/rs/cli/src/commands/mod.rs index d9a8a000c..c03178207 100644 --- a/rs/cli/src/commands/mod.rs +++ b/rs/cli/src/commands/mod.rs @@ -1,36 +1,10 @@ -use crate::commands::subnet::Subnet; -use crate::ctx::exe::impl_executable_command_for_enums; -use api_boundary_nodes::ApiBoundaryNodes; -use clap::Parser; -use completions::Completions; -use der_to_principal::DerToPrincipal; -use firewall::Firewall; -use get::Get; -use governance::Governance; -use hostos::HostOs; -use network::Network; -use neuron::Neuron; -use node_metrics::NodeMetrics; -use nodes::Nodes; -use proposals::Proposals; -use propose::Propose; -use qualify::Qualify; -use registry::Registry; -use strum::Display; -use update_authorized_subnets::UpdateAuthorizedSubnets; -use update_unassigned_nodes::UpdateUnassignedNodes; -use upgrade::Upgrade; -use url::Url; -use version::Version; -use vote::Vote; - pub(crate) mod api_boundary_nodes; -pub(crate) mod completions; pub(crate) mod der_to_principal; pub(crate) mod firewall; pub mod get; pub(crate) mod governance; pub mod hostos; +pub mod main_command; pub(crate) mod network; pub(crate) mod neuron; pub(crate) mod node_metrics; @@ -45,78 +19,3 @@ pub(crate) mod update_unassigned_nodes; pub mod upgrade; pub(crate) mod version; pub(crate) mod vote; -use crate::auth::AuthOpts; - -#[derive(Parser, Debug)] -#[clap(version = env!("CARGO_PKG_VERSION"), about, author)] -pub struct Args { - #[clap(flatten)] - pub(crate) auth_opts: AuthOpts, - - /// Neuron ID - #[clap(long, global = true, env = "NEURON_ID", visible_aliases = &["neuron", "proposer"])] - pub neuron_id: Option, - - /// Path to explicitly state ic-admin path to use - #[clap(long, global = true, env = "IC_ADMIN")] - pub ic_admin: Option, - - #[clap(long, global = true, env = "IC_ADMIN_VERSION", default_value = "from-governance", value_parser = clap::value_parser!(IcAdminVersion), help = r#"Specify the version of ic admin to use -Options: - 1. from-governance, governance, govn, g => same as governance canister - 2. default, d => strict default version, embedded at build time - 3. => specific commit"#)] - pub ic_admin_version: IcAdminVersion, - - #[clap( - long, - env = "NETWORK", - default_value = "mainnet", - help = r#"Specify the target network: - - "mainnet", - - "staging", - - "" -"# - )] - pub network: String, - - #[clap(long, env = "NNS_URLS", value_delimiter = ',', aliases = ["registry-url", "nns-url"], help = r#"NNS_URLs for target network, comma separated. -The argument is mandatory for testnets, and is optional for mainnet and staging"#)] - pub nns_urls: Vec, - - #[clap(subcommand)] - pub subcommands: Subcommands, - - /// To print as much information as possible - #[clap(long, env = "VERBOSE", global = true)] - pub verbose: bool, - - /// Run the tool offline when possible, i.e., do not sync registry and public dashboard data before the run - /// - /// Useful for when the NNS or Public dashboard are unreachable - #[clap(long)] - pub offline: bool, - - /// Path to file which contains cordoned features - #[clap(long, global = true, visible_aliases = &["cf-file", "cfff"])] - pub cordoned_features_file: Option, -} - -impl_executable_command_for_enums! { Args, DerToPrincipal, Network, Subnet, Get, Propose, UpdateUnassignedNodes, Version, NodeMetrics, HostOs, Nodes, ApiBoundaryNodes, Vote, Registry, Firewall, Upgrade, Proposals, Completions, Qualify, UpdateAuthorizedSubnets, Neuron, Governance } - -#[derive(Debug, Display, Clone)] -pub enum IcAdminVersion { - FromGovernance, - Fallback, - Strict(String), -} - -impl From<&str> for IcAdminVersion { - fn from(value: &str) -> Self { - match value { - "from-governance" | "governance" | "g" | "govn" => Self::FromGovernance, - "fallback" | "f" => Self::Fallback, - s => Self::Strict(s.to_string()), - } - } -} diff --git a/rs/cli/src/commands/network.rs b/rs/cli/src/commands/network.rs index 6ba11d357..f360251ba 100644 --- a/rs/cli/src/commands/network.rs +++ b/rs/cli/src/commands/network.rs @@ -8,7 +8,8 @@ use crate::{ submitter::{SubmissionParameters, Submitter}, }; -use super::{AuthRequirement, ExecutableCommand}; +use crate::auth::AuthRequirement; +use crate::exe::{args::GlobalArgs, ExecutableCommand}; #[derive(Args, Debug)] #[clap(alias = "heal")] @@ -220,7 +221,7 @@ impl ExecutableCommand for Network { } } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { // At least one of the two options must be provided let network_heal = self.heal || std::env::args().any(|arg| arg == "heal"); if !network_heal && !self.ensure_operator_nodes_assigned && !self.ensure_operator_nodes_unassigned && !self.remove_cordoned_nodes { diff --git a/rs/cli/src/commands/neuron/balance.rs b/rs/cli/src/commands/neuron/balance.rs index 13ac05eb6..a9b4b9977 100644 --- a/rs/cli/src/commands/neuron/balance.rs +++ b/rs/cli/src/commands/neuron/balance.rs @@ -1,17 +1,17 @@ use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; -use crate::commands::ExecutableCommand; +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; #[derive(Args, Debug)] pub struct Balance {} impl ExecutableCommand for Balance { - fn require_auth(&self) -> crate::commands::AuthRequirement { - crate::commands::AuthRequirement::Neuron + fn require_auth(&self) -> AuthRequirement { + AuthRequirement::Neuron } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { let (neuron, client) = ctx.create_ic_agent_canister_client().await?; diff --git a/rs/cli/src/commands/neuron/mod.rs b/rs/cli/src/commands/neuron/mod.rs index 59d7d64dc..12ec52b3d 100644 --- a/rs/cli/src/commands/neuron/mod.rs +++ b/rs/cli/src/commands/neuron/mod.rs @@ -3,7 +3,7 @@ use clap::Args; use crate::commands::neuron::balance::Balance; use crate::commands::neuron::refresh::Refresh; use crate::commands::neuron::top_up::TopUp; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; mod balance; mod refresh; diff --git a/rs/cli/src/commands/neuron/refresh.rs b/rs/cli/src/commands/neuron/refresh.rs index d7e5c4369..419ed59ba 100644 --- a/rs/cli/src/commands/neuron/refresh.rs +++ b/rs/cli/src/commands/neuron/refresh.rs @@ -1,17 +1,17 @@ use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; -use crate::commands::ExecutableCommand; +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; #[derive(Args, Debug)] pub struct Refresh {} impl ExecutableCommand for Refresh { - fn require_auth(&self) -> crate::commands::AuthRequirement { - crate::commands::AuthRequirement::Neuron + fn require_auth(&self) -> AuthRequirement { + AuthRequirement::Neuron } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { let (neuron, client) = ctx.create_ic_agent_canister_client().await?; diff --git a/rs/cli/src/commands/neuron/top_up.rs b/rs/cli/src/commands/neuron/top_up.rs index 8968e72aa..6640e72ee 100644 --- a/rs/cli/src/commands/neuron/top_up.rs +++ b/rs/cli/src/commands/neuron/top_up.rs @@ -2,17 +2,17 @@ use clap::Args; use ic_canisters::{governance::GovernanceCanisterWrapper, ledger::LedgerCanisterWrapper}; use itertools::Itertools; -use crate::commands::ExecutableCommand; +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; #[derive(Args, Debug)] pub struct TopUp {} impl ExecutableCommand for TopUp { - fn require_auth(&self) -> crate::commands::AuthRequirement { - crate::commands::AuthRequirement::Neuron + fn require_auth(&self) -> AuthRequirement { + AuthRequirement::Neuron } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { let (neuron, client) = ctx.create_ic_agent_canister_client().await?; diff --git a/rs/cli/src/commands/node_metrics.rs b/rs/cli/src/commands/node_metrics.rs index 33fd59a38..5b8b20761 100644 --- a/rs/cli/src/commands/node_metrics.rs +++ b/rs/cli/src/commands/node_metrics.rs @@ -14,7 +14,7 @@ use ic_types::{CanisterId, PrincipalId}; use itertools::Itertools; use log::{info, warn}; -use super::{AuthRequirement, ExecutableCommand}; +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; type CLINodeMetrics = BTreeMap>; @@ -143,7 +143,7 @@ impl ExecutableCommand for NodeMetrics { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if self.trustworthy && self.wallet.is_none() { cmd.error(ErrorKind::MissingRequiredArgument, "Wallet is required for fetching trustworthy metrics.") .exit(); diff --git a/rs/cli/src/commands/nodes/mod.rs b/rs/cli/src/commands/nodes/mod.rs index ffbe033e6..3fbbf4035 100644 --- a/rs/cli/src/commands/nodes/mod.rs +++ b/rs/cli/src/commands/nodes/mod.rs @@ -1,7 +1,7 @@ use clap::Args; use remove::Remove; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; mod remove; #[derive(Args, Debug)] diff --git a/rs/cli/src/commands/nodes/remove.rs b/rs/cli/src/commands/nodes/remove.rs index 5f5e30d6c..cce7046e0 100644 --- a/rs/cli/src/commands/nodes/remove.rs +++ b/rs/cli/src/commands/nodes/remove.rs @@ -1,9 +1,10 @@ +use crate::exe::args::GlobalArgs; use clap::{error::ErrorKind, Args}; use decentralization::subnets::NodesRemover; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -55,7 +56,7 @@ impl ExecutableCommand for Remove { .await } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if self.motivation.is_none() && !self.extra_nodes_filter.is_empty() { cmd.error(ErrorKind::MissingRequiredArgument, "Required argument motivation not found") .exit() diff --git a/rs/cli/src/commands/proposals/analyze.rs b/rs/cli/src/commands/proposals/analyze.rs index d726676da..966e3c0ad 100644 --- a/rs/cli/src/commands/proposals/analyze.rs +++ b/rs/cli/src/commands/proposals/analyze.rs @@ -5,7 +5,8 @@ use ic_nns_governance::pb::v1::ProposalStatus; use registry_canister::mutations::do_change_subnet_membership::ChangeSubnetMembershipPayload; use crate::auth::AuthRequirement; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::args::GlobalArgs; +use crate::exe::ExecutableCommand; #[derive(Args, Debug)] pub struct Analyze { @@ -44,5 +45,5 @@ impl ExecutableCommand for Analyze { } } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/proposals/filter.rs b/rs/cli/src/commands/proposals/filter.rs index 2155e5a6a..bc993ec80 100644 --- a/rs/cli/src/commands/proposals/filter.rs +++ b/rs/cli/src/commands/proposals/filter.rs @@ -1,3 +1,4 @@ +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; use ic_nns_common::pb::v1::ProposalId; @@ -10,7 +11,7 @@ use std::fmt::Display; use clap::ValueEnum; use ic_nns_governance::pb::v1::{ListProposalInfo, ProposalStatus as ProposalStatusUpstream, Topic as TopicUpstream}; -use crate::commands::{proposals::Proposal, AuthRequirement, ExecutableCommand}; +use crate::commands::proposals::Proposal; #[derive(Args, Debug)] pub struct Filter { /// Limit on the number of \[ProposalInfo\] to return. If value greater than @@ -309,5 +310,5 @@ impl ExecutableCommand for Filter { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/proposals/get.rs b/rs/cli/src/commands/proposals/get.rs index 1a38f82ec..17f13df7e 100644 --- a/rs/cli/src/commands/proposals/get.rs +++ b/rs/cli/src/commands/proposals/get.rs @@ -2,7 +2,9 @@ use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; use crate::auth::AuthRequirement; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::args::GlobalArgs; +use crate::exe::ExecutableCommand; + #[derive(Args, Debug)] pub struct Get { /// Proposal ID @@ -21,5 +23,5 @@ impl ExecutableCommand for Get { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/proposals/list.rs b/rs/cli/src/commands/proposals/list.rs index d1dcc80e6..142191df4 100644 --- a/rs/cli/src/commands/proposals/list.rs +++ b/rs/cli/src/commands/proposals/list.rs @@ -1,3 +1,4 @@ +use crate::exe::args::GlobalArgs; use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; use ic_nns_common::pb::v1::ProposalId; @@ -6,7 +7,7 @@ use itertools::Itertools; use super::Proposal; use crate::auth::AuthRequirement; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::ExecutableCommand; #[derive(Args, Debug)] pub struct List { @@ -89,5 +90,5 @@ impl ExecutableCommand for List { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/proposals/mod.rs b/rs/cli/src/commands/proposals/mod.rs index 3101b8eef..cee966bbd 100644 --- a/rs/cli/src/commands/proposals/mod.rs +++ b/rs/cli/src/commands/proposals/mod.rs @@ -47,7 +47,7 @@ use registry_canister::mutations::{ }; use serde::{Deserialize, Serialize}; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; mod analyze; mod filter; diff --git a/rs/cli/src/commands/proposals/pending.rs b/rs/cli/src/commands/proposals/pending.rs index 9d105e06a..a605a91e8 100644 --- a/rs/cli/src/commands/proposals/pending.rs +++ b/rs/cli/src/commands/proposals/pending.rs @@ -2,7 +2,9 @@ use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; use crate::auth::AuthRequirement; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::args::GlobalArgs; +use crate::exe::ExecutableCommand; + #[derive(Args, Debug)] pub struct Pending {} @@ -21,5 +23,5 @@ impl ExecutableCommand for Pending { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/propose.rs b/rs/cli/src/commands/propose.rs index da23176c2..8dc0b4cb3 100644 --- a/rs/cli/src/commands/propose.rs +++ b/rs/cli/src/commands/propose.rs @@ -1,13 +1,14 @@ use clap::{error::ErrorKind, Args}; +use crate::auth::AuthRequirement; +use crate::exe::ExecutableCommand; +use crate::exe::args::GlobalArgs; use crate::{ forum::ForumPostKind, ic_admin::{IcAdminProposal, IcAdminProposalCommand}, submitter::{SubmissionParameters, Submitter}, }; -use super::{AuthRequirement, ExecutableCommand}; - #[derive(Args, Debug)] pub struct Propose { #[clap(flatten)] @@ -47,19 +48,15 @@ impl ExecutableCommand for Propose { .await } - fn validate(&self, args: &crate::commands::Args, cmd: &mut clap::Command) { - let thisargs = match &args.subcommands { - super::Subcommands::Propose(p) => p.args.clone(), - _ => Vec::new(), - }; - if thisargs.iter().any(|arg| { - ["--forum", "--proposal-url", "--forum-post-link"] + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { + if self.args.iter().any(|arg| { + ["--forum", "--proposal-url", "--forum-post-link", "--yes", "--dry-run", "--no"] .iter() .any(|other| other == arg || arg.starts_with((other.to_string() + "=").as_str())) }) { cmd.error( ErrorKind::ValueValidation, - "Option --forum-post-link (or any of its variants) must appear prior to the propose verb or immediately after.", + "Some of the options you used must appear immediately after the `propose` verb.", ) .exit() } diff --git a/rs/cli/src/commands/qualify/execute.rs b/rs/cli/src/commands/qualify/execute.rs index 47d702d7c..23e33d5c2 100644 --- a/rs/cli/src/commands/qualify/execute.rs +++ b/rs/cli/src/commands/qualify/execute.rs @@ -5,7 +5,10 @@ use clap::Args; use ic_management_types::Network; use serde_json::Value; -use crate::{commands::ExecutableCommand, ic_admin::IcAdmin, qualification::QualificationExecutorBuilder}; +use crate::auth::AuthRequirement; +use crate::exe::ExecutableCommand; +use crate::exe::args::GlobalArgs; +use crate::{ic_admin::IcAdmin, qualification::QualificationExecutorBuilder}; #[derive(Args, Debug)] pub struct Execute { @@ -41,11 +44,11 @@ pub struct Execute { } impl ExecutableCommand for Execute { - fn require_auth(&self) -> crate::commands::AuthRequirement { - crate::commands::AuthRequirement::Neuron + fn require_auth(&self) -> AuthRequirement { + AuthRequirement::Neuron } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if self.artifacts.is_some() && self.grafana_url.is_none() { cmd.error( clap::error::ErrorKind::InvalidValue, diff --git a/rs/cli/src/commands/qualify/list.rs b/rs/cli/src/commands/qualify/list.rs index 960c64dd3..177d02fa2 100644 --- a/rs/cli/src/commands/qualify/list.rs +++ b/rs/cli/src/commands/qualify/list.rs @@ -1,6 +1,9 @@ use clap::Args; -use crate::{commands::ExecutableCommand, qualification::QualificationExecutorBuilder}; +use crate::auth::AuthRequirement; +use crate::exe::ExecutableCommand; +use crate::exe::args::GlobalArgs; +use crate::qualification::QualificationExecutorBuilder; #[derive(Args, Debug)] pub struct List { @@ -11,11 +14,11 @@ pub struct List { } impl ExecutableCommand for List { - fn require_auth(&self) -> crate::commands::AuthRequirement { - crate::commands::AuthRequirement::Anonymous + fn require_auth(&self) -> AuthRequirement { + AuthRequirement::Anonymous } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { let qualification_executor = QualificationExecutorBuilder::new(ctx) diff --git a/rs/cli/src/commands/qualify/mod.rs b/rs/cli/src/commands/qualify/mod.rs index bcda26090..c0036d15b 100644 --- a/rs/cli/src/commands/qualify/mod.rs +++ b/rs/cli/src/commands/qualify/mod.rs @@ -2,7 +2,7 @@ use clap::Args; use execute::Execute; use list::List; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; pub mod execute; mod list; diff --git a/rs/cli/src/commands/registry.rs b/rs/cli/src/commands/registry.rs index 4d50157f0..2192b3cd3 100644 --- a/rs/cli/src/commands/registry.rs +++ b/rs/cli/src/commands/registry.rs @@ -6,6 +6,7 @@ use std::{ sync::Arc, }; +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; use clap::Args; use ic_canisters::governance::GovernanceCanisterWrapper; use ic_canisters::IcAgentCanisterClient; @@ -31,8 +32,6 @@ use serde_json::Value; use crate::ctx::DreContext; -use super::{AuthRequirement, ExecutableCommand}; - #[derive(Args, Debug)] #[clap(after_help = r#"EXAMPLES: dre registry # Dump all contents to stdout @@ -113,7 +112,7 @@ impl ExecutableCommand for Registry { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } impl Registry { diff --git a/rs/cli/src/commands/subnet/create.rs b/rs/cli/src/commands/subnet/create.rs index 347cc829c..36d02d9c4 100644 --- a/rs/cli/src/commands/subnet/create.rs +++ b/rs/cli/src/commands/subnet/create.rs @@ -1,11 +1,13 @@ use clap::{error::ErrorKind, Args}; +use crate::exe::args::GlobalArgs; use ic_management_types::requests::SubnetCreateRequest; + use ic_types::PrincipalId; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -89,7 +91,7 @@ impl ExecutableCommand for Create { .await } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if self.motivation.is_none() && !self.help_other_args { cmd.error( ErrorKind::MissingRequiredArgument, diff --git a/rs/cli/src/commands/subnet/deploy.rs b/rs/cli/src/commands/subnet/deploy.rs index f8f8611ac..1d16933e5 100644 --- a/rs/cli/src/commands/subnet/deploy.rs +++ b/rs/cli/src/commands/subnet/deploy.rs @@ -1,3 +1,4 @@ +use crate::exe::args::GlobalArgs; use clap::Args; use ic_types::PrincipalId; @@ -5,7 +6,7 @@ use ic_types::PrincipalId; use crate::{ auth::get_automation_neuron_default_path, auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -37,7 +38,7 @@ impl ExecutableCommand for Deploy { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} fn neuron_override(&self) -> Option { Some(crate::auth::Neuron { diff --git a/rs/cli/src/commands/subnet/mod.rs b/rs/cli/src/commands/subnet/mod.rs index 76e910dd7..a693c81be 100644 --- a/rs/cli/src/commands/subnet/mod.rs +++ b/rs/cli/src/commands/subnet/mod.rs @@ -6,7 +6,7 @@ use rescue::Rescue; use resize::Resize; use whatif::WhatifDecentralization; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; mod create; mod deploy; diff --git a/rs/cli/src/commands/subnet/replace.rs b/rs/cli/src/commands/subnet/replace.rs index 89142c005..b64af630b 100644 --- a/rs/cli/src/commands/subnet/replace.rs +++ b/rs/cli/src/commands/subnet/replace.rs @@ -3,9 +3,10 @@ use clap::{error::ErrorKind, Args}; use ic_types::PrincipalId; use itertools::Itertools; +use crate::exe::args::GlobalArgs; use crate::forum::ForumPostKind; use crate::submitter::{SubmissionParameters, Submitter}; -use crate::{auth::AuthRequirement, ctx::exe::ExecutableCommand, subnet_manager::SubnetTarget}; +use crate::{auth::AuthRequirement, exe::ExecutableCommand, subnet_manager::SubnetTarget}; #[derive(Args, Debug)] pub struct Replace { @@ -105,7 +106,7 @@ impl ExecutableCommand for Replace { } } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if !self.nodes.is_empty() && self.id.is_some() { cmd.error( ErrorKind::ArgumentConflict, diff --git a/rs/cli/src/commands/subnet/rescue.rs b/rs/cli/src/commands/subnet/rescue.rs index 6a68b7031..6fd5c851d 100644 --- a/rs/cli/src/commands/subnet/rescue.rs +++ b/rs/cli/src/commands/subnet/rescue.rs @@ -2,9 +2,10 @@ use clap::Args; use ic_types::PrincipalId; +use crate::exe::args::GlobalArgs; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -38,5 +39,5 @@ impl ExecutableCommand for Rescue { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/subnet/resize.rs b/rs/cli/src/commands/subnet/resize.rs index 1c81dd9c8..e75c57f45 100644 --- a/rs/cli/src/commands/subnet/resize.rs +++ b/rs/cli/src/commands/subnet/resize.rs @@ -3,9 +3,10 @@ use clap::Args; use ic_management_types::requests::SubnetResizeRequest; use ic_types::PrincipalId; +use crate::exe::args::GlobalArgs; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -79,5 +80,5 @@ impl ExecutableCommand for Resize { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/subnet/whatif.rs b/rs/cli/src/commands/subnet/whatif.rs index f40cb4d75..16cf451cd 100644 --- a/rs/cli/src/commands/subnet/whatif.rs +++ b/rs/cli/src/commands/subnet/whatif.rs @@ -1,9 +1,10 @@ +use crate::exe::args::GlobalArgs; use clap::Args; use ic_types::PrincipalId; use registry_canister::mutations::do_change_subnet_membership::ChangeSubnetMembershipPayload; use crate::auth::AuthRequirement; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::ExecutableCommand; #[derive(Args, Debug)] #[clap(visible_aliases = &["analyze", "analyze-decentralization", "decentralization", "whatif", "what-if"])] pub struct WhatifDecentralization { @@ -42,5 +43,5 @@ impl ExecutableCommand for WhatifDecentralization { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/update_authorized_subnets.rs b/rs/cli/src/commands/update_authorized_subnets.rs index bfea58193..ea6b14b09 100644 --- a/rs/cli/src/commands/update_authorized_subnets.rs +++ b/rs/cli/src/commands/update_authorized_subnets.rs @@ -2,11 +2,13 @@ use ic_canisters::cycles_minting::CyclesMintingCanisterWrapper; use indexmap::IndexMap; use std::{path::PathBuf, sync::Arc}; +use crate::{auth::AuthRequirement, exe::args::GlobalArgs, exe::ExecutableCommand}; use clap::{error::ErrorKind, Args}; use ic_management_types::Subnet; use ic_registry_subnet_type::SubnetType; use ic_types::PrincipalId; use itertools::Itertools; + use log::info; use crate::{ @@ -15,8 +17,6 @@ use crate::{ submitter::{SubmissionParameters, Submitter}, }; -use super::{AuthRequirement, ExecutableCommand}; - const DEFAULT_CANISTER_LIMIT: u64 = 60_000; const DEFAULT_STATE_SIZE_BYTES_LIMIT: u64 = 400 * 1024 * 1024 * 1024; // 400GB @@ -46,10 +46,10 @@ pub struct UpdateAuthorizedSubnets { impl ExecutableCommand for UpdateAuthorizedSubnets { fn require_auth(&self) -> AuthRequirement { - super::AuthRequirement::Neuron + AuthRequirement::Neuron } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if let Some(path) = &self.path { if !path.exists() { cmd.error(ErrorKind::InvalidValue, format!("Path `{}` not found", path.display())).exit() diff --git a/rs/cli/src/commands/update_unassigned_nodes.rs b/rs/cli/src/commands/update_unassigned_nodes.rs index 86c477048..6cfa5a36d 100644 --- a/rs/cli/src/commands/update_unassigned_nodes.rs +++ b/rs/cli/src/commands/update_unassigned_nodes.rs @@ -4,11 +4,11 @@ use clap::Args; use ic_canisters::registry::RegistryCanisterWrapper; use ic_types::PrincipalId; +use crate::auth::AuthRequirement; +use crate::exe::{ExecutableCommand, args::GlobalArgs}; use crate::forum::ForumPostKind; use crate::submitter::{SubmissionParameters, Submitter}; -use super::{AuthRequirement, ExecutableCommand}; - #[derive(Args, Debug)] pub struct UpdateUnassignedNodes { /// NNS subnet id @@ -53,5 +53,5 @@ impl ExecutableCommand for UpdateUnassignedNodes { .await } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/upgrade.rs b/rs/cli/src/commands/upgrade.rs index 5d511b5c8..e01a647d8 100644 --- a/rs/cli/src/commands/upgrade.rs +++ b/rs/cli/src/commands/upgrade.rs @@ -4,7 +4,8 @@ use regex::Regex; use serde_json::Value; use tokio::task::JoinHandle; -use super::{AuthRequirement, ExecutableCommand}; +use crate::auth::AuthRequirement; +use crate::exe::{ExecutableCommand, args::GlobalArgs}; #[derive(Args, Debug, Default)] pub struct Upgrade { @@ -155,5 +156,5 @@ impl ExecutableCommand for Upgrade { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/commands/version/mod.rs b/rs/cli/src/commands/version/mod.rs index 0d8710594..69ffefb53 100644 --- a/rs/cli/src/commands/version/mod.rs +++ b/rs/cli/src/commands/version/mod.rs @@ -1,7 +1,7 @@ use clap::Args; use crate::commands::version::revise::ReviseElectedVersions; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; pub(crate) mod revise; diff --git a/rs/cli/src/commands/version/revise/guest_os.rs b/rs/cli/src/commands/version/revise/guest_os.rs index 2de738ef2..86cec0ede 100644 --- a/rs/cli/src/commands/version/revise/guest_os.rs +++ b/rs/cli/src/commands/version/revise/guest_os.rs @@ -1,8 +1,9 @@ use clap::{error::ErrorKind, Args}; +use crate::exe::args::GlobalArgs; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -51,7 +52,7 @@ impl ExecutableCommand for GuestOs { .await } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if self.submission_parameters.forum_parameters.forum_post_link_mandatory().is_err() { cmd.error( ErrorKind::MissingRequiredArgument, diff --git a/rs/cli/src/commands/version/revise/host_os.rs b/rs/cli/src/commands/version/revise/host_os.rs index 3429d4370..b45a4a791 100644 --- a/rs/cli/src/commands/version/revise/host_os.rs +++ b/rs/cli/src/commands/version/revise/host_os.rs @@ -2,7 +2,8 @@ use clap::{error::ErrorKind, Args}; use crate::{ auth::AuthRequirement, - ctx::exe::ExecutableCommand, + exe::args::GlobalArgs, + exe::ExecutableCommand, forum::ForumPostKind, submitter::{SubmissionParameters, Submitter}, }; @@ -51,7 +52,7 @@ impl ExecutableCommand for HostOs { .await } - fn validate(&self, _args: &crate::commands::Args, cmd: &mut clap::Command) { + fn validate(&self, _args: &GlobalArgs, cmd: &mut clap::Command) { if self.submission_parameters.forum_parameters.forum_post_link_mandatory().is_err() { cmd.error( ErrorKind::MissingRequiredArgument, diff --git a/rs/cli/src/commands/version/revise/mod.rs b/rs/cli/src/commands/version/revise/mod.rs index 133d919c4..71d096268 100644 --- a/rs/cli/src/commands/version/revise/mod.rs +++ b/rs/cli/src/commands/version/revise/mod.rs @@ -1,6 +1,6 @@ use crate::commands::version::revise::guest_os::GuestOs; use crate::commands::version::revise::host_os::HostOs; -use crate::ctx::exe::impl_executable_command_for_enums; +use crate::exe::impl_executable_command_for_enums; use clap::Args; use ic_management_types::Artifact; diff --git a/rs/cli/src/commands/vote.rs b/rs/cli/src/commands/vote.rs index 64ea5bf9f..9ce5b1143 100644 --- a/rs/cli/src/commands/vote.rs +++ b/rs/cli/src/commands/vote.rs @@ -7,7 +7,8 @@ use ic_nns_governance::pb::v1::ProposalInfo; use log::info; use spinners::{Spinner, Spinners}; -use super::{AuthRequirement, ExecutableCommand}; +use crate::auth::AuthRequirement; +use crate::exe::{ExecutableCommand, args::GlobalArgs}; use crate::{ confirm::{ConfirmationModeOptions, HowToProceed}, desktop_notify::DesktopNotifier, @@ -164,5 +165,5 @@ impl ExecutableCommand for Vote { Ok(()) } - fn validate(&self, _args: &crate::commands::Args, _cmd: &mut clap::Command) {} + fn validate(&self, _args: &GlobalArgs, _cmd: &mut clap::Command) {} } diff --git a/rs/cli/src/ctx/mod.rs b/rs/cli/src/ctx/mod.rs index 21fc4ae88..eedc96b30 100644 --- a/rs/cli/src/ctx/mod.rs +++ b/rs/cli/src/ctx/mod.rs @@ -1,6 +1,5 @@ use std::{cell::RefCell, rc::Rc, sync::Arc}; -use exe::ExecutableCommand; use ic_canisters::{governance::GovernanceCanisterWrapper, IcAgentCanisterClient}; use ic_management_backend::{ health::HealthStatusQuerier, @@ -14,8 +13,8 @@ use log::warn; use crate::{ artifact_downloader::{ArtifactDownloader, ArtifactDownloaderImpl}, auth::{AuthOpts, AuthRequirement, Neuron}, - commands::{Args, IcAdminVersion}, cordoned_feature_fetcher::CordonedFeatureFetcher, + exe::{args::GlobalArgs, args::IcAdminVersion}, governance::GovernanceCanisterProposalExecutor, ic_admin::{IcAdmin, IcAdminImpl, IcAdminProposalExecutor}, runner::Runner, @@ -23,8 +22,6 @@ use crate::{ subnet_manager::SubnetManager, }; -pub mod exe; - #[cfg(test)] mod unit_tests; @@ -93,7 +90,7 @@ impl DreContext { // Method that will be called from `main.rs` and // will return real implementations of services - pub async fn from_args(args: &Args) -> anyhow::Result { + pub async fn from_args(args: &GlobalArgs, require_auth: AuthRequirement, neuron_override: Option) -> anyhow::Result { let store = Store::new(args.offline)?; let network = match store.is_offline() { false => ic_management_types::Network::new(args.network.clone(), &args.nns_urls) @@ -107,12 +104,12 @@ impl DreContext { args.auth_opts.clone(), args.neuron_id, args.verbose, - args.subcommands.require_auth(), + require_auth, args.ic_admin_version.clone(), store.cordoned_features_fetcher(args.cordoned_features_file.clone())?, store.health_client(&network)?, store, - args.neuron_override(), + neuron_override, ) .await } @@ -274,6 +271,7 @@ pub mod tests { auth::Neuron, auth::{AuthOpts, AuthRequirement, HsmOpts, HsmParams}, cordoned_feature_fetcher::CordonedFeatureFetcher, + exe::args::IcAdminVersion, ic_admin::IcAdmin, store::Store, }; @@ -299,7 +297,7 @@ pub mod tests { verbose_runner: true, artifact_downloader, neuron: RefCell::new(Some(neuron.clone())), - version: crate::commands::IcAdminVersion::Strict("Shouldn't reach this because of mock".to_string()), + version: IcAdminVersion::Strict("Shouldn't reach this because of mock".to_string()), neuron_opts: super::NeuronOpts { auth_opts: AuthOpts { private_key_pem: None, diff --git a/rs/cli/src/ctx/unit_tests.rs b/rs/cli/src/ctx/unit_tests.rs index 7eb5b7a84..02c14073e 100644 --- a/rs/cli/src/ctx/unit_tests.rs +++ b/rs/cli/src/ctx/unit_tests.rs @@ -12,7 +12,7 @@ use ic_management_backend::health::MockHealthStatusQuerier; use ic_management_types::Network; use itertools::Itertools; -use crate::{commands::IcAdminVersion, ctx::DreContext}; +use crate::{ctx::DreContext, exe::args::IcAdminVersion}; fn status_file_path() -> PathBuf { Store::new(true).unwrap().ic_admin_status_file_outer().unwrap() diff --git a/rs/cli/src/exe/args.rs b/rs/cli/src/exe/args.rs new file mode 100644 index 000000000..44d04ee47 --- /dev/null +++ b/rs/cli/src/exe/args.rs @@ -0,0 +1,73 @@ +use crate::auth::AuthOpts; +use clap::Parser; +use strum::Display; +use url::Url; + +#[derive(Parser, Debug)] +#[clap(version = env!("CARGO_PKG_VERSION"), about, author)] +pub struct GlobalArgs { + #[clap(flatten)] + pub(crate) auth_opts: AuthOpts, + + /// Neuron ID + #[clap(long, global = true, env = "NEURON_ID", visible_aliases = &["neuron", "proposer"])] + pub neuron_id: Option, + + /// Path to explicitly state ic-admin path to use + #[clap(long, global = true, env = "IC_ADMIN")] + pub ic_admin: Option, + + #[clap(long, global = true, env = "IC_ADMIN_VERSION", default_value = "from-governance", value_parser = clap::value_parser!(IcAdminVersion), help = r#"Specify the version of ic admin to use +Options: + 1. from-governance, governance, govn, g => same as governance canister + 2. default, d => strict default version, embedded at build time + 3. => specific commit"#)] + pub ic_admin_version: IcAdminVersion, + + #[clap( + long, + env = "NETWORK", + default_value = "mainnet", + help = r#"Specify the target network: + - "mainnet", + - "staging", + - "" +"# + )] + pub network: String, + + #[clap(long, env = "NNS_URLS", value_delimiter = ',', aliases = ["registry-url", "nns-url"], help = r#"NNS_URLs for target network, comma separated. +The argument is mandatory for testnets, and is optional for mainnet and staging"#)] + pub nns_urls: Vec, + + /// To print as much information as possible + #[clap(long, env = "VERBOSE", global = true)] + pub verbose: bool, + + /// Run the tool offline when possible, i.e., do not sync registry and public dashboard data before the run + /// + /// Useful for when the NNS or Public dashboard are unreachable + #[clap(long)] + pub offline: bool, + + /// Path to file which contains cordoned features + #[clap(long, global = true, visible_aliases = &["cf-file", "cfff"])] + pub cordoned_features_file: Option, +} + +#[derive(Debug, Display, Clone)] +pub enum IcAdminVersion { + FromGovernance, + Fallback, + Strict(String), +} + +impl From<&str> for IcAdminVersion { + fn from(value: &str) -> Self { + match value { + "from-governance" | "governance" | "g" | "govn" => Self::FromGovernance, + "fallback" | "f" => Self::Fallback, + s => Self::Strict(s.to_string()), + } + } +} diff --git a/rs/cli/src/ctx/exe.rs b/rs/cli/src/exe/mod.rs similarity index 88% rename from rs/cli/src/ctx/exe.rs rename to rs/cli/src/exe/mod.rs index 48c7a6471..b2414678a 100644 --- a/rs/cli/src/ctx/exe.rs +++ b/rs/cli/src/exe/mod.rs @@ -1,11 +1,12 @@ use crate::auth::AuthRequirement; use crate::ctx::DreContext; use clap::Command; +pub mod args; pub trait ExecutableCommand { fn require_auth(&self) -> AuthRequirement; - fn validate(&self, args: &crate::commands::Args, cmd: &mut Command); + fn validate(&self, args: &args::GlobalArgs, cmd: &mut Command); fn execute(&self, ctx: DreContext) -> impl std::future::Future>; @@ -17,8 +18,9 @@ pub trait ExecutableCommand { macro_rules! impl_executable_command_for_enums { ($str_name:ident, $($var:ident),*) => { use crate::ctx::DreContext; - use crate::ctx::exe::ExecutableCommand; + use crate::exe::ExecutableCommand; use crate::auth::AuthRequirement; + use crate::exe::args::GlobalArgs; use clap::{Subcommand, Command}; #[derive(Subcommand, Debug)] @@ -39,7 +41,7 @@ macro_rules! impl_executable_command_for_enums { } } - fn validate(&self, args: &crate::commands::Args, cmd: &mut Command) { + fn validate(&self, args: &GlobalArgs, cmd: &mut Command) { match &self { $(Subcommands::$var(variant) => variant.validate(args, cmd),)* } @@ -68,7 +70,7 @@ macro_rules! impl_executable_command_for_enums { // cmd.error(ErrorKind::MissingRequiredArgument, "Neuron ID is required for this command.").exit(); // } // ``` - fn validate(&self, args: &crate::commands::Args, cmd: &mut Command) { + fn validate(&self, args: &GlobalArgs, cmd: &mut Command) { self.subcommands.validate(args, cmd) } diff --git a/rs/cli/src/lib.rs b/rs/cli/src/lib.rs index 793f0d779..6878175b3 100644 --- a/rs/cli/src/lib.rs +++ b/rs/cli/src/lib.rs @@ -5,6 +5,7 @@ mod confirm; mod cordoned_feature_fetcher; pub mod ctx; mod desktop_notify; +pub mod exe; mod forum; mod governance; mod ic_admin; diff --git a/rs/cli/src/main.rs b/rs/cli/src/main.rs index eeeff9b77..b3c4a489e 100644 --- a/rs/cli/src/main.rs +++ b/rs/cli/src/main.rs @@ -2,12 +2,11 @@ use clap::CommandFactory; use clap::Parser; use dotenv::dotenv; use dre::commands::{ - self, + main_command::{MainCommand, Subcommands}, upgrade::{UpdateStatus, Upgrade}, - Args, }; -use dre::ctx::exe::ExecutableCommand; use dre::ctx::DreContext; +use dre::exe::ExecutableCommand; use log::{info, warn}; #[tokio::main] @@ -18,12 +17,12 @@ async fn main() -> anyhow::Result<()> { dotenv().ok(); - let args = Args::parse(); + let args = MainCommand::parse(); - let mut cmd = Args::command(); - args.validate(&args, &mut cmd); + let mut cmd = MainCommand::command(); + args.validate(&args.global_args, &mut cmd); - if let commands::Subcommands::Upgrade(upgrade) = args.subcommands { + if let Subcommands::Upgrade(upgrade) = args.subcommands { let response = upgrade.run().await?; match response { UpdateStatus::NoUpdate => info!("Running the latest version"), @@ -33,7 +32,7 @@ async fn main() -> anyhow::Result<()> { return Ok(()); } - let ctx = DreContext::from_args(&args).await?; + let ctx = DreContext::from_args(&args.global_args, args.subcommands.require_auth(), args.neuron_override()).await?; let r = args.execute(ctx).await; diff --git a/rs/cli/src/store.rs b/rs/cli/src/store.rs index 5786307ce..5097a1fcf 100644 --- a/rs/cli/src/store.rs +++ b/rs/cli/src/store.rs @@ -14,8 +14,8 @@ use std::{io::Read, path::PathBuf, sync::Arc, time::Duration}; use crate::{ auth::Neuron, - commands::IcAdminVersion, cordoned_feature_fetcher::{CordonedFeatureFetcher, CordonedFeatureFetcherImpl}, + exe::args::IcAdminVersion, ic_admin::IcAdminImpl, }; diff --git a/rs/cli/src/unit_tests/update_unassigned_nodes.rs b/rs/cli/src/unit_tests/update_unassigned_nodes.rs index 11091e28c..a85d350e2 100644 --- a/rs/cli/src/unit_tests/update_unassigned_nodes.rs +++ b/rs/cli/src/unit_tests/update_unassigned_nodes.rs @@ -5,7 +5,7 @@ use crate::auth::Neuron; use crate::commands::update_unassigned_nodes::UpdateUnassignedNodes; use crate::confirm::ConfirmationModeOptions; use crate::cordoned_feature_fetcher::MockCordonedFeatureFetcher; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::ExecutableCommand; use crate::forum::ForumParameters; use crate::ic_admin::MockIcAdmin; use crate::submitter::SubmissionParameters; diff --git a/rs/cli/src/unit_tests/version.rs b/rs/cli/src/unit_tests/version.rs index bf46c9358..a5df75040 100644 --- a/rs/cli/src/unit_tests/version.rs +++ b/rs/cli/src/unit_tests/version.rs @@ -1,5 +1,5 @@ use crate::confirm::ConfirmationModeOptions; -use crate::ctx::exe::ExecutableCommand; +use crate::exe::ExecutableCommand; use crate::forum::ForumParameters; use crate::submitter::SubmissionParameters; use indexmap::IndexMap;