use crate::vulnerability::Vulnerability;
use cargo_lock::{Lockfile, Package};
use std::path::{Path, PathBuf};
use std::process::Command;
#[cfg_attr(docsrs, doc(cfg(feature = "fix")))]
pub struct Fixer {
lockfile: Lockfile,
manifest_path: Option<PathBuf>,
path_to_cargo: Option<PathBuf>,
}
impl Fixer {
pub fn new(
cargo_lock: Lockfile,
cargo_toml: Option<PathBuf>,
path_to_cargo: Option<PathBuf>,
) -> Self {
Self {
lockfile: cargo_lock,
manifest_path: cargo_toml,
path_to_cargo,
}
}
pub fn get_fix_command(&self, vulnerability: &Vulnerability, dry_run: bool) -> Command {
let cargo_path: &Path = self.path_to_cargo.as_deref().unwrap_or(Path::new("cargo"));
let pkg_name = &vulnerability.package.name;
let mut command = Command::new(cargo_path);
command.arg("update");
if let Some(path) = self.manifest_path.as_ref() {
command.arg("--manifest-path").arg(path);
}
if dry_run {
command.arg("--dry-run");
}
for pkg in self.lockfile.packages.iter().filter(|pkg| {
&pkg.name == pkg_name && vulnerability.versions.is_vulnerable(&pkg.version)
}) {
let pkgid = pkgid(pkg);
command.arg(&pkgid);
}
command
}
}
fn pkgid(pkg: &Package) -> String {
match pkg.source.as_ref() {
Some(source) => format!("{}#{}@{}", source, pkg.name, pkg.version),
None => format!("{}@{}", pkg.name, pkg.version),
}
}