impl profile evaluation
This commit is contained in:
75
src/repo/profile/packages/mod.rs
Normal file
75
src/repo/profile/packages/mod.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use std::{
|
||||
fs, io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||
|
||||
use crate::{
|
||||
Parseable,
|
||||
atom::Atom,
|
||||
repo::profile::{LineBasedFileExpr, Profile},
|
||||
};
|
||||
|
||||
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)]
|
||||
enum Package {
|
||||
Add(Atom),
|
||||
Remove(Atom),
|
||||
}
|
||||
|
||||
pub(super) fn evaluate<P: AsRef<Path>>(parents: &[Profile], path: P) -> Result<Vec<Atom>, Error> {
|
||||
let parsed = match fs::read_to_string(path.as_ref().join("packages")) {
|
||||
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, parsed))
|
||||
}
|
||||
|
||||
fn inherit(parents: &[Profile], packages: Vec<Package>) -> Vec<Atom> {
|
||||
let mut accumulated = Vec::new();
|
||||
|
||||
for parent in parents {
|
||||
for package in parent.packages() {
|
||||
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())
|
||||
}
|
||||
14
src/repo/profile/packages/parsers.rs
Normal file
14
src/repo/profile/packages/parsers.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use mon::{Parser, tag};
|
||||
|
||||
use crate::{Parseable, atom::Atom, repo::profile::packages::Package};
|
||||
|
||||
impl<'a> Parseable<'a, &'a str> for Package {
|
||||
type Parser = impl Parser<&'a str, Output = Self>;
|
||||
|
||||
fn parser() -> Self::Parser {
|
||||
Atom::parser()
|
||||
.preceded_by(tag("*"))
|
||||
.map(Package::Add)
|
||||
.or(Atom::parser().preceded_by(tag("-*")).map(Package::Remove))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user