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, requires = "custom_kernel")]
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 #[clap(long, requires_all = ["custom_openvmm_deps", "custom_protoc", "custom_kernel", "custom_kernel_modules", "custom_uefi"])]
182 pub use_local_deps: bool,
183
184 #[clap(long)]
186 pub custom_openvmm_deps: Option<PathBuf>,
187
188 #[clap(long)]
190 pub custom_protoc: Option<PathBuf>,
191}
192
193#[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)]
194pub enum KernelPackageKindCli {
195 Main,
197 Cvm,
199 Dev,
201 CvmDev,
203}
204
205#[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)]
206pub enum MaxTraceLevelCli {
207 Trace,
209 Debug,
211 Info,
213 Warn,
215 Error,
217 Off,
219}
220
221impl From<MaxTraceLevelCli> for MaxTraceLevel {
222 fn from(cli: MaxTraceLevelCli) -> Self {
223 match cli {
224 MaxTraceLevelCli::Trace => MaxTraceLevel::Trace,
225 MaxTraceLevelCli::Debug => MaxTraceLevel::Debug,
226 MaxTraceLevelCli::Info => MaxTraceLevel::Info,
227 MaxTraceLevelCli::Warn => MaxTraceLevel::Warn,
228 MaxTraceLevelCli::Error => MaxTraceLevel::Error,
229 MaxTraceLevelCli::Off => MaxTraceLevel::Off,
230 }
231 }
232}
233
234#[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)]
235pub enum BuildIgvmArch {
236 X86_64,
237 Aarch64,
238}
239
240pub fn bail_if_running_in_ci() -> anyhow::Result<()> {
241 const OVERRIDE_ENV: &str = "I_HAVE_A_GOOD_REASON_TO_RUN_BUILD_IGVM_IN_CI";
242
243 if std::env::var(OVERRIDE_ENV).is_ok() {
244 return Ok(());
245 }
246
247 for ci_env in ["TF_BUILD", "GITHUB_ACTIONS"] {
248 if std::env::var(ci_env).is_ok() {
249 log::warn!("Detected that {ci_env} is set");
250 log::warn!("");
251 log::warn!("Do not use `build-igvm` in CI scripts!");
252 log::warn!(
253 "This is a local-only, inner-dev-loop tool to build IGVM files, with an UNSTABLE CLI."
254 );
255 log::warn!("");
256 log::warn!(
257 "Automated pipelines should use the underlying `flowey` nodes that power build-igvm directly, _without_ relying on its CLI!"
258 );
259 log::warn!("");
260 log::warn!(
261 "If you _really_ know what you're doing, you can set {OVERRIDE_ENV} to disable this error."
262 );
263 anyhow::bail!("attempted to run `build-igvm` in CI")
264 }
265 }
266
267 Ok(())
268}
269
270impl IntoPipeline for BuildIgvmCli {
271 fn into_pipeline(self, backend_hint: PipelineBackendHint) -> anyhow::Result<Pipeline> {
272 if !matches!(backend_hint, PipelineBackendHint::Local) {
273 anyhow::bail!("build-igvm is for local use only")
274 }
275
276 bail_if_running_in_ci()?;
277
278 let openvmm_repo = flowey_lib_common::git_checkout::RepoSource::ExistingClone(
279 ReadVar::from_static(crate::repo_root()),
280 );
281
282 let Self {
283 recipe,
284 release,
285 release_cfg,
286 verbose,
287 locked,
288 install_missing_deps,
289 customizations:
290 BuildIgvmCliCustomizations {
291 build_label,
292 override_kernel_pkg,
293 override_openvmm_hcl_feature,
294 override_arch,
295 override_manifest,
296 with_perf_tools,
297 with_debuginfo,
298 custom_openvmm_hcl,
299 custom_openhcl_boot,
300 custom_uefi,
301 custom_kernel,
302 custom_kernel_modules,
303 custom_vtl0_kernel,
304 custom_layer,
305 custom_directory,
306 with_sidecar,
307 custom_sidecar,
308 mut custom_extra_rootfs,
309 max_trace_level,
310 custom_openvmm_deps,
311 custom_protoc,
312 use_local_deps: _, },
314 } = self;
315
316 if with_perf_tools {
317 custom_extra_rootfs.push(crate::repo_root().join("openhcl/perftoolsfs.config"));
318 }
319
320 let mut pipeline = Pipeline::new();
321
322 let (pub_out_dir, _) = pipeline.new_artifact("build-igvm");
323
324 let recipe_arch = match recipe {
326 OpenhclRecipeCli::X64
327 | OpenhclRecipeCli::X64Devkern
328 | OpenhclRecipeCli::X64Cvm
329 | OpenhclRecipeCli::X64CvmDevkern
330 | OpenhclRecipeCli::X64TestLinuxDirect
331 | OpenhclRecipeCli::X64TestLinuxDirectDevkern => CommonArch::X86_64,
332 OpenhclRecipeCli::Aarch64 | OpenhclRecipeCli::Aarch64Devkern => CommonArch::Aarch64,
333 };
334
335 let effective_arch = override_arch
337 .map(|a| match a {
338 BuildIgvmArch::X86_64 => CommonArch::X86_64,
339 BuildIgvmArch::Aarch64 => CommonArch::Aarch64,
340 })
341 .unwrap_or(recipe_arch);
342
343 let mut job = pipeline.new_job(
344 FlowPlatform::host(backend_hint),
345 FlowArch::host(backend_hint),
346 "build-igvm",
347 );
348
349 job = job.dep_on(|_| flowey_lib_hvlite::_jobs::cfg_versions::Request::Init);
352
353 if let Some(openvmm_deps_path) = custom_openvmm_deps {
355 job = job.dep_on(move |_| {
356 flowey_lib_hvlite::_jobs::cfg_versions::Request::LocalOpenvmmDeps(
357 effective_arch,
358 ReadVar::from_static(openvmm_deps_path),
359 )
360 });
361 }
362
363 if let Some(protoc_path) = custom_protoc {
365 job = job.dep_on(move |_| {
366 flowey_lib_hvlite::_jobs::cfg_versions::Request::LocalProtoc(ReadVar::from_static(
367 protoc_path,
368 ))
369 });
370 }
371
372 if let (Some(kernel_path), Some(modules_path)) =
374 (custom_kernel.clone(), custom_kernel_modules.clone())
375 {
376 job =
377 job.dep_on(
378 move |_| flowey_lib_hvlite::_jobs::cfg_versions::Request::LocalKernel {
379 arch: effective_arch,
380 kernel: ReadVar::from_static(kernel_path),
381 modules: ReadVar::from_static(modules_path),
382 },
383 );
384 }
385
386 if let Some(uefi_path) = custom_uefi {
388 job = job.dep_on(move |_| {
389 flowey_lib_hvlite::_jobs::cfg_versions::Request::LocalUefi(
390 effective_arch,
391 ReadVar::from_static(uefi_path),
392 )
393 });
394 }
395
396 job.dep_on(
397 |_| flowey_lib_hvlite::_jobs::cfg_hvlite_reposource::Params {
398 hvlite_repo_source: openvmm_repo,
399 },
400 )
401 .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_common::Params {
402 local_only: Some(flowey_lib_hvlite::_jobs::cfg_common::LocalOnlyParams {
403 interactive: true,
404 auto_install: install_missing_deps,
405 force_nuget_mono: false, external_nuget_auth: false,
407 ignore_rust_version: true,
408 }),
409 verbose: ReadVar::from_static(verbose),
410 locked,
411 deny_warnings: false,
412 })
413 .dep_on(|ctx| flowey_lib_hvlite::_jobs::local_build_igvm::Params {
414 artifact_dir: ctx.publish_artifact(pub_out_dir),
415 done: ctx.new_done_handle(),
416
417 base_recipe: match recipe {
418 OpenhclRecipeCli::X64 => OpenhclIgvmRecipe::X64,
419 OpenhclRecipeCli::X64Devkern => OpenhclIgvmRecipe::X64Devkern,
420 OpenhclRecipeCli::X64TestLinuxDirect => OpenhclIgvmRecipe::X64TestLinuxDirect,
421 OpenhclRecipeCli::X64TestLinuxDirectDevkern => {
422 OpenhclIgvmRecipe::X64TestLinuxDirectDevkern
423 }
424 OpenhclRecipeCli::X64Cvm => OpenhclIgvmRecipe::X64Cvm,
425 OpenhclRecipeCli::X64CvmDevkern => OpenhclIgvmRecipe::X64CvmDevkern,
426 OpenhclRecipeCli::Aarch64 => OpenhclIgvmRecipe::Aarch64,
427 OpenhclRecipeCli::Aarch64Devkern => OpenhclIgvmRecipe::Aarch64Devkern,
428 },
429 release,
430 release_cfg,
431
432 customizations: flowey_lib_hvlite::_jobs::local_build_igvm::Customizations {
433 build_label,
434 override_arch: override_arch.map(|a| match a {
435 BuildIgvmArch::X86_64 => CommonArch::X86_64,
436 BuildIgvmArch::Aarch64 => CommonArch::Aarch64,
437 }),
438 with_perf_tools,
439 with_debuginfo,
440 override_kernel_pkg: override_kernel_pkg.map(|p| match p {
441 KernelPackageKindCli::Main => OpenhclKernelPackage::Main,
442 KernelPackageKindCli::Cvm => OpenhclKernelPackage::Cvm,
443 KernelPackageKindCli::Dev => OpenhclKernelPackage::Dev,
444 KernelPackageKindCli::CvmDev => OpenhclKernelPackage::CvmDev,
445 }),
446 with_sidecar,
447 custom_extra_rootfs,
448 override_openvmm_hcl_feature,
449 custom_sidecar,
450 override_manifest,
451 override_max_trace_level: max_trace_level.map(Into::into),
452 custom_openvmm_hcl,
453 custom_openhcl_boot,
454 custom_kernel,
455 custom_vtl0_kernel,
456 custom_layer,
457 custom_directory,
458 },
459 })
460 .finish();
461
462 Ok(pipeline)
463 }
464}