Files
gentoo-utils-gitea/src/repo/profile/mod.rs
John Turner b929ddcafe
All checks were successful
Gentoo Utils / build-oci-image (pull_request) Successful in 3s
Gentoo Utils / build (pull_request) Successful in 44s
read global package.mask
2025-12-13 04:49:28 +00:00

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)
}
}