flowey_lib_hvlite/
resolve_openvmm_deps.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Download various pre-built `openvmm-deps` dependencies, or use a local path if specified.
5
6use 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        /// Use a locally downloaded openvmm-deps for a specific architecture
18        LocalPath(OpenvmmDepsArch, PathBuf),
19        /// Specify version of the github release to pull from
20        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, 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 let Some(existing) = local_paths.get(&arch) {
53                        if existing != &path {
54                            anyhow::bail!(
55                                "Conflicting LocalPath requests for {:?}: {:?} vs {:?}",
56                                arch,
57                                existing,
58                                path
59                            );
60                        }
61                    } else {
62                        local_paths.insert(arch, path);
63                    }
64                }
65                Request::GetLinuxTestKernel(arch, var) => {
66                    linux_test_kernel.entry(arch).or_default().push(var)
67                }
68                Request::GetLinuxTestInitrd(arch, var) => {
69                    linux_test_initrd.entry(arch).or_default().push(var)
70                }
71                Request::GetOpenhclCpioDbgrd(arch, var) => {
72                    openhcl_cpio_dbgrd.entry(arch).or_default().push(var)
73                }
74                Request::GetOpenhclCpioShell(arch, var) => {
75                    openhcl_cpio_shell.entry(arch).or_default().push(var)
76                }
77                Request::GetOpenhclSysroot(arch, var) => {
78                    openhcl_sysroot.entry(arch).or_default().push(var)
79                }
80            }
81        }
82
83        if version.is_some() && !local_paths.is_empty() {
84            anyhow::bail!("Cannot specify both Version and LocalPath requests");
85        }
86
87        if version.is_none() && local_paths.is_empty() {
88            anyhow::bail!("Must specify a Version or LocalPath request");
89        }
90
91        // -- end of req processing -- //
92
93        if linux_test_kernel.is_empty()
94            && linux_test_initrd.is_empty()
95            && openhcl_cpio_dbgrd.is_empty()
96            && openhcl_cpio_shell.is_empty()
97            && openhcl_sysroot.is_empty()
98        {
99            return Ok(());
100        }
101
102        if !local_paths.is_empty() {
103            ctx.emit_rust_step("use local openvmm-deps", |ctx| {
104                let linux_test_kernel = linux_test_kernel.claim(ctx);
105                let linux_test_initrd = linux_test_initrd.claim(ctx);
106                let openhcl_cpio_dbgrd = openhcl_cpio_dbgrd.claim(ctx);
107                let openhcl_cpio_shell = openhcl_cpio_shell.claim(ctx);
108                let openhcl_sysroot = openhcl_sysroot.claim(ctx);
109                let local_paths = local_paths.clone();
110                move |rt| {
111                    let get_base_dir = |arch: OpenvmmDepsArch| {
112                        local_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}