mitex_cli/
version.rs

1//! Version information
2
3use std::{fmt::Display, process::exit};
4
5use crate::build_info::VERSION;
6use clap::ValueEnum;
7
8/// Available version formats for `$program -VV`
9#[derive(ValueEnum, Debug, Clone)]
10#[value(rename_all = "kebab-case")]
11pub enum VersionFormat {
12    /// Don't show version information
13    None,
14    /// Shows short version information
15    Short,
16    /// Shows only features information
17    Features,
18    /// Shows full version information
19    Full,
20    /// Shows version information in JSON format
21    Json,
22    /// Shows version information in plain JSON format
23    JsonPlain,
24}
25
26impl Display for VersionFormat {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        f.write_str(self.to_possible_value().unwrap().get_name())
29    }
30}
31
32/// Version information
33#[derive(serde::Serialize, serde::Deserialize)]
34struct VersionInfo {
35    name: &'static str,
36    version: &'static str,
37    features: Vec<&'static str>,
38
39    program_semver: &'static str,
40    program_commit_hash: &'static str,
41    program_target_triple: &'static str,
42    program_opt_level: &'static str,
43    program_build_timestamp: &'static str,
44
45    rustc_semver: &'static str,
46    rustc_commit_hash: &'static str,
47    rustc_host_triple: &'static str,
48    rustc_channel: &'static str,
49    rustc_llvm_version: &'static str,
50}
51
52impl VersionInfo {
53    fn new() -> Self {
54        Self {
55            name: "mitex-cli",
56            version: VERSION,
57            features: env!("VERGEN_CARGO_FEATURES").split(',').collect::<Vec<_>>(),
58            program_semver: match env!("VERGEN_GIT_DESCRIBE") {
59                "VERGEN_IDEMPOTENT_OUTPUT" => "000000000000",
60                s => s,
61            },
62            program_commit_hash: match env!("VERGEN_GIT_SHA") {
63                "VERGEN_IDEMPOTENT_OUTPUT" => "0000000000000000000000000000000000000000",
64                s => s,
65            },
66            program_target_triple: env!("VERGEN_CARGO_TARGET_TRIPLE"),
67            program_opt_level: env!("VERGEN_CARGO_OPT_LEVEL"),
68            program_build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"),
69
70            rustc_semver: env!("VERGEN_RUSTC_SEMVER"),
71            rustc_commit_hash: env!("VERGEN_RUSTC_COMMIT_HASH"),
72            rustc_host_triple: env!("VERGEN_RUSTC_HOST_TRIPLE"),
73            rustc_channel: env!("VERGEN_RUSTC_CHANNEL"),
74            rustc_llvm_version: env!("VERGEN_RUSTC_LLVM_VERSION"),
75        }
76    }
77
78    fn program_build(&self) -> String {
79        format!(
80            "{} with opt_level({}) at {}",
81            self.program_target_triple, self.program_opt_level, self.program_build_timestamp
82        )
83    }
84
85    fn rustc_build(&self) -> String {
86        format!(
87            "{}-{} with LLVM {}",
88            self.rustc_host_triple, self.rustc_channel, self.rustc_llvm_version
89        )
90    }
91}
92
93impl Default for VersionInfo {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99/// Print version information and exit if `-VV` is present
100///
101/// # Panics
102/// panics if cannot print version information
103pub fn intercept_version(v: bool, f: VersionFormat) {
104    let f = match f {
105        VersionFormat::None if v => VersionFormat::Short,
106        VersionFormat::None => return,
107        _ => f,
108    };
109    let version_info = VersionInfo::new();
110    match f {
111        VersionFormat::Full => print_full_version(version_info),
112        VersionFormat::Features => println!("{}", version_info.features.join(",")),
113        VersionFormat::Json => {
114            println!("{}", serde_json::to_string_pretty(&version_info).unwrap())
115        }
116        VersionFormat::JsonPlain => println!("{}", serde_json::to_string(&version_info).unwrap()),
117        _ => print_short_version(version_info),
118    }
119    exit(0);
120}
121
122fn print_full_version(vi: VersionInfo) {
123    let program_semver = vi.program_semver;
124    let program_commit_hash = vi.program_commit_hash;
125    let program_build = vi.program_build();
126
127    let rustc_semver = vi.rustc_semver;
128    let rustc_commit_hash = vi.rustc_commit_hash;
129    let rustc_build = vi.rustc_build();
130
131    print_short_version(vi);
132    println!(
133        r##"
134program-ver: {program_semver}
135program-rev: {program_commit_hash}
136program-build: {program_build}
137
138rustc-ver: {rustc_semver}
139rustc-rev: {rustc_commit_hash}
140rustc-build: {rustc_build}"##
141    );
142}
143
144fn print_short_version(vi: VersionInfo) {
145    let name = vi.name;
146    let version = vi.version;
147    let features = vi
148        .features
149        .iter()
150        .copied()
151        .filter(|&s| s != "default" && !s.ends_with("_exporter"))
152        .collect::<Vec<_>>()
153        .join(" ");
154
155    println!(
156        r##"{name} version {version}
157features: {features}"##
158    );
159}