10000 feat: Add version information to CLI tools by frobware · Pull Request #1551 · bpfman/bpfman · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: Add version information to CLI tools #1551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 2, 2025

Conversation

frobware
Copy link
Contributor
@frobware frobware commented May 16, 2025

Fixes #1398.

This PR introduces standardised version information to all of bpfman’s CLI binaries (except bpf-log-exporter, which has no prior argument parsing), making the --version and -V flags available for all top-level commands.

All CLI tools now embed standardised version metadata using a shared buildinfo crate and a single API (generate_version_info()) called from each binary’s build script. The version string includes the package version (from Cargo.toml), the Git commit hash (with a dirty-state indicator if the working tree is not clean), the build timestamp (overridable via environment variable for CI), the Rust compiler version, and the Git repository origin URL (from the origin remote).

The version strings provide valuable context for debugging, support, and reproducibility.

Examples

% cargo run -q -p bpfman -- -V
bpfman 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T11:34:11Z) rustc 1.87.0 (17067e9ac 2025-05-09)

Changing the Rust toolchain is reflected in the version string:

rustup default nightly
cargo run -q -p bpfman -- --version
bpfman 0.5.6 (1611bec506-dirty https://github.com/frobware/bpfman 2025-05-16T14:52:21Z) rustc 1.88.0-nightly (b45dd71d1 2025-04-30)

Set a custom build timestamp (e.g., in CI):

% cargo run -q -p bpfman -- -V
bpfman 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T11:34:11Z) rustc 1.87.0 (17067e9ac 2025-05-09)
% BPFMAN_BUILD_TIMESTAMP="now" cargo run -q -p bpfman -- --version

bpfman 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman now) rustc 1.87.0 (17067e9ac 2025-05-09)

Summary

  • Each binary’s build info reflects the state at the last time its build.rs was triggered. Timestamps across binaries will vary unless you set a common env var (e.g., in CI).
  • Modifying a build.rs, Cargo.toml, or any source file for a binary triggers an update to that binary’s embedded version string (timestamp, git commit, dirty status).
  • If you build, then commit, then build again (with no other changes), Cargo won’t rebuild, so the version info (including git commit count) remains as it was for the last actual build—this is expected and correct due to incremental build caching.
  • To guarantee version info reflects the latest commit, ensure something triggers a rebuild (e.g., run cargo clean before building).

@frobware frobware requested a review from a team as a code owner May 16, 2025 15:09
@frobware frobware force-pushed the add-version-info-to-cli-commands branch 3 times, most recently from edbcfb5 to 4b17bce Compare May 16, 2025 15:26
@frobware frobware force-pushed the add-version-info-to-cli-commands branch from 4b17bce to c24db43 Compare May 20, 2025 15:13
Copy link
codecov bot commented May 20, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 0.00%. Comparing base (67fb271) to head (fa17c15).
Report is 15 commits behind head on main.

Additional details and impacted files
@@     Coverage Diff      @@
##   main   #1551   +/-   ##
============================
============================

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dave-tucker
Copy link
Collaborator

Adding a hold label while we do some testing.

@frobware are you sure this is working as expected?

If I check out your PR and do cargo build I get the following output.

