support ::repo syntax

This commit is contained in:
John Turner
2025-11-18 01:44:45 +00:00
parent db02762ee1
commit 78398b7ebe
2 changed files with 53 additions and 16 deletions

View File

@@ -103,6 +103,9 @@ pub enum UseDepCondition {
Question,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Repo(String);
#[derive(Clone, Debug, PartialEq, Eq, Get)]
pub struct UseDep {
negate: Option<UseDepNegate>,
@@ -132,6 +135,7 @@ pub struct Atom {
name: Name,
version: Option<(VersionOperator, Version, Option<Wildcard>)>,
slot: Option<Slot>,
repo: Option<Repo>,
#[get(kind = "deref")]
usedeps: Vec<UseDep>,
}

View File

@@ -5,7 +5,7 @@ use mon::{Parser, ParserIter, alphanumeric, r#if, numeric1, one_of, tag};
use crate::{
Parseable,
atom::{
Atom, Blocker, Category, Cp, Cpv, Name, Slot, SlotName, SlotOperator, UseDep,
Atom, Blocker, Category, Cp, Cpv, Name, Repo, Slot, SlotName, SlotOperator, UseDep,
UseDepCondition, UseDepNegate, UseDepSign, Version, VersionNumber, VersionNumbers,
VersionOperator, VersionSuffix, VersionSuffixKind, VersionSuffixes, Wildcard,
},
@@ -201,6 +201,21 @@ impl<'a> Parseable<'a, &'a str> for UseDepSign {
}
}
//A slot name may contain any of the characters [A-Za-z0-9+_.-]. It must not begin with a hyphen, a dot or a plus sign.
impl<'a> Parseable<'a, &'a str> for Repo {
type Parser = impl Parser<&'a str, Output = Self>;
fn parser() -> Self::Parser {
let start = alphanumeric().or(one_of("_".chars()));
let rest = alphanumeric().or(one_of("+_.-".chars())).repeated().many();
start
.and(rest)
.recognize()
.map(|output: &str| Repo(output.to_string()))
}
}
impl<'a> Parseable<'a, &'a str> for UseDep {
type Parser = impl Parser<&'a str, Output = Self>;
@@ -288,15 +303,19 @@ impl<'a> Parseable<'a, &'a str> for Atom {
.and(Category::parser())
.and(Name::parser().preceded_by(tag("/")))
.and(Slot::parser().preceded_by(tag(":")).opt())
.and(Repo::parser().preceded_by(tag("::")).opt())
.and(usedeps())
.map(|((((blocker, category), name), slot), usedeps)| Atom {
.map(
|(((((blocker, category), name), slot), repo), usedeps)| Atom {
blocker,
category,
name,
version: None,
slot,
repo,
usedeps: usedeps.unwrap_or(Vec::new()),
});
},
);
let with_version = Blocker::parser()
.opt()
@@ -306,16 +325,22 @@ impl<'a> Parseable<'a, &'a str> for Atom {
.and(Version::parser().preceded_by(tag("-")))
.and(tag("*").map(|_| Wildcard).opt())
.and(Slot::parser().preceded_by(tag(":")).opt())
.and(Repo::parser().preceded_by(tag("::")).opt())
.and(usedeps())
.verify_output(|(((((((_, version_operator), _), _), _), star), _), _)| {
.verify_output(
|((((((((_, version_operator), _), _), _), star), _), _), _)| {
matches!(
(version_operator, star),
(VersionOperator::Eq, Some(_) | None) | (_, None)
)
})
},
)
.map(
|(
(
((((((blocker, version_operator), category), name), version), star), slot),
repo,
),
usedeps,
)| {
Atom {
@@ -324,6 +349,7 @@ impl<'a> Parseable<'a, &'a str> for Atom {
name,
version: Some((version_operator, version, star)),
slot,
repo,
usedeps: usedeps.unwrap_or(Vec::new()),
}
},
@@ -502,6 +528,13 @@ mod test {
Atom::parser().check_finished(it).unwrap();
}
#[test]
fn test_with_repo() {
let it = InputIter::new("=foo/bar-1.0.0:slot/sub=::gentoo[a,b,c]");
Atom::parser().check_finished(it).unwrap();
}
#[test]
fn test_against_fuzzer_false_positives() {
let atoms = [