forked from gentoo-utils/gentoo-utils
impl profile evaluation
This commit is contained in:
125
src/repo/profile/package_use/mod.rs
Normal file
125
src/repo/profile/package_use/mod.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||
|
||||
use crate::{
|
||||
Parseable,
|
||||
atom::Atom,
|
||||
repo::profile::{FlagOperation, LineBasedFileExpr, Profile, read_config_files},
|
||||
useflag::UseFlag,
|
||||
};
|
||||
|
||||
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)]
|
||||
struct Expr(Atom, Vec<FlagOperation>);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum Kind {
|
||||
Use,
|
||||
Force,
|
||||
Mask,
|
||||
StableForce,
|
||||
StableMask,
|
||||
}
|
||||
|
||||
pub(super) fn evaluate<P: AsRef<Path>>(
|
||||
parents: &[Profile],
|
||||
kind: Kind,
|
||||
path: P,
|
||||
) -> Result<HashMap<Atom, Vec<UseFlag>>, Error> {
|
||||
let file_path = match kind {
|
||||
Kind::Use => "package.use",
|
||||
Kind::Force => "package.use.force",
|
||||
Kind::Mask => "package.use.mask",
|
||||
Kind::StableForce => "package.use.stable.force",
|
||||
Kind::StableMask => "package.use.stable.mask",
|
||||
};
|
||||
|
||||
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) => HashMap::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,
|
||||
vars: HashMap<Atom, Vec<FlagOperation>>,
|
||||
) -> HashMap<Atom, Vec<UseFlag>> {
|
||||
let mut accumulated: HashMap<Atom, Vec<UseFlag>> = HashMap::new();
|
||||
|
||||
for parent in parents {
|
||||
let source = match kind {
|
||||
Kind::Use => parent.package_use(),
|
||||
Kind::Force => parent.package_use_force(),
|
||||
Kind::Mask => parent.package_use_mask(),
|
||||
Kind::StableForce => parent.package_use_stable_force(),
|
||||
Kind::StableMask => parent.package_use_stable_mask(),
|
||||
};
|
||||
|
||||
for (atom, flags) in source {
|
||||
accumulated
|
||||
.entry(atom.clone())
|
||||
.and_modify(|f| f.extend(flags.iter().cloned()))
|
||||
.or_insert(flags.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for (atom, flags) in vars {
|
||||
match accumulated.get_mut(&atom) {
|
||||
Some(accumulated) => {
|
||||
for flag in flags {
|
||||
match flag {
|
||||
FlagOperation::Add(flag) => accumulated.push(flag),
|
||||
FlagOperation::Remove(flag) => accumulated.retain(|v| *v != flag),
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
accumulated.insert(
|
||||
atom.clone(),
|
||||
flags
|
||||
.iter()
|
||||
.filter_map(|flag| match flag {
|
||||
FlagOperation::Add(flag) => Some(flag),
|
||||
FlagOperation::Remove(_) => None,
|
||||
})
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accumulated
|
||||
}
|
||||
|
||||
fn parse(contents: &str) -> Result<HashMap<Atom, Vec<FlagOperation>>, Error> {
|
||||
Ok(LineBasedFileExpr::<Expr>::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(Expr(atom, operations)) => Some((atom, operations)),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
Reference in New Issue
Block a user