diff --git a/README.md b/README.md index 707e6d1..5e4e771 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[shadow-rs][docsrs]: build-time information stored in your rust project. (binary, lib, cdylib and dylib) +[`shadow-rs`][docsrs]: Build-time information stored in your Rust project (binary, lib, cdylib, dylib). ========================================

The build.rs **is not rebuilt** every-time if the repository has been history builld. -> The recommended way is to run `cargo clean` first, then execute `cargo build`, or use a CI/CD pipeline tool to help -> you -> perform this operation. -> For more details, see https://github.com/baoyachi/shadow-rs/issues/95. +`shadow-rs` build information **is not always rebuilt** when you build a project. `shadow-rs` outputs several hints to Cargo in order to force rebuilds when required, but this does not always work. You can enforce up-to-date build information by running `cargo clean` before the build, or use a CI/CD pipeline tool. For more details, see . -# Full Examples +# Examples -* Check out the [example_shadow](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow) for a simple - demonstration of how `shadow-rs` might be used to provide build-time information at run-time. -* Check out the [example_shadow_hook](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow_hook) for a - simple demonstration of how `shadow-rs` might be used to provide build-time information at run-time and add a custom - hook. -* Built-in function:[examples](https://github.com/baoyachi/shadow-rs/tree/master/examples). +* Check out the [example_shadow](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow) for a simple demonstration of how `shadow-rs` might be used to provide build-time information at run-time. +* Check out the [example_shadow_hook](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow_hook) for a demonstration of how custom hooks can be used to add extra information to `shadow-rs`'s output. +* Check out the [`builtin_fn` example](https://github.com/baoyachi/shadow-rs/tree/master/examples/builtin_fn.rs) for a simple demonstration of the built-in functions that `shadow-rs` provides. -# Setup Guide +# Setup ### 1) Modify `Cargo.toml` fields - Modify your `Cargo.toml` like so: -```TOML +```toml [package] build = "build.rs" @@ -67,21 +57,18 @@ shadow-rs = "{latest version}" ``` ### 2) Create `build.rs` file - Now in the root of your project (same directory as `Cargo.toml`) add a file `build.rs`: -* with add custom `const` or `fn` - see:[example_shadow_hook](https://github.com/baoyachi/shadow-rs/blob/master/example_shadow_hook/build.rs) - ```rust fn main() -> shadow_rs::SdResult<()> { shadow_rs::new() } ``` -### 3) Integrate shadow +If you want to exclude some build constants, you can use [`new_deny`] instead of [`new`]. -In your rust file (e.g. `*.rs`): +### 3) Integrate Shadow +In your main Rust file (usually `main.rs` or `lib.rs`), add this: ```rust use shadow_rs::shadow; @@ -89,56 +76,41 @@ use shadow_rs::shadow; shadow!(build); ``` -**Notice that the `shadow!` macro is provided the identifier `build`. You can now use this identifier to access -build-time information.** +The `shadow!` macro uses the given identifier to create a module with that name. -### 4) Done. Use shadow. +### 4) Use Shadow Constants +You can now use the module defined with `shadow!` to access build-time information. ```rust -fn main() { - - //shadow-rs built in function +fn main(){ println!("debug:{}", shadow_rs::is_debug()); // check if this is a debug build. e.g 'true/false' println!("branch:{}", shadow_rs::branch()); // get current project branch. e.g 'master/develop' println!("tag:{}", shadow_rs::tag()); // get current project tag. e.g 'v1.3.5' println!("git_clean:{}", shadow_rs::git_clean()); // get current project clean. e.g 'true/false' println!("git_status_file:{}", shadow_rs::git_status_file()); // get current project statue file. e.g ' * examples/builtin_fn.rs (dirty)' - //shadow-rs built in const - println!("{}", build::VERSION); // the version (description binary detail information) - println!("{}", build::CLAP_LONG_VERSION); // usually used by clap crates version() (description binary detail information) - println!("{}", build::PKG_VERSION); // current package version. e.g. '1.3.15-beta2' - println!("{}", build::PKG_VERSION_MAJOR); //current package major version. e.g. '1' - println!("{}", build::PKG_VERSION_MINOR); //current package minor version. e.g. '3' - println!("{}", build::PKG_VERSION_PATCH); //current package minor version. e.g. '15' - println!("{}", build::PKG_VERSION_PRE); //current package minor version. e.g. 'beta2' - println!("{}", build::BRANCH); // the branch, e.g. 'master' - println!("{}", build::TAG); // the tag, e.g. 'v1.0.0' - println!("{}", build::SHORT_COMMIT); // short commit hash, e.g. '8405e28e' - println!("{}", build::COMMIT_HASH); // full commit hash, e.g. '8405e28e64080a09525a6cf1b07c22fcaf71a5c5' - println!("{}", build::COMMIT_DATE); // commit date, e.g. '2021-08-04 12:34:03 +00:00' - println!("{}", build::COMMIT_DATE_2822); // commit date, e.g. 'Thu, 24 Jun 2021 21:33:59 +0800' - println!("{}", build::COMMIT_DATE_3339); // commit date, e.g. '2021-06-24T21:33:59.972494+08:00' - println!("{}", build::COMMIT_AUTHOR); // commit author, e.g. 'baoyachi' - println!("{}", build::COMMIT_EMAIL); // commit email, e.g. 'example@gmail.com' - - println!("{}", build::BUILD_OS); // the OS that built the binary, e.g. 'macos-x86_64' - println!("{}", build::BUILD_TARGET); // the OS target that built the binary, e.g. 'x86_64-apple-darwin' - println!("{}", build::BUILD_TARGET_ARCH); // the OS target arch that built the binary, e.g. 'x86_64' - println!("{}", build::RUST_VERSION); // rustc version e.g. 'rustc 1.45.0 (5c1f21c3b 2020-07-13)' - println!("{}", build::RUST_CHANNEL); // rust toolchain e.g. 'stable-x86_64-apple-darwin (default)' - println!("{}", build::CARGO_VERSION); // cargo version e.g. 'cargo 1.45.0 (744bd1fbb 2020-06-15)' - println!("{}", build::CARGO_TREE); // e.g. the output of '$ cargo tree' - println!("{}", build::CARGO_MANIFEST_DIR); // e.g. /User/baoyachi/shadow-rs/ - - println!("{}", build::PROJECT_NAME); // your project name, e.g. 'shadow-rs' - // Time respects SOURCE_DATE_EPOCH environment variable - see below - println!("{}", build::BUILD_TIME); // time when start build occurred, e.g. '2020-08-16 14:50:25' - println!("{}", build::BUILD_TIME_2822); // time when start build occurred by rfc2822, e.g. 'Thu, 24 Jun 2021 21:33:59 +0800' - println!("{}", build::BUILD_TIME_3339); // time when start build occurred by rfc3339, e.g. '2021-06-24T21:33:59.972494+08:00' - println!("{}", build::BUILD_RUST_CHANNEL); // e.g. 'debug' - println!("{}", build::GIT_CLEAN); // e.g. 'true' - println!("{}", build::GIT_STATUS_FILE); // e.g. '* src/lib.rs (dirty)' + println!("{}", build::VERSION); //print version const + println!("{}", build::CLAP_LONG_VERSION); //print CLAP_LONG_VERSION const + println!("{}", build::BRANCH); //master + println!("{}", build::SHORT_COMMIT);//8405e28e + println!("{}", build::COMMIT_HASH);//8405e28e64080a09525a6cf1b07c22fcaf71a5c5 + println!("{}", build::COMMIT_DATE);//2021-08-04 12:34:03 +00:00 + println!("{}", build::COMMIT_AUTHOR);//baoyachi + println!("{}", build::COMMIT_EMAIL);//xxx@gmail.com + + println!("{}", build::BUILD_OS);//macos-x86_64 + println!("{}", build::RUST_VERSION);//rustc 1.45.0 (5c1f21c3b 2020-07-13) + println!("{}", build::RUST_CHANNEL);//stable-x86_64-apple-darwin (default) + println!("{}", build::CARGO_VERSION);//cargo 1.45.0 (744bd1fbb 2020-06-15) + println!("{}", build::PKG_VERSION);//0.3.13 + println!("{}", build::CARGO_TREE); //like command:cargo tree + println!("{}", build::CARGO_MANIFEST_DIR); // /User/baoyachi/shadow-rs/ | + + println!("{}", build::PROJECT_NAME);//shadow-rs + println!("{}", build::BUILD_TIME);//2020-08-16 14:50:25 + println!("{}", build::BUILD_RUST_CHANNEL);//debug + println!("{}", build::GIT_CLEAN);//false + println!("{}", build::GIT_STATUS_FILE);//* src/lib.rs (dirty) } ``` @@ -148,33 +120,28 @@ This tool includes the current time in the binary which would normally make it n However, it respects the [`SOURCE_DATE_EPOCH` variable](https://reproducible-builds.org/docs/source-date-epoch/) - if set to a Unix timestamp it will override the value of build time. -## Clap Example - -You also can use shadow-rs with [`clap`](https://github.com/baoyachi/shadow-rs/blob/master/example_shadow/src/main.rs). +## Clap +You can also use `shadow-rs` to provide information to command-line interface crates such as [`clap`](https://docs.rs/clap/latest/clap/). An example of this can be found in [`example_shadow`](https://github.com/baoyachi/shadow-rs/blob/master/example_shadow/src/main.rs). -## Constants and functions in table +## List of Constants and Functions -#### shadow-rs built in function. +#### Functions -* how to use 👉 : [examples](https://github.com/baoyachi/shadow-rs/tree/master/examples) - -| function | desc | +| Function | Description | | ------ | ------ | -| is_debug() | check if this is a debug build.e.g.'true/false' | -| branch() | get current project branch.e.g.'master/develop' | -| tag() | get current project tag.e.g.'v1.3.5' | -| git_clean() | get current project clean. e.g 'true/false' | -| git_status_file() | get current project statue file. e.g ' * examples/builtin_fn.rs (dirty)' | - -#### shadow-rs support build const,function. +| `is_debug()` | `true` if this is a build with debug assertions. | +| `branch()` | Git branch at build time. | +| `tag()` | Current Git tag at build time. | +| `git_clean()` | Whether Git working tree was clean at build time. | +| `git_status_file()` | `git status`-like output, e.g. ` * examples/builtin_fn.rs (dirty)` | -* how to use 👉 : [shadow_example](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow) +#### Constants -| const/fn | example | +| Constant | Example | | ------ | ------ | -| VERSION | support mini version information.It's use easy. | -| CLAP_LONG_VERSION | support mini version information for clap.It's use easy. | -| BRANCH | master/develop | +| VERSION | 3.4.5 | +| CLAP_LONG_VERSION | (A multi-line string containing branch, commit hash, build time, Rust version and toolchain channel) | +| BRANCH | master | | TAG | v1.0.0 | | SHORT_COMMIT | 8405e28e | | COMMIT_HASH | 8405e28e64080a09525a6cf1b07c22fcaf71a5c5 | @@ -190,14 +157,14 @@ You also can use shadow-rs with [`clap`](https://github.com/baoyachi/shadow-rs/b | RUST_CHANNEL | stable-x86_64-apple-darwin (default) | | CARGO_VERSION | cargo 1.45.0 (744bd1fbb 2020-06-15) | | PKG_VERSION | 0.3.13 | -| CARGO_TREE | cargo tree | +| CARGO_TREE | (Output of `cargo tree`) | | CARGO_MANIFEST_DIR | /User/baoyachi/shadow-rs/ | | PROJECT_NAME | shadow-rs | | BUILD_TIME | 2021-06-24 21:33:59 | | BUILD_TIME_2822 | Thu, 24 Jun 2021 21:33:59 +0800 | | BUILD_TIME_3339 | 2021-06-24T15:53:55+08:00 | -| BUILD_RUST_CHANNEL | debug/release | -| GIT_CLEAN | true/false | +| BUILD_RUST_CHANNEL | release | +| GIT_CLEAN | true | | GIT_STATUS_FILE | * src/lib.rs (dirty) | If you have any questions, please create an [issue](https://github.com/baoyachi/shadow-rs/issues/new) so we may improve diff --git a/src/build.rs b/src/build.rs index 8cb39e6..12365d8 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,15 +1,20 @@ use std::collections::BTreeMap; +/// `shadow-rs` build constant identifiers. pub type ShadowConst = &'static str; pub trait ShadowGen { fn gen_const(&self) -> BTreeMap; } +/// Serialized values for build constants. #[derive(Debug, Clone)] pub struct ConstVal { + /// User-facing documentation for the build constant. pub desc: String, + /// Serialized value of the build constant. pub v: String, + /// Type of the build constant. pub t: ConstType, } @@ -31,10 +36,14 @@ impl ConstVal { } } +/// Supported types of build constants. #[derive(Debug, Clone)] pub enum ConstType { + /// [`Option<&str>`](`Option`). OptStr, + /// [`&str`](`str`). Str, + /// [`bool`]. Bool, } diff --git a/src/ci.rs b/src/ci.rs index e372267..518b864 100644 --- a/src/ci.rs +++ b/src/ci.rs @@ -1,9 +1,9 @@ +/// [`CiType`] holds the types of CI environment that `shadow-rs` can detect. #[derive(Debug)] pub enum CiType { Github, Gitlab, - // Jenkins, - // Travis, + // TODO: Recognize other CI types, especially Travis and Jenkins None, } @@ -18,8 +18,6 @@ impl ToString for CiType { match self { CiType::Github => "github".into(), CiType::Gitlab => "gitlab".into(), - // CIType::Jenkins => "jenkins".into(), - // CIType::Travis => "travis".into(), _ => "none".into(), } } diff --git a/src/date_time.rs b/src/date_time.rs index 337f974..0d72857 100644 --- a/src/date_time.rs +++ b/src/date_time.rs @@ -24,7 +24,6 @@ pub fn now_date_time() -> DateTime { .expect("Input SOURCE_DATE_EPOCH could not be parsed") .parse::() .expect("Input SOURCE_DATE_EPOCH could not be cast to a number"); - // BuildTime::Utc(Utc.timestamp(epoch, 0)) DateTime::Utc(OffsetDateTime::from_unix_timestamp(epoch).unwrap()) } } @@ -50,9 +49,9 @@ impl DateTime { #[cfg(not(feature = "tzdb"))] pub fn local_now() -> Result> { - // Warning: Attempt to create a new OffsetDateTime with the current date and time in the local offset. If the offset cannot be determined, an error is returned. - // At present, using it on MacOS return error. Use it with careful. - // Suggestion use feature tzdb crate exposed function at below. + // Warning: This attempts to create a new OffsetDateTime with the current date and time in the local offset, which may fail. + // Currently, it always fails on MacOS. + // This issue does not exist with the "tzdb" feature (see below), which should be used instead. OffsetDateTime::now_local() .map(DateTime::Local) .map_err(|e| e.into()) diff --git a/src/env.rs b/src/env.rs index be27b89..6ef99c7 100644 --- a/src/env.rs +++ b/src/env.rs @@ -13,23 +13,70 @@ pub struct SystemEnv { map: BTreeMap, } +const BUILD_OS_DOC: &str = r#" +Operating system and architecture on which the project was build. +The format of this variable is always `os-arch`, +where `os` is the operating system name as returned by [`std::env::consts::OS`], +and `arch` is the computer architecture as returned by [`std::env::consts::ARCH`]."#; pub const BUILD_OS: ShadowConst = "BUILD_OS"; + +const RUST_VERSION_DOC: &str = r#" +Rust version with which the project was built. +The version always uses the canonical Rust version format, +and is therefore identical to the output of the build toolchain's `rustc --version`."#; pub const RUST_VERSION: ShadowConst = "RUST_VERSION"; + +const RUST_CHANNEL_DOC: &str = r#" +The [Rustup toolchain](https://rust-lang.github.io/rustup/concepts/toolchains.html) with which the project was built. +Note that as per Rustup toolchain format, this variable may or may not contain host and date information, +but it will always contain [channel](https://rust-lang.github.io/rustup/concepts/channels.html) information (stable, beta or nightly)."#; pub const RUST_CHANNEL: ShadowConst = "RUST_CHANNEL"; + +const CARGO_VERSION_DOC: &str = r#" +The cargo version which which the project was built, as output by `cargo --version`."#; pub const CARGO_VERSION: ShadowConst = "CARGO_VERSION"; + +const CARGO_TREE_DOC: &str = r#" +The dependency tree of the project, as output by `cargo tree`. +Note that this variable may contain local file system paths for path dependencies, and may therefore contain sensitive information and not be reproducible."#; pub const CARGO_TREE: ShadowConst = "CARGO_TREE"; +const BUILD_TARGET_DOC: &str = r#" +The [target](https://doc.rust-lang.org/rustc/targets/index.html) for this build. +This is possibly distinct from the host target during build, in which case this project build was created via cross-compilation."#; pub const BUILD_TARGET: ShadowConst = "BUILD_TARGET"; + +const BUILD_TARGET_ARCH_DOC: &str = r#" +The architecture of the target for this build. This is the "architecture" part of the [`BUILD_TARGET`] constant."#; pub const BUILD_TARGET_ARCH: ShadowConst = "BUILD_TARGET_ARCH"; +const CARGO_MANIFEST_DIR_DOC: &str = r#" +The directory of the Cargo.toml manifest file of the project during build. +Note that this variable will contain a full local file system path, and will therefore contain sensitive information and not be reproducible."#; pub const CARGO_MANIFEST_DIR: ShadowConst = "CARGO_MANIFEST_DIR"; -// const CARGO_METADATA: ShadowConst = "CARGO_METADATA"; +const PKG_VERSION_DOC: &str = r#" +The project's full version string, as determined by the Cargo.toml manifest."#; pub const PKG_VERSION: ShadowConst = "PKG_VERSION"; + +const PKG_DESCRIPTION_DOC: &str = r#" +The project's description, as determined by the Cargo.toml manifest."#; pub const PKG_DESCRIPTION: ShadowConst = "PKG_DESCRIPTION"; + +const PKG_VERSION_MAJOR_DOC: &str = r#" +The project's semver major version, as determined by the Cargo.toml manifest."#; pub const PKG_VERSION_MAJOR: ShadowConst = "PKG_VERSION_MAJOR"; + +const PKG_VERSION_MINOR_DOC: &str = r#" +The project's semver minor version, as determined by the Cargo.toml manifest."#; pub const PKG_VERSION_MINOR: ShadowConst = "PKG_VERSION_MINOR"; + +const PKG_VERSION_PATCH_DOC: &str = r#" +The project's semver patch version, as determined by the Cargo.toml manifest."#; pub const PKG_VERSION_PATCH: ShadowConst = "PKG_VERSION_PATCH"; + +const PKG_VERSION_PRE_DOC: &str = r#" +The project's semver pre-release version, as determined by the Cargo.toml manifest."#; pub const PKG_VERSION_PRE: ShadowConst = "PKG_VERSION_PRE"; impl SystemEnv { @@ -196,80 +243,54 @@ mod dep_source_replace { } } +/// Create all `shadow-rs` constants which are determined by the build environment. +/// The data for these constants is provided by the `std_env` argument. pub fn new_system_env(std_env: &BTreeMap) -> BTreeMap { let mut env = SystemEnv::default(); env.map.insert( BUILD_OS, ConstVal { - desc: "display build system os".to_string(), + desc: BUILD_OS_DOC.to_string(), v: format!("{}-{}", env::consts::OS, env::consts::ARCH), t: ConstType::Str, }, ); - env.map.insert( - RUST_CHANNEL, - ConstVal::new("display build system rust channel"), - ); - env.map.insert( - RUST_VERSION, - ConstVal::new("display build system rust version"), - ); - env.map.insert( - CARGO_VERSION, - ConstVal::new("display build system cargo version"), - ); + env.map + .insert(RUST_CHANNEL, ConstVal::new(RUST_CHANNEL_DOC)); + env.map + .insert(RUST_VERSION, ConstVal::new(RUST_VERSION_DOC)); + env.map + .insert(CARGO_VERSION, ConstVal::new(CARGO_VERSION_DOC)); - env.map.insert( - CARGO_TREE, - ConstVal::new("display build cargo dependencies.It's used by rust version 1.44.0"), - ); + env.map.insert(CARGO_TREE, ConstVal::new(CARGO_TREE_DOC)); // env.map.insert( // CARGO_METADATA, // ConstVal::new("display build cargo dependencies by metadata.It's use by exec command `cargo metadata`"), // ); - env.map.insert( - BUILD_TARGET, - ConstVal::new("display build current project target"), - ); + env.map + .insert(BUILD_TARGET, ConstVal::new(BUILD_TARGET_DOC)); - env.map.insert( - BUILD_TARGET_ARCH, - ConstVal::new("display build current project version arch"), - ); + env.map + .insert(BUILD_TARGET_ARCH, ConstVal::new(BUILD_TARGET_ARCH_DOC)); - env.map.insert( - PKG_VERSION, - ConstVal::new("display build current project version"), - ); + env.map.insert(PKG_VERSION, ConstVal::new(PKG_VERSION_DOC)); - env.map.insert( - PKG_DESCRIPTION, - ConstVal::new("display build current project description"), - ); + env.map + .insert(PKG_DESCRIPTION, ConstVal::new(PKG_DESCRIPTION_DOC)); - env.map.insert( - PKG_VERSION_MAJOR, - ConstVal::new("display build current project major version"), - ); - env.map.insert( - PKG_VERSION_MINOR, - ConstVal::new("display build current project minor version"), - ); - env.map.insert( - PKG_VERSION_PATCH, - ConstVal::new("display build current project patch version"), - ); - env.map.insert( - PKG_VERSION_PRE, - ConstVal::new("display build current project preview version"), - ); - env.map.insert( - CARGO_MANIFEST_DIR, - ConstVal::new("display build current build cargo manifest dir"), - ); + env.map + .insert(PKG_VERSION_MAJOR, ConstVal::new(PKG_VERSION_MAJOR_DOC)); + env.map + .insert(PKG_VERSION_MINOR, ConstVal::new(PKG_VERSION_MINOR_DOC)); + env.map + .insert(PKG_VERSION_PATCH, ConstVal::new(PKG_VERSION_PATCH_DOC)); + env.map + .insert(PKG_VERSION_PRE, ConstVal::new(PKG_VERSION_PRE_DOC)); + env.map + .insert(CARGO_MANIFEST_DIR, ConstVal::new(CARGO_MANIFEST_DIR_DOC)); if let Err(e) = env.init(std_env) { println!("{e}"); @@ -282,10 +303,25 @@ pub struct Project { map: BTreeMap, } +const PROJECT_NAME_DOC: &str = r#" +The project name, as determined by the Cargo.toml manifest."#; const PROJECT_NAME: ShadowConst = "PROJECT_NAME"; + +const BUILD_TIME_DOC: &str = r#" +The project build time, formatted in modified ISO 8601 format (`YYYY-MM-DD HH-MM ±hh-mm` where hh-mm is the offset from UTC)."#; const BUILD_TIME: ShadowConst = "BUILD_TIME"; + +const BUILD_TIME_2822_DOC: &str = r#" +The project build time, formatted according to [RFC 2822](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) (e.g. HTTP Headers)."#; const BUILD_TIME_2822: ShadowConst = "BUILD_TIME_2822"; + +const BUILD_TIME_3339_DOC: &str = r#" +The project build time, formatted according to [RFC 3339 and ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6)."#; const BUILD_TIME_3339: ShadowConst = "BUILD_TIME_3339"; + +const BUILD_RUST_CHANNEL_DOC: &str = r#" +The debug configuration with which the project was built. +Note that this is not the Rust channel, but either `debug` or `release`, depending on whether debug assertions were enabled in the build or not. "#; const BUILD_RUST_CHANNEL: ShadowConst = "BUILD_RUST_CHANNEL"; pub fn build_time(project: &mut Project) { @@ -294,7 +330,7 @@ pub fn build_time(project: &mut Project) { project.map.insert( BUILD_TIME, ConstVal { - desc: "display project build time".to_string(), + desc: BUILD_TIME_DOC.to_string(), v: time.human_format(), t: ConstType::Str, }, @@ -302,7 +338,7 @@ pub fn build_time(project: &mut Project) { project.map.insert( BUILD_TIME_2822, ConstVal { - desc: "display project build time by rfc2822".to_string(), + desc: BUILD_TIME_2822_DOC.to_string(), v: time.to_rfc2822(), t: ConstType::Str, }, @@ -311,7 +347,7 @@ pub fn build_time(project: &mut Project) { project.map.insert( BUILD_TIME_3339, ConstVal { - desc: "display project build time by rfc3399".to_string(), + desc: BUILD_TIME_3339_DOC.to_string(), v: time.to_rfc3339(), t: ConstType::Str, }, @@ -324,14 +360,14 @@ pub fn new_project(std_env: &BTreeMap) -> BTreeMap = Result; +/// `shadow-rs` build process errors. +/// This type wraps multiple kinds of underlying errors that can occur downstream of `shadow-rs`, such as [`std::io::Error`]. #[derive(Debug)] pub enum ShadowError { String(String), diff --git a/src/gen_const.rs b/src/gen_const.rs index b18b24f..4491bac 100644 --- a/src/gen_const.rs +++ b/src/gen_const.rs @@ -1,12 +1,16 @@ macro_rules! gen_const { - ($fn_name:ident,$fn_desc:expr,$fn_body:expr) => { + ($fn_name:ident, $fn_body:expr) => { pub fn $fn_name() -> String { - format!("{}\n{}", $fn_desc, $fn_body) + $fn_body.to_string() } }; } -const VERSION_BRANCH_CONST: &str = r##"#[allow(dead_code)] +const VERSION_BRANCH_CONST: &str = r##" +/// A long version string describing the project. +/// The version string contains the package version, branch, commit hash, build time, and build environment on separate lines. +/// This constant is suitable for printing to the user. +#[allow(dead_code)] pub const VERSION:&str = shadow_rs::formatcp!(r#" pkg_version:{} branch:{} @@ -15,7 +19,11 @@ build_time:{} build_env:{},{}"#,PKG_VERSION, BRANCH, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; -const VERSION_TAG_CONST: &str = r##"#[allow(dead_code)] +const VERSION_TAG_CONST: &str = r##" +/// A long version string describing the project. +/// The version string contains the package version, current Git tag, commit hash, build time, and build environment on separate lines. +/// This constant is suitable for printing to the user. +#[allow(dead_code)] pub const VERSION:&str = shadow_rs::formatcp!(r#" pkg_version:{} tag:{} @@ -42,7 +50,11 @@ build_time:{} build_env:{},{}"#,PKG_VERSION, TAG, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; -const CLAP_LONG_VERSION_BRANCH_CONST: &str = r##"#[allow(dead_code)] +const CLAP_LONG_VERSION_BRANCH_CONST: &str = r##" +/// A long version string describing the project. +/// The version string contains the package version, branch, commit hash, build time, and build environment on separate lines. +/// This constant is intended to be used by clap or other CLI tools as a long version string. +#[allow(dead_code)] pub const CLAP_LONG_VERSION:&str = shadow_rs::formatcp!(r#"{} branch:{} commit_hash:{} @@ -50,7 +62,11 @@ build_time:{} build_env:{},{}"#,PKG_VERSION, BRANCH, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; -const CLAP_LONG_VERSION_TAG_CONST: &str = r##"#[allow(dead_code)] +const CLAP_LONG_VERSION_TAG_CONST: &str = r##" +/// A long version string describing the project. +/// The version string contains the package version, current Git tag, commit hash, build time, and build environment on separate lines. +/// This constant is intended to be used by clap or other CLI tools as a long version string. +#[allow(dead_code)] pub const CLAP_LONG_VERSION:&str = shadow_rs::formatcp!(r#"{} tag:{} commit_hash:{} @@ -58,43 +74,15 @@ build_time:{} build_env:{},{}"#,PKG_VERSION, TAG, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; -const VERSION_CONST_DESC: &str = r#"/// The common version const. It's so easy to use this const."#; - -const CLAP_VERSION_CONST_DESC: &str = - r#"/// The common version const. It's so easy to use this const with `CLAP_VERSION`."#; - -const CLAP_LONG_VERSION_CONST_DESC: &str = - r#"/// The common version const. It's so easy to use this const with `CLAP_VERSION`."#; - -gen_const!( - version_branch_const, - VERSION_CONST_DESC, - VERSION_BRANCH_CONST -); - -gen_const!(version_tag_const, VERSION_CONST_DESC, VERSION_TAG_CONST); - -gen_const!( - clap_version_branch_const, - CLAP_VERSION_CONST_DESC, - CLAP_VERSION_BRANCH_CONST -); -gen_const!( - clap_version_tag_const, - CLAP_VERSION_CONST_DESC, - CLAP_VERSION_TAG_CONST -); - +gen_const!(version_branch_const, VERSION_BRANCH_CONST); +gen_const!(version_tag_const, VERSION_TAG_CONST); +gen_const!(clap_version_branch_const, CLAP_VERSION_BRANCH_CONST); +gen_const!(clap_version_tag_const, CLAP_VERSION_TAG_CONST); gen_const!( clap_long_version_branch_const, - CLAP_LONG_VERSION_CONST_DESC, CLAP_LONG_VERSION_BRANCH_CONST ); -gen_const!( - clap_long_version_tag_const, - CLAP_LONG_VERSION_CONST_DESC, - CLAP_LONG_VERSION_TAG_CONST -); +gen_const!(clap_long_version_tag_const, CLAP_LONG_VERSION_TAG_CONST); pub(crate) const BUILD_CONST_VERSION: &str = "VERSION"; pub(crate) const BUILD_CONST_CLAP_LONG_VERSION: &str = "CLAP_LONG_VERSION"; @@ -105,11 +93,8 @@ mod tests { #[test] fn test_version_fn() { - assert!(version_branch_const().contains(VERSION_CONST_DESC)); assert!(version_tag_const().contains(VERSION_TAG_CONST)); assert!(clap_version_branch_const().contains(CLAP_VERSION_BRANCH_CONST)); - assert!(clap_version_tag_const().contains(CLAP_VERSION_CONST_DESC)); assert!(clap_long_version_branch_const().contains(CLAP_LONG_VERSION_BRANCH_CONST)); - assert!(clap_long_version_tag_const().contains(CLAP_LONG_VERSION_CONST_DESC)); } } diff --git a/src/git.rs b/src/git.rs index e86d031..b76e866 100644 --- a/src/git.rs +++ b/src/git.rs @@ -8,17 +8,74 @@ use std::io::{BufReader, Read}; use std::path::Path; use std::process::{Command, Stdio}; +const BRANCH_DOC: &str = r#" +The name of the Git branch that this project was built from. + +This constant will be empty if the branch cannot be determined."#; pub const BRANCH: ShadowConst = "BRANCH"; +const TAG_DOC: &str = r#" +The name of the Git tag that this project was built from. +Note that this will be empty if there is no tag for the HEAD at the time of build."#; pub const TAG: ShadowConst = "TAG"; +const LAST_TAG_DOC: &str = r#" +The name of the last Git tag on the branch that this project was built from. +As opposed to [`TAG`], this does not require the current commit to be tagged, just one of its parents. + +This constant will be empty if the last tag cannot be determined."#; pub const LAST_TAG: ShadowConst = "LAST_TAG"; +const SHORT_COMMIT_DOC: &str = r#" +The short hash of the Git commit that this project was built from. +Note that this will always truncate [`COMMIT_HASH`] to 8 characters if necessary. +Depending on the amount of commits in your project, this may not yield a unique Git identifier +([see here for more details on hash abbreviation](https://git-scm.com/docs/git-describe#_examples)). + +This constant will be empty if the last commit cannot be determined."#; pub const SHORT_COMMIT: ShadowConst = "SHORT_COMMIT"; +const COMMIT_HASH_DOC: &str = r#" +The full commit hash of the Git commit that this project was built from. +An abbreviated, but not necessarily unique, version of this is [`SHORT_COMMIT`]. + +This constant will be empty if the last commit cannot be determined."#; pub const COMMIT_HASH: ShadowConst = "COMMIT_HASH"; +const COMMIT_DATE_DOC: &str = r#"The time of the Git commit that this project was built from. +The time is formatted in modified ISO 8601 format (`YYYY-MM-DD HH-MM ±hh-mm` where hh-mm is the offset from UTC). + +This constant will be empty if the last commit cannot be determined."#; pub const COMMIT_DATE: ShadowConst = "COMMIT_DATE"; +const COMMIT_DATE_2822_DOC: &str = r#" +The name of the Git branch that this project was built from. +The time is formatted according to [RFC 2822](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) (e.g. HTTP Headers). + +This constant will be empty if the last commit cannot be determined."#; pub const COMMIT_DATE_2822: ShadowConst = "COMMIT_DATE_2822"; +const COMMIT_DATE_3339_DOC: &str = r#" +The name of the Git branch that this project was built from. +The time is formatted according to [RFC 3339 and ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6). + +This constant will be empty if the last commit cannot be determined."#; pub const COMMIT_DATE_3339: ShadowConst = "COMMIT_DATE_3339"; +const COMMIT_AUTHOR_DOC: &str = r#" +The author of the Git commit that this project was built from. + +This constant will be empty if the last commit cannot be determined."#; pub const COMMIT_AUTHOR: ShadowConst = "COMMIT_AUTHOR"; +const COMMIT_EMAIL_DOC: &str = r#" +The e-mail address of the author of the Git commit that this project was built from. + +This constant will be empty if the last commit cannot be determined."#; pub const COMMIT_EMAIL: ShadowConst = "COMMIT_EMAIL"; +const GIT_CLEAN_DOC: &str = r#" +Whether the Git working tree was clean at the time of project build (`true`), or not (`false`). + +This constant will be `false` if the last commit cannot be determined."#; pub const GIT_CLEAN: ShadowConst = "GIT_CLEAN"; +const GIT_STATUS_FILE_DOC: &str = r#" +The Git working tree status as a list of files with their status, similar to `git status`. +Each line of the list is preceded with ` * `, followed by the file name. +Files marked `(dirty)` have unstaged changes. +Files marked `(staged)` have staged changes. + +This constant will be empty if the working tree status cannot be determined."#; pub const GIT_STATUS_FILE: ShadowConst = "GIT_STATUS_FILE"; #[derive(Default, Debug)] @@ -222,49 +279,33 @@ pub fn new_git( map: Default::default(), ci_type: ci, }; - git.map - .insert(BRANCH, ConstVal::new("display current branch")); + git.map.insert(BRANCH, ConstVal::new(BRANCH_DOC)); + + git.map.insert(TAG, ConstVal::new(TAG_DOC)); - git.map.insert(TAG, ConstVal::new("display current tag")); + git.map.insert(LAST_TAG, ConstVal::new(LAST_TAG_DOC)); - git.map.insert(LAST_TAG, ConstVal::new("display last tag")); + git.map.insert(COMMIT_HASH, ConstVal::new(COMMIT_HASH_DOC)); git.map - .insert(COMMIT_HASH, ConstVal::new("display current commit_id")); + .insert(SHORT_COMMIT, ConstVal::new(SHORT_COMMIT_DOC)); - git.map.insert( - SHORT_COMMIT, - ConstVal::new("display current short commit_id"), - ); + git.map + .insert(COMMIT_AUTHOR, ConstVal::new(COMMIT_AUTHOR_DOC)); + git.map + .insert(COMMIT_EMAIL, ConstVal::new(COMMIT_EMAIL_DOC)); + git.map.insert(COMMIT_DATE, ConstVal::new(COMMIT_DATE_DOC)); - git.map.insert( - COMMIT_AUTHOR, - ConstVal::new("display current commit author"), - ); git.map - .insert(COMMIT_EMAIL, ConstVal::new("display current commit email")); + .insert(COMMIT_DATE_2822, ConstVal::new(COMMIT_DATE_2822_DOC)); + + git.map + .insert(COMMIT_DATE_3339, ConstVal::new(COMMIT_DATE_3339_DOC)); + + git.map.insert(GIT_CLEAN, ConstVal::new_bool(GIT_CLEAN_DOC)); + git.map - .insert(COMMIT_DATE, ConstVal::new("display current commit date")); - - git.map.insert( - COMMIT_DATE_2822, - ConstVal::new("display current commit date by rfc2822"), - ); - - git.map.insert( - COMMIT_DATE_3339, - ConstVal::new("display current commit date by rfc3339"), - ); - - git.map.insert( - GIT_CLEAN, - ConstVal::new_bool("display current git repository status clean:'true or false'"), - ); - - git.map.insert( - GIT_STATUS_FILE, - ConstVal::new("display current git repository status files:'dirty or stage'"), - ); + .insert(GIT_STATUS_FILE, ConstVal::new(GIT_STATUS_FILE_DOC)); if let Err(e) = git.init(path, std_env) { println!("{e}"); diff --git a/src/lib.rs b/src/lib.rs index 17ee351..09e796b 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,69 +1,23 @@ #![doc(html_logo_url = "https://raw.githubusercontent.com/baoyachi/shadow-rs/master/shadow-rs.png")] -//! `shadow-rs` :build-time information stored in your rust project.(binary,lib,cdylib,dylib) +//! `shadow-rs`: Build-time information stored in your Rust project (binary, lib, cdylib, dylib). //! -//! It's allows you to recall properties of the build process and environment at runtime, including: +//! `shadow-rs` allows you to access properties of the build process and environment at runtime, including: //! -//! `Cargo.toml` project version +//! * `Cargo.toml` information, such as the project version //! * Dependency information -//! * The Git commit that produced the build artifact (binary) -//! * What version of the rust toolchain was used in compilation +//! * Git information, such as the commit that produced the build artifact +//! * What version of the Rust toolchain was used in compilation //! * The build variant, e.g. `debug` or `release` -//! * (And more) +//! * ... And more! //! -//! You can use this tool to check in production exactly where a binary came from and how it was built. +//! You can use this crate to programmatically check where a binary came from and how it was built. //! -//! # Full Examples +//! # Examples //! * Check out the [example_shadow](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow) for a simple demonstration of how `shadow-rs` might be used to provide build-time information at run-time. -//! * Check out the [example_shadow_hook](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow_hook) for a simple demonstration of how `shadow-rs` might be used to provide build-time information at run-time,and add custom hook. +//! * Check out the [example_shadow_hook](https://github.com/baoyachi/shadow-rs/tree/master/example_shadow_hook) for a demonstration of how custom hooks can be used to add extra information to `shadow-rs`'s output. +//! * Check out the [`builtin_fn` example](https://github.com/baoyachi/shadow-rs/tree/master/examples/builtin_fn.rs) for a simple demonstration of the built-in functions that `shadow-rs` provides. //! -//! ## Built in function -//! * Check out the [examples](https://github.com/baoyachi/shadow-rs/tree/master/examples) for a simple demonstration of how `shadow-rs` might be used to provide build in function. -//! -//! # Example -//! -//! ``` -//! pub const PKG_VERSION :&str = "1.3.8-beta3"; -//! pub const PKG_VERSION_MAJOR :&str = "1"; -//! pub const PKG_VERSION_MINOR :&str = "3"; -//! pub const PKG_VERSION_PATCH :&str = "8"; -//! pub const PKG_VERSION_PRE :&str = "beta3"; -//! pub const RUST_VERSION :&str = "rustc 1.45.0 (5c1f21c3b 2020-07-13)"; -//! pub const BUILD_RUST_CHANNEL :&str = "debug"; -//! pub const COMMIT_AUTHOR :&str = "baoyachi"; -//! pub const BUILD_TIME :&str = "2020-08-16 13:48:52"; -//! pub const BUILD_TIME_2822 :&str = "Thu, 24 Jun 2021 21:44:14 +0800"; -//! pub const BUILD_TIME_3339 :&str = "2021-06-24T15:53:55+08:00"; -//! pub const COMMIT_DATE :&str = "2021-08-04 12:34:03 +00:00"; -//! pub const COMMIT_DATE_2822 :&str = "Thu, 24 Jun 2021 21:44:14 +0800"; -//! pub const COMMIT_DATE_3339 :&str = "2021-06-24T21:44:14.473058+08:00"; -//! pub const COMMIT_EMAIL :&str = "xxx@gmail.com"; -//! pub const PROJECT_NAME :&str = "shadow-rs"; -//! pub const RUST_CHANNEL :&str = "stable-x86_64-apple-darwin (default)"; -//! pub const BRANCH :&str = "master"; -//! pub const CARGO_LOCK :&str = r#" -//! ├── chrono v0.4.19 -//! │ ├── libc v0.2.80 -//! │ ├── num-integer v0.1.44 -//! │ │ └── num-traits v0.2.14 -//! │ │ [build-dependencies] -//! │ │ └── autocfg v1.0.1 -//! │ ├── num-traits v0.2.14 (*) -//! │ └── time v0.1.44 -//! │ └── libc v0.2.80 -//! └── git2 v0.13.12 -//! ├── log v0.4.11 -//! │ └── cfg-if v0.1.10 -//! └── url v2.2.0 -//! ├── form_urlencoded v1.0.0 -//! │ └── percent-encoding v2.1.0 -//! └── percent-encoding v2.1.0"#; -//! pub const CARGO_VERSION :&str = "cargo 1.45.0 (744bd1fbb 2020-06-15)"; -//! pub const BUILD_OS :&str = "macos-x86_64"; -//! pub const COMMIT_HASH :&str = "386741540d73c194a3028b96b92fdeb53ca2788a"; -//! pub const GIT_CLEAN :bool = true; -//! pub const GIT_STATUS_FILE :&str = "* src/lib.rs (dirty)"; -//! ``` -//! # Setup Guide +//! # Setup //! //! ### 1) Modify `Cargo.toml` fields //! Modify your `Cargo.toml` like so: @@ -85,63 +39,110 @@ //! //! ```ignore //! fn main() -> shadow_rs::SdResult<()> { -//! shadow_rs::new() +//! shadow_rs::new() //! } //! ``` //! +//! If you want to exclude some build constants, you can use [`new_deny`] instead of [`new`]. +//! //! ### 3) Integrate Shadow -//! In your rust file (e.g. `*.rs`): +//! In your main Rust file (usually `main.rs` or `lib.rs`), add this: //! //! ```ignore //! use shadow_rs::shadow; //! //! shadow!(build); //! ``` -//! **Notice that the `shadow!` macro is provided the identifier `build`. You can now use this identifier to access build-time information.** //! -//! ### 4) Done. Use Shadow. -//! Then you can use const that's shadow build it(main.rs). +//! The `shadow!` macro uses the given identifier to create a module with that name. //! -//! The `build` mod just we use `shadow!(build)` generated. +//! ### 4) Use Shadow Constants +//! You can now use the module defined with `shadow!` to access build-time information. //! //! ```ignore //! fn main(){ -//! println!("debug:{}", shadow_rs::is_debug()); // check if this is a debug build. e.g 'true/false' -//! println!("branch:{}", shadow_rs::branch()); // get current project branch. e.g 'master/develop' -//! println!("tag:{}", shadow_rs::tag()); // get current project tag. e.g 'v1.3.5' -//! println!("git_clean:{}", shadow_rs::git_clean()); // get current project clean. e.g 'true/false' -//! println!("git_status_file:{}", shadow_rs::git_status_file()); // get current project statue file. e.g ' * examples/builtin_fn.rs (dirty)' +//! println!("debug:{}", shadow_rs::is_debug()); // check if this is a debug build. e.g 'true/false' +//! println!("branch:{}", shadow_rs::branch()); // get current project branch. e.g 'master/develop' +//! println!("tag:{}", shadow_rs::tag()); // get current project tag. e.g 'v1.3.5' +//! println!("git_clean:{}", shadow_rs::git_clean()); // get current project clean. e.g 'true/false' +//! println!("git_status_file:{}", shadow_rs::git_status_file()); // get current project statue file. e.g ' * examples/builtin_fn.rs (dirty)' //! -//! println!("{}",build::VERSION); //print version const -//! println!("{}",build::CLAP_LONG_VERSION); //print CLAP_LONG_VERSION const -//! println!("{}",build::BRANCH); //master -//! println!("{}",build::SHORT_COMMIT);//8405e28e -//! println!("{}",build::COMMIT_HASH);//8405e28e64080a09525a6cf1b07c22fcaf71a5c5 -//! println!("{}",build::COMMIT_DATE);//2021-08-04 12:34:03 +00:00 -//! println!("{}",build::COMMIT_AUTHOR);//baoyachi -//! println!("{}",build::COMMIT_EMAIL);//xxx@gmail.com +//! println!("{}", build::VERSION); //print version const +//! println!("{}", build::CLAP_LONG_VERSION); //print CLAP_LONG_VERSION const +//! println!("{}", build::BRANCH); //master +//! println!("{}", build::SHORT_COMMIT);//8405e28e +//! println!("{}", build::COMMIT_HASH);//8405e28e64080a09525a6cf1b07c22fcaf71a5c5 +//! println!("{}", build::COMMIT_DATE);//2021-08-04 12:34:03 +00:00 +//! println!("{}", build::COMMIT_AUTHOR);//baoyachi +//! println!("{}", build::COMMIT_EMAIL);//xxx@gmail.com //! -//! println!("{}",build::BUILD_OS);//macos-x86_64 -//! println!("{}",build::RUST_VERSION);//rustc 1.45.0 (5c1f21c3b 2020-07-13) -//! println!("{}",build::RUST_CHANNEL);//stable-x86_64-apple-darwin (default) -//! println!("{}",build::CARGO_VERSION);//cargo 1.45.0 (744bd1fbb 2020-06-15) -//! println!("{}",build::PKG_VERSION);//0.3.13 -//! println!("{}",build::CARGO_TREE); //like command:cargo tree -//! println!("{}",build::CARGO_MANIFEST_DIR); // /User/baoyachi/shadow-rs/ | +//! println!("{}", build::BUILD_OS);//macos-x86_64 +//! println!("{}", build::RUST_VERSION);//rustc 1.45.0 (5c1f21c3b 2020-07-13) +//! println!("{}", build::RUST_CHANNEL);//stable-x86_64-apple-darwin (default) +//! println!("{}", build::CARGO_VERSION);//cargo 1.45.0 (744bd1fbb 2020-06-15) +//! println!("{}", build::PKG_VERSION);//0.3.13 +//! println!("{}", build::CARGO_TREE); //like command:cargo tree +//! println!("{}", build::CARGO_MANIFEST_DIR); // /User/baoyachi/shadow-rs/ | //! -//! println!("{}",build::PROJECT_NAME);//shadow-rs -//! println!("{}",build::BUILD_TIME);//2020-08-16 14:50:25 -//! println!("{}",build::BUILD_RUST_CHANNEL);//debug -//! println!("{}",build::GIT_CLEAN);//false -//! println!("{}",build::GIT_STATUS_FILE);//* src/lib.rs (dirty) +//! println!("{}", build::PROJECT_NAME);//shadow-rs +//! println!("{}", build::BUILD_TIME);//2020-08-16 14:50:25 +//! println!("{}", build::BUILD_RUST_CHANNEL);//debug +//! println!("{}", build::GIT_CLEAN);//false +//! println!("{}", build::GIT_STATUS_FILE);//* src/lib.rs (dirty) //! } -//!``` +//! ``` +//! +//! ## Clap +//! You can also use `shadow-rs` to provide information to command-line interface crates such as [`clap`](https://docs.rs/clap/latest/clap/). An example of this can be found in [`example_shadow`](https://github.com/baoyachi/shadow-rs/blob/master/example_shadow/src/main.rs). //! -//! ## Clap example -//! And you can also use `shadow-rs` with [`clap`](https://github.com/baoyachi/shadow-rs/blob/master/example_shadow/src/main.rs). +//! For the user guide and further documentation, see the [README of `shadow-rs`](https://github.com/baoyachi/shadow-rs). //! -//! For the user guide and further documentation, please read -//! [The shadow-rs document](https://github.com/baoyachi/shadow-rs). +//! # List of Generated Output Constants +//! +//! All constants produced by `shadow-rs` are documented in the module created with [`shadow!`], so `rustdoc` and your IDE will pick it up. +//! +//! ``` +//! pub const PKG_VERSION: &str = "1.3.8-beta3"; +//! pub const PKG_VERSION_MAJOR: &str = "1"; +//! pub const PKG_VERSION_MINOR: &str = "3"; +//! pub const PKG_VERSION_PATCH: &str = "8"; +//! pub const PKG_VERSION_PRE: &str = "beta3"; +//! pub const RUST_VERSION: &str = "rustc 1.45.0 (5c1f21c3b 2020-07-13)"; +//! pub const BUILD_RUST_CHANNEL: &str = "debug"; +//! pub const COMMIT_AUTHOR: &str = "baoyachi"; +//! pub const BUILD_TIME: &str = "2020-08-16 13:48:52"; +//! pub const BUILD_TIME_2822: &str = "Thu, 24 Jun 2021 21:44:14 +0800"; +//! pub const BUILD_TIME_3339: &str = "2021-06-24T15:53:55+08:00"; +//! pub const COMMIT_DATE: &str = "2021-08-04 12:34:03 +00:00"; +//! pub const COMMIT_DATE_2822: &str = "Thu, 24 Jun 2021 21:44:14 +0800"; +//! pub const COMMIT_DATE_3339: &str = "2021-06-24T21:44:14.473058+08:00"; +//! pub const COMMIT_EMAIL: &str = "xxx@gmail.com"; +//! pub const PROJECT_NAME: &str = "shadow-rs"; +//! pub const RUST_CHANNEL: &str = "stable-x86_64-apple-darwin (default)"; +//! pub const BRANCH: &str = "master"; +//! pub const CARGO_LOCK: &str = r#" +//! ├── chrono v0.4.19 +//! │ ├── libc v0.2.80 +//! │ ├── num-integer v0.1.44 +//! │ │ └── num-traits v0.2.14 +//! │ │ [build-dependencies] +//! │ │ └── autocfg v1.0.1 +//! │ ├── num-traits v0.2.14 (*) +//! │ └── time v0.1.44 +//! │ └── libc v0.2.80 +//! └── git2 v0.13.12 +//! ├── log v0.4.11 +//! │ └── cfg-if v0.1.10 +//! └── url v2.2.0 +//! ├── form_urlencoded v1.0.0 +//! │ └── percent-encoding v2.1.0 +//! └── percent-encoding v2.1.0"#; +//! pub const CARGO_VERSION: &str = "cargo 1.45.0 (744bd1fbb 2020-06-15)"; +//! pub const BUILD_OS: &str = "macos-x86_64"; +//! pub const COMMIT_HASH: &str = "386741540d73c194a3028b96b92fdeb53ca2788a"; +//! pub const GIT_CLEAN: bool = true; +//! pub const GIT_STATUS_FILE: &str = "* src/lib.rs (dirty)"; +//! ``` //! mod build; @@ -152,14 +153,7 @@ mod err; mod gen_const; mod git; -/// Get current project build mode. -/// -/// It's very useful. Debug mode is usually used for debugging information. -/// For example, log printing, environment variable switch. -/// -/// The default value is `true`. -/// -/// If we compile with `cargo build --release`. It's return value is `false`. +/// Re-exported from the is_debug crate pub use is_debug::*; use build::*; @@ -188,12 +182,21 @@ pub trait Format { const SHADOW_RS: &str = "shadow.rs"; -/// Add a mod in project with `$build_mod`. +/// Add a module with the provided name which contains the build information generated by `shadow-rs`. +/// +/// # Example +/// +/// ```ignore +/// use shadow_rs::shadow; /// -/// You can use `shadow!(build_shadow)`. Then shadow-rs can help you add a mod with name `build_shadow`. -/// Next, use mod with name `build_shadow`,and also use const like:`build_shadow::BRANCH`. +/// shadow!(my_build_information); +/// +/// fn main() { +/// println!("I'm version {}!", my_build_information::VERSION); +/// } +/// ``` /// -/// Normally, you just config `shadow!(build)`.It looks more concise. +/// The convention, however, is to use `shadow!(build);`. #[macro_export] macro_rules! shadow { ($build_mod:ident) => { @@ -204,13 +207,14 @@ macro_rules! shadow { }; } -/// It's shadow-rs Initialization entry. +/// Generates build information for the current project. +/// This function must be called from `build.rs`. /// -/// In build.rs `main()` function call for this function. -/// -/// # Examples +/// # Example /// /// ```ignore +/// // build.rs +/// /// fn main() -> shadow_rs::SdResult<()> { /// shadow_rs::new() /// } @@ -220,14 +224,16 @@ pub fn new() -> SdResult<()> { Ok(()) } -/// It's shadow-rs Initialization entry, If deny const is configured, constants will not be generated. +/// Identical to [`new`], but additionally accepts a build output denylist. +/// This list determines constants to be excluded in the build output. /// -/// In build.rs `main()` function call for this function. -/// -/// # Examples +/// Note that not all constants can be excluded independently, since some constants depend on others. +/// See [`ShadowConst`] for a list of constants that can be excluded. /// +/// # Example /// /// ```ignore +/// // build.rs /// /// use std::collections::BTreeSet; /// @@ -242,13 +248,15 @@ pub fn new_deny(deny_const: BTreeSet) -> SdResult<()> { Ok(()) } -/// It's shadow-rs Initialization entry with add custom hook. -/// -/// In build.rs `main()` function call for this function. +/// Identical to [`new`], but additionally accepts an output hook. +/// The hook receives the output file of `shadow-rs`, and it can add additional entries to the output of `shadow-rs` by writing to this file. +/// Note that since the output will be compiled as a Rust module, inserting invalid Rust code will lead to a compile error later on. /// -/// # Examples +/// # Example /// /// ```ignore +/// // build.rs +/// /// fn main() -> shadow_rs::SdResult<()> { /// shadow_rs::new_hook(append_write_const) /// } @@ -268,7 +276,7 @@ where shadow.hook(f) } -/// get std::env:vars +/// Returns the contents of [`std::env::vars`] as an ordered map. pub fn get_std_env() -> BTreeMap { let mut env_map = BTreeMap::new(); for (k, v) in std_env::vars() { @@ -277,15 +285,25 @@ pub fn get_std_env() -> BTreeMap { env_map } +/// `shadow-rs` configuration. +/// +/// If you use the recommended utility functions [`new`], [`new_deny`], or [`new_hook`], you do not have to handle [`Shadow`] configurations themselves. +/// However, this struct provides more fine-grained access to `shadow-rs` configuration, such as using a denylist and a hook function at the same time. #[derive(Debug)] pub struct Shadow { + /// The file that `shadow-rs` writes build information to. pub f: File, + /// The values of build constants to be written. pub map: BTreeMap, + /// Build environment variables, obtained through [`get_std_env`]. pub std_env: BTreeMap, + /// Constants in the denylist, passed through [`new_deny`] or [`Shadow::build`]. pub deny_const: BTreeSet, } impl Shadow { + /// Write the build configuration specified by this [`Shadow`] instance. + /// The hook function is run as well, allowing it to append to `shadow-rs`'s output. pub fn hook(&self, f: F) -> SdResult<()> where F: FnOnce(&File) -> SdResult<()>, @@ -296,7 +314,9 @@ impl Shadow { Ok(()) } - /// try get current ci env + /// Try to infer the CI system that we're currently running under. + /// + /// TODO: Recognize other CI types, especially Travis and Jenkins. fn try_ci(&self) -> CiType { if let Some(c) = self.std_env.get("GITLAB_CI") { if c == "true" { @@ -310,11 +330,11 @@ impl Shadow { } } - //TODO completed [travis,jenkins] env - CiType::None } + /// Create a new [`Shadow`] configuration with a provided denylist. + /// The project source path and output file are automatically derived from Cargo build environment variables. pub fn build(deny_const: BTreeSet) -> SdResult { let src_path = std::env::var("CARGO_MANIFEST_DIR")?; let out_path = std::env::var("OUT_DIR")?; @@ -382,12 +402,15 @@ impl Shadow { Ok(()) } + /// Request Cargo to re-run the build script if any environment variable observed by this [`Shadow`] configuration changes. pub fn cargo_rerun_if_env_changed(&self) { for k in self.std_env.keys() { println!("cargo:rerun-if-env-changed={k}"); } } + /// Request Cargo to re-run the build script if any of the specified environment variables change. + /// This function is not influenced by this [`Shadow`] configuration. pub fn cargo_rerun_env_inject(&self, env: &[&str]) { for k in env { println!("cargo:rerun-if-env-changed={}", *k); @@ -404,10 +427,9 @@ impl Shadow { fn gen_header(&self) -> SdResult<()> { let desc = format!( - r#"// Code generated by shadow-rs generator. DO NOT EDIT. -// Author by:https://www.github.com/baoyachi -// The build script repository:https://github.com/baoyachi/shadow-rs -// Create time by:{}"#, + r#"// Code automatically generated by `shadow-rs` (https://github.com/baoyachi/shadow-rs), do not edit. +// Author: https://www.github.com/baoyachi +// Generation time: {}"#, DateTime::now().human_format() ); writeln!(&self.f, "{desc}\n\n")?; @@ -492,7 +514,7 @@ impl Shadow { } let everything_define = format!( - "/// print build in method\n\ + "/// Prints all built-in `shadow-rs` build constants to standard output.\n\ #[allow(dead_code)]\n\ pub fn print_build_in() {\ {{print_val}}\