//! This build script gets run during every build. Its purpose is to put //! together the files used for the `--help` and `--version`, which need to //! come in both coloured and non-coloured variants. The main usage text is //! contained in `src/usage.txt`; to make it easier to edit, backslashes (\) //! are used instead of the beginning of ANSI escape codes. //! //! The version string is quite complex: we want to show the version, //! current Git hash, and compilation date when building *debug* //! versions, but just the version for *release* versions. //! //! This script generates the string from the environment variables //! that Cargo adds (http://doc.crates.io/environment-variables.html) //! and runs `git` to get the SHA1 hash. It then writes the strings //! into files, which we can include during compilation. use std::env; use std::fs::File; use std::io::{self, Write}; use std::path::PathBuf; use datetime::{LocalDateTime, ISO}; use regex::Regex; /// The build script entry point. fn main() -> io::Result<()> { #![allow(clippy::write_with_newline)] let usage = include_str!("src/usage.txt"); let tagline = "dog \\1;32m●\\0m command-line DNS client"; let url = "https://dns.lookup.dog/"; let ver = if is_development_version() { format!("{}\nv{} [{}] built on {} \\1;31m(pre-release!)\\0m\n\\1;4;34m{}\\0m", tagline, cargo_version(), git_hash(), build_date(), url) } else { format!("{}\nv{}\n\\1;4;34m{}\\0m", tagline, cargo_version(), url) }; // We need to create these files in the Cargo output directory. let out = PathBuf::from(env::var("OUT_DIR").unwrap()); // The bits .txt files contain ANSI escape codes, ish. let control_code = Regex::new(r##"\\.+?m"##).unwrap(); // Pretty version text let mut f = File::create(&out.join("version.pretty.txt"))?; write!(f, "{}\n", ver.replace("\\", "\x1B["))?; // Bland version text let mut f = File::create(&out.join("version.bland.txt"))?; write!(f, "{}\n", control_code.replace_all(&ver, ""))?; // Pretty usage text let mut f = File::create(&out.join("usage.pretty.txt"))?; write!(f, "{}\n\n{}", tagline.replace("\\", "\x1B["), usage.replace("\\", "\x1B["))?; // Bland usage text let mut f = File::create(&out.join("usage.bland.txt"))?; write!(f, "{}\n\n{}", control_code.replace_all(tagline, ""), control_code.replace_all(usage, ""))?; Ok(()) } /// Retrieve the project’s current Git hash, as a string. fn git_hash() -> String { use std::process::Command; String::from_utf8_lossy( &Command::new("git") .args(&["rev-parse", "--short", "HEAD"]) .output().unwrap() .stdout).trim().to_string() } /// Whether we should show pre-release info in the version string. /// /// Both weekly releases and actual releases are --release releases, /// but actual releases will have a proper version number. fn is_development_version() -> bool { cargo_version().ends_with("-pre") || env::var("PROFILE").unwrap() == "debug" } /// Retrieves the [package] version in Cargo.toml as a string. fn cargo_version() -> String { env::var("CARGO_PKG_VERSION").unwrap() } /// Formats the current date as an ISO 8601 string. fn build_date() -> String { let now = LocalDateTime::now(); format!("{}", now.date().iso()) }