$ ./target/debug/bpfman -V
bpfman 0.5.6 (c24db43080 https://github.com/bpfman/bpfman 2025-05-20T15:45:23Z) rustc 1.85.1 (4eb161250 2025-03-15)

If I then make the tree dirty - by adding a println! into src/bpfman/lib.rs - and run cargo build again I get the following output:

$ ./target/debug/bpfman -V
bpfman 0.5.6 (c24db43080 https://github.com/bpfman/bpfman 2025-05-20T15:45:23Z) rustc 1.85.1 (4eb161250 2025-03-15)

The I commit my change, rebuild, and get the following output:

$ ./target/debug/bpfman -V
bpfman 0.5.6 (c24db43080 https://github.com/bpfman/bpfman 2025-05-20T15:45:23Z) rustc 1.85.1 (4eb161250 2025-03-15)

I believe this is because of the following:

pub fn generate_version_info() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-env-changed=BPFMAN_BUILD_TIMESTAMP");
    println!("cargo:rustc-env=BPFMAN_BUILD_INFO={}", build_info_string());
}

That's only ever going to re-compute the version information if build.rs is changed, or Cargo.toml changes.
So in effect, the information on git SHA, build time, rust toolchain etc... is stale.

@frobware
Copy link
Contributor Author

Adding a hold label while we do some testing.

@frobware are you sure this is working as expected?

If I check out your PR and do cargo build I get the following output.

$ ./target/debug/bpfman -V
bpfman 0.5.6 (c24db43080 https://github.com/bpfman/bpfman 2025-05-20T15:45:23Z) rustc 1.85.1 (4eb161250 2025-03-15)

If I then make the tree dirty - by adding a println! into src/bpfman/lib.rs - and run cargo build again I get the following output:

$ ./target/debug/bpfman -V
bpfman 0.5.6 (c24db43080 https://github.com/bpfman/bpfman 2025-05-20T15:45:23Z) rustc 1.85.1 (4eb161250 2025-03-15)

The I commit my change, rebuild, and get the following output:

$ ./target/debug/bpfman -V
bpfman 0.5.6 (c24db43080 https://github.com/bpfman/bpfman 2025-05-20T15:45:23Z) rustc 1.85.1 (4eb161250 2025-03-15)

I believe this is because of the following:

pub fn generate_version_info() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-env-changed=BPFMAN_BUILD_TIMESTAMP");
    println!("cargo:rustc-env=BPFMAN_BUILD_INFO={}", build_info_string());
}

That's only ever going to re-compute the version information if build.rs is changed, or Cargo.toml changes. So in effect, the information on git SHA, build time, rust toolchain etc... is stale.

In CI, I believe this would be acceptable. In development, I did implement reruns for .git and HEAD branch changes, but this caused Cargo to relink even when there were no changes. A change followed by cargo build, and then another cargo build, would trigger a relink again, which I found a bit irritating and surprising. I can investigate further if we want it to be more dynamic during development builds.

This change introduces version information to all bpfman's CLI binaries, enabling
the --version flag on all top-level commands. The version details provide valuable
build context for debugging and support.

The implementation:
- Creates a new shared 'buildinfo' crate to centralise version generation logic
- Produces detailed version information including:
  * Package version from Cargo.toml
  * Git commit hash with dirty state indicator
  * Build timestamp
  * Rust compiler version
- Exposes a minimal public API through a single generate_version_info() function
- Enables --version/-V flags for all CLI tools (bpfman, bpfman-rpc, bpfman-ns, bpf-metrics-exporter)
- Uses namespaced BPFMAN_BUILD_INFO environment variable for version info
- Preserves the existing behaviour in subcommands (no version flags at subcommand level)
- Handles tarball builds gracefully by omitting git information when unavailable

If the BPFMAN_BUILD_TIMESTAMP environment variable is set and not
empty, its value is used as the build timestamp in the computed
version string. This can be useful in CI environments, where setting a
fixed timestamp ensures that all produced binaries from a given build
pipeline share the same version timestamp for traceability and
reproducibility.

The version string also includes the Git repository origin (as
configured for the 'origin' remote), enabling clear distinction
between upstream, downstream, and forked builds. This is especially
useful for debugging and support scenarios where identical commit
hashes might exist across different remotes. The repository URL is
automatically detected at build time from the output of `git config
--get remote.origin.url`, and is omitted if unavailable (e.g., in a
tarball or detached source build).

Example output:

% cargo run -p bpfman -- --version
   Compiling buildinfo v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/buildinfo)
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.39s
     Running `target/debug/bpfman --version`
bpfman 0.5.6 (65a2c97270-dirty https://github.com/frobware/bpfman 2025-05-16T14:48:03Z) rustc 1.88.0-nightly (b45dd71d1 2025-04-30)

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
@frobware
Copy link
Contributor Author

I added src to the trigger:

pub fn generate_version_info() {
    println!("cargo:rerun-if-changed=src");
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-env-changed=BPFMAN_BUILD_TIMESTAMP");
    println!("cargo:rustc-env=BPFMAN_BUILD_INFO={}", build_info_string());
}

Plus some testing:

#!/usr/bin/env bash

print_build_info() {
    for bin in bpfman bpfman-ns bpfman-rpc; do
        ./target/debug/"$bin" -V
    done
}

modify_src() {
    local bin="$1"
    local file="$bin/src/lib.rs"
    if [[ -f "$file" ]]; then
        echo "// dummy change to trigger rebuild" >> "$file"
        echo "Touched: $file"
    else
        echo "File not found: $file"
    fi
}

Initial build

$ source ~/version-test.sh

% cargo clean
     Removed 5658 files, 4.0GiB total  ]  83.96%
%
% cargo build -q
% print_build_info
bpfman 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:57Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-ns 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:57:00Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-rpc 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:59Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)

Note slight variations in the build timestamps. To be expected.

Re-run:

% cargo build
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s

% print_build_info
bpfman 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:57Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-ns 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:57:00Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-rpc 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:59Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)

Touch one of the triggers, in this case bpfman/build.rs.

% fd build.rs
bpf-metrics-exporter/build.rs
bpfman/build.rs
bpfman-api/build.rs
bpfman-ns/build.rs

% touch bpfman/build.rs

% cargo build
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
   Compiling bpfman-api v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman-api)
   Compiling bpf-metrics-exporter v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpf-metrics-exporter)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.99s

