diff options
| author | Hermes Agent <hermes@localhost> | 2026-08-12 01:06:37 +0000 |
|---|---|---|
| committer | Hermes Agent <hermes@localhost> | 2026-08-12 01:06:37 +0000 |
| commit | 915fcc5efbf45d8adee870cfbe2a25e466454a2f (patch) | |
| tree | d5fdf2a745f905bd5fcce2ddac14d3e1c7a852e9 /src/package_installer.rs | |
| parent | facbf9629f45b95d34a4d0844e617f87a35be5ff (diff) | |
Isolate Hasher behind typed installer adapter
Diffstat (limited to 'src/package_installer.rs')
| -rw-r--r-- | src/package_installer.rs | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/src/package_installer.rs b/src/package_installer.rs new file mode 100644 index 0000000..b08c469 --- /dev/null +++ b/src/package_installer.rs @@ -0,0 +1,91 @@ +use std::path::{Path, PathBuf}; + +use anyhow::{bail, Result}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AptConfig(PathBuf); + +impl AptConfig { + pub fn new(path: impl AsRef<Path>) -> Result<Self> { + let path = path.as_ref(); + if path.as_os_str().is_empty() || path.is_dir() { + bail!("APT configuration must be a file path: {}", path.display()); + } + Ok(Self(path.to_path_buf())) + } + + pub fn as_path(&self) -> &Path { + &self.0 + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PackageRequest { + workdir: PathBuf, + apt_config: AptConfig, + packages: Vec<String>, + selectors: Vec<String>, +} + +impl PackageRequest { + pub fn new( + workdir: impl AsRef<Path>, + apt_config: AptConfig, + packages: impl IntoIterator<Item = impl Into<String>>, + selectors: impl IntoIterator<Item = impl Into<String>>, + ) -> Result<Self> { + let workdir = workdir.as_ref(); + if workdir.as_os_str().is_empty() { + bail!("Hasher workdir cannot be empty"); + } + + let mut packages = normalize("package", packages)?; + let mut selectors = normalize("package selector", selectors)?; + packages.sort(); + packages.dedup(); + selectors.sort(); + selectors.dedup(); + Ok(Self { + workdir: workdir.to_path_buf(), + apt_config, + packages, + selectors, + }) + } + + pub fn workdir(&self) -> &Path { + &self.workdir + } + + pub fn apt_config(&self) -> &AptConfig { + &self.apt_config + } + + pub fn packages(&self) -> &[String] { + &self.packages + } + + pub fn selectors(&self) -> &[String] { + &self.selectors + } +} + +fn normalize( + kind: &str, + values: impl IntoIterator<Item = impl Into<String>>, +) -> Result<Vec<String>> { + values + .into_iter() + .map(Into::into) + .map(|value: String| { + if value.trim().is_empty() { + bail!("{kind} cannot be empty"); + } + Ok(value) + }) + .collect() +} + +pub trait PackageInstaller { + fn install(&self, request: &PackageRequest) -> Result<()>; +} |