1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00

cli: Add shell completion generation command

- Add completion subcommand supporting bash, zsh, and fish

Assisted-by: Cursor (Auto)
Signed-off-by: Shion Tanaka <shtanaka@redhat.com>
This commit is contained in:
Shion Tanaka
2026-01-09 06:12:09 +09:00
committed by Colin Walters
parent 0ee11dbfe2
commit d2eb1b69e2
3 changed files with 55 additions and 0 deletions

10
Cargo.lock generated
View File

@@ -239,6 +239,7 @@ dependencies = [
"cfg-if",
"chrono",
"clap",
"clap_complete",
"clap_mangen",
"comfy-table",
"composefs",
@@ -508,6 +509,15 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39615915e2ece2550c0149addac32fb5bd312c657f43845bb9088cb9c8a7c992"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.49"

View File

@@ -33,6 +33,7 @@ cap-std-ext = { workspace = true, features = ["fs_utf8"] }
cfg-if = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
clap = { workspace = true, features = ["derive","cargo"] }
clap_complete = "4"
clap_mangen = { workspace = true, optional = true }
composefs = { workspace = true }
composefs-boot = { workspace = true }

View File

@@ -12,6 +12,7 @@ use anyhow::{anyhow, ensure, Context, Result};
use camino::{Utf8Path, Utf8PathBuf};
use cap_std_ext::cap_std;
use cap_std_ext::cap_std::fs::Dir;
use clap::CommandFactory;
use clap::Parser;
use clap::ValueEnum;
use composefs::dumpfile;
@@ -745,6 +746,15 @@ pub(crate) enum Opt {
/// Diff current /etc configuration versus default
#[clap(hide = true)]
ConfigDiff,
/// Generate shell completion script for supported shells.
///
/// Example: `bootc completion bash` prints a bash completion script to stdout.
#[clap(hide = true)]
Completion {
/// Shell type to generate (bash, zsh, fish)
#[clap(value_enum)]
shell: clap_complete::aot::Shell,
},
#[clap(hide = true)]
DeleteDeployment {
depl_id: String,
@@ -1582,6 +1592,15 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
Ok(())
}
},
Opt::Completion { shell } => {
use clap_complete::aot::generate;
let mut cmd = Opt::command();
let mut stdout = std::io::stdout();
let bin_name = "bootc";
generate(shell, &mut cmd, bin_name, &mut stdout);
Ok(())
}
Opt::Image(opts) => match opts {
ImageOpts::List {
list_type,
@@ -2012,4 +2031,29 @@ mod tests {
]));
assert_eq!(args.as_slice(), ["container", "image", "pull"]);
}
#[test]
fn test_generate_completion_scripts_contain_commands() {
use clap_complete::aot::{generate, Shell};
// For each supported shell, generate the completion script and
// ensure obvious subcommands appear in the output. This mirrors
// the style of completion checks used in other projects (e.g.
// podman) where the generated script is examined for expected
// tokens.
// `completion` is intentionally hidden from --help / suggestions;
// ensure other visible subcommands are present instead.
let want = ["install", "upgrade"];
for shell in [Shell::Bash, Shell::Zsh, Shell::Fish] {
let mut cmd = Opt::command();
let mut buf = Vec::new();
generate(shell, &mut cmd, "bootc", &mut buf);
let s = String::from_utf8(buf).expect("completion should be utf8");
for w in &want {
assert!(s.contains(w), "{shell:?} completion missing {w}");
}
}
}
}