blue_build/commands/
switch.rs1use std::path::PathBuf;
2
3use blue_build_process_management::drivers::{
4 BootDriver, BuildDriver, CiDriver, Driver, DriverArgs, ImageStorageDriver, PodmanDriver,
5 opts::{BuildOpts, GenerateImageNameOpts, RemoveImageOpts, SwitchOpts},
6 types::{BuildDriverType, RunDriverType},
7};
8use blue_build_recipe::Recipe;
9use blue_build_utils::{constants::BB_SKIP_VALIDATION, container::ImageRef};
10use bon::Builder;
11use clap::Args;
12use log::trace;
13use miette::{IntoDiagnostic, Result, bail};
14use tempfile::TempDir;
15
16use crate::commands::generate::GenerateCommand;
17
18use super::BlueBuildCommand;
19
20#[derive(Default, Clone, Debug, Builder, Args)]
21pub struct SwitchCommand {
22 #[arg()]
24 recipe: PathBuf,
25
26 #[arg(short, long)]
29 #[builder(default)]
30 reboot: bool,
31
32 #[arg(long)]
35 tempdir: Option<PathBuf>,
36
37 #[arg(long, env = BB_SKIP_VALIDATION)]
39 #[builder(default)]
40 skip_validation: bool,
41
42 #[clap(flatten)]
43 #[builder(default)]
44 drivers: DriverArgs,
45}
46
47impl BlueBuildCommand for SwitchCommand {
48 fn try_run(&mut self) -> Result<()> {
49 trace!("SwitchCommand::try_run()");
50
51 Driver::init(
52 DriverArgs::builder()
53 .build_driver(BuildDriverType::Podman)
54 .run_driver(RunDriverType::Podman)
55 .maybe_boot_driver(self.drivers.boot_driver)
56 .maybe_signing_driver(self.drivers.signing_driver)
57 .build(),
58 );
59
60 let status = Driver::status()?;
61
62 if status.transaction_in_progress() {
63 bail!("There is a transaction in progress. Please cancel it using `rpm-ostree cancel`");
64 }
65
66 let recipe = Recipe::parse(&self.recipe)?;
67 let image_name = Driver::generate_image_name(
68 GenerateImageNameOpts::builder()
69 .name(recipe.name.trim())
70 .build(),
71 )?;
72 let tempdir = if let Some(ref dir) = self.tempdir {
73 TempDir::new_in(dir).into_diagnostic()?
74 } else {
75 TempDir::new().into_diagnostic()?
76 };
77 let containerfile = tempdir
78 .path()
79 .join(blue_build_utils::generate_containerfile_path(&self.recipe)?);
80
81 GenerateCommand::builder()
82 .output(&containerfile)
83 .recipe(&self.recipe)
84 .build()
85 .try_run()?;
86 Driver::build(
87 BuildOpts::builder()
88 .image(&ImageRef::from(&image_name))
89 .containerfile(&containerfile)
90 .secrets(&recipe.get_secrets())
91 .build(),
92 )?;
93 PodmanDriver::copy_image_to_root_store(&image_name)?;
94 PodmanDriver::remove_image(RemoveImageOpts::builder().image(&image_name).build())?;
95
96 if status
97 .booted_image()
98 .is_some_and(|booted| booted == image_name)
99 {
100 Driver::upgrade(
101 SwitchOpts::builder()
102 .image(&image_name)
103 .reboot(self.reboot)
104 .build(),
105 )
106 } else {
107 Driver::switch(
108 SwitchOpts::builder()
109 .image(&image_name)
110 .reboot(self.reboot)
111 .build(),
112 )
113 }
114 }
115}