vergen_lib/entries.rs
1use crate::VergenKey;
2
3use anyhow::{Error, Result};
4use std::collections::BTreeMap;
5
6/// The map used to emit `cargo:rustc-env=NAME=VALUE` cargo instructions
7pub type CargoRustcEnvMap = BTreeMap<VergenKey, String>;
8/// The vector of strings used to emit `cargo:rerun-if-changed=VALUE` cargo instructions
9pub type CargoRerunIfChanged = Vec<String>;
10/// The vector of strings used to emit `cargo:warning=VALUE` cargo instructions
11pub type CargoWarning = Vec<String>;
12
13/// The default configuration to use when an issue has occured generating instructions
14#[derive(Debug)]
15pub struct DefaultConfig {
16 /// Should idempotent output be generated?
17 idempotent: bool,
18 /// Should we fail if an error occurs or output idempotent values on error?
19 fail_on_error: bool,
20 /// The error that caused us to try default instruction output.
21 error: Error,
22}
23
24impl DefaultConfig {
25 /// Create a new [`DefaultConfig`] struct with the given values.
26 #[must_use]
27 pub fn new(idempotent: bool, fail_on_error: bool, error: Error) -> Self {
28 Self {
29 idempotent,
30 fail_on_error,
31 error,
32 }
33 }
34 /// Should idempotent output be generated?
35 #[must_use]
36 pub fn idempotent(&self) -> &bool {
37 &self.idempotent
38 }
39 /// Should we fail if an error occurs or output idempotent values on error?
40 #[must_use]
41 pub fn fail_on_error(&self) -> &bool {
42 &self.fail_on_error
43 }
44 /// The error that caused us to try default instruction output.
45 #[must_use]
46 pub fn error(&self) -> &Error {
47 &self.error
48 }
49}
50
51/// This trait should be implemented to allow the `vergen` emitter
52/// to properly emit instructions for your feature.
53pub trait Add {
54 /// Try to add instructions entries to the various given arguments.
55 ///
56 /// * Write to the `cargo_rustc_env` map to emit 'cargo:rustc-env=NAME=VALUE' instructions.
57 /// * Write to the `cargo_rerun_if_changed` vector to emit 'cargo:rerun-if-changed=VALUE' instructions.
58 /// * Write to the `cargo_warning` vector to emit 'cargo:warning=VALUE' instructions.
59 ///
60 /// # Errors
61 ///
62 /// If an error occurs, the `vergen` emitter will use `add_default_entries` to generate output.
63 /// This assumes generating instructions may fail in some manner so a [`anyhow::Result`] is returned.
64 ///
65 fn add_map_entries(
66 &self,
67 idempotent: bool,
68 cargo_rustc_env: &mut CargoRustcEnvMap,
69 cargo_rerun_if_changed: &mut CargoRerunIfChanged,
70 cargo_warning: &mut CargoWarning,
71 ) -> Result<()>;
72
73 /// Based on the given configuration, emit either default idempotent output or generate a failue.
74 ///
75 /// * Write to the `cargo_rustc_env` map to emit 'cargo:rustc-env=NAME=VALUE' instructions.
76 /// * Write to the `cargo_rerun_if_changed` vector to emit 'cargo:rerun-if-changed=VALUE' instructions.
77 /// * Write to the `cargo_warning` vector to emit 'cargo:warning=VALUE' instructions.
78 ///
79 /// # Errors
80 ///
81 /// This assumes generating instructions may fail in some manner so a [`anyhow::Result`] is returned.
82 ///
83 fn add_default_entries(
84 &self,
85 config: &DefaultConfig,
86 cargo_rustc_env_map: &mut CargoRustcEnvMap,
87 cargo_rerun_if_changed: &mut CargoRerunIfChanged,
88 cargo_warning: &mut CargoWarning,
89 ) -> Result<()>;
90}
91
92/// This trait should be implemented to allow the `vergen` emitter to properly emit your custom instructions.
93///
94/// # Example
95/// ```
96/// # use anyhow::Result;
97/// # use std::collections::BTreeMap;
98/// # use vergen_lib::{AddCustomEntries, CargoRerunIfChanged, CargoWarning, DefaultConfig};
99/// #[derive(Default)]
100/// struct Custom {}
101///
102/// impl AddCustomEntries<&str, &str> for Custom {
103/// fn add_calculated_entries(
104/// &self,
105/// _idempotent: bool,
106/// cargo_rustc_env_map: &mut BTreeMap<&str, &str>,
107/// _cargo_rerun_if_changed: &mut CargoRerunIfChanged,
108/// cargo_warning: &mut CargoWarning,
109/// ) -> Result<()> {
110/// cargo_rustc_env_map.insert("vergen-cl", "custom_instruction");
111/// cargo_warning.push("custom instruction generated".to_string());
112/// Ok(())
113/// }
114///
115/// fn add_default_entries(
116/// &self,
117/// _config: &DefaultConfig,
118/// _cargo_rustc_env_map: &mut BTreeMap<&str, &str>,
119/// _cargo_rerun_if_changed: &mut CargoRerunIfChanged,
120/// _cargo_warning: &mut CargoWarning,
121/// ) -> Result<()> {
122/// Ok(())
123/// }
124/// }
125/// ```
126/// ## Then in [`build.rs`]
127///
128/// ```will_not_compile
129/// let build = BuildBuilder::all_build()?;
130/// let cargo = CargoBuilder::all_cargo()?;
131/// let gix = GixBuilder::all_git()?;
132/// let rustc = RustcBuilder::all_rustc()?;
133/// let si = SysinfoBuilder::all_sysinfo()?;
134/// Emitter::default()
135/// .add_instructions(&build)?
136/// .add_instructions(&cargo)?
137/// .add_instructions(&gix)?
138/// .add_instructions(&rustc)?
139/// .add_instructions(&si)?
140/// .add_custom_instructions(&Custom::default())?
141/// .emit()
142/// ```
143pub trait AddCustom<K: Into<String> + Ord, V: Into<String>> {
144 /// Try to add instructions entries to the various given arguments.
145 ///
146 /// * Write to the `cargo_rustc_env` map to emit 'cargo:rustc-env=NAME=VALUE' instructions.
147 /// * Write to the `cargo_rerun_if_changed` vector to emit 'cargo:rerun-if-changed=VALUE' instructions.
148 /// * Write to the `cargo_warning` vector to emit 'cargo:warning=VALUE' instructions.
149 ///
150 /// # Errors
151 ///
152 /// If an error occurs, the `vergen` emitter will use `add_default_entries` to generate output.
153 /// This assumes generating instructions may fail in some manner so a [`anyhow::Result`] is returned.
154 ///
155 fn add_calculated_entries(
156 &self,
157 idempotent: bool,
158 cargo_rustc_env_map: &mut BTreeMap<K, V>,
159 cargo_rerun_if_changed: &mut CargoRerunIfChanged,
160 cargo_warning: &mut CargoWarning,
161 ) -> Result<()>;
162
163 /// Based on the given configuration, emit either default idempotent output or generate a failue.
164 ///
165 /// * Write to the `cargo_rustc_env` map to emit 'cargo:rustc-env=NAME=VALUE' instructions.
166 /// * Write to the `cargo_rerun_if_changed` vector to emit 'cargo:rerun-if-changed=VALUE' instructions.
167 /// * Write to the `cargo_warning` vector to emit 'cargo:warning=VALUE' instructions.
168 ///
169 /// # Errors
170 ///
171 /// This assumes generating instructions may fail in some manner so a [`anyhow::Result`] is returned.
172 ///
173 fn add_default_entries(
174 &self,
175 config: &DefaultConfig,
176 cargo_rustc_env_map: &mut BTreeMap<K, V>,
177 cargo_rerun_if_changed: &mut CargoRerunIfChanged,
178 cargo_warning: &mut CargoWarning,
179 ) -> Result<()>;
180}
181
182#[doc(hidden)]
183pub(crate) mod test_gen {
184 use crate::{AddCustomEntries, CargoRerunIfChanged, CargoWarning};
185 use anyhow::{Result, anyhow};
186 use bon::Builder;
187 use std::collections::BTreeMap;
188
189 #[doc(hidden)]
190 #[derive(Builder, Clone, Copy, Debug, Default)]
191 pub struct CustomInsGen {
192 #[builder(default = false)]
193 fail: bool,
194 }
195
196 impl AddCustomEntries<&str, &str> for CustomInsGen {
197 fn add_calculated_entries(
198 &self,
199 idempotent: bool,
200 cargo_rustc_env_map: &mut BTreeMap<&str, &str>,
201 _cargo_rerun_if_changed: &mut CargoRerunIfChanged,
202 _cargo_warning: &mut CargoWarning,
203 ) -> Result<()> {
204 if self.fail {
205 Err(anyhow!("We have failed"))
206 } else {
207 if idempotent {
208 let _ = cargo_rustc_env_map.insert("test", "VERGEN_IDEMPOTENT_OUTPUT");
209 } else {
210 let _ = cargo_rustc_env_map.insert("test", "value");
211 }
212 Ok(())
213 }
214 }
215
216 fn add_default_entries(
217 &self,
218 config: &crate::DefaultConfig,
219 cargo_rustc_env_map: &mut BTreeMap<&str, &str>,
220 _cargo_rerun_if_changed: &mut CargoRerunIfChanged,
221 _cargo_warning: &mut CargoWarning,
222 ) -> Result<()> {
223 if *config.fail_on_error() {
224 let error = anyhow!(format!("{}", config.error()));
225 Err(error)
226 } else {
227 let _ = cargo_rustc_env_map.insert("test", "VERGEN_IDEMPOTENT_OUTPUT");
228 Ok(())
229 }
230 }
231 }
232}
233
234#[cfg(test)]
235mod test {
236 use super::DefaultConfig;
237 use anyhow::{Result, anyhow};
238 use std::io::Write;
239
240 #[test]
241 fn default_config_debug() -> Result<()> {
242 let config = DefaultConfig::new(true, true, anyhow!("blah"));
243 let mut buf = vec![];
244 write!(buf, "{config:?}")?;
245 assert!(!buf.is_empty());
246 Ok(())
247 }
248}