use std::env;
use std::io::ErrorKind;
use std::path::PathBuf;
use std::process::Command;
use anyhow::{Context, bail};
use crate::config::{DRIVER_CRATE, RUSTUP_TOOLCHAIN_ENV, TOOL_VERSION};
use crate::toolchain::pinned_toolchain;
pub fn run_setup(_args: &[String]) -> anyhow::Result<i32> {
let toolchain = pinned_toolchain();
eprintln!("cargo-cgp: installing toolchain `{toolchain}` (with rustc-dev, llvm-tools)…");
install_toolchain(&toolchain)?;
eprintln!("cargo-cgp: installing {DRIVER_CRATE} {TOOL_VERSION} under `{toolchain}`…");
install_driver(&toolchain)?;
eprintln!("cargo-cgp: setup complete.");
Ok(0)
}
fn install_toolchain(toolchain: &str) -> anyhow::Result<()> {
let status = Command::new("rustup")
.args(["toolchain", "install", toolchain])
.args(["-c", "rustc-dev", "-c", "llvm-tools"])
.status()
.map_err(|e| {
if e.kind() == ErrorKind::NotFound {
anyhow::anyhow!(
"rustup was not found on PATH; cargo-cgp requires rustup to manage toolchains"
)
} else {
anyhow::Error::new(e).context("failed to run `rustup toolchain install`")
}
})?;
if !status.success() {
bail!("`rustup toolchain install {toolchain}` failed with status {status}");
}
Ok(())
}
fn install_driver(toolchain: &str) -> anyhow::Result<()> {
let mut command = Command::new("cargo");
command
.env(RUSTUP_TOOLCHAIN_ENV, toolchain)
.arg("install")
.arg(DRIVER_CRATE)
.args(["--version", TOOL_VERSION]);
if let Some(root) = install_root() {
command.arg("--root").arg(root);
}
let status = command
.status()
.context("failed to run `cargo install` for the driver (is cargo on PATH?)")?;
if !status.success() {
bail!("installing {DRIVER_CRATE} {TOOL_VERSION} failed with status {status}");
}
Ok(())
}
fn install_root() -> Option<PathBuf> {
let current = env::current_exe().ok()?;
let dir = current.parent()?;
if dir.file_name().is_some_and(|name| name == "bin") {
return dir.parent().map(PathBuf::from);
}
eprintln!(
"cargo-cgp: warning: cargo-cgp is not in a `bin` directory ({}); \
installing the driver to cargo's default location instead of beside it",
dir.display()
);
None
}