vergen_lib/utils.rs
1use crate::{CargoRustcEnvMap, CargoWarning, VergenKey, constants::VERGEN_IDEMPOTENT_DEFAULT};
2use std::env;
3
4/// Add a [`VergenKey`] entry as a default string into the [`CargoRustcEnvMap`].
5/// The value is either from an environment variable override or [`crate::constants::VERGEN_IDEMPOTENT_DEFAULT`]
6///
7/// # Example
8/// ```
9/// # use std::collections::BTreeMap;
10/// # use temp_env::with_var;
11/// # use vergen_lib::{add_default_map_entry, CargoRustcEnvMap, CargoWarning, VergenKey};
12/// with_var("VERGEN_BUILD_DATE", Some("my own date"), || {
13/// let mut map: CargoRustcEnvMap = BTreeMap::new();
14/// let mut warning: CargoWarning = vec![];
15#[cfg_attr(
16 feature = "build",
17 doc = r" add_default_map_entry(false, VergenKey::BuildDate, &mut map, &mut warning);
18assert_eq!(1, map.len());
19assert_eq!(1, warning.len());"
20)]
21/// });
22/// ```
23///
24pub fn add_default_map_entry(
25 idempotent: bool,
26 key: VergenKey,
27 map: &mut CargoRustcEnvMap,
28 warnings: &mut CargoWarning,
29) {
30 if let Ok(value) = env::var(key.name()) {
31 add_map_entry(key, value, map);
32 warnings.push(format!("{} overidden", key.name()));
33 } else if idempotent {
34 add_map_entry(key, VERGEN_IDEMPOTENT_DEFAULT, map);
35 warnings.push(format!("{} set to default", key.name()));
36 } else {
37 warnings.push(format!("Unable to set {}", key.name()));
38 }
39}
40
41/// Add a [`VergenKey`] entry as a string into the [`CargoRustcEnvMap`].
42///
43/// # Example
44/// ```
45/// # use std::collections::BTreeMap;
46/// # use vergen_lib::{add_map_entry, CargoRustcEnvMap, VergenKey};
47/// let mut map: CargoRustcEnvMap = BTreeMap::new();
48#[cfg_attr(
49 feature = "build",
50 doc = r#"add_map_entry(VergenKey::BuildDate, "test", &mut map);
51assert_eq!(1, map.len());"#
52)]
53/// ```
54///
55pub fn add_map_entry<T>(key: VergenKey, value: T, map: &mut CargoRustcEnvMap)
56where
57 T: Into<String>,
58{
59 let _old = map.insert(key, value.into());
60}
61
62/// Count the number of idempotent entries in a [`CargoRustcEnvMap`]
63///
64/// **NOTE** - This is mainly used for testing.
65///
66/// # Example
67///
68/// ```
69/// # use std::collections::BTreeMap;
70/// # use vergen_lib::{count_idempotent, CargoRustcEnvMap, VergenKey, constants::VERGEN_IDEMPOTENT_DEFAULT};
71/// #
72/// let mut map: CargoRustcEnvMap = BTreeMap::new();
73/// assert_eq!(0, count_idempotent(&map));
74#[cfg_attr(
75 feature = "build",
76 doc = r"_ = map.insert(VergenKey::BuildDate, VERGEN_IDEMPOTENT_DEFAULT.to_string());"
77)]
78#[cfg_attr(feature = "build", doc = r"assert_eq!(1, count_idempotent(&map));")]
79/// ```
80///
81#[must_use]
82pub fn count_idempotent(map: &CargoRustcEnvMap) -> usize {
83 map.values()
84 .filter(|x| *x == VERGEN_IDEMPOTENT_DEFAULT)
85 .count()
86}
87
88/// Read the git SHA and dirty flag from a `.cargo_vcs_info.json` file at
89/// `CARGO_MANIFEST_DIR`, if one is present.
90///
91/// This is the file [cargo includes in published crate tarballs][vcs-info], which
92/// lets the git SHA and dirty flag be recovered when building from a package where
93/// no `.git` directory exists (e.g. `cargo install` or a crates.io source).
94///
95/// Returns `Some((sha, dirty))` on success, or `None` if the file is absent or
96/// cannot be parsed. `dirty` defaults to `false` when the field is missing.
97///
98/// [vcs-info]: https://doc.rust-lang.org/cargo/commands/cargo-package.html#cargo_vcs_infojson-format
99#[cfg(feature = "vcs_info")]
100#[must_use]
101pub fn vcs_info() -> Option<(String, bool)> {
102 let manifest_dir = env::var_os("CARGO_MANIFEST_DIR")?;
103 let path = std::path::Path::new(&manifest_dir).join(".cargo_vcs_info.json");
104 let contents = std::fs::read_to_string(path).ok()?;
105 let json: serde_json::Value = serde_json::from_str(&contents).ok()?;
106 let git = json.get("git")?;
107 let sha = git.get("sha1")?.as_str()?.to_string();
108 let dirty = git
109 .get("dirty")
110 .and_then(serde_json::Value::as_bool)
111 .unwrap_or(false);
112 Some((sha, dirty))
113}