import CS bootc-1.15.1-1.el10

This commit is contained in:
AlmaLinux RelEng Bot 2026-05-19 15:06:18 -04:00
parent c2e22e7a10
commit 16b0382f1f
6 changed files with 129 additions and 605 deletions

5
.gitignore vendored
View File

@ -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

View File

@ -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 <<REPORUN
+tee "/etc/yum.repos.d/rhel.repo" >/dev/null <<RHELREPOEOF
+[rhel-baseos]
+name=baseos
+baseurl=http://download.devel.redhat.com/rhel-${VERSION_ID%%.*}/nightly/${BATCH_COMPOSE}RHEL-${VERSION_ID%%.*}/${CURRENT_COMPOSE_ID}/compose/BaseOS/${ARCH}/os/
+enabled=1
+gpgcheck=0
+
+[rhel-appstream]
+name=appstream
+baseurl=http://download.devel.redhat.com/rhel-${VERSION_ID%%.*}/nightly/${BATCH_COMPOSE}RHEL-${VERSION_ID%%.*}/${CURRENT_COMPOSE_ID}/compose/AppStream/${ARCH}/os/
+enabled=1
+gpgcheck=0
+RHELREPOEOF
+REPORUN
+
RUN dnf -y upgrade /rpms/*.rpm
+
+# Required by tmt avc checking after test
+RUN dnf -y install audit
FEDORACIEOF
cat >"$CONTAINERFILE" <<REALEOF
$(cat "$FEDORA_CI_CONTAINERFILE")

View File

@ -1,14 +0,0 @@
diff --git i/tmt/tests/bootc-install-provision.sh w/tmt/tests/bootc-install-provision.sh
index 6c9968c..c617d5e 100755
--- i/tmt/tests/bootc-install-provision.sh
+++ w/tmt/tests/bootc-install-provision.sh
@@ -50,7 +50,8 @@ if [ "$TMT_REBOOT_COUNT" -eq 0 ]; then
fi
# Some rhts-*, rstrnt-* and tmt-* commands are in /usr/local/bin
- cp -r /usr/local/bin "$BOOTC_TEMPDIR"
+ cp -r /var/lib/tmt/scripts "$BOOTC_TEMPDIR/bin"
+ ls -al "$BOOTC_TEMPDIR/bin"
# Check image building folder content
ls -al "$BOOTC_TEMPDIR"

View File

@ -1,475 +0,0 @@
From 1ac6c73d26b999c158414871fa5a98cee28bae92 Mon Sep 17 00:00:00 2001
From: Jose Marrero <jmarrero@redhat.com>
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 <jmarrero@redhat.com>
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<Device>,
@@ -117,6 +122,7 @@ pub struct Partition {
pub parttype: String,
pub uuid: Option<String>,
pub name: Option<String>,
+ pub bootable: Option<bool>,
}
#[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<Option<&Partition>> {
+ 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<String> {
+ 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<Option<String>> {
+ 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<Utf8PathBuf>,
rootfs_uuid: Option<String>,
/// 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

View File

@ -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} <<EOF
#!/bin/bash
exec dnf -y install podman
EOF
chmod +x %{?buildroot}/%{system_reinstall_bootc_install_podman_path}
# generate doc file list excluding directories; workaround for
# https://github.com/coreos/rpm-ostree/issues/5420
touch %{?buildroot}/%{_docdir}/bootc/baseimage/base/sysroot/.keepdir
find %{?buildroot}/%{_docdir} ! -type d -printf '%{_docdir}/%%P\n' | sort > 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 <xiaofwan@redhat.com> - 1.8.0-4
- Fix gating test issue and ignore rpminpect symbolic link checking
* Tue Apr 14 2026 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.15.1-1
- Release 1.15.1
* Sat Jan 24 2026 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.8.0-3
- Backport https://github.com/bootc-dev/bootc/pull/1752
* Fri Mar 20 2026 Colin Walters <walters@verbum.org> - 1.14.1-1
- Update to 1.14.1
* Thu Sep 11 2025 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.8.0-2
- Rev bump as rhpkg needed an update to tag into 10.1.z
* Tue Feb 24 2026 Colin Walters <walters@verbum.org> - 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 <xiaofwan@redhat.com> - 1.12.1-2
- Skip rpminspect checking for symbolic link /usr/lib/bootc/storage
* Fri Jan 16 2026 Colin Walters <walters@verbum.org> - 1.12.1-1
- Release 1.12.1
* Fri Jan 09 2026 Colin Walters <walters@verbum.org> - 1.12.0-1
- Release 1.12.0
* Tue Dec 09 2025 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.11.0-1
- Release 1.11.0
* Wed Nov 05 2025 Xiaofeng Wang <xiaofwan@redhat.com> - 1.10.0-2
- Fix gating test
* Fri Oct 31 2025 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.10.0-1
- Release 1.10.0
* Fri Sep 05 2025 Colin Walters <walters@verbum.org> - 1.8.0-1
- Rebase to 1.8.0
* Tue Aug 26 2025 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.7.1-1
- Release 1.7.1
* Fri Aug 22 2025 Joseph Marrero Corchado <jmarrero@redhat.com> - 1.7.0-1
- Release 1.7.0

View File

@ -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