meli/args: add --gzipped flag to man subcommand
Add --gzipped flag to print a manpage without decompressing it, for piping the output to a file. Because why not. Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
This commit is contained in:
parent
738f7c4695
commit
814af0e94d
3 changed files with 104 additions and 22 deletions
|
@ -91,17 +91,18 @@ pub enum SubCommand {
|
|||
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub struct ManOpt {
|
||||
/// If set, output text in stdout instead of spawning `$PAGER`.
|
||||
#[cfg(feature = "cli-docs")]
|
||||
#[cfg_attr(feature = "cli-docs", structopt(long = "no-raw", alias = "no-raw"))]
|
||||
pub no_raw: bool,
|
||||
/// If set, output compressed gzip manpage in binary form in stdout.
|
||||
#[cfg(feature = "cli-docs")]
|
||||
#[cfg_attr(feature = "cli-docs", structopt(long = "gzipped"))]
|
||||
pub gzipped: bool,
|
||||
#[cfg(feature = "cli-docs")]
|
||||
#[cfg_attr(feature = "cli-docs", structopt(default_value = "meli", possible_values=manpages::POSSIBLE_VALUES, value_name="PAGE", parse(try_from_str = manpages::parse_manpage)))]
|
||||
/// Name of manual page.
|
||||
pub page: manpages::ManPages,
|
||||
/// If true, output text in stdout instead of spawning `$PAGER`.
|
||||
#[cfg(feature = "cli-docs")]
|
||||
#[cfg_attr(
|
||||
feature = "cli-docs",
|
||||
structopt(long = "no-raw", alias = "no-raw", value_name = "bool")
|
||||
)]
|
||||
pub no_raw: Option<Option<bool>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
|
@ -161,6 +162,22 @@ impl Opt {
|
|||
SubCommand::Man(ManOpt {
|
||||
page,
|
||||
no_raw,
|
||||
gzipped: true,
|
||||
}) => {
|
||||
use std::io::Write;
|
||||
|
||||
ret_err!(std::io::stdout().write_all(if no_raw {
|
||||
page.text_gz()
|
||||
} else {
|
||||
page.mdoc_gz()
|
||||
}));
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "cli-docs")]
|
||||
SubCommand::Man(ManOpt {
|
||||
page,
|
||||
no_raw,
|
||||
gzipped: false,
|
||||
}) => {
|
||||
subcommands::man(page, false).and_then(|s| subcommands::pager(s, no_raw))
|
||||
}
|
||||
|
|
|
@ -84,6 +84,19 @@ impl std::fmt::Display for ManPages {
|
|||
}
|
||||
|
||||
impl ManPages {
|
||||
const MANPAGES: [&'static [u8]; 4] = [
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.conf.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli-themes.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.7.txt.gz")),
|
||||
];
|
||||
const MANPAGES_MDOC: [&'static [u8]; 4] = [
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.mdoc.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.conf.mdoc.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli-themes.mdoc.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.7.mdoc.gz")),
|
||||
];
|
||||
|
||||
pub fn install(destination: Option<PathBuf>) -> Result<PathBuf> {
|
||||
fn path_valid(p: &Path, tries: &mut Vec<PathBuf>) -> bool {
|
||||
tries.push(p.into());
|
||||
|
@ -145,24 +158,19 @@ impl ManPages {
|
|||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn read(self, source: bool) -> Result<String> {
|
||||
const MANPAGES: [&[u8]; 4] = [
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.conf.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli-themes.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.7.txt.gz")),
|
||||
];
|
||||
const MANPAGES_MDOC: [&[u8]; 4] = [
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.mdoc.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.conf.mdoc.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli-themes.mdoc.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.7.mdoc.gz")),
|
||||
];
|
||||
pub fn mdoc_gz(self) -> &'static [u8] {
|
||||
Self::MANPAGES_MDOC[self as usize]
|
||||
}
|
||||
|
||||
pub fn text_gz(self) -> &'static [u8] {
|
||||
Self::MANPAGES[self as usize]
|
||||
}
|
||||
|
||||
pub fn read(self, source: bool) -> Result<String> {
|
||||
let mut gz = GzDecoder::new(if source {
|
||||
MANPAGES_MDOC[self as usize]
|
||||
self.mdoc_gz()
|
||||
} else {
|
||||
MANPAGES[self as usize]
|
||||
self.text_gz()
|
||||
});
|
||||
let mut v = String::with_capacity(
|
||||
str::parse::<usize>(unsafe {
|
||||
|
|
|
@ -114,11 +114,68 @@ fn test_cli_subcommands() {
|
|||
}
|
||||
}
|
||||
|
||||
fn test_subcommand_man() {
|
||||
for (man, title) in [
|
||||
("meli.1", "MELI(1)"),
|
||||
("meli.conf.5", "MELI.CONF(5)"),
|
||||
("meli-themes.5", "MELI-THEMES(5)"),
|
||||
("meli.7", "MELI(7)"),
|
||||
] {
|
||||
for gzipped in [true, false] {
|
||||
for no_raw in [true, false] {
|
||||
let mut cmd = Command::cargo_bin("meli").unwrap();
|
||||
let args = match (no_raw, gzipped) {
|
||||
(true, true) => &["man", "--no-raw", "--gzipped", man][..],
|
||||
(true, false) => &["man", "--no-raw", man],
|
||||
(false, false) => &["man", man],
|
||||
(false, true) => &["man", "--gzipped", man],
|
||||
};
|
||||
let output = cmd.args(args).output().unwrap().assert();
|
||||
output.code(0).stdout(predicate::function(|x: &[u8]| {
|
||||
use std::io::Read;
|
||||
|
||||
use flate2::bufread::GzDecoder;
|
||||
|
||||
let mut gz = GzDecoder::new(x);
|
||||
let content = if gzipped {
|
||||
let size = gz.header().unwrap().comment().unwrap();
|
||||
|
||||
let mut v = String::with_capacity(
|
||||
str::parse::<usize>(
|
||||
std::str::from_utf8(size)
|
||||
.expect("was not compressed with size comment header"),
|
||||
)
|
||||
.expect("was not compressed with size comment header"),
|
||||
);
|
||||
gz.read_to_string(&mut v)
|
||||
.expect("expected gzipped output but could not decode it.");
|
||||
v
|
||||
} else {
|
||||
assert_eq!(gz.header(), None);
|
||||
let mut v = String::with_capacity(0);
|
||||
gz.read_to_string(&mut v).unwrap_err();
|
||||
String::from_utf8(x.to_vec()).expect("invalid utf-8 content")
|
||||
};
|
||||
if !no_raw && gzipped {
|
||||
assert!(content.contains(man));
|
||||
} else {
|
||||
assert!(content.contains('\u{8}'));
|
||||
assert!(content.contains(title));
|
||||
}
|
||||
|
||||
true
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
version();
|
||||
help();
|
||||
test_subcommand_succeeds("help");
|
||||
test_subcommand_succeeds("compiled-with");
|
||||
test_subcommand_succeeds("man");
|
||||
test_subcommand_man();
|
||||
|
||||
let tmp_dir = TempDir::new().unwrap();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue