linera_version/version_info/
mod.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4mod r#type;
5pub use r#type::*;
6
7pub static VERSION_INFO: VersionInfo = include!(env!("LINERA_VERSION_STATIC_PATH"));
8
9use crate::serde_pretty::Pretty;
10
11impl std::fmt::Display for VersionInfo {
12    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
13        write!(
14            formatter,
15            "\
16            Linera protocol: v{crate_version}\n\
17            RPC API hash: {rpc_hash}\n\
18            GraphQL API hash: {graphql_hash}\n\
19            WIT API hash: {wit_hash}\n\
20            Source code: {repo}/tree/{git_commit}{git_dirty}\n\
21            ",
22            repo = env!("CARGO_PKG_REPOSITORY"),
23            crate_version = self.crate_version,
24            rpc_hash = self.rpc_hash,
25            graphql_hash = self.graphql_hash,
26            wit_hash = self.wit_hash,
27            git_commit = self.git_commit,
28            git_dirty = if self.git_dirty { " (dirty)" } else { "" }
29        )
30    }
31}
32
33impl CrateVersion {
34    /// Whether this version is known to be API-compatible with `other`.
35    /// Note that this relation _is not_ symmetric.
36    pub fn is_compatible_with(&self, other: &CrateVersion) -> bool {
37        if self.major == 0 {
38            // Cargo conventions decree that if the major version is 0, minor versions
39            // denote backwards-incompatible changes and patch versions denote
40            // backwards-compatible changes.
41            self.minor == other.minor && self.patch <= other.patch
42        } else {
43            self.major == other.major && self.minor <= other.minor
44        }
45    }
46}
47
48async_graphql::scalar!(
49    CrateVersion,
50    "CrateVersion",
51    "The version of the Linera crates used in this build"
52);
53
54async_graphql::scalar!(
55    Pretty<CrateVersion, semver::Version>,
56    "CrateVersion",
57    "The version of the Linera crates used in this build"
58);
59
60impl VersionInfo {
61    /// Print a human-readable listing of the version information at `info` level.
62    pub fn log(&self) {
63        for line in format!("{self}").lines() {
64            tracing::info!("{line}");
65        }
66    }
67
68    /// A static string corresponding to `VersionInfo::default().to_string()` preceded by
69    /// a newline. The newline is meant for `clap` as in `#[command(version =
70    /// linera_version::VersionInfo::default_clap_str())]`
71    pub fn default_clap_str() -> &'static str {
72        use std::sync::LazyLock;
73        static STRING: LazyLock<String> = LazyLock::new(|| format!("\n{}", VersionInfo::default()));
74        STRING.as_str()
75    }
76
77    /// Whether this version is known to be (remote!) API-compatible with `other`.
78    /// Note that this relation _is not_ symmetric.
79    /// It also may give false negatives.
80    pub fn is_compatible_with(&self, other: &VersionInfo) -> bool {
81        self.api_hashes() == other.api_hashes()
82            || self
83                .crate_version
84                .value
85                .is_compatible_with(&other.crate_version.value)
86    }
87}
88
89impl Default for VersionInfo {
90    fn default() -> Self {
91        VERSION_INFO.clone()
92    }
93}