@@ -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;
@@ -733,6 +734,15 @@ pub(crate) enum Opt {
733734 /// Diff current /etc configuration versus default
734735 #[ clap( hide = true ) ]
735736 ConfigDiff ,
737+ /// Generate shell completion script for supported shells.
738+ ///
739+ /// Example: `bootc completion bash` prints a bash completion script to stdout.
740+ #[ clap( hide = true ) ]
741+ Completion {
742+ /// Shell type to generate (bash, zsh, fish)
743+ #[ clap( value_enum) ]
744+ shell : clap_complete:: aot:: Shell ,
745+ } ,
736746 #[ clap( hide = true ) ]
737747 DeleteDeployment {
738748 depl_id : String ,
@@ -1573,6 +1583,15 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
15731583 Ok ( ( ) )
15741584 }
15751585 } ,
1586+ Opt :: Completion { shell } => {
1587+ use clap_complete:: aot:: generate;
1588+
1589+ let mut cmd = Opt :: command ( ) ;
1590+ let mut stdout = std:: io:: stdout ( ) ;
1591+ let bin_name = "bootc" ;
1592+ generate ( shell, & mut cmd, bin_name, & mut stdout) ;
1593+ Ok ( ( ) )
1594+ }
15761595 Opt :: Image ( opts) => match opts {
15771596 ImageOpts :: List {
15781597 list_type,
@@ -1978,4 +1997,29 @@ mod tests {
19781997 ] ) ) ;
19791998 assert_eq ! ( args. as_slice( ) , [ "container" , "image" , "pull" ] ) ;
19801999 }
2000+
2001+ #[ test]
2002+ fn test_generate_completion_scripts_contain_commands ( ) {
2003+ use clap_complete:: aot:: { generate, Shell } ;
2004+
2005+ // For each supported shell, generate the completion script and
2006+ // ensure obvious subcommands appear in the output. This mirrors
2007+ // the style of completion checks used in other projects (e.g.
2008+ // podman) where the generated script is examined for expected
2009+ // tokens.
2010+
2011+ // `completion` is intentionally hidden from --help / suggestions;
2012+ // ensure other visible subcommands are present instead.
2013+ let want = [ "install" , "upgrade" ] ;
2014+
2015+ for shell in [ Shell :: Bash , Shell :: Zsh , Shell :: Fish ] {
2016+ let mut cmd = Opt :: command ( ) ;
2017+ let mut buf = Vec :: new ( ) ;
2018+ generate ( shell, & mut cmd, "bootc" , & mut buf) ;
2019+ let s = String :: from_utf8 ( buf) . expect ( "completion should be utf8" ) ;
2020+ for w in & want {
2021+ assert ! ( s. contains( w) , "{shell:?} completion missing {w}" ) ;
2022+ }
2023+ }
2024+ }
19812025}
0 commit comments