diff options
Diffstat (limited to 'src/repo/profile/mod.rs')
| -rw-r--r-- | src/repo/profile/mod.rs | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/repo/profile/mod.rs b/src/repo/profile/mod.rs new file mode 100644 index 0000000..3edd170 --- /dev/null +++ b/src/repo/profile/mod.rs @@ -0,0 +1,157 @@ +use std::{ + collections::HashMap, + fs::{self, File}, + io::{self, Read}, + path::{Path, PathBuf}, +}; + +use get::Get; +use itertools::Itertools; + +use crate::{atom::Atom, useflag::UseFlag}; + +mod make_defaults; +mod package; +mod package_use; +mod packages; +mod parsers; +mod useflags; + +#[derive(Debug, Clone)] +enum LineBasedFileExpr<T> { + Comment, + Expr(T), +} + +#[derive(Debug, Clone)] +enum FlagOperation { + Add(UseFlag), + Remove(UseFlag), +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("{0}: io error: {1}")] + Io(PathBuf, io::Error), + #[error("error evaluating make.defaults settings: {0}")] + MakeDefaults(#[from] make_defaults::Error), + #[error("error evaluating packages settings: {0}")] + Packages(#[from] packages::Error), + #[error("error evaluating package settings: {0}")] + Package(#[from] package::Error), + #[error("error evaluating package.use settings: {0}")] + PackageUse(#[from] package_use::Error), + #[error("error evaluating use settings: {0}")] + Use(#[from] useflags::Error), +} + +#[derive(Debug, Clone, Get)] +pub struct Profile { + #[get(kind = "deref")] + path: PathBuf, + #[get(kind = "deref")] + parents: Vec<Profile>, + make_defaults: HashMap<String, String>, + #[get(kind = "deref")] + packages: Vec<Atom>, + #[get(kind = "deref")] + package_mask: Vec<Atom>, + #[get(kind = "deref")] + package_provided: Vec<Atom>, + package_use: HashMap<Atom, Vec<UseFlag>>, + package_use_force: HashMap<Atom, Vec<UseFlag>>, + package_use_mask: HashMap<Atom, Vec<UseFlag>>, + package_use_stable_force: HashMap<Atom, Vec<UseFlag>>, + package_use_stable_mask: HashMap<Atom, Vec<UseFlag>>, + #[get(kind = "deref")] + use_force: Vec<UseFlag>, + #[get(kind = "deref")] + use_mask: Vec<UseFlag>, + #[get(kind = "deref")] + use_stable_force: Vec<UseFlag>, + #[get(kind = "deref")] + use_stable_mask: Vec<UseFlag>, +} + +impl Profile { + pub(super) fn evaluate<P: AsRef<Path>>(path: P) -> Result<Self, Error> { + let parents_path = path.as_ref().join("parent"); + + let parents = match fs::read_to_string(&parents_path) { + Ok(parents) => parents + .lines() + .map(|line| path.as_ref().join(line)) + .map(Profile::evaluate) + .collect::<Result<_, _>>()?, + Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Vec::new(), + Err(e) => return Err(Error::Io(parents_path, e)), + }; + + let make_defaults = make_defaults::evaluate(&parents, &path)?; + + let packages = packages::evaluate(&parents, &path)?; + + let package_mask = package::evaluate(&parents, package::Kind::Mask, &path)?; + let package_provided = package::evaluate(&parents, package::Kind::Provided, &path)?; + + let package_use = package_use::evaluate(&parents, package_use::Kind::Use, &path)?; + let package_use_force = package_use::evaluate(&parents, package_use::Kind::Force, &path)?; + let package_use_mask = package_use::evaluate(&parents, package_use::Kind::Mask, &path)?; + let package_use_stable_force = + package_use::evaluate(&parents, package_use::Kind::StableForce, &path)?; + let package_use_stable_mask = + package_use::evaluate(&parents, package_use::Kind::StableMask, &path)?; + + let use_force = useflags::evaluate(&parents, useflags::Kind::Force, &path)?; + let use_mask = useflags::evaluate(&parents, useflags::Kind::Mask, &path)?; + let use_stable_force = useflags::evaluate(&parents, useflags::Kind::StableForce, &path)?; + let use_stable_mask = useflags::evaluate(&parents, useflags::Kind::StableMask, &path)?; + + Ok(Self { + path: path.as_ref().to_path_buf(), + parents, + make_defaults, + packages, + package_mask, + package_provided, + package_use, + package_use_force, + package_use_mask, + package_use_stable_force, + package_use_stable_mask, + use_force, + use_mask, + use_stable_force, + use_stable_mask, + }) + } +} + +fn read_config_files<P: AsRef<Path>>(path: P) -> Result<String, io::Error> { + let metadata = fs::metadata(&path)?; + + if metadata.is_file() { + fs::read_to_string(&path) + } else if metadata.is_dir() { + let mut buffer = String::new(); + let paths = fs::read_dir(&path)? + .collect::<Result<Vec<_>, _>>()? + .into_iter() + .map(|entry| entry.path()) + .filter(|path| path.starts_with(".")) + .sorted() + .collect::<Vec<_>>(); + + for path in &paths { + let mut file = File::open(path)?; + + file.read_to_string(&mut buffer)?; + } + + Ok(buffer) + } else { + let path = fs::canonicalize(&path)?; + + read_config_files(path) + } +} |
