Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
25 changes: 25 additions & 0 deletions e2e/tests-dfx/subcommands.bash
Original file line number Diff line number Diff line change
@@ -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)"
}
11 changes: 4 additions & 7 deletions src/dfx/src/commands/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,12 +25,8 @@ pub struct BootstrapOpts {
#[clap(long)]
port: Option<String>,

/// 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<String>,
#[clap(flatten)]
network: NetworkOpt,

/// Specifies the maximum number of seconds that the bootstrap server
/// will wait for upstream requests to complete. Defaults to 30.
Expand All @@ -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,
)?;
Expand Down
11 changes: 4 additions & 7 deletions src/dfx/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<String>,
#[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();

Expand Down
24 changes: 12 additions & 12 deletions src/dfx/src/commands/cache/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::lib::environment::Environment;
use crate::lib::error::DfxResult;
use crate::{init_env, BaseOpts};

use clap::Parser;

Expand All @@ -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<delete::CacheDeleteOpts>),
Install(BaseOpts<install::CacheInstall>),
List(BaseOpts<list::CacheListOpts>),
Show(BaseOpts<show::CacheShowOpts>),
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),
}
}
145 changes: 50 additions & 95 deletions src/dfx/src/commands/canister/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -26,109 +23,67 @@ mod stop;
mod uninstall_code;
mod update_settings;

#[derive(Args)]
pub struct CanisterOpts<T: Args> {
/// Manages canisters deployed on a network replica.
#[derive(Parser)]
#[clap(name("canister"))]
pub struct CanisterOpts {
#[clap(flatten)]
network_opts: NetworkOpts<T>,
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<String>,
}

/// 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<call::CanisterCallOpts>),
Create(CanisterOpts<create::CanisterCreateOpts>),
Delete(CanisterOpts<delete::CanisterDeleteOpts>),
DepositCycles(CanisterOpts<deposit_cycles::DepositCyclesOpts>),
Id(CanisterOpts<id::CanisterIdOpts>),
Info(CanisterOpts<info::InfoOpts>),
Install(CanisterOpts<install::CanisterInstallOpts>),
Metadata(CanisterOpts<metadata::CanisterMetadataOpts>),
RequestStatus(CanisterOpts<request_status::RequestStatusOpts>),
Send(CanisterOpts<send::CanisterSendOpts>),
Sign(CanisterOpts<sign::CanisterSignOpts>),
Start(CanisterOpts<start::CanisterStartOpts>),
Status(CanisterOpts<status::CanisterStatusOpts>),
Stop(CanisterOpts<stop::CanisterStopOpts>),
UninstallCode(CanisterOpts<uninstall_code::UninstallCodeOpts>),
UpdateSettings(CanisterOpts<update_settings::UpdateSettingsOpts>),
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)
}),
}
})
}
11 changes: 4 additions & 7 deletions src/dfx/src/commands/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String>,
#[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.
Expand All @@ -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();
Expand Down
15 changes: 9 additions & 6 deletions src/dfx/src/commands/diagnose.rs
Original file line number Diff line number Diff line change
@@ -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<String>,
#[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(())
Expand Down
Loading