From 16b0382f1f6b406ceca085a953e9d7e17066d556 Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Tue, 19 May 2026 15:06:18 -0400 Subject: [PATCH] import CS bootc-1.15.1-1.el10 --- .gitignore | 5 +- 0000-bootc-inistall-provision.patch | 69 --- 0001-bootc-inistall-provision.patch | 14 - ...-PR-1752-add-target_root_path-for-Ro.patch | 475 ------------------ bootc.spec | 166 ++++-- sources | 5 +- 6 files changed, 129 insertions(+), 605 deletions(-) delete mode 100644 0000-bootc-inistall-provision.patch delete mode 100644 0001-bootc-inistall-provision.patch delete mode 100644 0001-install-Backport-PR-1752-add-target_root_path-for-Ro.patch diff --git a/.gitignore b/.gitignore index 70d2555..343f6ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -bootc-1.8.0-vendor.tar.zstd -bootc-1.8.0.tar.zstd -bootc-oraclelinux-configs.tar.gz +bootc-1.15.1-vendor.tar.zstd +bootc-1.15.1.tar.zstd diff --git a/0000-bootc-inistall-provision.patch b/0000-bootc-inistall-provision.patch deleted file mode 100644 index 9b2e64f..0000000 --- a/0000-bootc-inistall-provision.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff --git i/tmt/tests/bootc-install-provision.sh w/tmt/tests/bootc-install-provision.sh -index ca8f82dc..94f7819f 100755 ---- i/tmt/tests/bootc-install-provision.sh -+++ w/tmt/tests/bootc-install-provision.sh -@@ -9,6 +9,8 @@ set -exuo pipefail - BOOTC_TEMPDIR=$(mktemp -d) - trap 'rm -rf -- "$BOOTC_TEMPDIR"' EXIT - -+ARCH=$(uname -m) -+ - # LBI only enabled for test-22-logically-bound-install - LBI="${LBI:-disabled}" - -@@ -21,6 +23,28 @@ case "$ID" in - "fedora") - TIER1_IMAGE_URL="${TIER1_IMAGE_URL:-quay.io/fedora/fedora-bootc:${VERSION_ID}}" - ;; -+ "rhel") -+ TIER1_IMAGE_URL="${TIER1_IMAGE_URL:-images.paas.redhat.com/bootc/rhel-bootc:latest-${VERSION_ID}}" -+ -+ CURRENT_COMPOSE_ID=$(skopeo inspect --no-tags --retry-times=5 --tls-verify=false "docker://${TIER1_IMAGE_URL}" | jq -r '.Labels."redhat.compose-id"') -+ -+ if [[ -n ${CURRENT_COMPOSE_ID} ]]; then -+ if [[ ${CURRENT_COMPOSE_ID} == *-updates-* ]]; then -+ BATCH_COMPOSE="updates/" -+ else -+ BATCH_COMPOSE="" -+ fi -+ else -+ BATCH_COMPOSE="updates/" -+ CURRENT_COMPOSE_ID=latest-RHEL-$VERSION_ID -+ fi -+ -+ # use latest compose if specific compose is not accessible -+ RC=$(curl -skIw '%{http_code}' -o /dev/null "http://download.devel.redhat.com/rhel-${VERSION_ID%%.*}/nightly/${BATCH_COMPOSE}RHEL-${VERSION_ID%%.*}/${CURRENT_COMPOSE_ID}/STATUS") -+ if [[ $RC != "200" ]]; then -+ CURRENT_COMPOSE_ID=latest-RHEL-${VERSION_ID%%} -+ fi -+ ;; - esac - - if [ "$TMT_REBOOT_COUNT" -eq 0 ]; then -@@ -98,7 +122,26 @@ COMMONEOF - tee "$FEDORA_CI_CONTAINERFILE" > /dev/null << FEDORACIEOF - FROM $TIER1_IMAGE_URL - -+RUN </dev/null <"$CONTAINERFILE" < -Date: Fri, 23 Jan 2026 17:57:44 -0500 -Subject: [PATCH] install: Backport PR #1752 - add target_root_path for - RootSetup - -This is a backport of PR #1752 to v1.8.0, which enables bootc install -to-filesystem to work correctly on ostree OS systems (like FCOS). - -Changes backported: -- install: empty /boot & /boot/efi (preserving /boot/loader on ostree) -- install: add target_root_path for RootSetup -- install: remove empty directories under /boot after cleaning -- install: mount ESP in clean_boot_directories() - -Adaptation notes for v1.8.0: -The original commit 4 (mount ESP) depended on the composefs module -which does not exist in v1.8.0. This backport adapts it by: -- Adding ESP detection infrastructure to blockdev crate: - - ESP/ESP_ID_MBR constants - - find_partition_of_esp() and find_partition_of_type() methods - - parttype_matches() for case-insensitive UUID comparison -- Using path-based inspect_filesystem() instead of Dir-based - inspect_filesystem_of_dir() (which requires composefs) -- Implementing get_backing_device() locally in bootloader.rs - -Original PR: https://github.com/bootc-dev/bootc/pull/1752 - -Signed-off-by: Jose Marrero -Assisted-By: OpenCode (Claude Opus 4.5) ---- - crates/blockdev/src/blockdev.rs | 89 +++++++++++++++++++ - crates/lib/src/bootloader.rs | 53 ++++++++++++ - crates/lib/src/install.rs | 132 ++++++++++++++++++++++------- - crates/lib/src/install/baseline.rs | 1 + - 4 files changed, 243 insertions(+), 32 deletions(-) - -diff --git a/crates/blockdev/src/blockdev.rs b/crates/blockdev/src/blockdev.rs -index ceed18d9..4b18c248 100644 ---- a/crates/blockdev/src/blockdev.rs -+++ b/crates/blockdev/src/blockdev.rs -@@ -12,6 +12,11 @@ use serde::Deserialize; - - use bootc_utils::CommandRunExt; - -+/// ESP partition type UUID for GPT (EFI System Partition) -+pub const ESP: &str = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"; -+/// ESP partition type IDs for MBR (0x06 = FAT16, 0xEF = EFI System) -+pub const ESP_ID_MBR: &[u8] = &[0x06, 0xEF]; -+ - #[derive(Debug, Deserialize)] - struct DevicesOutput { - blockdevices: Vec, -@@ -117,6 +122,7 @@ pub struct Partition { - pub parttype: String, - pub uuid: Option, - pub name: Option, -+ pub bootable: Option, - } - - #[derive(Debug, Deserialize, PartialEq, Eq)] -@@ -161,6 +167,33 @@ impl PartitionTable { - .ok_or_else(|| anyhow::anyhow!("Missing partition for index {partno}"))?; - Ok(r) - } -+ -+ /// Find the partition with the given type UUID (case-insensitive). -+ /// -+ /// Partition type UUIDs are compared case-insensitively per the GPT specification, -+ /// as different tools may report them in different cases. -+ pub fn find_partition_of_type(&self, uuid: &str) -> Option<&Partition> { -+ self.partitions.iter().find(|p| p.parttype_matches(uuid)) -+ } -+ -+ /// Find the partition with bootable is 'true'. -+ #[allow(dead_code)] -+ pub fn find_partition_of_bootable(&self) -> Option<&Partition> { -+ self.partitions.iter().find(|p| p.is_bootable()) -+ } -+ -+ /// Find the ESP (EFI System Partition). -+ pub fn find_partition_of_esp(&self) -> Result> { -+ match &self.label { -+ PartitionType::Dos => Ok(self.partitions.iter().find(|b| { -+ u8::from_str_radix(&b.parttype, 16) -+ .map(|pt| ESP_ID_MBR.contains(&pt)) -+ .unwrap_or(false) -+ })), -+ PartitionType::Gpt => Ok(self.find_partition_of_type(ESP)), -+ _ => Err(anyhow::anyhow!("Unsupported partition table type")), -+ } -+ } - } - - impl Partition { -@@ -168,6 +201,17 @@ impl Partition { - pub fn path(&self) -> &Utf8Path { - self.node.as_str().into() - } -+ -+ /// Compare partition type UUID case-insensitively per the GPT specification, -+ /// as different tools may report them in different cases. -+ pub fn parttype_matches(&self, uuid: &str) -> bool { -+ self.parttype.eq_ignore_ascii_case(uuid) -+ } -+ -+ /// Check this partition's bootable property. -+ pub fn is_bootable(&self) -> bool { -+ self.bootable.unwrap_or(false) -+ } - } - - #[context("Listing partitions of {dev}")] -@@ -505,4 +549,49 @@ mod test { - ); - Ok(()) - } -+ -+ #[test] -+ fn test_find_partition_of_esp() -> Result<()> { -+ let fixture = indoc::indoc! { r#" -+ { -+ "partitiontable": { -+ "label": "gpt", -+ "id": "A67AA901-2C72-4818-B098-7F1CAC127279", -+ "device": "/dev/loop0", -+ "unit": "sectors", -+ "firstlba": 34, -+ "lastlba": 20971486, -+ "sectorsize": 512, -+ "partitions": [ -+ { -+ "node": "/dev/loop0p1", -+ "start": 2048, -+ "size": 8192, -+ "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", -+ "uuid": "58A4C5F0-BD12-424C-B563-195AC65A25DD", -+ "name": "EFI System" -+ },{ -+ "node": "/dev/loop0p2", -+ "start": 10240, -+ "size": 20961247, -+ "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", -+ "uuid": "F51ABB0D-DA16-4A21-83CB-37F4C805AAA0", -+ "name": "root" -+ } -+ ] -+ } -+ } -+ "# }; -+ let table: SfDiskOutput = serde_json::from_str(fixture).unwrap(); -+ -+ // Find ESP partition using case-insensitive UUID matching -+ let esp = table.partitiontable.find_partition_of_esp()?.unwrap(); -+ assert_eq!(esp.node, "/dev/loop0p1"); -+ -+ // Test parttype_matches is case-insensitive -+ assert!(esp.parttype_matches("c12a7328-f81f-11d2-ba4b-00a0c93ec93b")); -+ assert!(esp.parttype_matches("C12A7328-F81F-11D2-BA4B-00A0C93EC93B")); -+ -+ Ok(()) -+ } - } -diff --git a/crates/lib/src/bootloader.rs b/crates/lib/src/bootloader.rs -index aa07bfe8..1ebec94c 100644 ---- a/crates/lib/src/bootloader.rs -+++ b/crates/lib/src/bootloader.rs -@@ -3,6 +3,8 @@ use std::process::Command; - use anyhow::{anyhow, bail, Context, Result}; - use bootc_utils::CommandRunExt; - use camino::Utf8Path; -+use cap_std_ext::cap_std::fs::Dir; -+use cap_std_ext::dirext::CapStdExtDirExt; - use fn_error_context::context; - - use bootc_blockdev::PartitionTable; -@@ -11,6 +13,57 @@ use bootc_mount as mount; - /// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel) - pub(crate) const EFI_DIR: &str = "efi"; - -+/// Get the backing device for a filesystem at the given path -+fn get_backing_device(root_path: &Utf8Path) -> Result { -+ let fsinfo = mount::inspect_filesystem(root_path)?; -+ let mut dev = fsinfo.source; -+ loop { -+ let mut parents = bootc_blockdev::find_parent_devices(&dev)?.into_iter(); -+ let Some(parent) = parents.next() else { -+ break; -+ }; -+ dev = parent; -+ } -+ Ok(dev) -+} -+ -+/// Get ESP partition node based on the root path -+pub(crate) fn get_esp_partition_node(root_path: &Utf8Path) -> Result> { -+ let device = get_backing_device(root_path)?; -+ let base_partitions = bootc_blockdev::partitions_of(Utf8Path::new(&device))?; -+ let esp = base_partitions.find_partition_of_esp()?; -+ Ok(esp.map(|v| v.node.clone())) -+} -+ -+/// Mount ESP partition at /boot/efi if not already mounted -+pub(crate) fn mount_esp_part(root: &Dir, root_path: &Utf8Path, is_ostree: bool) -> Result<()> { -+ let efi_path = Utf8Path::new("boot").join(EFI_DIR); -+ let Some(esp_fd) = root -+ .open_dir_optional(&efi_path) -+ .context("Opening /boot/efi")? -+ else { -+ return Ok(()); -+ }; -+ -+ let Some(false) = esp_fd.is_mountpoint(".")? else { -+ return Ok(()); -+ }; -+ -+ tracing::debug!("Not a mountpoint: /boot/efi"); -+ // On ostree env, the physical root is at /target/sysroot -+ let physical_root_path = if is_ostree { -+ root_path.join("sysroot") -+ } else { -+ root_path.to_owned() -+ }; -+ -+ if let Some(esp_part) = get_esp_partition_node(&physical_root_path)? { -+ mount::mount(&esp_part, &root_path.join(&efi_path))?; -+ tracing::debug!("Mounted {esp_part} at /boot/efi"); -+ } -+ Ok(()) -+} -+ - #[context("Installing bootloader")] - pub(crate) fn install_via_bootupd( - device: &PartitionTable, -diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs -index 156270dd..ba35419a 100644 ---- a/crates/lib/src/install.rs -+++ b/crates/lib/src/install.rs -@@ -612,6 +612,17 @@ async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result - // Another implementation: https://github.com/coreos/coreos-assembler/blob/3cd3307904593b3a131b81567b13a4d0b6fe7c90/src/create_disk.sh#L295 - crate::lsm::ensure_dir_labeled(rootfs_dir, "", Some("/".into()), 0o755.into(), sepolicy)?; - -+ // If we're installing alongside existing ostree and there's a separate boot partition, -+ // we need to mount it to the sysroot's /boot so ostree can write bootloader entries there -+ if has_ostree && root_setup.boot.is_some() { -+ if let Some(boot) = &root_setup.boot { -+ let source_boot = &boot.source; -+ let target_boot = root_setup.physical_root_path.join(BOOT); -+ tracing::debug!("Mount {source_boot} to {target_boot} on ostree"); -+ bootc_mount::mount(source_boot, &target_boot)?; -+ } -+ } -+ - // And also label /boot AKA xbootldr, if it exists - if rootfs_dir.try_exists("boot")? { - crate::lsm::ensure_dir_labeled(rootfs_dir, "boot", None, 0o755.into(), sepolicy)?; -@@ -927,9 +938,11 @@ pub(crate) struct RootSetup { - device_info: bootc_blockdev::PartitionTable, - /// Absolute path to the location where we've mounted the physical - /// root filesystem for the system we're installing. -- physical_root_path: Utf8PathBuf, -+ pub(crate) physical_root_path: Utf8PathBuf, - /// Directory file descriptor for the above physical root. -- physical_root: Dir, -+ pub(crate) physical_root: Dir, -+ /// Target root path /target. -+ pub(crate) target_root_path: Option, - rootfs_uuid: Option, - /// True if we should skip finalizing - skip_finalize: bool, -@@ -1332,7 +1345,10 @@ async fn install_with_sysroot( - } else { - crate::bootloader::install_via_bootupd( - &rootfs.device_info, -- &rootfs.physical_root_path, -+ &rootfs -+ .target_root_path -+ .clone() -+ .unwrap_or(rootfs.physical_root_path.clone()), - &state.config_opts, - &deployment_path.as_str(), - )?; -@@ -1616,30 +1632,66 @@ fn remove_all_in_dir_no_xdev(d: &Dir, mount_err: bool) -> Result<()> { - anyhow::Ok(()) - } - -+#[context("Removing boot directory content except loader dir on ostree")] -+fn remove_all_except_loader_dirs(bootdir: &Dir, is_ostree: bool) -> Result<()> { -+ let entries = bootdir -+ .entries() -+ .context("Reading boot directory entries")?; -+ -+ for entry in entries { -+ let entry = entry.context("Reading directory entry")?; -+ let file_name = entry.file_name(); -+ let file_name = if let Some(n) = file_name.to_str() { -+ n -+ } else { -+ anyhow::bail!("Invalid non-UTF8 filename: {file_name:?} in /boot"); -+ }; -+ -+ // TODO: Preserve basically everything (including the bootloader entries -+ // on non-ostree) by default until the very end of the install. And ideally -+ // make the "commit" phase an optional step after. -+ if is_ostree && file_name.starts_with("loader") { -+ continue; -+ } -+ -+ let etype = entry.file_type()?; -+ if etype == FileType::dir() { -+ // Open the directory and remove its contents -+ if let Some(subdir) = bootdir.open_dir_noxdev(&file_name)? { -+ remove_all_in_dir_no_xdev(&subdir, false) -+ .with_context(|| format!("Removing directory contents: {}", file_name))?; -+ bootdir.remove_dir(&file_name)?; -+ } -+ } else { -+ bootdir -+ .remove_file_optional(&file_name) -+ .with_context(|| format!("Removing file: {}", file_name))?; -+ } -+ } -+ Ok(()) -+} -+ - #[context("Removing boot directory content")] --fn clean_boot_directories(rootfs: &Dir, is_ostree: bool) -> Result<()> { -+fn clean_boot_directories(rootfs: &Dir, rootfs_path: &Utf8Path, is_ostree: bool) -> Result<()> { - let bootdir = - crate::utils::open_dir_remount_rw(rootfs, BOOT.into()).context("Opening /boot")?; - -- if is_ostree { -- // On ostree systems, the boot directory already has our desired format, we should only -- // remove the bootupd-state.json file to avoid bootupctl complaining it already exists. -- bootdir -- .remove_file_optional("bootupd-state.json") -- .context("removing bootupd-state.json")?; -- } else { -- // This should not remove /boot/efi note. -- remove_all_in_dir_no_xdev(&bootdir, false).context("Emptying /boot")?; -- // TODO: Discover the ESP the same way bootupd does it; we should also -- // support not wiping the ESP. -- if ARCH_USES_EFI { -- if let Some(efidir) = bootdir -- .open_dir_optional(crate::bootloader::EFI_DIR) -- .context("Opening /boot/efi")? -- { -- remove_all_in_dir_no_xdev(&efidir, false) -- .context("Emptying EFI system partition")?; -- } -+ if ARCH_USES_EFI { -+ // On booted FCOS, esp is not mounted by default -+ // Mount ESP part at /boot/efi before clean -+ crate::bootloader::mount_esp_part(rootfs, rootfs_path, is_ostree)?; -+ } -+ -+ // This should not remove /boot/efi note. -+ remove_all_except_loader_dirs(&bootdir, is_ostree).context("Emptying /boot")?; -+ -+ // TODO: we should also support not wiping the ESP. -+ if ARCH_USES_EFI { -+ if let Some(efidir) = bootdir -+ .open_dir_optional(crate::bootloader::EFI_DIR) -+ .context("Opening /boot/efi")? -+ { -+ remove_all_in_dir_no_xdev(&efidir, false).context("Emptying EFI system partition")?; - } - } - -@@ -1767,6 +1819,18 @@ pub(crate) async fn install_to_filesystem( - .context("Mounting host / to {ALONGSIDE_ROOT_MOUNT}")?; - } - -+ let target_root_path = fsopts.root_path.clone(); -+ // Get a file descriptor for the root path /target -+ let target_rootfs_fd = -+ Dir::open_ambient_dir(&target_root_path, cap_std::ambient_authority()) -+ .with_context(|| format!("Opening target root directory {target_root_path}"))?; -+ -+ tracing::debug!("Target root filesystem: {target_root_path}"); -+ -+ if let Some(false) = target_rootfs_fd.is_mountpoint(".")? { -+ anyhow::bail!("Not a mountpoint: {target_root_path}"); -+ } -+ - // Check that the target is a directory - { - let root_path = &fsopts.root_path; -@@ -1780,10 +1844,7 @@ pub(crate) async fn install_to_filesystem( - - // Check to see if this happens to be the real host root - if !fsopts.acknowledge_destructive { -- let root_path = &fsopts.root_path; -- let rootfs_fd = Dir::open_ambient_dir(root_path, cap_std::ambient_authority()) -- .with_context(|| format!("Opening target root directory {root_path}"))?; -- warn_on_host_root(&rootfs_fd)?; -+ warn_on_host_root(&target_rootfs_fd)?; - } - - // If we're installing to an ostree root, then find the physical root from -@@ -1799,7 +1860,8 @@ pub(crate) async fn install_to_filesystem( - }; - - // Get a file descriptor for the root path -- let rootfs_fd = { -+ // It will be /target/sysroot on ostree OS, or will be /target -+ let rootfs_fd = if is_already_ostree { - let root_path = &fsopts.root_path; - let rootfs_fd = Dir::open_ambient_dir(&fsopts.root_path, cap_std::ambient_authority()) - .with_context(|| format!("Opening target root directory {root_path}"))?; -@@ -1810,6 +1872,8 @@ pub(crate) async fn install_to_filesystem( - anyhow::bail!("Not a mountpoint: {root_path}"); - } - rootfs_fd -+ } else { -+ target_rootfs_fd.try_clone()? - }; - - match fsopts.replace { -@@ -1819,7 +1883,9 @@ pub(crate) async fn install_to_filesystem( - tokio::task::spawn_blocking(move || remove_all_in_dir_no_xdev(&rootfs_fd, true)) - .await??; - } -- Some(ReplaceMode::Alongside) => clean_boot_directories(&rootfs_fd, is_already_ostree)?, -+ Some(ReplaceMode::Alongside) => { -+ clean_boot_directories(&target_rootfs_fd, &target_root_path, is_already_ostree)? -+ } - None => require_empty_rootdir(&rootfs_fd)?, - } - -@@ -1864,7 +1930,7 @@ pub(crate) async fn install_to_filesystem( - - let boot_is_mount = { - let root_dev = rootfs_fd.dir_metadata()?.dev(); -- let boot_dev = rootfs_fd -+ let boot_dev = target_rootfs_fd - .symlink_metadata_optional(BOOT)? - .ok_or_else(|| { - anyhow!("No /{BOOT} directory found in root; this is is currently required") -@@ -1875,9 +1941,10 @@ pub(crate) async fn install_to_filesystem( - }; - // Find the UUID of /boot because we need it for GRUB. - let boot_uuid = if boot_is_mount { -- let boot_path = fsopts.root_path.join(BOOT); -+ let boot_path = target_root_path.join(BOOT); -+ tracing::debug!("boot_path={boot_path}"); - let u = bootc_mount::inspect_filesystem(&boot_path) -- .context("Inspecting /{BOOT}")? -+ .with_context(|| format!("Inspecting /{BOOT}"))? - .uuid - .ok_or_else(|| anyhow!("No UUID found for /{BOOT}"))?; - Some(u) -@@ -1956,6 +2023,7 @@ pub(crate) async fn install_to_filesystem( - device_info, - physical_root_path: fsopts.root_path, - physical_root: rootfs_fd, -+ target_root_path: Some(target_root_path.clone()), - rootfs_uuid: inspect.uuid.clone(), - boot, - kargs, -diff --git a/crates/lib/src/install/baseline.rs b/crates/lib/src/install/baseline.rs -index 1cd48c48..fdafa9ac 100644 ---- a/crates/lib/src/install/baseline.rs -+++ b/crates/lib/src/install/baseline.rs -@@ -455,6 +455,7 @@ pub(crate) fn install_create_rootfs( - device_info, - physical_root_path, - physical_root, -+ target_root_path: None, - rootfs_uuid: Some(root_uuid.to_string()), - boot, - kargs, --- -2.52.0 - diff --git a/bootc.spec b/bootc.spec index fc755c1..247244a 100644 --- a/bootc.spec +++ b/bootc.spec @@ -1,15 +1,16 @@ ## START: Set by rpmautospec -## (rpmautospec version 0.8.3) +## (rpmautospec version 0.6.5) ## RPMAUTOSPEC: autorelease, autochangelog %define autorelease(e:s:pb:n) %{?-p:0.}%{lua: - release_number = 4; + release_number = 1; base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); print(release_number + base_release_number - 1); }%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} ## END: Set by rpmautospec %bcond_without check -%if 0%{?rhel} >= 10 || 0%{?fedora} > 41 +%bcond_with tests +%if 0%{?rhel} >= 9 || 0%{?fedora} > 41 %bcond_without ostree_ext %else %bcond_with ostree_ext @@ -21,8 +22,17 @@ %bcond_with rhsm %endif +%global rust_minor %(rustc --version | cut -f2 -d" " | cut -f2 -d".") + +# https://github.com/bootc-dev/bootc/issues/1640 +%if 0%{?fedora} || 0%{?rhel} >= 10 || 0%{?rust_minor} >= 89 + %global new_cargo_macros 1 +%else + %global new_cargo_macros 0 +%endif + Name: bootc -Version: 1.8.0 +Version: 1.15.1 Release: %{autorelease} Summary: Bootable container system @@ -35,16 +45,10 @@ Summary: Bootable container system # MIT OR Apache-2.0 # Unlicense OR MIT License: Apache-2.0 AND BSD-3-Clause AND MIT AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Unlicense OR MIT) -URL: https://github.com/containers/bootc +URL: https://github.com/bootc-dev/bootc Source0: %{url}/releases/download/v%{version}/bootc-%{version}.tar.zstd Source1: %{url}/releases/download/v%{version}/bootc-%{version}-vendor.tar.zstd -# Don't remove, downstream patch only -# Patch for integration test RHEL 9.x and 10.x support -Patch0: 0000-bootc-inistall-provision.patch -Patch1: 0001-bootc-inistall-provision.patch -Patch2: 0001-install-Backport-PR-1752-add-target_root_path-for-Ro.patch - # https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval ExcludeArch: %{ix86} @@ -52,6 +56,7 @@ BuildRequires: libzstd-devel BuildRequires: make BuildRequires: ostree-devel BuildRequires: openssl-devel +BuildRequires: go-md2man %if 0%{?rhel} BuildRequires: rust-toolset %else @@ -63,10 +68,13 @@ BuildRequires: skopeo ostree # Backing storage tooling https://github.com/containers/composefs/issues/125 Requires: composefs -# For OS updates +# Keep this list in sync with workspace.metadata.binary-dependencies until we sync +# it automatically Requires: ostree Requires: skopeo Requires: podman +Requires: util-linux-core +Requires: /usr/bin/chcon # For bootloader updates Recommends: bootupd @@ -87,96 +95,172 @@ Recommends: podman %description -n system-reinstall-bootc This package provides a utility to simplify reinstalling the current system to a given bootc image. +%if %{with tests} +%package tests +Summary: Integration tests for bootc +Requires: %{name} = %{version}-%{release} + +%description tests +This package contains the integration test suite for bootc. +%endif + %global system_reinstall_bootc_install_podman_path %{_prefix}/lib/system-reinstall-bootc/install-podman +%if 0%{?container_build} +# Source is already at /src, no subdirectory +%global _buildsubdir . +%endif + %prep +%if ! 0%{?container_build} %autosetup -p1 -a1 # Default -v vendor config doesn't support non-crates.io deps (i.e. git) cp .cargo/vendor-config.toml . %cargo_prep -N cat vendor-config.toml >> .cargo/config.toml rm vendor-config.toml +%else +# Container build: source already at _builddir (/src), nothing to extract +# RPM's %mkbuilddir creates a subdirectory; symlink it back to the source +cd .. +rm -rf %{name}-%{version}-build +ln -s . %{name}-%{version}-build +cd %{name}-%{version}-build +%endif %build -# Build the main bootc binary -%if 0%{?fedora} || 0%{?rhel} >= 10 - %cargo_build %{?with_rhsm:-f rhsm} -%else - %cargo_build %{?with_rhsm:--features rhsm} -%endif - -# Build the system reinstallation CLI binary -%global cargo_args -p system-reinstall-bootc export SYSTEM_REINSTALL_BOOTC_INSTALL_PODMAN_PATH=%{system_reinstall_bootc_install_podman_path} -%if 0%{?fedora} || 0%{?rhel} >= 10 - # In cargo-rpm-macros, the cargo_build macro does flag processing, - # so we need to pass '--' to signify that cargo_args is not part - # of the macro args - %cargo_build -- %cargo_args +# Build this first to avoid feature skew +make manpages + +# Build all binaries +%if 0%{?container_build} +# Container build: use cargo directly with cached dependencies to avoid RPM macro overhead +cargo build -j%{_smp_build_ncpus} --release %{?with_rhsm:--features rhsm} --bins %else - # Older macros from rust-toolset do *not* do flag processing, so - # '--' would be passed through to cargo directly, which is not - # what we want. - %cargo_build %cargo_args +# Non-container build: use RPM macros for proper dependency tracking +%if %new_cargo_macros + %cargo_build %{?with_rhsm:-f rhsm} -- --bins +%else + %cargo_build %{?with_rhsm:--features rhsm} -- --bins +%endif %endif +%if ! 0%{?container_build} %cargo_vendor_manifest # https://pagure.io/fedora-rust/rust-packaging/issue/33 sed -i -e '/https:\/\//d' cargo-vendor.txt %cargo_license_summary %{cargo_license} > LICENSE.dependencies +%endif %install -%make_install INSTALL="install -p -c" +# Pass CARGO_FEATURES explicitly to prevent auto-detection rebuild in install environment +%make_install INSTALL="install -p -c" CARGO_FEATURES="%{?with_rhsm:rhsm}" %if %{with ostree_ext} make install-ostree-hooks DESTDIR=%{?buildroot} %endif +%if %{with tests} +install -D -m 0755 target/release/tests-integration %{buildroot}%{_bindir}/bootc-integration-tests +%endif mkdir -p %{buildroot}/%{dirname:%{system_reinstall_bootc_install_podman_path}} cat >%{?buildroot}/%{system_reinstall_bootc_install_podman_path} < bootcdoclist.txt + +rm -f %{buildroot}/%{_datadir}/elvish/lib/bootc.elv +rm -f %{buildroot}/%{_datadir}/powershell/Modules/Bootc/Bootc.psm1 %if %{with check} %check -%cargo_test +if grep -qEe 'Seccomp:.*0$' /proc/self/status; then + %cargo_test +else + echo "skipping unit tests due to https://github.com/rpm-software-management/mock/pull/1613#issuecomment-3421908652" +fi %endif -%files +%files -f bootcdoclist.txt %license LICENSE-MIT %license LICENSE-APACHE +%if ! 0%{?container_build} %license LICENSE.dependencies %license cargo-vendor.txt +%endif %doc README.md %{_bindir}/bootc %{_prefix}/lib/bootc/ %{_prefix}/lib/systemd/system-generators/* +%{_prefix}/lib/dracut/modules.d/51bootc/ %if %{with ostree_ext} %{_prefix}/libexec/libostree/ext/* %endif %{_unitdir}/* -%{_docdir}/bootc/* -%{_mandir}/man*/bootc* +%{_mandir}/man*/*bootc* +%if 0%{?rhel} && 0%{?rhel} <= 9 +%{_datadir}/bash-completion/completions/bootc +%{_datadir}/zsh/site-functions/_bootc +%{_datadir}/fish/vendor_completions.d/bootc.fish +%else +%{bash_completions_dir}/bootc +%{zsh_completions_dir}/_bootc +%{fish_completions_dir}/bootc.fish +%endif %files -n system-reinstall-bootc %{_bindir}/system-reinstall-bootc %{system_reinstall_bootc_install_podman_path} +%if %{with tests} +%files tests +%{_bindir}/bootc-integration-tests +%endif + %changelog ## START: Generated by rpmautospec -* Wed Jan 28 2026 Xiaofeng Wang - 1.8.0-4 -- Fix gating test issue and ignore rpminpect symbolic link checking +* Tue Apr 14 2026 Joseph Marrero Corchado - 1.15.1-1 +- Release 1.15.1 -* Sat Jan 24 2026 Joseph Marrero Corchado - 1.8.0-3 -- Backport https://github.com/bootc-dev/bootc/pull/1752 +* Fri Mar 20 2026 Colin Walters - 1.14.1-1 +- Update to 1.14.1 -* Thu Sep 11 2025 Joseph Marrero Corchado - 1.8.0-2 -- Rev bump as rhpkg needed an update to tag into 10.1.z +* Tue Feb 24 2026 Colin Walters - 1.13.0-1 +- Release 1.13.0 +- Update to bootc 1.13.0 +- Pass CARGO_FEATURES explicitly to make install to prevent auto-detection + rebuild in install environment (workaround for upstream Makefile issue) +- Package shell completions (bash, zsh, fish) + +* Mon Jan 19 2026 Xiaofeng Wang - 1.12.1-2 +- Skip rpminspect checking for symbolic link /usr/lib/bootc/storage + +* Fri Jan 16 2026 Colin Walters - 1.12.1-1 +- Release 1.12.1 + +* Fri Jan 09 2026 Colin Walters - 1.12.0-1 +- Release 1.12.0 + +* Tue Dec 09 2025 Joseph Marrero Corchado - 1.11.0-1 +- Release 1.11.0 + +* Wed Nov 05 2025 Xiaofeng Wang - 1.10.0-2 +- Fix gating test + +* Fri Oct 31 2025 Joseph Marrero Corchado - 1.10.0-1 +- Release 1.10.0 * Fri Sep 05 2025 Colin Walters - 1.8.0-1 - Rebase to 1.8.0 +* Tue Aug 26 2025 Joseph Marrero Corchado - 1.7.1-1 +- Release 1.7.1 + * Fri Aug 22 2025 Joseph Marrero Corchado - 1.7.0-1 - Release 1.7.0 diff --git a/sources b/sources index da3234e..af61905 100644 --- a/sources +++ b/sources @@ -1,3 +1,2 @@ -SHA512 (bootc-1.8.0-vendor.tar.zstd) = 87efa96f2fb266a5ed951e24ce2992c313c7f69dbfbb36dce3ccbb5f75362db2542510ca18c405aedc5e1fa8b8d9b05855398a25d9422b978a18c3065dce7930 -SHA512 (bootc-1.8.0.tar.zstd) = 8ca696abd901dbc934c64199ee817466c41ae18dc516310e3bfcb9e67b97e5380507da6a7f480ef335241afc53794721efc6ffec58cd3b36ed857006390b9ab8 -SHA512 (bootc-oraclelinux-configs.tar.gz) = e9c390d502214b7fdd0b80aaad28066f6efff262565863803d535b6864e39533ff1b5a3c5ba3ee6901e2506c5e74c380ce806e9bed00f59c0e83cb47974ea9dd +SHA512 (bootc-1.15.1-vendor.tar.zstd) = dad48260d88e1a278aee8721c9985b1b3ff47474c64876f335a05b3e93af259b28b387a056394b09b3dd2ae42db2c141140f77aac6c3c887262f73a24671f125 +SHA512 (bootc-1.15.1.tar.zstd) = afd7deeb1f34b8d023675a8d8cc40eb5802b7ec541269db93488cac9776ccd967d9d4737a39ae445d4cd78b57fd8a236e0b6f0bc0d447f207361828a2e2ca4c4