summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/atom/meson.build1
-rw-r--r--src/atom/mod.rs772
-rw-r--r--src/atom/parsers.rs599
-rw-r--r--src/lib.rs81
-rw-r--r--src/meson.build4
-rw-r--r--src/repo/ebuild/meson.build1
-rw-r--r--src/repo/ebuild/mod.rs83
-rw-r--r--src/repo/ebuild/parsers.rs205
-rw-r--r--src/repo/meson.build3
-rw-r--r--src/repo/mod.rs325
-rw-r--r--src/useflag/meson.build1
-rw-r--r--src/useflag/mod.rs20
-rw-r--r--src/useflag/parsers.rs40
13 files changed, 3 insertions, 2132 deletions
diff --git a/src/atom/meson.build b/src/atom/meson.build
deleted file mode 100644
index a7331a8..0000000
--- a/src/atom/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-sources += files('mod.rs', 'parsers.rs')
diff --git a/src/atom/mod.rs b/src/atom/mod.rs
deleted file mode 100644
index 24cb555..0000000
--- a/src/atom/mod.rs
+++ /dev/null
@@ -1,772 +0,0 @@
-use core::{
- fmt::{self},
- option::Option,
-};
-use std::cmp::Ordering;
-
-use crate::useflag::UseFlag;
-
-use get::Get;
-
-use itertools::Itertools;
-
-mod parsers;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum Blocker {
- Weak,
- Strong,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum VersionOperator {
- Lt,
- Gt,
- Eq,
- LtEq,
- GtEq,
- Roughly,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct Category(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct Name(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct VersionNumber(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Get)]
-struct VersionNumbers(#[get(method = "get", kind = "deref")] Vec<VersionNumber>);
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum VersionSuffixKind {
- Alpha,
- Beta,
- Pre,
- Rc,
- P,
-}
-
-#[derive(Clone, Debug, Hash, PartialEq, Eq, Get)]
-pub struct VersionSuffix {
- kind: VersionSuffixKind,
- number: Option<VersionNumber>,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Get)]
-pub struct VersionSuffixes(#[get(method = "get", kind = "deref")] Vec<VersionSuffix>);
-
-#[derive(Debug, Clone, Get, PartialEq, Eq, Hash)]
-pub struct BuildId(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct Version {
- numbers: VersionNumbers,
- letter: Option<char>,
- suffixes: VersionSuffixes,
- rev: Option<VersionNumber>,
- build_id: Option<BuildId>,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct Wildcard;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum SlotOperator {
- Eq,
- Star,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct SlotName(#[get(method = "name", kind = "deref")] String);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub enum Slot {
- Wildcard,
- Equal,
- NameEqual {
- primary: SlotName,
- sub: Option<SlotName>,
- },
- Name {
- primary: SlotName,
- sub: Option<SlotName>,
- },
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum UseDepNegate {
- Minus,
- Exclamation,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum UseDepSign {
- Enabled,
- Disabled,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum UseDepCondition {
- Eq,
- Question,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct Repo(String);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct UseDep {
- negate: Option<UseDepNegate>,
- flag: UseFlag,
- sign: Option<UseDepSign>,
- condition: Option<UseDepCondition>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct Cp {
- category: Category,
- name: Name,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct Cpv {
- category: Category,
- name: Name,
- version: Version,
- slot: Option<Slot>,
-}
-
-#[derive(Clone, Debug, Get, PartialEq, Eq, Hash)]
-pub struct Atom {
- blocker: Option<Blocker>,
- category: Category,
- name: Name,
- version: Option<(VersionOperator, Version, Option<Wildcard>)>,
- slot: Option<Slot>,
- repo: Option<Repo>,
- #[get(kind = "deref")]
- usedeps: Vec<UseDep>,
-}
-
-impl Cpv {
- #[must_use]
- pub fn into_cp(self) -> Cp {
- Cp {
- name: self.name,
- category: self.category,
- }
- }
-}
-
-impl Atom {
- #[must_use]
- pub fn version_operator(&self) -> Option<VersionOperator> {
- self.version.clone().map(|(oper, _, _)| oper)
- }
-
- #[must_use]
- pub fn into_cp(self) -> Cp {
- Cp {
- category: self.category,
- name: self.name,
- }
- }
-
- #[must_use]
- pub fn into_cpv(self) -> Option<Cpv> {
- match self.version {
- Some((_, version, _)) => Some(Cpv {
- category: self.category,
- name: self.name,
- version,
- slot: self.slot,
- }),
- None => None,
- }
- }
-}
-
-impl VersionNumber {
- #[must_use]
- pub fn cmp_as_ints(&self, other: &Self) -> Ordering {
- let a = self.get().trim_start_matches('0');
- let b = other.get().trim_start_matches('0');
-
- a.len().cmp(&b.len()).then_with(|| a.cmp(b))
- }
-
- #[must_use]
- pub fn cmp_as_str(&self, other: &Self) -> Ordering {
- if self.get().starts_with('0') || other.get().starts_with('0') {
- let a = self.get().trim_end_matches('0');
- let b = other.get().trim_end_matches('0');
-
- a.cmp(b)
- } else {
- self.cmp_as_ints(other)
- }
- }
-}
-
-impl PartialOrd for BuildId {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for BuildId {
- fn cmp(&self, other: &Self) -> Ordering {
- // build-id may not start with a zero so we dont need to strip them
- self.get()
- .len()
- .cmp(&other.get().len())
- .then_with(|| self.get().cmp(other.get()))
- }
-}
-
-impl PartialOrd for VersionSuffix {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for VersionSuffix {
- fn cmp(&self, other: &Self) -> Ordering {
- match &self.kind.cmp(&other.kind) {
- Ordering::Less => Ordering::Less,
- Ordering::Greater => Ordering::Greater,
- Ordering::Equal => match (&self.number, &other.number) {
- (Some(a), Some(b)) => a.cmp_as_ints(b),
- (Some(a), None) if a.get().chars().all(|c| c == '0') => Ordering::Equal,
- (None, Some(b)) if b.get().chars().all(|c| c == '0') => Ordering::Equal,
- (Some(_), None) => Ordering::Greater,
- (None, Some(_)) => Ordering::Less,
- (None, None) => Ordering::Equal,
- },
- }
- }
-}
-
-impl PartialOrd for VersionSuffixes {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for VersionSuffixes {
- fn cmp(&self, other: &Self) -> Ordering {
- let mut a = self.get().iter();
- let mut b = other.get().iter();
-
- loop {
- match (a.next(), b.next()) {
- (Some(a), Some(b)) => match a.cmp(b) {
- Ordering::Less => break Ordering::Less,
- Ordering::Greater => break Ordering::Greater,
- Ordering::Equal => (),
- },
- (Some(a), None) if matches!(a.kind, VersionSuffixKind::P) => {
- break Ordering::Greater;
- }
- (Some(_), None) => break Ordering::Less,
- (None, Some(b)) if matches!(b.kind, VersionSuffixKind::P) => break Ordering::Less,
- (None, Some(_)) => break Ordering::Greater,
- (None, None) => break Ordering::Equal,
- }
- }
- }
-}
-
-impl PartialOrd for VersionNumbers {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for VersionNumbers {
- fn cmp(&self, other: &Self) -> Ordering {
- match self
- .get()
- .first()
- .unwrap()
- .cmp_as_ints(other.get().first().unwrap())
- {
- Ordering::Less => Ordering::Less,
- Ordering::Greater => Ordering::Greater,
- Ordering::Equal => {
- let mut a = self.get().iter().skip(1);
- let mut b = other.get().iter().skip(1);
-
- loop {
- match (a.next(), b.next()) {
- (Some(a), Some(b)) => match a.cmp_as_str(b) {
- Ordering::Less => break Ordering::Less,
- Ordering::Greater => break Ordering::Greater,
- Ordering::Equal => (),
- },
-
- (Some(_), None) => break Ordering::Greater,
- (None, Some(_)) => break Ordering::Less,
- (None, None) => break Ordering::Equal,
- }
- }
- }
- }
- }
-}
-
-impl PartialOrd for Version {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for Version {
- fn cmp(&self, other: &Self) -> Ordering {
- match self.numbers.cmp(&other.numbers) {
- Ordering::Less => return Ordering::Less,
- Ordering::Greater => return Ordering::Greater,
- Ordering::Equal => (),
- }
-
- match (self.letter, other.letter) {
- (Some(a), Some(b)) if a < b => return Ordering::Less,
- (Some(a), Some(b)) if a > b => return Ordering::Greater,
- (Some(a), Some(b)) if a == b => (),
- (Some(_), None) => return Ordering::Greater,
- (None, Some(_)) => return Ordering::Less,
- (None, None) => (),
- _ => unreachable!(),
- }
-
- match self.suffixes.cmp(&other.suffixes) {
- Ordering::Less => return Ordering::Less,
- Ordering::Greater => return Ordering::Greater,
- Ordering::Equal => (),
- }
-
- match (&self.rev, &other.rev) {
- (Some(a), Some(b)) => match a.cmp_as_ints(b) {
- Ordering::Less => return Ordering::Less,
- Ordering::Greater => return Ordering::Greater,
- Ordering::Equal => (),
- },
- (Some(a), None) if a.get().chars().all(|c| c == '0') => (),
- (Some(_), None) => return Ordering::Greater,
- (None, Some(b)) if b.get().chars().all(|c| c == '0') => (),
- (None, Some(_)) => return Ordering::Less,
- (None, None) => (),
- }
-
- match (&self.build_id, &other.build_id) {
- (Some(a), Some(b)) => a.cmp(b),
- (Some(_), None) => Ordering::Greater,
- (None, Some(_)) => Ordering::Less,
- (None, None) => Ordering::Equal,
- }
- }
-}
-
-impl PartialOrd for Cpv {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- if self.category == other.category && self.name == other.name {
- Some(self.version.cmp(&other.version))
- } else {
- None
- }
- }
-}
-
-impl fmt::Display for Blocker {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Weak => write!(f, "!"),
- Self::Strong => write!(f, "!!"),
- }
- }
-}
-
-impl fmt::Display for VersionOperator {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Lt => write!(f, "<"),
- Self::Gt => write!(f, ">"),
- Self::Eq => write!(f, "="),
- Self::LtEq => write!(f, "<="),
- Self::GtEq => write!(f, ">="),
- Self::Roughly => write!(f, "~"),
- }
- }
-}
-
-impl fmt::Display for Category {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-impl fmt::Display for Name {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-impl fmt::Display for VersionNumber {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-impl fmt::Display for BuildId {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.get())
- }
-}
-
-impl fmt::Display for VersionSuffixKind {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Alpha => write!(f, "alpha"),
- Self::Beta => write!(f, "beta"),
- Self::Pre => write!(f, "pre"),
- Self::Rc => write!(f, "rc"),
- Self::P => write!(f, "p"),
- }
- }
-}
-
-impl fmt::Display for VersionSuffix {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.kind)?;
-
- if let Some(number) = self.number.as_ref() {
- write!(f, "{number}")?;
- }
-
- Ok(())
- }
-}
-
-impl fmt::Display for Version {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let numbers = self
- .numbers
- .get()
- .iter()
- .map(VersionNumber::get)
- .intersperse(".")
- .collect::<String>();
-
- let suffixes = self
- .suffixes
- .get()
- .iter()
- .map(VersionSuffix::to_string)
- .intersperse("_".to_string())
- .collect::<String>();
-
- write!(f, "{numbers}")?;
-
- if let Some(letter) = self.letter {
- write!(f, "{letter}")?;
- }
-
- if !suffixes.is_empty() {
- write!(f, "_{suffixes}")?;
- }
-
- if let Some(rev) = self.rev.as_ref() {
- write!(f, "-r{rev}")?;
- }
-
- if let Some(build_id) = self.build_id.as_ref() {
- write!(f, "-{build_id}")?;
- }
-
- Ok(())
- }
-}
-
-impl fmt::Display for SlotOperator {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Eq => write!(f, "="),
- Self::Star => write!(f, "*"),
- }
- }
-}
-
-impl fmt::Display for SlotName {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-impl fmt::Display for Slot {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Wildcard => write!(f, "*"),
- Self::Equal => {
- write!(f, "=")
- }
- Self::NameEqual { primary, sub } => {
- write!(f, "{primary}")?;
-
- if let Some(sub) = sub {
- write!(f, "/{sub}")?;
- }
-
- write!(f, "=")
- }
- Self::Name { primary, sub } => {
- write!(f, "{primary}")?;
-
- if let Some(sub) = sub {
- write!(f, "/{sub}")?;
- }
-
- Ok(())
- }
- }
- }
-}
-
-impl fmt::Display for UseDepNegate {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Minus => write!(f, "-"),
- Self::Exclamation => write!(f, "!"),
- }
- }
-}
-
-impl fmt::Display for UseDepSign {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Enabled => write!(f, "(+)"),
- Self::Disabled => write!(f, "(-)"),
- }
- }
-}
-
-impl fmt::Display for UseDepCondition {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Eq => write!(f, "="),
- Self::Question => write!(f, "?"),
- }
- }
-}
-
-impl fmt::Display for UseDep {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if let Some(negate) = self.negate.as_ref() {
- write!(f, "{negate}")?;
- }
-
- write!(f, "{}", self.flag)?;
-
- if let Some(sign) = self.sign.as_ref() {
- write!(f, "{sign}")?;
- }
-
- if let Some(condition) = self.condition.as_ref() {
- write!(f, "{condition}")?;
- }
-
- Ok(())
- }
-}
-
-impl fmt::Display for Cp {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}/{}", &self.category, &self.name)
- }
-}
-
-impl fmt::Display for Cpv {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}/{}-{}", &self.category, &self.name, &self.version)?;
-
- if let Some(slot) = self.slot.as_ref() {
- write!(f, ":{slot}")?;
- }
-
- Ok(())
- }
-}
-
-impl fmt::Display for Atom {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if let Some(blocker) = self.blocker.as_ref() {
- write!(f, "{blocker}")?;
- }
-
- if let Some(version_operator) = self.version_operator().as_ref() {
- write!(f, "{version_operator}")?;
- }
-
- write!(f, "{}", self.category)?;
- write!(f, "/")?;
- write!(f, "{}", self.name)?;
-
- if let Some((_, version, None)) = self.version() {
- write!(f, "-{version}")?;
- } else if let Some((_, version, Some(_))) = self.version() {
- write!(f, "-{version}*")?;
- }
-
- if let Some(slot) = self.slot.as_ref() {
- write!(f, ":{slot}")?;
- }
-
- let usedeps = self
- .usedeps
- .iter()
- .map(UseDep::to_string)
- .intersperse(",".to_string())
- .collect::<String>();
-
- if !usedeps.is_empty() {
- write!(f, "[{usedeps}]")?;
- }
-
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod test {
- use mon::{Parser, input::InputIter};
-
- use super::*;
-
- use crate::Parseable;
-
- macro_rules! assert_cmp_display {
- ($a:expr, $b:expr, $ordering:expr) => {
- if $a.cmp(&$b) != $ordering {
- panic!("{} ~ {} != {:?}", $a, $b, $ordering)
- }
- };
- }
-
- macro_rules! assert_partial_cmp_display {
- ($a:expr, $b:expr, $ordering:expr) => {
- if $a.partial_cmp(&$b) != $ordering {
- panic!("{} ~ {} != {:?}", $a, $b, $ordering)
- }
- };
- }
-
- #[test]
- fn test_version_display() {
- let s = "1.0.0_alpha1_beta1-r1";
- let version = Version::parser().parse_finished(InputIter::new(s)).unwrap();
-
- assert_eq!(version.to_string().as_str(), s);
- }
-
- #[test]
- fn test_display_atom() {
- let s = "!!>=foo/bar-1.0.0v_alpha1_beta1-r1:slot/sub=[a,b,c]";
- let atom = Atom::parser().parse_finished(InputIter::new(s)).unwrap();
-
- assert_eq!(atom.to_string().as_str(), s);
- }
-
- #[test]
- fn test_version_cmp() {
- let versions = [
- ("1.0.1", "1.0", Ordering::Greater),
- ("1.0.0", "1.0.0_alpha", Ordering::Greater),
- ("1.0.0_alpha", "1.0.0_alpha_p", Ordering::Less),
- ("1.0.0-r0", "1.0.0", Ordering::Equal),
- ("1.0.0-r0000", "1.0.0", Ordering::Equal),
- ("1.0.0-r1-1", "1.0.0-r1-2", Ordering::Less),
- ];
-
- for (a, b, ordering) in versions.iter().map(|(a, b, ordering)| {
- (
- Version::parser().parse_finished(InputIter::new(a)).unwrap(),
- Version::parser().parse_finished(InputIter::new(b)).unwrap(),
- ordering,
- )
- }) {
- assert_cmp_display!(a, b, *ordering);
- }
- }
-
- #[test]
- fn test_cpv_eq() {
- let cpvs = [
- ("foo/bar-1", "foo/bar-1", Some(Ordering::Equal)),
- ("foo/baz-1", "foo/bar-1", None),
- ];
-
- for (a, b, ordering) in cpvs.iter().copied().map(|(a, b, ordering)| {
- (
- Cpv::parser().parse_finished(InputIter::new(a)).unwrap(),
- Cpv::parser().parse_finished(InputIter::new(b)).unwrap(),
- ordering,
- )
- }) {
- assert_partial_cmp_display!(a, b, ordering);
- }
- }
-
- #[test]
- fn test_version_cmp_letter() {
- let a = Version::parser()
- .parse_finished(InputIter::new("1.0.0"))
- .unwrap();
- let b = Version::parser()
- .parse_finished(InputIter::new("1.0.0a"))
- .unwrap();
-
- assert_cmp_display!(a, b, Ordering::Less);
- }
-
- #[test]
- fn test_version_cmp_where_b_has_leading_zeros() {
- let a = Version::parser()
- .parse_finished(InputIter::new("1.2"))
- .unwrap();
- let b = Version::parser()
- .parse_finished(InputIter::new("1.054"))
- .unwrap();
-
- assert_cmp_display!(a, b, Ordering::Greater);
- }
-
- #[test]
- fn test_version_has_more_zeros() {
- let a = Version::parser()
- .parse_finished(InputIter::new("1.0.0"))
- .unwrap();
- let b = Version::parser()
- .parse_finished(InputIter::new("1.0"))
- .unwrap();
-
- assert_cmp_display!(a, b, Ordering::Greater);
- }
-
- #[test]
- fn test_fuzzer_cases() {
- let control = Version::parser()
- .parse_finished(InputIter::new("1.2.0a_alpha1_beta2-r1-8"))
- .unwrap();
-
- #[allow(clippy::single_element_loop)]
- for (version_str, expected) in [("1.2.0", Ordering::Greater)] {
- let version = Version::parser()
- .parse_finished(InputIter::new(version_str))
- .unwrap();
-
- assert_cmp_display!(control, version, expected);
- }
- }
-}
diff --git a/src/atom/parsers.rs b/src/atom/parsers.rs
deleted file mode 100644
index c7ff586..0000000
--- a/src/atom/parsers.rs
+++ /dev/null
@@ -1,599 +0,0 @@
-use core::option::Option::None;
-
-use mon::{
- Parser, ParserIter, ascii_alphanumeric, ascii_numeric, ascii_numeric1, eof, r#if,
- input::InputIter, one_of, tag,
-};
-
-use crate::{
- Parseable,
- atom::{
- Atom, Blocker, BuildId, Category, Cp, Cpv, Name, Repo, Slot, SlotName, SlotOperator,
- UseDep, UseDepCondition, UseDepNegate, UseDepSign, Version, VersionNumber, VersionNumbers,
- VersionOperator, VersionSuffix, VersionSuffixKind, VersionSuffixes, Wildcard,
- },
- useflag::UseFlag,
-};
-
-impl<'a> Parseable<'a, &'a str> for Blocker {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- tag("!!")
- .map(|_| Blocker::Strong)
- .or(tag("!").map(|_| Blocker::Weak))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for VersionOperator {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- tag("<=")
- .map(|_| VersionOperator::LtEq)
- .or(tag(">=").map(|_| VersionOperator::GtEq))
- .or(tag("<").map(|_| VersionOperator::Lt))
- .or(tag(">").map(|_| VersionOperator::Gt))
- .or(tag("=").map(|_| VersionOperator::Eq))
- .or(tag("~").map(|_| VersionOperator::Roughly))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for VersionNumber {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- ascii_numeric1().map(|output: &str| VersionNumber(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for BuildId {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_numeric().and_not(tag("0"));
- let rest = ascii_numeric().repeated().many();
-
- start
- .and(rest)
- .recognize()
- .or(tag("0"))
- .map(|output: &str| BuildId(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for VersionSuffixKind {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- tag("alpha")
- .map(|_| VersionSuffixKind::Alpha)
- .or(tag("beta").map(|_| VersionSuffixKind::Beta))
- .or(tag("pre").map(|_| VersionSuffixKind::Pre))
- .or(tag("rc").map(|_| VersionSuffixKind::Rc))
- .or(tag("p").map(|_| VersionSuffixKind::P))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for VersionSuffix {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- VersionSuffixKind::parser()
- .and(VersionNumber::parser().opt())
- .map(|(kind, number)| VersionSuffix { kind, number })
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for VersionNumbers {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- VersionNumber::parser()
- .separated_by(tag("."))
- .at_least(1)
- .map(VersionNumbers)
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for VersionSuffixes {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- VersionSuffix::parser()
- .separated_by(tag("_"))
- .at_least(1)
- .map(VersionSuffixes)
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Version {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let rev = VersionNumber::parser().preceded_by(tag("-r"));
- let build_id = BuildId::parser().preceded_by(tag("-"));
-
- VersionNumbers::parser()
- .and(r#if(|c: &char| c.is_ascii_alphabetic() && c.is_ascii_lowercase()).opt())
- .and(VersionSuffixes::parser().preceded_by(tag("_")).opt())
- .and(rev.opt())
- .and(build_id.opt())
- .map(|((((numbers, letter), suffixes), rev), build_id)| Version {
- numbers,
- letter,
- suffixes: suffixes.unwrap_or(VersionSuffixes(Vec::new())),
- rev,
- build_id,
- })
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Category {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_alphanumeric().or(one_of("_".chars()));
- let rest = ascii_alphanumeric()
- .or(one_of("+_.-".chars()))
- .repeated()
- .many();
-
- start
- .and(rest)
- .recognize()
- .map(|output: &str| Category(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Name {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = || ascii_alphanumeric().or(one_of("_".chars()));
-
- let rest = ascii_alphanumeric()
- .or(one_of("_+".chars()))
- .or(one_of("-".chars()).and_not(
- Version::parser()
- .preceded_by(tag("-"))
- .followed_by(ascii_alphanumeric().or(one_of("_+-".chars())).not()),
- ))
- .repeated()
- .many();
-
- let verify = ascii_alphanumeric()
- .or(one_of("_+".chars()))
- .or(one_of("-".chars())
- .and_not(Version::parser().preceded_by(tag("-")).followed_by(eof())))
- .repeated()
- .many();
-
- start()
- .and(rest)
- .recognize()
- .verify_output(move |output: &&str| {
- verify.check_finished(InputIter::new(*output)).is_ok()
- })
- .map(|output: &str| Name(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for SlotOperator {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- tag("=")
- .map(|_| SlotOperator::Eq)
- .or(tag("*").map(|_| SlotOperator::Star))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for SlotName {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_alphanumeric().or(one_of("_".chars()));
- let rest = ascii_alphanumeric()
- .or(one_of("+_.-".chars()))
- .repeated()
- .many();
-
- start
- .and(rest)
- .recognize()
- .map(|output: &str| SlotName(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Slot {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let wildcard = tag("*").map(|_| Slot::Wildcard);
- let equal = tag("=").map(|_| Slot::Equal);
- let name_equal = SlotName::parser()
- .and(SlotName::parser().preceded_by(tag("/")).opt())
- .followed_by(tag("="))
- .map(|(primary, sub)| Slot::NameEqual { primary, sub });
- let name = SlotName::parser()
- .and(SlotName::parser().preceded_by(tag("/")).opt())
- .map(|(primary, sub)| Self::Name { primary, sub });
-
- wildcard.or(equal).or(name_equal).or(name)
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for UseDepSign {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- tag("(-)")
- .map(|_| UseDepSign::Disabled)
- .or(tag("(+)").map(|_| UseDepSign::Enabled))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Repo {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_alphanumeric().or(one_of("_".chars()));
- let rest = ascii_alphanumeric()
- .or(one_of("_-".chars()))
- .repeated()
- .many();
-
- start
- .and(rest)
- .recognize()
- .verify_output(move |output: &&str| {
- Name::parser()
- .check_finished(InputIter::new(*output))
- .is_ok()
- })
- .map(|output: &str| Repo(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for UseDep {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- #[allow(clippy::many_single_char_names)]
- fn parser() -> Self::Parser {
- let a = UseFlag::parser()
- .and(UseDepSign::parser().opt())
- .preceded_by(tag("-"))
- .map(|(flag, sign)| UseDep {
- negate: Some(UseDepNegate::Minus),
- flag,
- sign,
- condition: None,
- });
-
- let b = UseFlag::parser()
- .and(UseDepSign::parser().opt())
- .preceded_by(tag("!"))
- .followed_by(tag("?"))
- .map(|(flag, sign)| UseDep {
- negate: Some(UseDepNegate::Exclamation),
- flag,
- sign,
- condition: Some(UseDepCondition::Question),
- });
-
- let c = UseFlag::parser()
- .and(UseDepSign::parser().opt())
- .followed_by(tag("?"))
- .map(|(flag, sign)| UseDep {
- negate: None,
- flag,
- sign,
- condition: Some(UseDepCondition::Question),
- });
-
- let d = UseFlag::parser()
- .and(UseDepSign::parser().opt())
- .preceded_by(tag("!"))
- .followed_by(tag("="))
- .map(|(flag, sign)| UseDep {
- negate: Some(UseDepNegate::Exclamation),
- flag,
- sign,
- condition: Some(UseDepCondition::Eq),
- });
-
- let e = UseFlag::parser()
- .and(UseDepSign::parser().opt())
- .followed_by(tag("="))
- .map(|(flag, sign)| UseDep {
- negate: None,
- flag,
- sign,
- condition: Some(UseDepCondition::Eq),
- });
-
- let f = UseFlag::parser()
- .and(UseDepSign::parser().opt())
- .map(|(flag, sign)| UseDep {
- negate: None,
- flag,
- sign,
- condition: None,
- });
-
- a.or(b).or(c).or(d).or(e).or(f)
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Atom {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let usedeps = || {
- UseDep::parser()
- .separated_by(tag(","))
- .at_least(1)
- .delimited_by(tag("["), tag("]"))
- .opt()
- };
-
- let without_version = Blocker::parser()
- .opt()
- .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), repo), usedeps)| Atom {
- blocker,
- category,
- name,
- version: None,
- slot,
- repo,
- usedeps: usedeps.unwrap_or(Vec::new()),
- },
- );
-
- let with_version = Blocker::parser()
- .opt()
- .and(VersionOperator::parser())
- .and(Category::parser())
- .and(Name::parser().preceded_by(tag("/")))
- .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), _), _), version), star), _), _), _)| {
- matches!(
- (version_operator, star),
- (VersionOperator::Eq, Some(_) | None) | (_, None)
- ) && matches!((version.build_id(), star), (Some(_), None) | (None, _))
- },
- )
- .map(
- |(
- (
- ((((((blocker, version_operator), category), name), version), star), slot),
- repo,
- ),
- usedeps,
- )| {
- Atom {
- blocker,
- category,
- name,
- version: Some((version_operator, version, star)),
- slot,
- repo,
- usedeps: usedeps.unwrap_or(Vec::new()),
- }
- },
- );
-
- with_version.or(without_version)
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Cp {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- Category::parser()
- .and(Name::parser().preceded_by(tag("/")))
- .map(|(category, name)| Cp { category, name })
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Cpv {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- Category::parser()
- .and(Name::parser().preceded_by(tag("/")))
- .and(Version::parser().preceded_by(tag("-")))
- .and(Slot::parser().preceded_by(tag(":")).opt())
- .map(|(((category, name), version), slot)| Cpv {
- category,
- name,
- version,
- slot,
- })
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use mon::input::InputIter;
-
- use super::*;
-
- #[test]
- fn test_version() {
- let it = InputIter::new("1.0.0v_alpha1_beta1-r1");
-
- Version::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_name() {
- let it = InputIter::new("foo-1-bar-1.0.0");
-
- match Name::parser().parse(it) {
- Ok((_, output)) => {
- assert_eq!(output.0.as_str(), "foo-1-bar");
- }
- _ => unreachable!(),
- }
- }
-
- #[test]
- fn test_atom() {
- let it = InputIter::new(
- "!!>=cat/pkg-1-foo-1.0.0v_alpha1_p20250326-r1:primary/sub=[use,use=,!use=,use?,!use?,-use,use(+),use(-)]",
- );
-
- Atom::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_cursed_atom() {
- let it = InputIter::new(
- "!!>=_.+-0-/_-test-T-123_beta1_-4a-6+-_p--1.00.02b_alpha3_pre_p4-r5:slot/_-+6-9=[test(+),test(-)]",
- );
-
- Atom::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_atom_with_star_in_non_empty_slot() {
- let it = InputIter::new("foo/bar:*/subslot");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_invalid_usedep() {
- let it = InputIter::new("foo-bar:slot/sub=[!use]");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_empty_slot() {
- let it = InputIter::new("=dev-ml/uucp-17*:");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_usedep_with_underscore() {
- let it = InputIter::new("foo/bar[use_dep]");
-
- Atom::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_version_with_uppercase_letter() {
- let it = InputIter::new("=foo/bar-1.0.0V");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_version_with_version_operator_without_version() {
- let it = InputIter::new("=foo/bar");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_version_with_version_without_version_operator() {
- let it = InputIter::new("foo/bar-1.0.0");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_atom_with_eq_version_operator() {
- let it = InputIter::new("=foo/bar-1.0.0");
-
- Atom::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_atom_with_star_in_version() {
- let it = InputIter::new("=foo/bar-1.2*");
-
- Atom::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_atom_with_star_in_version_without_eq_version_operator() {
- let it = InputIter::new(">=foo/bar-1.2*");
-
- assert!(Atom::parser().check_finished(it).is_err());
- }
-
- #[test]
- fn test_atom_with_trailing_dash_and_letter() {
- let it = InputIter::new("dev-db/mysql-connector-c");
-
- Atom::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_cpv_with_slot() {
- let it = InputIter::new("foo/bar-1.0:slot/sub=");
-
- Cpv::parser().check_finished(it).unwrap();
- }
-
- #[test]
- fn test_cpv_without_version_but_trailing_almost_version() {
- let it = InputIter::new("dev-perl/mod-p-2.3_");
-
- assert!(Cpv::parser().parse_finished(it).is_err());
- }
-
- #[test]
- fn test_empty_slot_with_operator() {
- let it = InputIter::new("foo/bar:=");
-
- 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 = [
- "media-libs/libsdl2[haptitick(+),sound(+)vd,eio(+)]",
- "=kde-frameworks/kcodecs-6.19*86",
- "=dev-ml/stdio-0.17*t:=[ocamlopt?]",
- ">=dev-libs/libgee-0-8.5:0..8=",
- "<dev-haskell/wai-3.3:=[]",
- ">=kde-frameworks/kcrash-2.16.0:6*",
- "0-f/merreka+m::k+",
- "iev-a/h:/n=",
- "=dev-ml/stdio-0-17*:=[ocamlopt?]",
- ];
-
- for atom in atoms {
- assert!(
- Atom::parser().check_finished(InputIter::new(atom)).is_err(),
- "{atom}"
- );
- }
- }
-}
diff --git a/src/lib.rs b/src/lib.rs
index b7b01a7..78fe580 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,81 +11,6 @@
//! - vdb reader
//! - sourcing ebuilds with bash
//!
-
-#![deny(clippy::pedantic, unused_imports)]
-#![allow(
- dead_code,
- unstable_name_collisions,
- clippy::missing_errors_doc,
- clippy::missing_panics_doc
-)]
-#![feature(impl_trait_in_assoc_type)]
-
-use mon::{
- Parser,
- input::{Input, InputIter},
-};
-
-pub trait Parseable<'a, I: Input + 'a> {
- type Parser: Parser<I, Output = Self>;
-
- fn parser() -> Self::Parser;
-
- fn parse(input: I) -> Result<Self, I>
- where
- Self: Sized,
- {
- Self::parser()
- .parse_finished(InputIter::new(input))
- .map_err(|e| e.rest())
- }
-}
-
-/// Strongly typed atom and cpv representations.
-///
-/// Create atoms from parsers:
-/// ```
-/// use gentoo_utils::{Parseable, atom::Atom};
-///
-/// let emacs = Atom::parse("=app-editors/emacs-31.0-r1")
-/// .expect("failed to parse atom");
-///
-/// assert_eq!(emacs.to_string(), "=app-editors/emacs-31.0-r1");
-/// ````
-///
-/// Compare versions:
-/// ```
-/// use gentoo_utils::{Parseable, atom::Cpv};
-///
-/// let a = Cpv::parse("foo/bar-1.0").unwrap();
-/// let b = Cpv::parse("foo/bar-2.0").unwrap();
-///
-/// assert!(a < b);
-/// ```
-pub mod atom;
-
-/// Access to repos and ebuilds.
-///
-/// ```
-/// use gentoo_utils::repo::Repo;
-///
-/// let repo = Repo::new("/var/db/repos/gentoo");
-///
-/// for result in repo.categories().expect("failed to read categories") {
-/// let category = result.expect("failed to read category");
-///
-/// for result in category.ebuilds().expect("failed to read ebuilds") {
-/// let ebuild = result.expect("failed to read ebuild");
-///
-/// println!(
-/// "{}-{}: {}",
-/// ebuild.name(),
-/// ebuild.version(),
-/// ebuild.description().clone().unwrap_or("no description available".to_string())
-/// );
-/// }
-/// }
-///
-/// ```
-pub mod repo;
-pub mod useflag;
+pub use atom;
+pub use useflag;
+pub use repo;
diff --git a/src/meson.build b/src/meson.build
index 33a09de..8b7f4c9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,5 +1 @@
sources += files('lib.rs')
-
-subdir('atom')
-subdir('repo')
-subdir('useflag')
diff --git a/src/repo/ebuild/meson.build b/src/repo/ebuild/meson.build
deleted file mode 100644
index a7331a8..0000000
--- a/src/repo/ebuild/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-sources += files('mod.rs', 'parsers.rs')
diff --git a/src/repo/ebuild/mod.rs b/src/repo/ebuild/mod.rs
deleted file mode 100644
index 3f52db9..0000000
--- a/src/repo/ebuild/mod.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-use get::Get;
-use std::path::PathBuf;
-
-use crate::{
- atom::{Atom, Name, Slot, Version},
- useflag::{IUseFlag, UseFlag},
-};
-
-mod parsers;
-
-#[derive(Clone, Debug)]
-pub enum Conditional {
- Negative(UseFlag),
- Positive(UseFlag),
-}
-
-#[derive(Clone, Debug)]
-pub enum Depend<T> {
- Element(T),
- AllOf(Vec<Self>),
- AnyOf(Vec<Self>),
- OneOf(Vec<Self>),
- ConditionalGroup(Conditional, Vec<Self>),
-}
-
-#[derive(Debug, Clone)]
-pub enum UriPrefix {
- Mirror,
- Fetch,
-}
-
-#[derive(Debug, Clone, Get)]
-pub struct Uri {
- #[get(kind = "deref")]
- protocol: String,
- #[get(kind = "deref")]
- path: String,
-}
-
-#[derive(Debug, Clone)]
-pub enum SrcUri {
- Filename(PathBuf),
- Uri {
- prefix: Option<UriPrefix>,
- uri: Uri,
- filename: Option<PathBuf>,
- },
-}
-
-#[derive(Debug, Clone, Get)]
-pub struct License(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Debug, Clone, Get)]
-pub struct Eapi(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Debug, Clone, Get)]
-pub struct Eclass(#[get(method = "get", kind = "deref")] String);
-
-#[derive(Debug, Clone, Get)]
-pub struct Ebuild {
- pub(super) name: Name,
- pub(super) version: Version,
- pub(super) slot: Option<Slot>,
- pub(super) homepage: Option<String>,
- #[get(kind = "deref")]
- pub(super) src_uri: Vec<Depend<SrcUri>>,
- pub(super) eapi: Option<Eapi>,
- #[get(kind = "deref")]
- pub(super) inherit: Vec<Eclass>,
- #[get(kind = "deref")]
- pub(super) iuse: Vec<IUseFlag>,
- #[get(kind = "deref")]
- pub(super) license: Vec<Depend<License>>,
- pub(super) description: Option<String>,
- #[get(kind = "deref")]
- pub(super) depend: Vec<Depend<Atom>>,
- #[get(kind = "deref")]
- pub(super) bdepend: Vec<Depend<Atom>>,
- #[get(kind = "deref")]
- pub(super) rdepend: Vec<Depend<Atom>>,
- #[get(kind = "deref")]
- pub(super) idepend: Vec<Depend<Atom>>,
-}
diff --git a/src/repo/ebuild/parsers.rs b/src/repo/ebuild/parsers.rs
deleted file mode 100644
index c80cdf2..0000000
--- a/src/repo/ebuild/parsers.rs
+++ /dev/null
@@ -1,205 +0,0 @@
-use std::path::PathBuf;
-
-use mon::{
- Parser, ParserIter, ascii_alpha1, ascii_alphanumeric, ascii_whitespace1, r#if, one_of, tag,
-};
-
-use crate::{
- Parseable,
- repo::ebuild::{Conditional, Depend, Eapi, Eclass, License, SrcUri, Uri, UriPrefix},
- useflag::UseFlag,
-};
-
-impl<'a> Parseable<'a, &'a str> for UriPrefix {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- tag("+mirror")
- .map(|_| UriPrefix::Mirror)
- .or(tag("+fetch").map(|_| UriPrefix::Fetch))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Uri {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let protocol = ascii_alpha1::<&str>()
- .followed_by(tag("://"))
- .map(|output: &str| output.to_string());
- let path = r#if(|c: &char| !c.is_ascii_whitespace())
- .repeated()
- .at_least(1)
- .recognize()
- .map(|output: &str| output.to_string());
-
- protocol
- .and(path)
- .map(|(protocol, path)| Uri { protocol, path })
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for SrcUri {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let filename = || {
- r#if(|c: &char| !c.is_ascii_whitespace())
- .repeated()
- .at_least(1)
- .recognize()
- .map(|output: &str| PathBuf::from(output))
- };
-
- let uri = UriPrefix::parser()
- .opt()
- .and(Uri::parser())
- .and(filename().preceded_by(tag(" -> ")).opt())
- .map(|((prefix, uri), filename)| SrcUri::Uri {
- prefix,
- uri,
- filename,
- });
-
- uri.or(filename().map(|path: PathBuf| SrcUri::Filename(path)))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for License {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_alphanumeric().or(one_of("_".chars()));
- let rest = ascii_alphanumeric()
- .or(one_of("+_.-".chars()))
- .repeated()
- .many();
-
- start
- .and(rest)
- .recognize()
- .map(|output: &str| License(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Eapi {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_alphanumeric().or(one_of("_".chars()));
- let rest = ascii_alphanumeric()
- .or(one_of("+_.-".chars()))
- .repeated()
- .many();
-
- start
- .and(rest)
- .recognize()
- .map(|output: &str| Eapi(output.to_string()))
- }
-}
-
-// TODO:
-// Cant find information about eclass names in pms so we allow anything except
-// for whitespace.
-impl<'a> Parseable<'a, &'a str> for Eclass {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- r#if(|c: &char| !c.is_ascii_whitespace())
- .repeated()
- .at_least(1)
- .recognize()
- .map(|output: &str| Eclass(output.to_string()))
- }
-}
-
-impl<'a, T> Parseable<'a, &'a str> for Depend<T>
-where
- T: Parseable<'a, &'a str>,
-{
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- |it| {
- let exprs = || {
- Depend::parser()
- .separated_by_with_trailing(ascii_whitespace1())
- .at_least(1)
- .delimited_by(tag("(").followed_by(ascii_whitespace1()), tag(")"))
- };
-
- let all_of_group = exprs().map(|exprs| Depend::AllOf(exprs));
-
- let any_of_group = exprs()
- .preceded_by(tag("||").followed_by(ascii_whitespace1()))
- .map(|exprs| Depend::AnyOf(exprs));
-
- let one_of_group = exprs()
- .preceded_by(tag("^^").followed_by(ascii_whitespace1()))
- .map(|exprs| Depend::OneOf(exprs));
-
- let conditional_group = Conditional::parser()
- .followed_by(ascii_whitespace1())
- .and(exprs())
- .map(|(conditional, exprs)| Depend::ConditionalGroup(conditional, exprs));
-
- T::parser()
- .map(|e| Depend::Element(e))
- .or(conditional_group)
- .or(any_of_group)
- .or(all_of_group)
- .or(one_of_group)
- .parse(it)
- }
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for Conditional {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- UseFlag::parser()
- .preceded_by(tag("!"))
- .followed_by(tag("?"))
- .map(Conditional::Negative)
- .or(UseFlag::parser()
- .followed_by(tag("?"))
- .map(Conditional::Positive))
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use mon::{ParserIter, input::InputIter};
-
- use crate::{atom::Atom, repo::ebuild::Depend};
-
- use super::*;
-
- #[test]
- fn test_src_uri() {
- let tests = [
- "https://example.com/foo/bar.tar.gz",
- "https://example.com/foo/bar.tar.gz -> bar.tar.gz",
- ];
-
- for test in tests {
- SrcUri::parser()
- .check_finished(InputIter::new(test))
- .unwrap();
- }
- }
-
- #[test]
- fn test_expr() {
- let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )");
-
- Depend::<Atom>::parser()
- .separated_by(ascii_whitespace1())
- .many()
- .check_finished(it)
- .unwrap();
- }
-}
diff --git a/src/repo/meson.build b/src/repo/meson.build
deleted file mode 100644
index c1be7a7..0000000
--- a/src/repo/meson.build
+++ /dev/null
@@ -1,3 +0,0 @@
-sources += files('mod.rs')
-
-subdir('ebuild')
diff --git a/src/repo/mod.rs b/src/repo/mod.rs
deleted file mode 100644
index eb68839..0000000
--- a/src/repo/mod.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-use std::{
- fs, io,
- os::unix::ffi::OsStrExt,
- path::{Path, PathBuf},
-};
-
-use get::Get;
-
-use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter, tag};
-
-use crate::{
- Parseable,
- atom::{self, Atom},
- repo::ebuild::{Depend, Eapi, Ebuild, Eclass, License, SrcUri},
- useflag::IUseFlag,
-};
-
-pub mod ebuild;
-
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
- #[error("io error: {0}")]
- Io(PathBuf, io::Error),
- #[error("error while reading directory: {0:?}: {1}")]
- ReadDir(PathBuf, io::Error),
- #[error("failed to decode path: {0}")]
- Unicode(PathBuf),
- #[error("parser error: {0}")]
- Parser(String),
-}
-
-#[derive(Debug, Clone, Get)]
-pub struct Repo {
- #[get(kind = "deref")]
- path: PathBuf,
-}
-
-#[derive(Debug, Clone, Get)]
-pub struct Category {
- name: atom::Category,
- #[get(kind = "deref")]
- path: PathBuf,
-}
-
-#[derive(Debug)]
-pub struct Categories(PathBuf, fs::ReadDir);
-
-#[derive(Debug)]
-pub struct Ebuilds(PathBuf, fs::ReadDir);
-
-impl Repo {
- pub fn new<P: AsRef<Path>>(path: P) -> Self {
- Self {
- path: path.as_ref().to_path_buf(),
- }
- }
-
- pub fn categories(&self) -> Result<Categories, Error> {
- let path = self.path.as_path().join("metadata/md5-cache");
-
- Ok(Categories(
- path.clone(),
- fs::read_dir(&path).map_err(|e| Error::Io(path, e))?,
- ))
- }
-}
-
-impl Category {
- pub fn ebuilds(&self) -> Result<Ebuilds, Error> {
- Ok(Ebuilds(
- self.path.clone(),
- fs::read_dir(&self.path).map_err(|e| Error::Io(self.path.clone(), e))?,
- ))
- }
-}
-
-impl Iterator for Categories {
- type Item = Result<Category, Error>;
-
- fn next(&mut self) -> Option<Self::Item> {
- loop {
- match self.1.next()? {
- Ok(entry) if entry.path().file_name().unwrap().as_bytes() == b"Manifest.gz" => (),
- Ok(entry) => match read_category(entry.path()) {
- Ok(category) => break Some(Ok(category)),
- Err(e) => break Some(Err(e)),
- },
- Err(e) => break Some(Err(Error::ReadDir(self.0.clone(), e))),
- }
- }
- }
-}
-
-impl Iterator for Ebuilds {
- type Item = Result<Ebuild, Error>;
-
- fn next(&mut self) -> Option<Self::Item> {
- loop {
- match self.1.next()? {
- Ok(entry) if entry.path().file_name().unwrap().as_bytes() == b"Manifest.gz" => (),
- Ok(entry) => match read_ebuild(entry.path()) {
- Ok(ebuild) => break Some(Ok(ebuild)),
- Err(e) => break Some(Err(e)),
- },
- Err(e) => break Some(Err(Error::ReadDir(self.0.clone(), e))),
- }
- }
- }
-}
-
-fn read_category(path: PathBuf) -> Result<Category, Error> {
- let file_name = path
- .as_path()
- .file_name()
- .unwrap()
- .to_str()
- .ok_or(Error::Unicode(path.clone()))?;
-
- let name = atom::Category::parser()
- .parse_finished(InputIter::new(file_name))
- .map_err(|_| Error::Parser(file_name.to_string()))?;
-
- Ok(Category { name, path })
-}
-
-fn read_ebuild(path: PathBuf) -> Result<Ebuild, Error> {
- let file_name = path
- .as_path()
- .file_name()
- .unwrap()
- .to_str()
- .ok_or(Error::Unicode(path.clone()))?;
-
- let (name, version) = atom::Name::parser()
- .and(atom::Version::parser().preceded_by(tag("-")))
- .parse_finished(InputIter::new(file_name))
- .map_err(|_| Error::Parser(file_name.to_string()))?;
-
- let metadata = fs::read_to_string(path.as_path()).map_err(|e| Error::Io(path, e))?;
-
- Ok(Ebuild {
- name,
- version,
- slot: match read_slot(&metadata) {
- Some(Ok(slot)) => Some(slot),
- Some(Err(e)) => return Err(e),
- None => None,
- },
- homepage: read_homepage(&metadata),
- src_uri: match read_src_uri(&metadata) {
- Some(Ok(src_uri)) => src_uri,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- eapi: match read_eapi(&metadata) {
- Some(Ok(eapi)) => Some(eapi),
- Some(Err(e)) => return Err(e),
- None => None,
- },
- inherit: match read_inherit(&metadata) {
- Some(Ok(inherit)) => inherit,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- iuse: match read_iuse(&metadata) {
- Some(Ok(iuse)) => iuse,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- license: match read_license(&metadata) {
- Some(Ok(license)) => license,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- description: read_description(&metadata),
- depend: match read_depend(&metadata) {
- Some(Ok(depend)) => depend,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- bdepend: match read_bdepend(&metadata) {
- Some(Ok(depend)) => depend,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- rdepend: match read_rdepend(&metadata) {
- Some(Ok(depend)) => depend,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- idepend: match read_idepend(&metadata) {
- Some(Ok(depend)) => depend,
- Some(Err(e)) => return Err(e),
- None => Vec::new(),
- },
- })
-}
-
-fn read_slot(input: &str) -> Option<Result<atom::Slot, Error>> {
- let line = input.lines().find_map(|line| line.strip_prefix("SLOT="))?;
-
- match atom::Slot::parser().parse_finished(InputIter::new(line)) {
- Ok(slot) => Some(Ok(slot)),
- Err(_) => Some(Err(Error::Parser(line.to_string()))),
- }
-}
-
-fn read_homepage(input: &str) -> Option<String> {
- input
- .lines()
- .find_map(|line| line.strip_prefix("HOMEPAGE=").map(str::to_string))
-}
-
-fn read_src_uri(input: &str) -> Option<Result<Vec<Depend<SrcUri>>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_prefix("SRC_URI="))?;
-
- match Depend::<SrcUri>::parser()
- .separated_by(ascii_whitespace1())
- .many()
- .parse_finished(InputIter::new(line))
- {
- Ok(slot) => Some(Ok(slot)),
- Err(_) => Some(Err(Error::Parser(line.to_string()))),
- }
-}
-
-fn read_eapi(input: &str) -> Option<Result<Eapi, Error>> {
- let line = input.lines().find_map(|line| line.strip_prefix("EAPI="))?;
-
- match Eapi::parser().parse_finished(InputIter::new(line)) {
- Ok(slot) => Some(Ok(slot)),
- Err(_) => Some(Err(Error::Parser(line.to_string()))),
- }
-}
-
-fn read_inherit(input: &str) -> Option<Result<Vec<Eclass>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_prefix("INHERIT="))?;
-
- match Eclass::parser()
- .separated_by(ascii_whitespace1())
- .many()
- .parse_finished(InputIter::new(line))
- {
- Ok(inherit) => Some(Ok(inherit)),
- Err(_) => Some(Err(Error::Parser(line.to_string()))),
- }
-}
-
-fn read_iuse(input: &str) -> Option<Result<Vec<IUseFlag>, Error>> {
- let line = input.lines().find_map(|line| line.strip_prefix("IUSE="))?;
-
- match IUseFlag::parser()
- .separated_by(ascii_whitespace1())
- .many()
- .parse_finished(InputIter::new(line))
- {
- Ok(iuse) => Some(Ok(iuse)),
- Err(_) => Some(Err(Error::Parser(line.to_string()))),
- }
-}
-
-fn read_license(input: &str) -> Option<Result<Vec<Depend<License>>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_suffix("LICENSE="))?;
-
- match Depend::<License>::parser()
- .separated_by(ascii_whitespace1())
- .many()
- .parse_finished(InputIter::new(line))
- {
- Ok(license) => Some(Ok(license)),
- Err(_) => Some(Err(Error::Parser(line.to_string()))),
- }
-}
-
-fn read_description(input: &str) -> Option<String> {
- input
- .lines()
- .find_map(|line| line.strip_prefix("DESCRIPTION=").map(str::to_string))
-}
-
-fn read_depend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_prefix("DEPEND="))?;
-
- Some(parse_depends(line))
-}
-
-fn read_bdepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_prefix("BDEPEND="))?;
-
- Some(parse_depends(line))
-}
-
-fn read_rdepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_prefix("RDEPEND="))?;
-
- Some(parse_depends(line))
-}
-
-fn read_idepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
- let line = input
- .lines()
- .find_map(|line| line.strip_prefix("IDEPEND="))?;
-
- Some(parse_depends(line))
-}
-
-fn parse_depends(line: &str) -> Result<Vec<Depend<Atom>>, Error> {
- Depend::<Atom>::parser()
- .separated_by(ascii_whitespace1())
- .many()
- .parse_finished(InputIter::new(line))
- .map_err(|_| Error::Parser(line.to_string()))
-}
diff --git a/src/useflag/meson.build b/src/useflag/meson.build
deleted file mode 100644
index a7331a8..0000000
--- a/src/useflag/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-sources += files('mod.rs', 'parsers.rs')
diff --git a/src/useflag/mod.rs b/src/useflag/mod.rs
deleted file mode 100644
index c367b1a..0000000
--- a/src/useflag/mod.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use core::fmt;
-
-use get::Get;
-
-mod parsers;
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct UseFlag(#[get(method = "name", kind = "deref")] String);
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
-pub struct IUseFlag {
- default: bool,
- flag: UseFlag,
-}
-
-impl fmt::Display for UseFlag {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
diff --git a/src/useflag/parsers.rs b/src/useflag/parsers.rs
deleted file mode 100644
index ca5929d..0000000
--- a/src/useflag/parsers.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use mon::{Parser, ParserIter, ascii_alphanumeric, one_of, tag};
-
-use crate::{
- Parseable,
- useflag::{IUseFlag, UseFlag},
-};
-
-impl<'a> Parseable<'a, &'a str> for UseFlag {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- let start = ascii_alphanumeric();
- let rest = ascii_alphanumeric()
- .or(one_of("+_@-".chars()))
- .repeated()
- .many();
-
- start
- .and(rest)
- .recognize()
- .map(|output: &str| UseFlag(output.to_string()))
- }
-}
-
-impl<'a> Parseable<'a, &'a str> for IUseFlag {
- type Parser = impl Parser<&'a str, Output = Self>;
-
- fn parser() -> Self::Parser {
- UseFlag::parser()
- .preceded_by(tag("+"))
- .map(|flag| IUseFlag {
- default: true,
- flag,
- })
- .or(UseFlag::parser().map(|flag| IUseFlag {
- default: false,
- flag,
- }))
- }
-}