this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(cli): generate shell completions and man page

Add hidden `cmprss completions <shell>` and `cmprss manpage`
subcommands that emit to stdout. Packagers can pipe the output into
standard system locations during install:

cmprss completions bash > /usr/share/bash-completion/completions/cmprss
cmprss completions zsh > /usr/share/zsh/site-functions/_cmprss
cmprss manpage > /usr/share/man/man1/cmprss.1

Built on clap_complete and clap_mangen so the output tracks the real
clap derive — no hand-maintained scripts to drift.

+117 -6
+27
Cargo.lock
··· 270 270 ] 271 271 272 272 [[package]] 273 + name = "clap_complete" 274 + version = "4.6.2" 275 + source = "registry+https://github.com/rust-lang/crates.io-index" 276 + checksum = "3ff7a1dccbdd8b078c2bdebff47e404615151534d5043da397ec50286816f9cb" 277 + dependencies = [ 278 + "clap", 279 + ] 280 + 281 + [[package]] 273 282 name = "clap_derive" 274 283 version = "4.6.0" 275 284 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 288 297 checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" 289 298 290 299 [[package]] 300 + name = "clap_mangen" 301 + version = "0.2.33" 302 + source = "registry+https://github.com/rust-lang/crates.io-index" 303 + checksum = "7e30ffc187e2e3aeafcd1c6e2aa416e29739454c0ccaa419226d5ecd181f2d78" 304 + dependencies = [ 305 + "clap", 306 + "roff", 307 + ] 308 + 309 + [[package]] 291 310 name = "cmprss" 292 311 version = "0.3.0" 293 312 dependencies = [ ··· 297 316 "brotli", 298 317 "bzip2", 299 318 "clap", 319 + "clap_complete", 320 + "clap_mangen", 300 321 "flate2", 301 322 "indicatif", 302 323 "is-terminal", ··· 987 1008 version = "0.8.10" 988 1009 source = "registry+https://github.com/rust-lang/crates.io-index" 989 1010 checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" 1011 + 1012 + [[package]] 1013 + name = "roff" 1014 + version = "1.1.1" 1015 + source = "registry+https://github.com/rust-lang/crates.io-index" 1016 + checksum = "323c417e1d9665a65b263ec744ba09030cfb277e9daa0b018a4ab62e57bc8189" 990 1017 991 1018 [[package]] 992 1019 name = "rustix"
+6 -4
Cargo.toml
··· 12 12 13 13 [dependencies] 14 14 anyhow = "1" 15 + brotli = "8" 15 16 bzip2 = { version = "0.6", features = ["static"] } 16 17 clap = { version = "4", features = ["derive"] } 18 + clap_complete = "4" 19 + clap_mangen = "0.2" 17 20 flate2 = "1" 18 21 indicatif = "0.18" 19 22 is-terminal = "0.4" 23 + lz4_flex = "0.13" 24 + snap = "1" 20 25 tar = "0.4" 26 + tempfile = "3" 21 27 xz2 = { version = "0.1", features = ["static"] } 22 28 zip = "8" 23 - tempfile = "3" 24 29 zstd = "0.13" 25 - lz4_flex = "0.13" 26 - brotli = "8" 27 - snap = "1" 28 30 29 31 [dev-dependencies] 30 32 assert_cmd = "2"
+29 -2
src/main.rs
··· 5 5 pub mod utils; 6 6 7 7 use backends::*; 8 - use clap::{Parser, Subcommand}; 8 + use clap::{CommandFactory, Parser, Subcommand}; 9 + use clap_complete::Shell; 9 10 use job::{Action, get_job}; 10 11 use utils::*; 11 12 ··· 58 59 59 60 /// lzma (legacy LZMA1) compression 60 61 Lzma(LzmaArgs), 62 + 63 + /// Print a shell completion script to stdout. 64 + #[clap(hide = true)] 65 + Completions { 66 + /// Shell to generate completions for. 67 + #[arg(value_enum)] 68 + shell: Shell, 69 + }, 70 + 71 + /// Print the cmprss(1) man page (in troff format) to stdout. 72 + #[clap(hide = true)] 73 + Manpage, 74 + } 75 + 76 + fn write_completions(shell: Shell) -> Result { 77 + let mut cmd = CmprssArgs::command(); 78 + clap_complete::generate(shell, &mut cmd, "cmprss", &mut std::io::stdout()); 79 + Ok(()) 80 + } 81 + 82 + fn write_manpage() -> Result { 83 + let cmd = CmprssArgs::command(); 84 + clap_mangen::Man::new(cmd).render(&mut std::io::stdout())?; 85 + Ok(()) 61 86 } 62 87 63 88 fn command(compressor: Option<Box<dyn Compressor>>, args: &CommonArgs) -> Result { ··· 81 106 Some(Format::Brotli(a)) => command(Some(Box::new(Brotli::new(&a))), &a.common_args), 82 107 Some(Format::Snappy(a)) => command(Some(Box::new(Snappy::new(&a))), &a.common_args), 83 108 Some(Format::Lzma(a)) => command(Some(Box::new(Lzma::new(&a))), &a.common_args), 84 - _ => command(None, &args.base_args), 109 + Some(Format::Completions { shell }) => write_completions(shell), 110 + Some(Format::Manpage) => write_manpage(), 111 + None => command(None, &args.base_args), 85 112 } 86 113 .unwrap_or_else(|e| { 87 114 eprintln!("ERROR(cmprss): {}", e);
+55
tests/meta.rs
··· 1 + use assert_cmd::prelude::*; 2 + use predicates::prelude::*; 3 + use std::process::Command; 4 + 5 + mod common; 6 + 7 + /// The hidden `completions` / `manpage` subcommands are integration-tested by 8 + /// shape, not content: each must succeed and emit non-empty stdout so that 9 + /// packagers can pipe the output into a file during install. 10 + mod meta { 11 + use super::*; 12 + 13 + #[test] 14 + fn completions_bash() -> Result<(), Box<dyn std::error::Error>> { 15 + let mut cmd = Command::cargo_bin("cmprss")?; 16 + cmd.args(["completions", "bash"]); 17 + cmd.assert() 18 + .success() 19 + .stdout(predicate::str::contains("_cmprss")); 20 + Ok(()) 21 + } 22 + 23 + #[test] 24 + fn completions_zsh() -> Result<(), Box<dyn std::error::Error>> { 25 + let mut cmd = Command::cargo_bin("cmprss")?; 26 + cmd.args(["completions", "zsh"]); 27 + cmd.assert() 28 + .success() 29 + .stdout(predicate::str::contains("#compdef cmprss")); 30 + Ok(()) 31 + } 32 + 33 + #[test] 34 + fn manpage_emits_troff() -> Result<(), Box<dyn std::error::Error>> { 35 + let mut cmd = Command::cargo_bin("cmprss")?; 36 + cmd.arg("manpage"); 37 + cmd.assert() 38 + .success() 39 + .stdout(predicate::str::contains(".TH cmprss 1")) 40 + .stdout(predicate::str::contains(".SH NAME")); 41 + Ok(()) 42 + } 43 + 44 + /// `cmprss --help` must not advertise the hidden meta subcommands. 45 + #[test] 46 + fn meta_subcommands_hidden_from_help() -> Result<(), Box<dyn std::error::Error>> { 47 + let mut cmd = Command::cargo_bin("cmprss")?; 48 + cmd.arg("--help"); 49 + cmd.assert() 50 + .success() 51 + .stdout(predicate::str::contains("completions").not()) 52 + .stdout(predicate::str::contains("manpage").not()); 53 + Ok(()) 54 + } 55 + }