deps: give legacy < and > relations their documented dpkg semantics
Debian Policy 7 defines the deprecated single-character spellings as 'earlier/later or equal' (i.e. <= and >=), and dpkg still accepts them that way; the parser mapped them to the strict << and >> instead, so 'foo (< 1.0)' was wrongly reported unmet against installed 1.0.
This commit is contained in:
+58
-4
@@ -187,12 +187,16 @@ pub fn parse_simple(dep: &str, build_dep: bool) -> Result<PkgRelation, String> {
|
|||||||
|
|
||||||
let constraint = match (caps.get(5), caps.get(6)) {
|
let constraint = match (caps.get(5), caps.get(6)) {
|
||||||
(Some(op), Some(version)) => {
|
(Some(op), Some(version)) => {
|
||||||
|
// The deprecated single-character spellings `<` and `>` were
|
||||||
|
// "confusingly defined" (Debian Policy §7) to mean earlier-or-equal
|
||||||
|
// and later-or-equal, i.e. `<=` and `>=`; dpkg still accepts them
|
||||||
|
// with those non-strict semantics.
|
||||||
let relation = match op.as_str() {
|
let relation = match op.as_str() {
|
||||||
"<<" | "<" => Relation::Lt,
|
"<<" => Relation::Lt,
|
||||||
"<=" => Relation::Le,
|
"<" | "<=" => Relation::Le,
|
||||||
"=" => Relation::Eq,
|
"=" => Relation::Eq,
|
||||||
">=" => Relation::Ge,
|
">" | ">=" => Relation::Ge,
|
||||||
">>" | ">" => Relation::Gt,
|
">>" => Relation::Gt,
|
||||||
other => return Err(format!("invalid relation '{other}' in '{dep}'")),
|
other => return Err(format!("invalid relation '{other}' in '{dep}'")),
|
||||||
};
|
};
|
||||||
let version = DebianVersion::parse(version.as_str())
|
let version = DebianVersion::parse(version.as_str())
|
||||||
@@ -1024,6 +1028,56 @@ mod tests {
|
|||||||
assert!(Deps::parse("foo:native", &opts("amd64", &[])).is_ok());
|
assert!(Deps::parse("foo:native", &opts("amd64", &[])).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The deprecated single-character operators `<` and `>` mean `<=` and
|
||||||
|
/// `>=` (Debian Policy §7, dpkg behavior), and canonicalize on output.
|
||||||
|
#[test]
|
||||||
|
fn legacy_single_char_relations() {
|
||||||
|
let rel = |dep: &str| {
|
||||||
|
parse_simple(dep, true)
|
||||||
|
.unwrap()
|
||||||
|
.constraint
|
||||||
|
.unwrap()
|
||||||
|
.relation
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(rel("foo (<< 1.0)"), Relation::Lt);
|
||||||
|
assert_eq!(rel("foo (< 1.0)"), Relation::Le);
|
||||||
|
assert_eq!(rel("foo (<= 1.0)"), Relation::Le);
|
||||||
|
assert_eq!(rel("foo (= 1.0)"), Relation::Eq);
|
||||||
|
assert_eq!(rel("foo (>= 1.0)"), Relation::Ge);
|
||||||
|
assert_eq!(rel("foo (> 1.0)"), Relation::Ge);
|
||||||
|
assert_eq!(rel("foo (>> 1.0)"), Relation::Gt);
|
||||||
|
|
||||||
|
// Rendering always uses the canonical modern spellings.
|
||||||
|
for (dep, rendered) in [
|
||||||
|
("foo (< 1.0)", "foo (<= 1.0)"),
|
||||||
|
("foo (> 1.0)", "foo (>= 1.0)"),
|
||||||
|
("foo (<< 1.0)", "foo (<< 1.0)"),
|
||||||
|
("foo (>> 1.0)", "foo (>> 1.0)"),
|
||||||
|
] {
|
||||||
|
assert_eq!(parse_simple(dep, true).unwrap().output(), rendered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `foo (< 1.0)` is satisfied by an installed `foo 1.0` (the legacy
|
||||||
|
/// operator is non-strict); `foo (< 0.9)` is not.
|
||||||
|
#[test]
|
||||||
|
fn legacy_single_char_evaluation() {
|
||||||
|
let mut facts = Facts::new("amd64", "amd64");
|
||||||
|
facts.add_installed("foo", "1.0", "amd64", "no");
|
||||||
|
let o = |s: &str| parse_simple(s, true).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (< 1.0)")), Some(true));
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (<= 1.0)")), Some(true));
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (< 0.9)")), Some(false));
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (<< 1.0)")), Some(false));
|
||||||
|
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (> 1.0)")), Some(true));
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (>= 1.0)")), Some(true));
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (> 1.1)")), Some(false));
|
||||||
|
assert_eq!(facts.evaluate_relation(&o("foo (>> 1.0)")), Some(false));
|
||||||
|
}
|
||||||
|
|
||||||
/// Ported from dpkg `t/Dpkg_Deps.t`: architecture reduction.
|
/// Ported from dpkg `t/Dpkg_Deps.t`: architecture reduction.
|
||||||
#[test]
|
#[test]
|
||||||
fn arch_reduction() {
|
fn arch_reduction() {
|
||||||
|
|||||||
Reference in New Issue
Block a user