195 lines
6.1 KiB
Rust
195 lines
6.1 KiB
Rust
//! Evaluate profiles:
|
|
//! ```rust
|
|
//! use gentoo_utils::repo::Repo;
|
|
//!
|
|
//! let repo = Repo::new("/var/db/repos/gentoo")
|
|
//! .expect("failed to open repo");
|
|
//! let profile = repo.evaluate_profile("default/linux/23.0")
|
|
//! .expect("failed to evaluate profile");
|
|
//!
|
|
//! for (key, value) in profile.make_defaults() {
|
|
//! println!("{key} = {value}");
|
|
//! }
|
|
//! ```
|
|
|
|
use std::{
|
|
collections::HashMap,
|
|
fs::{self, File},
|
|
io::{self, Read},
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use get::Get;
|
|
use itertools::Itertools;
|
|
|
|
use crate::{Parseable, atom::Atom, repo::ebuild::Eapi, useflag::UseFlag};
|
|
|
|
mod make_defaults;
|
|
mod package;
|
|
mod package_use;
|
|
mod packages;
|
|
mod parsers;
|
|
mod useflags;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(super) 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),
|
|
#[error("parser error: {0}")]
|
|
Parser(String),
|
|
}
|
|
|
|
#[derive(Debug, Clone, Get)]
|
|
pub struct Profile {
|
|
#[get(kind = "deref")]
|
|
path: PathBuf,
|
|
eapi: Eapi,
|
|
deprecated: Option<String>,
|
|
#[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 eapi_path = path.as_ref().join("eapi");
|
|
let eapi = match fs::read_to_string(&eapi_path)
|
|
.map(|s| Eapi::parse(s.trim()).map_err(str::to_string))
|
|
{
|
|
Ok(Ok(eapi)) => eapi,
|
|
Ok(Err(rest)) => return Err(Error::Parser(rest)),
|
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Eapi::parse("0").unwrap(),
|
|
Err(e) => return Err(Error::Io(eapi_path, e)),
|
|
};
|
|
|
|
let deprecated_path = path.as_ref().join("deprecated");
|
|
let deprecated = match fs::read_to_string(&deprecated_path) {
|
|
Ok(string) => Some(string),
|
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => None,
|
|
Err(e) => return Err(Error::Io(deprecated_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,
|
|
eapi,
|
|
deprecated,
|
|
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)
|
|
}
|
|
}
|