From 570d12e850f82322b1f3be5b3e26ea26ecfefaea Mon Sep 17 00:00:00 2001 From: cgwalters-bot Date: Tue, 22 Sep 2026 22:27:29 -0400 Subject: [PATCH 1/2] cli: Reuse DVerb for `bootupctl backend` `bootupctl backend` had its own copy of the `bootupd` verbs that had to be kept in sync by hand, and its variants were each individually hidden. Share the one enum so both entrypoints get the same verbs and help text. Prep for un-hiding `backend`. Generated-by: AI --- src/cli/bootupctl.rs | 24 ++---------------------- src/cli/bootupd.rs | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/src/cli/bootupctl.rs b/src/cli/bootupctl.rs index 7f2d7507..2fc7ebf5 100644 --- a/src/cli/bootupctl.rs +++ b/src/cli/bootupctl.rs @@ -52,7 +52,7 @@ pub enum CtlVerb { // FIXME(lucab): drop this after refreshing // https://github.com/coreos/fedora-coreos-config/pull/595 #[clap(name = "backend", hide = true, subcommand)] - Backend(CtlBackend), + Backend(super::bootupd::DVerb), #[clap(name = "status", about = "Show components status")] Status(StatusOpts), #[clap(name = "update", about = "Update all components")] @@ -69,17 +69,6 @@ pub enum CtlVerb { MigrateStaticGrubConfig, } -#[derive(Debug, Parser)] -pub enum CtlBackend { - #[clap(name = "generate-update-metadata", hide = true)] - Generate(super::bootupd::GenerateOpts), - #[clap(name = "install", hide = true)] - Install(super::bootupd::InstallOpts), - #[clap(hide = true)] - #[cfg(efi_arch)] - SetDefaultBootloader(super::bootupd::DefaultBootloaderOpts), -} - #[derive(Debug, Parser)] pub struct StatusOpts { /// If there are updates available, output `Updates available: ` to standard output; @@ -123,16 +112,7 @@ impl CtlCommand { CtlVerb::Update(opts) => Self::run_update(opts), CtlVerb::AdoptAndUpdate(opts) => Self::run_adopt_and_update(opts), CtlVerb::Validate => Self::run_validate(), - CtlVerb::Backend(CtlBackend::Generate(opts)) => { - super::bootupd::DCommand::run_generate_meta(opts) - } - CtlVerb::Backend(CtlBackend::Install(opts)) => { - super::bootupd::DCommand::run_install(opts) - } - #[cfg(efi_arch)] - CtlVerb::Backend(CtlBackend::SetDefaultBootloader(opts)) => { - super::bootupd::DCommand::set_default_bootloader(opts) - } + CtlVerb::Backend(verb) => verb.run(), CtlVerb::MigrateStaticGrubConfig => Self::run_migrate_static_grub_config(), } } diff --git a/src/cli/bootupd.rs b/src/cli/bootupd.rs index a9b8951b..f7949791 100644 --- a/src/cli/bootupd.rs +++ b/src/cli/bootupd.rs @@ -108,15 +108,22 @@ pub struct DefaultBootloaderOpts { pub(crate) bootloader: Bootloader, } +impl DVerb { + /// Run this verb; shared by `bootupd` and `bootupctl backend`. + pub(crate) fn run(self) -> Result<()> { + match self { + DVerb::Install(opts) => DCommand::run_install(opts), + DVerb::GenerateUpdateMetadata(opts) => DCommand::run_generate_meta(opts), + #[cfg(efi_arch)] + DVerb::SetDefaultBootloader(opts) => DCommand::set_default_bootloader(opts), + } + } +} + impl DCommand { /// Run CLI application. pub fn run(self) -> Result<()> { - match self.cmd { - DVerb::Install(opts) => Self::run_install(opts), - DVerb::GenerateUpdateMetadata(opts) => Self::run_generate_meta(opts), - #[cfg(efi_arch)] - DVerb::SetDefaultBootloader(opts) => Self::set_default_bootloader(opts), - } + self.cmd.run() } /// Runner for `generate-install-metadata` verb. From a5fa13ee31e8ada2cabbb44d9c1c6c4c3fc492d7 Mon Sep 17 00:00:00 2001 From: cgwalters-bot Date: Tue, 22 Sep 2026 22:28:13 -0400 Subject: [PATCH 2/2] cli: Un-hide `bootupctl backend` and document its verbs Hiding `backend` was meant to keep the client side less confusing, but in practice hidden commands cause more confusion than they avoid: they are used by image build tooling and referenced in our own docs, yet `--help` gives no hint they exist or what they are for. Show it, listed after the verbs for a booted system, and give it and its verbs help text that explains they operate on an OS tree or target root at build/install time, pointing users who want to update a booted system at `update` and `adopt-and-update`. Add a test so the verbs stay visible and documented. Note this reverses the intent of the deleted FIXME(lucab) comment, which planned to eventually drop `backend` from bootupctl once coreos/fedora-coreos-config#595 was refreshed. Since image build tooling still relies on it, making it a documented interface seems better, but that is a call for the maintainers. Related: #1119 Generated-by: AI --- src/cli/bootupctl.rs | 12 ++++++++---- src/cli/bootupd.rs | 17 ++++++++++++++--- src/cli/mod.rs | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/cli/bootupctl.rs b/src/cli/bootupctl.rs index 2fc7ebf5..f462b2c8 100644 --- a/src/cli/bootupctl.rs +++ b/src/cli/bootupctl.rs @@ -49,10 +49,6 @@ impl CtlCommand { /// CLI sub-commands. #[derive(Debug, Parser)] pub enum CtlVerb { - // FIXME(lucab): drop this after refreshing - // https://github.com/coreos/fedora-coreos-config/pull/595 - #[clap(name = "backend", hide = true, subcommand)] - Backend(super::bootupd::DVerb), #[clap(name = "status", about = "Show components status")] Status(StatusOpts), #[clap(name = "update", about = "Update all components")] @@ -61,6 +57,14 @@ pub enum CtlVerb { AdoptAndUpdate(AdoptAndUpdateOpts), #[clap(name = "validate", about = "Validate system state")] Validate, + /// Low-level commands for building and installing OS images + /// + /// These act on an OS tree or target root rather than on the running + /// system, and are intended for image build and installation tooling + /// (e.g. `bootc install` or disk image builders). To update the + /// bootloader of a booted system, use `update` or `adopt-and-update`. + #[clap(name = "backend", subcommand)] + Backend(super::bootupd::DVerb), #[clap( name = "migrate-static-grub-config", hide = true, diff --git a/src/cli/bootupd.rs b/src/cli/bootupd.rs index f7949791..4d57637f 100644 --- a/src/cli/bootupd.rs +++ b/src/cli/bootupd.rs @@ -36,10 +36,21 @@ impl DCommand { /// CLI sub-commands. #[derive(Debug, Parser)] pub enum DVerb { - #[clap(name = "generate-update-metadata", about = "Generate metadata")] + /// Generate update metadata from the bootloader files in an OS tree + /// + /// Run this at image build time. It records the bootloader component + /// versions (e.g. from the RPM database) under /usr/lib/bootupd/updates, + /// which `install` and `update` later use as their source. + #[clap(name = "generate-update-metadata")] GenerateUpdateMetadata(GenerateOpts), - #[clap(name = "install", about = "Install components")] + /// Install bootloader components to a target root + /// + /// Used when creating a disk image or installing a system: copies the + /// update payload from the source root into the target's ESP and/or + /// boot partition, and installs to the target block device(s) as needed. + #[clap(name = "install")] Install(InstallOpts), + /// Set the default bootloader on EFI systems #[cfg(efi_arch)] SetDefaultBootloader(DefaultBootloaderOpts), } @@ -94,7 +105,7 @@ pub(crate) struct InstallOpts { #[derive(Debug, Parser)] pub struct GenerateOpts { - /// Physical root mountpoint + /// Root of the OS tree (only `/` is currently supported) #[clap(value_parser)] sysroot: Option, } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 02212b56..6b505797 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -58,6 +58,23 @@ mod tests { bootupd::DCommand::command().debug_assert(); } + #[test] + fn backend_is_documented() { + use clap::CommandFactory; + let ctl = bootupctl::CtlCommand::command(); + let backend = ctl.find_subcommand("backend").unwrap(); + assert!(!backend.is_hide_set()); + assert!(backend.get_about().is_some()); + for verb in backend.get_subcommands() { + assert!(!verb.is_hide_set(), "{} is hidden", verb.get_name()); + assert!( + verb.get_about().is_some(), + "{} has no help", + verb.get_name() + ); + } + } + #[test] fn test_multicall_dispatch() { {