shadow-rs-0.29.0/.cargo_vcs_info.json0000644000000001360000000000100130330ustar { "git": { "sha1": "4eabcda5debb838fe8d0ac1150c51c11fe7b82fb" }, "path_in_vcs": "" }shadow-rs-0.29.0/.github/dependabot.yml000064400000000000000000000005431046102023000160150ustar 00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily open-pull-requests-limit: 10 labels: - "\U0001F4E6 dependencies" - package-ecosystem: github-actions directory: "/" schedule: interval: daily open-pull-requests-limit: 10 labels: - "\U0001F4E6 dependencies" shadow-rs-0.29.0/.github/workflows/audit.yml000064400000000000000000000013031046102023000170460ustar 00000000000000name: Security audit on: pull_request: paths: # Run if workflow changes - '.github/workflows/audit.yml' # Run on changed dependencies - '**/Cargo.toml' - '**/Cargo.lock' # Run if the configuration file changes - '**/audit.toml' push: paths: # Run if workflow changes - '.github/workflows/audit.yml' # Run on changed dependencies - '**/Cargo.toml' - '**/Cargo.lock' # Run if the configuration file changes - '**/audit.toml' jobs: security_audit: runs-on: ubuntu-latest steps: - name: Set up Rust uses: actions/checkout@v4 - name: Run audit uses: actions-rust-lang/audit@v1shadow-rs-0.29.0/.github/workflows/check.yml000064400000000000000000000066051046102023000170270ustar 00000000000000name: check on: push: branches: - "*" tags: - "*" pull_request: branches: - "*" jobs: build: strategy: matrix: os: - ubuntu-latest - macos-latest - windows-latest runs-on: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true components: clippy, rustfmt - name: Check format run: cargo fmt --all -- --check - name: Check fix run: cargo fix && cargo fix - name: Check with clippy run: cargo clippy --all-targets --all-features -- -D warnings - name: Build Release run: cargo build --release - name: Run tests run: cargo test --all -- --nocapture # Run examples with debug - name: Run examples with debug run: cargo run --example builtin_fn # Run examples with debug - name: Run examples with release run: cargo run --example builtin_fn # example_shadow check - name: Check example_shadow run: | cargo fmt --all -- --check cargo clippy --all -- -D warnings cargo run working-directory: ./example_shadow # example_shadow_hook check - name: Check example_shadow_hook run: | cargo fmt --all -- --check cargo clippy --all -- -D warnings cargo run working-directory: ./example_shadow_hook # example_wasm check - uses: jetli/wasm-pack-action@v0.4.0 with: version: latest - name: Setup wasm-pack run: | cargo b wasm-pack build --target bundler wasm-pack build --target web working-directory: ./example_wasm # build on nightly - uses: actions-rs/toolchain@v1 with: toolchain: nightly override: true components: clippy - name: Build on nightly run: | cargo build --release cargo +nightly clippy --all --all-features -- -D warnings test: strategy: matrix: rust: [ stable, beta, nightly ] runs-on: ubuntu-latest needs: [ build ] steps: - name: Setup Rust uses: hecrj/setup-rust-action@v2 with: rust-version: ${{ matrix.rust }} - name: Install Tarpaulin uses: actions-rs/install@v0.1 with: crate: cargo-tarpaulin version: 0.14.2 use-tool-cache: true - name: Checkout uses: actions/checkout@v4 - name: Test run: | cargo test --all-features cargo test --examples - name: Coverage if: matrix.rust == 'stable' run: cargo tarpaulin -o Lcov --output-dir ./coverage - name: Coveralls if: matrix.rust == 'stable' continue-on-error: true uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} publish-crate: if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest needs: [ test ] steps: - name: Set up Rust uses: hecrj/setup-rust-action@v2 - uses: actions/checkout@v4 - name: Publish shell: bash run: | cargo publish --token ${{ secrets.CRATES_GITHUB_TOKEN }} shadow-rs-0.29.0/.gitignore000064400000000000000000000005201046102023000136100ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk .idea shadow.rs shadow-rs-0.29.0/CHANGELOG.md000064400000000000000000000012221046102023000134310ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. ## [0.11.0] - 2022-03-19 ### Bug Fixes - Https://github.com/baoyachi/shadow-rs/issues/86 - Https://github.com/baoyachi/shadow-rs/issues/68 ## [0.9.0] - 2022-02-22 ### Bug Fixes - Https://github.com/baoyachi/shadow-rs/issues/46 - Https://github.com/baoyachi/shadow-rs/issues/51 - Https://github.com/baoyachi/shadow-rs/issues/61 - Https://github.com/baoyachi/shadow-rs/issues/44 - Replace clap_version with clap_long_version ### Documentation - Update to clap3 - Single-sourced cargo feature flags ### Git2 - Disable default-features shadow-rs-0.29.0/Cargo.lock0000644000000362110000000000100110110ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cc" version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" dependencies = [ "jobserver", "libc", "once_cell", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const_fn" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" [[package]] name = "const_format" version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] [[package]] name = "document-features" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" dependencies = [ "litrs", ] [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "git2" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ "bitflags", "libc", "libgit2-sys", "log", "url", ] [[package]] name = "iana-time-zone" version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "idna" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "is_debug" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89" [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libgit2-sys" version = "0.17.0+1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" dependencies = [ "cc", "libc", "libz-sys", "pkg-config", ] [[package]] name = "libz-sys" version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "litrs" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num_threads" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "serde" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "shadow-rs" version = "0.29.0" dependencies = [ "const_format", "document-features", "git2", "is_debug", "time", "tzdb", "winnow", ] [[package]] name = "syn" version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "time" version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "libc", "num-conv", "num_threads", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tz-rs" version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33851b15c848fad2cf4b105c6bb66eb9512b6f6c44a4b13f57c53c73c707e2b4" dependencies = [ "const_fn", ] [[package]] name = "tzdb" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b580f6b365fa89f5767cdb619a55d534d04a4e14c2d7e5b9a31e94598687fb1" dependencies = [ "iana-time-zone", "tz-rs", "tzdb_data", ] [[package]] name = "tzdb_data" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1889fdffac09d65c1d95c42d5202e9b21ad8c758f426e9fe09088817ea998d6" dependencies = [ "tz-rs", ] [[package]] name = "unicode-bidi" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] name = "windows_i686_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] shadow-rs-0.29.0/Cargo.toml0000644000000032000000000000100110240ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "shadow-rs" version = "0.29.0" authors = ["baoyachi "] exclude = [ "shadow-rs.png", "build_module.png", ] description = "A build-time information stored in your rust project" homepage = "https://github.com/baoyachi/shadow-rs" documentation = "https://docs.rs/shadow-rs" readme = "README.md" keywords = [ "cargo", "build-script", "build", "shadow", "compile", ] categories = [ "development-tools", "development-tools::build-utils", ] license = "MIT AND Apache-2.0" repository = "https://github.com/baoyachi/shadow-rs" [package.metadata.docs.rs] all-features = true [dependencies.const_format] version = "0.2.22" [dependencies.document-features] version = "0.2" optional = true [dependencies.git2] version = "0.19.0" optional = true default-features = false [dependencies.is_debug] version = "1.0.1" [dependencies.time] version = "0.3.11" features = [ "formatting", "local-offset", "parsing", ] [dependencies.tzdb] version = "0.6.0" features = ["local"] optional = true default-features = false [dev-dependencies.winnow] version = "0.6" [features] default = [ "git2", "tzdb", ] shadow-rs-0.29.0/Cargo.toml.orig000064400000000000000000000025241046102023000145150ustar 00000000000000[package] name = "shadow-rs" version = "0.29.0" authors = ["baoyachi "] edition = "2021" description = "A build-time information stored in your rust project" keywords = ["cargo", "build-script", "build", "shadow", "compile"] readme = "README.md" categories = ["development-tools", "development-tools::build-utils"] repository = "https://github.com/baoyachi/shadow-rs" documentation = "https://docs.rs/shadow-rs" homepage = "https://github.com/baoyachi/shadow-rs" license = "MIT AND Apache-2.0" exclude = ["shadow-rs.png", "build_module.png"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [package.metadata.docs.rs] all-features = true [dependencies] is_debug = "1.0.1" const_format = "0.2.22" time = { version = "0.3.11", features = ["formatting", "local-offset", "parsing"] } #! Optional Dependencies: ## Use `libgit2` as a backend for git operations git2 = { version = "0.19.0", default-features = false, optional = true } ## Better support for querying the local system time tzdb = { version = "0.6.0", optional = true, default-features = false, features = ["local"] } document-features = { version = "0.2", optional = true } [features] default = ["git2", "tzdb"] [dev-dependencies] winnow = "0.6" [workspace] members = ["example_shadow", "example_shadow_hook", "example_wasm"] shadow-rs-0.29.0/LICENSE000064400000000000000000000020511046102023000126260ustar 00000000000000MIT License Copyright (c) 2020 baoyachi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. shadow-rs-0.29.0/README.md000064400000000000000000000224371046102023000131120ustar 00000000000000[`shadow-rs`][docsrs]: Build-time information stored in your Rust project (binary, lib, cdylib, dylib). ========================================

