Add comprehensive build identification to agent
- Add git hash (short and full), branch, commit date
- Add build timestamp and dirty/clean state
- Add build profile (debug/release) and target triple
- New `version-info` command shows all build details
- `--version` now shows version-hash format (e.g., 0.1.0-4614df04)
- Startup logs now include version hash and build info
Example output:
GuruConnect v0.1.0
Git: 4614df04 (clean)
Branch: main
Commit: 2025-12-30 06:30:28 -0700
Built: 2025-12-30 15:25:20 UTC
Profile: release
Target: x86_64-pc-windows-msvc
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,7 @@ windows-service = "0.7"
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
prost-build = "0.13"
|
prost-build = "0.13"
|
||||||
winres = "0.1"
|
winres = "0.1"
|
||||||
|
chrono = "0.4"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "guruconnect"
|
name = "guruconnect"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// Compile protobuf definitions
|
// Compile protobuf definitions
|
||||||
@@ -7,6 +8,71 @@ fn main() -> Result<()> {
|
|||||||
// Rerun if proto changes
|
// Rerun if proto changes
|
||||||
println!("cargo:rerun-if-changed=../proto/guruconnect.proto");
|
println!("cargo:rerun-if-changed=../proto/guruconnect.proto");
|
||||||
|
|
||||||
|
// Rerun if git HEAD changes (new commits)
|
||||||
|
println!("cargo:rerun-if-changed=../.git/HEAD");
|
||||||
|
println!("cargo:rerun-if-changed=../.git/index");
|
||||||
|
|
||||||
|
// Build timestamp (UTC)
|
||||||
|
let build_timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string();
|
||||||
|
println!("cargo:rustc-env=BUILD_TIMESTAMP={}", build_timestamp);
|
||||||
|
|
||||||
|
// Git commit hash (short)
|
||||||
|
let git_hash = Command::new("git")
|
||||||
|
.args(["rev-parse", "--short=8", "HEAD"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
||||||
|
|
||||||
|
// Git commit hash (full)
|
||||||
|
let git_hash_full = Command::new("git")
|
||||||
|
.args(["rev-parse", "HEAD"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
println!("cargo:rustc-env=GIT_HASH_FULL={}", git_hash_full);
|
||||||
|
|
||||||
|
// Git branch name
|
||||||
|
let git_branch = Command::new("git")
|
||||||
|
.args(["rev-parse", "--abbrev-ref", "HEAD"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
println!("cargo:rustc-env=GIT_BRANCH={}", git_branch);
|
||||||
|
|
||||||
|
// Git dirty state (uncommitted changes)
|
||||||
|
let git_dirty = Command::new("git")
|
||||||
|
.args(["status", "--porcelain"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.map(|o| !o.stdout.is_empty())
|
||||||
|
.unwrap_or(false);
|
||||||
|
println!("cargo:rustc-env=GIT_DIRTY={}", if git_dirty { "dirty" } else { "clean" });
|
||||||
|
|
||||||
|
// Git commit date
|
||||||
|
let git_commit_date = Command::new("git")
|
||||||
|
.args(["log", "-1", "--format=%ci"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
println!("cargo:rustc-env=GIT_COMMIT_DATE={}", git_commit_date);
|
||||||
|
|
||||||
|
// Build profile (debug/release)
|
||||||
|
let profile = std::env::var("PROFILE").unwrap_or_else(|_| "unknown".to_string());
|
||||||
|
println!("cargo:rustc-env=BUILD_PROFILE={}", profile);
|
||||||
|
|
||||||
|
// Target triple
|
||||||
|
let target = std::env::var("TARGET").unwrap_or_else(|_| "unknown".to_string());
|
||||||
|
println!("cargo:rustc-env=BUILD_TARGET={}", target);
|
||||||
|
|
||||||
// On Windows, embed the manifest for UAC elevation
|
// On Windows, embed the manifest for UAC elevation
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,66 @@ pub mod proto {
|
|||||||
include!(concat!(env!("OUT_DIR"), "/guruconnect.rs"));
|
include!(concat!(env!("OUT_DIR"), "/guruconnect.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build information embedded at compile time
|
||||||
|
pub mod build_info {
|
||||||
|
/// Cargo package version (from Cargo.toml)
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
/// Git commit hash (short, 8 chars)
|
||||||
|
pub const GIT_HASH: &str = env!("GIT_HASH");
|
||||||
|
|
||||||
|
/// Git commit hash (full)
|
||||||
|
pub const GIT_HASH_FULL: &str = env!("GIT_HASH_FULL");
|
||||||
|
|
||||||
|
/// Git branch name
|
||||||
|
pub const GIT_BRANCH: &str = env!("GIT_BRANCH");
|
||||||
|
|
||||||
|
/// Git dirty state ("clean" or "dirty")
|
||||||
|
pub const GIT_DIRTY: &str = env!("GIT_DIRTY");
|
||||||
|
|
||||||
|
/// Git commit date
|
||||||
|
pub const GIT_COMMIT_DATE: &str = env!("GIT_COMMIT_DATE");
|
||||||
|
|
||||||
|
/// Build timestamp (UTC)
|
||||||
|
pub const BUILD_TIMESTAMP: &str = env!("BUILD_TIMESTAMP");
|
||||||
|
|
||||||
|
/// Build profile (debug/release)
|
||||||
|
pub const BUILD_PROFILE: &str = env!("BUILD_PROFILE");
|
||||||
|
|
||||||
|
/// Target triple (e.g., x86_64-pc-windows-msvc)
|
||||||
|
pub const BUILD_TARGET: &str = env!("BUILD_TARGET");
|
||||||
|
|
||||||
|
/// Short version string for display (version + git hash)
|
||||||
|
pub fn short_version() -> String {
|
||||||
|
if GIT_DIRTY == "dirty" {
|
||||||
|
format!("{}-{}-dirty", VERSION, GIT_HASH)
|
||||||
|
} else {
|
||||||
|
format!("{}-{}", VERSION, GIT_HASH)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Full version string with all details
|
||||||
|
pub fn full_version() -> String {
|
||||||
|
format!(
|
||||||
|
"GuruConnect v{}\n\
|
||||||
|
Git: {} ({})\n\
|
||||||
|
Branch: {}\n\
|
||||||
|
Commit: {}\n\
|
||||||
|
Built: {}\n\
|
||||||
|
Profile: {}\n\
|
||||||
|
Target: {}",
|
||||||
|
VERSION,
|
||||||
|
GIT_HASH,
|
||||||
|
GIT_DIRTY,
|
||||||
|
GIT_BRANCH,
|
||||||
|
GIT_COMMIT_DATE,
|
||||||
|
BUILD_TIMESTAMP,
|
||||||
|
BUILD_PROFILE,
|
||||||
|
BUILD_TARGET
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use tracing::{info, error, warn, Level};
|
use tracing::{info, error, warn, Level};
|
||||||
@@ -46,7 +106,7 @@ use windows::Win32::UI::WindowsAndMessaging::{ShowWindow, SW_SHOW};
|
|||||||
/// GuruConnect Remote Desktop
|
/// GuruConnect Remote Desktop
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "guruconnect")]
|
#[command(name = "guruconnect")]
|
||||||
#[command(version, about = "Remote desktop agent and viewer")]
|
#[command(version = concat!(env!("CARGO_PKG_VERSION"), "-", env!("GIT_HASH")), about = "Remote desktop agent and viewer")]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Option<Commands>,
|
command: Option<Commands>,
|
||||||
@@ -102,6 +162,10 @@ enum Commands {
|
|||||||
/// The guruconnect:// URL to handle
|
/// The guruconnect:// URL to handle
|
||||||
url: String,
|
url: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Show detailed version and build information
|
||||||
|
#[command(name = "version-info")]
|
||||||
|
VersionInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
@@ -115,7 +179,8 @@ fn main() -> Result<()> {
|
|||||||
.with_thread_ids(true)
|
.with_thread_ids(true)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
info!("GuruConnect v{}", env!("CARGO_PKG_VERSION"));
|
info!("GuruConnect {} ({})", build_info::short_version(), build_info::BUILD_TARGET);
|
||||||
|
info!("Built: {} | Commit: {}", build_info::BUILD_TIMESTAMP, build_info::GIT_COMMIT_DATE);
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Some(Commands::Agent { code }) => {
|
Some(Commands::Agent { code }) => {
|
||||||
@@ -133,6 +198,13 @@ fn main() -> Result<()> {
|
|||||||
Some(Commands::Launch { url }) => {
|
Some(Commands::Launch { url }) => {
|
||||||
run_launch(&url)
|
run_launch(&url)
|
||||||
}
|
}
|
||||||
|
Some(Commands::VersionInfo) => {
|
||||||
|
// Show detailed version info (allocate console on Windows for visibility)
|
||||||
|
#[cfg(windows)]
|
||||||
|
show_debug_console();
|
||||||
|
println!("{}", build_info::full_version());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
// Legacy mode: if a support code was provided, run as agent
|
// Legacy mode: if a support code was provided, run as agent
|
||||||
if let Some(code) = cli.support_code {
|
if let Some(code) = cli.support_code {
|
||||||
|
|||||||
Reference in New Issue
Block a user