Skip to main content

nanite_docker/instruction/run/
mod.rs

1// WARNING: This is by far the longest and most complex system in the whole project. Most Instructions have only maybe 30 odd lines of code and were written in an hour
2// This one took me a few weekends to finally figure out how to make it ergonomic
3// ENTER AT YOUR OWN RISK
4
5use alloc::string::String;
6use alloc::vec::Vec;
7use core::fmt::{Display, Formatter};
8
9mod runmount;
10pub use runmount::{
11    RunMount, RunMountBind, RunMountBindOpts, RunMountCache, RunMountCacheOpts, RunMountSSH,
12    RunMountSSHOpts, RunMountSecret, RunMountSecretOpts, RunMountTmpfs, RunMountTmpfsOpts,
13    RunSharing,
14};
15/// Represents a `RUN` instruction.
16/// The RUN instruction is a bit more complex than other instructions, due to how mounting works.
17/// ```rust
18/// use nanite_docker::*;
19///
20/// let run = Run {
21///     argv: vec![
22///         "bash".into(),
23///         "-c".into(),
24///         "echo building && make all".into(),
25///     ],
26///     mounts: vec![
27///         RunMount::Bind(RunMountBind {
28///             target: "/mnt/bind".into(),
29///             opts: vec![RunMountBindOpts::ReadWrite],
30///         }),
31///         RunMount::Cache(RunMountCache {
32///             target: "/mnt/cache".into(),
33///             opts: vec![
34///                 RunMountCacheOpts::Id("build-cache".into()),
35///                 RunMountCacheOpts::Sharing(RunSharing::Shared),
36///                 RunMountCacheOpts::Uid(1000),
37///                 RunMountCacheOpts::Gid(1000),
38///                 RunMountCacheOpts::Mode("0o755".into()),
39///             ],
40///         }),
41///         RunMount::Ssh(RunMountSSH {
42///             target: None,
43///             opts: vec![
44///                 RunMountSSHOpts::Id("default".into()),
45///                 RunMountSSHOpts::Required,
46///             ],
47///         }),
48///         RunMount::Secret(RunMountSecret {
49///             target: Some("/run/secrets/mysecret".into()),
50///             opts: vec![
51///                 RunMountSecretOpts::Id("mysecret".into()),
52///                 RunMountSecretOpts::Required,
53///             ],
54///         }),
55///         RunMount::Tmpfs(RunMountTmpfs {
56///             target: "/mnt/tmpfs".into(),
57///             opts: vec![RunMountTmpfsOpts::Size("65536".into())],
58///         }),
59///     ],
60///     network: Some(RunNetwork::Host),
61///     security: Some(RunSecurity::Sandbox),
62/// };
63///
64/// let run_built = format!("{run}");
65/// assert_eq!(run_built, r#"RUN --mount=type=bind,target=/mnt/bind,readwrite=true --mount=type=cache,target=/mnt/cache,id=build-cache,sharing=shared,uid=1000,gid=1000,mode=0o755 --mount=type=ssh,id=default,required=true --mount=type=secret,source=/run/secrets/mysecret,id=mysecret,required=true --mount=type=tmpfs,target=/mnt/tmpfs,size=65536 --network=host --security=sandbox ["bash", "-c", "echo building && make all"]"#)
66/// ```
67#[derive(Debug, Clone)]
68pub struct Run {
69    pub argv: Vec<String>,
70    pub mounts: Vec<runmount::RunMount>,
71    pub network: Option<RunNetwork>,
72    pub security: Option<RunSecurity>,
73}
74
75impl Display for Run {
76    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
77        write!(f, "RUN ")?;
78        for i in &self.mounts {
79            match i {
80                RunMount::Bind(b) => write!(f, "{b} "),
81                RunMount::Cache(c) => write!(f, "{c} "),
82                RunMount::Tmpfs(t) => write!(f, "{t} "),
83                RunMount::Secret(s) => write!(f, "{s} "),
84                RunMount::Ssh(s) => write!(f, "{s} "),
85            }?;
86        }
87
88        match &self.network {
89            Some(n) => write!(f, "{n} ")?,
90            None => {}
91        };
92
93        match &self.security {
94            Some(s) => write!(f, "{s} ")?,
95            None => {}
96        }
97
98        write!(f, "[")?;
99
100        for (i, arg) in self.argv.iter().enumerate() {
101            if i != 0 {
102                write!(f, ", ")?;
103            }
104            write!(f, r#""{arg}""#)?;
105        }
106
107        write!(f, "]")?;
108
109        Ok(())
110    }
111}
112
113#[derive(Debug, Clone)]
114pub enum RunSecurity {
115    Sandbox,
116    Insecure,
117}
118
119impl Display for RunSecurity {
120    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
121        match self {
122            RunSecurity::Sandbox => write!(f, "--security=sandbox"),
123            RunSecurity::Insecure => write!(f, "--security=insecure"),
124        }
125    }
126}
127
128#[derive(Debug, Clone)]
129pub enum RunNetwork {
130    Default,
131    None,
132    Host,
133}
134
135impl Display for RunNetwork {
136    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
137        match self {
138            RunNetwork::Default => write!(f, "--network=default"),
139            RunNetwork::None => write!(f, "--network=none"),
140            RunNetwork::Host => write!(f, "--network=host"),
141        }
142    }
143}