use anyhow::{bail, Result};
use colored::Colorize;
use crate::{config::Config, toolchain, user_version::VersionSpec};
pub fn run(config: &Config, spec_str: &str, args: &[String]) -> Result<()> {
if args.is_empty() {
bail!("No command specified. Usage: gvsn exec <version> <command> [args...]");
}
let spec = VersionSpec::parse(spec_str)?;
let version = toolchain::resolve_installed(config, &spec)?;
let bin = toolchain::version_bin_path(config, &version)?;
let root = config.version_dir(&version.tag());
let cmd_name = &args[0];
let cmd_args = &args[1..];
let path_var = std::env::var("PATH").unwrap_or_default();
let sep = if cfg!(windows) { ";" } else { ":" };
let new_path = format!("{}{sep}{path_var}", bin.display());
println!("{} Running with Go {}", "->".cyan(), version.tag().dimmed());
let status = std::process::Command::new(cmd_name)
.args(cmd_args)
.env("GOROOT", &root)
.env("PATH", &new_path)
.status()
.map_err(|e| anyhow::anyhow!("Failed to run '{}': {e}", cmd_name))?;
std::process::exit(status.code().unwrap_or(1));
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
fn make_config() -> (tempfile::TempDir, Config) {
let dir = tempdir().unwrap();
let config = Config {
root: dir.path().to_path_buf(),
};
(dir, config)
}
#[test]
fn run_errors_when_no_command_given() {
let (_dir, config) = make_config();
let err = run(&config, "1.22.4", &[]).unwrap_err();
assert!(err.to_string().contains("No command specified"));
}
#[test]
fn run_errors_on_invalid_spec() {
let (_dir, config) = make_config();
let args = vec!["echo".to_string(), "hi".to_string()];
assert!(run(&config, "not-a-version", &args).is_err());
}
#[test]
fn run_errors_when_version_not_installed() {
let (_dir, config) = make_config();
let args = vec!["echo".to_string(), "hi".to_string()];
assert!(run(&config, "1.22.4", &args).is_err());
}
}