summaryrefslogtreecommitdiff
path: root/src/hasher.rs
blob: da00778e6a8470491a539bc3eeddb7bb7650b6dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::ffi::OsString;
use std::process::Command;

use anyhow::{Context, Result, bail};

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