diff --git a/Cargo.lock b/Cargo.lock index f296410140..1b7d8dab75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4621,7 +4621,9 @@ dependencies = [ "color-eyre", "futures", "libp2p", + "sn_build_info", "sn_networking", + "sn_protocol", "tokio", "tracing", "tracing-log 0.2.0", @@ -4758,7 +4760,9 @@ dependencies = [ "signal-hook", "sn-node-manager", "sn-releases", + "sn_build_info", "sn_peers_acquisition", + "sn_protocol", "sn_service_management", "strip-ansi-escapes", "strum", @@ -6986,6 +6990,7 @@ dependencies = [ "serde_json", "service-manager", "sn-releases", + "sn_build_info", "sn_logging", "sn_peers_acquisition", "sn_protocol", @@ -7034,9 +7039,11 @@ dependencies = [ "lazy_static", "serde", "serde_json", + "sn_build_info", "sn_client", "sn_logging", "sn_peers_acquisition", + "sn_protocol", "tiny_http", "tokio", "tracing", @@ -7059,6 +7066,8 @@ dependencies = [ name = "sn_build_info" version = "0.1.13" dependencies = [ + "chrono", + "tracing", "vergen", ] @@ -7368,6 +7377,7 @@ dependencies = [ "hex 0.4.3", "libp2p", "libp2p-identity", + "sn_build_info", "sn_client", "sn_logging", "sn_node", diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 21e67b55e8..47f925dd70 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -13,6 +13,9 @@ version = "0.2.5" name = "nat-detection" path = "src/main.rs" +[features] +nightly = [] + [dependencies] clap = { version = "4.5.4", features = ["derive"] } clap-verbosity-flag = "2.2.0" @@ -28,7 +31,9 @@ libp2p = { version = "0.54.1", features = [ "macros", "upnp", ] } +sn_build_info = { path = "../sn_build_info", version = "0.1.13" } sn_networking = { path = "../sn_networking", version = "0.18.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.9" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/nat-detection/src/main.rs b/nat-detection/src/main.rs index 645b181266..fccbe3ea4c 100644 --- a/nat-detection/src/main.rs +++ b/nat-detection/src/main.rs @@ -35,7 +35,7 @@ const RETRY_INTERVAL: Duration = Duration::from_secs(10); /// - 11: Public under UPnP /// - 12: Private or Unknown NAT #[derive(Debug, Parser)] -#[clap(version, author, verbatim_doc_comment)] +#[clap(disable_version_flag = true)] struct Opt { /// Port to listen on. /// @@ -60,15 +60,50 @@ struct Opt { #[command(flatten)] verbose: clap_verbosity_flag::Verbosity, + + /// Print the crate version + #[clap(long)] + crate_version: bool, + + /// Print the package version + #[clap(long)] + #[cfg(not(feature = "nightly"))] + package_version: bool, + + /// Print version information. + #[clap(long)] + version: bool, } #[tokio::main] async fn main() -> Result<()> { color_eyre::install()?; - // Process command line arguments. let opt = Opt::parse(); + if opt.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi NAT Detection", + env!("CARGO_PKG_VERSION"), + None + ) + ); + return Ok(()); + } + + if opt.crate_version { + println!("Crate version: {}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if opt.package_version { + println!("Package version: {}", sn_build_info::package_version()); + return Ok(()); + } + let registry = tracing_subscriber::registry().with(tracing_subscriber::fmt::layer()); // Use `RUST_LOG` if set, else use the verbosity flag (where `-vvvv` is trace level). let _ = if std::env::var_os("RUST_LOG").is_some() { diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 7f2f493f51..f1b006bd67 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -14,6 +14,9 @@ build = "build.rs" name = "node-launchpad" path = "src/bin/tui/main.rs" +[features] +nightly = [] + [dependencies] atty = "0.2.14" better-panic = "0.3.0" @@ -48,8 +51,10 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" +sn_build_info = { path = "../sn_build_info", version = "0.1.13" } sn-node-manager = { version = "0.10.4", path = "../sn_node_manager" } sn_peers_acquisition = { version = "0.5.1", path = "../sn_peers_acquisition" } +sn_protocol = { path = "../sn_protocol", version = "0.17.9" } sn-releases = "~0.2.6" sn_service_management = { version = "0.3.12", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" diff --git a/node-launchpad/src/bin/tui/main.rs b/node-launchpad/src/bin/tui/main.rs index 2ceb235900..d3074018af 100644 --- a/node-launchpad/src/bin/tui/main.rs +++ b/node-launchpad/src/bin/tui/main.rs @@ -16,7 +16,7 @@ use color_eyre::eyre::Result; use node_launchpad::{ app::App, config::configure_winsw, - utils::{initialize_logging, initialize_panic_handler, version}, + utils::{initialize_logging, initialize_panic_handler}, }; #[cfg(target_os = "windows")] use sn_node_manager::config::is_running_as_root; @@ -25,7 +25,7 @@ use std::{env, path::PathBuf}; use tokio::task::LocalSet; #[derive(Parser, Debug)] -#[command(author, version = version(), about)] +#[command(disable_version_flag = true)] pub struct Cli { #[arg( short, @@ -53,12 +53,48 @@ pub struct Cli { #[command(flatten)] pub(crate) peers: PeersArgs, + + /// Print the crate version. + #[clap(long)] + crate_version: bool, + + /// Print the package version. + #[clap(long)] + #[cfg(not(feature = "nightly"))] + package_version: bool, + + /// Print the version. + #[clap(long)] + version: bool, } async fn tokio_main() -> Result<()> { initialize_panic_handler()?; let args = Cli::parse(); + if args.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi Node Launchpad", + env!("CARGO_PKG_VERSION"), + None + ) + ); + return Ok(()); + } + + if args.crate_version { + println!("{}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if args.package_version { + println!("{}", sn_build_info::package_version()); + return Ok(()); + } + info!("Starting app with args: {args:?}"); let mut app = App::new( args.tick_rate, diff --git a/node-launchpad/src/utils.rs b/node-launchpad/src/utils.rs index ffb997246c..02b6b72fa1 100644 --- a/node-launchpad/src/utils.rs +++ b/node-launchpad/src/utils.rs @@ -14,15 +14,6 @@ use tracing_subscriber::{ self, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer, }; -const VERSION_MESSAGE: &str = concat!( - env!("CARGO_PKG_VERSION"), - "-", - env!("VERGEN_GIT_DESCRIBE"), - " (", - env!("VERGEN_BUILD_DATE"), - ")" -); - pub fn initialize_panic_handler() -> Result<()> { let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default() .panic_section(format!( @@ -132,18 +123,3 @@ macro_rules! trace_dbg { trace_dbg!(level: tracing::Level::DEBUG, $ex) }; } - -pub fn version() -> String { - let author = clap::crate_authors!(); - - let data_dir_path = get_launchpad_data_dir_path().unwrap().display().to_string(); - - format!( - "\ -{VERSION_MESSAGE} - -Authors: {author} - -Data directory: {data_dir_path}" - ) -} diff --git a/sn_auditor/Cargo.toml b/sn_auditor/Cargo.toml index cf78b8877d..f396596218 100644 --- a/sn_auditor/Cargo.toml +++ b/sn_auditor/Cargo.toml @@ -16,6 +16,7 @@ local-discovery = [ "sn_peers_acquisition/local-discovery", ] network-contacts = ["sn_peers_acquisition/network-contacts"] +nightly = [] open-metrics = ["sn_client/open-metrics"] websockets = ["sn_client/websockets"] svg-dag = ["graphviz-rust", "dag-collection"] @@ -31,9 +32,11 @@ graphviz-rust = { version = "0.9.0", optional = true } lazy_static = "1.4.0" serde = { version = "1.0.133", features = ["derive", "rc"] } serde_json = "1.0.108" +sn_build_info = { path = "../sn_build_info", version = "0.1.13" } sn_client = { path = "../sn_client", version = "0.110.1" } sn_logging = { path = "../sn_logging", version = "0.2.34" } sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.9" } tiny_http = { version = "0.12", features = ["ssl-rustls"] } tracing = { version = "~0.1.26" } tokio = { version = "1.32.0", features = [ diff --git a/sn_auditor/src/main.rs b/sn_auditor/src/main.rs index 2faf8551e1..1cbdaf2f58 100644 --- a/sn_auditor/src/main.rs +++ b/sn_auditor/src/main.rs @@ -19,6 +19,7 @@ use dag_db::SpendDagDb; use sn_client::Client; use sn_logging::{Level, LogBuilder, LogFormat, LogOutputDest}; use sn_peers_acquisition::PeersArgs; +use sn_protocol::version::IDENTIFY_PROTOCOL_STR; use std::collections::BTreeSet; use std::path::PathBuf; use tiny_http::{Response, Server}; @@ -27,7 +28,7 @@ use tiny_http::{Response, Server}; const BETA_REWARDS_BACKUP_INTERVAL_SECS: u64 = 20 * 60; #[derive(Parser)] -#[command(author, version, about, long_about = None)] +#[command(disable_version_flag = true)] struct Opt { #[command(flatten)] peers: PeersArgs, @@ -70,14 +71,59 @@ struct Opt { /// discord usernames of the beta participants #[clap(short = 'k', long, value_name = "hex_secret_key")] beta_encryption_key: Option, + + /// Print the crate version. + #[clap(long)] + pub crate_version: bool, + + /// Print the network protocol version. + #[clap(long)] + pub protocol_version: bool, + + /// Print the package version. + #[cfg(not(feature = "nightly"))] + #[clap(long)] + pub package_version: bool, + + /// Print version information. + #[clap(long)] + version: bool, } #[tokio::main] async fn main() -> Result<()> { let opt = Opt::parse(); + + if opt.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi Auditor", + env!("CARGO_PKG_VERSION"), + Some(&IDENTIFY_PROTOCOL_STR) + ) + ); + return Ok(()); + } + + if opt.crate_version { + println!("{}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if opt.package_version { + println!("{}", sn_build_info::package_version()); + return Ok(()); + } + + if opt.protocol_version { + println!("{}", *IDENTIFY_PROTOCOL_STR); + return Ok(()); + } + let log_builder = logging_init(opt.log_output_dest, opt.log_format)?; let _log_handles = log_builder.initialize()?; - let beta_participants = load_and_update_beta_participants(opt.beta_participants)?; let maybe_sk = if let Some(sk_str) = opt.beta_encryption_key { diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index a14eed90dd..51142a3f5d 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -9,9 +9,17 @@ name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" version = "0.1.13" +build = "build.rs" [build-dependencies] vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } +[features] +nightly = [] + [lints] workspace = true + +[dependencies] +chrono = "0.4" +tracing = { version = "~0.1.26" } diff --git a/sn_build_info/build.rs b/sn_build_info/build.rs index 392c55da4e..7ca807729d 100644 --- a/sn_build_info/build.rs +++ b/sn_build_info/build.rs @@ -5,6 +5,8 @@ // under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. +use std::fs; +use std::path::Path; use vergen::EmitBuilder; fn main() -> Result<(), Box> { @@ -18,5 +20,47 @@ fn main() -> Result<(), Box> { .git_describe(true, false, None) .emit()?; + let release_info_path = Path::new("../release-cycle-info"); + let contents = + fs::read_to_string(release_info_path).expect("Failed to read release-cycle-info"); + + let mut year = String::new(); + let mut month = String::new(); + let mut cycle = String::new(); + let mut counter = String::new(); + + for line in contents.lines() { + if line.starts_with("release-year:") { + year = line + .split(':') + .nth(1) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); + } else if line.starts_with("release-month:") { + month = line + .split(':') + .nth(1) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); + } else if line.starts_with("release-cycle:") { + cycle = line + .split(':') + .nth(1) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); + } else if line.starts_with("release-cycle-counter:") { + counter = line + .split(':') + .nth(1) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); + } + } + + println!("cargo:rustc-env=RELEASE_YEAR={year}"); + println!("cargo:rustc-env=RELEASE_MONTH={month}"); + println!("cargo:rustc-env=RELEASE_CYCLE={cycle}"); + println!("cargo:rustc-env=RELEASE_CYCLE_COUNTER={counter}"); + Ok(()) } diff --git a/sn_build_info/src/lib.rs b/sn_build_info/src/lib.rs index 6b858254ac..1e270f2a73 100644 --- a/sn_build_info/src/lib.rs +++ b/sn_build_info/src/lib.rs @@ -6,14 +6,15 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. +use chrono::Utc; +use tracing::debug; + /// Git information separated by slashes: ` / / ` pub const fn git_info() -> &'static str { concat!( - env!("VERGEN_GIT_SHA"), - " / ", env!("VERGEN_GIT_BRANCH"), " / ", - env!("VERGEN_GIT_DESCRIBE"), + env!("VERGEN_GIT_SHA"), " / ", env!("VERGEN_BUILD_DATE") ) @@ -33,3 +34,77 @@ pub const fn git_branch() -> &'static str { pub const fn git_sha() -> &'static str { env!("VERGEN_GIT_SHA") } + +/// Nightly version format: YYYY.MM.DD +pub fn nightly_version() -> String { + let now = Utc::now(); + now.format("%Y.%m.%d").to_string() +} + +/// Git information for nightly builds: ` / / ` +pub fn nightly_git_info() -> String { + format!("{} / {} / {}", nightly_version(), git_branch(), git_sha(),) +} + +pub fn package_version() -> String { + format!( + "{}.{}.{}.{}", + env!("RELEASE_YEAR"), + env!("RELEASE_MONTH"), + env!("RELEASE_CYCLE"), + env!("RELEASE_CYCLE_COUNTER") + ) +} + +pub fn full_version_info( + app_name: &str, + crate_version: &str, + protocol_version: Option<&str>, +) -> String { + let mut info = format!("{app_name} v{crate_version}"); + + if let Some(version) = protocol_version { + info.push_str(&format!("\nNetwork version: {version}")); + } + + info.push_str(&format!( + "\nPackage version: {}\nGit info: {}", + package_version(), + git_info() + )); + + info +} + +pub fn full_nightly_version_info(app_name: &str, protocol_version: Option<&str>) -> String { + let mut info = format!("{app_name} -- Nightly Release {}", nightly_version(),); + if let Some(version) = protocol_version { + info.push_str(&format!("\nNetwork version: {version}")); + } + info.push_str(&format!("\nGit info: {} / {}", git_branch(), git_sha(),)); + info +} + +pub fn version_string( + app_name: &str, + crate_version: &str, + protocol_version: Option<&str>, +) -> String { + if cfg!(feature = "nightly") { + full_nightly_version_info(app_name, protocol_version) + } else { + full_version_info(app_name, crate_version, protocol_version) + } +} + +pub fn log_version_info(crate_version: &str, protocol_version: &str) { + if cfg!(feature = "nightly") { + debug!("nightly build info: {}", nightly_git_info()); + debug!("network version: {protocol_version}"); + } else { + debug!("version: {crate_version}"); + debug!("network version: {protocol_version}"); + debug!("package version: {}", package_version()); + debug!("git info: {}", git_info()); + } +} diff --git a/sn_cli/Cargo.toml b/sn_cli/Cargo.toml index acdaccc9c8..66d29270c8 100644 --- a/sn_cli/Cargo.toml +++ b/sn_cli/Cargo.toml @@ -27,6 +27,7 @@ local-discovery = [ ] metrics = ["sn_logging/process-metrics"] network-contacts = ["sn_peers_acquisition/network-contacts"] +nightly = [] open-metrics = ["sn_client/open-metrics"] [dependencies] diff --git a/sn_cli/src/bin/main.rs b/sn_cli/src/bin/main.rs index 0ac03d458b..d4c8cac1d0 100644 --- a/sn_cli/src/bin/main.rs +++ b/sn_cli/src/bin/main.rs @@ -30,6 +30,7 @@ use sn_client::transfers::bls_secret_from_hex; use sn_client::{Client, ClientEvent, ClientEventsBroadcaster, ClientEventsReceiver}; #[cfg(feature = "metrics")] use sn_logging::{metrics::init_metrics, Level, LogBuilder, LogFormat}; +use sn_protocol::version::IDENTIFY_PROTOCOL_STR; use std::{io, path::PathBuf, time::Duration}; use tokio::{sync::broadcast::error::RecvError, task::JoinHandle}; @@ -39,6 +40,35 @@ const CLIENT_KEY: &str = "clientkey"; async fn main() -> Result<()> { color_eyre::install()?; let opt = Opt::parse(); + + if opt.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi CLI", + env!("CARGO_PKG_VERSION"), + Some(&IDENTIFY_PROTOCOL_STR) + ) + ); + return Ok(()); + } + + if opt.crate_version { + println!("{}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + if opt.protocol_version { + println!("{}", *IDENTIFY_PROTOCOL_STR); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if opt.package_version { + println!("{}", sn_build_info::package_version()); + return Ok(()); + } + let logging_targets = vec![ // TODO: Reset to nice and clean defaults once we have a better idea of what we want ("sn_networking".to_string(), Level::INFO), @@ -74,7 +104,7 @@ async fn main() -> Result<()> { let client_data_dir_path = get_client_data_dir_path()?; // Perform actions that do not require us connecting to the network and return early - if let SubCmd::Wallet(cmds) = &opt.cmd { + if let Some(SubCmd::Wallet(cmds)) = &opt.cmd { if let WalletCmds::Address { .. } | WalletCmds::Balance { .. } | WalletCmds::Create { .. } @@ -87,7 +117,7 @@ async fn main() -> Result<()> { } } - if let SubCmd::WatchOnlyWallet(cmds) = &opt.cmd { + if let Some(SubCmd::WatchOnlyWallet(cmds)) = &opt.cmd { if let WatchOnlyWalletCmds::Addresses | WatchOnlyWalletCmds::Balance { .. } | WatchOnlyWalletCmds::Deposit { .. } @@ -138,30 +168,32 @@ async fn main() -> Result<()> { }; progress_bar_handler.await?; - // default to verifying storage let should_verify_store = !opt.no_verify; // PowerShell seems having issue to showing the unwrapped error // Hence capture the result and print it out explicity. - let cmd_str = format!("{:?}", opt.cmd); let result = match opt.cmd { - SubCmd::Wallet(cmds) => { + Some(SubCmd::Wallet(cmds)) => { wallet_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await } - SubCmd::WatchOnlyWallet(cmds) => { + Some(SubCmd::WatchOnlyWallet(cmds)) => { wo_wallet_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await } - SubCmd::Files(cmds) => { + Some(SubCmd::Files(cmds)) => { files_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await } - SubCmd::Folders(cmds) => { + Some(SubCmd::Folders(cmds)) => { folders_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await } - SubCmd::Register(cmds) => { + Some(SubCmd::Register(cmds)) => { register_cmds(cmds, &client, &client_data_dir_path, should_verify_store).await } + None => { + println!("Use --help to see available commands"); + return Ok(()); + } }; - println!("Completed with {result:?} of execute {cmd_str:?}"); + println!("Completed with {result:?}"); Ok(()) } diff --git a/sn_cli/src/bin/subcommands/mod.rs b/sn_cli/src/bin/subcommands/mod.rs index 7a7ba11cad..575e90b3d3 100644 --- a/sn_cli/src/bin/subcommands/mod.rs +++ b/sn_cli/src/bin/subcommands/mod.rs @@ -21,7 +21,7 @@ use std::time::Duration; // Please do not remove the blank lines in these doc comments. // They are used for inserting line breaks when the help menu is rendered in the UI. #[derive(Parser)] -#[command(author, version, about, long_about = None)] +#[command(disable_version_flag = true)] pub(crate) struct Opt { /// Specify the logging output destination. /// @@ -49,7 +49,7 @@ pub(crate) struct Opt { /// Available sub commands. #[clap(subcommand)] - pub cmd: SubCmd, + pub cmd: Option, /// The maximum duration to wait for a connection to the network before timing out. #[clap(long = "timeout", global = true, value_parser = |t: &str| -> Result { Ok(t.parse().map(Duration::from_secs)?) })] @@ -60,6 +60,23 @@ pub(crate) struct Opt { /// This may increase operation speed, but offers no guarantees that operations were successful. #[clap(global = true, long = "no-verify", short = 'x')] pub no_verify: bool, + + /// Print the crate version. + #[clap(long)] + pub crate_version: bool, + + /// Print the network protocol version. + #[clap(long)] + pub protocol_version: bool, + + /// Print the package version. + #[clap(long)] + #[cfg(not(feature = "nightly"))] + pub package_version: bool, + + /// Print version information. + #[clap(long)] + pub version: bool, } #[derive(Subcommand, Debug)] diff --git a/sn_faucet/Cargo.toml b/sn_faucet/Cargo.toml index 3a203b3d8d..a8348c2aac 100644 --- a/sn_faucet/Cargo.toml +++ b/sn_faucet/Cargo.toml @@ -15,6 +15,7 @@ default = ["gifting"] distribution = ["base64", "bitcoin", "minreq"] gifting = [] initial-data = ["reqwest", "futures"] +nightly = [] [[bin]] path = "src/main.rs" diff --git a/sn_faucet/src/main.rs b/sn_faucet/src/main.rs index 833178a8f9..e01aecf426 100644 --- a/sn_faucet/src/main.rs +++ b/sn_faucet/src/main.rs @@ -22,15 +22,44 @@ use sn_client::{ }; use sn_logging::{Level, LogBuilder, LogOutputDest}; use sn_peers_acquisition::PeersArgs; +use sn_protocol::version::IDENTIFY_PROTOCOL_STR; use sn_transfers::{get_faucet_data_dir, HotWallet, MainPubkey, NanoTokens, Transfer}; use std::{path::PathBuf, time::Duration}; use tokio::{sync::broadcast::error::RecvError, task::JoinHandle}; -use tracing::{debug, error, info}; +use tracing::{error, info}; #[tokio::main] async fn main() -> Result<()> { let opt = Opt::parse(); + if opt.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi Test Faucet", + env!("CARGO_PKG_VERSION"), + Some(&IDENTIFY_PROTOCOL_STR.to_string()) + ) + ); + return Ok(()); + } + + if opt.crate_version { + println!("Crate version: {}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + if opt.protocol_version { + println!("Network version: {}", *IDENTIFY_PROTOCOL_STR); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if opt.package_version { + println!("Package version: {}", sn_build_info::package_version()); + return Ok(()); + } + let bootstrap_peers = opt.peers.get_peers().await?; let bootstrap_peers = if bootstrap_peers.is_empty() { // empty vec is returned if `local-discovery` flag is provided @@ -57,14 +86,8 @@ async fn main() -> Result<()> { log_builder.output_dest(opt.log_output_dest); let _log_handles = log_builder.initialize()?; - debug!( - "faucet built with git version: {}", - sn_build_info::git_info() - ); - println!( - "faucet built with git version: {}", - sn_build_info::git_info() - ); + sn_build_info::log_version_info(env!("CARGO_PKG_VERSION"), &IDENTIFY_PROTOCOL_STR); + info!("Instantiating a SAFE Test Faucet..."); let secret_key = bls::SecretKey::random(); @@ -147,7 +170,7 @@ fn spawn_connection_progress_bar(mut rx: ClientEventsReceiver) -> (ProgressBar, } #[derive(Parser)] -#[command(author, version, about, long_about = None)] +#[command(disable_version_flag = true)] struct Opt { /// Specify the logging output destination. /// @@ -167,7 +190,24 @@ struct Opt { /// Available sub commands. #[clap(subcommand)] - pub cmd: SubCmd, + pub cmd: Option, + + /// Print the crate version + #[clap(long)] + crate_version: bool, + + /// Print the protocol version + #[clap(long)] + protocol_version: bool, + + /// Print the package version + #[cfg(not(feature = "nightly"))] + #[clap(long)] + package_version: bool, + + /// Print version information. + #[clap(long)] + version: bool, } #[derive(Subcommand, Debug, Clone)] @@ -198,22 +238,29 @@ enum SubCmd { RestartServer, } -async fn faucet_cmds(cmds: SubCmd, client: &Client, funded_wallet: HotWallet) -> Result<()> { - match cmds { - SubCmd::ClaimGenesis => { - claim_genesis(client, funded_wallet).await?; - } - SubCmd::Send { amount, to } => { - send_tokens(client, funded_wallet, &amount, &to).await?; - } - SubCmd::Server => { - // shouldn't return except on error - run_faucet_server(client).await?; - } - SubCmd::RestartServer => { - // shouldn't return except on error - restart_faucet_server(client).await?; +async fn faucet_cmds( + cmds: Option, + client: &Client, + funded_wallet: HotWallet, +) -> Result<()> { + if let Some(cmds) = cmds { + match cmds { + SubCmd::ClaimGenesis => { + claim_genesis(client, funded_wallet).await?; + } + SubCmd::Send { amount, to } => { + send_tokens(client, funded_wallet, &amount, &to).await?; + } + SubCmd::Server => { + run_faucet_server(client).await?; + } + SubCmd::RestartServer => { + restart_faucet_server(client).await?; + } } + } else { + // Handle the case when no subcommand is provided + println!("No subcommand provided. Use --help for more information."); } Ok(()) } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index b5bf576e7c..99c6d3f273 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -15,14 +15,15 @@ path = "src/bin/safenode/main.rs" [features] default = ["metrics", "upnp", "reward-forward", "open-metrics"] +encrypt-records = ["sn_networking/encrypt-records"] local-discovery = ["sn_networking/local-discovery"] -otlp = ["sn_logging/otlp"] metrics = ["sn_logging/process-metrics"] network-contacts = ["sn_peers_acquisition/network-contacts"] +nightly = [] open-metrics = ["sn_networking/open-metrics", "prometheus-client"] -encrypt-records = ["sn_networking/encrypt-records"] -upnp = ["sn_networking/upnp"] +otlp = ["sn_logging/otlp"] reward-forward = ["sn_transfers/reward-forward"] +upnp = ["sn_networking/upnp"] [dependencies] assert_fs = "1.0.0" diff --git a/sn_node/src/bin/safenode/main.rs b/sn_node/src/bin/safenode/main.rs index cf30e04c65..c503504528 100644 --- a/sn_node/src/bin/safenode/main.rs +++ b/sn_node/src/bin/safenode/main.rs @@ -11,15 +11,17 @@ extern crate tracing; mod rpc_service; -use clap::Parser; -use eyre::{eyre, Result}; +use clap::{command, Parser}; +use color_eyre::{eyre::eyre, Result}; use libp2p::{identity::Keypair, PeerId}; #[cfg(feature = "metrics")] use sn_logging::metrics::init_metrics; use sn_logging::{Level, LogFormat, LogOutputDest, ReloadHandle}; use sn_node::{Marker, NodeBuilder, NodeEvent, NodeEventsReceiver}; use sn_peers_acquisition::PeersArgs; -use sn_protocol::{node::get_safenode_root_dir, node_rpc::NodeCtrl}; +use sn_protocol::{ + node::get_safenode_root_dir, node_rpc::NodeCtrl, version::IDENTIFY_PROTOCOL_STR, +}; use std::{ env, io::Write, @@ -65,7 +67,7 @@ pub fn parse_log_output(val: &str) -> Result { // Please do not remove the blank lines in these doc comments. // They are used for inserting line breaks when the help menu is rendered in the UI. #[derive(Parser, Debug)] -#[clap(name = "safenode cli", version = env!("CARGO_PKG_VERSION"))] +#[command(disable_version_flag = true)] struct Opt { /// Specify whether the node is operating from a home network and situated behind a NAT without port forwarding /// capabilities. Setting this to true, activates hole-punching to facilitate direct connections from other nodes. @@ -177,12 +179,57 @@ struct Opt { required_if_eq("metrics_server_port", "0") )] enable_metrics_server: bool, + + /// Print the crate version. + #[clap(long)] + crate_version: bool, + + /// Print the network protocol version. + #[clap(long)] + protocol_version: bool, + + /// Print the package version. + #[cfg(not(feature = "nightly"))] + #[clap(long)] + package_version: bool, + + /// Print version information. + #[clap(long)] + version: bool, } fn main() -> Result<()> { color_eyre::install()?; let opt = Opt::parse(); + if opt.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi Node", + env!("CARGO_PKG_VERSION"), + Some(&IDENTIFY_PROTOCOL_STR) + ) + ); + return Ok(()); + } + + if opt.crate_version { + println!("Crate version: {}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + if opt.protocol_version { + println!("Network version: {}", *IDENTIFY_PROTOCOL_STR); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if opt.package_version { + println!("Package version: {}", sn_build_info::package_version()); + return Ok(()); + } + let node_socket_addr = SocketAddr::new(opt.ip, opt.port); let (root_dir, keypair) = get_root_dir_and_keypair(&opt.root_dir)?; @@ -197,10 +244,8 @@ fn main() -> Result<()> { env!("CARGO_PKG_VERSION") ); info!("\n{}\n{}", msg, "=".repeat(msg.len())); - debug!( - "safenode built with git version: {}", - sn_build_info::git_info() - ); + + sn_build_info::log_version_info(env!("CARGO_PKG_VERSION"), &IDENTIFY_PROTOCOL_STR); info!("Node started with initial_peers {bootstrap_peers:?}"); diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 3e415a0d9c..6dfd50bd04 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -22,6 +22,7 @@ chaos = [] default = ["quic"] local-discovery = [] network-contacts = [] +nightly = [] open-metrics = [] otlp = [] quic = [] @@ -44,6 +45,7 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" +sn_build_info = { path = "../sn_build_info", version = "0.1.13" } sn_logging = { path = "../sn_logging", version = "0.2.34" } sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.1" } sn_protocol = { path = "../sn_protocol", version = "0.17.9" } diff --git a/sn_node_manager/src/bin/cli/main.rs b/sn_node_manager/src/bin/cli/main.rs index 7e89275279..b827e3f6a4 100644 --- a/sn_node_manager/src/bin/cli/main.rs +++ b/sn_node_manager/src/bin/cli/main.rs @@ -22,22 +22,35 @@ use tracing::Level; const DEFAULT_NODE_COUNT: u16 = 25; #[derive(Parser)] -#[command(author, version, about, long_about = None)] +#[command(disable_version_flag = true)] pub(crate) struct Cmd { /// Available sub commands. #[clap(subcommand)] - pub cmd: SubCmd, + pub cmd: Option, - #[clap(short, long, action = clap::ArgAction::Count, default_value_t = 2)] - verbose: u8, + /// Print the crate version. + #[clap(long)] + pub crate_version: bool, /// Output debug-level logging to stderr. #[clap(long, conflicts_with = "trace")] debug: bool, + /// Print the package version. + #[cfg(not(feature = "nightly"))] + #[clap(long)] + pub package_version: bool, + /// Output trace-level logging to stderr. #[clap(long, conflicts_with = "debug")] trace: bool, + + #[clap(short, long, action = clap::ArgAction::Count, default_value_t = 2)] + verbose: u8, + + /// Print version information. + #[clap(long)] + version: bool, } #[derive(Subcommand, Debug)] @@ -997,6 +1010,26 @@ pub enum LocalSubCmd { async fn main() -> Result<()> { color_eyre::install()?; let args = Cmd::parse(); + + if args.version { + println!( + "{}", + sn_build_info::version_string("Autonomi Node Manager", env!("CARGO_PKG_VERSION"), None) + ); + return Ok(()); + } + + if args.crate_version { + println!("{}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if args.package_version { + println!("{}", sn_build_info::package_version()); + return Ok(()); + } + let verbosity = VerbosityLevel::from(args.verbose); let _log_handle = if args.debug || args.trace { @@ -1015,7 +1048,7 @@ async fn main() -> Result<()> { tracing::info!("Executing cmd: {:?}", args.cmd); match args.cmd { - SubCmd::Add { + Some(SubCmd::Add { auto_restart, auto_set_nat_flags, count, @@ -1038,7 +1071,7 @@ async fn main() -> Result<()> { upnp, user, version, - } => { + }) => { let _ = cmd::node::add( auto_restart, auto_set_nat_flags, @@ -1067,7 +1100,7 @@ async fn main() -> Result<()> { .await?; Ok(()) } - SubCmd::Auditor(AuditorSubCmd::Add { + Some(SubCmd::Auditor(AuditorSubCmd::Add { beta_encryption_key, env_variables, log_dir_path, @@ -1075,7 +1108,7 @@ async fn main() -> Result<()> { peers, url, version, - }) => { + })) => { cmd::auditor::add( beta_encryption_key, env_variables, @@ -1088,32 +1121,32 @@ async fn main() -> Result<()> { ) .await } - SubCmd::Auditor(AuditorSubCmd::Start {}) => cmd::auditor::start(verbosity).await, - SubCmd::Auditor(AuditorSubCmd::Stop {}) => cmd::auditor::stop(verbosity).await, - SubCmd::Auditor(AuditorSubCmd::Upgrade { + Some(SubCmd::Auditor(AuditorSubCmd::Start {})) => cmd::auditor::start(verbosity).await, + Some(SubCmd::Auditor(AuditorSubCmd::Stop {})) => cmd::auditor::stop(verbosity).await, + Some(SubCmd::Auditor(AuditorSubCmd::Upgrade { do_not_start, force, env_variables, url, version, - }) => { + })) => { cmd::auditor::upgrade(do_not_start, force, env_variables, url, version, verbosity).await } - SubCmd::Balance { + Some(SubCmd::Balance { peer_id: peer_ids, service_name: service_names, - } => cmd::node::balance(peer_ids, service_names, verbosity).await, - SubCmd::Daemon(DaemonSubCmd::Add { + }) => cmd::node::balance(peer_ids, service_names, verbosity).await, + Some(SubCmd::Daemon(DaemonSubCmd::Add { address, env_variables, port, path, url, version, - }) => cmd::daemon::add(address, env_variables, port, path, url, version, verbosity).await, - SubCmd::Daemon(DaemonSubCmd::Start {}) => cmd::daemon::start(verbosity).await, - SubCmd::Daemon(DaemonSubCmd::Stop {}) => cmd::daemon::stop(verbosity).await, - SubCmd::Faucet(faucet_command) => match faucet_command { + })) => cmd::daemon::add(address, env_variables, port, path, url, version, verbosity).await, + Some(SubCmd::Daemon(DaemonSubCmd::Start {})) => cmd::daemon::start(verbosity).await, + Some(SubCmd::Daemon(DaemonSubCmd::Stop {})) => cmd::daemon::stop(verbosity).await, + Some(SubCmd::Faucet(faucet_command)) => match faucet_command { FaucetSubCmd::Add { env_variables, log_dir_path, @@ -1153,7 +1186,7 @@ async fn main() -> Result<()> { .await } }, - SubCmd::Local(local_command) => match local_command { + Some(SubCmd::Local(local_command)) => match local_command { LocalSubCmd::Join { build, count, @@ -1239,27 +1272,27 @@ async fn main() -> Result<()> { json, } => cmd::local::status(details, fail, json).await, }, - SubCmd::NatDetection(NatDetectionSubCmd::Run { + Some(SubCmd::NatDetection(NatDetectionSubCmd::Run { path, servers, url, version, - }) => { + })) => { cmd::nat_detection::run_nat_detection(servers, true, path, url, version, verbosity) .await } - SubCmd::Remove { + Some(SubCmd::Remove { keep_directories, peer_id: peer_ids, service_name: service_names, - } => cmd::node::remove(keep_directories, peer_ids, service_names, verbosity).await, - SubCmd::Reset { force } => cmd::node::reset(force, verbosity).await, - SubCmd::Start { + }) => cmd::node::remove(keep_directories, peer_ids, service_names, verbosity).await, + Some(SubCmd::Reset { force }) => cmd::node::reset(force, verbosity).await, + Some(SubCmd::Start { connection_timeout, interval, peer_id: peer_ids, service_name: service_names, - } => { + }) => { cmd::node::start( connection_timeout, interval, @@ -1269,16 +1302,16 @@ async fn main() -> Result<()> { ) .await } - SubCmd::Status { + Some(SubCmd::Status { details, fail, json, - } => cmd::node::status(details, fail, json).await, - SubCmd::Stop { + }) => cmd::node::status(details, fail, json).await, + Some(SubCmd::Stop { peer_id: peer_ids, service_name: service_names, - } => cmd::node::stop(peer_ids, service_names, verbosity).await, - SubCmd::Upgrade { + }) => cmd::node::stop(peer_ids, service_names, verbosity).await, + Some(SubCmd::Upgrade { connection_timeout, do_not_start, force, @@ -1289,7 +1322,7 @@ async fn main() -> Result<()> { env_variables: provided_env_variable, url, version, - } => { + }) => { cmd::node::upgrade( connection_timeout, do_not_start, @@ -1305,6 +1338,7 @@ async fn main() -> Result<()> { ) .await } + None => Ok(()), } } diff --git a/sn_node_manager/src/bin/daemon/main.rs b/sn_node_manager/src/bin/daemon/main.rs index 99925943be..5de75e2904 100644 --- a/sn_node_manager/src/bin/daemon/main.rs +++ b/sn_node_manager/src/bin/daemon/main.rs @@ -27,16 +27,26 @@ use tonic::{transport::Server, Code, Request, Response, Status}; use tracing::Level; #[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] +#[command(disable_version_flag = true)] struct Args { - /// Specify a port for the daemon to listen for RPCs. It defaults to 12500 if not set. - #[clap(long, default_value_t = DAEMON_DEFAULT_PORT)] - port: u16, /// Specify an Ipv4Addr for the daemon to listen on. This is useful if you want to manage the nodes remotely. /// /// If not set, the daemon listens locally for commands. #[clap(long, default_value_t = Ipv4Addr::new(127, 0, 0, 1))] address: Ipv4Addr, + /// Print the crate version. + #[clap(long)] + pub crate_version: bool, + /// Print the package version. + #[cfg(not(feature = "nightly"))] + #[clap(long)] + pub package_version: bool, + /// Specify a port for the daemon to listen for RPCs. It defaults to 12500 if not set. + #[clap(long, default_value_t = DAEMON_DEFAULT_PORT)] + port: u16, + /// Print version information. + #[clap(long)] + version: bool, } struct SafeNodeManagerDaemon {} @@ -128,12 +138,35 @@ impl SafeNodeManagerDaemon {} #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { + let args = Args::parse(); + + if args.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi Node Manager RPC Daemon", + env!("CARGO_PKG_VERSION"), + None + ) + ); + return Ok(()); + } + + if args.crate_version { + println!("{}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if args.package_version { + println!("{}", sn_build_info::package_version()); + return Ok(()); + } + let _log_handles = get_log_builder()?.initialize()?; println!("Starting safenodemand"); - let args = Args::parse(); let service = SafeNodeManagerDaemon {}; - // adding our service to our server. if let Err(err) = Server::builder() .add_service(SafeNodeManagerServer::new(service)) .serve(SocketAddr::new(IpAddr::V4(args.address), args.port)) diff --git a/sn_node_manager/src/helpers.rs b/sn_node_manager/src/helpers.rs index a841b54e6f..bd0ca2baae 100644 --- a/sn_node_manager/src/helpers.rs +++ b/sn_node_manager/src/helpers.rs @@ -276,7 +276,7 @@ pub async fn download_and_extract_release( } pub fn get_bin_version(bin_path: &PathBuf) -> Result { - trace!("Obtaining version of binary {bin_path:?}"); + debug!("Obtaining version of binary {bin_path:?}"); let mut cmd = Command::new(bin_path) .arg("--version") .stdout(Stdio::piped()) @@ -293,15 +293,28 @@ pub fn get_bin_version(bin_path: &PathBuf) -> Result { .read_to_string(&mut output) .inspect_err(|err| error!("Output contained non utf8 chars: {err:?}"))?; - let version = output - .split_whitespace() - .last() - .ok_or_else(|| { - error!("Failed to parse version"); - eyre!("Failed to parse version") - })? - .to_string(); - trace!("Obtained version of binary: {version}"); + // Extract the first line of the output + let first_line = output.lines().next().ok_or_else(|| { + error!("No output received from binary"); + eyre!("No output received from binary") + })?; + + let version = if let Some(v_pos) = first_line.find('v') { + // Stable binary: Extract version after 'v' + first_line[v_pos + 1..] + .split_whitespace() + .next() + .map(String::from) + } else { + // Nightly binary: Extract the date at the end of the first line + first_line.split_whitespace().last().map(String::from) + } + .ok_or_else(|| { + error!("Failed to parse version from output"); + eyre!("Failed to parse version from output") + })?; + + debug!("Obtained version of binary: {version}"); Ok(version) } diff --git a/sn_node_manager/src/local.rs b/sn_node_manager/src/local.rs index ec3a7ae34e..58d650cf67 100644 --- a/sn_node_manager/src/local.rs +++ b/sn_node_manager/src/local.rs @@ -62,11 +62,18 @@ impl Launcher for LocalSafeLauncher { fn launch_faucet(&self, genesis_multiaddr: &Multiaddr) -> Result { info!("Launching the faucet server..."); + debug!("Using genesis_multiaddr: {}", genesis_multiaddr.to_string()); let args = vec![ "--peer".to_string(), genesis_multiaddr.to_string(), "server".to_string(), ]; + + debug!( + "Using faucet binary: {}", + self.faucet_bin_path.to_string_lossy() + ); + debug!("Using args: {}", args.join(" ")); let child = Command::new(self.faucet_bin_path.clone()) .args(args) .stdout(Stdio::inherit()) @@ -369,8 +376,8 @@ pub async fn run_network( if !options.join { println!("Launching the faucet server..."); - let pid = launcher.launch_faucet(&bootstrap_peers[0])?; let version = get_bin_version(&options.faucet_bin_path)?; + let pid = launcher.launch_faucet(&bootstrap_peers[0])?; let faucet = FaucetServiceData { faucet_path: options.faucet_bin_path, local: true, diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index 5949d13ecd..055f1913b9 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -14,6 +14,9 @@ version = "0.6.29" name = "safenode_rpc_client" path = "src/main.rs" +[features] +nightly = [] + [dependencies] assert_fs = "1.0.0" async-trait = "0.1" @@ -23,6 +26,7 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version = "0.54.1", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } +sn_build_info = { path = "../sn_build_info", version = "0.1.13" } sn_client = { path = "../sn_client", version = "0.110.1" } sn_logging = { path = "../sn_logging", version = "0.2.34" } sn_node = { path = "../sn_node", version = "0.111.2" } diff --git a/sn_node_rpc_client/src/main.rs b/sn_node_rpc_client/src/main.rs index 7d019bff95..7930a3b712 100644 --- a/sn_node_rpc_client/src/main.rs +++ b/sn_node_rpc_client/src/main.rs @@ -9,26 +9,35 @@ use clap::Parser; use color_eyre::eyre::Result; - use sn_logging::{Level, LogBuilder}; use sn_node::NodeEvent; - use sn_protocol::safenode_proto::{safe_node_client::SafeNodeClient, NodeEventsRequest}; - use sn_service_management::rpc::{RpcActions, RpcClient}; - use std::{net::SocketAddr, time::Duration}; use tokio_stream::StreamExt; use tonic::Request; #[derive(Parser, Debug)] -#[clap(version, name = "safenode RPC client")] +#[command(disable_version_flag = true)] struct Opt { /// Address of the node's RPC service, e.g. 127.0.0.1:12001. addr: SocketAddr, /// subcommands #[clap(subcommand)] cmd: Cmd, + + /// Print the crate version. + #[clap(long)] + crate_version: bool, + + /// Print the package version. + #[cfg(not(feature = "nightly"))] + #[clap(long)] + package_version: bool, + + /// Print version information. + #[clap(long)] + version: bool, } #[derive(Parser, Debug)] @@ -90,6 +99,29 @@ async fn main() -> Result<()> { let _log_appender_guard = LogBuilder::new(logging_targets).initialize()?; let opt = Opt::parse(); + + if opt.version { + println!( + "{}", + sn_build_info::version_string( + "Autonomi Node RPC Client", + env!("CARGO_PKG_VERSION"), + None + ) + ); + } + + if opt.crate_version { + println!("Crate version: {}", env!("CARGO_PKG_VERSION")); + return Ok(()); + } + + #[cfg(not(feature = "nightly"))] + if opt.package_version { + println!("Package version: {}", sn_build_info::package_version()); + return Ok(()); + } + let addr = opt.addr; match opt.cmd {