shadow-rs build tool

[docsrs]: https://docs.rs/shadow-rs [![GitHub Actions](https://github.com/baoyachi/shadow-rs/workflows/check/badge.svg)](https://github.com/baoyachi/shadow-rs/actions?query=workflow%3Acheck) [![Crates.io](https://img.shields.io/crates/v/shadow-rs.svg)](https://crates.io/crates/shadow-rs) [![Docs.rs](https://docs.rs/shadow-rs/badge.svg)](https://docs.rs/shadow-rs) [![Download](https://img.shields.io/crates/d/shadow-rs)](https://crates.io/crates/shadow-rs) [![DepStatus](https://deps.rs/repo/github/baoyachi/shadow-rs/status.svg)](https://deps.rs/repo/github/baoyachi/shadow-rs) [![Gitter](https://badges.gitter.im/shadow-rs/community.svg)](https://gitter.im/shadow-rs/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Coverage Status](https://coveralls.io/repos/github/baoyachi/shadow-rs/badge.svg)](https://coveralls.io/github/baoyachi/shadow-rs) `shadow-rs` allows you to access properties of the build process and environment at runtime, including: * `Cargo.toml` information, such as the project version * Dependency information * 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! You can use this crate to programmatically check where a binary came from and how it was built. Currently, integration into **wasm** is also supported. For detailed settings, please refer to the link [example_wasm](https://github.com/baoyachi/shadow-rs/tree/master/example_wasm). ![build_module](./build_module.png) # Note on Caching `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 . # 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 ### 1) Modify `Cargo.toml` fields Modify your `Cargo.toml` like so: ```toml [package] build = "build.rs" [dependencies] shadow-rs = "{latest version}" [build-dependencies] shadow-rs = "{latest version}" ``` >About `build = "build.rs"`,this is an optional addition where, by default, build points to the build.rs file. It is recommended to use it as such. However, if your build script file is not named build.rs, please manually specify it. For example: `build = "gen.rs"`. ### 2) Create `build.rs` file Now in the root of your project (same directory as `Cargo.toml`) add a file `build.rs`: ```rust fn main() -> shadow_rs::SdResult<()> { shadow_rs::new() } ``` If you want to exclude some build constants, you can use [`new_deny`] instead of [`new`]. ### 3) Integrate Shadow In your main Rust file (usually `main.rs` or `lib.rs`), add this: ```rust use shadow_rs::shadow; shadow!(build); ``` The `shadow!` macro uses the given identifier to create a module with that name. ### 4) Use Shadow Constants You can now use the module defined with `shadow!` to access build-time information. ```rust 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!("{}", 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) } ``` #### Reproducibility This tool includes the current time in the binary which would normally make it non-reproducible. 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 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). ## List of Constants and Functions #### Functions | Function | Description | | ------ | ------ | | `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)` | #### Constants | Constant | Example | | ------ | ------ | | 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 | | COMMIT_DATE | 2021-08-04 12:34:03 +00:00 | | COMMIT_DATE_2822 | Thu, 24 Jun 2021 21:33:59 +0800 | | COMMIT_DATE_3339 | 2021-06-24T21:33:59.972494+08:00 | | COMMIT_AUTHOR | baoyachi | | COMMIT_EMAIL | xxx@gmail.com | | BUILD_OS | macos-x86_64 | | BUILD_TARGET | x86_64-apple-darwin | | BUILD_TARGET_ARCH | x86_64 | | RUST_VERSION | rustc 1.45.0 (5c1f21c3b 2020-07-13) | | 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 | (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 | 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 the documentation where it may be unclear. ## People using shadow-rs If you are using `shadow-rs`, please tell me! Or instead, consider making a note here: [Shadow Users Collection](https://github.com/baoyachi/shadow-rs/issues/19).
nushell
nushell

starship
starship

exocore
exocore

starship
bagua-core

starship
inclavare-containers

