@@ -12,6 +12,7 @@ use anyhow::{anyhow, ensure, Context, Result};
1212use camino:: { Utf8Path , Utf8PathBuf } ;
1313use cap_std_ext:: cap_std;
1414use cap_std_ext:: cap_std:: fs:: Dir ;
15+ use clap:: CommandFactory ;
1516use clap:: Parser ;
1617use clap:: ValueEnum ;
1718use composefs:: dumpfile;
@@ -745,6 +746,15 @@ pub(crate) enum Opt {
745746 /// Diff current /etc configuration versus default
746747 #[ clap( hide = true ) ]
747748 ConfigDiff ,
749+ /// Generate shell completion script for supported shells.
750+ ///
751+ /// Example: `bootc completion bash` prints a bash completion script to stdout.
752+ #[ clap( hide = true ) ]
753+ Completion {
754+ /// Shell type to generate (bash, zsh, fish)
755+ #[ clap( value_enum) ]
756+ shell : clap_complete:: aot:: Shell ,
757+ } ,
748758 #[ clap( hide = true ) ]
749759 DeleteDeployment {
750760 depl_id : String ,
@@ -1582,6 +1592,15 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
15821592 Ok ( ( ) )
15831593 }
15841594 } ,
1595+ Opt :: Completion { shell } => {
1596+ use clap_complete:: aot:: generate;
1597+
1598+ let mut cmd = Opt :: command ( ) ;
1599+ let mut stdout = std:: io:: stdout ( ) ;
1600+ let bin_name = "bootc" ;
1601+ generate ( shell, & mut cmd, bin_name, & mut stdout) ;
1602+ Ok ( ( ) )
1603+ }
15851604 Opt :: Image ( opts) => match opts {
15861605 ImageOpts :: List {
15871606 list_type,
@@ -2012,4 +2031,29 @@ mod tests {
20122031 ] ) ) ;
20132032 assert_eq ! ( args. as_slice( ) , [ "container" , "image" , "pull" ] ) ;
20142033 }
2034+
2035+ #[ test]
2036+ fn test_generate_completion_scripts_contain_commands ( ) {
2037+ use clap_complete:: aot:: { generate, Shell } ;
2038+
2039+ // For each supported shell, generate the completion script and
2040+ // ensure obvious subcommands appear in the output. This mirrors
2041+ // the style of completion checks used in other projects (e.g.
2042+ // podman) where the generated script is examined for expected
2043+ // tokens.
2044+
2045+ // `completion` is intentionally hidden from --help / suggestions;
2046+ // ensure other visible subcommands are present instead.
2047+ let want = [ "install" , "upgrade" ] ;
2048+
2049+ for shell in [ Shell :: Bash , Shell :: Zsh , Shell :: Fish ] {
2050+ let mut cmd = Opt :: command ( ) ;
2051+ let mut buf = Vec :: new ( ) ;
2052+ generate ( shell, & mut cmd, "bootc" , & mut buf) ;
2053+ let s = String :: from_utf8 ( buf) . expect ( "completion should be utf8" ) ;
2054+ for w in & want {
2055+ assert ! ( s. contains( w) , "{shell:?} completion missing {w}" ) ;
2056+ }
2057+ }
2058+ }
20152059}
0 commit comments