76 lines
1.9 KiB
Rust
76 lines
1.9 KiB
Rust
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())
|
|
}
|