diff --git a/CHANGELOG.md b/CHANGELOG.md index b8d986d185..f9c9402bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -193,16 +193,17 @@ When installing a new WASM module to a canister, DFX will now wait for the updat `dfx config` has been removed. Please update Bash scripts to use `jq`, PowerShell scripts to use `ConvertTo-Json`, nushell scripts to use `to json`, etc. -### feat!: move all the flags to the end +### feat: move all the flags to the end -Command flags have been moved to a more traditional location; they are no longer positioned per subcommand, but instead are all positioned after the final subcommand. In prior versions, a command might look like: +Command flags have been moved to a more traditional location; they are no longer positioned per subcommand, but instead are able to be all positioned after the final subcommand. In prior versions, a command might look like: ```bash dfx --identity alice canister --network ic --wallet "$WALLET" create --all ``` -This command should now read: +This command can now be written: ```bash dfx canister create --all --network ic --wallet "$WALLET" --identity alice ``` +The old syntax is still available, though, so you don't need to migrate your scripts. ### feat!: changed update-settings syntax diff --git a/e2e/tests-dfx/subcommands.bash b/e2e/tests-dfx/subcommands.bash new file mode 100644 index 0000000000..70fcbc2b16 --- /dev/null +++ b/e2e/tests-dfx/subcommands.bash @@ -0,0 +1,25 @@ +#!/usr/bin/env bats + +load ../utils/_ + +setup() { + standard_setup + + dfx_new +} + +teardown() { + dfx_stop + + standard_teardown +} + +@test "--identity and --network are stil accepted as prefix" { + install_asset whoami + dfx_start + dfx deploy + dfx identity new alice --disable-encryption + assert_command dfx --identity alice canister --network local call whoami whoami + assert_match "$(dfx --identity alice identity get-principal)" + assert_match "$(dfx identity get-principal --identity alice)" +} diff --git a/src/dfx/src/commands/bootstrap.rs b/src/dfx/src/commands/bootstrap.rs index 896b34d364..995c238cdf 100644 --- a/src/dfx/src/commands/bootstrap.rs +++ b/src/dfx/src/commands/bootstrap.rs @@ -6,6 +6,7 @@ use crate::lib::network::network_descriptor::NetworkDescriptor; use crate::lib::provider::{create_network_descriptor, LocalBindDetermination}; use crate::util::get_reusable_socket_addr; use crate::util::network::get_replica_urls; +use crate::NetworkOpt; use anyhow::{anyhow, Context, Error}; use clap::Parser; @@ -24,12 +25,8 @@ pub struct BootstrapOpts { #[clap(long)] port: Option, - /// Override the compute network to connect to. By default, the local network is used. - /// A valid URL (starting with `http:` or `https:`) can be used here, and a special - /// ephemeral network will be created specifically for this request. E.g. - /// "http://localhost:12345/" is a valid network name. - #[clap(long)] - network: Option, + #[clap(flatten)] + network: NetworkOpt, /// Specifies the maximum number of seconds that the bootstrap server /// will wait for upstream requests to complete. Defaults to 30. @@ -50,7 +47,7 @@ pub fn exec( let network_descriptor = create_network_descriptor( env.get_config(), env.get_networks_config(), - network, + network.network, Some(env.get_logger().clone()), LocalBindDetermination::AsConfigured, )?; diff --git a/src/dfx/src/commands/build.rs b/src/dfx/src/commands/build.rs index 1e3f92f1b9..ea22824178 100644 --- a/src/dfx/src/commands/build.rs +++ b/src/dfx/src/commands/build.rs @@ -4,6 +4,7 @@ use crate::lib::error::DfxResult; use crate::lib::models::canister::CanisterPool; use crate::lib::models::canister_id_store::CanisterIdStore; use crate::lib::provider::create_agent_environment; +use crate::NetworkOpt; use clap::Parser; @@ -22,16 +23,12 @@ pub struct CanisterBuildOpts { #[clap(long)] check: bool, - /// Override the compute network to connect to. By default, the local network is used. - /// A valid URL (starting with `http:` or `https:`) can be used here, and a special - /// ephemeral network will be created specifically for this request. E.g. - /// "http://localhost:12345/" is a valid network name. - #[clap(long)] - network: Option, + #[clap(flatten)] + network: NetworkOpt, } pub fn exec(env: &dyn Environment, opts: CanisterBuildOpts) -> DfxResult { - let env = create_agent_environment(env, opts.network)?; + let env = create_agent_environment(env, opts.network.network)?; let logger = env.get_logger(); diff --git a/src/dfx/src/commands/cache/mod.rs b/src/dfx/src/commands/cache/mod.rs index 321ac19388..d2fd976b22 100644 --- a/src/dfx/src/commands/cache/mod.rs +++ b/src/dfx/src/commands/cache/mod.rs @@ -1,5 +1,5 @@ +use crate::lib::environment::Environment; use crate::lib::error::DfxResult; -use crate::{init_env, BaseOpts}; use clap::Parser; @@ -11,24 +11,24 @@ mod show; /// Manages the dfx version cache. #[derive(Parser)] #[clap(name("cache"))] -pub struct CacheCommand { +pub struct CacheOpts { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] pub enum SubCommand { - Delete(BaseOpts), - Install(BaseOpts), - List(BaseOpts), - Show(BaseOpts), + Delete(delete::CacheDeleteOpts), + Install(install::CacheInstall), + List(list::CacheListOpts), + Show(show::CacheShowOpts), } -pub fn dispatch(cmd: CacheCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::Delete(v) => delete::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::Install(v) => install::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::List(v) => list::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::Show(v) => show::exec(&init_env(v.env_opts)?, v.command_opts), +pub fn exec(env: &dyn Environment, opts: CacheOpts) -> DfxResult { + match opts.subcmd { + SubCommand::Delete(v) => delete::exec(env, v), + SubCommand::Install(v) => install::exec(env, v), + SubCommand::List(v) => list::exec(env, v), + SubCommand::Show(v) => show::exec(env, v), } } diff --git a/src/dfx/src/commands/canister/mod.rs b/src/dfx/src/commands/canister/mod.rs index 99b5ab7a94..1bb15a7898 100644 --- a/src/dfx/src/commands/canister/mod.rs +++ b/src/dfx/src/commands/canister/mod.rs @@ -1,14 +1,11 @@ -use crate::init_env; - use crate::lib::error::DfxResult; use crate::lib::identity::identity_utils::call_sender; use crate::lib::provider::create_agent_environment; +use crate::{lib::environment::Environment, NetworkOpt}; -use clap::{Args, Parser, Subcommand}; +use clap::{Parser, Subcommand}; use tokio::runtime::Runtime; -use super::NetworkOpts; - mod call; mod create; mod delete; @@ -26,109 +23,67 @@ mod stop; mod uninstall_code; mod update_settings; -#[derive(Args)] -pub struct CanisterOpts { +/// Manages canisters deployed on a network replica. +#[derive(Parser)] +#[clap(name("canister"))] +pub struct CanisterOpts { #[clap(flatten)] - network_opts: NetworkOpts, + network: NetworkOpt, /// Specify a wallet canister id to perform the call. /// If none specified, defaults to use the selected Identity's wallet canister. - #[clap(long)] + #[clap(long, global(true))] wallet: Option, -} -/// Manages canisters deployed on a network replica. -#[derive(Parser)] -#[clap(name("canister"))] -pub struct CanisterCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Subcommand)] -enum SubCommand { - Call(CanisterOpts), - Create(CanisterOpts), - Delete(CanisterOpts), - DepositCycles(CanisterOpts), - Id(CanisterOpts), - Info(CanisterOpts), - Install(CanisterOpts), - Metadata(CanisterOpts), - RequestStatus(CanisterOpts), - Send(CanisterOpts), - Sign(CanisterOpts), - Start(CanisterOpts), - Status(CanisterOpts), - Stop(CanisterOpts), - UninstallCode(CanisterOpts), - UpdateSettings(CanisterOpts), +pub enum SubCommand { + Call(call::CanisterCallOpts), + Create(create::CanisterCreateOpts), + Delete(delete::CanisterDeleteOpts), + DepositCycles(deposit_cycles::DepositCyclesOpts), + Id(id::CanisterIdOpts), + Info(info::InfoOpts), + Install(install::CanisterInstallOpts), + Metadata(metadata::CanisterMetadataOpts), + RequestStatus(request_status::RequestStatusOpts), + Send(send::CanisterSendOpts), + Sign(sign::CanisterSignOpts), + Start(start::CanisterStartOpts), + Status(status::CanisterStatusOpts), + Stop(stop::CanisterStopOpts), + UninstallCode(uninstall_code::UninstallCodeOpts), + UpdateSettings(update_settings::UpdateSettingsOpts), } -macro_rules! with_env { - ($opts:expr, |$env:pat, $v:pat, $call_sender:pat_param| $e:expr) => {{ - let CanisterOpts { - network_opts: NetworkOpts { base_opts, network }, - wallet, - } = $opts; - let env = init_env(base_opts.env_opts)?; - let agent_env = create_agent_environment(&env, network)?; - let $v = base_opts.command_opts; - let runtime = Runtime::new().expect("Unable to create a runtime"); - runtime.block_on(async { - let $call_sender = call_sender(&agent_env, &wallet).await?; - let $env = agent_env; - $e.await?; - Ok(()) - }) - }}; -} +pub fn exec(env: &dyn Environment, opts: CanisterOpts) -> DfxResult { + let agent_env = create_agent_environment(env, opts.network.network)?; + let runtime = Runtime::new().expect("Unable to create a runtime"); -pub fn dispatch(cmd: CanisterCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::Call(v) => { - with_env!(v, |env, v, call_sender| call::exec(&env, v, &call_sender)) - } - SubCommand::Create(v) => { - with_env!(v, |env, v, call_sender| create::exec(&env, v, &call_sender)) - } - SubCommand::Delete(v) => { - with_env!(v, |env, v, call_sender| delete::exec(&env, v, &call_sender)) - } - SubCommand::DepositCycles(v) => with_env!(v, |env, v, call_sender| { - deposit_cycles::exec(&env, v, &call_sender) - }), - SubCommand::Id(v) => with_env!(v, |env, v, _| id::exec(&env, v)), - SubCommand::Install(v) => with_env!(v, |env, v, call_sender| { - install::exec(&env, v, &call_sender) - }), - SubCommand::Info(v) => with_env!(v, |env, v, _| info::exec(&env, v)), - SubCommand::Metadata(v) => { - with_env!(v, |env, v, _| metadata::exec(&env, v)) - } - SubCommand::RequestStatus(v) => { - with_env!(v, |env, v, _| request_status::exec(&env, v)) - } - SubCommand::Send(v) => { - with_env!(v, |env, v, call_sender| send::exec(&env, v, &call_sender)) - } - SubCommand::Sign(v) => { - with_env!(v, |env, v, call_sender| sign::exec(&env, v, &call_sender)) - } - SubCommand::Start(v) => { - with_env!(v, |env, v, call_sender| start::exec(&env, v, &call_sender)) - } - SubCommand::Status(v) => { - with_env!(v, |env, v, call_sender| status::exec(&env, v, &call_sender)) - } - SubCommand::Stop(v) => { - with_env!(v, |env, v, call_sender| stop::exec(&env, v, &call_sender)) + runtime.block_on(async { + let call_sender = call_sender(&agent_env, &opts.wallet).await?; + match opts.subcmd { + SubCommand::Call(v) => call::exec(&agent_env, v, &call_sender).await, + SubCommand::Create(v) => create::exec(&agent_env, v, &call_sender).await, + SubCommand::Delete(v) => delete::exec(&agent_env, v, &call_sender).await, + SubCommand::DepositCycles(v) => deposit_cycles::exec(&agent_env, v, &call_sender).await, + SubCommand::Id(v) => id::exec(&agent_env, v).await, + SubCommand::Install(v) => install::exec(&agent_env, v, &call_sender).await, + SubCommand::Info(v) => info::exec(&agent_env, v).await, + SubCommand::Metadata(v) => metadata::exec(&agent_env, v).await, + SubCommand::RequestStatus(v) => request_status::exec(&agent_env, v).await, + SubCommand::Send(v) => send::exec(&agent_env, v, &call_sender).await, + SubCommand::Sign(v) => sign::exec(&agent_env, v, &call_sender).await, + SubCommand::Start(v) => start::exec(&agent_env, v, &call_sender).await, + SubCommand::Status(v) => status::exec(&agent_env, v, &call_sender).await, + SubCommand::Stop(v) => stop::exec(&agent_env, v, &call_sender).await, + SubCommand::UninstallCode(v) => uninstall_code::exec(&agent_env, v, &call_sender).await, + SubCommand::UpdateSettings(v) => { + update_settings::exec(&agent_env, v, &call_sender).await + } } - SubCommand::UninstallCode(v) => with_env!(v, |env, v, call_sender| { - uninstall_code::exec(&env, v, &call_sender) - }), - SubCommand::UpdateSettings(v) => with_env!(v, |env, v, call_sender| { - update_settings::exec(&env, v, &call_sender) - }), - } + }) } diff --git a/src/dfx/src/commands/deploy.rs b/src/dfx/src/commands/deploy.rs index a2ae4b3d28..a9d253980d 100644 --- a/src/dfx/src/commands/deploy.rs +++ b/src/dfx/src/commands/deploy.rs @@ -6,6 +6,7 @@ use crate::lib::root_key::fetch_root_key_if_needed; use crate::lib::{environment::Environment, identity::Identity, named_canister}; use crate::util::clap::validators::cycle_amount_validator; use crate::util::expiry_duration; +use crate::NetworkOpt; use std::collections::BTreeMap; use crate::lib::canister_info::CanisterInfo; @@ -52,12 +53,8 @@ pub struct DeployOpts { #[clap(long)] upgrade_unchanged: bool, - /// Override the compute network to connect to. By default, the local network is used. - /// A valid URL (starting with `http:` or `https:`) can be used here, and a special - /// ephemeral network will be created specifically for this request. E.g. - /// "http://localhost:12345/" is a valid network name. - #[clap(long)] - network: Option, + #[clap(flatten)] + network: NetworkOpt, /// Specifies the initial cycle balance to deposit into the newly created canister. /// The specified amount needs to take the canister create fee into account. @@ -77,7 +74,7 @@ pub struct DeployOpts { } pub fn exec(env: &dyn Environment, opts: DeployOpts) -> DfxResult { - let env = create_agent_environment(env, opts.network)?; + let env = create_agent_environment(env, opts.network.network)?; let timeout = expiry_duration(); let canister_name = opts.canister_name.as_deref(); diff --git a/src/dfx/src/commands/diagnose.rs b/src/dfx/src/commands/diagnose.rs index 65785fa265..2621f7c565 100644 --- a/src/dfx/src/commands/diagnose.rs +++ b/src/dfx/src/commands/diagnose.rs @@ -1,21 +1,24 @@ use clap::Parser; use tokio::runtime::Runtime; -use crate::lib::{ - environment::Environment, error::DfxResult, migrate::migrate, - provider::create_agent_environment, +use crate::{ + lib::{ + environment::Environment, error::DfxResult, migrate::migrate, + provider::create_agent_environment, + }, + NetworkOpt, }; /// Detects known problems in the current environment caused by upgrading DFX, and suggests commands to fix them. /// These commands can be batch-run automatically via `dfx fix`. #[derive(Parser)] pub struct DiagnoseOpts { - #[clap(long)] - network: Option, + #[clap(flatten)] + network: NetworkOpt, } pub fn exec(env: &dyn Environment, opts: DiagnoseOpts) -> DfxResult { - let env = create_agent_environment(env, opts.network)?; + let env = create_agent_environment(env, opts.network.network)?; let runtime = Runtime::new().expect("Unable to create a runtime"); runtime.block_on(async { migrate(&env, env.get_network_descriptor(), false).await })?; Ok(()) diff --git a/src/dfx/src/commands/fix.rs b/src/dfx/src/commands/fix.rs index 5f536ab86b..e76188980c 100644 --- a/src/dfx/src/commands/fix.rs +++ b/src/dfx/src/commands/fix.rs @@ -1,22 +1,24 @@ use clap::Parser; use tokio::runtime::Runtime; -use crate::lib::{ - environment::Environment, error::DfxResult, migrate::migrate, - provider::create_agent_environment, +use crate::{ + lib::{ + environment::Environment, error::DfxResult, migrate::migrate, + provider::create_agent_environment, + }, + NetworkOpt, }; /// Applies one-time fixes for known problems in the current environment caused by upgrading DFX. /// Makes no changes that would not have been suggested by `dfx diagnose`. #[derive(Parser)] pub struct FixOpts { - #[clap(long)] - /// Override the network to connect to. By default the local network is used. - network: Option, + #[clap(flatten)] + network: NetworkOpt, } pub fn exec(env: &dyn Environment, opts: FixOpts) -> DfxResult { - let env = create_agent_environment(env, opts.network)?; + let env = create_agent_environment(env, opts.network.network)?; let runtime = Runtime::new().expect("Failed to create runtime"); runtime.block_on(async { migrate(&env, env.get_network_descriptor(), true).await })?; Ok(()) diff --git a/src/dfx/src/commands/identity/mod.rs b/src/dfx/src/commands/identity/mod.rs index 8c0fabf681..723883a31e 100644 --- a/src/dfx/src/commands/identity/mod.rs +++ b/src/dfx/src/commands/identity/mod.rs @@ -1,9 +1,9 @@ -use crate::{init_env, lib::error::DfxResult}; +use crate::lib::environment::Environment; +use crate::lib::error::DfxResult; +use crate::NetworkOpt; use clap::Parser; -use super::NetworkOpts; - mod deploy_wallet; mod export; mod get_wallet; @@ -21,68 +21,43 @@ mod whoami; /// Setting an identity enables you to test user-based access controls. #[derive(Parser)] #[clap(name("identity"))] -pub struct IdentityCommand { +pub struct IdentityOpts { + #[clap(flatten)] + network: NetworkOpt, + #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - DeployWallet(NetworkOpts), - Export(NetworkOpts), - GetWallet(NetworkOpts), - Import(NetworkOpts), - List(NetworkOpts), - New(NetworkOpts), - GetPrincipal(NetworkOpts), - Remove(NetworkOpts), - Rename(NetworkOpts), - SetWallet(NetworkOpts), - Use(NetworkOpts), - Whoami(NetworkOpts), + DeployWallet(deploy_wallet::DeployWalletOpts), + Export(export::ExportOpts), + GetWallet(get_wallet::GetWalletOpts), + Import(import::ImportOpts), + List(list::ListOpts), + New(new::NewIdentityOpts), + GetPrincipal(principal::GetPrincipalOpts), + Remove(remove::RemoveOpts), + Rename(rename::RenameOpts), + SetWallet(set_wallet::SetWalletOpts), + Use(r#use::UseOpts), + Whoami(whoami::WhoAmIOpts), } -pub fn dispatch(cmd: IdentityCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::DeployWallet(v) => deploy_wallet::exec( - &init_env(v.base_opts.env_opts)?, - v.base_opts.command_opts, - v.network, - ), - SubCommand::Export(v) => { - export::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::GetWallet(v) => get_wallet::exec( - &init_env(v.base_opts.env_opts)?, - v.base_opts.command_opts, - v.network, - ), - SubCommand::List(v) => { - list::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::New(v) => new::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts), - SubCommand::GetPrincipal(v) => { - principal::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::Import(v) => { - import::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::Remove(v) => { - remove::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::Rename(v) => { - rename::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::SetWallet(v) => set_wallet::exec( - &init_env(v.base_opts.env_opts)?, - v.base_opts.command_opts, - v.network, - ), - SubCommand::Use(v) => { - r#use::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } - SubCommand::Whoami(v) => { - whoami::exec(&init_env(v.base_opts.env_opts)?, v.base_opts.command_opts) - } +pub fn exec(env: &dyn Environment, opts: IdentityOpts) -> DfxResult { + match opts.subcmd { + SubCommand::DeployWallet(v) => deploy_wallet::exec(env, v, opts.network.network), + SubCommand::Export(v) => export::exec(env, v), + SubCommand::GetWallet(v) => get_wallet::exec(env, v, opts.network.network), + SubCommand::List(v) => list::exec(env, v), + SubCommand::New(v) => new::exec(env, v), + SubCommand::GetPrincipal(v) => principal::exec(env, v), + SubCommand::Import(v) => import::exec(env, v), + SubCommand::Remove(v) => remove::exec(env, v), + SubCommand::Rename(v) => rename::exec(env, v), + SubCommand::SetWallet(v) => set_wallet::exec(env, v, opts.network.network), + SubCommand::Use(v) => r#use::exec(env, v), + SubCommand::Whoami(v) => whoami::exec(env, v), } } diff --git a/src/dfx/src/commands/info/mod.rs b/src/dfx/src/commands/info/mod.rs index 693abd0238..9eb699de15 100644 --- a/src/dfx/src/commands/info/mod.rs +++ b/src/dfx/src/commands/info/mod.rs @@ -1,8 +1,9 @@ mod webserver_port; use crate::commands::info::webserver_port::get_webserver_port; +use crate::lib::error::DfxResult; use crate::lib::info; -use crate::{DfxResult, Environment}; +use crate::Environment; use clap::Parser; #[derive(clap::ValueEnum, Clone, Debug)] diff --git a/src/dfx/src/commands/info/webserver_port.rs b/src/dfx/src/commands/info/webserver_port.rs index 59ce45908b..7dfc3d9f5f 100644 --- a/src/dfx/src/commands/info/webserver_port.rs +++ b/src/dfx/src/commands/info/webserver_port.rs @@ -1,5 +1,6 @@ +use crate::lib::error::DfxResult; use crate::lib::provider::{create_network_descriptor, LocalBindDetermination}; -use crate::{DfxResult, Environment}; +use crate::Environment; pub(crate) fn get_webserver_port(env: &dyn Environment) -> DfxResult { let port = create_network_descriptor( diff --git a/src/dfx/src/commands/ledger/mod.rs b/src/dfx/src/commands/ledger/mod.rs index 430603195e..3ea6f5743d 100644 --- a/src/dfx/src/commands/ledger/mod.rs +++ b/src/dfx/src/commands/ledger/mod.rs @@ -1,5 +1,4 @@ -use crate::init_env; - +use crate::lib::environment::Environment; use crate::lib::error::DfxResult; use crate::lib::ledger_types::{ AccountIdBlob, BlockHeight, Memo, NotifyCreateCanisterArg, NotifyCreateCanisterResult, @@ -11,6 +10,7 @@ use crate::lib::nns_types::icpts::ICPTs; use crate::lib::provider::create_agent_environment; use crate::lib::waiter::waiter_with_timeout; use crate::util::expiry_duration; +use crate::NetworkOpt; use anyhow::{anyhow, bail, Context}; use candid::Principal; @@ -20,13 +20,10 @@ use fn_error_context::context; use garcon::{Delay, Waiter}; use ic_agent::agent_error::HttpErrorPayload; use ic_agent::{Agent, AgentError}; - use std::str::FromStr; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::runtime::Runtime; -use super::NetworkOpts; - const TRANSFER_METHOD: &str = "transfer"; const NOTIFY_TOP_UP_METHOD: &str = "notify_top_up"; const NOTIFY_CREATE_METHOD: &str = "notify_create_canister"; @@ -42,47 +39,39 @@ mod transfer; /// Ledger commands. #[derive(Parser)] #[clap(name("ledger"))] -pub struct LedgerCommand { +pub struct LedgerOpts { + #[clap(flatten)] + network: NetworkOpt, + #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - AccountId(NetworkOpts), - Balance(NetworkOpts), - CreateCanister(NetworkOpts), - FabricateCycles(NetworkOpts), - Notify(NetworkOpts), - TopUp(NetworkOpts), - Transfer(NetworkOpts), + AccountId(account_id::AccountIdOpts), + Balance(balance::BalanceOpts), + CreateCanister(create_canister::CreateCanisterOpts), + FabricateCycles(fabricate_cycles::FabricateCyclesOpts), + Notify(notify::NotifyOpts), + TopUp(top_up::TopUpOpts), + Transfer(transfer::TransferOpts), } -macro_rules! with_env { - ($opts:expr, |$env:ident, $v:ident| $e:expr) => {{ - let NetworkOpts { base_opts, network } = $opts; - let env = init_env(base_opts.env_opts)?; - let $env = create_agent_environment(&env, network)?; - let runtime = Runtime::new().expect("Unable to create a runtime"); - let $v = base_opts.command_opts; - runtime.block_on($e) - }}; -} - -pub fn dispatch(cmd: LedgerCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::AccountId(v) => with_env!(v, |env, v| account_id::exec(&env, v)), - SubCommand::Balance(v) => with_env!(v, |env, v| balance::exec(&env, v)), - SubCommand::CreateCanister(v) => { - with_env!(v, |env, v| create_canister::exec(&env, v)) +pub fn exec(env: &dyn Environment, opts: LedgerOpts) -> DfxResult { + let agent_env = create_agent_environment(env, opts.network.network)?; + let runtime = Runtime::new().expect("Unable to create a runtime"); + runtime.block_on(async { + match opts.subcmd { + SubCommand::AccountId(v) => account_id::exec(&agent_env, v).await, + SubCommand::Balance(v) => balance::exec(&agent_env, v).await, + SubCommand::CreateCanister(v) => create_canister::exec(&agent_env, v).await, + SubCommand::FabricateCycles(v) => fabricate_cycles::exec(&agent_env, v).await, + SubCommand::Notify(v) => notify::exec(&agent_env, v).await, + SubCommand::TopUp(v) => top_up::exec(&agent_env, v).await, + SubCommand::Transfer(v) => transfer::exec(&agent_env, v).await, } - SubCommand::FabricateCycles(v) => { - with_env!(v, |env, v| fabricate_cycles::exec(&env, v)) - } - SubCommand::Notify(v) => with_env!(v, |env, v| notify::exec(&env, v)), - SubCommand::TopUp(v) => with_env!(v, |env, v| top_up::exec(&env, v)), - SubCommand::Transfer(v) => with_env!(v, |env, v| transfer::exec(&env, v)), - } + }) } #[context("Failed to determine icp amount from supplied arguments.")] diff --git a/src/dfx/src/commands/mod.rs b/src/dfx/src/commands/mod.rs index bc8728bedf..340a209767 100644 --- a/src/dfx/src/commands/mod.rs +++ b/src/dfx/src/commands/mod.rs @@ -1,7 +1,7 @@ +use crate::lib::environment::Environment; use crate::lib::error::DfxResult; -use crate::{init_env, BaseOpts}; -use clap::{Args, Subcommand}; +use clap::Subcommand; mod bootstrap; mod build; @@ -31,81 +31,62 @@ mod wallet; #[derive(Subcommand)] pub enum Command { - Bootstrap(BaseOpts), - Build(BaseOpts), - Cache(cache::CacheCommand), - Canister(canister::CanisterCommand), - Deploy(BaseOpts), - Diagnose(BaseOpts), - Fix(BaseOpts), - Generate(BaseOpts), - Identity(identity::IdentityCommand), - Info(BaseOpts), + Bootstrap(bootstrap::BootstrapOpts), + Build(build::CanisterBuildOpts), + Cache(cache::CacheOpts), + Canister(canister::CanisterOpts), + Deploy(deploy::DeployOpts), + Diagnose(diagnose::DiagnoseOpts), + Fix(fix::FixOpts), + Generate(generate::GenerateOpts), + Identity(identity::IdentityOpts), + Info(info::InfoOpts), #[clap(name("_language-service"))] - LanguageServices(BaseOpts), - Ledger(ledger::LedgerCommand), - New(BaseOpts), + LanguageServices(language_service::LanguageServiceOpts), + Ledger(ledger::LedgerOpts), + New(new::NewOpts), #[clap(hide(true))] - Nns(nns::NnsCommand), - Ping(BaseOpts), - Quickstart(BaseOpts), - Remote(remote::RemoteCommand), - Replica(BaseOpts), - Schema(BaseOpts), + Nns(nns::NnsOpts), + Ping(ping::PingOpts), + Quickstart, + Remote(remote::RemoteOpts), + Replica(replica::ReplicaOpts), + Schema(schema::SchemaOpts), #[clap(hide(true))] - Sns(sns::SnsCommand), - Start(BaseOpts), - Stop(BaseOpts), - Toolchain(toolchain::ToolchainCommand), - Upgrade(BaseOpts), - Wallet(wallet::WalletCommand), + Sns(sns::SnsOpts), + Start(start::StartOpts), + Stop(stop::StopOpts), + Toolchain(toolchain::ToolchainOpts), + Upgrade(upgrade::UpgradeOpts), + Wallet(wallet::WalletOpts), } -#[derive(Args)] -pub struct Empty; - -#[derive(Args)] -pub struct NetworkOpts { - #[clap(flatten)] - base_opts: BaseOpts, - /// Override the compute network to connect to. By default, the local network is used. - /// - /// A valid URL (starting with `http:` or `https:`) can be used here, and a special - /// ephemeral network will be created specifically for this request. E.g. - /// "http://localhost:12345/" is a valid network name. - #[clap(long)] - network: Option, -} - -pub fn dispatch(cmd: Command) -> DfxResult { +pub fn exec(env: &dyn Environment, cmd: Command) -> DfxResult { match cmd { - Command::Cache(v) => cache::dispatch(v), - Command::Canister(v) => canister::dispatch(v), - Command::Identity(v) => identity::dispatch(v), - Command::Ledger(v) => ledger::dispatch(v), - Command::Nns(v) => nns::dispatch(v), - Command::Remote(v) => remote::dispatch(v), - Command::Sns(v) => sns::dispatch(v), - Command::Toolchain(v) => toolchain::dispatch(v), - Command::Wallet(v) => wallet::dispatch(v), - - Command::Bootstrap(v) => bootstrap::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Build(v) => build::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Deploy(v) => deploy::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Diagnose(v) => diagnose::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Fix(v) => fix::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Generate(v) => generate::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Info(v) => info::exec(&init_env(v.env_opts)?, v.command_opts), - Command::LanguageServices(v) => { - language_service::exec(&init_env(v.env_opts)?, v.command_opts) - } - Command::New(v) => new::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Ping(v) => ping::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Quickstart(v) => quickstart::exec(&init_env(v.env_opts)?), - Command::Replica(v) => replica::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Schema(v) => schema::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Start(v) => start::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Stop(v) => stop::exec(&init_env(v.env_opts)?, v.command_opts), - Command::Upgrade(v) => upgrade::exec(&init_env(v.env_opts)?, v.command_opts), + Command::Bootstrap(v) => bootstrap::exec(env, v), + Command::Build(v) => build::exec(env, v), + Command::Cache(v) => cache::exec(env, v), + Command::Canister(v) => canister::exec(env, v), + Command::Deploy(v) => deploy::exec(env, v), + Command::Diagnose(v) => diagnose::exec(env, v), + Command::Fix(v) => fix::exec(env, v), + Command::Generate(v) => generate::exec(env, v), + Command::Identity(v) => identity::exec(env, v), + Command::Info(v) => info::exec(env, v), + Command::LanguageServices(v) => language_service::exec(env, v), + Command::Ledger(v) => ledger::exec(env, v), + Command::New(v) => new::exec(env, v), + Command::Nns(v) => nns::exec(env, v), + Command::Ping(v) => ping::exec(env, v), + Command::Quickstart => quickstart::exec(env), + Command::Remote(v) => remote::exec(env, v), + Command::Replica(v) => replica::exec(env, v), + Command::Schema(v) => schema::exec(env, v), + Command::Sns(v) => sns::exec(env, v), + Command::Start(v) => start::exec(env, v), + Command::Stop(v) => stop::exec(env, v), + Command::Toolchain(v) => toolchain::exec(env, v), + Command::Upgrade(v) => upgrade::exec(env, v), + Command::Wallet(v) => wallet::exec(env, v), } } diff --git a/src/dfx/src/commands/nns/install.rs b/src/dfx/src/commands/nns/install.rs index 2471dcb589..c7e38428e6 100644 --- a/src/dfx/src/commands/nns/install.rs +++ b/src/dfx/src/commands/nns/install.rs @@ -1,4 +1,5 @@ -use crate::{DfxResult, Environment}; +use crate::lib::error::DfxResult; +use crate::Environment; use anyhow::anyhow; use crate::lib::nns::install_nns::install_nns; diff --git a/src/dfx/src/commands/nns/mod.rs b/src/dfx/src/commands/nns/mod.rs index 7e32732d75..793c2393cb 100644 --- a/src/dfx/src/commands/nns/mod.rs +++ b/src/dfx/src/commands/nns/mod.rs @@ -1,7 +1,7 @@ -use crate::commands::NetworkOpts; -use crate::init_env; +use crate::lib::environment::Environment; +use crate::lib::error::DfxResult; use crate::lib::provider::create_agent_environment; -use crate::DfxResult; +use crate::NetworkOpt; use clap::Parser; use tokio::runtime::Runtime; @@ -11,30 +11,26 @@ mod install; /// NNS commands. #[derive(Parser)] #[clap(name("nns"))] -pub struct NnsCommand { +pub struct NnsOpts { #[clap(subcommand)] subcmd: SubCommand, + + #[clap(flatten)] + network: NetworkOpt, } #[derive(Parser)] enum SubCommand { #[clap(hide(true))] - Install(NetworkOpts), -} - -macro_rules! with_env { - ($opts:expr, |$env:ident, $v:ident| $e:expr) => {{ - let NetworkOpts { base_opts, network } = $opts; - let env = init_env(base_opts.env_opts)?; - let $env = create_agent_environment(&env, network)?; - let runtime = Runtime::new().expect("Unable to create a runtime"); - let $v = base_opts.command_opts; - runtime.block_on($e) - }}; + Install(install::InstallOpts), } -pub fn dispatch(cmd: NnsCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::Install(v) => with_env!(v, |env, v| install::exec(&env, v)), - } +pub fn exec(env: &dyn Environment, opts: NnsOpts) -> DfxResult { + let env = create_agent_environment(env, opts.network.network)?; + let runtime = Runtime::new().expect("Unable to create a runtime"); + runtime.block_on(async { + match opts.subcmd { + SubCommand::Install(v) => install::exec(&env, v).await, + } + }) } diff --git a/src/dfx/src/commands/remote/generate_binding.rs b/src/dfx/src/commands/remote/generate_binding.rs index 715a912bc0..008f307349 100644 --- a/src/dfx/src/commands/remote/generate_binding.rs +++ b/src/dfx/src/commands/remote/generate_binding.rs @@ -1,7 +1,7 @@ use crate::lib::environment::Environment; use crate::lib::error::DfxResult; use crate::lib::models::canister::CanisterPool; - +use crate::lib::provider::create_agent_environment; use crate::util::check_candid_file; use anyhow::Context; @@ -29,6 +29,7 @@ pub struct GenerateBindingOpts { } pub fn exec(env: &dyn Environment, opts: GenerateBindingOpts) -> DfxResult { + let env = create_agent_environment(env, None)?; let config = env.get_config_or_anyhow()?; let log = env.get_logger(); @@ -36,7 +37,7 @@ pub fn exec(env: &dyn Environment, opts: GenerateBindingOpts) -> DfxResult { let canister_names = config .get_config() .get_canister_names_with_dependencies(opts.canister.as_deref())?; - let canister_pool = CanisterPool::load(env, false, &canister_names)?; + let canister_pool = CanisterPool::load(&env, false, &canister_names)?; for canister in canister_pool.get_canister_list() { let info = canister.get_info(); diff --git a/src/dfx/src/commands/remote/mod.rs b/src/dfx/src/commands/remote/mod.rs index f8d08ef2d7..e157ce4abf 100644 --- a/src/dfx/src/commands/remote/mod.rs +++ b/src/dfx/src/commands/remote/mod.rs @@ -1,32 +1,28 @@ -use crate::init_env; - +use crate::lib::environment::Environment; use crate::lib::error::DfxResult; -use crate::lib::provider::create_agent_environment; +use crate::NetworkOpt; use clap::Parser; -use super::NetworkOpts; - mod generate_binding; /// Commands used to work with remote canisters #[derive(Parser)] -pub struct RemoteCommand { +pub struct RemoteOpts { + #[clap(flatten)] + network: NetworkOpt, + #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - GenerateBinding(NetworkOpts), + GenerateBinding(generate_binding::GenerateBindingOpts), } -pub fn dispatch(cmd: RemoteCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::GenerateBinding(v) => { - let env = init_env(v.base_opts.env_opts)?; - let agent_env = create_agent_environment(&env, v.network)?; - generate_binding::exec(&agent_env, v.base_opts.command_opts) - } +pub fn exec(env: &dyn Environment, opts: RemoteOpts) -> DfxResult { + match opts.subcmd { + SubCommand::GenerateBinding(v) => generate_binding::exec(env, v), } } diff --git a/src/dfx/src/commands/sns/config/create.rs b/src/dfx/src/commands/sns/config/create.rs index 26bbe41dd2..2192bf0d21 100644 --- a/src/dfx/src/commands/sns/config/create.rs +++ b/src/dfx/src/commands/sns/config/create.rs @@ -1,4 +1,5 @@ -use crate::{DfxResult, Environment}; +use crate::lib::error::DfxResult; +use crate::Environment; use crate::lib::sns; use crate::lib::sns::create_config::create_config; diff --git a/src/dfx/src/commands/sns/config/mod.rs b/src/dfx/src/commands/sns/config/mod.rs index f5cc552f71..05734a9d3c 100644 --- a/src/dfx/src/commands/sns/config/mod.rs +++ b/src/dfx/src/commands/sns/config/mod.rs @@ -1,6 +1,4 @@ -use crate::{BaseOpts, DfxResult}; - -use crate::init_env; +use crate::lib::{environment::Environment, error::DfxResult}; use clap::Parser; mod create; @@ -12,20 +10,20 @@ pub struct ConfigOpts {} /// SNS config commands. #[derive(Parser)] #[clap(name("config"))] -pub struct SnsConfigCommand { +pub struct SnsConfigOpts { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - Create(BaseOpts), - Validate(BaseOpts), + Create(create::CreateOpts), + Validate(validate::ValidateOpts), } -pub fn dispatch(cmd: SnsConfigCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::Create(v) => create::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::Validate(v) => validate::exec(&init_env(v.env_opts)?, v.command_opts), +pub fn exec(env: &dyn Environment, opts: SnsConfigOpts) -> DfxResult { + match opts.subcmd { + SubCommand::Create(v) => create::exec(env, v), + SubCommand::Validate(v) => validate::exec(env, v), } } diff --git a/src/dfx/src/commands/sns/config/validate.rs b/src/dfx/src/commands/sns/config/validate.rs index 0a83808ced..5590d0b6b8 100644 --- a/src/dfx/src/commands/sns/config/validate.rs +++ b/src/dfx/src/commands/sns/config/validate.rs @@ -1,4 +1,5 @@ -use crate::{DfxResult, Environment}; +use crate::lib::error::DfxResult; +use crate::Environment; use crate::lib::sns; use crate::lib::sns::validate_config::validate_config; diff --git a/src/dfx/src/commands/sns/mod.rs b/src/dfx/src/commands/sns/mod.rs index a3e51d8938..3aee9aefa3 100644 --- a/src/dfx/src/commands/sns/mod.rs +++ b/src/dfx/src/commands/sns/mod.rs @@ -1,5 +1,7 @@ -use crate::commands::sns::config::SnsConfigCommand; -use crate::DfxResult; +use crate::{ + commands::sns::config::SnsConfigOpts, + lib::{environment::Environment, error::DfxResult}, +}; use clap::Parser; @@ -8,7 +10,7 @@ mod config; /// SNS commands. #[derive(Parser)] #[clap(name("sns"))] -pub struct SnsCommand { +pub struct SnsOpts { #[clap(subcommand)] subcmd: SubCommand, } @@ -16,11 +18,11 @@ pub struct SnsCommand { #[derive(Parser)] enum SubCommand { #[clap(hide(true))] - Config(SnsConfigCommand), + Config(SnsConfigOpts), } -pub fn dispatch(cmd: SnsCommand) -> DfxResult { +pub fn exec(env: &dyn Environment, cmd: SnsOpts) -> DfxResult { match cmd.subcmd { - SubCommand::Config(v) => config::dispatch(v), + SubCommand::Config(v) => config::exec(env, v), } } diff --git a/src/dfx/src/commands/toolchain/mod.rs b/src/dfx/src/commands/toolchain/mod.rs index e12c498dbb..6797109bfa 100644 --- a/src/dfx/src/commands/toolchain/mod.rs +++ b/src/dfx/src/commands/toolchain/mod.rs @@ -1,5 +1,5 @@ +use crate::lib::environment::Environment; use crate::lib::error::DfxResult; -use crate::{init_env, BaseOpts}; use clap::Parser; @@ -11,24 +11,24 @@ mod uninstall; /// Manage the dfx toolchains #[derive(Parser)] #[clap(name("toolchain"))] -pub struct ToolchainCommand { +pub struct ToolchainOpts { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] pub enum SubCommand { - Install(BaseOpts), - Uninstall(BaseOpts), - List(BaseOpts), - Default(BaseOpts), + Install(install::ToolchainInstall), + Uninstall(uninstall::ToolchainUninstall), + List(list::ToolchainList), + Default(default::ToolchainDefault), } -pub fn dispatch(cmd: ToolchainCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::Install(v) => install::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::Uninstall(v) => uninstall::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::List(v) => list::exec(&init_env(v.env_opts)?, v.command_opts), - SubCommand::Default(v) => default::exec(&init_env(v.env_opts)?, v.command_opts), +pub fn exec(env: &dyn Environment, opts: ToolchainOpts) -> DfxResult { + match opts.subcmd { + SubCommand::Install(v) => install::exec(env, v), + SubCommand::Uninstall(v) => uninstall::exec(env, v), + SubCommand::List(v) => list::exec(env, v), + SubCommand::Default(v) => default::exec(env, v), } } diff --git a/src/dfx/src/commands/wallet/mod.rs b/src/dfx/src/commands/wallet/mod.rs index 9524d6ad64..efd689792b 100644 --- a/src/dfx/src/commands/wallet/mod.rs +++ b/src/dfx/src/commands/wallet/mod.rs @@ -1,4 +1,3 @@ -use crate::init_env; use crate::lib::environment::Environment; use crate::lib::error::DfxResult; use crate::lib::identity::Identity; @@ -6,6 +5,7 @@ use crate::lib::provider::create_agent_environment; use crate::lib::root_key::fetch_root_key_if_needed; use crate::lib::waiter::waiter_with_timeout; use crate::util::expiry_duration; +use crate::NetworkOpt; use anyhow::Context; use candid::utils::ArgumentDecoder; @@ -16,8 +16,6 @@ use ic_utils::call::SyncCall; use ic_utils::interfaces::WalletCanister; use tokio::runtime::Runtime; -use super::NetworkOpts; - mod add_controller; mod authorize; mod balance; @@ -35,69 +33,51 @@ mod upgrade; /// Helper commands to manage the user's cycles wallet. #[derive(Parser)] #[clap(name("wallet"))] -pub struct WalletCommand { +pub struct WalletOpts { + #[clap(flatten)] + network: NetworkOpt, + #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - Addresses(NetworkOpts), - AddController(NetworkOpts), - Authorize(NetworkOpts), - Balance(NetworkOpts), - RedeemFaucetCoupon(NetworkOpts), - Controllers(NetworkOpts), - Custodians(NetworkOpts), - Deauthorize(NetworkOpts), - Name(NetworkOpts), - RemoveController(NetworkOpts), - Send(NetworkOpts), - SetName(NetworkOpts), - Upgrade(NetworkOpts), + Addresses(list_addresses::AddressesOpts), + AddController(add_controller::AddControllerOpts), + Authorize(authorize::AuthorizeOpts), + Balance(balance::WalletBalanceOpts), + Controllers(controllers::ControllersOpts), + Custodians(custodians::CustodiansOpts), + Deauthorize(deauthorize::DeauthorizeOpts), + Name(name::NameOpts), + RedeemFaucetCoupon(redeem_faucet_coupon::RedeemFaucetCouponOpts), + RemoveController(remove_controller::RemoveControllerOpts), + Send(send::SendOpts), + SetName(set_name::SetNameOpts), + Upgrade(upgrade::UpgradeOpts), } -macro_rules! with_env { - ($opts:expr, |$env:ident, $v:ident| $e:expr) => {{ - let NetworkOpts { base_opts, network } = $opts; - let env = init_env(base_opts.env_opts)?; - let $env = create_agent_environment(&env, network)?; - let runtime = Runtime::new().expect("Unable to create a runtime"); - let $v = base_opts.command_opts; - runtime.block_on($e) - }}; -} - -pub fn dispatch(cmd: WalletCommand) -> DfxResult { - match cmd.subcmd { - SubCommand::Addresses(v) => { - with_env!(v, |env, v| list_addresses::exec(&env, v)) - } - SubCommand::AddController(v) => { - with_env!(v, |env, v| add_controller::exec(&env, v)) - } - SubCommand::Authorize(v) => with_env!(v, |env, v| authorize::exec(&env, v)), - SubCommand::Balance(v) => with_env!(v, |env, v| balance::exec(&env, v)), - SubCommand::RedeemFaucetCoupon(v) => { - with_env!(v, |env, v| redeem_faucet_coupon::exec(&env, v)) - } - SubCommand::Controllers(v) => { - with_env!(v, |env, v| controllers::exec(&env, v)) - } - SubCommand::Custodians(v) => { - with_env!(v, |env, v| custodians::exec(&env, v)) - } - SubCommand::Deauthorize(v) => { - with_env!(v, |env, v| deauthorize::exec(&env, v)) - } - SubCommand::Name(v) => with_env!(v, |env, v| name::exec(&env, v)), - SubCommand::RemoveController(v) => { - with_env!(v, |env, v| remove_controller::exec(&env, v)) +pub fn exec(env: &dyn Environment, opts: WalletOpts) -> DfxResult { + let agent_env = create_agent_environment(env, opts.network.network)?; + let runtime = Runtime::new().expect("Unable to create a runtime"); + runtime.block_on(async { + match opts.subcmd { + SubCommand::Addresses(v) => list_addresses::exec(&agent_env, v).await, + SubCommand::AddController(v) => add_controller::exec(&agent_env, v).await, + SubCommand::Authorize(v) => authorize::exec(&agent_env, v).await, + SubCommand::Balance(v) => balance::exec(&agent_env, v).await, + SubCommand::Controllers(v) => controllers::exec(&agent_env, v).await, + SubCommand::Custodians(v) => custodians::exec(&agent_env, v).await, + SubCommand::Deauthorize(v) => deauthorize::exec(&agent_env, v).await, + SubCommand::Name(v) => name::exec(&agent_env, v).await, + SubCommand::RedeemFaucetCoupon(v) => redeem_faucet_coupon::exec(&agent_env, v).await, + SubCommand::RemoveController(v) => remove_controller::exec(&agent_env, v).await, + SubCommand::Send(v) => send::exec(&agent_env, v).await, + SubCommand::SetName(v) => set_name::exec(&agent_env, v).await, + SubCommand::Upgrade(v) => upgrade::exec(&agent_env, v).await, } - SubCommand::Send(v) => with_env!(v, |env, v| send::exec(&env, v)), - SubCommand::SetName(v) => with_env!(v, |env, v| set_name::exec(&env, v)), - SubCommand::Upgrade(v) => with_env!(v, |env, v| upgrade::exec(&env, v)), - } + }) } #[context("Failed to call query function '{}' on wallet.", method)] diff --git a/src/dfx/src/lib/nns/install_nns.rs b/src/dfx/src/lib/nns/install_nns.rs index 87d5d3450c..62f720b1ee 100644 --- a/src/dfx/src/lib/nns/install_nns.rs +++ b/src/dfx/src/lib/nns/install_nns.rs @@ -1,10 +1,10 @@ -use crate::DfxResult; - use anyhow::{bail, Context}; use fn_error_context::context; use ic_agent::Agent; use std::path::Path; +use crate::lib::error::DfxResult; + #[context("Failed to install nns components.")] pub async fn install_nns( _agent: &Agent, diff --git a/src/dfx/src/lib/sns/create_config.rs b/src/dfx/src/lib/sns/create_config.rs index 120e6193bc..711c96c5e1 100644 --- a/src/dfx/src/lib/sns/create_config.rs +++ b/src/dfx/src/lib/sns/create_config.rs @@ -1,8 +1,8 @@ -use crate::DfxResult; - use fn_error_context::context; use std::path::Path; +use crate::lib::error::DfxResult; + #[context("Failed to create sns config at {}.", path.display())] pub fn create_config(path: &Path) -> DfxResult { todo!() diff --git a/src/dfx/src/lib/sns/validate_config.rs b/src/dfx/src/lib/sns/validate_config.rs index a8773925d3..3aed53e04a 100644 --- a/src/dfx/src/lib/sns/validate_config.rs +++ b/src/dfx/src/lib/sns/validate_config.rs @@ -1,8 +1,8 @@ -use crate::DfxResult; - use fn_error_context::context; use std::path::Path; +use crate::lib::error::DfxResult; + #[context("Failed to validate sns config at {}.", path.display())] pub fn validate_config(path: &Path) -> DfxResult { todo!() diff --git a/src/dfx/src/main.rs b/src/dfx/src/main.rs index 112f77cc5c..26c503d0b8 100644 --- a/src/dfx/src/main.rs +++ b/src/dfx/src/main.rs @@ -5,7 +5,6 @@ use crate::lib::logger::{create_root_logger, LoggingMode}; use anyhow::Error; use clap::{Args, Parser}; use lib::diagnosis::{diagnose, Diagnosis, NULL_DIAGNOSIS}; -use lib::error::DfxResult; use semver::Version; use std::path::PathBuf; @@ -19,39 +18,38 @@ mod util; #[derive(Parser)] #[clap(name("dfx"), version = dfx_version_str())] pub struct CliOpts { - #[clap(subcommand)] - command: commands::Command, -} - -#[derive(Args)] -pub struct BaseOpts { - #[clap(flatten)] - command_opts: T, - #[clap(flatten, next_help_heading = "COMMON")] - env_opts: EnvOpts, -} - -#[derive(Args)] -struct EnvOpts { /// Displays detailed information about operations. -vv will generate a very large number of messages and can affect performance. - #[clap(long, short('v'), parse(from_occurrences))] + #[clap(long, short('v'), parse(from_occurrences), global(true))] verbose: u64, /// Suppresses informational messages. -qq limits to errors only; -qqqq disables them all. - #[clap(long, short('q'), parse(from_occurrences))] + #[clap(long, short('q'), parse(from_occurrences), global(true))] quiet: u64, /// The logging mode to use. You can log to stderr, a file, or both. - #[clap(long("log"), default_value("stderr"), possible_values(&["stderr", "tee", "file"]))] + #[clap(long("log"), default_value("stderr"), possible_values(&["stderr", "tee", "file"]), global(true))] logmode: String, /// The file to log to, if logging to a file (see --logmode). - #[clap(long)] + #[clap(long, global(true))] logfile: Option, /// The user identity to run this command as. It contains your principal as well as some things DFX associates with it like the wallet. - #[clap(long)] + #[clap(long, global(true))] identity: Option, + + #[clap(subcommand)] + command: commands::Command, +} + +#[derive(Args, Clone, Debug)] +struct NetworkOpt { + /// Override the compute network to connect to. By default, the local network is used. + /// A valid URL (starting with `http:` or `https:`) can be used here, and a special + /// ephemeral network will be created specifically for this request. E.g. + /// "http://localhost:12345/" is a valid network name. + #[clap(long, global(true))] + network: Option, } fn is_warning_disabled(warning: &str) -> bool { @@ -104,7 +102,7 @@ fn maybe_redirect_dfx(version: &Version) -> Option<()> { /// Setup a logger with the proper configuration, based on arguments. /// Returns a topple of whether or not to have a progress bar, and a logger. -fn setup_logging(opts: &EnvOpts) -> (bool, slog::Logger) { +fn setup_logging(opts: &CliOpts) -> (bool, slog::Logger) { // Create a logger with our argument matches. let level = opts.verbose as i64 - opts.quiet as i64; @@ -174,32 +172,34 @@ fn print_error_and_diagnosis(err: Error, error_diagnosis: Diagnosis) { } } -fn init_env(env_opts: EnvOpts) -> DfxResult { - let (progress_bar, log) = setup_logging(&env_opts); - let env = EnvironmentImpl::new()? - .with_logger(log) - .with_progress_bar(progress_bar) - .with_identity_override(env_opts.identity); - slog::trace!( - env.get_logger(), - "Trace mode enabled. Lots of logs coming up." - ); - Ok(env) -} - fn main() { let cli_opts = CliOpts::parse(); + let (progress_bar, log) = setup_logging(&cli_opts); + let identity = cli_opts.identity; let command = cli_opts.command; let mut error_diagnosis: Diagnosis = NULL_DIAGNOSIS; let result = match EnvironmentImpl::new() { Ok(env) => { maybe_redirect_dfx(env.get_version()).map_or((), |_| unreachable!()); - match commands::dispatch(command) { - Err(e) => { - error_diagnosis = diagnose(&env, &e); - Err(e) + match EnvironmentImpl::new().map(|env| { + env.with_logger(log) + .with_progress_bar(progress_bar) + .with_identity_override(identity) + }) { + Ok(env) => { + slog::trace!( + env.get_logger(), + "Trace mode enabled. Lots of logs coming up." + ); + match commands::exec(&env, command) { + Err(e) => { + error_diagnosis = diagnose(&env, &e); + Err(e) + } + ok => ok, + } } - ok => ok, + Err(e) => Err(e), } } Err(e) => Err(e),