Add manpage generation using xtask

* Add manpage generation.

* Hide xtask compilation info.
This changes the default behavior of the `cargo run` command for xtasks
to hide the compilation info. This makes sense as xtask's are run as a
program, and showing the compilation info every time clutters stdout
with unrelated info.

* Move ncspot's `clap::Command` to `lib.rs`.
Moving the `clap::Command` used internally by ncspot to a library allows
it to be easily shared between different packages (xtask and ncspot
itself).

This commit also reworks the xtasks to use clap for parsing the xtask
arguments, which simplifies writing new xtasks.

* Make `generate-manpage` `--output` optional.
When more xtasks get added, it would make sense to have a `generate-all`
subcommand that executes all xtasks, which wouldn't be able to have
options for every separate subcommand. Therefore the `output` argument
should be optional, and by default output to the `misc` directory which
contains extra metadata files already.

* Add packaging info to `README.md`.
Update the README to include information for packagers. The information
includes provided files as well as info on how to generate some of them.
This commit is contained in:
Thomas Frans
2023-03-06 21:55:19 +01:00
committed by GitHub
parent 7d1a9d2e80
commit b27e84a386
9 changed files with 194 additions and 35 deletions

13
xtask/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"
[dependencies]
clap_mangen = "0.2.8"
clap = "4.1.6"
[dependencies.ncspot]
path = ".."

92
xtask/src/main.rs Normal file
View File

@@ -0,0 +1,92 @@
use std::path::PathBuf;
use std::{env, fs};
use clap::builder::PathBufValueParser;
use clap::error::{Error, ErrorKind};
use clap::ArgMatches;
use ncspot::AUTHOR;
enum XTaskSubcommand {
GenerateManpage,
}
impl TryFrom<&ArgMatches> for XTaskSubcommand {
type Error = clap::Error;
fn try_from(value: &ArgMatches) -> Result<Self, Self::Error> {
if let Some(subcommand) = value.subcommand() {
match subcommand.0 {
"generate-manpage" => Ok(XTaskSubcommand::GenerateManpage),
_ => Err(Error::new(clap::error::ErrorKind::InvalidSubcommand)),
}
} else {
Err(Error::new(ErrorKind::MissingSubcommand))
}
}
}
type DynError = Box<dyn std::error::Error>;
fn main() {
if let Err(e) = try_main() {
eprintln!("{}", e);
std::process::exit(-1);
}
}
fn try_main() -> Result<(), DynError> {
let arguments_model = clap::Command::new("cargo xtask")
.version(env!("CARGO_PKG_VERSION"))
.author(AUTHOR)
.about("Automation using the cargo xtask convention.")
.arg_required_else_help(true)
.bin_name("cargo xtask")
.disable_version_flag(true)
.long_about(
"
Cargo xtask is a convention that allows easy integration of third party commands into the regular
cargo workflox. Xtask's are defined as a separate package and can be used for all kinds of
automation.
",
)
.subcommand(
clap::Command::new("generate-manpage")
.visible_alias("gm")
.args([clap::Arg::new("output")
.short('o')
.long("output")
.value_name("PATH")
.help("Output directory for the generated man page.")
.value_parser(PathBufValueParser::new())])
.about("Automatic man page generation."),
);
let program_parsed_arguments = arguments_model.get_matches();
let parsed_subcommand = XTaskSubcommand::try_from(&program_parsed_arguments)?;
match parsed_subcommand {
XTaskSubcommand::GenerateManpage => {
generate_manpage(program_parsed_arguments.subcommand().unwrap().1)
}
}
}
fn generate_manpage(subcommand_arguments: &ArgMatches) -> Result<(), DynError> {
let output_directory =
if let Some(output_argument) = subcommand_arguments.get_one::<PathBuf>("output") {
output_argument.clone()
} else {
fs::create_dir_all("misc")?;
PathBuf::from("misc")
};
let cmd = ncspot::program_arguments();
let man = clap_mangen::Man::new(cmd);
let mut buffer: Vec<u8> = Default::default();
man.render(&mut buffer)?;
std::fs::write(output_directory.join("ncspot.1"), buffer)?;
Ok(())
}