shadow-rs-0.29.0/cliff.toml000064400000000000000000000036471046102023000136150ustar 00000000000000# configuration file for git-cliff (0.1.0) [changelog] # changelog header header = """ # Changelog\n All notable changes to this project will be documented in this file.\n """ # template for the changelog body # https://tera.netlify.app/docs/#introduction body = """ {% if version %}\ ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else %}\ ## [unreleased] {% endif %}\ {% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\ {% endfor %} {% endfor %}\n """ # remove the leading and trailing whitespace from the template trim = true # changelog footer footer = """ """ [git] # parse the commits based on https://www.conventionalcommits.org conventional_commits = true # filter out the commits that are not conventional filter_unconventional = true # regex for parsing and grouping commits commit_parsers = [ { message = "^feat", group = "Features"}, { message = "^fix", group = "Bug Fixes"}, { message = "^doc", group = "Documentation"}, { message = "^perf", group = "Performance"}, { message = "^refactor", group = "Refactor"}, { message = "^style", group = "Styling"}, { message = "^test", group = "Testing"}, { message = "^chore\\(release\\): prepare for", skip = true}, { message = "^chore", group = "Miscellaneous Tasks"}, { body = ".*security", group = "Security"}, ] # filter out the commits that are not matched by commit parsers filter_commits = false # glob pattern for matching git tags tag_pattern = "v[0-9]*" # regex for skipping tags skip_tags = "v0.1.0-beta.1" # regex for ignoring tags ignore_tags = "" # sort the tags chronologically date_order = false # sort the commits inside sections by oldest/newest order sort_commits = "oldest" shadow-rs-0.29.0/examples/builtin_fn.rs000064400000000000000000000011001046102023000161300ustar 00000000000000// cargo run --example builtin_fn 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-0.29.0/src/build.rs000064400000000000000000000024271046102023000140640ustar 00000000000000use std::fmt::{Display, Formatter}; /// `shadow-rs` build constant identifiers. pub type ShadowConst = &'static str; /// 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, } impl ConstVal { pub fn new>(desc: S) -> ConstVal { ConstVal { desc: desc.into(), v: "".to_string(), t: ConstType::OptStr, } } pub fn new_bool>(desc: S) -> ConstVal { ConstVal { desc: desc.into(), v: "true".to_string(), t: ConstType::Bool, } } } /// Supported types of build constants. #[derive(Debug, Clone)] pub enum ConstType { /// [`Option<&str>`](`Option`). OptStr, /// [`&str`](`str`). Str, /// [`bool`]. Bool, } impl Display for ConstType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ConstType::OptStr => write!(f, "Option<&str>"), ConstType::Str => write!(f, "&str"), ConstType::Bool => write!(f, "bool"), } } } shadow-rs-0.29.0/src/ci.rs000064400000000000000000000011331046102023000133510ustar 00000000000000use std::fmt::{Display, Formatter}; /// [`CiType`] holds the types of CI environment that `shadow-rs` can detect. #[derive(Debug)] pub enum CiType { Github, Gitlab, // TODO: Recognize other CI types, especially Travis and Jenkins None, } impl Default for CiType { fn default() -> Self { Self::None } } impl Display for CiType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { CiType::Github => write!(f, "github"), CiType::Gitlab => write!(f, "gitlab"), _ => write!(f, "none"), } } } shadow-rs-0.29.0/src/date_time.rs000064400000000000000000000154711046102023000147230ustar 00000000000000use crate::Format; use std::error::Error; use time::format_description::well_known::{Rfc2822, Rfc3339}; #[cfg(feature = "tzdb")] use time::UtcOffset; use time::{format_description, OffsetDateTime}; pub enum DateTime { Local(OffsetDateTime), Utc(OffsetDateTime), } pub fn now_date_time() -> DateTime { // Enable reproducibility for uses of `now_date_time` by respecting the // `SOURCE_DATE_EPOCH` env variable. // // https://reproducible-builds.org/docs/source-date-epoch/ println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH"); match std::env::var_os("SOURCE_DATE_EPOCH") { None => DateTime::now(), Some(timestamp) => { let epoch = timestamp .into_string() .expect("Input SOURCE_DATE_EPOCH could not be parsed") .parse::() .expect("Input SOURCE_DATE_EPOCH could not be cast to a number"); DateTime::Utc(OffsetDateTime::from_unix_timestamp(epoch).unwrap()) } } } impl Default for DateTime { fn default() -> Self { Self::now() } } impl DateTime { pub fn now() -> Self { Self::local_now().unwrap_or_else(|_| DateTime::Utc(OffsetDateTime::now_utc())) } pub fn offset_datetime() -> OffsetDateTime { let date_time = Self::now(); match date_time { DateTime::Local(time) | DateTime::Utc(time) => time, } } #[cfg(not(feature = "tzdb"))] pub fn local_now() -> Result> { // 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()) } #[cfg(feature = "tzdb")] pub fn local_now() -> Result> { let local_time = tzdb::now::local()?; let time_zone_offset = UtcOffset::from_whole_seconds(local_time.local_time_type().ut_offset())?; let local_date_time = OffsetDateTime::from_unix_timestamp(local_time.unix_time())? .to_offset(time_zone_offset); Ok(DateTime::Local(local_date_time)) } pub fn timestamp_2_utc(time_stamp: i64) -> Self { let time = OffsetDateTime::from_unix_timestamp(time_stamp).unwrap(); DateTime::Utc(time) } pub fn to_rfc2822(&self) -> String { match self { DateTime::Local(dt) | DateTime::Utc(dt) => dt.format(&Rfc2822).unwrap(), } } pub fn to_rfc3339(&self) -> String { match self { DateTime::Local(dt) | DateTime::Utc(dt) => dt.format(&Rfc3339).unwrap(), } } } impl Format for DateTime { fn human_format(&self) -> String { match self { DateTime::Local(dt) | DateTime::Utc(dt) => dt.human_format(), } } } impl Format for OffsetDateTime { fn human_format(&self) -> String { let fmt = format_description::parse( "[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \ sign:mandatory]:[offset_minute]", ) .unwrap(); self.format(&fmt).unwrap() } } #[cfg(test)] mod tests { use super::*; use human_format_validate::parse_human_format; mod human_format_validate { use std::num::{NonZeroU32, NonZeroU8}; use winnow::ascii::{digit1, space1}; use winnow::error::{ContextError, ParseError}; use winnow::token::{literal, take}; use winnow::{PResult, Parser}; fn u8_len2(input: &mut &str) -> PResult { take(2_usize).try_map(str::parse).parse_next(input) } fn non_zero_u8_len2(input: &mut &str) -> PResult { take(2_usize) .try_map(str::parse) .verify(|x| *x <= unsafe { NonZeroU8::new_unchecked(LIMIT) }) .parse_next(input) } // fn non_zero_u32(input: &mut &str) -> PResult { digit1.try_map(str::parse).parse_next(input) } // 2022-07-14 00:40:05 +08:00 pub(crate) fn parse_human_format( input: &str, ) -> Result<(), ParseError<&str, ContextError>> { ( non_zero_u32, literal('-'), non_zero_u8_len2::<12>, literal('-'), non_zero_u8_len2::<31>, space1, u8_len2, literal(':'), u8_len2, literal(':'), u8_len2, space1, literal('+'), u8_len2, literal(':'), u8_len2, ) .parse(input)?; Ok(()) } #[test] fn test_parse() { assert!(parse_human_format("2022-07-14 00:40:05 +08:00").is_ok()); assert!(parse_human_format("2022-12-14 00:40:05 +08:00").is_ok()); assert!(parse_human_format("2022-13-14 00:40:05 +08:00").is_err()); assert!(parse_human_format("2022-12-31 00:40:05 +08:00").is_ok()); assert!(parse_human_format("2022-12-32 00:40:05 +08:00").is_err()); assert!(parse_human_format("2022-07-14 00:40:05 +08:0").is_err()); assert!(parse_human_format("2022-07-14 00:40:05 -08:0").is_err()); assert!(parse_human_format("2022-07-00 00:40:05 +08:00").is_err()); assert!(parse_human_format("2022-00-01 00:40:05 +08:00").is_err()); assert!(parse_human_format("2022-00-01 00:40:05 08:00").is_err()); assert!(parse_human_format("2022-00-01 00:40:05+08:00").is_err()); assert!(parse_human_format("20221-00-01 00:40:05+08:00").is_err()); assert!(parse_human_format("20221-01-01 00:40:05 +08:00").is_ok()); } } #[test] fn test_source_date_epoch() { std::env::set_var("SOURCE_DATE_EPOCH", "1628080443"); let time = now_date_time(); assert_eq!(time.human_format(), "2021-08-04 12:34:03 +00:00"); } #[test] fn test_local_now_human_format() { let time = DateTime::local_now().unwrap().human_format(); #[cfg(unix)] assert!(!std::fs::read("/etc/localtime").unwrap().is_empty()); assert!(parse_human_format(&time).is_ok()); println!("local now:{time}"); // 2022-07-14 00:40:05 +08:00 assert_eq!(time.len(), 26); } #[test] fn test_timestamp_2_utc() { let time = DateTime::timestamp_2_utc(1628080443); assert_eq!(time.to_rfc2822(), "Wed, 04 Aug 2021 12:34:03 +0000"); assert_eq!(time.to_rfc3339(), "2021-08-04T12:34:03Z"); assert_eq!(time.human_format(), "2021-08-04 12:34:03 +00:00"); } } shadow-rs-0.29.0/src/env.rs000064400000000000000000000373711046102023000135630ustar 00000000000000use crate::build::*; use crate::date_time::now_date_time; use crate::env::dep_source_replace::filter_cargo_tree; use crate::err::SdResult; use crate::Format; use is_debug::build_channel; use std::collections::BTreeMap; use std::env; use std::process::Command; #[derive(Default, Debug)] 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 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 { fn init(&mut self, std_env: &BTreeMap) -> SdResult<()> { let mut update_val = |c: ShadowConst, v: String| { if let Some(val) = self.map.get_mut(c) { val.t = ConstType::Str; val.v = v; } }; if let Some(v) = std_env.get("RUSTUP_TOOLCHAIN") { update_val(RUST_CHANNEL, v.to_string()); } if let Ok(out) = Command::new("rustc").arg("-V").output() { update_val( RUST_VERSION, String::from_utf8(out.stdout)?.trim().to_string(), ); } if let Ok(out) = Command::new("cargo").arg("-V").output() { update_val( CARGO_VERSION, String::from_utf8(out.stdout)?.trim().to_string(), ); } if let Ok(out) = Command::new("cargo").arg("tree").output() { let input = String::from_utf8(out.stdout)?; if let Some(index) = input.find('\n') { let lines = filter_cargo_tree(input.get(index..).unwrap_or_default().split('\n').collect()); update_val(CARGO_TREE, lines); } } // TODO completed // if let Ok(_out) = Command::new("cargo") // .args(["metadata", "--format-version", "1"]) // .output() // { // update_val( // CARGO_METADATA, // String::from_utf8(out.stdout)?.trim().to_string(), // ); // } if let Some(v) = std_env.get("TARGET") { update_val(BUILD_TARGET, v.to_string()); } if let Some(v) = std_env.get("CARGO_CFG_TARGET_ARCH") { update_val(BUILD_TARGET_ARCH, v.to_string()); } if let Some(v) = std_env.get("CARGO_PKG_VERSION") { update_val(PKG_VERSION, v.to_string()); } if let Some(v) = std_env.get("CARGO_PKG_DESCRIPTION") { update_val(PKG_DESCRIPTION, v.to_string()); } if let Some(v) = std_env.get("CARGO_PKG_VERSION_MAJOR") { update_val(PKG_VERSION_MAJOR, v.to_string()); } if let Some(v) = std_env.get("CARGO_PKG_VERSION_MINOR") { update_val(PKG_VERSION_MINOR, v.to_string()); } if let Some(v) = std_env.get("CARGO_PKG_VERSION_PATCH") { update_val(PKG_VERSION_PATCH, v.to_string()); } if let Some(v) = std_env.get("CARGO_PKG_VERSION_PRE") { update_val(PKG_VERSION_PRE, v.to_string()); } if let Some(v) = std_env.get("CARGO_MANIFEST_DIR") { update_val(CARGO_MANIFEST_DIR, v.to_string()); } Ok(()) } } mod dep_source_replace { use std::fs; fn path_exists(path: &str) -> bool { fs::metadata(path).is_ok() } const DEP_REPLACE_NONE: &str = ""; const DEP_REPLACE_PATH: &str = " (* path)"; const DEP_REPLACE_GIT: &str = " (* git)"; const DEP_REPLACE_REGISTRY: &str = " (* registry)"; /// filter cargo tree dependencies source /// /// Why do this? /// /// Sometimes, the private registry or private git url that our cargo relies on will carry this information /// with the cargo tree command output we use. In order to protect the privacy of dependence, we need to shield it. /// /// This can protect us from the security issues we rely on environmental information. /// /// I think it is very necessary.So we need to do fuzzy replacement of dependent output. /// /// for examples: /// /// - dep by git: shadow-rs = { git = "https://github.com/baoyachi/shadow-rs", branch="master" } /// - dep by registry: shadow-rs = { version = "0.5.23",registry="private-crates" } /// - dep by path: shadow-rs = { path = "/Users/baoyachi/shadow-rs" } /// /// before exec: cargo tree output by difference dependencies source: /// /// - git: └── shadow-rs v0.5.23 (https://github.com/baoyachi/shadow-rs?branch=master#eb712990) /// - registry: └── shadow-rs v0.5.23 (registry ssh://git@github.com/baoyachi/shadow-rs.git) /// - path: └── shadow-rs v0.5.23 ((/Users/baoyachi/shadow-rs)) /// /// after filter dependencies source /// /// - git: └── shadow-rs v0.5.23 (* git) /// - registry: └── shadow-rs v0.5.23 (* registry) /// - path: └── shadow-rs v0.5.23 (* path) /// pub fn filter_dep_source(input: &str) -> String { let (val, index) = if let Some(index) = input.find(" (/") { (DEP_REPLACE_PATH, index) } else if let Some(index) = input.find(" (registry ") { (DEP_REPLACE_REGISTRY, index) } else if let Some(index) = input.find(" (http") { (DEP_REPLACE_GIT, index) } else if let Some(index) = input.find(" (https") { (DEP_REPLACE_GIT, index) } else if let Some(index) = input.find(" (ssh") { (DEP_REPLACE_GIT, index) } else if let (Some(start), Some(end)) = (input.find(" ("), input.find(')')) { let path = input.get(start + 2..end).unwrap_or_default().trim(); if path_exists(path) { (DEP_REPLACE_PATH, start) } else { (DEP_REPLACE_NONE, input.len()) } } else { (DEP_REPLACE_NONE, input.len()) }; format!("{}{}", &input.get(..index).unwrap_or_default(), val) } pub fn filter_cargo_tree(lines: Vec<&str>) -> String { let mut tree = "\n".to_string(); for line in lines { let val = filter_dep_source(line); if tree.trim().is_empty() { tree.push_str(&val); } else { tree = format!("{tree}\n{val}"); } } tree } } /// 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: BUILD_OS_DOC.to_string(), v: format!("{}-{}", env::consts::OS, env::consts::ARCH), t: ConstType::Str, }, ); 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(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(BUILD_TARGET_DOC)); env.map .insert(BUILD_TARGET_ARCH, ConstVal::new(BUILD_TARGET_ARCH_DOC)); env.map.insert(PKG_VERSION, ConstVal::new(PKG_VERSION_DOC)); env.map .insert(PKG_DESCRIPTION, ConstVal::new(PKG_DESCRIPTION_DOC)); 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}"); } env.map } #[derive(Default, Debug)] 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) { // Enable reproducible builds: https://reproducible-builds.org/docs/source-date-epoch/ let time = now_date_time(); project.map.insert( BUILD_TIME, ConstVal { desc: BUILD_TIME_DOC.to_string(), v: time.human_format(), t: ConstType::Str, }, ); project.map.insert( BUILD_TIME_2822, ConstVal { desc: BUILD_TIME_2822_DOC.to_string(), v: time.to_rfc2822(), t: ConstType::Str, }, ); project.map.insert( BUILD_TIME_3339, ConstVal { desc: BUILD_TIME_3339_DOC.to_string(), v: time.to_rfc3339(), t: ConstType::Str, }, ); } pub fn new_project(std_env: &BTreeMap) -> BTreeMap { let mut project = Project::default(); build_time(&mut project); project.map.insert( BUILD_RUST_CHANNEL, ConstVal { desc: BUILD_RUST_CHANNEL_DOC.to_string(), v: build_channel().to_string(), t: ConstType::Str, }, ); project .map .insert(PROJECT_NAME, ConstVal::new(PROJECT_NAME_DOC)); if let (Some(v), Some(val)) = ( std_env.get("CARGO_PKG_NAME"), project.map.get_mut(PROJECT_NAME), ) { val.t = ConstType::Str; val.v = v.to_string(); } project.map } #[cfg(test)] mod tests { use crate::env::dep_source_replace::filter_dep_source; #[test] fn test_filter_dep_source_none() { let input = "shadow-rs v0.5.23"; let ret = filter_dep_source(input); assert_eq!(input, ret) } #[test] fn test_filter_dep_source_multi() { let input = "shadow-rs v0.5.23 (*)"; let ret = filter_dep_source(input); assert_eq!(input, ret) } #[test] fn test_filter_dep_source_path() { let input = "shadow-rs v0.5.23 (/Users/baoyachi/shadow-rs)"; let ret = filter_dep_source(input); assert_eq!("shadow-rs v0.5.23 (* path)", ret) } #[test] fn test_filter_dep_source_registry() { let input = "shadow-rs v0.5.23 (registry `ssh://git@github.com/baoyachi/shadow-rs.git`)"; let ret = filter_dep_source(input); assert_eq!("shadow-rs v0.5.23 (* registry)", ret) } #[test] fn test_filter_dep_source_git_https() { let input = "shadow-rs v0.5.23 (https://github.com/baoyachi/shadow-rs#13572c90)"; let ret = filter_dep_source(input); assert_eq!("shadow-rs v0.5.23 (* git)", ret) } #[test] fn test_filter_dep_source_git_http() { let input = "shadow-rs v0.5.23 (http://github.com/baoyachi/shadow-rs#13572c90)"; let ret = filter_dep_source(input); assert_eq!("shadow-rs v0.5.23 (* git)", ret) } #[test] fn test_filter_dep_source_git() { let input = "shadow-rs v0.5.23 (ssh://git@github.com/baoyachi/shadow-rs)"; let ret = filter_dep_source(input); assert_eq!("shadow-rs v0.5.23 (* git)", ret) } #[test] fn test_filter_dep_windows_path() { let input = r"shadow-rs v0.5.23 (FD:\a\shadow-rs\shadow-rs)"; let ret = filter_dep_source(input); assert_eq!(input, ret) } } shadow-rs-0.29.0/src/err.rs000064400000000000000000000031661046102023000135560ustar 00000000000000use std::error::Error; use std::error::Error as StdError; use std::fmt::{Display, Formatter}; use std::string::FromUtf8Error; /// Results returned by the `shadow-rs` build process. /// For more information see [`ShadowError`]. pub type SdResult = 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), } impl ShadowError { pub fn new(err: impl Error) -> Self { ShadowError::String(err.to_string()) } } impl From for ShadowError { fn from(e: FromUtf8Error) -> Self { ShadowError::String(e.to_string()) } } impl From for ShadowError { fn from(e: std::io::Error) -> Self { ShadowError::String(e.to_string()) } } impl From for ShadowError { fn from(e: String) -> Self { ShadowError::String(e) } } impl From<&str> for ShadowError { fn from(e: &str) -> Self { ShadowError::String(e.to_string()) } } impl From for ShadowError { fn from(e: std::env::VarError) -> Self { ShadowError::String(e.to_string()) } } impl From for ShadowError { fn from(e: std::num::ParseIntError) -> Self { ShadowError::String(e.to_string()) } } impl Display for ShadowError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ShadowError::String(err) => f.write_str(err), } } } impl StdError for ShadowError {} shadow-rs-0.29.0/src/gen_const.rs000064400000000000000000000072211046102023000147410ustar 00000000000000macro_rules! gen_const { ($fn_name:ident, $fn_body:expr) => { pub fn $fn_name() -> String { $fn_body.to_string() } }; } 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:{} commit_hash:{} build_time:{} build_env:{},{}"#,PKG_VERSION, BRANCH, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; 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:{} commit_hash:{} build_time:{} build_env:{},{}"#,PKG_VERSION, TAG, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; const CLAP_VERSION_BRANCH_CONST: &str = r##"#[allow(dead_code,missing_docs)] #[deprecated = "Replaced with `CLAP_LONG_VERSION`"] pub const CLAP_VERSION:&str = shadow_rs::formatcp!(r#"{} branch:{} commit_hash:{} build_time:{} build_env:{},{}"#,PKG_VERSION, BRANCH, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; const CLAP_VERSION_TAG_CONST: &str = r##"#[allow(dead_code,missing_docs)] #[deprecated = "Replaced with `CLAP_LONG_VERSION`"] pub const CLAP_VERSION:&str = shadow_rs::formatcp!(r#"{} tag:{} commit_hash:{} build_time:{} build_env:{},{}"#,PKG_VERSION, TAG, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; 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:{} build_time:{} build_env:{},{}"#,PKG_VERSION, BRANCH, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; 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:{} build_time:{} build_env:{},{}"#,PKG_VERSION, TAG, SHORT_COMMIT, BUILD_TIME, RUST_VERSION, RUST_CHANNEL );"##; 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_BRANCH_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"; #[cfg(test)] mod tests { use super::*; #[test] fn test_version_fn() { assert!(version_tag_const().contains(VERSION_TAG_CONST)); assert!(clap_version_branch_const().contains(CLAP_VERSION_BRANCH_CONST)); assert!(clap_long_version_branch_const().contains(CLAP_LONG_VERSION_BRANCH_CONST)); } } shadow-rs-0.29.0/src/git.rs000064400000000000000000000457021046102023000135530ustar 00000000000000use crate::build::{ConstType, ConstVal, ShadowConst}; use crate::ci::CiType; use crate::err::*; use std::collections::BTreeMap; 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)] pub struct Git { map: BTreeMap, ci_type: CiType, } impl Git { fn update_str(&mut self, c: ShadowConst, v: String) { if let Some(val) = self.map.get_mut(c) { *val = ConstVal { desc: val.desc.clone(), v, t: ConstType::Str, } } } fn update_bool(&mut self, c: ShadowConst, v: bool) { if let Some(val) = self.map.get_mut(c) { *val = ConstVal { desc: val.desc.clone(), v: v.to_string(), t: ConstType::Bool, } } } fn init(&mut self, path: &Path, std_env: &BTreeMap) -> SdResult<()> { // check git status let x = command_git_clean(); self.update_bool(GIT_CLEAN, x); let x = command_git_status_file(); self.update_str(GIT_STATUS_FILE, x); self.init_git2(path)?; // use command branch if let Some(x) = command_current_branch() { self.update_str(BRANCH, x) }; // use command tag if let Some(x) = command_current_tag() { self.update_str(TAG, x) } // use command get last tag if let Some(x) = command_last_tag() { self.update_str(LAST_TAG, x) } // try use ci branch,tag self.ci_branch_tag(std_env); Ok(()) } #[allow(unused_variables)] fn init_git2(&mut self, path: &Path) -> SdResult<()> { #[cfg(feature = "git2")] { use crate::date_time::DateTime; use crate::git::git2_mod::git_repo; use crate::Format; let repo = git_repo(path).map_err(ShadowError::new)?; let reference = repo.head().map_err(ShadowError::new)?; //get branch let branch = reference .shorthand() .map(|x| x.trim().to_string()) .or_else(command_current_branch) .unwrap_or_default(); //get HEAD branch let tag = command_current_tag().unwrap_or_default(); let last_tag = command_last_tag().unwrap_or_default(); self.update_str(BRANCH, branch); self.update_str(TAG, tag); self.update_str(LAST_TAG, last_tag); if let Some(v) = reference.target() { let commit = v.to_string(); self.update_str(COMMIT_HASH, commit.clone()); let mut short_commit = commit.as_str(); if commit.len() > 8 { short_commit = short_commit.get(0..8).unwrap(); } self.update_str(SHORT_COMMIT, short_commit.to_string()); } let commit = reference.peel_to_commit().map_err(ShadowError::new)?; let time_stamp = commit.time().seconds().to_string().parse::()?; let date_time = DateTime::timestamp_2_utc(time_stamp); self.update_str(COMMIT_DATE, date_time.human_format()); self.update_str(COMMIT_DATE_2822, date_time.to_rfc2822()); self.update_str(COMMIT_DATE_3339, date_time.to_rfc3339()); let author = commit.author(); if let Some(v) = author.email() { self.update_str(COMMIT_EMAIL, v.to_string()); } if let Some(v) = author.name() { self.update_str(COMMIT_AUTHOR, v.to_string()); } let status_file = Self::git2_dirty_stage(&repo); if status_file.trim().is_empty() { self.update_bool(GIT_CLEAN, true); } else { self.update_bool(GIT_CLEAN, false); } self.update_str(GIT_STATUS_FILE, status_file); } Ok(()) } //use git2 crates git repository 'dirty or stage' status files. #[cfg(feature = "git2")] pub fn git2_dirty_stage(repo: &git2::Repository) -> String { let mut repo_opts = git2::StatusOptions::new(); repo_opts.include_ignored(false); if let Ok(statue) = repo.statuses(Some(&mut repo_opts)) { let mut dirty_files = Vec::new(); let mut staged_files = Vec::new(); for status in statue.iter() { if let Some(path) = status.path() { match status.status() { git2::Status::CURRENT => (), git2::Status::INDEX_NEW | git2::Status::INDEX_MODIFIED | git2::Status::INDEX_DELETED | git2::Status::INDEX_RENAMED | git2::Status::INDEX_TYPECHANGE => staged_files.push(path.to_string()), _ => dirty_files.push(path.to_string()), }; } } filter_git_dirty_stage(dirty_files, staged_files) } else { "".into() } } #[allow(clippy::manual_strip)] fn ci_branch_tag(&mut self, std_env: &BTreeMap) { let mut branch: Option = None; let mut tag: Option = None; match self.ci_type { CiType::Gitlab => { if let Some(v) = std_env.get("CI_COMMIT_TAG") { tag = Some(v.to_string()); } else if let Some(v) = std_env.get("CI_COMMIT_REF_NAME") { branch = Some(v.to_string()); } } CiType::Github => { if let Some(v) = std_env.get("GITHUB_REF") { let ref_branch_prefix: &str = "refs/heads/"; let ref_tag_prefix: &str = "refs/tags/"; if v.starts_with(ref_branch_prefix) { branch = Some( v.get(ref_branch_prefix.len()..) .unwrap_or_default() .to_string(), ) } else if v.starts_with(ref_tag_prefix) { tag = Some( v.get(ref_tag_prefix.len()..) .unwrap_or_default() .to_string(), ) } } } _ => {} } if let Some(x) = branch { self.update_str(BRANCH, x); } if let Some(x) = tag { self.update_str(TAG, x.clone()); self.update_str(LAST_TAG, x); } } } pub fn new_git( path: &Path, ci: CiType, std_env: &BTreeMap, ) -> BTreeMap { let mut git = Git { map: Default::default(), ci_type: ci, }; git.map.insert(BRANCH, ConstVal::new(BRANCH_DOC)); git.map.insert(TAG, ConstVal::new(TAG_DOC)); git.map.insert(LAST_TAG, ConstVal::new(LAST_TAG_DOC)); git.map.insert(COMMIT_HASH, ConstVal::new(COMMIT_HASH_DOC)); git.map .insert(SHORT_COMMIT, ConstVal::new(SHORT_COMMIT_DOC)); 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_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(GIT_STATUS_FILE, ConstVal::new(GIT_STATUS_FILE_DOC)); if let Err(e) = git.init(path, std_env) { println!("{e}"); } git.map } #[cfg(feature = "git2")] pub mod git2_mod { use git2::Error as git2Error; use git2::Repository; use std::path::Path; pub fn git_repo>(path: P) -> Result { git2::Repository::discover(path) } pub fn git2_current_branch(repo: &Repository) -> Option { repo.head() .map(|x| x.shorthand().map(|x| x.to_string())) .unwrap_or(None) } } /// get current repository git branch. /// /// When current repository exists git folder. /// /// It's use default feature.This function try use [git2] crates get current branch. /// If not use git2 feature,then try use [Command] to get. pub fn branch() -> String { #[cfg(feature = "git2")] { use crate::git::git2_mod::{git2_current_branch, git_repo}; git_repo(".") .map(|x| git2_current_branch(&x)) .unwrap_or_else(|_| command_current_branch()) .unwrap_or_default() } #[cfg(not(feature = "git2"))] { command_current_branch().unwrap_or_default() } } /// get current repository git tag. /// /// When current repository exists git folder. /// I's use [Command] to get. pub fn tag() -> String { command_current_tag().unwrap_or_default() } /// Check current git Repository status without nothing(dirty or stage) /// /// if nothing,It means clean:true. On the contrary, it is 'dirty':false pub fn git_clean() -> bool { #[cfg(feature = "git2")] { use crate::git::git2_mod::git_repo; git_repo(".") .map(|x| Git::git2_dirty_stage(&x)) .map(|x| x.trim().is_empty()) .unwrap_or(true) } #[cfg(not(feature = "git2"))] { command_git_clean() } } /// List current git Repository statue(dirty or stage) contain file changed /// /// Refer to the 'cargo fix' result output when git statue(dirty or stage) changed. /// /// Example output:` * examples/builtin_fn.rs (dirty)` pub fn git_status_file() -> String { #[cfg(feature = "git2")] { use crate::git::git2_mod::git_repo; git_repo(".") .map(|x| Git::git2_dirty_stage(&x)) .unwrap_or_default() } #[cfg(not(feature = "git2"))] { command_git_status_file() } } /// Command exec git current tag fn command_current_tag() -> Option { Command::new("git") .args(["tag", "-l", "--contains", "HEAD"]) .output() .map(|x| String::from_utf8(x.stdout).ok()) .map(|x| x.map(|x| x.trim().to_string())) .unwrap_or(None) } /// git describe --tags --abbrev=0 HEAD /// Command exec git last tag fn command_last_tag() -> Option { Command::new("git") .args(["describe", "--tags", "--abbrev=0", "HEAD"]) .output() .map(|x| String::from_utf8(x.stdout).ok()) .map(|x| x.map(|x| x.trim().to_string())) .unwrap_or(None) } /// git clean:git status --porcelain /// check repository git status is clean fn command_git_clean() -> bool { Command::new("git") .args(["status", "--porcelain"]) .output() .map(|x| String::from_utf8(x.stdout).ok()) .map(|x| x.map(|x| x.trim().to_string())) .map(|x| x.is_none() || x.map(|y| y.is_empty()).unwrap_or_default()) .unwrap_or(true) } /// check git repository 'dirty or stage' status files. /// git dirty:git status --porcelain | grep '^\sM.' |awk '{print $2}' /// git stage:git status --porcelain --untracked-files=all | grep '^[A|M|D|R]'|awk '{print $2}' fn command_git_status_file() -> String { let git_status_files = move |args: &[&str], grep: &[&str], awk: &[&str]| -> SdResult> { let git_shell = Command::new("git") .args(args) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; let git_out = git_shell.stdout.ok_or("Failed to exec git stdout")?; let grep_shell = Command::new("grep") .args(grep) .stdin(Stdio::from(git_out)) .stdout(Stdio::piped()) .spawn()?; let grep_out = grep_shell.stdout.ok_or("Failed to exec grep stdout")?; let mut awk_shell = Command::new("awk") .args(awk) .stdin(Stdio::from(grep_out)) .stdout(Stdio::piped()) .spawn()?; let mut awk_out = BufReader::new( awk_shell .stdout .as_mut() .ok_or("Failed to exec awk stdout")?, ); let mut line = String::new(); awk_out.read_to_string(&mut line)?; Ok(line.lines().map(|x| x.into()).collect()) }; let dirty = git_status_files(&["status", "--porcelain"], &[r"^\sM."], &["{print $2}"]) .unwrap_or_default(); let stage = git_status_files( &["status", "--porcelain", "--untracked-files=all"], &[r#"^[A|M|D|R]"#], &["{print $2}"], ) .unwrap_or_default(); filter_git_dirty_stage(dirty, stage) } /// Command exec git current branch fn command_current_branch() -> Option { Command::new("git") .args(["symbolic-ref", "--short", "HEAD"]) .output() .map(|x| String::from_utf8(x.stdout).ok()) .map(|x| x.map(|x| x.trim().to_string())) .unwrap_or(None) } fn filter_git_dirty_stage(dirty_files: Vec, staged_files: Vec) -> String { let mut concat_file = String::new(); for file in dirty_files { concat_file.push_str(" * "); concat_file.push_str(&file); concat_file.push_str(" (dirty)\n"); } for file in staged_files { concat_file.push_str(" * "); concat_file.push_str(&file); concat_file.push_str(" (staged)\n"); } concat_file } #[cfg(test)] mod tests { use super::*; use crate::get_std_env; #[test] fn test_git() { let env_map = get_std_env(); let map = new_git(Path::new("./"), CiType::Github, &env_map); for (k, v) in map { println!("k:{},v:{:?}", k, v); assert!(!v.desc.is_empty()); if !k.eq(TAG) && !k.eq(LAST_TAG) && !k.eq(BRANCH) && !k.eq(GIT_STATUS_FILE) { assert!(!v.v.is_empty()); continue; } //assert github tag always exist value if let Some(github_ref) = env_map.get("GITHUB_REF") { if github_ref.starts_with("refs/tags/") && k.eq(TAG) { assert!(!v.v.is_empty(), "not empty"); } else if github_ref.starts_with("refs/heads/") && k.eq(BRANCH) { assert!(!v.v.is_empty()); } } } } #[test] fn test_current_branch() { if get_std_env().contains_key("GITHUB_REF") { return; } #[cfg(feature = "git2")] { use crate::git::git2_mod::{git2_current_branch, git_repo}; let git2_branch = git_repo(".") .map(|x| git2_current_branch(&x)) .unwrap_or(None); let command_branch = command_current_branch(); assert!(git2_branch.is_some()); assert!(command_branch.is_some()); assert_eq!(command_branch, git2_branch); } assert_eq!(Some(branch()), command_current_branch()); } #[test] fn test_command_last_tag() { let opt_last_tag = command_last_tag(); assert!(opt_last_tag.is_some()) } } shadow-rs-0.29.0/src/lib.rs000075500000000000000000000456751046102023000135520ustar 00000000000000#![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` allows you to access properties of the build process and environment at runtime, including: //! //! * `Cargo.toml` information, such as the project version //! * Dependency information //! * 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! //! //! You can use this crate to programmatically check where a binary came from and how it was built. //! //! # 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 //! //! ### 1) Modify `Cargo.toml` fields //! Modify your `Cargo.toml` like so: //! //! ```toml //! [package] //! build = "build.rs" //! //! [dependencies] //! shadow-rs = "{latest version}" //! //! [build-dependencies] //! shadow-rs = "{latest version}" //! ``` #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] //! //! ### 2) Create `build.rs` file //! Now in the root of your project (same directory as `Cargo.toml`) add a file `build.rs`: //! //! ```ignore //! fn main() -> shadow_rs::SdResult<()> { //! shadow_rs::new() //! } //! ``` //! //! If you want to exclude some build constants, you can use [`new_deny`] instead of [`new`]. //! //! ### 3) Integrate Shadow //! In your main Rust file (usually `main.rs` or `lib.rs`), add this: //! //! ```ignore //! use shadow_rs::shadow; //! //! shadow!(build); //! ``` //! //! The `shadow!` macro uses the given identifier to create a module with that name. //! //! ### 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!("{}", 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) //! } //! ``` //! //! ## 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). //! //! For the user guide and further documentation, see the [README of `shadow-rs`](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; mod ci; mod date_time; mod env; mod err; mod gen_const; mod git; /// Re-exported from the is_debug crate pub use is_debug::*; use build::*; use crate::ci::CiType; pub use crate::date_time::DateTime; pub use const_format::*; use std::collections::{BTreeMap, BTreeSet}; use std::env as std_env; use std::fs::File; use std::io::Write; use std::path::Path; use crate::gen_const::{ clap_long_version_branch_const, clap_long_version_tag_const, clap_version_branch_const, clap_version_tag_const, version_branch_const, version_tag_const, BUILD_CONST_CLAP_LONG_VERSION, BUILD_CONST_VERSION, }; pub use err::{SdResult, ShadowError}; pub use {build::ShadowConst, env::*, git::*}; pub trait Format { fn human_format(&self) -> String; } const SHADOW_RS: &str = "shadow.rs"; /// Add a module with the provided name which contains the build information generated by `shadow-rs`. /// /// # Example /// /// ```ignore /// use shadow_rs::shadow; /// /// shadow!(my_build_information); /// /// fn main() { /// println!("I'm version {}!", my_build_information::VERSION); /// } /// ``` /// /// The convention, however, is to use `shadow!(build);`. #[macro_export] macro_rules! shadow { ($build_mod:ident) => { #[doc = r#"shadow-rs mod"#] pub mod $build_mod { include!(concat!(env!("OUT_DIR"), "/shadow.rs")); } }; } /// Generates build information for the current project. /// This function must be called from `build.rs`. /// /// # Example /// /// ```ignore /// // build.rs /// /// fn main() -> shadow_rs::SdResult<()> { /// shadow_rs::new() /// } /// ``` pub fn new() -> SdResult<()> { Shadow::build(Default::default())?; Ok(()) } /// Identical to [`new`], but additionally accepts a build output denylist. /// This list determines constants to be excluded in the build output. /// /// 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; /// /// fn main() -> shadow_rs::SdResult<()> { /// let mut deny = BTreeSet::new(); /// deny.insert(shadow_rs::CARGO_TREE); /// shadow_rs::new_deny(deny) /// } /// ``` pub fn new_deny(deny_const: BTreeSet) -> SdResult<()> { Shadow::build(deny_const)?; Ok(()) } /// 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. /// /// # Example /// /// ```ignore /// // build.rs /// /// fn main() -> shadow_rs::SdResult<()> { /// shadow_rs::new_hook(append_write_const) /// } /// /// fn append_write_const(mut file: &File) -> SdResult<()> { /// let foo: &str = r#"pub const foo: &str = "foo";"#; /// writeln!(file, "{}", foo)?; /// Ok(()) /// } /// /// ``` pub fn new_hook(f: F) -> SdResult<()> where F: FnOnce(&File) -> SdResult<()>, { let shadow = Shadow::build(Default::default())?; shadow.hook(f) } /// 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() { env_map.insert(k, v); } 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<()>, { let desc = r#"/// Below code generated by project custom from by build.rs"#; writeln!(&self.f, "\n{desc}\n")?; f(&self.f)?; Ok(()) } /// 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" { return CiType::Gitlab; } } if let Some(c) = self.std_env.get("GITHUB_ACTIONS") { if c == "true" { return CiType::Github; } } 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")?; Self::build_inner(src_path, out_path, deny_const) } fn build_inner( src_path: String, out_path: String, deny_const: BTreeSet, ) -> SdResult { let out = { let path = Path::new(out_path.as_str()); if !out_path.ends_with('/') { path.join(format!("{out_path}/{SHADOW_RS}")) } else { path.join(SHADOW_RS) } }; let mut shadow = Shadow { f: File::create(out)?, map: Default::default(), std_env: Default::default(), deny_const, }; shadow.std_env = get_std_env(); let ci_type = shadow.try_ci(); let src_path = Path::new(src_path.as_str()); let mut map = new_git(src_path, ci_type, &shadow.std_env); for (k, v) in new_project(&shadow.std_env) { map.insert(k, v); } for (k, v) in new_system_env(&shadow.std_env) { map.insert(k, v); } shadow.map = map; // deny const shadow.filter_deny(); shadow.write_all()?; Ok(shadow) } fn filter_deny(&mut self) { self.deny_const.iter().for_each(|x| { self.map.remove(&**x); }) } fn write_all(&mut self) -> SdResult<()> { self.gen_header()?; self.gen_const()?; //write version function let gen_version = self.gen_version()?; self.gen_build_in(gen_version)?; 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); } } fn gen_const(&mut self) -> SdResult<()> { for (k, v) in self.map.clone() { println!("cargo:rerun-if-env-changed={k}"); self.write_const(k, v)?; } Ok(()) } fn gen_header(&self) -> SdResult<()> { let desc = format!( 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")?; Ok(()) } fn write_const(&mut self, shadow_const: ShadowConst, val: ConstVal) -> SdResult<()> { let desc = format!("#[doc=r#\"{}\"#]", val.desc); let define = match val.t { ConstType::OptStr => format!( "#[allow(dead_code)]\n\ #[allow(clippy::all)]\n\ pub const {} :{} = r#\"{}\"#;", shadow_const.to_ascii_uppercase(), ConstType::Str, "" ), ConstType::Str => format!( "#[allow(dead_code)]\n\ #[allow(clippy::all)]\n\ pub const {} :{} = r#\"{}\"#;", shadow_const.to_ascii_uppercase(), ConstType::Str, val.v ), ConstType::Bool => format!( "#[allow(dead_code)]\n\ pub const {} :{} = {};", shadow_const.to_ascii_uppercase(), ConstType::Bool, val.v.parse::().unwrap() ), }; writeln!(&self.f, "{desc}")?; writeln!(&self.f, "{define}\n")?; Ok(()) } fn gen_version(&mut self) -> SdResult> { let (ver_fn, clap_ver_fn, clap_long_ver_fn) = match self.map.get(TAG) { None => ( version_branch_const(), clap_version_branch_const(), clap_long_version_branch_const(), ), Some(tag) => { if !tag.v.is_empty() { ( version_tag_const(), clap_version_tag_const(), clap_long_version_tag_const(), ) } else { ( version_branch_const(), clap_version_branch_const(), clap_long_version_branch_const(), ) } } }; writeln!(&self.f, "{ver_fn}\n")?; writeln!(&self.f, "{clap_ver_fn}\n")?; writeln!(&self.f, "{clap_long_ver_fn}\n")?; Ok(vec![BUILD_CONST_VERSION, BUILD_CONST_CLAP_LONG_VERSION]) } fn gen_build_in(&self, gen_const: Vec<&'static str>) -> SdResult<()> { let mut print_val = String::from("\n"); // append gen const for k in self.map.keys() { let tmp = format!(r#"{}println!("{k}:{{{k}}}\n");{}"#, "\t", "\n"); print_val.push_str(tmp.as_str()); } // append gen fn for k in gen_const { let tmp = format!(r#"{}println!("{k}:{{{k}}}\n");{}"#, "\t", "\n"); print_val.push_str(tmp.as_str()); } let everything_define = format!( "/// Prints all built-in `shadow-rs` build constants to standard output.\n\ #[allow(dead_code)]\n\ pub fn print_build_in() {\ {{print_val}}\ }\n", ); writeln!(&self.f, "{everything_define}")?; Ok(()) } } #[cfg(test)] mod tests { use super::*; use std::fs; #[test] fn test_build() -> SdResult<()> { Shadow::build_inner("./".into(), "./".into(), Default::default())?; let shadow = fs::read_to_string("./shadow.rs")?; assert!(!shadow.is_empty()); assert!(shadow.lines().count() > 0); println!("{shadow}"); Ok(()) } #[test] fn test_build_deny() -> SdResult<()> { let mut deny = BTreeSet::new(); deny.insert(CARGO_TREE); Shadow::build_inner("./".into(), "./".into(), deny)?; let shadow = fs::read_to_string("./shadow.rs")?; assert!(!shadow.is_empty()); assert!(shadow.lines().count() > 0); println!("{shadow}"); let expect = "pub const CARGO_TREE :&str"; assert!(!shadow.contains(expect)); Ok(()) } #[test] fn test_env() { for (k, v) in std::env::vars() { println!("K:{k},V:{v}"); } } }