Skip to main content

start_command/
version_info.rs

1//! `start --version`: the version of start and of the isolation tools it
2//! can use. Moved out of the binary to keep it under the file-size limit.
3
4use std::process::{Command, Stdio};
5
6/// Print version information
7pub fn print_version(verbose: bool) {
8    let version = env!("CARGO_PKG_VERSION");
9    println!("start-command version: {} (Rust)", version);
10    println!();
11
12    println!("OS: {}", std::env::consts::OS);
13    println!("Architecture: {}", std::env::consts::ARCH);
14    println!();
15
16    // Check for installed isolation tools
17    println!("Isolation tools:");
18
19    if verbose {
20        println!("[verbose] Checking isolation tools...");
21    }
22
23    // Check screen
24    if let Some(version) = get_tool_version("screen", "-v", verbose) {
25        println!("  screen: {}", version);
26    } else {
27        println!("  screen: not installed");
28    }
29
30    // Check tmux
31    if let Some(version) = get_tool_version("tmux", "-V", verbose) {
32        println!("  tmux: {}", version);
33    } else {
34        println!("  tmux: not installed");
35    }
36
37    // Check docker
38    if let Some(version) = get_tool_version("docker", "--version", verbose) {
39        println!("  docker: {}", version);
40    } else {
41        println!("  docker: not installed");
42    }
43}
44
45/// Get version of an installed tool
46fn get_tool_version(tool_name: &str, version_flag: &str, verbose: bool) -> Option<String> {
47    let which_cmd = if cfg!(windows) { "where" } else { "which" };
48
49    // Check if tool exists
50    let exists = Command::new(which_cmd)
51        .arg(tool_name)
52        .stdout(Stdio::null())
53        .stderr(Stdio::null())
54        .status()
55        .map(|s| s.success())
56        .unwrap_or(false);
57
58    if !exists {
59        if verbose {
60            println!("[verbose] {}: not found in PATH", tool_name);
61        }
62        return None;
63    }
64
65    // Get version
66    let output = Command::new(tool_name).arg(version_flag).output().ok()?;
67
68    let stdout = String::from_utf8_lossy(&output.stdout);
69    let stderr = String::from_utf8_lossy(&output.stderr);
70    let combined = format!("{}{}", stdout, stderr).trim().to_string();
71
72    if verbose {
73        println!(
74            "[verbose] {} {}: exit={}, output=\"{}\"",
75            tool_name,
76            version_flag,
77            output.status.code().unwrap_or(-1),
78            &combined[..100.min(combined.len())]
79        );
80    }
81
82    if combined.is_empty() {
83        return None;
84    }
85
86    combined.lines().next().map(String::from)
87}