Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Add `--version` flag to binaries
Alexis Sellier committed 2 years ago
commit 3119294367d8382868babb9e02e5a2f5a4212590
parent f24590afe218b67793e90a8d2c1e77a64f7c8237
6 files changed +76 -97
modified radicle-cli/src/main.rs
@@ -4,6 +4,7 @@ use std::{io::ErrorKind, iter, process};

use anyhow::anyhow;

+
use radicle::version;
use radicle_cli::commands::*;
use radicle_cli::terminal as term;

@@ -63,20 +64,8 @@ fn parse_args() -> anyhow::Result<Command> {
    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<()> {
-
    print_version(&mut io::stdout())?;
+
    version::print(&mut io::stdout(), NAME, VERSION, GIT_HEAD)?;
    println!("{DESCRIPTION}");
    println!();

@@ -86,7 +75,8 @@ fn print_help() -> anyhow::Result<()> {
fn run(command: Command) -> Result<(), Option<anyhow::Error>> {
    match command {
        Command::Version => {
-
            print_version(&mut io::stdout())?;
+
            version::print(&mut io::stdout(), NAME, VERSION, GIT_HEAD)
+
                .map_err(|e| Some(e.into()))?;
        }
        Command::Help => {
            print_help()?;
@@ -349,84 +339,3 @@ fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyhow::Error>>
    }
    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"
-
        );
-
    }
-
}
modified radicle-node/src/main.rs
@@ -1,3 +1,4 @@
+
use std::io;
use std::{env, fs, net, process};

use anyhow::anyhow;
@@ -8,11 +9,16 @@ use localtime::LocalDuration;
use radicle::node;
use radicle::prelude::Signer;
use radicle::profile;
+
use radicle::version;
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
use radicle_node::prelude::{Address, NodeId};
use radicle_node::Runtime;
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#"
Usage

@@ -28,6 +34,7 @@ Options
    --force                             Force start even if an existing control socket is found
    --help                              Print help
    --listen             <address>      Address to listen on
+
    --version                           Print program version
"#;

#[derive(Debug)]
@@ -95,6 +102,10 @@ impl Options {
                    println!("{HELP_MSG}");
                    process::exit(0);
                }
+
                Long("version") => {
+
                    version::print(&mut io::stdout(), NAME, VERSION, GIT_HEAD)?;
+
                    process::exit(0);
+
                }
                _ => anyhow::bail!(arg.unexpected()),
            }
        }
modified radicle-remote-helper/Cargo.toml
@@ -4,6 +4,7 @@ license = "MIT OR Apache-2.0"
version = "0.2.0"
authors = ["Alexis Sellier <alexis@radicle.xyz>"]
edition = "2021"
+
build = "../build.rs"

[dependencies]
thiserror = "1"
modified radicle-remote-helper/src/git-remote-rad.rs
@@ -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() {
+
    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() {
        Ok(profile) => profile,
        Err(err) => {
            eprintln!("fatal: couldn't load profile: {err}");
-
            std::process::exit(1);
+
            process::exit(1);
        }
    };

    if let Err(err) = radicle_remote_helper::run(profile) {
        eprintln!("fatal: {err}");
-
        std::process::exit(1);
+
        process::exit(1);
    }
}
modified radicle/src/lib.rs
@@ -21,6 +21,7 @@ pub mod sql;
pub mod storage;
#[cfg(any(test, feature = "test"))]
pub mod test;
+
pub mod version;

pub use node::Node;
pub use profile::Profile;
added radicle/src/version.rs
@@ -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);
+
    }
+
}