use super::WrappedPackage;
const ECO: &str = "crates";
const VERB: &str = "add";
pub fn parse(argv: &[&str]) -> Vec<WrappedPackage> {
let Some(verb_pos) = argv.iter().position(|a| *a == VERB) else {
return Vec::new();
};
let mut packages: Vec<WrappedPackage> = Vec::new();
let mut overridden_version: Option<String> = None;
let mut path_or_git_install = false;
let mut iter = argv.iter().skip(verb_pos + 1);
while let Some(arg) = iter.next() {
if matches!(*arg, "--version" | "-v" | "--vers") {
if let Some(v) = iter.next() {
overridden_version = Some((*v).to_string());
}
continue;
}
if let Some(rest) = arg.strip_prefix("--version=") {
overridden_version = Some(rest.to_string());
continue;
}
if matches!(
*arg,
"--path" | "--git" | "--branch" | "--tag" | "--rev"
) {
path_or_git_install = true;
let _ = iter.next();
continue;
}
if matches!(*arg, "--registry" | "--features" | "--rename") {
let _ = iter.next();
continue;
}
if let Some(stripped) = arg.strip_prefix("--") {
let _ = stripped;
continue;
}
if arg.starts_with('-') {
continue;
}
if arg.is_empty() {
continue;
}
let (name, version) = split_pkg_spec(arg);
packages.push(WrappedPackage::new(ECO, name, version));
}
if let Some(v) = overridden_version {
if let Some(last) = packages.last_mut() {
last.version = v;
}
}
if path_or_git_install {
packages.clear();
}
packages
}
pub fn split_pkg_spec(spec: &str) -> (String, String) {
match spec.split_once('@') {
Some((name, ver)) if !name.is_empty() && !ver.is_empty() => {
(name.to_string(), ver.to_string())
}
_ => (spec.to_string(), "latest".to_string()),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn argv<'a>(args: &[&'a str]) -> Vec<&'a str> {
let mut v: Vec<&'a str> = vec!["cargo"];
v.extend_from_slice(args);
v
}
#[test]
fn parses_add_unpinned() {
let a = argv(&["add", "serde"]);
let pkgs = parse(&a);
assert_eq!(pkgs[0], WrappedPackage::new("crates", "serde", "latest"));
}
#[test]
fn parses_add_at_version() {
let a = argv(&["add", "serde@1.0.200"]);
let pkgs = parse(&a);
assert_eq!(pkgs[0], WrappedPackage::new("crates", "serde", "1.0.200"));
}
#[test]
fn parses_add_version_flag() {
let a = argv(&["add", "serde", "--version", "1.0.200"]);
let pkgs = parse(&a);
assert_eq!(pkgs[0], WrappedPackage::new("crates", "serde", "1.0.200"));
}
#[test]
fn parses_add_version_equals_flag() {
let a = argv(&["add", "serde", "--version=1.0.200"]);
let pkgs = parse(&a);
assert_eq!(pkgs[0].version, "1.0.200");
}
#[test]
fn skips_path_add() {
let a = argv(&["add", "--path", "./local-crate"]);
assert!(parse(&a).is_empty());
}
#[test]
fn skips_git_add() {
let a = argv(&["add", "--git", "https://github.com/serde-rs/serde.git"]);
assert!(parse(&a).is_empty());
}
#[test]
fn no_add_verb_returns_empty() {
let a = argv(&["build"]);
assert!(parse(&a).is_empty());
}
}