use super::common::{PackageError, command_exists, run_package_command};
use super::config::{CargoConfig, PackageSpec};
pub struct CargoHandler {
config: CargoConfig,
}
impl CargoHandler {
pub fn new(config: CargoConfig) -> Self {
Self { config }
}
pub fn install(&self) -> Result<(), PackageError> {
if !command_exists("cargo") {
return Err(PackageError::PackageManagerNotInstalled(
"cargo".to_string(),
));
}
if self.config.packages.is_empty() {
println!(" No cargo packages configured");
return Ok(());
}
for (name, spec) in &self.config.packages {
if spec.is_optional() {
continue;
}
if let Err(e) = self.install_crate(name, spec) {
eprintln!(" Warning: Failed to install {}: {}", name, e);
}
}
Ok(())
}
fn install_crate(&self, name: &str, spec: &PackageSpec) -> Result<(), PackageError> {
println!(" Installing {}...", name);
let mut args = vec!["install", name];
let version = spec.version();
if version != "latest" {
args.push("--version");
args.push(version);
}
let features = spec.features();
let features_str: String;
if !features.is_empty() {
features_str = features.join(",");
args.push("--features");
args.push(&features_str);
}
if self.config.locked {
args.push("--locked");
}
let current_dir = std::env::current_dir().map_err(PackageError::Io)?;
run_package_command("cargo", &args, ¤t_dir)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_cargo_handler_empty() {
let config = CargoConfig::default();
let handler = CargoHandler::new(config);
assert!(handler.config.packages.is_empty());
}
#[test]
fn test_cargo_config_with_packages() {
let mut packages = HashMap::new();
packages.insert(
"cargo-watch".to_string(),
PackageSpec::Version("latest".to_string()),
);
packages.insert(
"cargo-nextest".to_string(),
PackageSpec::Version("0.9".to_string()),
);
let config = CargoConfig {
packages,
locked: true,
};
let handler = CargoHandler::new(config);
assert!(handler.config.locked);
assert_eq!(handler.config.packages.len(), 2);
}
}