1use std::collections::HashMap;
11
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase", default)]
17pub struct ImageSpec {
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub base: Option<BaseImage>,
21 #[serde(skip_serializing_if = "Vec::is_empty")]
23 pub build_steps: Vec<ImageBuildStep>,
24 #[serde(skip_serializing_if = "HashMap::is_empty")]
26 pub env: HashMap<String, String>,
27 #[serde(skip_serializing_if = "ImageArchitecture::is_unspecified")]
29 pub architecture: ImageArchitecture,
30 #[serde(skip_serializing_if = "String::is_empty")]
32 pub python_version: String,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
37pub enum BaseImage {
38 #[serde(rename = "BASE_IMAGE_DEBIAN")]
40 Debian,
41 #[serde(rename = "BASE_IMAGE_DEVBOX")]
45 Devbox,
46}
47
48#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
50pub enum ImageArchitecture {
51 #[default]
53 #[serde(rename = "IMAGE_ARCHITECTURE_UNSPECIFIED")]
54 Unspecified,
55 #[serde(rename = "IMAGE_ARCHITECTURE_AMD64")]
57 Amd64,
58 #[serde(rename = "IMAGE_ARCHITECTURE_ARM64")]
60 Arm64,
61}
62
63impl ImageArchitecture {
64 #[allow(clippy::trivially_copy_pass_by_ref)]
66 fn is_unspecified(&self) -> bool {
67 matches!(self, ImageArchitecture::Unspecified)
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub enum ImageBuildStep {
75 AptInstall(PackageInstall),
77 PipInstall(PackageInstall),
79 RunCommand(RunCommand),
81 AddLocalFile(AddLocalFile),
83 AddLocalDir(AddLocalDir),
85}
86
87#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
89#[serde(default)]
90pub struct PackageInstall {
91 #[serde(skip_serializing_if = "Vec::is_empty")]
93 pub packages: Vec<String>,
94}
95
96#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
98#[serde(default)]
99pub struct RunCommand {
100 #[serde(skip_serializing_if = "String::is_empty")]
102 pub command: String,
103}
104
105#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase", default)]
108pub struct AddLocalFile {
109 #[serde(skip_serializing_if = "String::is_empty")]
111 pub content_sha256: String,
112 #[serde(skip_serializing_if = "String::is_empty")]
114 pub remote_path: String,
115 #[serde(skip_serializing_if = "is_zero")]
117 pub mode: u32,
118}
119
120#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
122#[serde(rename_all = "camelCase", default)]
123pub struct AddLocalDir {
124 #[serde(skip_serializing_if = "String::is_empty")]
126 pub remote_path: String,
127 #[serde(skip_serializing_if = "Vec::is_empty")]
129 pub files: Vec<AddLocalDirFile>,
130}
131
132#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
134#[serde(rename_all = "camelCase", default)]
135pub struct AddLocalDirFile {
136 #[serde(skip_serializing_if = "String::is_empty")]
138 pub relative_path: String,
139 #[serde(skip_serializing_if = "String::is_empty")]
141 pub content_sha256: String,
142 #[serde(skip_serializing_if = "is_zero")]
144 pub mode: u32,
145}
146
147#[allow(clippy::trivially_copy_pass_by_ref)]
149fn is_zero(n: &u32) -> bool {
150 *n == 0
151}