1use flowey::node::prelude::ReadVar;
7use flowey::pipeline::prelude::*;
8use flowey_lib_hvlite::build_openhcl_igvm_from_recipe::OpenhclIgvmRecipe;
9use flowey_lib_hvlite::build_openhcl_igvm_from_recipe::OpenhclKernelPackage;
10use flowey_lib_hvlite::build_openvmm_hcl::MaxTraceLevel;
11use flowey_lib_hvlite::run_cargo_build::common::CommonArch;
12use std::path::PathBuf;
13
14#[derive(clap::ValueEnum, Copy, Clone)]
15pub enum OpenhclRecipeCli {
16 Aarch64,
18 Aarch64Devkern,
20 X64Cvm,
22 X64CvmDevkern,
24 X64TestLinuxDirect,
27 X64TestLinuxDirectDevkern,
30 X64,
32 X64Devkern,
34}
35
36#[derive(clap::Args)]
38pub struct BuildIgvmCli<Recipe = OpenhclRecipeCli>
39where
40 Recipe: clap::ValueEnum + Clone + Send + Sync + 'static,
43{
44 pub recipe: Recipe,
53
54 #[clap(long)]
59 pub release: bool,
60
61 #[clap(long)]
64 pub release_cfg: bool,
65
66 #[clap(long)]
68 pub verbose: bool,
69
70 #[clap(long)]
72 pub locked: bool,
73
74 #[clap(long)]
76 pub install_missing_deps: bool,
77
78 #[clap(flatten)]
79 pub customizations: BuildIgvmCliCustomizations,
80}
81
82#[derive(clap::Args)]
83#[clap(next_help_heading = "Customizations")]
84pub struct BuildIgvmCliCustomizations {
85 #[clap(long, short = 'o')]
89 pub build_label: Option<String>,
90
91 #[clap(long)]
93 pub override_kernel_pkg: Option<KernelPackageKindCli>,
94
95 #[clap(long)]
97 pub override_openvmm_hcl_feature: Vec<String>,
98
99 #[clap(long)]
102 pub override_arch: Option<BuildIgvmArch>,
103
104 #[clap(long)]
107 pub override_manifest: Option<PathBuf>,
108
109 #[clap(long, requires = "release")]
115 pub with_perf_tools: bool,
116
117 #[clap(long)]
122 pub with_debuginfo: bool,
123
124 #[clap(long)]
126 pub custom_openvmm_hcl: Option<PathBuf>,
127
128 #[clap(long)]
130 pub custom_openhcl_boot: Option<PathBuf>,
131
132 #[clap(long)]
134 pub custom_uefi: Option<PathBuf>,
135
136 #[clap(long)]
139 pub custom_kernel: Option<PathBuf>,
140
141 #[clap(long)]
144 pub custom_kernel_modules: Option<PathBuf>,
145
146 #[clap(long)]
151 pub custom_vtl0_kernel: Option<PathBuf>,
152
153 #[clap(long)]
155 pub custom_layer: Vec<PathBuf>,
156
157 #[clap(long)]
159 pub custom_directory: Vec<PathBuf>,
160
161 #[clap(long)]
163 pub custom_extra_rootfs: Vec<PathBuf>,
164
165 #[clap(long)]
167 pub with_sidecar: bool,
168
169 #[clap(long, requires = "with_sidecar")]
172 pub custom_sidecar: Option<PathBuf>,
173
174 #[clap(long)]
177 pub max_trace_level: Option<MaxTraceLevelCli>,
178}
179
180#[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)]
181pub enum KernelPackageKindCli {
182 Main,
184 Cvm,
186 Dev,
188 CvmDev,
190}
191
192#[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)]
193pub enum MaxTraceLevelCli {
194 Trace,
196 Debug,
198 Info,
200 Warn,
202 Error,
204 Off,
206}
207
208impl From<MaxTraceLevelCli> for MaxTraceLevel {
209 fn from(cli: MaxTraceLevelCli) -> Self {
210 match cli {
211 MaxTraceLevelCli::Trace => MaxTraceLevel::Trace,
212 MaxTraceLevelCli::Debug => MaxTraceLevel::Debug,
213 MaxTraceLevelCli::Info => MaxTraceLevel::Info,
214 MaxTraceLevelCli::Warn => MaxTraceLevel::Warn,
215 MaxTraceLevelCli::Error => MaxTraceLevel::Error,
216 MaxTraceLevelCli::Off => MaxTraceLevel::Off,
217 }
218 }
219}
220
221#[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)]
222pub enum BuildIgvmArch {
223 X86_64,
224 Aarch64,
225}
226
227pub fn bail_if_running_in_ci() -> anyhow::Result<()> {
228 const OVERRIDE_ENV: &str = "I_HAVE_A_GOOD_REASON_TO_RUN_BUILD_IGVM_IN_CI";
229
230 if std::env::var(OVERRIDE_ENV).is_ok() {
231 return Ok(());
232 }
233
234 for ci_env in ["TF_BUILD", "GITHUB_ACTIONS"] {
235 if std::env::var(ci_env).is_ok() {
236 log::warn!("Detected that {ci_env} is set");
237 log::warn!("");
238 log::warn!("Do not use `build-igvm` in CI scripts!");
239 log::warn!(
240 "This is a local-only, inner-dev-loop tool to build IGVM files, with an UNSTABLE CLI."
241 );
242 log::warn!("");
243 log::warn!(
244 "Automated pipelines should use the underlying `flowey` nodes that power build-igvm directly, _without_ relying on its CLI!"
245 );
246 log::warn!("");
247 log::warn!(
248 "If you _really_ know what you're doing, you can set {OVERRIDE_ENV} to disable this error."
249 );
250 anyhow::bail!("attempted to run `build-igvm` in CI")
251 }
252 }
253
254 Ok(())
255}
256
257impl IntoPipeline for BuildIgvmCli {
258 fn into_pipeline(self, backend_hint: PipelineBackendHint) -> anyhow::Result<Pipeline> {
259 if !matches!(backend_hint, PipelineBackendHint::Local) {
260 anyhow::bail!("build-igvm is for local use only")
261 }
262
263 bail_if_running_in_ci()?;
264
265 let openvmm_repo = flowey_lib_common::git_checkout::RepoSource::ExistingClone(
266 ReadVar::from_static(crate::repo_root()),
267 );
268
269 let Self {
270 recipe,
271 release,
272 release_cfg,
273 verbose,
274 locked,
275 install_missing_deps,
276 customizations:
277 BuildIgvmCliCustomizations {
278 build_label,
279 override_kernel_pkg,
280 override_openvmm_hcl_feature,
281 override_arch,
282 override_manifest,
283 with_perf_tools,
284 with_debuginfo,
285 custom_openvmm_hcl,
286 custom_openhcl_boot,
287 custom_uefi,
288 custom_kernel,
289 custom_kernel_modules,
290 custom_vtl0_kernel,
291 custom_layer,
292 custom_directory,
293 with_sidecar,
294 custom_sidecar,
295 mut custom_extra_rootfs,
296 max_trace_level,
297 },
298 } = self;
299
300 if with_perf_tools {
301 custom_extra_rootfs.push(crate::repo_root().join("openhcl/perftoolsfs.config"));
302 }
303
304 let mut pipeline = Pipeline::new();
305
306 let (pub_out_dir, _) = pipeline.new_artifact("build-igvm");
307
308 pipeline
309 .new_job(
310 FlowPlatform::host(backend_hint),
311 FlowArch::host(backend_hint),
312 "build-igvm",
313 )
314 .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_versions::Request {})
315 .dep_on(
316 |_| flowey_lib_hvlite::_jobs::cfg_hvlite_reposource::Params {
317 hvlite_repo_source: openvmm_repo,
318 },
319 )
320 .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_common::Params {
321 local_only: Some(flowey_lib_hvlite::_jobs::cfg_common::LocalOnlyParams {
322 interactive: true,
323 auto_install: install_missing_deps,
324 force_nuget_mono: false, external_nuget_auth: false,
326 ignore_rust_version: true,
327 }),
328 verbose: ReadVar::from_static(verbose),
329 locked,
330 deny_warnings: false,
331 })
332 .dep_on(|ctx| flowey_lib_hvlite::_jobs::local_build_igvm::Params {
333 artifact_dir: ctx.publish_artifact(pub_out_dir),
334 done: ctx.new_done_handle(),
335
336 base_recipe: match recipe {
337 OpenhclRecipeCli::X64 => OpenhclIgvmRecipe::X64,
338 OpenhclRecipeCli::X64Devkern => OpenhclIgvmRecipe::X64Devkern,
339 OpenhclRecipeCli::X64TestLinuxDirect => OpenhclIgvmRecipe::X64TestLinuxDirect,
340 OpenhclRecipeCli::X64TestLinuxDirectDevkern => {
341 OpenhclIgvmRecipe::X64TestLinuxDirectDevkern
342 }
343 OpenhclRecipeCli::X64Cvm => OpenhclIgvmRecipe::X64Cvm,
344 OpenhclRecipeCli::X64CvmDevkern => OpenhclIgvmRecipe::X64CvmDevkern,
345 OpenhclRecipeCli::Aarch64 => OpenhclIgvmRecipe::Aarch64,
346 OpenhclRecipeCli::Aarch64Devkern => OpenhclIgvmRecipe::Aarch64Devkern,
347 },
348 release,
349 release_cfg,
350
351 customizations: flowey_lib_hvlite::_jobs::local_build_igvm::Customizations {
352 build_label,
353 override_arch: override_arch.map(|a| match a {
354 BuildIgvmArch::X86_64 => CommonArch::X86_64,
355 BuildIgvmArch::Aarch64 => CommonArch::Aarch64,
356 }),
357 with_perf_tools,
358 with_debuginfo,
359 override_kernel_pkg: override_kernel_pkg.map(|p| match p {
360 KernelPackageKindCli::Main => OpenhclKernelPackage::Main,
361 KernelPackageKindCli::Cvm => OpenhclKernelPackage::Cvm,
362 KernelPackageKindCli::Dev => OpenhclKernelPackage::Dev,
363 KernelPackageKindCli::CvmDev => OpenhclKernelPackage::CvmDev,
364 }),
365 with_sidecar,
366 custom_extra_rootfs,
367 override_openvmm_hcl_feature,
368 custom_sidecar,
369 override_manifest,
370 override_max_trace_level: max_trace_level.map(Into::into),
371 custom_openvmm_hcl,
372 custom_openhcl_boot,
373 custom_uefi,
374 custom_kernel,
375 custom_kernel_modules,
376 custom_vtl0_kernel,
377 custom_layer,
378 custom_directory,
379 },
380 })
381 .finish();
382
383 Ok(pipeline)
384 }
385}