1use flowey::node::prelude::*;
7use std::collections::BTreeMap;
8
9#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
10pub enum OpenvmmDepsArch {
11 X86_64,
12 Aarch64,
13}
14
15flowey_request! {
16 pub enum Request {
17 LocalPath(OpenvmmDepsArch, ReadVar<PathBuf>),
19 Version(String),
21 GetLinuxTestKernel(OpenvmmDepsArch, WriteVar<PathBuf>),
22 GetLinuxTestInitrd(OpenvmmDepsArch, WriteVar<PathBuf>),
23 GetOpenhclCpioDbgrd(OpenvmmDepsArch, WriteVar<PathBuf>),
24 GetOpenhclCpioShell(OpenvmmDepsArch, WriteVar<PathBuf>),
25 GetOpenhclSysroot(OpenvmmDepsArch, WriteVar<PathBuf>),
26 }
27}
28
29new_flow_node!(struct Node);
30
31impl FlowNode for Node {
32 type Request = Request;
33
34 fn imports(ctx: &mut ImportCtx<'_>) {
35 ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
36 ctx.import::<flowey_lib_common::download_gh_release::Node>();
37 }
38
39 fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
40 let mut version = None;
41 let mut local_paths: BTreeMap<OpenvmmDepsArch, ReadVar<PathBuf>> = BTreeMap::new();
42 let mut linux_test_kernel: BTreeMap<_, Vec<_>> = BTreeMap::new();
43 let mut linux_test_initrd: BTreeMap<_, Vec<_>> = BTreeMap::new();
44 let mut openhcl_cpio_dbgrd: BTreeMap<_, Vec<_>> = BTreeMap::new();
45 let mut openhcl_cpio_shell: BTreeMap<_, Vec<_>> = BTreeMap::new();
46 let mut openhcl_sysroot: BTreeMap<_, Vec<_>> = BTreeMap::new();
47
48 for req in requests {
49 match req {
50 Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
51 Request::LocalPath(arch, path) => {
52 if local_paths.contains_key(&arch) {
53 anyhow::bail!("Duplicate LocalPath requests for {:?}", arch,);
54 }
55 local_paths.insert(arch, path);
56 }
57 Request::GetLinuxTestKernel(arch, var) => {
58 linux_test_kernel.entry(arch).or_default().push(var)
59 }
60 Request::GetLinuxTestInitrd(arch, var) => {
61 linux_test_initrd.entry(arch).or_default().push(var)
62 }
63 Request::GetOpenhclCpioDbgrd(arch, var) => {
64 openhcl_cpio_dbgrd.entry(arch).or_default().push(var)
65 }
66 Request::GetOpenhclCpioShell(arch, var) => {
67 openhcl_cpio_shell.entry(arch).or_default().push(var)
68 }
69 Request::GetOpenhclSysroot(arch, var) => {
70 openhcl_sysroot.entry(arch).or_default().push(var)
71 }
72 }
73 }
74
75 if version.is_some() && !local_paths.is_empty() {
76 anyhow::bail!("Cannot specify both Version and LocalPath requests");
77 }
78
79 if version.is_none() && local_paths.is_empty() {
80 anyhow::bail!("Must specify a Version or LocalPath request");
81 }
82
83 if linux_test_kernel.is_empty()
86 && linux_test_initrd.is_empty()
87 && openhcl_cpio_dbgrd.is_empty()
88 && openhcl_cpio_shell.is_empty()
89 && openhcl_sysroot.is_empty()
90 {
91 return Ok(());
92 }
93
94 if !local_paths.is_empty() {
95 ctx.emit_rust_step("use local openvmm-deps", |ctx| {
96 let linux_test_kernel = linux_test_kernel.claim(ctx);
97 let linux_test_initrd = linux_test_initrd.claim(ctx);
98 let openhcl_cpio_dbgrd = openhcl_cpio_dbgrd.claim(ctx);
99 let openhcl_cpio_shell = openhcl_cpio_shell.claim(ctx);
100 let openhcl_sysroot = openhcl_sysroot.claim(ctx);
101 let local_paths: BTreeMap<_, _> = local_paths
102 .into_iter()
103 .map(|(arch, var)| (arch, var.claim(ctx)))
104 .collect();
105 move |rt| {
106 let resolved_paths: BTreeMap<OpenvmmDepsArch, PathBuf> = local_paths
107 .into_iter()
108 .map(|(arch, var)| (arch, rt.read(var)))
109 .collect();
110
111 let get_base_dir = |arch: OpenvmmDepsArch| -> anyhow::Result<&PathBuf> {
112 resolved_paths.get(&arch).ok_or_else(|| {
113 anyhow::anyhow!("No local path specified for architecture {:?}", arch)
114 })
115 };
116
117 let kernel_file_name = |arch| match arch {
118 OpenvmmDepsArch::X86_64 => "vmlinux",
119 OpenvmmDepsArch::Aarch64 => "Image",
120 };
121
122 for (arch, vars) in linux_test_kernel {
123 let base_dir = get_base_dir(arch)?;
124 let path = base_dir.join(kernel_file_name(arch));
125 rt.write_all(vars, &path)
126 }
127
128 for (arch, vars) in linux_test_initrd {
129 let base_dir = get_base_dir(arch)?;
130 let path = base_dir.join("initrd");
131 rt.write_all(vars, &path)
132 }
133
134 for (arch, vars) in openhcl_cpio_dbgrd {
135 let base_dir = get_base_dir(arch)?;
136 let path = base_dir.join("dbgrd.cpio.gz");
137 rt.write_all(vars, &path)
138 }
139
140 for (arch, vars) in openhcl_cpio_shell {
141 let base_dir = get_base_dir(arch)?;
142 let path = base_dir.join("shell.cpio.gz");
143 rt.write_all(vars, &path)
144 }
145
146 for (arch, vars) in openhcl_sysroot {
147 let base_dir = get_base_dir(arch)?;
148 let path = base_dir.join("sysroot.tar.gz");
149 rt.write_all(vars, &path)
150 }
151
152 Ok(())
153 }
154 });
155
156 return Ok(());
157 }
158
159 let extract_tar_bz2_deps =
160 flowey_lib_common::_util::extract::extract_tar_bz2_if_new_deps(ctx);
161
162 let openvmm_deps_tar_bz2_x64 = if linux_test_initrd.contains_key(&OpenvmmDepsArch::X86_64)
163 || linux_test_kernel.contains_key(&OpenvmmDepsArch::X86_64)
164 || openhcl_cpio_dbgrd.contains_key(&OpenvmmDepsArch::X86_64)
165 || openhcl_cpio_shell.contains_key(&OpenvmmDepsArch::X86_64)
166 || openhcl_sysroot.contains_key(&OpenvmmDepsArch::X86_64)
167 {
168 let version = version.clone().expect("local requests handled above");
169 Some(
170 ctx.reqv(|v| flowey_lib_common::download_gh_release::Request {
171 repo_owner: "microsoft".into(),
172 repo_name: "openvmm-deps".into(),
173 needs_auth: false,
174 tag: version.clone(),
175 file_name: format!("openvmm-deps.x86_64.{version}.tar.bz2"),
176 path: v,
177 }),
178 )
179 } else {
180 None
181 };
182
183 let openvmm_deps_tar_bz2_aarch64 = if linux_test_initrd
184 .contains_key(&OpenvmmDepsArch::Aarch64)
185 || linux_test_kernel.contains_key(&OpenvmmDepsArch::Aarch64)
186 || openhcl_cpio_dbgrd.contains_key(&OpenvmmDepsArch::Aarch64)
187 || openhcl_cpio_shell.contains_key(&OpenvmmDepsArch::Aarch64)
188 || openhcl_sysroot.contains_key(&OpenvmmDepsArch::Aarch64)
189 {
190 let version = version.clone().expect("local requests handled above");
191 Some(
192 ctx.reqv(|v| flowey_lib_common::download_gh_release::Request {
193 repo_owner: "microsoft".into(),
194 repo_name: "openvmm-deps".into(),
195 needs_auth: false,
196 tag: version.clone(),
197 file_name: format!("openvmm-deps.aarch64.{version}.tar.bz2"),
198 path: v,
199 }),
200 )
201 } else {
202 None
203 };
204
205 ctx.emit_rust_step("unpack openvmm-deps archive", |ctx| {
206 let extract_tar_bz2_deps = extract_tar_bz2_deps.claim(ctx);
207 let openvmm_deps_tar_bz2_x64 = openvmm_deps_tar_bz2_x64.claim(ctx);
208 let openvmm_deps_tar_bz2_aarch64 = openvmm_deps_tar_bz2_aarch64.claim(ctx);
209
210 let linux_test_kernel = linux_test_kernel.claim(ctx);
211 let linux_test_initrd = linux_test_initrd.claim(ctx);
212 let openhcl_cpio_dbgrd = openhcl_cpio_dbgrd.claim(ctx);
213 let openhcl_cpio_shell = openhcl_cpio_shell.claim(ctx);
214 let openhcl_sysroot = openhcl_sysroot.claim(ctx);
215 let version = version.clone().expect("local requests handled above");
216 move |rt| {
217 let extract_dir_x64 = openvmm_deps_tar_bz2_x64
218 .map(|file| {
219 let file = rt.read(file);
220 flowey_lib_common::_util::extract::extract_tar_bz2_if_new(
221 rt,
222 extract_tar_bz2_deps.clone(),
223 &file,
224 &version,
225 )
226 })
227 .transpose()?;
228 let extract_dir_aarch64 = openvmm_deps_tar_bz2_aarch64
229 .map(|file| {
230 let file = rt.read(file);
231 flowey_lib_common::_util::extract::extract_tar_bz2_if_new(
232 rt,
233 extract_tar_bz2_deps.clone(),
234 &file,
235 &version,
236 )
237 })
238 .transpose()?;
239
240 let base_dir = move |arch| match arch {
241 OpenvmmDepsArch::X86_64 => extract_dir_x64.clone().unwrap(),
242 OpenvmmDepsArch::Aarch64 => extract_dir_aarch64.clone().unwrap(),
243 };
244
245 let kernel_file_name = |arch| match arch {
246 OpenvmmDepsArch::X86_64 => "vmlinux",
247 OpenvmmDepsArch::Aarch64 => "Image",
248 };
249
250 for (arch, vars) in linux_test_kernel {
251 let path = base_dir(arch).join(kernel_file_name(arch));
252 rt.write_all(vars, &path)
253 }
254
255 for (arch, vars) in linux_test_initrd {
256 let path = base_dir(arch).join("initrd");
257 rt.write_all(vars, &path)
258 }
259
260 for (arch, vars) in openhcl_cpio_dbgrd {
261 let path = base_dir(arch).join("dbgrd.cpio.gz");
262 rt.write_all(vars, &path)
263 }
264
265 for (arch, vars) in openhcl_cpio_shell {
266 let path = base_dir(arch).join("shell.cpio.gz");
267 rt.write_all(vars, &path)
268 }
269
270 for (arch, vars) in openhcl_sysroot {
271 let path = base_dir(arch).join("sysroot.tar.gz");
272 rt.write_all(vars, &path)
273 }
274
275 Ok(())
276 }
277 });
278
279 Ok(())
280 }
281}