use crate::version::vercmp;
use std::cmp::Ordering;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VersionOp {
Eq,
Ge,
Le,
Gt,
Lt,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Dependency {
pub raw: String,
pub name: String,
pub op: Option<VersionOp>,
pub version: Option<String>,
}
pub fn parse_dependency(raw: &str) -> Dependency {
let trimmed = raw.trim();
for (token, op) in [
(">=", VersionOp::Ge),
("<=", VersionOp::Le),
("=", VersionOp::Eq),
(">", VersionOp::Gt),
("<", VersionOp::Lt),
] {
if let Some((name, version)) = trimmed.split_once(token) {
return Dependency {
raw: trimmed.to_string(),
name: name.trim().to_string(),
op: Some(op),
version: Some(version.trim().to_string()),
};
}
}
Dependency {
raw: trimmed.to_string(),
name: trimmed.to_string(),
op: None,
version: None,
}
}
pub fn dependency_satisfied(local_version: &str, dep: &Dependency) -> bool {
let Some(op) = dep.op else {
return true;
};
let Some(required) = dep.version.as_deref() else {
return true;
};
matches!(
(op, vercmp(local_version, required)),
(VersionOp::Eq, Ordering::Equal)
| (VersionOp::Ge, Ordering::Equal | Ordering::Greater)
| (VersionOp::Le, Ordering::Equal | Ordering::Less)
| (VersionOp::Gt, Ordering::Greater)
| (VersionOp::Lt, Ordering::Less)
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_versioned_dependency() {
let dep = parse_dependency("openssl>=3.0");
assert_eq!(dep.name, "openssl");
assert_eq!(dep.op, Some(VersionOp::Ge));
assert_eq!(dep.version.as_deref(), Some("3.0"));
}
#[test]
fn checks_dependency_versions() {
let dep = parse_dependency("foo>=1.2-1");
assert!(dependency_satisfied("1.2-2", &dep));
assert!(!dependency_satisfied("1.1-9", &dep));
}
}