flowey_lib_hvlite/
download_openhcl_kernel_package.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Download pre-built OpenHCL kernel packages from their GitHub Release
5
6use flowey::node::prelude::*;
7use std::collections::BTreeMap;
8
9#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
10pub enum OpenhclKernelPackageKind {
11    Main,
12    Cvm,
13    Dev,
14    CvmDev,
15}
16
17#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
18pub enum OpenhclKernelPackageArch {
19    X86_64,
20    Aarch64,
21}
22
23flowey_request! {
24    pub enum Request {
25        /// Specify version string to use for each package kind
26        Version(OpenhclKernelPackageKind, String),
27        /// Download the specified kernel package
28        GetPackage {
29            kind: OpenhclKernelPackageKind,
30            arch: OpenhclKernelPackageArch,
31            pkg: WriteVar<PathBuf>
32        }
33    }
34}
35
36new_flow_node!(struct Node);
37
38impl FlowNode for Node {
39    type Request = Request;
40
41    fn imports(ctx: &mut ImportCtx<'_>) {
42        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
43        ctx.import::<flowey_lib_common::download_gh_release::Node>();
44    }
45
46    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
47        let mut versions: BTreeMap<OpenhclKernelPackageKind, String> = BTreeMap::new();
48        let mut reqs: BTreeMap<
49            (OpenhclKernelPackageKind, OpenhclKernelPackageArch),
50            Vec<WriteVar<PathBuf>>,
51        > = BTreeMap::new();
52
53        for req in requests {
54            match req {
55                Request::Version(arch, v) => {
56                    let mut old = versions.insert(arch, v.clone());
57                    same_across_all_reqs("SetVersion", &mut old, v)?
58                }
59                Request::GetPackage { kind, arch, pkg } => {
60                    reqs.entry((kind, arch)).or_default().push(pkg)
61                }
62            }
63        }
64
65        for req_kind in reqs.keys().map(|(k, _)| k) {
66            if !versions.contains_key(req_kind) {
67                anyhow::bail!("missing SetVersion for {:?}", req_kind)
68            }
69        }
70
71        // -- end of req processing -- //
72
73        if reqs.is_empty() {
74            return Ok(());
75        }
76
77        let extract_zip_deps = flowey_lib_common::_util::extract::extract_zip_if_new_deps(ctx);
78
79        for ((kind, arch), out_vars) in reqs {
80            let version = versions.get(&kind).expect("checked above");
81            let tag = format!(
82                "rolling-lts/hcl-{}/{}",
83                match kind {
84                    OpenhclKernelPackageKind::Main | OpenhclKernelPackageKind::Cvm => "main",
85                    OpenhclKernelPackageKind::Dev | OpenhclKernelPackageKind::CvmDev => "dev",
86                },
87                version
88            );
89
90            let file_name = format!(
91                "Microsoft.OHCL.Kernel{}.{}{}-{}.tar.gz",
92                match kind {
93                    OpenhclKernelPackageKind::Main | OpenhclKernelPackageKind::Cvm => {
94                        ""
95                    }
96                    OpenhclKernelPackageKind::Dev | OpenhclKernelPackageKind::CvmDev => {
97                        ".Dev"
98                    }
99                },
100                version,
101                match kind {
102                    OpenhclKernelPackageKind::Main | OpenhclKernelPackageKind::Dev => "",
103                    OpenhclKernelPackageKind::Cvm | OpenhclKernelPackageKind::CvmDev => "-cvm",
104                },
105                match arch {
106                    OpenhclKernelPackageArch::X86_64 => "x64",
107                    OpenhclKernelPackageArch::Aarch64 => "arm64",
108                },
109            );
110
111            let kernel_package_tar_gz =
112                ctx.reqv(|v| flowey_lib_common::download_gh_release::Request {
113                    repo_owner: "microsoft".into(),
114                    repo_name: "OHCL-Linux-Kernel".into(),
115                    needs_auth: false,
116                    tag,
117                    file_name: file_name.clone(),
118                    path: v,
119                });
120
121            ctx.emit_rust_step("unpack kernel package", |ctx| {
122                let extract_zip_deps = extract_zip_deps.clone().claim(ctx);
123                let out_vars = out_vars.claim(ctx);
124                let kernel_package_tar_gz = kernel_package_tar_gz.claim(ctx);
125                move |rt| {
126                    let kernel_package_tar_gz = rt.read(kernel_package_tar_gz);
127
128                    let extract_dir = flowey_lib_common::_util::extract::extract_zip_if_new(
129                        rt,
130                        extract_zip_deps,
131                        &kernel_package_tar_gz,
132                        &file_name, // filename includes version and arch
133                    )?;
134
135                    let base_dir = std::env::current_dir()?;
136
137                    if cfg!(unix) {
138                        #[cfg(unix)]
139                        {
140                            // HACK: recreate the layout used by nuget packages.
141                            let nuget_path = "build/native/bin";
142                            let metadata_file = "kernel_build_metadata.json";
143                            fs_err::create_dir_all(nuget_path)?;
144                            fs_err::os::unix::fs::symlink(
145                                extract_dir.join(metadata_file),
146                                format!("{}/{}", nuget_path, metadata_file),
147                            )?;
148
149                            fs_err::os::unix::fs::symlink(
150                                extract_dir,
151                                format!(
152                                    "{}/{}",
153                                    nuget_path,
154                                    match arch {
155                                        OpenhclKernelPackageArch::X86_64 => "x64",
156                                        OpenhclKernelPackageArch::Aarch64 => "arm64",
157                                    }
158                                ),
159                            )?;
160                        }
161                    } else {
162                        let _ = extract_dir;
163                        anyhow::bail!(
164                            "cannot download openhcl kernel package on non-unix machines"
165                        );
166                    }
167
168                    rt.write_all(out_vars, &base_dir);
169
170                    Ok(())
171                }
172            });
173        }
174
175        Ok(())
176    }
177}