diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 08641b9ad..f2f53bd78 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -27,8 +27,6 @@ jobs: crate: - name: stellar-cli binary: stellar - - name: soroban-cli - binary: soroban sys: - os: ubuntu-20.04 # Use 20.04 to get an older version of glibc for increased compat target: x86_64-unknown-linux-gnu diff --git a/Cargo.lock b/Cargo.lock index e5c37b671..5bd7c178c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4981,6 +4981,10 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stellar-bye" +version = "21.5.0" + [[package]] name = "stellar-cli" version = "21.5.0" diff --git a/Cargo.toml b/Cargo.toml index ef052c569..8b10f373d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,10 @@ members = [ "cmd/crates/*", "cmd/crates/soroban-test/tests/fixtures/test-wasms/*", "cmd/crates/soroban-test/tests/fixtures/hello", + "cmd/crates/soroban-test/tests/fixtures/bye", ] default-members = ["cmd/soroban-cli", "cmd/crates/soroban-spec-tools", "cmd/crates/soroban-test"] -exclude = ["cmd/crates/soroban-test/tests/fixtures/hello"] +exclude = ["cmd/crates/soroban-test/tests/fixtures/hello", "cmd/crates/soroban-test/tests/fixtures/bye"] [workspace.package] version = "21.5.0" diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index 41575aea0..b3724b98b 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -1517,7 +1517,7 @@ Creates and funds a new account with the specified starting balance * `--destination ` — Account Id to create, e.g. `GBX...` * `--starting-balance ` — Initial balance in stroops of the account, default 1 XLM - Default value: `10_000_000` + Default value: `10000000` diff --git a/Makefile b/Makefile index 4db0946ce..8a1333bd9 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ install_rust: install install: cargo install --force --locked --path ./cmd/stellar-cli --debug cargo install --force --locked --path ./cmd/crates/soroban-test/tests/fixtures/hello --root ./target --debug --quiet + cargo install --force --locked --path ./cmd/crates/soroban-test/tests/fixtures/bye --root ./target --debug --quiet # regenerate the example lib in `cmd/crates/soroban-spec-typsecript/fixtures/ts` build-snapshot: typescript-bindings-fixtures diff --git a/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.lock b/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.lock new file mode 100644 index 000000000..59924f294 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "stellar-bye" +version = "0.1.0" diff --git a/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml b/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml new file mode 100644 index 000000000..7678eee5e --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/bye/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "stellar-bye" +version = "21.5.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/cmd/crates/soroban-test/tests/fixtures/bye/src/main.rs b/cmd/crates/soroban-test/tests/fixtures/bye/src/main.rs new file mode 100644 index 000000000..5fb678863 --- /dev/null +++ b/cmd/crates/soroban-test/tests/fixtures/bye/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Bye, world!"); +} diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index 70dfaa693..31d60e116 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -1,4 +1,5 @@ use assert_fs::TempDir; +use predicates::prelude::predicate; use soroban_test::{AssertExt, TestEnv}; use std::{fs, path::Path}; @@ -288,3 +289,54 @@ fn use_env() { .success() .stdout("SDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2DYQCHVCQYFD\n"); } + +#[test] +fn config_dirs_precedence() { + let sandbox = TestEnv::default(); + + sandbox + .new_assert_cmd("keys") + .env( + "SOROBAN_SECRET_KEY", + "SC4ZPYELVR7S7EE7KZDZN3ETFTNQHHLTUL34NUAAWZG5OK2RGJ4V2U3Z", + ) + .arg("add") + .arg("alice") + .assert() + .success(); + + fs::rename( + sandbox.dir().join(".stellar"), + sandbox.dir().join("_soroban"), + ) + .unwrap(); + + sandbox + .new_assert_cmd("keys") + .env( + "SOROBAN_SECRET_KEY", + "SAQMV6P3OWM2SKCK3OEWNXSRYWK5RNNUL5CPHQGIJF2WVT4EI2BZ63GG", + ) + .arg("add") + .arg("alice") + .assert() + .success(); + + fs::rename( + sandbox.dir().join("_soroban"), + sandbox.dir().join(".soroban"), + ) + .unwrap(); + + sandbox + .new_assert_cmd("keys") + .arg("show") + .arg("alice") + .arg("--verbose") + .assert() + .success() + .stderr(predicate::str::contains( + "WARN soroban_cli::utils: the .stellar and .soroban config directories exist at path", + )) + .stdout("SAQMV6P3OWM2SKCK3OEWNXSRYWK5RNNUL5CPHQGIJF2WVT4EI2BZ63GG\n"); +} diff --git a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs index 767c9a07c..272587c53 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -74,7 +74,7 @@ async fn invoke() { .assert() .stdout_as_str(); let dir = sandbox.dir(); - let seed_phrase = std::fs::read_to_string(dir.join(".soroban/identity/test.toml")).unwrap(); + let seed_phrase = std::fs::read_to_string(dir.join(".stellar/identity/test.toml")).unwrap(); let s = toml::from_str::(&seed_phrase).unwrap(); let secret::Secret::SeedPhrase { seed_phrase } = s else { panic!("Expected seed phrase") @@ -113,7 +113,7 @@ async fn invoke() { }, ) .unwrap(); - let sk_from_file = std::fs::read_to_string(dir.join(".soroban/identity/testone.toml")).unwrap(); + let sk_from_file = std::fs::read_to_string(dir.join(".stellar/identity/testone.toml")).unwrap(); assert_eq!(sk_from_file, format!("secret_key = \"{secret_key_1}\"\n")); let secret_key_1_readin = sandbox diff --git a/cmd/crates/soroban-test/tests/it/plugin.rs b/cmd/crates/soroban-test/tests/it/plugin.rs index 450902d65..5e5eabee9 100644 --- a/cmd/crates/soroban-test/tests/it/plugin.rs +++ b/cmd/crates/soroban-test/tests/it/plugin.rs @@ -1,7 +1,7 @@ /* -This function calls the soroban executable via cargo and checks that the output +This function calls the stellar executable via cargo and checks that the output is correct. The PATH environment variable is set to include the target/bin -directory, so that the soroban executable can be found. +directory, so that the stellar executable can be found. */ use std::{ffi::OsString, path::PathBuf}; @@ -11,7 +11,7 @@ fn soroban_hello() { // Add the target/bin directory to the iterator of paths let paths = get_paths(); // Call soroban with the PATH variable set to include the target/bin directory - assert_cmd::Command::cargo_bin("soroban") + assert_cmd::Command::cargo_bin("stellar") .unwrap_or_else(|_| assert_cmd::Command::new("soroban")) .arg("hello") .env("PATH", &paths) @@ -19,23 +19,37 @@ fn soroban_hello() { .stdout("Hello, world!\n"); } +#[test] +fn stellar_bye() { + // Add the target/bin directory to the iterator of paths + let paths = get_paths(); + // Call soroban with the PATH variable set to include the target/bin directory + assert_cmd::Command::cargo_bin("stellar") + .unwrap_or_else(|_| assert_cmd::Command::new("stellar")) + .arg("bye") + .env("PATH", &paths) + .assert() + .stdout("Bye, world!\n"); +} + #[test] fn list() { // Call `soroban --list` with the PATH variable set to include the target/bin directory - assert_cmd::Command::cargo_bin("soroban") - .unwrap_or_else(|_| assert_cmd::Command::new("soroban")) + assert_cmd::Command::cargo_bin("stellar") + .unwrap_or_else(|_| assert_cmd::Command::new("stellar")) .arg("--list") .env("PATH", get_paths()) .assert() - .stdout(predicates::str::contains("hello")); + .stdout(predicates::str::contains("hello")) + .stdout(predicates::str::contains("bye")); } #[test] #[cfg(not(unix))] fn has_no_path() { // Call soroban with the PATH variable set to include just target/bin directory - assert_cmd::Command::cargo_bin("soroban") - .unwrap_or_else(|_| assert_cmd::Command::new("soroban")) + assert_cmd::Command::cargo_bin("stellar") + .unwrap_or_else(|_| assert_cmd::Command::new("stellar")) .arg("hello") .env("PATH", target_bin()) .assert() @@ -45,8 +59,8 @@ fn has_no_path() { #[test] fn has_no_path_failure() { // Call soroban with the PATH variable set to include just target/bin directory - assert_cmd::Command::cargo_bin("soroban") - .unwrap_or_else(|_| assert_cmd::Command::new("soroban")) + assert_cmd::Command::cargo_bin("stellar") + .unwrap_or_else(|_| assert_cmd::Command::new("stellar")) .arg("hello") .assert() .stderr(predicates::str::contains("error: no such command: `hello`")); diff --git a/cmd/soroban-cli/src/cli.rs b/cmd/soroban-cli/src/cli.rs index 5470562db..9183d0e30 100644 --- a/cmd/soroban-cli/src/cli.rs +++ b/cmd/soroban-cli/src/cli.rs @@ -2,8 +2,9 @@ use clap::CommandFactory; use dotenvy::dotenv; use tracing_subscriber::{fmt, EnvFilter}; +use crate::print::Print; use crate::upgrade_check::upgrade_check; -use crate::{commands, print, Root}; +use crate::{commands, Root}; #[tokio::main] pub async fn main() { @@ -42,6 +43,7 @@ pub async fn main() { std::process::exit(1); } }); + // Now use root to setup the logger if let Some(level) = root.global_args.log_level() { let mut e_filter = EnvFilter::from_default_env() @@ -78,7 +80,7 @@ pub async fn main() { upgrade_check(root.global_args.quiet).await; }); - let printer = print::Print::new(root.global_args.quiet); + let printer = Print::new(root.global_args.quiet); if let Err(e) = root.run().await { printer.errorln(format!("error: {e}")); std::process::exit(1); diff --git a/cmd/soroban-cli/src/commands/plugin.rs b/cmd/soroban-cli/src/commands/plugin.rs index 2fa028d5c..d933564f2 100644 --- a/cmd/soroban-cli/src/commands/plugin.rs +++ b/cmd/soroban-cli/src/commands/plugin.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::{path::PathBuf, process::Command}; use clap::CommandFactory; use which::which; @@ -44,7 +44,7 @@ pub fn run() -> Result<(), Error> { return Ok(()); } - let bin = which(format!("soroban-{name}")).map_err(|_| { + let bin = find_bin(&name).map_err(|_| { let suggestion = if let Ok(bins) = list() { let suggested_name = bins .iter() @@ -53,6 +53,7 @@ pub fn run() -> Result<(), Error> { .min_by(|a, b| a.1.total_cmp(&b.1)) .map(|(a, _)| a.to_string()) .unwrap_or_default(); + if suggested_name.is_empty() { suggested_name } else { @@ -64,8 +65,10 @@ pub fn run() -> Result<(), Error> { } else { String::new() }; + Error::ExecutableNotFound(name, suggestion) })?; + std::process::exit( Command::new(bin) .args(args) @@ -78,19 +81,29 @@ pub fn run() -> Result<(), Error> { const MAX_HEX_LENGTH: usize = 10; +fn find_bin(name: &str) -> Result { + if let Ok(path) = which(format!("stellar-{name}")) { + Ok(path) + } else { + which(format!("soroban-{name}")) + } +} + pub fn list() -> Result, Error> { let re_str = if cfg!(target_os = "windows") { - r"^soroban-.*.exe$" + r"^(soroban|stellar)-.*.exe$" } else { - r"^soroban-.*" + r"^(soroban|stellar)-.*" }; + let re = regex::Regex::new(re_str)?; + Ok(which::which_re(re)? .filter_map(|b| { let s = b.file_name()?.to_str()?; Some(s.strip_suffix(".exe").unwrap_or(s).to_string()) }) .filter(|s| !(utils::is_hex_string(s) && s.len() > MAX_HEX_LENGTH)) - .map(|s| s.replace("soroban-", "")) + .map(|s| s.replace("soroban-", "").replace("stellar-", "")) .collect()) } diff --git a/cmd/soroban-cli/src/commands/tx/new/create_account.rs b/cmd/soroban-cli/src/commands/tx/new/create_account.rs index 967c0cf43..9cc3a62ff 100644 --- a/cmd/soroban-cli/src/commands/tx/new/create_account.rs +++ b/cmd/soroban-cli/src/commands/tx/new/create_account.rs @@ -11,7 +11,7 @@ pub struct Cmd { #[arg(long)] pub destination: xdr::AccountId, /// Initial balance in stroops of the account, default 1 XLM - #[arg(long, default_value = "10_000_000")] + #[arg(long, default_value = "10000000")] pub starting_balance: i64, } diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index 2fad2bb62..70b4f75f8 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -145,7 +145,7 @@ impl Args { pub fn local_config(&self) -> Result { let pwd = self.current_dir()?; - Ok(find_config_dir(pwd.clone()).unwrap_or_else(|_| pwd.join(".soroban"))) + Ok(find_config_dir(pwd.clone()).unwrap_or_else(|_| pwd.join(".stellar"))) } pub fn current_dir(&self) -> Result { @@ -468,14 +468,32 @@ impl KeyType { } pub fn global_config_path() -> Result { - Ok(if let Ok(config_home) = std::env::var("XDG_CONFIG_HOME") { + let config_dir = if let Ok(config_home) = std::env::var("XDG_CONFIG_HOME") { PathBuf::from_str(&config_home).map_err(|_| Error::XdgConfigHome(config_home))? } else { dirs::home_dir() .ok_or(Error::HomeDirNotFound)? .join(".config") + }; + + let soroban_dir = config_dir.join("soroban"); + let stellar_dir = config_dir.join("stellar"); + let soroban_exists = soroban_dir.exists(); + let stellar_exists = stellar_dir.exists(); + + if stellar_exists && soroban_exists { + tracing::warn!("the .stellar and .soroban config directories exist at path {config_dir:?}, using the .stellar"); + } + + if stellar_exists { + return Ok(stellar_dir); } - .join("soroban")) + + if soroban_exists { + return Ok(soroban_dir); + } + + Ok(stellar_dir) } impl Pwd for Args { diff --git a/cmd/soroban-cli/src/print.rs b/cmd/soroban-cli/src/print.rs index 5b8ca2bd2..ca66cdc50 100644 --- a/cmd/soroban-cli/src/print.rs +++ b/cmd/soroban-cli/src/print.rs @@ -8,6 +8,7 @@ use crate::{ const TERMS: &[&str] = &["Apple_Terminal", "vscode"]; +#[derive(Clone)] pub struct Print { pub quiet: bool, } diff --git a/cmd/soroban-cli/src/utils.rs b/cmd/soroban-cli/src/utils.rs index 6e87d15a6..0c4207a4e 100644 --- a/cmd/soroban-cli/src/utils.rs +++ b/cmd/soroban-cli/src/utils.rs @@ -95,10 +95,12 @@ pub fn find_config_dir(mut pwd: std::path::PathBuf) -> std::io::Result