summaryrefslogtreecommitdiff
path: root/src/hasher.rs
diff options
context:
space:
mode:
authorHermes Agent <hermes@localhost>2026-08-12 01:06:37 +0000
committerHermes Agent <hermes@localhost>2026-08-12 01:06:37 +0000
commit915fcc5efbf45d8adee870cfbe2a25e466454a2f (patch)
treed5fdf2a745f905bd5fcce2ddac14d3e1c7a852e9 /src/hasher.rs
parentfacbf9629f45b95d34a4d0844e617f87a35be5ff (diff)
Isolate Hasher behind typed installer adapter
Diffstat (limited to 'src/hasher.rs')
-rw-r--r--src/hasher.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/hasher.rs b/src/hasher.rs
new file mode 100644
index 0000000..0be1808
--- /dev/null
+++ b/src/hasher.rs
@@ -0,0 +1,95 @@
+use std::ffi::OsString;
+use std::process::Command;
+
+use anyhow::{bail, Context, Result};
+
+use crate::package_installer::{PackageInstaller, PackageRequest};
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Invocation {
+ program: OsString,
+ arguments: Vec<OsString>,
+}
+
+impl Invocation {
+ pub fn new(
+ program: impl Into<OsString>,
+ arguments: impl IntoIterator<Item = impl Into<OsString>>,
+ ) -> Self {
+ Self {
+ program: program.into(),
+ arguments: arguments.into_iter().map(Into::into).collect(),
+ }
+ }
+
+ pub fn program(&self) -> &OsString {
+ &self.program
+ }
+
+ pub fn arguments(&self) -> &[OsString] {
+ &self.arguments
+ }
+}
+
+pub trait CommandRunner {
+ fn run(&self, invocation: Invocation) -> Result<()>;
+}
+
+#[derive(Debug, Default, Clone, Copy)]
+pub struct ProcessRunner;
+
+impl CommandRunner for ProcessRunner {
+ fn run(&self, invocation: Invocation) -> Result<()> {
+ let status = Command::new(&invocation.program)
+ .args(&invocation.arguments)
+ .status()
+ .with_context(|| format!("run {}", invocation.program.to_string_lossy()))?;
+ if !status.success() {
+ bail!(
+ "{} exited with {status}",
+ invocation.program.to_string_lossy()
+ );
+ }
+ Ok(())
+ }
+}
+
+#[derive(Debug)]
+pub struct HasherInstaller<R> {
+ runner: R,
+}
+
+impl<R> HasherInstaller<R> {
+ pub fn new(runner: R) -> Self {
+ Self { runner }
+ }
+
+ pub fn runner(&self) -> &R {
+ &self.runner
+ }
+}
+
+impl<R: CommandRunner> PackageInstaller for HasherInstaller<R> {
+ fn install(&self, request: &PackageRequest) -> Result<()> {
+ self.runner.run(Invocation::new(
+ "hsh",
+ [
+ "--mountpoints=/proc".into(),
+ "--initroot-only".into(),
+ "--apt-config".into(),
+ request.apt_config().as_path().as_os_str().to_owned(),
+ "--workdir".into(),
+ request.workdir().as_os_str().to_owned(),
+ ],
+ ))?;
+
+ let mut arguments = vec![
+ OsString::from("--mountpoints=/proc"),
+ OsString::from("--workdir"),
+ request.workdir().as_os_str().to_owned(),
+ ];
+ arguments.extend(request.selectors().iter().map(OsString::from));
+ arguments.extend(request.packages().iter().map(OsString::from));
+ self.runner.run(Invocation::new("hsh-install", arguments))
+ }
+}