From: Vihiga Tyonum Date: Fri, 2 Oct 2026 05:14:16 +0000 (+0100) Subject: fix(cli): use valid envt variable names for env fallbacks X-Git-Url: http://internal-gitweb-vhost/-client-interface/src/example_cli/enum.Segwitv0.html?a=commitdiff_plain;h=e8fc1e3ed10e351886b31cdd431fc4bda974aca0;p=bdk-cli fix(cli): use valid envt variable names for env fallbacks Several `#[arg(env = "...")]` attributes mistakenly used colons (e.g., `ADDRESS:SAT`) following value-shape documentation conventions. Because colons are invalid in POSIX environment variable names, these fallbacks could never actually be set by users. Renamed these environment variables to use valid identifiers while keeping the flag names and expected value shapes unchanged. Also, format integration tests --- diff --git a/src/commands.rs b/src/commands.rs index 86826ff..d921e7c 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -271,7 +271,7 @@ pub struct WalletOpts { #[cfg(feature = "rpc")] /// Sets the rpc basic authentication. #[arg( - env = "USER:PASSWD", + env = "RPC_BASIC_AUTH", short = 'a', long, value_parser = parse_proxy_auth, @@ -307,16 +307,17 @@ impl WalletOpts { ))); } #[cfg(any(feature = "electrum", feature = "esplora"))] - if self.proxy_opts.proxy_auth.is_some() { - return Err(Error::Generic(format!( - "The {_backend} backend does not support --proxy_auth." - ))); - } - #[cfg(any(feature = "electrum", feature = "esplora"))] - if self.proxy_opts.timeout.is_some() { - return Err(Error::Generic(format!( - "The {_backend} backend does not support --timeout." - ))); + { + if self.proxy_opts.proxy_auth.is_some() { + return Err(Error::Generic(format!( + "The {_backend} backend does not support --proxy_auth." + ))); + } + if self.proxy_opts.timeout.is_some() { + return Err(Error::Generic(format!( + "The {_backend} backend does not support --timeout." + ))); + } } Ok(()) } @@ -330,16 +331,17 @@ impl WalletOpts { #[cfg(feature = "cbf")] pub(crate) fn reject_proxy_auth(&self, _backend: &str) -> Result<(), Error> { #[cfg(any(feature = "electrum", feature = "esplora"))] - if self.proxy_opts.proxy_auth.is_some() { - return Err(Error::Generic(format!( - "The {_backend} backend does not support --proxy_auth." - ))); - } - #[cfg(any(feature = "electrum", feature = "esplora"))] - if self.proxy_opts.timeout.is_some() { - return Err(Error::Generic(format!( - "The {_backend} backend does not support --timeout." - ))); + { + if self.proxy_opts.proxy_auth.is_some() { + return Err(Error::Generic(format!( + "The {_backend} backend does not support --proxy_auth." + ))); + } + if self.proxy_opts.timeout.is_some() { + return Err(Error::Generic(format!( + "The {_backend} backend does not support --timeout." + ))); + } } Ok(()) } @@ -350,12 +352,12 @@ impl WalletOpts { #[derive(Debug, Args, Clone, PartialEq, Eq)] pub struct ProxyOpts { /// Sets the SOCKS5 proxy for a blockchain client. - #[arg(env = "PROXY_ADDRS:PORT", long = "proxy")] + #[arg(env = "PROXY_ADDRS_PORT", long = "proxy")] pub proxy: Option, /// Sets the SOCKS5 proxy credential. #[cfg(any(feature = "electrum", feature = "esplora"))] - #[arg(env = "PROXY_USER:PASSWD", long="proxy_auth", value_parser = parse_proxy_auth)] + #[arg(env = "PROXY_USER_PASSWD", long="proxy_auth", value_parser = parse_proxy_auth)] pub proxy_auth: Option<(String, String)>, /// Sets the SOCKS5 proxy retries for the blockchain client. diff --git a/src/handlers/dns/mod.rs b/src/handlers/dns/mod.rs index a573369..645672c 100644 --- a/src/handlers/dns/mod.rs +++ b/src/handlers/dns/mod.rs @@ -41,7 +41,7 @@ impl AsyncAppCommand> for ResolveDnsRecipientCommand { /// Creates a new unsigned transaction from DNS payment instructions. #[derive(Parser, Debug, Clone, PartialEq)] pub struct CreateDnsTxCommand { - #[arg(env = "ADDRESS:SAT", long = "to", value_parser = parse_recipient)] + #[arg(env = "ADDRESS_SAT", long = "to", value_parser = parse_recipient)] pub recipients: Vec<(ScriptBuf, u64)>, #[arg(long = "to_dns", value_parser = parse_dns_recipient)] pub dns_recipients: Vec<(String, u64)>, @@ -53,9 +53,9 @@ pub struct CreateDnsTxCommand { pub enable_rbf: bool, #[arg(long = "offline_signer")] pub offline_signer: bool, - #[arg(env = "MUST_SPEND_TXID:VOUT", long = "utxos", value_parser = parse_outpoint)] + #[arg(env = "MUST_SPEND_TXID_VOUT", long = "utxos", value_parser = parse_outpoint)] pub utxos: Option>, - #[arg(env = "CANT_SPEND_TXID:VOUT", long = "unspendable", value_parser = parse_outpoint)] + #[arg(env = "CANT_SPEND_TXID_VOUT", long = "unspendable", value_parser = parse_outpoint)] pub unspendable: Option>, #[arg(env = "SATS_VBYTE", short = 'f', long = "fee_rate", value_parser = parse_fee_rate)] pub fee_rate: Option, diff --git a/src/handlers/offline.rs b/src/handlers/offline.rs index 4b623b4..15cdd26 100644 --- a/src/handlers/offline.rs +++ b/src/handlers/offline.rs @@ -193,7 +193,7 @@ impl AppCommand>> for BalanceCommand { #[derive(Debug, Parser, Clone, PartialEq)] pub struct CreateTxCommand { /// Adds a recipient to the transaction. - #[arg(env = "ADDRESS:SAT", long = "to", required = true, value_parser = parse_recipient)] + #[arg(env = "ADDRESS_SAT", long = "to", required = true, value_parser = parse_recipient)] pub recipients: Vec<(ScriptBuf, u64)>, /// Sends all the funds (or all the selected utxos). Requires only one recipient with value 0. @@ -209,11 +209,11 @@ pub struct CreateTxCommand { pub offline_signer: bool, /// Selects which utxos *must* be spent. - #[arg(env = "MUST_SPEND_TXID:VOUT", long = "utxos", value_parser = parse_outpoint)] + #[arg(env = "MUST_SPEND_TXID_VOUT", long = "utxos", value_parser = parse_outpoint)] pub utxos: Option>, /// Marks a utxo as unspendable. - #[arg(env = "CANT_SPEND_TXID:VOUT", long = "unspendable", value_parser = parse_outpoint)] + #[arg(env = "CANT_SPEND_TXID_VOUT", long = "unspendable", value_parser = parse_outpoint)] pub unspendable: Option>, /// Fee rate to use in sat/vbyte. @@ -327,7 +327,7 @@ pub struct CreateSpTxCommand { /// Adds a recipient to the transaction. // Clap Doesn't support complex vector parsing https://github.com/clap-rs/clap/issues/1704. // Address and amount parsing is done at run time in handler function. - #[arg(env = "ADDRESS:SAT", long = "to", required = false, value_parser = parse_recipient)] + #[arg(env = "ADDRESS_SAT", long = "to", required = false, value_parser = parse_recipient)] pub recipients: Option>, /// Parse silent payment recipients #[arg(long = "to-sp", required = true, value_parser = parse_sp_code_value_pairs)] @@ -339,10 +339,10 @@ pub struct CreateSpTxCommand { #[arg(long = "offline_signer")] pub offline_signer: bool, /// Selects which utxos *must* be spent. - #[arg(env = "MUST_SPEND_TXID:VOUT", long = "utxos", value_parser = parse_outpoint)] + #[arg(env = "MUST_SPEND_TXID_VOUT", long = "utxos", value_parser = parse_outpoint)] pub utxos: Option>, /// Marks a utxo as unspendable. - #[arg(env = "CANT_SPEND_TXID:VOUT", long = "unspendable", value_parser = parse_outpoint)] + #[arg(env = "CANT_SPEND_TXID_VOUT", long = "unspendable", value_parser = parse_outpoint)] pub unspendable: Option>, /// Fee rate to use in sat/vbyte. #[arg(env = "SATS_VBYTE", short = 'f', long = "fee_rate", value_parser = parse_fee_rate)] @@ -547,11 +547,11 @@ pub struct BumpFeeCommand { pub offline_signer: bool, /// Selects which utxos *must* be added to the tx. Unconfirmed utxos cannot be used. - #[arg(env = "MUST_SPEND_TXID:VOUT", long = "utxos", value_parser = parse_outpoint)] + #[arg(env = "MUST_SPEND_TXID_VOUT", long = "utxos", value_parser = parse_outpoint)] pub utxos: Option>, /// Marks an utxo as unspendable, in case more inputs are needed to cover the extra fees. - #[arg(env = "CANT_SPEND_TXID:VOUT", long = "unspendable", value_parser = parse_outpoint)] + #[arg(env = "CANT_SPEND_TXID_VOUT", long = "unspendable", value_parser = parse_outpoint)] pub unspendable: Option>, /// The new targeted fee rate in sat/vbyte. diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4322016..d38edf8 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -40,14 +40,14 @@ impl BdkCli { pub fn build_base_cmd(&self) -> Command { let mut cmd = Command::cargo_bin("bdk-cli").expect("bdk-cli binary must compile"); - cmd.arg("--network").arg(&self.network); + cmd.args(["--network", &self.network]); if let Some(dir) = &self.datadir { cmd.arg("--datadir").arg(dir); } if let Some(url) = &self.server_url { - cmd.arg("--server").arg(url); + cmd.args(["--server", url]); } cmd diff --git a/tests/integration/init.rs b/tests/integration/init.rs index 0a2af96..4f57b46 100644 --- a/tests/integration/init.rs +++ b/tests/integration/init.rs @@ -138,19 +138,13 @@ mod test_wallets { cli.build_base_cmd() .arg("wallet") - .arg("--wallet") - .arg(wallet_name) + .args(["--wallet", wallet_name]) .arg("config") - .arg("--ext-descriptor") - .arg(ext_desc) - .arg("--int-descriptor") - .arg(int_desc) - .arg("--client-type") - .arg("rpc") - .arg("--database-type") - .arg("sqlite") - .arg("--url") - .arg("http://localhost:18443") + .args(["--ext-descriptor", ext_desc]) + .args(["--int-descriptor", int_desc]) + .args(["--client-type", "rpc"]) + .args(["--database-type", "sqlite"]) + .args(["--url", "http://localhost:18443"]) .assert() .success(); } @@ -246,19 +240,13 @@ mod test_config { let mut cmd_init = cli.build_base_cmd(); cmd_init .arg("wallet") - .arg("--wallet") - .arg(wallet_name) + .args(["--wallet", wallet_name]) .arg("config") - .arg("--ext-descriptor") - .arg(ext_desc) - .arg("--int-descriptor") - .arg(int_desc) - .arg("--client-type") - .arg(client_type) - .arg("--database-type") - .arg(db) - .arg("--url") - .arg(url); + .args(["--ext-descriptor", ext_desc]) + .args(["--int-descriptor", int_desc]) + .args(["--client-type", client_type]) + .args(["--database-type", db]) + .args(["--url", url]); cmd_init.assert().success(); @@ -310,19 +298,15 @@ mod test_config { cli.build_base_cmd() .arg("wallet") - .arg("--wallet") - .arg("secret_wallet") + .args(["--wallet", "secret_wallet"]) .arg("config") .arg("--ext-descriptor") .arg(priv_desc["external"].as_str().unwrap()) .arg("--int-descriptor") .arg(priv_desc["internal"].as_str().unwrap()) - .arg("--client-type") - .arg("rpc") - .arg("--database-type") - .arg("sqlite") - .arg("--url") - .arg("http://localhost:18443") + .args(["--client-type", "rpc"]) + .args(["--database-type", "sqlite"]) + .args(["--url", "http://localhost:18443"]) .assert() .success() .stderr(predicate::str::contains("PRIVATE KEYS")); diff --git a/tests/integration/offline.rs b/tests/integration/offline.rs index 4b678eb..417bf72 100644 --- a/tests/integration/offline.rs +++ b/tests/integration/offline.rs @@ -35,19 +35,13 @@ mod test_offline { let mut cmd_init = cli.build_base_cmd(); cmd_init .arg("wallet") - .arg("--wallet") - .arg(WALLET_NAME) + .args(["--wallet", WALLET_NAME]) .arg("config") - .arg("--ext-descriptor") - .arg(ext_desc) - .arg("--int-descriptor") - .arg(int_desc) - .arg("--client-type") - .arg(client_type) - .arg("--database-type") - .arg(db) - .arg("--url") - .arg(url); + .args(["--ext-descriptor", ext_desc]) + .args(["--int-descriptor", int_desc]) + .args(["--client-type", client_type]) + .args(["--database-type", db]) + .args(["--url", url]); (cli, cmd_init) } @@ -438,13 +432,10 @@ mod multipath_tests { fn save_config(cli: &BdkCli, wallet: &str, ext: &str, int: Option<&str>) -> Command { let mut cmd = cli.build_base_cmd(); cmd.arg("wallet") - .arg("--wallet") - .arg(wallet) + .args(["--wallet", wallet]) .arg("config") - .arg("--ext-descriptor") - .arg(ext) - .arg("--database-type") - .arg("sqlite"); + .args(["--ext-descriptor", ext]) + .args(["--database-type", "sqlite"]); if let Some(int) = int { cmd.arg("--int-descriptor").arg(int); } diff --git a/tests/integration/online.rs b/tests/integration/online.rs index b9dcc7b..4d3f11a 100644 --- a/tests/integration/online.rs +++ b/tests/integration/online.rs @@ -33,19 +33,13 @@ mod test_online { let mut cmd_init = cli.build_base_cmd(); cmd_init .arg("wallet") - .arg("--wallet") - .arg(WALLET_NAME) + .args(["--wallet", WALLET_NAME]) .arg("config") - .arg("--ext-descriptor") - .arg(ext_desc) - .arg("--int-descriptor") - .arg(int_desc) - .arg("--client-type") - .arg("electrum") - .arg("--database-type") - .arg("sqlite") - .arg("--url") - .arg(server_url); + .args(["--ext-descriptor", ext_desc]) + .args(["--int-descriptor", int_desc]) + .args(["--client-type", "electrum"]) + .args(["--database-type", "sqlite"]) + .args(["--url", server_url]); (cli, cmd_init, env) } @@ -862,19 +856,13 @@ mod test_online { .unwrap(); cli.build_base_cmd() .arg("wallet") - .arg("--wallet") - .arg(WALLET_NAME) + .args(["--wallet", WALLET_NAME]) .arg("config") - .arg("--ext-descriptor") - .arg(ext_desc) - .arg("--int-descriptor") - .arg(int_desc) - .arg("--client-type") - .arg("electrum") - .arg("--database-type") - .arg("sqlite") - .arg("--url") - .arg(server_url) + .args(["--ext-descriptor", ext_desc]) + .args(["--int-descriptor", int_desc]) + .args(["--client-type", "electrum"]) + .args(["--database-type", "sqlite"]) + .args(["--url", server_url]) .assert() .success(); diff --git a/tests/integration/proxy.rs b/tests/integration/proxy.rs index 2d676b6..9b36946 100644 --- a/tests/integration/proxy.rs +++ b/tests/integration/proxy.rs @@ -10,14 +10,14 @@ mod test_proxy { #[cfg(any(feature = "rpc", feature = "cbf"))] use predicates::prelude::*; use serde_json::Value; - #[cfg(any(feature = "electrum", feature = "esplora"))] - use std::net::{TcpListener, TcpStream}; - #[cfg(any(feature = "electrum", feature = "esplora"))] - use std::sync::mpsc::{Receiver, channel}; - #[cfg(any(feature = "electrum", feature = "esplora"))] - use std::thread; use std::time::Duration; use tempfile::TempDir; + #[cfg(any(feature = "electrum", feature = "esplora"))] + use { + std::net::{TcpListener, TcpStream}, + std::sync::mpsc::{Receiver, channel}, + std::thread, + }; static WALLET_NAME: &str = "proxy_test_wallet"; @@ -75,19 +75,13 @@ mod test_proxy { let mut cmd = cli.build_base_cmd(); cmd.arg("wallet") - .arg("--wallet") - .arg(WALLET_NAME) + .args(["--wallet", WALLET_NAME]) .arg("config") - .arg("--ext-descriptor") - .arg(ext_desc) - .arg("--int-descriptor") - .arg(int_desc) - .arg("--client-type") - .arg(client_type) - .arg("--database-type") - .arg("sqlite") - .arg("--url") - .arg(url); + .args(["--ext-descriptor", ext_desc]) + .args(["--int-descriptor", int_desc]) + .args(["--client-type", client_type]) + .args(["--database-type", "sqlite"]) + .args(["--url", url]); if let Some(proxy) = proxy_addr { cmd.arg("--proxy").arg(proxy); } @@ -122,17 +116,14 @@ mod test_proxy { let mut cmd = cli.build_base_cmd(); cmd.arg("wallet") - .arg("--wallet") - .arg(WALLET_NAME) + .args(["--wallet", WALLET_NAME]) .arg("config") .arg("--ext-descriptor") .arg(public["external"].as_str().unwrap()) .arg("--int-descriptor") .arg(public["internal"].as_str().unwrap()) - .arg("--client-type") - .arg(client_type) - .arg("--database-type") - .arg("sqlite"); + .args(["--client-type", client_type]) + .args(["--database-type", "sqlite"]); // `--url` is required whenever electrum, esplora or rpc is built, no matter // which `--client-type` is chosen; it does not exist at all otherwise. #[cfg(any(feature = "electrum", feature = "esplora", feature = "rpc"))]