chksum_build/
script.rs

1//! Build script required items.
2
3use std::env;
4use std::fmt::Write;
5use std::str::FromStr;
6
7use chrono::Local;
8
9use crate::cargo::Profile;
10use crate::error::Result;
11use crate::rust::{Channel, Toolchain};
12
13/// Wraps [`BuildScript::setup`] to return [`anyhow::Result`] instead of [`Result`].
14///
15/// # Errors
16///
17/// Returns an error when [`BuildScript::setup`] will do.
18///
19/// # Examples
20///
21/// ```rust,no_run
22/// use anyhow::Result;
23/// use chksum_build::{setup, BuildScript};
24///
25/// fn main() -> Result<()> {
26///     setup(&BuildScript::default())
27/// }
28/// ```
29pub fn setup(build_script: &BuildScript) -> anyhow::Result<()> {
30    build_script.setup()?;
31    Ok(())
32}
33
34/// Configuration for build script.
35#[allow(clippy::module_name_repetitions)]
36#[derive(Clone, Copy, Debug, Default)]
37pub struct BuildScript;
38
39impl BuildScript {
40    /// Emits `cargo:*` instructions that set enviroment variables or enable compile-time [`cfg`](https://doc.rust-lang.org/reference/conditional-compilation.html#forms-of-conditional-compilation) settings.
41    ///
42    /// Resources:
43    /// * [The Cargo Book: Environment variables Cargo sets for build scripts](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts),
44    /// * [The Cargo Book: Outputs of the Build Script](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script).
45    ///
46    /// # Errors
47    ///
48    /// Returns an error when environment variables couldn't be parsed.
49    ///
50    /// # Examples
51    ///
52    /// ```rust,no_run
53    /// use chksum_build::{BuildScript, Result};
54    ///
55    /// fn main() -> Result<()> {
56    ///     BuildScript::default().setup()
57    /// }
58    /// ```
59    pub fn setup(&self) -> Result<()> {
60        let mut stdout_buffer = String::new();
61
62        self.setup_build(&mut stdout_buffer)?;
63
64        self.setup_cargo(&mut stdout_buffer)?;
65
66        self.setup_rust(&mut stdout_buffer)?;
67
68        print!("{stdout_buffer}");
69
70        Ok(())
71    }
72
73    fn setup_build<T>(&self, stdout: &mut T) -> Result<()>
74    where
75        T: Write,
76    {
77        let datetime = Local::now().format("%Y-%m-%d %H:%M:%S");
78
79        writeln!(
80            stdout,
81            "cargo:rustc-env=CHKSUM_BUILD_INFO_BUILD_DATETIME=\"{datetime}\""
82        )?;
83
84        Ok(())
85    }
86
87    fn setup_cargo<T>(&self, stdout: &mut T) -> Result<()>
88    where
89        T: Write,
90    {
91        let profile = {
92            let profile = env::var("PROFILE")?;
93            Profile::from_str(&profile)?
94        };
95
96        writeln!(stdout, "cargo:rustc-cfg={profile}")?;
97        writeln!(stdout, "cargo:rustc-env=CHKSUM_BUILD_INFO_CARGO_PROFILE=\"{profile}\"")?;
98
99        Ok(())
100    }
101
102    fn setup_rust<T>(&self, stdout: &mut T) -> Result<()>
103    where
104        T: Write,
105    {
106        let toolchain = {
107            let toolchain = env::var("RUSTUP_TOOLCHAIN")?;
108            Toolchain::from_str(&toolchain)?
109        };
110        let channel = match toolchain.channel {
111            Channel::Version(_) => Channel::Stable,
112            channel => channel,
113        };
114
115        writeln!(stdout, "cargo:rustc-cfg={channel}")?;
116        writeln!(stdout, "cargo:rustc-env=CHKSUM_BUILD_INFO_RUST_CHANNEL=\"{channel}\"")?;
117
118        Ok(())
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_setup_build() {
128        let mut stdout = String::new();
129        assert!(BuildScript::default().setup_build(&mut stdout).is_ok());
130        assert_eq!(
131            stdout.to_string(),
132            format!(
133                "cargo:rustc-env=CHKSUM_BUILD_INFO_BUILD_DATETIME=\"{}\"\n",
134                Local::now().format("%Y-%m-%d %H:%M:%S")
135            )
136        );
137    }
138
139    #[test]
140    fn test_setup_cargo() {
141        env::set_var("PROFILE", "release");
142
143        let mut stdout = String::new();
144        assert!(BuildScript::default().setup_cargo(&mut stdout).is_ok());
145        assert_eq!(
146            stdout.to_string(),
147            "cargo:rustc-cfg=release\ncargo:rustc-env=CHKSUM_BUILD_INFO_CARGO_PROFILE=\"release\"\n"
148        );
149    }
150
151    #[test]
152    fn test_setup_rust() {
153        env::set_var("RUSTUP_TOOLCHAIN", "nightly-x86_64-unknown-linux-gnu");
154
155        let mut stdout = String::new();
156        assert!(BuildScript::default().setup_rust(&mut stdout).is_ok());
157        assert_eq!(
158            stdout.to_string(),
159            "cargo:rustc-cfg=nightly\ncargo:rustc-env=CHKSUM_BUILD_INFO_RUST_CHANNEL=\"nightly\"\n"
160        );
161    }
162}