Skip to content

Commit f19436d

Browse files
committed
Show fabric build version
1 parent 77140bc commit f19436d

10 files changed

Lines changed: 92 additions & 6 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fabric"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
edition = "2024"
55

66
[dependencies]

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ endpoint allow-list.
9191

9292
## Commands
9393

94+
```sh
95+
fabric --version
96+
```
97+
98+
Print the installed build version as `<semver>+<short-git-sha>`.
99+
94100
```sh
95101
fabric key gen --out <path>
96102
```
@@ -118,6 +124,7 @@ fabric status
118124
Show the running daemon's local state and echo-ping every trusted peer. Each
119125
peer is reported as reachable or unreachable with round-trip latency and, when
120126
iroh exposes it, the active transport path: `direct`, `relay`, or `mixed`.
127+
Status also prints the daemon build version.
121128

122129
```sh
123130
fabric add <nodeid> [name] [--addr-json JSON]

build.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use std::{env, process::Command};
2+
3+
fn main() {
4+
println!("cargo:rerun-if-env-changed=GITHUB_SHA");
5+
println!("cargo:rerun-if-changed=.git/HEAD");
6+
7+
let sha = env::var("GITHUB_SHA")
8+
.ok()
9+
.and_then(|sha| short_sha(&sha))
10+
.or_else(git_sha)
11+
.unwrap_or_else(|| "unknown".to_string());
12+
println!("cargo:rustc-env=FABRIC_BUILD_SHA={sha}");
13+
}
14+
15+
fn git_sha() -> Option<String> {
16+
let output = Command::new("git")
17+
.args(["rev-parse", "--short=7", "HEAD"])
18+
.output()
19+
.ok()?;
20+
if !output.status.success() {
21+
return None;
22+
}
23+
let sha = String::from_utf8(output.stdout).ok()?;
24+
short_sha(sha.trim())
25+
}
26+
27+
fn short_sha(sha: &str) -> Option<String> {
28+
let sha = sha.trim();
29+
if sha.is_empty() {
30+
None
31+
} else {
32+
Some(sha.chars().take(7).collect())
33+
}
34+
}

src/control.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub enum ControlResponse {
2626
dial_sockets: Vec<PathBuf>,
2727
},
2828
ReachabilityStatus {
29+
version: String,
2930
node_id: String,
3031
endpoint_addr: serde_json::Value,
3132
exposed_protocols: Vec<String>,

src/daemon.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ impl DaemonState {
247247
self.local_status_fields().await?;
248248
let peers = self.peer_reachability().await;
249249
Ok(ControlResponse::ReachabilityStatus {
250+
version: crate::version_string(),
250251
node_id,
251252
endpoint_addr,
252253
exposed_protocols,

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ pub mod shell;
1212

1313
const SPIKE_ALPN: &[u8] = b"fabric/spike/echo/0";
1414

15+
pub fn version_string() -> String {
16+
format!(
17+
"{}+{}",
18+
env!("CARGO_PKG_VERSION"),
19+
option_env!("FABRIC_BUILD_SHA").unwrap_or("unknown")
20+
)
21+
}
22+
1523
pub async fn iroh_spike_round_trip(payload: &[u8]) -> Result<Vec<u8>> {
1624
let router = start_spike_accept_side().await?;
1725
router.endpoint().online().await;

src/main.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{
77
};
88

99
use anyhow::{Result, bail};
10-
use clap::{Parser, Subcommand};
10+
use clap::{CommandFactory, Parser, Subcommand};
1111
use fabric::{
1212
config::{
1313
FabricHome, PeerBook, generate_identity_file, load_or_create_identity, parse_addr_json,
@@ -23,11 +23,14 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
2323
#[command(name = "fabric")]
2424
#[command(about = "Local socket facade for iroh-backed cross-machine transports")]
2525
struct Cli {
26+
#[arg(long)]
27+
version: bool,
28+
2629
#[arg(long, global = true)]
2730
home: Option<PathBuf>,
2831

2932
#[command(subcommand)]
30-
command: Commands,
33+
command: Option<Commands>,
3134
}
3235

3336
#[derive(Debug, Subcommand)]
@@ -99,8 +102,18 @@ enum KeyCommands {
99102
#[tokio::main]
100103
async fn main() -> Result<()> {
101104
let cli = Cli::parse();
105+
if cli.version {
106+
println!("{}", fabric::version_string());
107+
return Ok(());
108+
}
109+
110+
let Some(command) = cli.command else {
111+
Cli::command().print_help()?;
112+
println!();
113+
return Ok(());
114+
};
102115

103-
match cli.command {
116+
match command {
104117
Commands::Key {
105118
command: KeyCommands::Gen { out },
106119
} => {
@@ -124,13 +137,15 @@ async fn main() -> Result<()> {
124137
Commands::Status => {
125138
match send_control(&home, ControlRequest::ReachabilityStatus).await? {
126139
ControlResponse::ReachabilityStatus {
140+
version,
127141
node_id,
128142
endpoint_addr,
129143
exposed_protocols,
130144
dial_sockets,
131145
peers,
132146
} => {
133147
print_status(
148+
&version,
134149
&node_id,
135150
&endpoint_addr,
136151
&exposed_protocols,
@@ -240,12 +255,14 @@ async fn main() -> Result<()> {
240255
}
241256

242257
fn print_status(
258+
version: &str,
243259
node_id: &str,
244260
endpoint_addr: &serde_json::Value,
245261
exposed_protocols: &[String],
246262
dial_sockets: &[PathBuf],
247263
peers: &[PeerReachability],
248264
) -> Result<()> {
265+
println!("version\t{version}");
249266
println!("node\t{node_id}");
250267
println!("addr\t{}", serde_json::to_string(endpoint_addr)?);
251268
println!("exposed\t{}", joined_or_dash(exposed_protocols));

tests/local_slice.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,10 @@ async fn status_reports_peer_reachability() -> Result<()> {
237237
.await?;
238238

239239
let response = send_control(&node_b_home, ControlRequest::ReachabilityStatus).await?;
240-
let ControlResponse::ReachabilityStatus { peers, .. } = response else {
240+
let ControlResponse::ReachabilityStatus { version, peers, .. } = response else {
241241
panic!("unexpected response: {response:?}");
242242
};
243+
assert_eq!(version, fabric::version_string());
243244
let peer = peers
244245
.iter()
245246
.find(|peer| peer.name.as_deref() == Some("node-a"))

tests/provisioning.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,23 @@ fn key_gen_writes_identity_consumed_by_id() -> Result<()> {
4949
Ok(())
5050
}
5151

52+
#[test]
53+
fn version_flag_prints_semver_and_build_sha() -> Result<()> {
54+
let version = stdout(
55+
Command::new(fabric_bin())
56+
.arg("--version")
57+
.output()
58+
.context("failed to run fabric --version")?,
59+
)?;
60+
let prefix = format!("{}+", env!("CARGO_PKG_VERSION"));
61+
assert!(
62+
version.starts_with(&prefix),
63+
"version {version:?} did not start with {prefix:?}"
64+
);
65+
assert!(version.len() > prefix.len());
66+
Ok(())
67+
}
68+
5269
#[test]
5370
fn peers_lists_declarative_config_without_add() -> Result<()> {
5471
let temp = TempDir::new()?;

0 commit comments

Comments
 (0)