Add `--version` flag to binaries
Help users confirm all their radicle binary versions by providing the '--version' flag. Move the print_version function to the radicle crate for use by the node and remote-rad binaries, and remove tests to confirm the output format as it is deemed redundant. Co-Developed-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
parent
f24590afe2
commit
3119294367
|
|
@ -4,6 +4,7 @@ use std::{io::ErrorKind, iter, process};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
|
use radicle::version;
|
||||||
use radicle_cli::commands::*;
|
use radicle_cli::commands::*;
|
||||||
use radicle_cli::terminal as term;
|
use radicle_cli::terminal as term;
|
||||||
|
|
||||||
|
|
@ -63,20 +64,8 @@ fn parse_args() -> anyhow::Result<Command> {
|
||||||
Ok(command.unwrap_or_else(|| Command::Other(vec![])))
|
Ok(command.unwrap_or_else(|| Command::Other(vec![])))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print the Radicle CLI's version.
|
|
||||||
///
|
|
||||||
/// Third party applications use it to parse Radicle Cli's version.
|
|
||||||
fn print_version(mut w: impl std::io::Write) -> anyhow::Result<()> {
|
|
||||||
if VERSION.contains("-dev") {
|
|
||||||
writeln!(w, "{NAME} {VERSION}+{GIT_HEAD}")?;
|
|
||||||
} else {
|
|
||||||
writeln!(w, "{NAME} {VERSION} ({GIT_HEAD})")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_help() -> anyhow::Result<()> {
|
fn print_help() -> anyhow::Result<()> {
|
||||||
print_version(&mut io::stdout())?;
|
version::print(&mut io::stdout(), NAME, VERSION, GIT_HEAD)?;
|
||||||
println!("{DESCRIPTION}");
|
println!("{DESCRIPTION}");
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
|
|
@ -86,7 +75,8 @@ fn print_help() -> anyhow::Result<()> {
|
||||||
fn run(command: Command) -> Result<(), Option<anyhow::Error>> {
|
fn run(command: Command) -> Result<(), Option<anyhow::Error>> {
|
||||||
match command {
|
match command {
|
||||||
Command::Version => {
|
Command::Version => {
|
||||||
print_version(&mut io::stdout())?;
|
version::print(&mut io::stdout(), NAME, VERSION, GIT_HEAD)
|
||||||
|
.map_err(|e| Some(e.into()))?;
|
||||||
}
|
}
|
||||||
Command::Help => {
|
Command::Help => {
|
||||||
print_help()?;
|
print_help()?;
|
||||||
|
|
@ -349,84 +339,3 @@ fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyhow::Error>>
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn is_dot_separated_identifier(s: &str) -> bool {
|
|
||||||
let vs: Vec<_> = s.split('.').collect();
|
|
||||||
|
|
||||||
if Some(&"") == vs.first() || Some(&"") == vs.last() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for v in vs {
|
|
||||||
if v.is_empty() || v.contains(|c: char| !(c.is_ascii_alphanumeric() || c == '-')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions
|
|
||||||
fn is_semantic_version(s: &str) -> bool {
|
|
||||||
let (s, build) = s.split_once('+').unwrap_or((s, ""));
|
|
||||||
let (version_core, pre_release) = s.split_once('-').unwrap_or((s, ""));
|
|
||||||
|
|
||||||
let versions: Vec<_> = version_core.split('.').collect();
|
|
||||||
if versions.len() != 3 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for v in versions {
|
|
||||||
if v != "0" && (v.get(0..1) == Some("0") || v.parse::<u32>().is_err()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(pre_release.is_empty() || is_dot_separated_identifier(pre_release))
|
|
||||||
&& (build.is_empty() || is_dot_separated_identifier(build))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_semantic_version() {
|
|
||||||
assert!(is_semantic_version("0.0.1"));
|
|
||||||
assert!(is_semantic_version("1.0.0-alpha.1"));
|
|
||||||
assert!(is_semantic_version("1.0.0-0.3.7"));
|
|
||||||
assert!(is_semantic_version("1.0.0-x.7.z.92"));
|
|
||||||
assert!(is_semantic_version("1.0.0-alpha+001"));
|
|
||||||
assert!(is_semantic_version("1.0.0+20130313144700"));
|
|
||||||
assert!(is_semantic_version("1.0.0-beta+exp.sha.5114f85"));
|
|
||||||
assert!(is_semantic_version("1.0.0+21AF26D3----117B344092BD"));
|
|
||||||
|
|
||||||
assert!(!is_semantic_version(""), "empty");
|
|
||||||
assert!(!is_semantic_version("1.0"), "too little versions");
|
|
||||||
assert!(!is_semantic_version("1.0.01"), "no leading zeroes");
|
|
||||||
assert!(
|
|
||||||
!is_semantic_version("1.0.0-beta+exp..sha.5114f85"),
|
|
||||||
"dot separated value must be non-empty"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!is_semantic_version("1.0.0-beta+exp.sha.5114f85."),
|
|
||||||
"dot separated value must be non-empty"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!is_semantic_version("1.0.0-alpha+001+002"),
|
|
||||||
"only one '+' allowed"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensure version output is consistent for consumption by third parties.
|
|
||||||
#[test]
|
|
||||||
fn test_version() {
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
print_version(&mut buffer).unwrap();
|
|
||||||
let str = std::str::from_utf8(&buffer).unwrap();
|
|
||||||
|
|
||||||
let mut strs = str.split(' ');
|
|
||||||
assert_eq!("rad", strs.next().unwrap_or_default(), "program name");
|
|
||||||
assert!(
|
|
||||||
is_semantic_version(strs.next().unwrap_or_default()),
|
|
||||||
"semantic version"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::io;
|
||||||
use std::{env, fs, net, process};
|
use std::{env, fs, net, process};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
@ -8,11 +9,16 @@ use localtime::LocalDuration;
|
||||||
use radicle::node;
|
use radicle::node;
|
||||||
use radicle::prelude::Signer;
|
use radicle::prelude::Signer;
|
||||||
use radicle::profile;
|
use radicle::profile;
|
||||||
|
use radicle::version;
|
||||||
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
|
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
|
||||||
use radicle_node::prelude::{Address, NodeId};
|
use radicle_node::prelude::{Address, NodeId};
|
||||||
use radicle_node::Runtime;
|
use radicle_node::Runtime;
|
||||||
use radicle_node::{logger, service, signals};
|
use radicle_node::{logger, service, signals};
|
||||||
|
|
||||||
|
pub const NAME: &str = "radicle-node";
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
pub const GIT_HEAD: &str = env!("GIT_HEAD");
|
||||||
|
|
||||||
pub const HELP_MSG: &str = r#"
|
pub const HELP_MSG: &str = r#"
|
||||||
Usage
|
Usage
|
||||||
|
|
||||||
|
|
@ -28,6 +34,7 @@ Options
|
||||||
--force Force start even if an existing control socket is found
|
--force Force start even if an existing control socket is found
|
||||||
--help Print help
|
--help Print help
|
||||||
--listen <address> Address to listen on
|
--listen <address> Address to listen on
|
||||||
|
--version Print program version
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -95,6 +102,10 @@ impl Options {
|
||||||
println!("{HELP_MSG}");
|
println!("{HELP_MSG}");
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
Long("version") => {
|
||||||
|
version::print(&mut io::stdout(), NAME, VERSION, GIT_HEAD)?;
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
_ => anyhow::bail!(arg.unexpected()),
|
_ => anyhow::bail!(arg.unexpected()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ license = "MIT OR Apache-2.0"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
authors = ["Alexis Sellier <alexis@radicle.xyz>"]
|
authors = ["Alexis Sellier <alexis@radicle.xyz>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
build = "../build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,33 @@
|
||||||
|
use std::env;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
use radicle::version;
|
||||||
|
|
||||||
|
pub const NAME: &str = "git-remote-rad";
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
pub const GIT_HEAD: &str = env!("GIT_HEAD");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let mut args = env::args();
|
||||||
|
|
||||||
|
if args.nth(1).as_deref() == Some("--version") {
|
||||||
|
if let Err(e) = version::print(std::io::stdout(), NAME, VERSION, GIT_HEAD) {
|
||||||
|
eprintln!("fatal: {e}");
|
||||||
|
process::exit(1);
|
||||||
|
};
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
let profile = match radicle::Profile::load() {
|
let profile = match radicle::Profile::load() {
|
||||||
Ok(profile) => profile,
|
Ok(profile) => profile,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("fatal: couldn't load profile: {err}");
|
eprintln!("fatal: couldn't load profile: {err}");
|
||||||
std::process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = radicle_remote_helper::run(profile) {
|
if let Err(err) = radicle_remote_helper::run(profile) {
|
||||||
eprintln!("fatal: {err}");
|
eprintln!("fatal: {err}");
|
||||||
std::process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ pub mod sql;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
#[cfg(any(test, feature = "test"))]
|
#[cfg(any(test, feature = "test"))]
|
||||||
pub mod test;
|
pub mod test;
|
||||||
|
pub mod version;
|
||||||
|
|
||||||
pub use node::Node;
|
pub use node::Node;
|
||||||
pub use profile::Profile;
|
pub use profile::Profile;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
/// Print program version.
|
||||||
|
///
|
||||||
|
/// The program version follows [semantic versioning](https://semver.org).
|
||||||
|
///
|
||||||
|
/// Adjust with caution, third party applications parse the string for version info.
|
||||||
|
pub fn print(
|
||||||
|
mut w: impl std::io::Write,
|
||||||
|
name: &str,
|
||||||
|
version: &str,
|
||||||
|
git_head: &str,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
if version.ends_with("-dev") {
|
||||||
|
writeln!(w, "{name} {version}+{git_head}")?;
|
||||||
|
} else {
|
||||||
|
writeln!(w, "{name} {version} ({git_head})")?;
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_version() {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
print(&mut buffer, "rad", "1.2.3", "28b341d").unwrap();
|
||||||
|
let res = std::str::from_utf8(&buffer).unwrap();
|
||||||
|
assert_eq!("rad 1.2.3 (28b341d)\n", res);
|
||||||
|
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
print(&mut buffer, "rad", "1.2.3-dev", "28b341d").unwrap();
|
||||||
|
let res = std::str::from_utf8(&buffer).unwrap();
|
||||||
|
assert_eq!("rad 1.2.3-dev+28b341d\n", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue