1use std::fmt;
9use std::str::FromStr;
10
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21#[serde(rename_all = "kebab-case")]
22pub enum BuilderBackendKind {
23 BuildahCli,
24 BuildahSidecar,
25 Sandbox,
26 Hcs,
27 Wsl2Buildah,
28}
29
30impl BuilderBackendKind {
31 #[must_use]
33 pub const fn as_str(self) -> &'static str {
34 match self {
35 Self::BuildahCli => "buildah-cli",
36 Self::BuildahSidecar => "buildah-sidecar",
37 Self::Sandbox => "sandbox",
38 Self::Hcs => "hcs",
39 Self::Wsl2Buildah => "wsl2",
40 }
41 }
42}
43
44impl fmt::Display for BuilderBackendKind {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.write_str(self.as_str())
47 }
48}
49
50impl FromStr for BuilderBackendKind {
51 type Err = String;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 match s.trim().to_ascii_lowercase().as_str() {
55 "buildah-cli" | "buildah" | "cli" => Ok(Self::BuildahCli),
56 "buildah-sidecar" | "sidecar" | "buildd" => Ok(Self::BuildahSidecar),
57 "sandbox" | "macos-sandbox" => Ok(Self::Sandbox),
58 "hcs" | "windows-hcs" => Ok(Self::Hcs),
59 "wsl2" | "wsl2-buildah" | "wsl" => Ok(Self::Wsl2Buildah),
60 other => Err(format!(
61 "unknown builder backend kind: {other:?} (expected one of: \
62 buildah-cli, buildah-sidecar, sandbox, hcs, wsl2)"
63 )),
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub struct SidecarConfig {
76 #[serde(skip_serializing_if = "Option::is_none")]
79 pub addr: Option<String>,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
84 pub tls_dir: Option<std::path::PathBuf>,
85
86 #[serde(default = "SidecarConfig::default_idle_secs")]
90 pub idle_secs: u64,
91
92 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub storage_graph_root: Option<std::path::PathBuf>,
96
97 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub storage_run_root: Option<std::path::PathBuf>,
100
101 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub storage_driver: Option<String>,
105
106 #[serde(default, skip_serializing_if = "Option::is_none")]
119 pub context_mount: Option<(std::path::PathBuf, std::path::PathBuf)>,
120}
121
122impl SidecarConfig {
123 pub const DEFAULT_IDLE_SECS: u64 = 30;
124
125 #[must_use]
126 pub fn default_idle_secs() -> u64 {
127 Self::DEFAULT_IDLE_SECS
128 }
129}
130
131impl Default for SidecarConfig {
132 fn default() -> Self {
133 Self {
134 addr: None,
135 tls_dir: None,
136 idle_secs: Self::DEFAULT_IDLE_SECS,
137 storage_graph_root: None,
138 storage_run_root: None,
139 storage_driver: None,
140 context_mount: None,
141 }
142 }
143}
144
145#[derive(Debug, Clone, Default, Serialize, Deserialize)]
151#[allow(clippy::struct_excessive_bools)]
152pub struct BuildSidecarRequest {
153 pub context_dir: String,
154 pub dockerfile_paths: Vec<String>,
155 pub tags: Vec<String>,
156 pub platforms: Vec<String>,
157 pub build_args: std::collections::BTreeMap<String, String>,
158 pub secrets: Vec<String>,
159 pub ssh: Vec<String>,
160 pub target_stage: Option<String>,
161 pub host_network: bool,
162 pub cache_from: Option<String>,
163 pub cache_to: Option<String>,
164 pub no_cache: bool,
165 pub squash: bool,
166 pub layers: bool,
167 pub format: Option<String>,
168 pub pull_policy: Option<String>,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
176#[serde(tag = "type", rename_all = "snake_case")]
177pub enum BuildSidecarEvent {
178 StageStarted {
179 index: u32,
180 name: Option<String>,
181 base_image: String,
182 },
183 StageFinished {
184 index: u32,
185 },
186 InstructionStarted {
187 stage: u32,
188 index: u32,
189 instruction: String,
190 },
191 InstructionFinished {
192 stage: u32,
193 index: u32,
194 cached: bool,
195 },
196 Log {
197 line: String,
198 is_stderr: bool,
199 },
200 Warning {
201 message: String,
202 },
203 Finished {
204 image_id: String,
205 manifest_ref: Option<String>,
206 },
207 Error {
208 message: String,
209 },
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn backend_kind_round_trips_through_as_str() {
218 for kind in [
219 BuilderBackendKind::BuildahCli,
220 BuilderBackendKind::BuildahSidecar,
221 BuilderBackendKind::Sandbox,
222 BuilderBackendKind::Hcs,
223 BuilderBackendKind::Wsl2Buildah,
224 ] {
225 assert_eq!(BuilderBackendKind::from_str(kind.as_str()).unwrap(), kind);
226 }
227 }
228
229 #[test]
230 fn backend_kind_accepts_aliases() {
231 assert_eq!(
232 BuilderBackendKind::from_str("buildah").unwrap(),
233 BuilderBackendKind::BuildahCli
234 );
235 assert_eq!(
236 BuilderBackendKind::from_str("sidecar").unwrap(),
237 BuilderBackendKind::BuildahSidecar
238 );
239 assert_eq!(
240 BuilderBackendKind::from_str("BUILDAH-SIDECAR").unwrap(),
241 BuilderBackendKind::BuildahSidecar
242 );
243 }
244
245 #[test]
246 fn sidecar_config_idle_default() {
247 let cfg = SidecarConfig::default();
248 assert_eq!(cfg.idle_secs, 30);
249 assert!(cfg.addr.is_none());
250 assert!(cfg.tls_dir.is_none());
251 assert!(cfg.storage_graph_root.is_none());
252 assert!(cfg.storage_run_root.is_none());
253 assert!(cfg.storage_driver.is_none());
254 }
255}