refactor!: Rename template to generate and move rebase/upgrade under switch (#116)
This updates the `template` subcommand to be `generate`. The `template` usage will continue to work as an alias to `generate`. A new `switch` command is added that will manage both `rpm-ostree rebase` and `rpm-ostree upgrade` and is fully replacing the respective subcommands as a breaking change. The new `switch` command is under the feature flag `switch` and will currently only build for the `main` branch builds until it is moved as a default feature (`v0.9.0`). Closes #159
This commit is contained in:
parent
968cf3db97
commit
02b2fe5434
21 changed files with 672 additions and 62 deletions
|
|
@ -19,13 +19,25 @@ fn main() {
|
|||
match args.command {
|
||||
#[cfg(feature = "init")]
|
||||
CommandArgs::Init(mut command) => command.run(),
|
||||
|
||||
#[cfg(feature = "init")]
|
||||
CommandArgs::New(mut command) => command.run(),
|
||||
|
||||
CommandArgs::Build(mut command) => command.run(),
|
||||
|
||||
CommandArgs::Generate(mut command) => command.run(),
|
||||
|
||||
#[cfg(feature = "switch")]
|
||||
CommandArgs::Switch(mut command) => command.run(),
|
||||
|
||||
#[cfg(not(feature = "switch"))]
|
||||
CommandArgs::Rebase(mut command) => command.run(),
|
||||
|
||||
#[cfg(not(feature = "switch"))]
|
||||
CommandArgs::Upgrade(mut command) => command.run(),
|
||||
CommandArgs::Template(mut command) => command.run(),
|
||||
|
||||
CommandArgs::BugReport(mut command) => command.run(),
|
||||
|
||||
CommandArgs::Completions(mut command) => command.run(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,13 @@ use crate::{
|
|||
pub mod bug_report;
|
||||
pub mod build;
|
||||
pub mod completions;
|
||||
pub mod generate;
|
||||
#[cfg(feature = "init")]
|
||||
pub mod init;
|
||||
#[cfg(not(feature = "switch"))]
|
||||
pub mod local;
|
||||
pub mod template;
|
||||
#[cfg(feature = "switch")]
|
||||
pub mod switch;
|
||||
|
||||
pub trait BlueBuildCommand {
|
||||
/// Runs the command and returns a result
|
||||
|
|
@ -57,7 +60,8 @@ pub enum CommandArgs {
|
|||
Build(build::BuildCommand),
|
||||
|
||||
/// Generate a Containerfile from a recipe
|
||||
Template(template::TemplateCommand),
|
||||
#[clap(visible_alias = "template")]
|
||||
Generate(generate::GenerateCommand),
|
||||
|
||||
/// Upgrade your current OS with the
|
||||
/// local image saved at `/etc/bluebuild/`.
|
||||
|
|
@ -69,6 +73,7 @@ pub enum CommandArgs {
|
|||
/// NOTE: This can only be used if you have `rpm-ostree`
|
||||
/// installed. This image will not be signed.
|
||||
#[command(visible_alias("update"))]
|
||||
#[cfg(not(feature = "switch"))]
|
||||
Upgrade(local::UpgradeCommand),
|
||||
|
||||
/// Rebase your current OS onto the image
|
||||
|
|
@ -80,8 +85,21 @@ pub enum CommandArgs {
|
|||
///
|
||||
/// NOTE: This can only be used if you have `rpm-ostree`
|
||||
/// installed. This image will not be signed.
|
||||
#[cfg(not(feature = "switch"))]
|
||||
Rebase(local::RebaseCommand),
|
||||
|
||||
/// Switch your current OS onto the image
|
||||
/// being built.
|
||||
///
|
||||
/// This will create a tarball of your image at
|
||||
/// `/etc/bluebuild/` and invoke `rpm-ostree` to
|
||||
/// rebase/upgrade onto the image using `oci-archive`.
|
||||
///
|
||||
/// NOTE: This can only be used if you have `rpm-ostree`
|
||||
/// installed. This image will not be signed.
|
||||
#[cfg(feature = "switch")]
|
||||
Switch(switch::SwitchCommand),
|
||||
|
||||
/// Initialize a new Ublue Starting Point repo
|
||||
#[cfg(feature = "init")]
|
||||
Init(init::InitCommand),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use log::{debug, info, trace, warn};
|
|||
use typed_builder::TypedBuilder;
|
||||
|
||||
use crate::{
|
||||
commands::template::TemplateCommand,
|
||||
commands::generate::GenerateCommand,
|
||||
credentials,
|
||||
drivers::{
|
||||
opts::{BuildTagPushOpts, CompressionType, GetMetadataOpts},
|
||||
|
|
@ -120,6 +120,15 @@ impl BlueBuildCommand for BuildCommand {
|
|||
.build()
|
||||
.init()?;
|
||||
|
||||
if self.push && self.archive.is_some() {
|
||||
bail!("You cannot use '--archive' and '--push' at the same time");
|
||||
}
|
||||
|
||||
if self.push {
|
||||
blue_build_utils::check_command_exists("cosign")?;
|
||||
check_cosign_files()?;
|
||||
}
|
||||
|
||||
// Check if the Containerfile exists
|
||||
// - If doesn't => *Build*
|
||||
// - If it does:
|
||||
|
|
@ -172,10 +181,6 @@ impl BlueBuildCommand for BuildCommand {
|
|||
}
|
||||
}
|
||||
|
||||
if self.push && self.archive.is_some() {
|
||||
bail!("You cannot use '--archive' and '--push' at the same time");
|
||||
}
|
||||
|
||||
let recipe_path = self.recipe.clone().unwrap_or_else(|| {
|
||||
let legacy_path = Path::new(CONFIG_PATH);
|
||||
let recipe_path = Path::new(RECIPE_PATH);
|
||||
|
|
@ -187,18 +192,12 @@ impl BlueBuildCommand for BuildCommand {
|
|||
}
|
||||
});
|
||||
|
||||
TemplateCommand::builder()
|
||||
GenerateCommand::builder()
|
||||
.recipe(&recipe_path)
|
||||
.output(PathBuf::from("Containerfile"))
|
||||
.drivers(DriverArgs::builder().squash(self.drivers.squash).build())
|
||||
.build()
|
||||
.try_run()?;
|
||||
|
||||
if self.push {
|
||||
blue_build_utils::check_command_exists("cosign")?;
|
||||
check_cosign_files()?;
|
||||
}
|
||||
|
||||
info!("Building image for recipe at {}", recipe_path.display());
|
||||
|
||||
self.start(&recipe_path)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use crate::{drivers::Driver, shadow};
|
|||
use super::{BlueBuildCommand, DriverArgs};
|
||||
|
||||
#[derive(Debug, Clone, Args, TypedBuilder)]
|
||||
pub struct TemplateCommand {
|
||||
pub struct GenerateCommand {
|
||||
/// The recipe file to create a template from
|
||||
#[arg()]
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
|
|
@ -71,7 +71,7 @@ pub struct TemplateCommand {
|
|||
drivers: DriverArgs,
|
||||
}
|
||||
|
||||
impl BlueBuildCommand for TemplateCommand {
|
||||
impl BlueBuildCommand for GenerateCommand {
|
||||
fn try_run(&mut self) -> Result<()> {
|
||||
Driver::builder()
|
||||
.build_driver(self.drivers.build_driver)
|
||||
|
|
@ -83,7 +83,7 @@ impl BlueBuildCommand for TemplateCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl TemplateCommand {
|
||||
impl GenerateCommand {
|
||||
fn template_file(&self) -> Result<()> {
|
||||
trace!("TemplateCommand::template_file()");
|
||||
|
||||
223
src/commands/switch.rs
Normal file
223
src/commands/switch.rs
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_utils::constants::{
|
||||
ARCHIVE_SUFFIX, LOCAL_BUILD, OCI_ARCHIVE, OSTREE_UNVERIFIED_IMAGE,
|
||||
};
|
||||
use clap::Args;
|
||||
use colored::Colorize;
|
||||
use log::{debug, trace, warn};
|
||||
use tempdir::TempDir;
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
use crate::{commands::build::BuildCommand, drivers::Driver, rpm_ostree_status::RpmOstreeStatus};
|
||||
|
||||
use super::{BlueBuildCommand, DriverArgs};
|
||||
|
||||
#[derive(Default, Clone, Debug, TypedBuilder, Args)]
|
||||
pub struct SwitchCommand {
|
||||
/// The recipe file to build an image.
|
||||
#[arg()]
|
||||
recipe: PathBuf,
|
||||
|
||||
/// Reboot your system after
|
||||
/// the update is complete.
|
||||
#[arg(short, long)]
|
||||
#[builder(default)]
|
||||
reboot: bool,
|
||||
|
||||
/// Allow `bluebuild` to overwrite an existing
|
||||
/// Containerfile without confirmation.
|
||||
///
|
||||
/// This is not needed if the Containerfile is in
|
||||
/// .gitignore or has already been built by `bluebuild`.
|
||||
#[arg(short, long)]
|
||||
#[builder(default)]
|
||||
force: bool,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[builder(default)]
|
||||
drivers: DriverArgs,
|
||||
}
|
||||
|
||||
impl BlueBuildCommand for SwitchCommand {
|
||||
fn try_run(&mut self) -> Result<()> {
|
||||
trace!("SwitchCommand::try_run()");
|
||||
|
||||
Driver::builder()
|
||||
.build_driver(self.drivers.build_driver)
|
||||
.inspect_driver(self.drivers.inspect_driver)
|
||||
.build()
|
||||
.init()?;
|
||||
|
||||
let status = RpmOstreeStatus::try_new()?;
|
||||
trace!("{status:?}");
|
||||
|
||||
if status.transaction_in_progress() {
|
||||
bail!("There is a transaction in progress. Please cancel it using `rpm-ostree cancel`");
|
||||
}
|
||||
|
||||
let tempdir = TempDir::new("oci-archive")?;
|
||||
trace!("{tempdir:?}");
|
||||
|
||||
BuildCommand::builder()
|
||||
.recipe(self.recipe.clone())
|
||||
.archive(tempdir.path())
|
||||
.force(self.force)
|
||||
.build()
|
||||
.try_run()?;
|
||||
|
||||
let recipe = Recipe::parse(&self.recipe)?;
|
||||
let image_file_name = format!(
|
||||
"{}.{ARCHIVE_SUFFIX}",
|
||||
recipe.name.to_lowercase().replace('/', "_")
|
||||
);
|
||||
let temp_file_path = tempdir.path().join(&image_file_name);
|
||||
let archive_path = Path::new(LOCAL_BUILD).join(&image_file_name);
|
||||
|
||||
warn!(
|
||||
"{notice}: {} {sudo} {}",
|
||||
"The next few steps will require".yellow(),
|
||||
"You may have to supply your password".yellow(),
|
||||
notice = "NOTICE".bright_red().bold(),
|
||||
sudo = "`sudo`.".italic().bright_red().bold(),
|
||||
);
|
||||
Self::sudo_clean_local_build_dir()?;
|
||||
Self::sudo_move_archive(&temp_file_path, &archive_path)?;
|
||||
|
||||
// We drop the tempdir ahead of time so that the directory
|
||||
// can be cleaned out.
|
||||
drop(tempdir);
|
||||
|
||||
self.switch(&archive_path, &status)
|
||||
}
|
||||
}
|
||||
|
||||
impl SwitchCommand {
|
||||
fn switch(&self, archive_path: &Path, status: &RpmOstreeStatus<'_>) -> Result<()> {
|
||||
trace!(
|
||||
"SwitchCommand::switch({}, {status:#?})",
|
||||
archive_path.display()
|
||||
);
|
||||
|
||||
let status = if status.is_booted_on_archive(archive_path)
|
||||
|| status.is_staged_on_archive(archive_path)
|
||||
{
|
||||
let mut command = Command::new("rpm-ostree");
|
||||
command.arg("upgrade");
|
||||
|
||||
if self.reboot {
|
||||
command.arg("--reboot");
|
||||
}
|
||||
|
||||
trace!(
|
||||
"rpm-ostree upgrade {}",
|
||||
self.reboot.then_some("--reboot").unwrap_or_default()
|
||||
);
|
||||
command
|
||||
} else {
|
||||
let image_ref = format!(
|
||||
"{OSTREE_UNVERIFIED_IMAGE}:{OCI_ARCHIVE}:{path}",
|
||||
path = archive_path.display()
|
||||
);
|
||||
let mut command = Command::new("rpm-ostree");
|
||||
command.arg("rebase").arg(&image_ref);
|
||||
|
||||
if self.reboot {
|
||||
command.arg("--reboot");
|
||||
}
|
||||
|
||||
trace!(
|
||||
"rpm-ostree rebase{} {image_ref}",
|
||||
self.reboot.then_some(" --reboot").unwrap_or_default()
|
||||
);
|
||||
command
|
||||
}
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
bail!("Failed to switch to new image!");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sudo_move_archive(from: &Path, to: &Path) -> Result<()> {
|
||||
trace!(
|
||||
"SwitchCommand::sudo_move_archive({}, {})",
|
||||
from.display(),
|
||||
to.display()
|
||||
);
|
||||
|
||||
trace!("sudo mv {} {}", from.display(), to.display());
|
||||
let status = Command::new("sudo").arg("mv").args([from, to]).status()?;
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"Failed to move archive from {from} to {to}",
|
||||
from = from.display(),
|
||||
to = to.display()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sudo_clean_local_build_dir() -> Result<()> {
|
||||
trace!("SwitchCommand::clean_local_build_dir()");
|
||||
|
||||
let local_build_path = Path::new(LOCAL_BUILD);
|
||||
|
||||
if local_build_path.exists() {
|
||||
debug!("Cleaning out build dir {LOCAL_BUILD}");
|
||||
|
||||
trace!("sudo ls {LOCAL_BUILD}");
|
||||
let output = String::from_utf8(
|
||||
Command::new("sudo")
|
||||
.args(["ls", LOCAL_BUILD])
|
||||
.output()?
|
||||
.stdout,
|
||||
)?;
|
||||
|
||||
trace!("{output}");
|
||||
|
||||
let files = output
|
||||
.lines()
|
||||
.filter(|line| line.ends_with(ARCHIVE_SUFFIX))
|
||||
.map(|file| local_build_path.join(file).display().to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !files.is_empty() {
|
||||
let files = files.join(" ");
|
||||
|
||||
trace!("sudo rm -f {files}");
|
||||
let status = Command::new("sudo")
|
||||
.args(["rm", "-f"])
|
||||
.arg(files)
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
bail!("Failed to clean out archives in {LOCAL_BUILD}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"Creating build output dir at {}",
|
||||
local_build_path.display()
|
||||
);
|
||||
|
||||
let status = Command::new("sudo")
|
||||
.args(["mkdir", "-p", LOCAL_BUILD])
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
bail!("Failed to create directory {LOCAL_BUILD}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use std::process::Command;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use log::{info, trace};
|
||||
use log::{error, info, trace};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
|
|
@ -34,7 +34,8 @@ impl DriverVersion for BuildahDriver {
|
|||
.arg("--json")
|
||||
.output()?;
|
||||
|
||||
let version_json: BuildahVersionJson = serde_json::from_slice(&output.stdout)?;
|
||||
let version_json: BuildahVersionJson = serde_json::from_slice(&output.stdout)
|
||||
.inspect_err(|e| error!("{e}: {}", String::from_utf8_lossy(&output.stdout)))?;
|
||||
trace!("{version_json:#?}");
|
||||
|
||||
Ok(version_json.version)
|
||||
|
|
|
|||
|
|
@ -210,7 +210,6 @@ impl BuildDriver for DockerDriver {
|
|||
trace!("build --progress=plain --pull -f {CONTAINER_FILE}",);
|
||||
command
|
||||
.arg("build")
|
||||
.arg("--progress=plain")
|
||||
.arg("--pull")
|
||||
.arg("-f")
|
||||
.arg(CONTAINER_FILE);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::process::{Command, Stdio};
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
use blue_build_utils::constants::SKOPEO_IMAGE;
|
||||
use log::{debug, info, trace};
|
||||
use log::{debug, error, info, trace};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
|
|
@ -44,7 +44,8 @@ impl DriverVersion for PodmanDriver {
|
|||
.arg("json")
|
||||
.output()?;
|
||||
|
||||
let version_json: PodmanVersionJson = serde_json::from_slice(&output.stdout)?;
|
||||
let version_json: PodmanVersionJson = serde_json::from_slice(&output.stdout)
|
||||
.inspect_err(|e| error!("{e}: {}", String::from_utf8_lossy(&output.stdout)))?;
|
||||
trace!("{version_json:#?}");
|
||||
|
||||
Ok(version_json.client.version)
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ pub mod commands;
|
|||
pub mod credentials;
|
||||
pub mod drivers;
|
||||
pub mod image_metadata;
|
||||
pub mod rpm_ostree_status;
|
||||
|
|
|
|||
247
src/rpm_ostree_status.rs
Normal file
247
src/rpm_ostree_status.rs
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
use std::{borrow::Cow, path::Path, process::Command};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use log::trace;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct RpmOstreeStatus<'a> {
|
||||
deployments: Cow<'a, [RpmOstreeDeployments<'a>]>,
|
||||
transactions: Option<Cow<'a, [Cow<'a, str>]>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
struct RpmOstreeDeployments<'a> {
|
||||
container_image_reference: Cow<'a, str>,
|
||||
booted: bool,
|
||||
staged: bool,
|
||||
}
|
||||
|
||||
impl<'a> RpmOstreeStatus<'a> {
|
||||
/// Creates a status struct for `rpm-ostree`.
|
||||
///
|
||||
/// # Errors
|
||||
/// Errors if the command fails or deserialization fails.
|
||||
pub fn try_new() -> Result<Self> {
|
||||
blue_build_utils::check_command_exists("rpm-ostree")?;
|
||||
|
||||
trace!("rpm-ostree status --json");
|
||||
let output = Command::new("rpm-ostree")
|
||||
.args(["status", "--json"])
|
||||
.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
bail!("Failed to get `rpm-ostree` status!");
|
||||
}
|
||||
|
||||
trace!("{}", String::from_utf8_lossy(&output.stdout));
|
||||
|
||||
Ok(serde_json::from_slice(&output.stdout)?)
|
||||
}
|
||||
|
||||
/// Checks if there is a transaction in progress.
|
||||
#[must_use]
|
||||
pub fn transaction_in_progress(&self) -> bool {
|
||||
self.transactions.as_ref().is_some_and(|tr| !tr.is_empty())
|
||||
}
|
||||
|
||||
/// Get the booted image's reference.
|
||||
#[must_use]
|
||||
pub fn booted_image(&self) -> Option<String> {
|
||||
Some(
|
||||
self.deployments
|
||||
.iter()
|
||||
.find(|deployment| deployment.booted)?
|
||||
.container_image_reference
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the booted image's reference.
|
||||
#[must_use]
|
||||
pub fn staged_image(&self) -> Option<String> {
|
||||
Some(
|
||||
self.deployments
|
||||
.iter()
|
||||
.find(|deployment| deployment.staged)?
|
||||
.container_image_reference
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_booted_on_archive<P>(&self, archive_path: P) -> bool
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
self.booted_image().is_some_and(|deployment| {
|
||||
deployment
|
||||
.split(':')
|
||||
.last()
|
||||
.is_some_and(|boot_ref| Path::new(boot_ref) == archive_path.as_ref())
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_staged_on_archive<P>(&self, archive_path: P) -> bool
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
self.staged_image().is_some_and(|deployment| {
|
||||
deployment
|
||||
.split(':')
|
||||
.last()
|
||||
.is_some_and(|boot_ref| Path::new(boot_ref) == archive_path.as_ref())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::Path;
|
||||
|
||||
use blue_build_utils::constants::{
|
||||
ARCHIVE_SUFFIX, LOCAL_BUILD, OCI_ARCHIVE, OSTREE_IMAGE_SIGNED, OSTREE_UNVERIFIED_IMAGE,
|
||||
};
|
||||
|
||||
use super::{RpmOstreeDeployments, RpmOstreeStatus};
|
||||
|
||||
fn create_image_status<'a>() -> RpmOstreeStatus<'a> {
|
||||
RpmOstreeStatus {
|
||||
deployments: vec![
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference: format!(
|
||||
"{OSTREE_IMAGE_SIGNED}:docker://ghcr.io/blue-build/cli/test"
|
||||
)
|
||||
.into(),
|
||||
booted: true,
|
||||
staged: false,
|
||||
},
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference: format!(
|
||||
"{OSTREE_IMAGE_SIGNED}:docker://ghcr.io/blue-build/cli/test:last"
|
||||
)
|
||||
.into(),
|
||||
booted: false,
|
||||
staged: false,
|
||||
},
|
||||
]
|
||||
.into(),
|
||||
transactions: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_transaction_status<'a>() -> RpmOstreeStatus<'a> {
|
||||
RpmOstreeStatus {
|
||||
deployments: vec![
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference: format!(
|
||||
"{OSTREE_IMAGE_SIGNED}:docker://ghcr.io/blue-build/cli/test"
|
||||
)
|
||||
.into(),
|
||||
booted: true,
|
||||
staged: false,
|
||||
},
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference: format!(
|
||||
"{OSTREE_IMAGE_SIGNED}:docker://ghcr.io/blue-build/cli/test:last"
|
||||
)
|
||||
.into(),
|
||||
booted: false,
|
||||
staged: false,
|
||||
},
|
||||
]
|
||||
.into(),
|
||||
transactions: Some(vec!["Upgrade".into(), "/".into()].into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_archive_status<'a>() -> RpmOstreeStatus<'a> {
|
||||
RpmOstreeStatus {
|
||||
deployments: vec![
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference:
|
||||
format!("{OSTREE_UNVERIFIED_IMAGE}:{OCI_ARCHIVE}:{LOCAL_BUILD}/cli_test.{ARCHIVE_SUFFIX}").into(),
|
||||
booted: true,
|
||||
staged: false,
|
||||
},
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference:
|
||||
format!("{OSTREE_IMAGE_SIGNED}:docker://ghcr.io/blue-build/cli/test:last").into(),
|
||||
booted: false,
|
||||
staged: false,
|
||||
},
|
||||
]
|
||||
.into(),
|
||||
transactions: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_archive_staged_status<'a>() -> RpmOstreeStatus<'a> {
|
||||
RpmOstreeStatus {
|
||||
deployments: vec![
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference:
|
||||
format!("{OSTREE_UNVERIFIED_IMAGE}:{OCI_ARCHIVE}:{LOCAL_BUILD}/cli_test.{ARCHIVE_SUFFIX}").into(),
|
||||
booted: false,
|
||||
staged: true,
|
||||
},
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference:
|
||||
format!("{OSTREE_UNVERIFIED_IMAGE}:{OCI_ARCHIVE}:{LOCAL_BUILD}/cli_test.{ARCHIVE_SUFFIX}").into(),
|
||||
booted: true,
|
||||
staged: false,
|
||||
},
|
||||
RpmOstreeDeployments {
|
||||
container_image_reference:
|
||||
format!("{OSTREE_IMAGE_SIGNED}:docker://ghcr.io/blue-build/cli/test:last").into(),
|
||||
booted: false,
|
||||
staged: false,
|
||||
},
|
||||
]
|
||||
.into(),
|
||||
transactions: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_booted_image() {
|
||||
assert!(create_image_status()
|
||||
.booted_image()
|
||||
.expect("Contains image")
|
||||
.ends_with("cli/test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_staged_image() {
|
||||
assert!(create_archive_staged_status()
|
||||
.staged_image()
|
||||
.expect("Contains image")
|
||||
.ends_with(&format!("cli_test.{ARCHIVE_SUFFIX}")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_in_progress() {
|
||||
assert!(create_transaction_status().transaction_in_progress());
|
||||
assert!(!create_image_status().transaction_in_progress());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_booted_archive() {
|
||||
assert!(!create_archive_status()
|
||||
.is_booted_on_archive(Path::new(LOCAL_BUILD).join(format!("cli.{ARCHIVE_SUFFIX}"))));
|
||||
assert!(create_archive_status().is_booted_on_archive(
|
||||
Path::new(LOCAL_BUILD).join(format!("cli_test.{ARCHIVE_SUFFIX}"))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_staged_archive() {
|
||||
assert!(!create_archive_staged_status()
|
||||
.is_staged_on_archive(Path::new(LOCAL_BUILD).join(format!("cli.{ARCHIVE_SUFFIX}"))));
|
||||
assert!(create_archive_staged_status().is_staged_on_archive(
|
||||
Path::new(LOCAL_BUILD).join(format!("cli_test.{ARCHIVE_SUFFIX}"))
|
||||
));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue