Christoffer Martinsson 17b5921d8d Fix dashboard -V to show cm-dashboard package hash not system hash
Make dashboard -V show the same hash as the agent by extracting
the hash from the dashboard binary's nix store path instead of
the system configuration path. Now both will show identical
hashes since they're from the same cm-dashboard package.
2025-10-25 14:45:26 +02:00

103 lines
3.0 KiB
Rust

use anyhow::Result;
use clap::Parser;
use tracing::{error, info};
use tracing_subscriber::EnvFilter;
mod app;
mod communication;
mod config;
mod metrics;
mod ui;
use app::Dashboard;
/// Get version showing cm-dashboard package hash for easy rebuild verification
fn get_version() -> &'static str {
// Get the path of the current executable
let exe_path = std::env::current_exe().expect("Failed to get executable path");
let exe_str = exe_path.to_string_lossy();
// Extract Nix store hash from path like /nix/store/HASH-cm-dashboard-0.1.0/bin/cm-dashboard
let hash_part = exe_str.strip_prefix("/nix/store/").expect("Not a nix store path");
let hash = hash_part.split('-').next().expect("Invalid nix store path format");
assert!(hash.len() >= 8, "Hash too short");
// Return first 8 characters of nix store hash
let short_hash = hash[..8].to_string();
Box::leak(short_hash.into_boxed_str())
}
#[derive(Parser)]
#[command(name = "cm-dashboard")]
#[command(about = "CM Dashboard TUI with individual metric consumption")]
#[command(version = get_version())]
struct Cli {
/// Increase logging verbosity (-v, -vv)
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
/// Configuration file path (defaults to /etc/cm-dashboard/dashboard.toml)
#[arg(short, long)]
config: Option<String>,
/// Run in headless mode (no TUI, just logging)
#[arg(long)]
headless: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
// Setup logging - only if headless or verbose
if cli.headless || cli.verbose > 0 {
let log_level = match cli.verbose {
0 => "warn", // Only warnings and errors when not verbose
1 => "info",
2 => "debug",
_ => "trace",
};
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env().add_directive(log_level.parse()?))
.init();
} else {
// No logging output when running TUI mode
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env().add_directive("off".parse()?))
.init();
}
if cli.headless || cli.verbose > 0 {
info!("CM Dashboard starting with individual metrics architecture...");
}
// Create and run dashboard
let mut dashboard = Dashboard::new(cli.config, cli.headless).await?;
// Setup graceful shutdown
let ctrl_c = async {
tokio::signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
// Run dashboard with graceful shutdown
tokio::select! {
result = dashboard.run() => {
if let Err(e) = result {
error!("Dashboard error: {}", e);
return Err(e);
}
}
_ = ctrl_c => {
info!("Shutdown signal received");
}
}
if cli.headless || cli.verbose > 0 {
info!("Dashboard shutdown complete");
}
Ok(())
}