diff options
| author | John Turner <jturner.usa@gmail.com> | 2025-11-29 20:43:28 +0000 |
|---|---|---|
| committer | John Turner <jturner.usa@gmail.com> | 2025-11-29 20:50:59 +0000 |
| commit | d1127df296aa7871555293e324d125e6d8a843e1 (patch) | |
| tree | baddfab365df586207fa9c1dadf270ee94c3f46f /src/repo/profile/package | |
| parent | 94f3397d197e47eb58a7391acd9c63c5565fa26e (diff) | |
| download | gentoo-utils-profiles.tar.gz | |
impl profile evaluationprofiles
Diffstat (limited to 'src/repo/profile/package')
| -rw-r--r-- | src/repo/profile/package/mod.rs | 95 | ||||
| -rw-r--r-- | src/repo/profile/package/parsers.rs | 13 |
2 files changed, 108 insertions, 0 deletions
diff --git a/src/repo/profile/package/mod.rs b/src/repo/profile/package/mod.rs new file mode 100644 index 0000000..facf9ea --- /dev/null +++ b/src/repo/profile/package/mod.rs @@ -0,0 +1,95 @@ +use std::{ + io, + path::{Path, PathBuf}, +}; + +use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter}; + +use crate::{ + Parseable, + atom::Atom, + repo::profile::{LineBasedFileExpr, Profile, read_config_files}, +}; + +mod parsers; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("{0}: io error: {1}")] + Io(PathBuf, io::Error), + #[error("parser error: {0}")] + Parser(String), +} + +#[derive(Debug, Clone, Copy)] +pub(super) enum Kind { + Mask, + Provided, +} + +#[derive(Debug, Clone)] +enum Package { + Add(Atom), + Remove(Atom), +} + +pub(super) fn evaluate<P: AsRef<Path>>( + parents: &[Profile], + kind: Kind, + path: P, +) -> Result<Vec<Atom>, Error> { + let file_path = match kind { + Kind::Mask => "package.mask", + Kind::Provided => "package.provided", + }; + + let parsed = match read_config_files(path.as_ref().join(file_path)) { + Ok(contents) => parse(&contents)?, + Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Vec::new(), + Err(e) => return Err(Error::Io(path.as_ref().to_path_buf(), e)), + }; + + Ok(inherit(parents, kind, parsed)) +} + +fn inherit(parents: &[Profile], kind: Kind, packages: Vec<Package>) -> Vec<Atom> { + let mut accumulated = Vec::new(); + + for parent in parents { + let source = match kind { + Kind::Mask => parent.package_mask(), + Kind::Provided => parent.package_provided(), + }; + + for package in source { + accumulated.push(package.clone()); + } + } + + for package in packages { + match package { + Package::Add(package) => { + accumulated.push(package); + } + Package::Remove(package) => { + accumulated.retain(|p| *p != package); + } + } + } + + accumulated +} + +fn parse(contents: &str) -> Result<Vec<Package>, Error> { + Ok(LineBasedFileExpr::<Package>::parser() + .separated_by_with_opt_trailing(ascii_whitespace1()) + .many() + .parse_finished(InputIter::new(contents)) + .map_err(|e| Error::Parser(e.rest().to_string()))? + .into_iter() + .filter_map(|expr| match expr { + LineBasedFileExpr::Comment => None, + LineBasedFileExpr::Expr(package) => Some(package), + }) + .collect()) +} diff --git a/src/repo/profile/package/parsers.rs b/src/repo/profile/package/parsers.rs new file mode 100644 index 0000000..74d9acc --- /dev/null +++ b/src/repo/profile/package/parsers.rs @@ -0,0 +1,13 @@ +use mon::{Parser, tag}; + +use crate::{Parseable, atom::Atom, repo::profile::package::Package}; + +impl<'a> Parseable<'a, &'a str> for Package { + type Parser = impl Parser<&'a str, Output = Self>; + + fn parser() -> Self::Parser { + Atom::parser() + .map(Package::Add) + .or(Atom::parser().preceded_by(tag("-")).map(Package::Remove)) + } +} |
