diff --git a/CHANGELOG.md b/CHANGELOG.md index 5187254e36..5060074cc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ If the local did file doesn't contain `import` or init args, we will not perform ### fix: subtyping check reports the special opt rule as error +### fix: can now run several dfx canister commands outside of a project + +The following commands now work outside of a project: +- `dfx canister start ` +- `dfx canister stop ` +- `dfx canister deposit-cycles ` +- `dfx canister uninstall-code ` + # 0.16.0 ### feat: large canister modules now supported diff --git a/e2e/tests-dfx/start.bash b/e2e/tests-dfx/start.bash index 52a735bda6..276f430ee7 100644 --- a/e2e/tests-dfx/start.bash +++ b/e2e/tests-dfx/start.bash @@ -12,6 +12,43 @@ teardown() { standard_teardown } +@test "start and stop outside project" { + dfx_start + + mkdir subdir + cd subdir || exit 1 + dfx_new + assert_command dfx deploy + CANISTER_ID="$(dfx canister id e2e_project_backend)" + cd .. + assert_command dfx canister status "$CANISTER_ID" + assert_contains "Status: Running" + assert_command dfx canister stop "$CANISTER_ID" + assert_command dfx canister status "$CANISTER_ID" + assert_contains "Status: Stopped" + assert_command dfx canister start "$CANISTER_ID" + assert_command dfx canister status "$CANISTER_ID" + assert_contains "Status: Running" +} + +@test "uninstall-code outside of a project" { + dfx_start + + mkdir subdir + cd subdir || exit 1 + dfx_new + assert_command dfx deploy + CANISTER_ID="$(dfx canister id e2e_project_backend)" + cd .. + assert_command dfx canister status "$CANISTER_ID" + assert_contains "Module hash: 0x" + assert_command dfx canister uninstall-code "$CANISTER_ID" + assert_contains "Uninstalling code for canister $CANISTER_ID" + assert_command dfx canister status "$CANISTER_ID" + assert_contains "Module hash: None" +} + + @test "icx-proxy domain configuration in string form" { create_networks_json jq '.local.proxy.domain="xyz.domain"' "$E2E_NETWORKS_JSON" | sponge "$E2E_NETWORKS_JSON" diff --git a/e2e/tests-dfx/wallet.bash b/e2e/tests-dfx/wallet.bash index e1d7da527d..8c2fb9a52b 100644 --- a/e2e/tests-dfx/wallet.bash +++ b/e2e/tests-dfx/wallet.bash @@ -12,6 +12,28 @@ teardown() { standard_teardown } +@test "deposit cycles inside a project" { + dfx_start + + dfx_new + assert_command dfx deploy + assert_command dfx canister deposit-cycles 47 e2e_project_backend + assert_contains "Deposited 47 cycles" +} + +@test "deposit cycles outside a project" { + dfx_start + + mkdir subdir + cd subdir || exit 1 + dfx_new + assert_command dfx deploy + CANISTER_ID="$(dfx canister id e2e_project_backend)" + cd .. + assert_command dfx canister deposit-cycles 42 "$CANISTER_ID" + assert_contains "Deposited 42 cycles" +} + @test "DFX_WALLET_WASM environment variable overrides wallet module wasm at installation" { dfx_new hello dfx_start diff --git a/src/dfx/src/commands/canister/deposit_cycles.rs b/src/dfx/src/commands/canister/deposit_cycles.rs index 1db9ed67f2..0ff9bdb06b 100644 --- a/src/dfx/src/commands/canister/deposit_cycles.rs +++ b/src/dfx/src/commands/canister/deposit_cycles.rs @@ -79,11 +79,11 @@ pub async fn exec( // amount has been validated by cycle_amount_validator let cycles = opts.cycles; - let config = env.get_config_or_anyhow()?; - if let Some(canister) = opts.canister.as_deref() { deposit_cycles(env, canister, call_sender, cycles).await } else if opts.all { + let config = env.get_config_or_anyhow()?; + if let Some(canisters) = &config.get_config().canisters { for canister in canisters.keys() { deposit_cycles(env, canister, call_sender, cycles) diff --git a/src/dfx/src/commands/canister/start.rs b/src/dfx/src/commands/canister/start.rs index 672068ec42..529817ca59 100644 --- a/src/dfx/src/commands/canister/start.rs +++ b/src/dfx/src/commands/canister/start.rs @@ -45,12 +45,12 @@ pub async fn exec( opts: CanisterStartOpts, call_sender: &CallSender, ) -> DfxResult { - let config = env.get_config_or_anyhow()?; fetch_root_key_if_needed(env).await?; if let Some(canister) = opts.canister.as_deref() { start_canister(env, canister, call_sender).await } else if opts.all { + let config = env.get_config_or_anyhow()?; if let Some(canisters) = &config.get_config().canisters { for canister in canisters.keys() { start_canister(env, canister, call_sender).await?; diff --git a/src/dfx/src/commands/canister/stop.rs b/src/dfx/src/commands/canister/stop.rs index 898ea5aef3..7f71472908 100644 --- a/src/dfx/src/commands/canister/stop.rs +++ b/src/dfx/src/commands/canister/stop.rs @@ -46,13 +46,12 @@ pub async fn exec( opts: CanisterStopOpts, call_sender: &CallSender, ) -> DfxResult { - let config = env.get_config_or_anyhow()?; - fetch_root_key_if_needed(env).await?; if let Some(canister) = opts.canister.as_deref() { stop_canister(env, canister, call_sender).await } else if opts.all { + let config = env.get_config_or_anyhow()?; if let Some(canisters) = &config.get_config().canisters { for canister in canisters.keys() { stop_canister(env, canister, call_sender).await?; diff --git a/src/dfx/src/commands/canister/uninstall_code.rs b/src/dfx/src/commands/canister/uninstall_code.rs index e7e9838e8f..4b386d7a36 100644 --- a/src/dfx/src/commands/canister/uninstall_code.rs +++ b/src/dfx/src/commands/canister/uninstall_code.rs @@ -47,13 +47,13 @@ pub async fn exec( opts: UninstallCodeOpts, call_sender: &CallSender, ) -> DfxResult { - let config = env.get_config_or_anyhow()?; - fetch_root_key_if_needed(env).await?; if let Some(canister) = opts.canister.as_deref() { uninstall_code(env, canister, call_sender).await } else if opts.all { + let config = env.get_config_or_anyhow()?; + if let Some(canisters) = &config.get_config().canisters { for canister in canisters.keys() { uninstall_code(env, canister, call_sender).await?; diff --git a/src/dfx/src/commands/new.rs b/src/dfx/src/commands/new.rs index 708adff9b6..98569b85b2 100644 --- a/src/dfx/src/commands/new.rs +++ b/src/dfx/src/commands/new.rs @@ -12,7 +12,6 @@ use dfx_core::config::model::dfinity::CONFIG_FILE_NAME; use dfx_core::json::{load_json_file, save_json_file}; use fn_error_context::context; use indicatif::HumanBytes; -use lazy_static::lazy_static; use semver::Version; use serde_json::Value; use slog::{info, warn, Logger}; @@ -30,15 +29,12 @@ const RELEASE_ROOT: &str = "https://sdk.dfinity.org"; // The dist-tag to use when getting the version from NPM. const AGENT_JS_DEFAULT_INSTALL_DIST_TAG: &str = "latest"; -lazy_static! { // Tested on a phone tethering connection. This should be fine with // little impact to the user, given that "new" is supposedly a // heavy-weight operation. Thus, worst case we are utilizing the user // expectation for the duration to have a more expensive version // check. - static ref CHECK_VERSION_TIMEOUT: Duration = Duration::from_secs(2); - -} +const CHECK_VERSION_TIMEOUT: Duration = Duration::from_secs(2); /// Creates a new project. #[derive(Parser)] @@ -417,7 +413,7 @@ pub fn exec(env: &dyn Environment, opts: NewOpts) -> DfxResult { // It is fine for the following command to timeout or fail. We // drop the error. - let latest_version = get_latest_version(RELEASE_ROOT, Some(*CHECK_VERSION_TIMEOUT)).ok(); + let latest_version = get_latest_version(RELEASE_ROOT, Some(CHECK_VERSION_TIMEOUT)).ok(); if is_upgrade_necessary(latest_version.as_ref(), current_version) { warn_upgrade(log, latest_version.as_ref(), current_version); diff --git a/src/dfx/src/lib/info/mod.rs b/src/dfx/src/lib/info/mod.rs index 67e3d4ea31..04bf28df82 100644 --- a/src/dfx/src/lib/info/mod.rs +++ b/src/dfx/src/lib/info/mod.rs @@ -1,8 +1,5 @@ -use lazy_static::lazy_static; -lazy_static! { - static ref REPLICA_REV_STR: String = env!("DFX_ASSET_REPLICA_REV").to_string(); -} +const REPLICA_REV_STR: &str = env!("DFX_ASSET_REPLICA_REV"); pub fn replica_rev() -> &'static str { - &REPLICA_REV_STR + REPLICA_REV_STR }