use crate::{check_output, reduce_whitespace, PackageResult};
use std::process::Command;
use strp::*;
pub fn check_cargo(package_name: &str) -> Result<PackageResult, String> {
let output = match Command::new("cargo")
.arg("search")
.arg(package_name)
.output()
{
Ok(output) => output,
Err(e) => return Err(format!("[cargo] {}", e)),
};
let lines = match check_output(output) {
Ok(lines) => lines,
Err(_) => {
return Result::Ok(PackageResult::none("cargo", package_name)); }
};
if lines.is_empty() {
return Result::Ok(PackageResult::none("cargo", package_name));
}
if lines.iter().all(|line| !line.contains(package_name)) {
return Result::Ok(PackageResult::none("cargo", package_name));
}
fn check_exact_name(line: &String, package_name: &str) -> bool {
let mut iter = line.split_whitespace();
let name: &str = iter.next().unwrap_or_default();
name == package_name
}
if lines
.iter()
.all(|line| !check_exact_name(line, package_name))
{
return Result::Ok(PackageResult::none("cargo", package_name));
}
let mut version = String::new();
let mut desc = String::new();
let filtered_lines: Vec<String> = lines
.iter()
.filter(|line| line.contains(" = "))
.filter(|line| check_exact_name(line, package_name))
.map(|line| line.to_string())
.collect();
for line in &filtered_lines {
let reduced_line = reduce_whitespace(line.to_string());
let scanned: Result<(String, String, String), _> =
try_scan!(reduced_line => "{} = \"{}\" # {}");
(version, desc) = match scanned {
Ok((_, version, desc)) => (version, desc),
Err(e) => return Err(format!("[cargo] parsing error: {:?}", e)),
};
}
let output = match Command::new("cargo").arg("install").arg("--list").output() {
Ok(output) => output,
Err(e) => return Err(e.to_string()),
};
let lines = match check_output(output) {
Ok(lines) => lines,
Err(e) => return Err(e),
};
let filtered_lines: Vec<String> = lines
.iter()
.filter(|line| !line.is_empty() && !line.starts_with(' ') && line.contains(package_name))
.map(|line| line.to_string())
.collect();
for line in &filtered_lines {
let scanned: Result<(String, String), _> = try_scan!(line => "{} v{}:");
let (name, local_version): (String, String) = match scanned {
Ok((name, version)) => (name, version),
Err(e) => return Err(format!("[cargo] parsing error: {e:?}")),
};
if package_name == name {
let version_info: String = if local_version != version {
format!("{} -> {}", local_version, version)
} else {
local_version
};
return Result::Ok(PackageResult::some(
"cargo",
&name,
"installed",
&version_info,
&desc,
"",
));
}
}
Result::Ok(PackageResult::some(
"cargo",
package_name,
"available",
&version,
&desc,
"",
))
}