diff --git a/CHANGELOG.md b/CHANGELOG.md index 54ae21b770..b8a12c9ca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ ## DFX +### 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: +```bash +dfx --identity alice canister --network ic --wallet "$WALLET" create --all +``` +This command should now read: +```bash +dfx canister create --all --network ic --wallet "$WALLET" --identity alice +``` + ### feat!: changed update-settings syntax When using `dfx canister update-settings`, it is easy to mistake `--controller` for `--add-controller`. For this reason `--controller` has been renamed to `--set-controller`. diff --git a/docs/cli-reference/dfx-canister.md b/docs/cli-reference/dfx-canister.md index b808b47b16..64c195b43d 100644 --- a/docs/cli-reference/dfx-canister.md +++ b/docs/cli-reference/dfx-canister.md @@ -5,7 +5,7 @@ Use the `dfx canister` command with flags and subcommands to manage canister ope The basic syntax for running `dfx canister` commands is: ``` bash -dfx canister [canister flags] subcommand [subcommand flags] +dfx canister [flags] ``` Depending on the `dfx canister` subcommand you specify, additional arguments, options, and flags might apply or be required. To view usage information for a specific `dfx canister` subcommand, specify the subcommand and the `--help` flag. For example, to see usage information for `dfx canister call`, you can run the following command: @@ -49,7 +49,7 @@ dfx canister create --all If you want to register unique canister identifiers for the same project on the Internet Computer, you can run the following command: ``` bash -dfx canister --network ic create --all +dfx canister create --all --network ic ``` The SDK comes with an alias of `ic`, which is configured to point to the Internet Computer. You can also pass a URL as a network option, or you can configure additional aliases in `dfx.json` under the `networks` configuration. @@ -57,29 +57,27 @@ The SDK comes with an alias of `ic`, which is configured to point to the Interne To illustrate, you can call a canister and function running on a testnet using a command similar to the following: ``` bash -dfx canister --network http://192.168.3.1:5678 call counter get +dfx canister call counter get --network http://192.168.3.1:5678 ``` -Note that you must specify the `--network` parameter before the canister operation (`create` or `call`) and any additional arguments such as the canister name (`counter`), and function (`get`). - ## Performing a call through the wallet By default, most `dfx canister` commands to the Internet Computer are signed by and sent from your own principal. (Exceptions are commands that require cycles: `dfx canister create` and `dfx canister deposit-cycles`. Those automatically go through the wallet.) Occasionally, you may want to make a call from your wallet, e.g. when only your wallet is allowed to call a certain function. To send a call through your wallet, you can use the `--wallet` flag like this: ``` bash -dfx canister --wallet status +dfx canister status --wallet ``` As a concrete example, if you want to request the status of a canister on the ic that is only controlled by your wallet, you would do the following: ``` bash -dfx identity --network ic get-wallet +dfx identity get-wallet --network ic ``` This command outputs your wallet's principal (e.g. `22ayq-aiaaa-aaaai-qgmma-cai`) on the `ic` network. Using this id, you can then query the status of the canister (let's assume the canister is called `my_canister_name`) as follows: ``` bash -dfx canister --network ic --wallet 22ayq-aiaaa-aaaai-qgmma-cai status +dfx canister status --network ic --wallet 22ayq-aiaaa-aaaai-qgmma-cai ``` ## dfx canister call @@ -272,7 +270,7 @@ dfx canister delete hello_world To delete all of the canisters you have deployed on the `ic` Internet Computer and configured in your `dfx.json`, you can run the following command: ``` bash -dfx canister --network=ic delete --all +dfx canister delete --all--network=ic ``` ## dfx canister deposit-cycles @@ -488,11 +486,9 @@ If you want to deploy a canister on a testnet without changing the settings in y For example, you can specify a testnet URL by running a command similar to the following: ``` bash -dfx canister --network http://192.168.3.1:5678 install --all +dfx canister install --all --network http://192.168.3.1:5678 ``` -Note that you must specify the network parameter before the canister operation (`install`) and before the canister name or `--all` flag. - #### Allocating message processing The `--compute-allocation` options allows you to allocate computing resources as a percentage in the range of 0 to 100 to indicate how often your canister should be scheduled for execution. @@ -677,7 +673,7 @@ You can specify the following arguments for the `dfx canister sign` command. Use the `dfx canister sign` command to create a signed `message.json` file using the selected identity by running a command similar to the following: -`dfx canister --network=ic sign --expire-after=1h rno2w-sqaaa-aaaaa-aaacq-cai create_neurons ‘(“PUBLIC_KEY”)’` +`dfx canister sign --network=ic --expire-after=1h rno2w-sqaaa-aaaaa-aaacq-cai create_neurons ‘(“PUBLIC_KEY”)’` This command illustrates how to creates a `message.json` file to create neurons on the Internet Computer specified by the `ic` alias, that is signed using your principal identifier as the message sender and with an expiration window that ends in one hour. @@ -735,7 +731,7 @@ dfx canister start hello_world To start all of the canisters you have deployed on the `ic` Internet Computer, you can run the following command: ``` bash -dfx canister --network=ic start --all +dfx canister start --all --network=ic ``` ## dfx canister status @@ -780,7 +776,7 @@ dfx canister status hello_world To check the status for all of the canisters you have deployed on the `ic` Internet Computer, you can run the following command: ``` bash -dfx canister --network=ic status --all +dfx canister status --all --network=ic ``` ## dfx canister stop @@ -827,7 +823,7 @@ dfx canister stop hello_world To stop all of the canisters you have deployed on the `ic` Internet Computer, you can run the following command: ``` bash -dfx canister --network=ic stop --all +dfx canister stop --all --network=ic ``` ## dfx canister uninstall-code @@ -874,7 +870,7 @@ dfx canister uninstall-code hello_world To uninstall all of the canisters you have deployed on the `ic` Internet Computer, you can run the following command: ``` bash -dfx canister --network=ic uninstall-code --all +dfx canister uninstall-code --all --network=ic ``` ## dfx canister update-settings diff --git a/docs/cli-reference/dfx-identity.md b/docs/cli-reference/dfx-identity.md index 12d7d9b8db..3470df2956 100644 --- a/docs/cli-reference/dfx-identity.md +++ b/docs/cli-reference/dfx-identity.md @@ -104,7 +104,7 @@ dfx identity get-wallet To display the canister identifier for the wallet canister associated with your identity on a specific testnet, you might run a command similar to the following: ``` bash -dfx identity --network=https://192.168.74.4 get-wallet +dfx identity get-wallet --network=https://192.168.74.4 ``` ## dfx identity import @@ -344,7 +344,7 @@ If you use more than one principal for your identity, you might have access to m For example, you might store the wallet canister identifier in an environment variable, then invoke the `dfx identity set-wallet` command to use that wallet canister for additional operations by running the following: export WALLET_CANISTER_ID=$(dfx identity get-wallet) - dfx identity --network=https://192.168.74.4 set-wallet --canister-name ${WALLET_CANISTER_ID} + dfx identity set-wallet --canister-name ${WALLET_CANISTER_ID} --network=https://192.168.74.4 ## dfx identity use diff --git a/docs/cli-reference/dfx-ledger.md b/docs/cli-reference/dfx-ledger.md index c45c19a6d3..2a9b9e3a6b 100644 --- a/docs/cli-reference/dfx-ledger.md +++ b/docs/cli-reference/dfx-ledger.md @@ -7,7 +7,7 @@ This command can be used to make ICP utility token transactions from one caniste The basic syntax for running `dfx ledger` commands is: ``` bash -dfx ledger [options] [subcommand] +dfx ledger [subcommand] [options] ``` Depending on the `dfx ledger` subcommand you specify, additional arguments, options, and flags might apply. For reference information and examples that illustrate using `dfx ledger` commands, select an appropriate command. @@ -68,7 +68,7 @@ Use the `dfx ledger balance` command to print your account balance or that of an ### Basic usage ``` bash -dfx ledger --network ic balance [of] [flag] +dfx ledger balance [of] [flag] --network ic ``` ### Flags @@ -93,7 +93,7 @@ You can specify the following argument for the `dfx ledger balance` command. You can use the `dfx ledger balance` command to check the balance of another user. For example, you can run the following command to see the ICP utlity tokens associated with a known Account Identifier: ``` bash -dfx ledger --network ic balance 03e3d86f29a069c6f2c5c48e01bc084e4ea18ad02b0eec8fccadf4487183c223 +dfx ledger balance 03e3d86f29a069c6f2c5c48e01bc084e4ea18ad02b0eec8fccadf4487183c223 --network ic ``` This command displays an ICP amount similar to the following: @@ -107,7 +107,7 @@ Use the `dfx ledger create-canister` command to convert ICP tokens to cycles and ### Basic usage ``` bash -dfx ledger --network ic create-canister controller [options] [flag] +dfx ledger create-canister [options] [flag] --network ic ``` ### Flags @@ -144,7 +144,7 @@ You can specify the following argument for the `dfx ledger create-canister` comm To create a new canister with cycles, transfer ICP tokens from your ledger account by running a command similar to the following: ``` bash -dfx ledger --network ic create-canister tsqwz-udeik-5migd-ehrev-pvoqv-szx2g-akh5s-fkyqc-zy6q7-snav6-uqe --amount 1.25 +dfx ledger create-canister tsqwz-udeik-5migd-ehrev-pvoqv-szx2g-akh5s-fkyqc-zy6q7-snav6-uqe --amount 1.25 --network ic ``` This command converts the number of ICP tokens you specify for the `--amount` argument into cycles, and associates the cycles with a new canister identifier controlled by the principal you specify. @@ -159,7 +159,7 @@ If the transaction is successful, the ledger records the event and you should se You can create a new canister by specifying separate values for ICP tokens and e8s by running a command similar to the following: ``` bash -dfx ledger --network ic create-canister tsqwz-udeik-5migd-ehrev-pvoqv-szx2g-akh5s-fkyqc-zy6q7-snav6-uqe --icp 3 --e8s 5000 +dfx ledger create-canister tsqwz-udeik-5migd-ehrev-pvoqv-szx2g-akh5s-fkyqc-zy6q7-snav6-uqe --icp 3 --e8s 5000 --network ic ``` ## dfx ledger fabricate-cycles @@ -261,7 +261,7 @@ You can specify the following argument for the `dfx ledger notify` command. The following example illustrates sending a `notify` message to the ledger in response to a `_send+` transaction that was recorded at the block height `75948`. ``` bash -dfx ledger --network ic notify 75948 tsqwz-udeik-5migd-ehrev-pvoqv-szx2g-akh5s-fkyqc-zy6q7-snav6-uqe +dfx ledger notify 75948 tsqwz-udeik-5migd-ehrev-pvoqv-szx2g-akh5s-fkyqc-zy6q7-snav6-uqe --network ic ``` ## dfx ledger top-up @@ -271,7 +271,7 @@ Use the `dfx ledger top-up` command to top up a canister with cycles minted from ### Basic usage ``` bash -dfx ledger --network ic top-up [options] canister [flag] +dfx ledger top-up [options] canister [flag] --network ic ``` ### Flags @@ -310,7 +310,7 @@ You can use the `dfx ledger top-up` command to top up the cycles of a specific c For example, you can run the following command to top-up a cycles wallet canister deployed on the Internet Computer with 1 ICP worth of cycles: ``` bash -dfx ledger --network ic top-up --icp 1 5a46r-jqaaa-aaaaa-qaadq-cai +dfx ledger top-up --icp 1 5a46r-jqaaa-aaaaa-qaadq-cai --network ic ``` This command displays output similar to the following: @@ -374,7 +374,7 @@ This command displays output similar to the following: You can check the balance of this account by running the following command: ``` bash -dfx ledger --network ic balance +dfx ledger balance --network ic ``` This command displays output similar to the following: @@ -384,11 +384,11 @@ This command displays output similar to the following: Use the `dfx ledger transfer` command to send some of your ICP balance to another known destination using the following command: ``` bash -dfx ledger --network ic transfer dd81336dbfef5c5870e84b48405c7b229c07ad999fdcacb85b9b9850bd60766f --memo 12345 --icp 1 +dfx ledger transfer dd81336dbfef5c5870e84b48405c7b229c07ad999fdcacb85b9b9850bd60766f --memo 12345 --icp 1 --network ic ``` This command displays output similar to the following: Transfer sent at BlockHeight: 59513 -You can then use the `dfx ledger --network ic balance` command to check that your account balance reflects the transaction you just made. +You can then use the `dfx ledger balance --network ic` command to check that your account balance reflects the transaction you just made. diff --git a/docs/cli-reference/dfx-parent.md b/docs/cli-reference/dfx-parent.md index 98be3f0e46..55487a72b6 100644 --- a/docs/cli-reference/dfx-parent.md +++ b/docs/cli-reference/dfx-parent.md @@ -7,7 +7,7 @@ Use the `dfx` parent command with flags and subcommands to specify the operation ## Basic usage ``` bash -dfx [option] [subcommand] [flag] +dfx [subcommand] [flag] ``` ## Flags @@ -17,7 +17,7 @@ You can use the following optional flags with the `dfx` parent command or with a | Flag | Description | |----------------------|-------------------------------------------------| | `-h`, `--help` | Displays usage information. | -| ` -q`, `--quiet` | Suppresses informational messages. | +| `-q`, `--quiet` | Suppresses informational messages. | | `-v`, `--verbose` | Displays detailed information about operations. | | `-V`, `--version` | Displays version information. | @@ -27,7 +27,7 @@ You can use the following options with the `dfx` command. | Option | Description | |--------------------------------|-------------------------------------------------| -| `-- identity ` | Specifies the user identity to use when running a command. | +| `--identity ` | Specifies the user identity to use when running a command. | | `--logfile ` | Writes log file messages to the specified log file name if you use the `--log file` logging option. | | `--log ` | Specifies the logging mode to use. + You can set the log mode to one of the following:
- `stderr` to log messages to the standard error facility.
- `tee` to write messages to both standard output and to a specified file name.
- `file` to write messages to a specified file name.
The default logging mode is stderr.| @@ -77,7 +77,7 @@ You can use the `--verbose` and `--quiet` flags to increment or decrement the lo Adding a `--quiet` flag decreases the logging level. For example, to remove all messages, you can run a command similar the following: ``` bash -dfx -qqqq build +dfx build -qqqq ``` Keep in mind that using TRACE level logging (`--vv`) generates a lot of log messages that can affect performance and should only be used when required for troubleshooting or analysis. @@ -85,7 +85,7 @@ Keep in mind that using TRACE level logging (`--vv`) generates a lot of log mess To output log messages to a file named `newlog.txt` and display the messages on your terminal when creating a new project, you can run a command similar to the following: ``` bash -dfx --log tee --logfile newlog.txt new hello_world +dfx new hello_world --log tee --logfile newlog.txt ``` ### Specifying a user identity @@ -96,4 +96,4 @@ In the most common use case, you use the `--identity` option to call specific ca For example, you might want to test whether the `devops` user identity can call the `modify_profile` function for the `accounts` canister by running the following command: - dfx --identity devops canister call accounts modify_profile '("Kris Smith")' + dfx canister call accounts modify_profile '("Kris Smith")' --identity devops diff --git a/docs/cli-reference/dfx-wallet.md b/docs/cli-reference/dfx-wallet.md index 5c7445cbef..efca02c305 100644 --- a/docs/cli-reference/dfx-wallet.md +++ b/docs/cli-reference/dfx-wallet.md @@ -140,7 +140,7 @@ You can use the following optional flags with the `dfx wallet add-controller` co You can use the `dfx wallet addresses` command to retrieve information on the addresses in your wallet's address book. For example: ``` -dfx wallet --network ic addresses +dfx wallet addresses --network ic ``` The command displays the controllers and custodians for the cycles wallet with output similar to the following: diff --git a/docs/cli-reference/index.md b/docs/cli-reference/index.md index 11426ec709..aa639a15d2 100644 --- a/docs/cli-reference/index.md +++ b/docs/cli-reference/index.md @@ -7,7 +7,7 @@ You can use the `dfx` parent command with different flags and subcommands to per The basic syntax for running `dfx` commands is: ``` bash -dfx [option] [subcommand] [flag] +dfx [subcommand] [flag] ``` Depending on the subcommand, the options and flags you specify might apply to the parent command or to a specific subcommand. For example, the flags for enabling or suppressing verbose logging are specified for the `dfx` parent command, then applied to any subcommands. diff --git a/e2e/tests-dfx/basic-project.bash b/e2e/tests-dfx/basic-project.bash index aef756cfc2..a5b1502394 100644 --- a/e2e/tests-dfx/basic-project.bash +++ b/e2e/tests-dfx/basic-project.bash @@ -41,7 +41,7 @@ teardown() { assert_eq '("Hello, Blueberry!")' # Call using the wallet's call forwarding - assert_command dfx canister --wallet="$(dfx identity get-wallet)" call --async hello_backend greet Blueberry + assert_command dfx canister call --async hello_backend greet Blueberry --wallet="$(dfx identity get-wallet)" # At this point $output is the request ID. # shellcheck disable=SC2154 assert_command dfx canister request-status "$stdout" "$(dfx identity get-wallet)" @@ -93,7 +93,7 @@ teardown() { assert_eq "(1_337 : nat)" # Call using the wallet's call forwarding - assert_command dfx canister --wallet="$(dfx identity get-wallet)" call hello_backend read --async + assert_command dfx canister call hello_backend read --async --wallet="$(dfx identity get-wallet)" assert_command dfx canister request-status "$stdout" "$(dfx identity get-wallet)" assert_eq '(variant { 17_724 = record { 153_986_224 = blob "DIDL\00\01}\b9\0a" } })' diff --git a/e2e/tests-dfx/build.bash b/e2e/tests-dfx/build.bash index 6e7ab428de..613d93e14d 100644 --- a/e2e/tests-dfx/build.bash +++ b/e2e/tests-dfx/build.bash @@ -178,14 +178,14 @@ teardown() { @test "build succeeds with network parameter" { dfx_start - dfx canister --network local create --all + dfx canister create --all --network local assert_command dfx build --network local } @test "build succeeds with URL as network parameter" { dfx_start webserver_port=$(get_webserver_port) - dfx canister --network "http://127.0.0.1:$webserver_port" create --all + dfx canister create --all --network "http://127.0.0.1:$webserver_port" assert_command dfx build --network "http://127.0.0.1:$webserver_port" } @@ -194,7 +194,7 @@ teardown() { setup_actuallylocal_network - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal assert_command dfx build --network actuallylocal } @@ -203,7 +203,7 @@ teardown() { setup_actuallylocal_network assert_command dfx_set_wallet - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal assert_command dfx build --network actuallylocal } @@ -220,7 +220,7 @@ teardown() { setup_actuallylocal_network assert_command dfx_set_wallet - dfx canister --network actuallylocal create --all + dfx canister create --all --network actuallylocal assert_command dfx build --network actuallylocal assert_command ls .dfx/actuallylocal/canisters/e2e_project_backend/ assert_command ls .dfx/actuallylocal/canisters/e2e_project_backend/e2e_project_backend.wasm diff --git a/e2e/tests-dfx/call.bash b/e2e/tests-dfx/call.bash index 1f7ee09e05..5c98d3e9bd 100644 --- a/e2e/tests-dfx/call.bash +++ b/e2e/tests-dfx/call.bash @@ -111,7 +111,7 @@ teardown() { dfx_start dfx deploy assert_command_fail dfx canister call hello_backend greet '' --with-cycles 100 - assert_command dfx canister --wallet "$(dfx identity get-wallet)" call hello_backend greet '' --with-cycles 100 + assert_command dfx canister call hello_backend greet '' --with-cycles 100 --wallet "$(dfx identity get-wallet)" } @test "call by canister id outside of a project" { @@ -126,7 +126,7 @@ teardown() { cd "$DFX_E2E_TEMP_DIR" mkdir "not-a-project-dir" cd "not-a-project-dir" - assert_command dfx canister --network "$NETWORK" call "$ID" greet '("you")' + assert_command dfx canister call "$ID" greet '("you")' --network "$NETWORK" assert_match '("Hello, you!")' ) } diff --git a/e2e/tests-dfx/create.bash b/e2e/tests-dfx/create.bash index a4a63dfd05..895f3fa517 100644 --- a/e2e/tests-dfx/create.bash +++ b/e2e/tests-dfx/create.bash @@ -61,12 +61,12 @@ teardown() { @test "create succeeds with network parameter" { dfx_start - assert_command dfx canister --network local create --all + assert_command dfx canister create --all --network local } @test "create fails with incorrect network" { dfx_start - assert_command_fail dfx canister --network nosuch create --all + assert_command_fail dfx canister create --all --network nosuch assert_match "ComputeNetworkNotFound" } @@ -74,7 +74,7 @@ teardown() { dfx_start setup_actuallylocal_network - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal } @test "create with wallet succeeds when requested network is configured" { @@ -82,7 +82,7 @@ teardown() { setup_actuallylocal_network assert_command dfx_set_wallet - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal } @test "create fails if selected network exists but has no providers" { @@ -90,7 +90,7 @@ teardown() { # shellcheck disable=SC2094 cat <<<"$(jq '.networks.actuallylocal.providers=[]' dfx.json)" >dfx.json - assert_command_fail dfx canister --network actuallylocal create --all + assert_command_fail dfx canister create --all --network actuallylocal assert_match "Cannot find providers for network" } @@ -98,14 +98,14 @@ teardown() { dfx_start # shellcheck disable=SC2094 cat <<<"$(jq '.networks.actuallylocal.providers=["http://not-real.nowhere.test."]' dfx.json)" >dfx.json - assert_command_fail dfx canister --network actuallylocal create --all + assert_command_fail dfx canister create --all --network actuallylocal assert_match "dns error: failed to lookup address information" } @test "create accepts --controller named parameter, with controller by identity name" { dfx_start dfx identity new --disable-encryption alice - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) assert_command dfx canister create --all --controller alice @@ -113,14 +113,14 @@ teardown() { assert_match "Controllers: $ALICE_PRINCIPAL" assert_command_fail dfx deploy - assert_command dfx --identity alice deploy + assert_command dfx deploy --identity alice } @test "create accepts --controller named parameter, with controller by identity principal" { dfx_start dfx identity new --disable-encryption alice - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - ALICE_WALLET=$(dfx --identity alice identity get-wallet) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) assert_command dfx canister create --all --controller "${ALICE_PRINCIPAL}" assert_command dfx canister info e2e_project_backend @@ -128,21 +128,21 @@ teardown() { assert_match "Controllers: $ALICE_PRINCIPAL" assert_command_fail dfx deploy - assert_command dfx --identity alice deploy + assert_command dfx deploy --identity alice } @test "create accepts --controller named parameter, with controller by wallet principal" { dfx_start dfx identity new --disable-encryption alice - ALICE_WALLET=$(dfx --identity alice identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) assert_command dfx canister create --all --controller "${ALICE_WALLET}" assert_command dfx canister info e2e_project_backend assert_match "Controllers: $ALICE_WALLET" assert_command_fail dfx deploy - assert_command_fail dfx --identity alice deploy - assert_command dfx --identity alice deploy --wallet "${ALICE_WALLET}" + assert_command_fail dfx deploy --identity alice + assert_command dfx deploy --identity alice --wallet "${ALICE_WALLET}" } @test "create accepts --controller named parameter, with controller by name of selected identity" { @@ -151,7 +151,7 @@ teardown() { dfx_start dfx identity new --disable-encryption alice dfx identity new --disable-encryption bob - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) dfx identity use bob @@ -162,15 +162,15 @@ teardown() { assert_match "Controllers: $BOB_PRINCIPAL" assert_command_fail dfx deploy - assert_command dfx --identity bob deploy + assert_command dfx deploy --identity bob } @test "create single controller accepts --controller named parameter, with controller by identity name" { dfx_start dfx identity new --disable-encryption alice dfx identity new --disable-encryption bob - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) assert_command dfx canister create --controller alice e2e_project_backend assert_command dfx canister create --controller bob e2e_project_frontend @@ -182,36 +182,36 @@ teardown() { assert_match "Controllers: $BOB_PRINCIPAL" # check this first, because alice will deploy e2e_project in the next step - assert_command_fail dfx --identity bob deploy e2e_project_backend + assert_command_fail dfx deploy e2e_project_backend --identity bob # this actually deploys e2e_project before failing, because it is a dependency - assert_command_fail dfx --identity alice deploy e2e_project_frontend + assert_command_fail dfx deploy e2e_project_frontend --identity alice - assert_command dfx --identity alice deploy e2e_project_backend - assert_command dfx --identity bob deploy e2e_project_frontend + assert_command dfx deploy e2e_project_backend --identity alice + assert_command dfx deploy e2e_project_frontend --identity bob } @test "create canister with multiple controllers" { dfx_start dfx identity new --disable-encryption alice dfx identity new --disable-encryption bob - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) # awk step is to avoid trailing space PRINCIPALS_SORTED=$(echo "$ALICE_PRINCIPAL" "$BOB_PRINCIPAL" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s",$1,$2}' ) - assert_command dfx --identity alice canister create --all --controller alice --controller bob + assert_command dfx canister create --all --controller alice --controller bob --identity alice assert_command dfx canister info e2e_project_backend assert_match "Controllers: ${PRINCIPALS_SORTED}" - assert_command dfx --identity alice deploy - assert_command_fail dfx --identity bob deploy + assert_command dfx deploy --identity alice + assert_command_fail dfx deploy --identity bob # The certified assets canister will have added alice as an authorized user, because she was the caller # at initialization time. Bob has to be added separately. BUT, the canister has to be deployed first # in order to call the authorize method. - assert_command dfx --identity alice canister call e2e_project_frontend authorize "(principal \"$BOB_PRINCIPAL\")" + assert_command dfx canister call e2e_project_frontend authorize "(principal \"$BOB_PRINCIPAL\")" --identity alice - assert_command dfx --identity bob deploy + assert_command dfx deploy --identity bob } @test "reports wallet must be upgraded if attempting to create a canister with multiple controllers through an old wallet" { @@ -221,13 +221,13 @@ teardown() { dfx identity new --disable-encryption alice dfx identity new --disable-encryption bob - assert_command_fail dfx --identity alice canister create --all --controller alice --controller bob + assert_command_fail dfx canister create --all --controller alice --controller bob --identity alice assert_match "The wallet canister must be upgraded: The installed wallet does not support multiple controllers." assert_match "To upgrade, run dfx wallet upgrade" use_wallet_wasm 0.8.2 - assert_command dfx --identity alice wallet upgrade - assert_command dfx --identity alice canister create --all --controller alice --controller bob + assert_command dfx wallet upgrade --identity alice + assert_command dfx canister create --all --controller alice --controller bob --identity alice } @test "canister-create on mainnet without wallet does not propagate the 404" { diff --git a/e2e/tests-dfx/error_context.bash b/e2e/tests-dfx/error_context.bash index 3e15aff331..01c317dcce 100644 --- a/e2e/tests-dfx/error_context.bash +++ b/e2e/tests-dfx/error_context.bash @@ -45,7 +45,7 @@ teardown() { # can't write it? chmod u=r,go= .dfx/local/wallets.json assert_command dfx identity new --disable-encryption alice - assert_command_fail dfx --identity alice identity get-wallet + assert_command_fail dfx identity get-wallet --identity alice assert_match "Unable to write .*/.dfx/local/wallets.json" assert_match "Permission denied" } diff --git a/e2e/tests-dfx/error_diagnosis.bash b/e2e/tests-dfx/error_diagnosis.bash index f58a510400..302c0f30af 100644 --- a/e2e/tests-dfx/error_diagnosis.bash +++ b/e2e/tests-dfx/error_diagnosis.bash @@ -28,7 +28,7 @@ teardown() { # calling canister status with different identity provokes HTTP 403 assert_command_fail dfx canister status hello_backend assert_match "not part of the controllers" # this is part of the error explanation - assert_match "'dfx canister \(--network ic\) update-settings --add-controller '" # this is part of the solution + assert_match "'dfx canister update-settings --add-controller \(--network ic\)'" # this is part of the solution } @test "Instruct user to set a wallet" { @@ -40,5 +40,5 @@ teardown() { # this will fail because no wallet is configured for alice on network ic assert_command_fail dfx deploy --network ic assert_match "requires a configured wallet" # this is part of the error explanation - assert_match "'dfx identity --network set-wallet '" # this is part of the solution + assert_match "'dfx identity set-wallet --network '" # this is part of the solution } diff --git a/e2e/tests-dfx/fabricate_cycles.bash b/e2e/tests-dfx/fabricate_cycles.bash index 682c2982cd..616668fce1 100644 --- a/e2e/tests-dfx/fabricate_cycles.bash +++ b/e2e/tests-dfx/fabricate_cycles.bash @@ -39,15 +39,15 @@ teardown() { @test "ledger fabricate-cycles fails on real IC" { install_asset greet - assert_command_fail dfx ledger --network ic fabricate-cycles --all + assert_command_fail dfx ledger fabricate-cycles --all --network ic assert_match "Cannot run this on the real IC." } @test "ledger fabricate-cycles fails with wrong option combinations" { install_asset greet - assert_command_fail dfx ledger --network ic fabricate-cycles --all --cycles 1 --icp 1 - assert_command_fail dfx ledger --network ic fabricate-cycles --all --icp 1 --t 1 - assert_command_fail dfx ledger --network ic fabricate-cycles --all --t 1 --cycles 1 - assert_command_fail dfx ledger --network ic fabricate-cycles --all --e8s 1 --amount 1 - assert_command_fail dfx ledger --network ic fabricate-cycles --all --amount 1 --cycles 1 + assert_command_fail dfx ledger fabricate-cycles --all --cycles 1 --icp 1 --network ic + assert_command_fail dfx ledger fabricate-cycles --all --icp 1 --t 1 --network ic + assert_command_fail dfx ledger fabricate-cycles --all --t 1 --cycles 1 --network ic + assert_command_fail dfx ledger fabricate-cycles --all --e8s 1 --amount 1 --network ic + assert_command_fail dfx ledger fabricate-cycles --all --amount 1 --cycles 1 --network ic } diff --git a/e2e/tests-dfx/identity.bash b/e2e/tests-dfx/identity.bash index 120331452a..d04099b577 100644 --- a/e2e/tests-dfx/identity.bash +++ b/e2e/tests-dfx/identity.bash @@ -20,15 +20,15 @@ teardown() { dfx_start assert_command dfx identity new --disable-encryption jose - PRINCPAL_ID=$(dfx --identity jose identity get-principal) + PRINCPAL_ID=$(dfx identity get-principal --identity jose) - dfx --identity jose canister create e2e_project_backend - dfx --identity jose build e2e_project_backend - dfx --identity jose canister install e2e_project_backend + dfx canister create e2e_project_backend --identity jose + dfx build e2e_project_backend --identity jose + dfx canister install e2e_project_backend --identity jose - assert_command dfx --identity jose canister call e2e_project_backend amInitializer + assert_command dfx canister call e2e_project_backend amInitializer --identity jose - SENDER_ID=$(dfx --identity jose canister call e2e_project_backend fromCall) + SENDER_ID=$(dfx canister call e2e_project_backend fromCall --identity jose) if [ "$PRINCPAL_ID" -ne "$SENDER_ID" ]; then echo "IDs did not match: Principal '${PRINCPAL_ID}' != Sender '${SENDER_ID}'..." | fail @@ -42,17 +42,17 @@ teardown() { ANONYMOUS_PRINCIPAL_ID="2vxsx-fae" - PRINCIPAL_ID=$(dfx --identity anonymous identity get-principal) + PRINCIPAL_ID=$(dfx identity get-principal --identity anonymous) if [ "$PRINCIPAL_ID" -ne "$ANONYMOUS_PRINCIPAL_ID" ]; then echo "IDs did not match: Principal '${ANONYMOUS_PRINCIPAL_ID}' != Sender '${PRINCIPAL_ID}'..." | fail fi - dfx --identity jose canister create e2e_project_backend - dfx --identity jose build e2e_project_backend - dfx --identity jose canister install e2e_project_backend + dfx canister create e2e_project_backend --identity jose + dfx build e2e_project_backend --identity jose + dfx canister install e2e_project_backend --identity jose - SENDER_ID=$(dfx --identity anonymous canister call e2e_project_backend fromCall) + SENDER_ID=$(dfx canister call e2e_project_backend fromCall --identity anonymous) if [ "$ANONYMOUS_PRINCIPAL_ID" -ne "$SENDER_ID" ]; then echo "IDs did not match: Principal '${ANONYMOUS_PRINCIPAL_ID}' != Sender '${SENDER_ID}'..." | fail @@ -111,25 +111,25 @@ teardown() { assert_command dfx identity new --disable-encryption alice assert_command dfx identity new --disable-encryption bob - dfx --identity alice canister create --all - assert_command dfx --identity alice build - assert_command dfx --identity alice canister install --all + dfx canister create --all --identity alice + assert_command dfx build --identity alice + assert_command dfx canister install --all --identity alice # The user Identity's principal is the initializer - assert_command dfx --identity alice canister call e2e_project_backend amInitializer + assert_command dfx canister call e2e_project_backend amInitializer --identity alice assert_eq '(true)' - assert_command dfx --identity bob canister call e2e_project_backend amInitializer + assert_command dfx canister call e2e_project_backend amInitializer --identity bob assert_eq '(false)' # these all fail (other identities are not initializer; cannot store assets): - assert_command_fail dfx --identity bob canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' - assert_command_fail dfx --identity default canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' + assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' --identity bob + assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' --identity default assert_command_fail dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' assert_command_fail dfx canister call e2e_project_frontend retrieve '("B")' # but alice, the initializer, can store assets: - assert_command dfx --identity alice canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' + assert_command dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=vec { 88; 87; 86; }})' --identity alice assert_eq '()' assert_command dfx canister call --output idl e2e_project_frontend retrieve '("B")' assert_eq '(blob "XWV")' @@ -140,10 +140,10 @@ teardown() { dfx_start assert_command dfx identity new --disable-encryption alice - dfx --identity alice canister create --all - assert_command dfx --identity alice build - assert_command dfx --identity alice canister install --all - assert_command dfx --identity alice canister call e2e_project_backend amInitializer + dfx canister create --all --identity alice + assert_command dfx build --identity alice + assert_command dfx canister install --all --identity alice + assert_command dfx canister call e2e_project_backend amInitializer --identity alice assert_eq '(true)' assert_command dfx canister call e2e_project_backend amInitializer assert_eq '(false)' @@ -152,10 +152,10 @@ teardown() { assert_command dfx identity whoami assert_eq 'default' - assert_command dfx --identity bob canister call e2e_project_backend amInitializer + assert_command dfx canister call e2e_project_backend amInitializer --identity bob assert_eq '(true)' - assert_command dfx --identity bob canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob "hello"})' + assert_command dfx canister call e2e_project_frontend store '(record{key="B"; content_type="application/octet-stream"; content_encoding="identity"; content=blob "hello"})' --identity bob assert_eq '()' assert_command dfx canister call --output idl e2e_project_frontend retrieve '("B")' assert_eq '(blob "hello")' diff --git a/e2e/tests-dfx/identity_command.bash b/e2e/tests-dfx/identity_command.bash index 922a210cde..5333900717 100644 --- a/e2e/tests-dfx/identity_command.bash +++ b/e2e/tests-dfx/identity_command.bash @@ -18,8 +18,8 @@ teardown() { assert_command dfx identity new --disable-encryption jose assert_command dfx identity new --disable-encryption juana - PRINCPAL_ID_JOSE=$(dfx --identity jose identity get-principal) - PRINCPAL_ID_JUANA=$(dfx --identity juana identity get-principal) + PRINCPAL_ID_JOSE=$(dfx identity get-principal --identity jose) + PRINCPAL_ID_JUANA=$(dfx identity get-principal --identity juana) if [ "$PRINCPAL_ID_JOSE" -eq "$PRINCPAL_ID_JUANA" ]; then echo "IDs should not match: Jose '${PRINCPAL_ID_JOSE}' == Juana '${PRINCPAL_ID_JUANA}'..." | fail @@ -137,7 +137,7 @@ teardown() { WALLET="rwlgt-iiaaa-aaaaa-aaaaa-cai" assert_command dfx identity new --disable-encryption alice assert_command dfx identity use alice - assert_command dfx identity --network ic set-wallet --force "$WALLET" + assert_command dfx identity set-wallet --force "$WALLET" --network ic assert_command dfx identity use default assert_command_fail dfx identity remove alice # make sure the configured wallet is displayed @@ -308,20 +308,20 @@ teardown() { assert_eq 'charlie' } -## dfx --identity (+other commands) +## dfx (+other commands) --identity -@test "dfx --identity (name) identity whoami: shows the overriding identity" { +@test "dfx identity whoami --identity (name): shows the overriding identity" { assert_command dfx identity whoami assert_eq 'default' "$stdout" assert_command dfx identity new --disable-encryption charlie assert_command dfx identity new --disable-encryption alice - assert_command dfx --identity charlie identity whoami + assert_command dfx identity whoami --identity charlie assert_eq 'charlie' - assert_command dfx --identity alice identity whoami + assert_command dfx identity whoami --identity alice assert_eq 'alice' } -@test "dfx --identity does not persistently change the selected identity" { +@test "dfx (command) --identity does not persistently change the selected identity" { assert_command dfx identity whoami assert_eq 'default' "$stdout" assert_command dfx identity new --disable-encryption charlie @@ -329,7 +329,7 @@ teardown() { assert_command dfx identity use charlie assert_command dfx identity whoami assert_eq 'charlie' - assert_command dfx --identity alice identity whoami + assert_command dfx identity whoami --identity alice assert_eq 'alice' assert_command dfx identity whoami assert_eq 'charlie' @@ -408,10 +408,10 @@ oUQDQgAEBQKn0CLyiA/fQf6L8S07/MDJ9kIJTzZvm2jFo2/yvSToGee+XzP/GCE4 -----END EC PRIVATE KEY----- XXX assert_command dfx identity import --disable-encryption private-key-no-ec-parameters private-key-no-ec-parameters.pem - assert_command dfx --identity private-key-no-ec-parameters identity get-principal + assert_command dfx identity get-principal --identity private-key-no-ec-parameters assert_eq "j4p4p-o5ogq-4gzev-t3kay-hpm5o-xuwpz-yvrpp-47cc4-qyunt-k76yw-qae" echo "{}" >dfx.json # avoid "dfx.json not found, using default." - assert_command dfx --identity private-key-no-ec-parameters ledger account-id + assert_command dfx ledger account-id --identity private-key-no-ec-parameters assert_eq "3c00cf85d77b9dbf74a2acec1d9a9e73a3fc65f5048c64800b15f3b2c4c8eb11" } diff --git a/e2e/tests-dfx/install.bash b/e2e/tests-dfx/install.bash index fa0efa5d29..b76b1ea583 100644 --- a/e2e/tests-dfx/install.bash +++ b/e2e/tests-dfx/install.bash @@ -52,7 +52,7 @@ teardown() { dfx canister create --all dfx build - assert_command dfx canister --network local install --all + assert_command dfx canister install --all --network local assert_match "Installing code for canister e2e_project_backend" } @@ -62,7 +62,7 @@ teardown() { dfx canister create --all dfx build - assert_command_fail dfx canister --network nosuch install --all + assert_command_fail dfx canister install --all --network nosuch assert_match "ComputeNetworkNotFound.*nosuch" } diff --git a/e2e/tests-dfx/ledger.bash b/e2e/tests-dfx/ledger.bash index eda7b0ba64..891151bd52 100644 --- a/e2e/tests-dfx/ledger.bash +++ b/e2e/tests-dfx/ledger.bash @@ -70,7 +70,7 @@ teardown() { @test "ledger subaccounts" { subacct=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f - assert_command dfx --identity bob ledger account-id --subaccount "$subacct" + assert_command dfx ledger account-id --identity bob --subaccount "$subacct" assert_match 5a94fe181e9d411c58726cb87cbf2d016241b6c350bc3330e4869ca76e54ecbc dfx identity use alice @@ -93,7 +93,7 @@ teardown() { assert_match "10000.00000000 ICP" assert_command dfx ledger balance --subaccount "$subacct" assert_match "9999.99990000 ICP" - assert_command dfx --identity alice ledger balance + assert_command dfx ledger balance --identity alice assert_match "9999.99990000 ICP" } tc_to_num() { diff --git a/e2e/tests-dfx/network.bash b/e2e/tests-dfx/network.bash index c3830f3507..584d124719 100644 --- a/e2e/tests-dfx/network.bash +++ b/e2e/tests-dfx/network.bash @@ -22,10 +22,10 @@ teardown() { dfx_set_wallet assert_command dfx_set_wallet - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal # canister creates writes to a spinner (stderr), not stdout - assert_command dfx canister --network actuallylocal id e2e_project_backend + assert_command dfx canister id e2e_project_backend --network actuallylocal assert_match "$(jq -r .e2e_project_backend.actuallylocal dfx.json + cat <<<"$(jq '.networks.actuallylocal.type="ephemeral"' dfx.json)" >dfx.json assert_command dfx_set_wallet - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal # canister creates writes to a spinner (stderr), not stdout - assert_command dfx canister --network actuallylocal id e2e_project_backend + assert_command dfx canister id e2e_project_backend --network actuallylocal assert_match "$(jq -r .e2e_project_backend.actuallylocal <.dfx/actuallylocal/canister_ids.json)" } @test "create stores canister ids for default-ephemeral local networks in .dfx/{network}canister_ids.json" { dfx_start - assert_command dfx canister --network local create --all + assert_command dfx canister create --all --network local # canister creates writes to a spinner (stderr), not stdout - assert_command dfx canister --network local id e2e_project_backend + assert_command dfx canister id e2e_project_backend --network local assert_match "$(jq -r .e2e_project_backend.local <.dfx/local/canister_ids.json)" } @@ -59,12 +59,12 @@ teardown() { dfx_start # shellcheck disable=SC2094 - cat <<<"$(jq .networks.local.type=\"persistent\" dfx.json)" >dfx.json + cat <<<"$(jq '.networks.local.type="persistent"' dfx.json)" >dfx.json - assert_command dfx canister --network local create --all + assert_command dfx canister create --all --network local # canister creates writes to a spinner (stderr), not stdout - assert_command dfx canister --network local id e2e_project_backend + assert_command dfx canister id e2e_project_backend --network local assert_match "$(jq -r .e2e_project_backend.local dfx.json + cat <<<"$(jq ".canisters.remote.remote.id.actuallylocal=\"$REMOTE_CANISTER_ID\"" dfx.json)" >dfx.json # set up: remote method is update, local is query # call remote method as update to make a change assert_command dfx deploy --network actuallylocal - assert_command dfx canister --network actuallylocal call remote which_am_i + assert_command dfx canister call remote which_am_i --network actuallylocal assert_eq '("actual")' cat dfx.json @@ -51,24 +51,24 @@ teardown() { # - look up the canister by (remote) canister id # - use the remote candid definition # - assert_command dfx canister --network actuallylocal call --query "$REMOTE_CANISTER_ID" make_struct '("A query by principal", "B query by principal")' + assert_command dfx canister call --query "$REMOTE_CANISTER_ID" make_struct '("A query by principal", "B query by principal")' --network actuallylocal assert_eq '(record { a = "A query by principal"; b = "B query by principal" })' - assert_command dfx canister --network actuallylocal call "$REMOTE_CANISTER_ID" make_struct '("A default by principal", "B default by principal")' + assert_command dfx canister call "$REMOTE_CANISTER_ID" make_struct '("A default by principal", "B default by principal")' --network actuallylocal assert_eq '(record { a = "A default by principal"; b = "B default by principal" })' - assert_command dfx canister --network actuallylocal call --update "$REMOTE_CANISTER_ID" make_struct '("A update by principal", "B update by principal")' + assert_command dfx canister call --update "$REMOTE_CANISTER_ID" make_struct '("A update by principal", "B update by principal")' --network actuallylocal assert_eq '(record { a = "A update by principal"; b = "B update by principal" })' - assert_command dfx canister --network actuallylocal call --query remote make_struct '("A query by name", "B query by name")' + assert_command dfx canister call --query remote make_struct '("A query by name", "B query by name")' --network actuallylocal assert_eq '(record { a = "A query by name"; b = "B query by name" })' - assert_command dfx canister --network actuallylocal call remote make_struct '("A default by name", "B default by name")' + assert_command dfx canister call remote make_struct '("A default by name", "B default by name")' --network actuallylocal assert_eq '(record { a = "A default by name"; b = "B default by name" })' - assert_command dfx canister --network actuallylocal call --update remote make_struct '("A update by name", "B update by name")' + assert_command dfx canister call --update remote make_struct '("A update by name", "B update by name")' --network actuallylocal assert_eq '(record { a = "A update by name"; b = "B update by name" })' # This also should work when no canister type can be determined / if no info but the bare minimum of remote id and remote candid is given: # shellcheck disable=SC2094 cat <<<"$(jq 'del(.canisters.remote.main)' dfx.json)" >dfx.json - assert_command dfx canister --network actuallylocal call --query remote make_struct '("A query by name", "B query by name")' + assert_command dfx canister call --query remote make_struct '("A query by name", "B query by name")' --network actuallylocal assert_eq '(record { a = "A query by name"; b = "B query by name" })' # We can't check this for sign, because dfx canister send outputs something like this: @@ -83,15 +83,15 @@ teardown() { # We try to call with --query. # We expect dfx to notice that the method is in fact an update, which it knows from the remote candid definition. # - assert_command_fail dfx canister --network actuallylocal call --query "$REMOTE_CANISTER_ID" actual_update_mock_query_remote_candid_update '("call by principal with --query")' + assert_command_fail dfx canister call --query "$REMOTE_CANISTER_ID" actual_update_mock_query_remote_candid_update '("call by principal with --query")' --network actuallylocal assert_match 'not a query method' - assert_command_fail dfx canister --network actuallylocal call --query remote actual_update_mock_query_remote_candid_update '("call by name with --query")' + assert_command_fail dfx canister call --query remote actual_update_mock_query_remote_candid_update '("call by name with --query")' --network actuallylocal assert_match 'not a query method' # And the same for dfx canister sign: - assert_command_fail dfx canister --network actuallylocal sign --query "$REMOTE_CANISTER_ID" actual_update_mock_query_remote_candid_update '("call by principal with --query")' + assert_command_fail dfx canister sign --query "$REMOTE_CANISTER_ID" actual_update_mock_query_remote_candid_update '("call by principal with --query")' --network actuallylocal assert_match 'not a query method' - assert_command_fail dfx canister --network actuallylocal sign --query remote actual_update_mock_query_remote_candid_update '("call by name with --query")' + assert_command_fail dfx canister sign --query remote actual_update_mock_query_remote_candid_update '("call by name with --query")' --network actuallylocal assert_match 'not a query method' } @@ -102,7 +102,7 @@ teardown() { dfx identity new --disable-encryption alice - assert_command dfx --identity alice deploy --network actuallylocal + assert_command dfx deploy --network actuallylocal --identity alice REMOTE_CANISTER_ID=$(jq -r .remote.actuallylocal canister_ids.json) echo "Remote canister id: $REMOTE_CANISTER_ID" @@ -112,9 +112,9 @@ teardown() { setup_actuallylocal_network setup_local_network # shellcheck disable=SC2094 - cat <<<"$(jq .canisters.remote.remote.id.actuallylocal=\""$REMOTE_CANISTER_ID"\" dfx.json)" >dfx.json + cat <<<"$(jq ".canisters.remote.remote.id.actuallylocal=\"$REMOTE_CANISTER_ID\"" dfx.json)" >dfx.json - assert_command_fail dfx canister --network actuallylocal create remote + assert_command_fail dfx canister create remote --network actuallylocal assert_match "remote" canister is remote on network actuallylocal and has canister id: "$REMOTE_CANISTER_ID" } @@ -125,7 +125,7 @@ teardown() { dfx identity new --disable-encryption alice - assert_command dfx --identity alice deploy --network actuallylocal + assert_command dfx deploy --network actuallylocal --identity alice REMOTE_CANISTER_ID=$(jq -r .remote.actuallylocal canister_ids.json) echo "Remote canister id: $REMOTE_CANISTER_ID" @@ -135,9 +135,9 @@ teardown() { setup_actuallylocal_network setup_local_network # shellcheck disable=SC2094 - cat <<<"$(jq .canisters.remote.remote.id.actuallylocal=\""$REMOTE_CANISTER_ID"\" dfx.json)" >dfx.json + cat <<<"$(jq ".canisters.remote.remote.id.actuallylocal=\"$REMOTE_CANISTER_ID\"" dfx.json)" >dfx.json - assert_command_fail dfx canister --network actuallylocal install remote + assert_command_fail dfx canister install remote --network actuallylocal assert_match "Canister 'remote' is a remote canister on network 'actuallylocal', and cannot be installed from here." } @@ -152,10 +152,10 @@ teardown() { # dfx identity new --disable-encryption alice - assert_command dfx --identity alice deploy --network actuallylocal - assert_command dfx --identity alice canister --network actuallylocal call remote write '("this is data in the remote canister")' + assert_command dfx deploy --network actuallylocal --identity alice + assert_command dfx canister call remote write '("this is data in the remote canister")' --identity alice --network actuallylocal - assert_command dfx --identity alice canister --network actuallylocal call remote read + assert_command dfx canister call remote read --identity alice --network actuallylocal assert_eq '("this is data in the remote canister")' REMOTE_CANISTER_ID=$(jq -r .remote.actuallylocal canister_ids.json) @@ -166,7 +166,7 @@ teardown() { setup_actuallylocal_network setup_local_network # shellcheck disable=SC2094 - cat <<<"$(jq .canisters.remote.remote.id.actuallylocal=\""$REMOTE_CANISTER_ID"\" dfx.json)" >dfx.json + cat <<<"$(jq ".canisters.remote.remote.id.actuallylocal=\"$REMOTE_CANISTER_ID\"" dfx.json)" >dfx.json # Here we want to make sure that create+build+install works with the common flow assert_command dfx canister create --all @@ -178,29 +178,29 @@ teardown() { assert_command dfx canister call remote which_am_i assert_eq '("mock")' - assert_command dfx canister --network actuallylocal create --all + assert_command dfx canister create --all --network actuallylocal assert_command dfx build --network actuallylocal - assert_command dfx canister --network actuallylocal install --all + assert_command dfx canister install --all --network actuallylocal - assert_command dfx canister --network actuallylocal call basic read_remote + assert_command dfx canister call basic read_remote --network actuallylocal assert_eq '("this is data in the remote canister")' # We can change the value by calling the original canister - assert_command dfx canister --network actuallylocal call "${REMOTE_CANISTER_ID}" write '("altered data (by canister id) in the remote canister")' - assert_command dfx canister --network actuallylocal call basic read_remote + assert_command dfx canister call "${REMOTE_CANISTER_ID}" write '("altered data (by canister id) in the remote canister")' --network actuallylocal + assert_command dfx canister call basic read_remote --network actuallylocal assert_eq '("altered data (by canister id) in the remote canister")' # We can also call through the canister name - assert_command dfx canister --network actuallylocal call remote write '("altered data (by canister name) in the remote canister")' - assert_command dfx canister --network actuallylocal call basic read_remote + assert_command dfx canister call remote write '("altered data (by canister name) in the remote canister")' --network actuallylocal + assert_command dfx canister call basic read_remote --network actuallylocal assert_eq '("altered data (by canister name) in the remote canister")' - assert_command dfx canister --network actuallylocal call remote which_am_i + assert_command dfx canister call remote which_am_i --network actuallylocal assert_eq '("actual")' assert_command jq .basic.actuallylocal canister_ids.json - assert_eq '"'"$(dfx canister --network actuallylocal id basic)"'"' + assert_eq '"'"$(dfx canister id basic --network actuallylocal)"'"' assert_command jq .remote canister_ids.json assert_eq "null" @@ -221,7 +221,7 @@ teardown() { # dfx identity new --disable-encryption alice - assert_command dfx --identity alice deploy --network actuallylocal + assert_command dfx deploy --network actuallylocal --identity alice REMOTE_CANISTER_ID=$(jq -r .remote.actuallylocal canister_ids.json) echo "Remote canister id: $REMOTE_CANISTER_ID" @@ -231,7 +231,7 @@ teardown() { setup_actuallylocal_network setup_local_network # shellcheck disable=SC2094 - cat <<<"$(jq .canisters.remote.remote.id.actuallylocal=\""$REMOTE_CANISTER_ID"\" dfx.json)" >dfx.json + cat <<<"$(jq ".canisters.remote.remote.id.actuallylocal=\"$REMOTE_CANISTER_ID\"" dfx.json)" >dfx.json # We expect the local network deploy to succeed, because it is built using the candid file from # the local canister. @@ -258,10 +258,10 @@ teardown() { # dfx identity new --disable-encryption alice - assert_command dfx --identity alice deploy --network actuallylocal - assert_command dfx --identity alice canister --network actuallylocal call remote write '("this is data in the remote canister")' + assert_command dfx deploy --network actuallylocal --identity alice + assert_command dfx canister call remote write '("this is data in the remote canister")' --network actuallylocal --identity alice - assert_command dfx --identity alice canister --network actuallylocal call remote read + assert_command dfx canister call remote read --network actuallylocal --identity alice assert_eq '("this is data in the remote canister")' REMOTE_CANISTER_ID=$(jq -r .remote.actuallylocal canister_ids.json) @@ -272,7 +272,7 @@ teardown() { setup_actuallylocal_network setup_local_network # shellcheck disable=SC2094 - cat <<<"$(jq .canisters.remote.remote.id.actuallylocal=\""$REMOTE_CANISTER_ID"\" dfx.json)" >dfx.json + cat <<<"$(jq ".canisters.remote.remote.id.actuallylocal=\"$REMOTE_CANISTER_ID\"" dfx.json)" >dfx.json assert_command dfx deploy assert_command dfx canister call basic read_remote @@ -281,25 +281,25 @@ teardown() { assert_eq '("mock")' assert_command dfx deploy --network actuallylocal - assert_command dfx canister --network actuallylocal call basic read_remote + assert_command dfx canister call basic read_remote --network actuallylocal assert_eq '("this is data in the remote canister")' # We can change the value by calling the original canister - assert_command dfx canister --network actuallylocal call "${REMOTE_CANISTER_ID}" write '("data altered by canister id in the remote canister")' - assert_command dfx canister --network actuallylocal call basic read_remote + assert_command dfx canister call "${REMOTE_CANISTER_ID}" write '("data altered by canister id in the remote canister")' --network actuallylocal + assert_command dfx canister call basic read_remote --network actuallylocal assert_eq '("data altered by canister id in the remote canister")' # We can also call through the canister name - assert_command dfx canister --network actuallylocal call remote write '("data altered by canister name in the remote canister")' - assert_command dfx canister --network actuallylocal call basic read_remote + assert_command dfx canister call remote write '("data altered by canister name in the remote canister")' --network actuallylocal + assert_command dfx canister call basic read_remote --network actuallylocal assert_eq '("data altered by canister name in the remote canister")' - assert_command dfx canister --network actuallylocal call remote which_am_i + assert_command dfx canister call remote which_am_i --network actuallylocal assert_eq '("actual")' assert_command jq .basic.actuallylocal canister_ids.json - assert_eq '"'"$(dfx canister --network actuallylocal id basic)"'"' + assert_eq '"'"$(dfx canister id basic --network actuallylocal)"'"' assert_command jq .remote canister_ids.json assert_eq "null" diff --git a/e2e/tests-dfx/sign_send.bash b/e2e/tests-dfx/sign_send.bash index aed6d36122..ee784e116f 100644 --- a/e2e/tests-dfx/sign_send.bash +++ b/e2e/tests-dfx/sign_send.bash @@ -45,6 +45,6 @@ teardown() { mkdir not-a-project-dir cd not-a-project-dir - assert_command dfx canister --network ic sign --query rwlgt-iiaaa-aaaaa-aaaaa-cai read + assert_command dfx canister sign --query rwlgt-iiaaa-aaaaa-aaaaa-cai read --network ic assert_match "Query message generated at \[message.json\]" } diff --git a/e2e/tests-dfx/update_settings.bash b/e2e/tests-dfx/update_settings.bash index 2065a5d3b6..355a84c04e 100644 --- a/e2e/tests-dfx/update_settings.bash +++ b/e2e/tests-dfx/update_settings.bash @@ -39,8 +39,8 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) dfx canister create hello_backend dfx build hello_backend @@ -55,7 +55,7 @@ teardown() { echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall # Bob can reinstall - echo "yes" | assert_command dfx --identity bob canister install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob assert_command dfx identity use bob # Set controller using canister id and principal @@ -64,18 +64,18 @@ teardown() { echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall # Set controller using combination of name/id and identity/principal - assert_command dfx --identity alice canister update-settings hello_backend --set-controller "${BOB_PRINCIPAL}" + assert_command dfx canister update-settings hello_backend --set-controller "${BOB_PRINCIPAL}" --identity alice assert_match "Set controller of \"hello_backend\" to: ${BOB_PRINCIPAL}" - assert_command dfx --identity bob canister update-settings "${ID}" --set-controller alice + assert_command dfx canister update-settings "${ID}" --set-controller alice --identity bob assert_match "Set controller of \"${ID}\" to: alice" # Set controller using invalid principal/identity fails - assert_command_fail dfx --identity alice canister update-settings hello_backend --set-controller charlie + assert_command_fail dfx canister update-settings hello_backend --set-controller charlie --identity alice assert_match "Identity charlie does not exist" # Set controller using invalid canister name/id fails - assert_command_fail dfx --identity alice canister update-settings hello_assets --set-controller bob + assert_command_fail dfx canister update-settings hello_assets --set-controller bob --identity alice assert_match "Cannot find canister id. Please issue 'dfx canister create hello_assets'." } @@ -87,43 +87,43 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB_WALLET=$(dfx --identity bob identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB_WALLET=$(dfx identity get-wallet --identity bob) - dfx canister --wallet "${ALICE_WALLET}" create hello_backend + dfx canister create hello_backend --wallet "${ALICE_WALLET}" dfx build hello_backend - dfx canister --wallet "${ALICE_WALLET}" install hello_backend + dfx canister install hello_backend --wallet "${ALICE_WALLET}" ID=$(dfx canister id hello_backend) # Set controller using canister name and identity name - assert_command dfx canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller "${BOB_WALLET}" + assert_command dfx canister update-settings hello_backend --set-controller "${BOB_WALLET}" --wallet "${ALICE_WALLET}" assert_match "Set controller of \"hello_backend\" to: ${BOB_WALLET}" # Bob is controller, Alice cannot reinstall - echo "yes" | assert_command_fail dfx canister --wallet "${ALICE_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall --wallet "${ALICE_WALLET}" # Bob can reinstall - echo "yes" | assert_command dfx --identity bob canister --wallet "${BOB_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob --wallet "${BOB_WALLET}" assert_command dfx identity use bob # Set controller using canister id and principal - assert_command dfx canister --wallet "${BOB_WALLET}" update-settings "${ID}" --set-controller "${ALICE_WALLET}" + assert_command dfx canister update-settings "${ID}" --set-controller "${ALICE_WALLET}" --wallet "${BOB_WALLET}" assert_match "Set controller of \"${ID}\" to: ${ALICE_WALLET}" - echo "yes" | assert_command_fail dfx canister --wallet "${BOB_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall --wallet "${BOB_WALLET}" # Set controller using combination of name/id and identity/principal - assert_command dfx --identity alice canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller "${BOB_WALLET}" + assert_command dfx canister update-settings hello_backend --set-controller "${BOB_WALLET}" --identity alice --wallet "${ALICE_WALLET}" assert_match "Set controller of \"hello_backend\" to: ${BOB_WALLET}" - assert_command dfx --identity bob canister --wallet "${BOB_WALLET}" update-settings "${ID}" --set-controller alice + assert_command dfx canister update-settings "${ID}" --set-controller alice --identity bob --wallet "${BOB_WALLET}" assert_match "Set controller of \"${ID}\" to: alice" # Set controller using invalid principal/identity fails - assert_command_fail dfx --identity alice canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller charlie + assert_command_fail dfx canister update-settings hello_backend --set-controller charlie --identity alice --wallet "${ALICE_WALLET}" assert_match "Identity charlie does not exist" # Set controller using invalid canister name/id fails - assert_command_fail dfx --identity alice canister --wallet "${ALICE_WALLET}" update-settings hello_assets --set-controller bob + assert_command_fail dfx canister update-settings hello_assets --set-controller bob --identity alice --wallet "${ALICE_WALLET}" assert_match "Cannot find canister id. Please issue 'dfx canister create hello_assets'." } @@ -137,43 +137,43 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB_WALLET=$(dfx --identity bob identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB_WALLET=$(dfx identity get-wallet --identity bob) - dfx canister --wallet "${ALICE_WALLET}" create hello_backend + dfx canister create hello_backend --wallet "${ALICE_WALLET}" dfx build hello_backend - dfx canister --wallet "${ALICE_WALLET}" install hello_backend + dfx canister install hello_backend --wallet "${ALICE_WALLET}" ID=$(dfx canister id hello_backend) # Set controller using canister name and identity name - assert_command dfx canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller "${BOB_WALLET}" + assert_command dfx canister update-settings hello_backend --set-controller "${BOB_WALLET}" --wallet "${ALICE_WALLET}" assert_match "Set controller of \"hello_backend\" to: ${BOB_WALLET}" # Bob is controller, Alice cannot reinstall - echo "yes" | assert_command_fail dfx canister --wallet "${ALICE_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall --wallet "${ALICE_WALLET}" # Bob can reinstall - echo "yes" | assert_command dfx --identity bob canister --wallet "${BOB_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob --wallet "${BOB_WALLET}" assert_command dfx identity use bob # Set controller using canister id and principal - assert_command dfx canister --wallet "${BOB_WALLET}" update-settings "${ID}" --set-controller "${ALICE_WALLET}" + assert_command dfx canister update-settings "${ID}" --set-controller "${ALICE_WALLET}" --wallet "${BOB_WALLET}" assert_match "Set controller of \"${ID}\" to: ${ALICE_WALLET}" - echo "yes" | assert_command_fail dfx canister --wallet "${BOB_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall --wallet "${BOB_WALLET}" # Set controller using combination of name/id and identity/principal - assert_command dfx --identity alice canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller "${BOB_WALLET}" + assert_command dfx canister update-settings hello_backend --set-controller "${BOB_WALLET}" --identity alice --wallet "${ALICE_WALLET}" assert_match "Set controller of \"hello_backend\" to: ${BOB_WALLET}" - assert_command dfx --identity bob canister --wallet "${BOB_WALLET}" update-settings "${ID}" --set-controller alice + assert_command dfx canister update-settings "${ID}" --set-controller alice --identity bob --wallet "${BOB_WALLET}" assert_match "Set controller of \"${ID}\" to: alice" # Set controller using invalid principal/identity fails - assert_command_fail dfx --identity alice canister update-settings hello_backend --set-controller charlie + assert_command_fail dfx canister update-settings hello_backend --set-controller charlie --identity alice assert_match "Identity charlie does not exist" # Set controller using invalid canister name/id fails - assert_command_fail dfx --identity alice canister update-settings hello_assets --set-controller bob + assert_command_fail dfx canister update-settings hello_assets --set-controller bob --identity alice assert_match "Cannot find canister id. Please issue 'dfx canister create hello_assets'." } @@ -186,11 +186,11 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) dfx canister create hello_backend - dfx canister --wallet "$(dfx identity get-wallet)" update-settings hello_backend --add-controller "$ALICE_PRINCIPAL" + dfx canister update-settings hello_backend --add-controller "$ALICE_PRINCIPAL" --wallet "$(dfx identity get-wallet)" dfx build hello_backend dfx canister install hello_backend ID=$(dfx canister id hello_backend) @@ -203,7 +203,7 @@ teardown() { echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall # Bob can reinstall - echo "yes" | assert_command dfx --identity bob canister install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob assert_command dfx identity use bob # Set controller using canister id and principal @@ -212,18 +212,18 @@ teardown() { echo "yes" | assert_command_fail dfx canister install hello_backend -m reinstall # Set controller using combination of name/id and identity/principal - assert_command dfx --identity alice canister update-settings hello_backend --set-controller "${BOB_PRINCIPAL}" + assert_command dfx canister update-settings hello_backend --set-controller "${BOB_PRINCIPAL}" --identity alice assert_match "Set controller of \"hello_backend\" to: ${BOB_PRINCIPAL}" - assert_command dfx --identity bob canister update-settings "${ID}" --set-controller alice + assert_command dfx canister update-settings "${ID}" --set-controller alice --identity bob assert_match "Set controller of \"${ID}\" to: alice" # Set controller using invalid principal/identity fails - assert_command_fail dfx --identity alice canister update-settings hello_backend --set-controller charlie + assert_command_fail dfx canister update-settings hello_backend --set-controller charlie --identity alice assert_match "Identity charlie does not exist" # Set controller using invalid canister name/id fails - assert_command_fail dfx --identity alice canister update-settings hello_assets --set-controller bob + assert_command_fail dfx canister update-settings hello_assets --set-controller bob --identity alice assert_match "Cannot find canister id. Please issue 'dfx canister create hello_assets'." } @@ -236,8 +236,8 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) # awk step is to avoid trailing space PRINCIPALS_SORTED=$(echo "$ALICE_PRINCIPAL" "$BOB_PRINCIPAL" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s",$1,$2}' ) @@ -251,8 +251,8 @@ teardown() { assert_match "Set controllers of \"hello_backend\" to: $PRINCIPALS_SORTED" # Both can reinstall - echo "yes" | assert_command dfx --identity alice canister install hello_backend -m reinstall - echo "yes" | assert_command dfx --identity bob canister install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity alice + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob assert_command dfx canister info hello_backend assert_match "Controllers: ${PRINCIPALS_SORTED}" @@ -265,8 +265,8 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB_WALLET=$(dfx --identity bob identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB_WALLET=$(dfx identity get-wallet --identity bob) # awk step is to avoid trailing space WALLETS_SORTED=$(echo "${ALICE_WALLET}" "${BOB_WALLET}" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s",$1,$2}' ) @@ -276,12 +276,12 @@ teardown() { ID=$(dfx canister id hello_backend) # Set controller using canister name and identity name - assert_command dfx canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller "${ALICE_WALLET}" --set-controller "${BOB_WALLET}" + assert_command dfx canister update-settings hello_backend --set-controller "${ALICE_WALLET}" --set-controller "${BOB_WALLET}" --wallet "${ALICE_WALLET}" assert_match "Set controllers of \"hello_backend\" to: ${WALLETS_SORTED}" # Both can reinstall - echo "yes" | assert_command dfx --identity alice canister --wallet "${ALICE_WALLET}" install hello_backend -m reinstall - echo "yes" | assert_command dfx --identity bob canister --wallet "${BOB_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity alice --wallet "${ALICE_WALLET}" + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob --wallet "${BOB_WALLET}" assert_command dfx canister info hello_backend assert_match "Controllers: ${WALLETS_SORTED}" @@ -296,23 +296,23 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB_WALLET=$(dfx --identity bob identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB_WALLET=$(dfx identity get-wallet --identity bob) # awk step is to avoid trailing space WALLETS_SORTED=$(echo "${ALICE_WALLET}" "${BOB_WALLET}" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s",$1,$2}' ) dfx canister create hello_backend dfx build hello_backend - dfx canister --wallet "${ALICE_WALLET}" install hello_backend + dfx canister install hello_backend --wallet "${ALICE_WALLET}" ID=$(dfx canister id hello_backend) # Set controller using canister name and identity name - assert_command dfx canister --wallet "${ALICE_WALLET}" update-settings hello_backend --set-controller "${ALICE_WALLET}" --set-controller "${BOB_WALLET}" + assert_command dfx canister update-settings hello_backend --set-controller "${ALICE_WALLET}" --set-controller "${BOB_WALLET}" --wallet "${ALICE_WALLET}" assert_match "Set controllers of \"hello_backend\" to: $WALLETS_SORTED" # Both can reinstall - echo "yes" | assert_command dfx --identity alice canister --wallet "${ALICE_WALLET}" install hello_backend -m reinstall - echo "yes" | assert_command dfx --identity bob canister --wallet "${BOB_WALLET}" install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity alice --wallet "${ALICE_WALLET}" + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob --wallet "${BOB_WALLET}" assert_command dfx canister info hello_backend assert_match "Controllers: ${WALLETS_SORTED}" @@ -327,13 +327,13 @@ teardown() { assert_command dfx identity use alice dfx_start - ALICE_PRINCIPAL=$(dfx --identity alice identity get-principal) - BOB_PRINCIPAL=$(dfx --identity bob identity get-principal) + ALICE_PRINCIPAL=$(dfx identity get-principal --identity alice) + BOB_PRINCIPAL=$(dfx identity get-principal --identity bob) # awk step is to avoid trailing space PRINCIPALS_SORTED=$(echo "$ALICE_PRINCIPAL" "$BOB_PRINCIPAL" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s",$1,$2}' ) dfx canister create hello_backend - dfx canister --wallet "$(dfx identity get-wallet)" update-settings hello_backend --add-controller "$ALICE_PRINCIPAL" + dfx canister update-settings hello_backend --add-controller "$ALICE_PRINCIPAL" --wallet "$(dfx identity get-wallet)" dfx build hello_backend dfx canister install hello_backend ID=$(dfx canister id hello_backend) @@ -343,8 +343,8 @@ teardown() { assert_match "Set controllers of \"hello_backend\" to: $PRINCIPALS_SORTED" # Both can reinstall - echo "yes" | assert_command dfx --identity alice canister install hello_backend -m reinstall - echo "yes" | assert_command dfx --identity bob canister install hello_backend -m reinstall + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity alice + echo "yes" | assert_command dfx canister install hello_backend -m reinstall --identity bob assert_command dfx canister info hello_backend assert_match "Controllers: ${PRINCIPALS_SORTED}" @@ -358,10 +358,10 @@ teardown() { dfx identity use alice dfx_start - ALICE=$(dfx --identity alice identity get-principal) - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB=$(dfx --identity bob identity get-principal) - CHARLIE=$(dfx --identity charlie identity get-principal) + ALICE=$(dfx identity get-principal --identity alice) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB=$(dfx identity get-principal --identity bob) + CHARLIE=$(dfx identity get-principal --identity charlie) SORTED=$(echo "$ALICE" "$ALICE_WALLET" "$BOB" "$CHARLIE" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s %s %s",$1,$2,$3,$4}' ) dfx canister create hello_backend @@ -371,7 +371,7 @@ teardown() { # make bob a controller assert_command dfx canister update-settings hello_backend --add-controller bob # check that bob has the authority to make someone else a controller - assert_command dfx --identity bob canister update-settings hello_backend --add-controller charlie + assert_command dfx canister update-settings hello_backend --add-controller charlie --identity bob assert_command dfx canister info hello_backend assert_match "Controllers: $SORTED" } @@ -384,10 +384,10 @@ teardown() { dfx identity use alice dfx_start - ALICE=$(dfx --identity alice identity get-principal) - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB=$(dfx --identity bob identity get-principal) - CHARLIE=$(dfx --identity charlie identity get-principal) + ALICE=$(dfx identity get-principal --identity alice) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB=$(dfx identity get-principal --identity bob) + CHARLIE=$(dfx identity get-principal --identity charlie) SORTED=$(echo "$ALICE" "$ALICE_WALLET" "$BOB" "$CHARLIE" | tr " " "\n" | sort | tr "\n" " " | awk '{printf "%s %s %s %s",$1,$2,$3,$4}' ) dfx canister create --all @@ -397,7 +397,7 @@ teardown() { # make bob a controller assert_command dfx canister update-settings --all --add-controller bob # check that bob has the authority to make someone else a controller - assert_command dfx --identity bob canister update-settings --all --add-controller charlie + assert_command dfx canister update-settings --all --add-controller charlie --identity bob assert_command dfx canister info hello_backend assert_match "Controllers: $SORTED" } diff --git a/e2e/tests-dfx/wallet.bash b/e2e/tests-dfx/wallet.bash index 849e78bc4b..d52a537aab 100644 --- a/e2e/tests-dfx/wallet.bash +++ b/e2e/tests-dfx/wallet.bash @@ -20,20 +20,20 @@ teardown() { dfx identity new --disable-encryption bob use_wallet_wasm 0.7.0 - assert_command dfx --identity alice identity get-wallet + assert_command dfx identity get-wallet --identity alice assert_match "Using wasm at path: .*/wallet/0.7.0/wallet.wasm" use_wallet_wasm 0.7.2 - assert_command dfx --identity bob identity get-wallet + assert_command dfx identity get-wallet --identity bob assert_match "Using wasm at path: .*/wallet/0.7.2/wallet.wasm" - ALICE_WALLET=$(dfx --identity alice identity get-wallet) - BOB_WALLET=$(dfx --identity bob identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) + BOB_WALLET=$(dfx identity get-wallet --identity bob) - assert_command dfx --identity alice canister info "$ALICE_WALLET" + assert_command dfx canister info "$ALICE_WALLET" --identity alice assert_match "Module hash: 0xa609400f2576d1d6df72ce868b359fd08e1d68e58454ef17db2361d2f1c242a1" - assert_command dfx --identity bob canister info "$BOB_WALLET" + assert_command dfx canister info "$BOB_WALLET" --identity bob assert_match "Module hash: 0x1404b28b1c66491689b59e184a9de3c2be0dbdd75d952f29113b516742b7f898" } @@ -62,18 +62,18 @@ teardown() { setup_actuallylocal_network # get Canister IDs to install the wasm onto - dfx canister --network actuallylocal create hello_backend - ID=$(dfx canister --network actuallylocal id hello_backend) - dfx canister --network actuallylocal create hello_frontend - ID_TWO=$(dfx canister --network actuallylocal id hello_frontend) + dfx canister create hello_backend --network actuallylocal + ID=$(dfx canister id hello_backend --network actuallylocal) + dfx canister create hello_frontend --network actuallylocal + ID_TWO=$(dfx canister id hello_frontend --network actuallylocal) # set controller to user - dfx canister --network actuallylocal update-settings hello_backend --set-controller "$(dfx identity get-principal)" - dfx canister --network actuallylocal update-settings hello_frontend --set-controller "$(dfx identity get-principal)" + dfx canister update-settings hello_backend --set-controller "$(dfx identity get-principal)" --network actuallylocal + dfx canister update-settings hello_frontend --set-controller "$(dfx identity get-principal)" --network actuallylocal - assert_command_fail dfx identity --network actuallylocal set-wallet "${ID}" + assert_command_fail dfx identity set-wallet "${ID}" --network actuallylocal assert_not_match "Setting wallet for identity" - assert_command dfx identity --network actuallylocal set-wallet --force "${ID}" + assert_command dfx identity set-wallet --force "${ID}" --network actuallylocal assert_match "Setting wallet for identity 'default' on network 'actuallylocal' to id '$ID'" assert_command jq -r .identities.default.actuallylocal <"$DFX_CONFIG_ROOT"/.config/dfx/identity/default/wallets.json assert_eq "$ID" @@ -85,25 +85,25 @@ teardown() { setup_actuallylocal_network # get Canister IDs to install the wasm onto - dfx canister --network actuallylocal create hello_frontend - ID=$(dfx canister --network actuallylocal id hello_frontend) - dfx deploy --network actuallylocal hello_backend - ID_TWO=$(dfx canister --network actuallylocal id hello_backend) + dfx canister create hello_frontend --network actuallylocal + ID=$(dfx canister id hello_frontend --network actuallylocal) + dfx deploy hello_backend --network actuallylocal + ID_TWO=$(dfx canister id hello_backend --network actuallylocal) # set controller to user - dfx canister --network actuallylocal update-settings hello_backend --set-controller "$(dfx identity get-principal)" - dfx canister --network actuallylocal update-settings hello_frontend --set-controller "$(dfx identity get-principal)" + dfx canister update-settings hello_backend --set-controller "$(dfx identity get-principal)" --network actuallylocal + dfx canister update-settings hello_frontend --set-controller "$(dfx identity get-principal)" --network actuallylocal # We're testing on a local network so the create command actually creates a wallet # Delete this file to force associate wallet created by deploy-wallet to identity rm "$DFX_CONFIG_ROOT"/.config/dfx/identity/default/wallets.json - assert_command dfx identity --network actuallylocal deploy-wallet "${ID}" - GET_WALLET_RES=$(dfx identity --network actuallylocal get-wallet) + assert_command dfx identity deploy-wallet "${ID}" --network actuallylocal + GET_WALLET_RES=$(dfx identity get-wallet --network actuallylocal) assert_eq "$ID" "$GET_WALLET_RES" # Command should fail on an already-deployed canister - assert_command_fail dfx identity --network actuallylocal deploy-wallet "${ID_TWO}" + assert_command_fail dfx identity deploy-wallet "${ID_TWO}" --network actuallylocal assert_match "The wallet canister \"${ID_TWO}\"\ already exists for user \"default\" on \"actuallylocal\" network." } @@ -121,11 +121,11 @@ teardown() { install_asset identity dfx_start WALLET=$(dfx identity get-wallet) - assert_command dfx canister --wallet "$WALLET" create --all + assert_command dfx canister create --all --wallet "$WALLET" assert_command dfx build - assert_command dfx canister --wallet "$WALLET" install --all + assert_command dfx canister install --all --wallet "$WALLET" - CALL_RES=$(dfx canister --wallet "$WALLET" call e2e_project_backend fromCall) + CALL_RES=$(dfx canister call e2e_project_backend fromCall --wallet "$WALLET") CALLER=$(echo "${CALL_RES}" | cut -d'"' -f 2) assert_eq "$CALLER" "$WALLET" @@ -140,7 +140,7 @@ teardown() { dfx_start WALLET=$(dfx identity get-wallet) assert_command dfx deploy --wallet "$WALLET" - CALL_RES=$(dfx canister --wallet "$WALLET" call e2e_project_backend fromCall) + CALL_RES=$(dfx canister call e2e_project_backend fromCall --wallet "$WALLET") CALLER=$(echo "${CALL_RES}" | cut -d'"' -f 2) assert_eq "$CALLER" "$WALLET" @@ -157,9 +157,9 @@ teardown() { WALLET=$(dfx identity get-wallet) assert_command dfx wallet balance assert_command dfx deploy --wallet "$WALLET" - assert_command dfx canister --wallet "$WALLET" call hello_backend greet '("")' --with-cycles 1 + assert_command dfx canister call hello_backend greet '("")' --with-cycles 1 --wallet "$WALLET" dfx identity new alice --disable-encryption - ALICE_WALLET=$(dfx --identity alice identity get-wallet) + ALICE_WALLET=$(dfx identity get-wallet --identity alice) dfx wallet send "$ALICE_WALLET" 1 } @@ -167,8 +167,8 @@ teardown() { dfx_new hello dfx_start dfx identity new alice --disable-encryption - dfx --identity alice deploy --no-wallet hello_backend - assert_command dfx canister --wallet "$(dfx identity get-wallet)" deposit-cycles 1 hello_backend + dfx deploy --no-wallet hello_backend --identity alice + assert_command dfx canister deposit-cycles 1 hello_backend --wallet "$(dfx identity get-wallet)" } @test "detects if there is no wallet to upgrade" { diff --git a/e2e/utils/_.bash b/e2e/utils/_.bash index d0972ca135..fd181c04dd 100644 --- a/e2e/utils/_.bash +++ b/e2e/utils/_.bash @@ -240,7 +240,7 @@ dfx_stop() { dfx_set_wallet() { export WALLET_CANISTER_ID=$(dfx identity get-wallet) - assert_command dfx identity --network actuallylocal set-wallet ${WALLET_CANISTER_ID} --force + assert_command dfx identity set-wallet ${WALLET_CANISTER_ID} --force --network actuallylocal assert_match 'Wallet set successfully.' } @@ -259,7 +259,7 @@ setup_local_network() { fi # shellcheck disable=SC2094 - cat <<<"$(jq .networks.local.bind=\"127.0.0.1:${replica_port}\" dfx.json)" >dfx.json + cat <<<"$(jq ".networks.local.bind=\"127.0.0.1:${replica_port}\"" dfx.json)" >dfx.json } use_wallet_wasm() { diff --git a/src/dfx/src/commands/cache/mod.rs b/src/dfx/src/commands/cache/mod.rs index d2fd976b22..321ac19388 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 CacheOpts { +pub struct CacheCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] pub enum SubCommand { - Delete(delete::CacheDeleteOpts), - Install(install::CacheInstall), - List(list::CacheListOpts), - Show(show::CacheShowOpts), + Delete(BaseOpts), + Install(BaseOpts), + List(BaseOpts), + Show(BaseOpts), } -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), +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), } } diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index 52b0965866..8095ab9b93 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -164,8 +164,8 @@ pub fn get_effective_canister_id( "{} can only be called by a canister, not by an external user.", method_name.as_ref() ), - format!("The easiest way to call {} externally is to proxy this call through a wallet. Try calling this with 'dfx canister (--network ic) --wallet call '.\n\ - To figure out the id of your wallet, run 'dfx identity (--network ic) get-wallet'.", method_name.as_ref()) + format!("The easiest way to call {} externally is to proxy this call through a wallet. Try calling this with 'dfx canister call (--network ic) --wallet '.\n\ + To figure out the id of your wallet, run 'dfx identity get-wallet (--network ic)'.", method_name.as_ref()) )).context("Method only callable by a canister."); } MgmtMethod::InstallCode => { @@ -291,8 +291,8 @@ pub async fn exec( .map_or(0_u128, |amount| amount.parse::().unwrap()); if call_sender == &CallSender::SelectedId && cycles != 0 { - return Err(DiagnosedError::new("It is only possible to send cycles from a canister.".to_string(), "To send the same function call from your wallet (a canister), run the command using 'dfx canister (--network ic) --wallet call '.\n\ - To figure out the id of your wallet, run 'dfx identity (--network ic) get-wallet'.".to_string())).context("Function caller is not a canister."); + return Err(DiagnosedError::new("It is only possible to send cycles from a canister.".to_string(), "To send the same function call from your wallet (a canister), run the command using 'dfx canister call (--network ic) --wallet '.\n\ + To figure out the id of your wallet, run 'dfx identity get-wallet (--network ic)'.".to_string())).context("Function caller is not a canister."); } if is_query { diff --git a/src/dfx/src/commands/canister/deposit_cycles.rs b/src/dfx/src/commands/canister/deposit_cycles.rs index 8e6946b6ca..a4d65d9578 100644 --- a/src/dfx/src/commands/canister/deposit_cycles.rs +++ b/src/dfx/src/commands/canister/deposit_cycles.rs @@ -65,7 +65,7 @@ pub async fn exec( call_sender: &CallSender, ) -> DfxResult { if call_sender == &CallSender::SelectedId { - bail!("The deposit cycles call needs to proxied via the wallet canister. Please run this command using 'dfx canister --wallet deposit-cycles '."); + bail!("The deposit cycles call needs to be proxied via the wallet canister. Please run this command using 'dfx canister deposit-cycles --wallet '."); } // amount has been validated by cycle_amount_validator diff --git a/src/dfx/src/commands/canister/mod.rs b/src/dfx/src/commands/canister/mod.rs index 1e0146bd6e..a90cc61561 100644 --- a/src/dfx/src/commands/canister/mod.rs +++ b/src/dfx/src/commands/canister/mod.rs @@ -1,11 +1,14 @@ -use crate::lib::environment::Environment; +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 clap::{Parser, Subcommand}; +use clap::{Args, Parser, Subcommand}; use tokio::runtime::Runtime; +use super::NetworkOpts; + mod call; mod create; mod delete; @@ -23,71 +26,109 @@ mod stop; mod uninstall_code; mod update_settings; -/// Manages canisters deployed on a network replica. -#[derive(Parser)] -#[clap(name("canister"))] -pub struct CanisterOpts { - /// 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, +#[derive(Args)] +pub struct CanisterOpts { + #[clap(flatten)] + network_opts: NetworkOpts, /// Specify a wallet canister id to perform the call. /// If none specified, defaults to use the selected Identity's wallet canister. #[clap(long)] 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(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), + 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 fn exec(env: &dyn Environment, opts: CanisterOpts) -> DfxResult { - let agent_env = create_agent_environment(env, opts.network.clone())?; - let runtime = Runtime::new().expect("Unable to create a runtime"); +macro_rules! with_env { + ($opts:expr, |$env:pat, $v:pat, $call_sender:pat| $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(()) + }) + }}; +} - 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 - } +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)) } - }) + 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/canister/request_status.rs b/src/dfx/src/commands/canister/request_status.rs index dca0befdb6..7eedb60885 100644 --- a/src/dfx/src/commands/canister/request_status.rs +++ b/src/dfx/src/commands/canister/request_status.rs @@ -26,7 +26,7 @@ pub struct RequestStatusOpts { /// If the request was made to the Management canister, specify the id of the /// canister it is updating/querying. /// If the call was proxied by the wallet, - /// i.e. a `dfx canister --wallet= call --async` flag, + /// i.e. a `dfx canister call --async --wallet=` flag, /// specify the wallet canister id. canister: String, diff --git a/src/dfx/src/commands/canister/send.rs b/src/dfx/src/commands/canister/send.rs index 590026525d..62a3a0c05c 100644 --- a/src/dfx/src/commands/canister/send.rs +++ b/src/dfx/src/commands/canister/send.rs @@ -29,7 +29,7 @@ pub async fn exec( call_sender: &CallSender, ) -> DfxResult { if *call_sender != CallSender::SelectedId { - bail!("`sign` currently doesn't support proxy through wallet canister, please use `dfx canister --no-wallet send ...`."); + bail!("`send` currently doesn't support proxying through the wallet canister, please use `dfx canister send --no-wallet ...`."); } let file_name = opts.file_name; let path = Path::new(&file_name); diff --git a/src/dfx/src/commands/canister/sign.rs b/src/dfx/src/commands/canister/sign.rs index 8f585a5ee4..7a7896c14b 100644 --- a/src/dfx/src/commands/canister/sign.rs +++ b/src/dfx/src/commands/canister/sign.rs @@ -69,7 +69,7 @@ pub async fn exec( ) -> DfxResult { let log = env.get_logger(); if *call_sender != CallSender::SelectedId { - bail!("`sign` currently doesn't support proxy through wallet canister, please use `dfx canister --no-wallet sign ...`."); + bail!("`sign` currently doesn't support proxying through the wallet canister, please use `dfx canister sign --no-wallet ...`."); } let callee_canister = opts.canister_name.as_str(); diff --git a/src/dfx/src/commands/identity/export.rs b/src/dfx/src/commands/identity/export.rs index c950414f7f..0a04dd2b91 100644 --- a/src/dfx/src/commands/identity/export.rs +++ b/src/dfx/src/commands/identity/export.rs @@ -8,11 +8,11 @@ use clap::Parser; #[derive(Parser)] pub struct ExportOpts { /// The identity to export. - identity: String, + exported_identity: String, } pub fn exec(env: &dyn Environment, opts: ExportOpts) -> DfxResult { - let name = opts.identity.as_str(); + let name = opts.exported_identity.as_str(); let pem = IdentityManager::new(env)?.export(name)?; print!("{}", pem); diff --git a/src/dfx/src/commands/identity/import.rs b/src/dfx/src/commands/identity/import.rs index 3e5f87f40b..a6666ba97c 100644 --- a/src/dfx/src/commands/identity/import.rs +++ b/src/dfx/src/commands/identity/import.rs @@ -10,13 +10,13 @@ use std::path::PathBuf; #[derive(Parser)] pub struct ImportOpts { /// The identity to create. - identity: String, + new_identity: String, /// The PEM file to import. pem_file: PathBuf, /// DANGEROUS: By default, PEM files are encrypted with a password when writing them to disk. - /// I you want the convenience of not having to type your password (but at the risk of having your PEM file compromised), you can disable the encryption. + /// If you want the convenience of not having to type your password (but at the risk of having your PEM file compromised), you can disable the encryption. #[clap(long)] disable_encryption: bool, @@ -28,7 +28,7 @@ pub struct ImportOpts { /// Executes the import subcommand. pub fn exec(env: &dyn Environment, opts: ImportOpts) -> DfxResult { let log = env.get_logger(); - let name = opts.identity.as_str(); + let name = opts.new_identity.as_str(); let params = IdentityCreationParameters::PemFile { src_pem_file: opts.pem_file, disable_encryption: opts.disable_encryption, diff --git a/src/dfx/src/commands/identity/mod.rs b/src/dfx/src/commands/identity/mod.rs index 7db477a4ca..8c0fabf681 100644 --- a/src/dfx/src/commands/identity/mod.rs +++ b/src/dfx/src/commands/identity/mod.rs @@ -1,8 +1,9 @@ -use crate::lib::environment::Environment; -use crate::lib::error::DfxResult; +use crate::{init_env, lib::error::DfxResult}; use clap::Parser; +use super::NetworkOpts; + mod deploy_wallet; mod export; mod get_wallet; @@ -20,44 +21,68 @@ mod whoami; /// Setting an identity enables you to test user-based access controls. #[derive(Parser)] #[clap(name("identity"))] -pub struct IdentityOpt { - /// Override the compute network to connect to. By default, the local network is used. - #[clap(long)] - network: Option, - +pub struct IdentityCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - 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), + DeployWallet(NetworkOpts), + Export(NetworkOpts), + GetWallet(NetworkOpts), + Import(NetworkOpts), + List(NetworkOpts), + New(NetworkOpts), + GetPrincipal(NetworkOpts), + Remove(NetworkOpts), + Rename(NetworkOpts), + SetWallet(NetworkOpts), + Use(NetworkOpts), + Whoami(NetworkOpts), } -pub fn exec(env: &dyn Environment, opts: IdentityOpt) -> DfxResult { - match opts.subcmd { - SubCommand::DeployWallet(v) => deploy_wallet::exec(env, v, opts.network.clone()), - SubCommand::Export(v) => export::exec(env, v), - SubCommand::GetWallet(v) => get_wallet::exec(env, v, opts.network.clone()), - 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.clone()), - SubCommand::Use(v) => r#use::exec(env, v), - SubCommand::Whoami(v) => whoami::exec(env, v), +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) + } } } diff --git a/src/dfx/src/commands/identity/new.rs b/src/dfx/src/commands/identity/new.rs index 6be3bc590b..822a823032 100644 --- a/src/dfx/src/commands/identity/new.rs +++ b/src/dfx/src/commands/identity/new.rs @@ -13,7 +13,7 @@ use IdentityCreationParameters::{Hardware, Pem}; #[derive(Parser)] pub struct NewIdentityOpts { /// The identity to create. - identity: String, + new_identity: String, /// The file path to the opensc-pkcs11 library e.g. "/usr/local/lib/opensc-pkcs11.so" #[clap(long, requires("hsm-key-id"))] @@ -24,7 +24,7 @@ pub struct NewIdentityOpts { hsm_key_id: Option, /// DANGEROUS: By default, PEM files are encrypted with a password when writing them to disk. - /// I you want the convenience of not having to type your password (but at the risk of having your PEM file compromised), you can disable the encryption. + /// If you want the convenience of not having to type your password (but at the risk of having your PEM file compromised), you can disable the encryption. #[clap(long)] disable_encryption: bool, @@ -34,7 +34,7 @@ pub struct NewIdentityOpts { } pub fn exec(env: &dyn Environment, opts: NewIdentityOpts) -> DfxResult { - let name = opts.identity.as_str(); + let name = opts.new_identity.as_str(); let log = env.get_logger(); diff --git a/src/dfx/src/commands/identity/remove.rs b/src/dfx/src/commands/identity/remove.rs index cdacdb1de3..7684036268 100644 --- a/src/dfx/src/commands/identity/remove.rs +++ b/src/dfx/src/commands/identity/remove.rs @@ -9,7 +9,7 @@ use slog::info; #[derive(Parser)] pub struct RemoveOpts { /// The identity to remove. - identity: String, + removed_identity: String, /// Required if the identity has wallets configured so that users do not accidentally lose access to wallets. #[clap(long)] @@ -17,7 +17,7 @@ pub struct RemoveOpts { } pub fn exec(env: &dyn Environment, opts: RemoveOpts) -> DfxResult { - let name = opts.identity.as_str(); + let name = opts.removed_identity.as_str(); let log = env.get_logger(); diff --git a/src/dfx/src/commands/identity/use.rs b/src/dfx/src/commands/identity/use.rs index 69aca854fe..612a5efeae 100644 --- a/src/dfx/src/commands/identity/use.rs +++ b/src/dfx/src/commands/identity/use.rs @@ -9,11 +9,11 @@ use slog::info; #[derive(Parser)] pub struct UseOpts { /// The identity to use. - identity: String, + new_identity: String, } pub fn exec(env: &dyn Environment, opts: UseOpts) -> DfxResult { - let identity = opts.identity.as_str(); + let identity = opts.new_identity.as_str(); let log = env.get_logger(); info!(log, r#"Using identity: "{}"."#, identity); diff --git a/src/dfx/src/commands/ledger/mod.rs b/src/dfx/src/commands/ledger/mod.rs index 6e4cd0cbde..d75aa1bba9 100644 --- a/src/dfx/src/commands/ledger/mod.rs +++ b/src/dfx/src/commands/ledger/mod.rs @@ -1,4 +1,5 @@ -use crate::lib::environment::Environment; +use crate::init_env; + use crate::lib::error::DfxResult; use crate::lib::ledger_types::{ AccountIdBlob, BlockHeight, Memo, NotifyCreateCanisterArg, NotifyCreateCanisterResult, @@ -19,10 +20,13 @@ 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"; @@ -38,40 +42,47 @@ mod transfer; /// Ledger commands. #[derive(Parser)] #[clap(name("ledger"))] -pub struct LedgerOpts { - /// Override the compute network to connect to. By default, the local network is used. - #[clap(long)] - network: Option, - +pub struct LedgerCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - 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), + AccountId(NetworkOpts), + Balance(NetworkOpts), + CreateCanister(NetworkOpts), + FabricateCycles(NetworkOpts), + Notify(NetworkOpts), + TopUp(NetworkOpts), + Transfer(NetworkOpts), } -pub fn exec(env: &dyn Environment, opts: LedgerOpts) -> DfxResult { - let agent_env = create_agent_environment(env, opts.network.clone())?; - 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, +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)) } - }) + 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 87e00a90ff..78c1a492bc 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::Subcommand; +use clap::{Args, Subcommand}; mod bootstrap; mod build; @@ -28,54 +28,70 @@ mod wallet; #[derive(Subcommand)] pub enum Command { - Bootstrap(bootstrap::BootstrapOpts), - Build(build::CanisterBuildOpts), - Cache(cache::CacheOpts), - Canister(canister::CanisterOpts), - Config(config::ConfigOpts), - Deploy(deploy::DeployOpts), - Diagnose(diagnose::DiagnoseOpts), - Fix(fix::FixOpts), - Generate(generate::GenerateOpts), - Identity(identity::IdentityOpt), + Bootstrap(BaseOpts), + Build(BaseOpts), + Cache(cache::CacheCommand), + Canister(canister::CanisterCommand), + Config(BaseOpts), + Deploy(BaseOpts), + Diagnose(BaseOpts), + Fix(BaseOpts), + Generate(BaseOpts), + Identity(identity::IdentityCommand), #[clap(name("_language-service"))] - LanguageServices(language_service::LanguageServiceOpts), - Ledger(ledger::LedgerOpts), - New(new::NewOpts), - Ping(ping::PingOpts), - Remote(remote::RemoteOpts), - Replica(replica::ReplicaOpts), - Schema(schema::SchemaOpts), - Start(start::StartOpts), - Stop(stop::StopOpts), - Toolchain(toolchain::ToolchainOpts), - Upgrade(upgrade::UpgradeOpts), - Wallet(wallet::WalletOpts), + LanguageServices(BaseOpts), + Ledger(ledger::LedgerCommand), + New(BaseOpts), + Ping(BaseOpts), + Remote(remote::RemoteCommand), + Replica(BaseOpts), + Schema(BaseOpts), + Start(BaseOpts), + Stop(BaseOpts), + Toolchain(toolchain::ToolchainCommand), + Upgrade(BaseOpts), + Wallet(wallet::WalletCommand), } -pub fn exec(env: &dyn Environment, cmd: Command) -> DfxResult { +#[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 { match cmd { - 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::Config(v) => config::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::LanguageServices(v) => language_service::exec(env, v), - Command::Ledger(v) => ledger::exec(env, v), - Command::New(v) => new::exec(env, v), - Command::Ping(v) => ping::exec(env, v), - Command::Remote(v) => remote::exec(env, v), - Command::Replica(v) => replica::exec(env, v), - Command::Schema(v) => schema::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), + 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::Remote(v) => remote::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::Config(v) => config::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::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::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), } } diff --git a/src/dfx/src/commands/remote/generate_binding.rs b/src/dfx/src/commands/remote/generate_binding.rs index 008f307349..715a912bc0 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,7 +29,6 @@ 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(); @@ -37,7 +36,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 84507bd1cf..f8d08ef2d7 100644 --- a/src/dfx/src/commands/remote/mod.rs +++ b/src/dfx/src/commands/remote/mod.rs @@ -1,28 +1,32 @@ -use crate::lib::environment::Environment; +use crate::init_env; + use crate::lib::error::DfxResult; +use crate::lib::provider::create_agent_environment; use clap::Parser; +use super::NetworkOpts; + mod generate_binding; /// Commands used to work with remote canisters #[derive(Parser)] -pub struct RemoteOpts { - /// Override the compute network to connect to. By default, the local network is used. - #[clap(long)] - network: Option, - +pub struct RemoteCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - GenerateBinding(generate_binding::GenerateBindingOpts), + GenerateBinding(NetworkOpts), } -pub fn exec(env: &dyn Environment, opts: RemoteOpts) -> DfxResult { - match opts.subcmd { - SubCommand::GenerateBinding(v) => generate_binding::exec(env, v), +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) + } } } diff --git a/src/dfx/src/commands/toolchain/mod.rs b/src/dfx/src/commands/toolchain/mod.rs index 6797109bfa..e12c498dbb 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 ToolchainOpts { +pub struct ToolchainCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] pub enum SubCommand { - Install(install::ToolchainInstall), - Uninstall(uninstall::ToolchainUninstall), - List(list::ToolchainList), - Default(default::ToolchainDefault), + Install(BaseOpts), + Uninstall(BaseOpts), + List(BaseOpts), + Default(BaseOpts), } -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), +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), } } diff --git a/src/dfx/src/commands/wallet/mod.rs b/src/dfx/src/commands/wallet/mod.rs index e6c6910f6e..d6b1fef851 100644 --- a/src/dfx/src/commands/wallet/mod.rs +++ b/src/dfx/src/commands/wallet/mod.rs @@ -1,3 +1,4 @@ +use crate::init_env; use crate::lib::environment::Environment; use crate::lib::error::DfxResult; use crate::lib::identity::Identity; @@ -15,6 +16,8 @@ use ic_utils::call::SyncCall; use ic_utils::interfaces::WalletCanister; use tokio::runtime::Runtime; +use super::NetworkOpts; + mod add_controller; mod authorize; mod balance; @@ -31,53 +34,65 @@ mod upgrade; /// Helper commands to manage the user's cycles wallet. #[derive(Parser)] #[clap(name("wallet"))] -pub struct WalletOpts { - /// 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 struct WalletCommand { #[clap(subcommand)] subcmd: SubCommand, } #[derive(Parser)] enum SubCommand { - 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), - RemoveController(remove_controller::RemoveControllerOpts), - Send(send::SendOpts), - SetName(set_name::SetNameOpts), - Upgrade(upgrade::UpgradeOpts), + Addresses(NetworkOpts), + AddController(NetworkOpts), + Authorize(NetworkOpts), + Balance(NetworkOpts), + Controllers(NetworkOpts), + Custodians(NetworkOpts), + Deauthorize(NetworkOpts), + Name(NetworkOpts), + RemoveController(NetworkOpts), + Send(NetworkOpts), + SetName(NetworkOpts), + Upgrade(NetworkOpts), } -pub fn exec(env: &dyn Environment, opts: WalletOpts) -> DfxResult { - let agent_env = create_agent_environment(env, opts.network.clone())?; - 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::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, +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::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)) } - }) + 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/diagnosis.rs b/src/dfx/src/lib/diagnosis.rs index f3a1b425e3..ecf12e9c7b 100644 --- a/src/dfx/src/lib/diagnosis.rs +++ b/src/dfx/src/lib/diagnosis.rs @@ -64,14 +64,14 @@ fn diagnose_http_403() -> Diagnosis { let error_explanation = "Each canister has a set of controllers. Only those controllers have access to the canister's management functions (like install_code or stop_canister).\n\ The principal you are using to call a management function is not part of the controllers."; let action_suggestion = "To make the management function call succeed, you have to make sure the principal that calls the function is a controller. -To see the current controllers of a canister, use the 'dfx canister (--network ic) info' command. +To see the current controllers of a canister, use the 'dfx canister info (--network ic)' command. To figure out which principal is calling the management function, look at the command you entered: If you used '--wallet ', then the wallet's principal (the '') is calling the function. If you used '--no-wallet' or none of the flags, then your own principal is calling the function. You can see your own principal by running 'dfx identity get-principal'. -To add a principal to the list of controllers, one of the existing controllers has to add the new principal. The base command to do this is 'dfx canister (--network ic) update-settings --add-controller '. -If your wallet is a controller, but not your own principal, then you have to make your wallet perform the call by adding '--wallet ' to the command (before the 'update-settings' subcommand). +To add a principal to the list of controllers, one of the existing controllers has to add the new principal. The base command to do this is 'dfx canister update-settings --add-controller (--network ic)'. +If your wallet is a controller, but not your own principal, then you have to make your wallet perform the call by adding '--wallet ' to the command. -The most common way this error is solved is by running 'dfx canister --network ic --wallet \"$(dfx identity get-wallet)\" update-settings --all --add-controller \"$(dfx identity get-principal)\"'."; +The most common way this error is solved is by running 'dfx canister update-settings --network ic --wallet \"$(dfx identity get-wallet)\" --all --add-controller \"$(dfx identity get-principal)\"'."; ( Some(error_explanation.to_string()), Some(action_suggestion.to_string()), diff --git a/src/dfx/src/lib/identity/mod.rs b/src/dfx/src/lib/identity/mod.rs index c21b298128..15cb1bdff2 100644 --- a/src/dfx/src/lib/identity/mod.rs +++ b/src/dfx/src/lib/identity/mod.rs @@ -575,7 +575,7 @@ impl Identity { "To use an identity with a configured wallet you can do one of the following:\n\ - Run the command for a network where you have a wallet configured. To do so, add '--network ' to your command.\n\ - Switch to an identity that has a wallet configured using 'dfx identity use '.\n\ - - Configure a wallet for this identity/network combination: 'dfx identity --network set-wallet '.".to_string())).context("Wallet not configured.") + - Configure a wallet for this identity/network combination: 'dfx identity set-wallet --network '.".to_string())).context("Wallet not configured.") } } Some(principal) => Ok(principal), diff --git a/src/dfx/src/lib/models/canister_id_store.rs b/src/dfx/src/lib/models/canister_id_store.rs index 095ccb296d..12cd5bdc02 100644 --- a/src/dfx/src/lib/models/canister_id_store.rs +++ b/src/dfx/src/lib/models/canister_id_store.rs @@ -134,13 +134,9 @@ impl CanisterIdStore { let network = if self.network_descriptor.name == "local" { "".to_string() } else { - format!("--network {} ", self.network_descriptor.name) + format!(" --network {}", self.network_descriptor.name) }; - anyhow!( - "Cannot find canister id. Please issue 'dfx canister {}create {}'.", - network, - canister_name, - ) + anyhow!("Cannot find canister id. Please issue 'dfx canister create {canister_name}{network}'.") }) } diff --git a/src/dfx/src/main.rs b/src/dfx/src/main.rs index e380b512f5..112f77cc5c 100644 --- a/src/dfx/src/main.rs +++ b/src/dfx/src/main.rs @@ -3,8 +3,9 @@ use crate::lib::environment::{Environment, EnvironmentImpl}; use crate::lib::logger::{create_root_logger, LoggingMode}; use anyhow::Error; -use clap::Parser; +use clap::{Args, Parser}; use lib::diagnosis::{diagnose, Diagnosis, NULL_DIAGNOSIS}; +use lib::error::DfxResult; use semver::Version; use std::path::PathBuf; @@ -18,23 +19,39 @@ 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))] verbose: u64, + /// Suppresses informational messages. -qq limits to errors only; -qqqq disables them all. #[clap(long, short('q'), parse(from_occurrences))] 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"]))] logmode: String, + /// The file to log to, if logging to a file (see --logmode). #[clap(long)] 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)] identity: Option, - - #[clap(subcommand)] - command: commands::Command, } fn is_warning_disabled(warning: &str) -> bool { @@ -87,7 +104,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: &CliOpts) -> (bool, slog::Logger) { +fn setup_logging(opts: &EnvOpts) -> (bool, slog::Logger) { // Create a logger with our argument matches. let level = opts.verbose as i64 - opts.quiet as i64; @@ -157,34 +174,32 @@ 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 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, - } + match commands::dispatch(command) { + Err(e) => { + error_diagnosis = diagnose(&env, &e); + Err(e) } - Err(e) => Err(e), + ok => ok, } } Err(e) => Err(e),