% print_build_info
bpfman 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:59:17Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-ns 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:57:00Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-rpc 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:59Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)

Make a modification to bpfman/src/lib.rs:

% modify_src bpfman
Touched: bpfman/src/lib.rs

% git diff
diff --git a/bpfman/src/lib.rs b/bpfman/src/lib.rs
index 209a4d20..ddead20b 100644
--- a/bpfman/src/lib.rs
+++ b/bpfman/src/lib.rs
@@ -2063,3 +2063,4 @@ fn get_map(id: u32, root_db: &Db) -> Option<sled::Tree> {
         .find(|n| bytes_to_string(n) == format!("{}{}", MAP_PREFIX, id))
         .map(|n| root_db.open_tree(n).expect("unable to open map tree"))
 }
+// dummy change to trigger rebuild

% cargo build
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
   Compiling bpfman-api v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman-api)
   Compiling bpf-metrics-exporter v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpf-metrics-exporter)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.93s

% print_build_info
bpfman 0.5.6 (v0.5.6-127-gfa17c153-dirty https://github.com/frobware/bpfman 2025-05-21T11:00:47Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-ns 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:57:00Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-rpc 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:59Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)

Commit the file/change.

% git commit -m 'dummy change to bpfman/src/lib.rs' bpfman/src/lib.rs
[add-version-info-to-cli-commands 00228145] dummy change to bpfman/src/lib.rs
 1 file changed, 1 insertion(+)

% cargo build
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s

% print_build_info
bpfman 0.5.6 (v0.5.6-127-gfa17c153-dirty https://github.com/frobware/bpfman 2025-05-21T11:00:47Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-ns 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:57:00Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-rpc 0.5.6 (v0.5.6-127-gfa17c153 https://github.com/frobware/bpfman 2025-05-21T10:56:59Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)

The previous build was a no-op because we had already built the change but technically the number of commits post the tag is actually 128. Not sure what to do about this edge case.

% git describe --tags --always --dirty
v0.5.6-128-g00228145

Switch from nightly to stable

% rustup default stable
info: using existing install for 'stable-x86_64-unknown-linux-gnu'
info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'

  stable-x86_64-unknown-linux-gnu unchanged - rustc 1.87.0 (17067e9ac 2025-05-09)

% cargo build -q

% print_build_info
bpfman 0.5.6 (v0.5.6-128-g00228145 https://github.com/frobware/bpfman 2025-05-21T11:07:59Z) rustc 1.87.0 (17067e9ac 2025-05-09)
bpfman-ns 0.5.6 (v0.5.6-128-g00228145 https://github.com/frobware/bpfman 2025-05-21T11:08:02Z) rustc 1.87.0 (17067e9ac 2025-05-09)
bpfman-rpc 0.5.6 (v0.5.6-128-g00228145 https://github.com/frobware/bpfman 2025-05-21T11:08:00Z) rustc 1.87.0 (17067e9ac 2025-05-09)

Bump project version:

% cargo set-version 0.5.7 --exclude bpfman-csi
   Upgrading workspace version from 0.5.6 to 0.5.7
   Upgrading bpf-log-exporter from 0.5.6 to 0.5.7 (inherited from workspace)
   Upgrading bpf-metrics-exporter from 0.5.6 to 0.5.7 (inherited from workspace)
   Upgrading bpfman from 0.5.6 to 0.5.7 (inherited from workspace)
    Updating workspace's dependency from 0.5.6 to 0.5.7
   Upgrading bpfman-api from 0.5.6 to 0.5.7 (inherited from workspace)
    Updating workspace's dependency from 0.5.6 to 0.5.7
   Upgrading bpfman-ns from 0.5.6 to 0.5.7 (inherited from workspace)
   Upgrading buildinfo from 0.5.6 to 0.5.7 (inherited from workspace)
    Updating workspace's dependency from 0.5.6 to 0.5.7
   Upgrading integration-test from 0.5.6 to 0.5.7 (inherited from workspace)
   Upgrading xtask from 0.5.6 to 0.5.7 (inherited from workspace)

% cargo build -q

% print_build_info
bpfman 0.5.7 (v0.5.6-128-g00228145-dirty https://github.com/frobware/bpfman 2025-05-21T11:15:45Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-ns 0.5.7 (v0.5.6-128-g00228145-dirty https://github.com/frobware/bpfman 2025-05-21T11:15:45Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)
bpfman-rpc 0.5.7 (v0.5.6-128-g00228145-dirty https://github.com/frobware/bpfman 2025-05-21T11:15:45Z) rustc 1.89.0-nightly (d97326eab 2025-05-15)

@frobware frobware force-pushed the add-version-info-to-cli-commands branch from c24db43 to fa17c15 Compare May 21, 2025 11:24
@frobware
Copy link
Contributor Author

The edge case where you make a change, build, then commit, then build again could be addressed by adding:

println!("cargo:rerun-if-changed=.git/HEAD");

and that does work:

% modify_src bpfman
Touched: bpfman/src/lib.rs

% cargo run -p bpfman -- -V
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.30s
     Running `target/debug/bpfman -V`
bpfman 0.5.6 (v0.5.6-127-gfa17c153-dirty https://github.com/frobware/bpfman 2025-05-21T11:56:53Z) rustc 1.87.0 (17067e9ac 2025-05-09)

# Now commit the change, and:

% cargo run -p bpfman -- -V
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.31s
     Running `target/debug/bpfman -V`
bpfman 0.5.6 (v0.5.6-128-g9f8f3e9e-dirty https://github.com/frobware/bpfman 2025-05-21T11:57:04Z) rustc 1.87.0 (17067e9ac 2025-05-09)

However, running cargo build repeatedly without making any changes means that you will always relink:

% cargo run -p bpfman -- -V
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.31s
     Running `target/debug/bpfman -V`
bpfman 0.5.6 (v0.5.6-128-g9f8f3e9e-dirty https://github.com/frobware/bpfman 2025-05-21T11:59:44Z) rustc 1.87.0 (17067e9ac 2025-05-09)

% cargo run -p bpfman -- -V
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.31s
     Running `target/debug/bpfman -V`
bpfman 0.5.6 (v0.5.6-128-g9f8f3e9e-dirty https://github.com/frobware/bpfman 2025-05-21T11:59:46Z) rustc 1.87.0 (17067e9ac 2025-05-09)

% cargo run -p bpfman -- -V
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.31s
     Running `target/debug/bpfman -V`
bpfman 0.5.6 (v0.5.6-128-g9f8f3e9e-dirty https://github.com/frobware/bpfman 2025-05-21T11:59:48Z) rustc 1.87.0 (17067e9ac 2025-05-09)

which is admittedly a bit weird if the trigger is based on timestamps:

% stat .git/HEAD
  File: .git/HEAD
  Size: 49              Blocks: 8          IO Block: 4096   regular file
Device: 0,57    Inode: 80002533    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/     aim)   Gid: (  100/   users)
Access: 2025-05-21 12:24:19.633230835 +0100
Modify: 2025-05-21 12:24:19.536232266 +0100
Change: 2025-05-21 12:24:19.536232266 +0100
 Birth: 2025-05-21 12:24:19.536232266 +0100

% sleep 2; cargo build
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
   Compiling bpfman-api v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman-api)
   Compiling bpf-metrics-exporter v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpf-metrics-exporter)
   Compiling bpfman-ns v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman-ns)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.04s

% stat .git/HEAD
  File: .git/HEAD
  Size: 49              Blocks: 8          IO Block: 4096   regular file
Device: 0,57    Inode: 80002533    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/     aim)   Gid: (  100/   users)
Access: 2025-05-21 12:24:19.633230835 +0100
Modify: 2025-05-21 12:24:19.536232266 +0100
Change: 2025-05-21 12:24:19.536232266 +0100
 Birth: 2025-05-21 12:24:19.536232266 +0100

% sleep 2; cargo build
   Compiling bpfman v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman)
   Compiling bpfman-api v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman-api)
   Compiling bpfman-ns v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpfman-ns)
   Compiling bpf-metrics-exporter v0.5.6 (/home/aim/src/github.com/bpfman/bpfman/bpf-metrics-exporter)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.07s

@dave-tucker dave-tucker removed the hold label Jun 2, 2025
@dave-tucker
Copy link
Collaborator

@frobware thanks! looks like this is working as expected now. LGTM

@dave-tucker dave-tucker merged commit 3a0f12c into bpfman:main Jun 2, 2025
18 checks passed
@frobware frobware deleted the add-version-info-to-cli-commands branch June 2, 2025 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add version option or command to bpfman CLI tools
2 participants
0