summaryrefslogtreecommitdiff
path: root/src/repo/profile/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/repo/profile/mod.rs')
-rw-r--r--src/repo/profile/mod.rs157
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)
+ }
+}