Move the Rust and Clippy linting options into the Cargo manifest and share them with all the packages in the workspace. This ensures a consistent style in all packages.
165 lines
5.6 KiB
Rust
165 lines
5.6 KiB
Rust
use std::path::PathBuf;
|
|
use std::{env, fs};
|
|
|
|
use clap::builder::PathBufValueParser;
|
|
use clap::error::{Error, ErrorKind};
|
|
use clap::ArgMatches;
|
|
use clap_complete::Shell;
|
|
use ncspot::{AUTHOR, BIN_NAME};
|
|
|
|
static DEFAULT_OUTPUT_DIRECTORY: &str = "misc";
|
|
|
|
enum XTaskSubcommand {
|
|
GenerateManpage,
|
|
GenerateShellCompletion,
|
|
}
|
|
|
|
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(Self::GenerateManpage),
|
|
"generate-shell-completion" => Ok(Self::GenerateShellCompletion),
|
|
_ => 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 workflow. Xtask's are defined as a separate package and can be used for all kinds of
|
|
automation.",
|
|
)
|
|
.subcommands([
|
|
clap::Command::new("generate-manpage")
|
|
.visible_alias("gm")
|
|
.args([clap::Arg::new("output")
|
|
.short('o')
|
|
.long("output")
|
|
.value_name("PATH")
|
|
.default_value("misc")
|
|
.help("Output directory for the generated man page.")
|
|
.value_parser(PathBufValueParser::new())])
|
|
.about("Automatic man page generation."),
|
|
clap::Command::new("generate-shell-completion")
|
|
.visible_alias("gsc")
|
|
.args([
|
|
clap::Arg::new("shells")
|
|
.short('s')
|
|
.long("shells")
|
|
.value_name("SHELLS")
|
|
.default_values(["bash", "zsh", "fish"])
|
|
.value_delimiter(',')
|
|
.help("The shells for which completion should be generated."),
|
|
clap::Arg::new("output")
|
|
.short('o')
|
|
.long("output")
|
|
.value_name("PATH")
|
|
.default_value("misc")
|
|
.help("Output directory for the generated completion script.")
|
|
.value_parser(PathBufValueParser::new()),
|
|
])
|
|
.about("Automatic shell completion generation.")
|
|
.long_about(
|
|
"
|
|
Automatic shell completion generation.
|
|
Supported shells: bash,zsh,fish,elvish,powershell",
|
|
),
|
|
]);
|
|
|
|
let program_parsed_arguments = arguments_model.get_matches();
|
|
|
|
let parsed_subcommand = XTaskSubcommand::try_from(&program_parsed_arguments)?;
|
|
|
|
let subcommand_parsed_arguments = program_parsed_arguments.subcommand().unwrap().1;
|
|
|
|
match parsed_subcommand {
|
|
XTaskSubcommand::GenerateManpage => generate_manpage(subcommand_parsed_arguments),
|
|
XTaskSubcommand::GenerateShellCompletion => {
|
|
generate_shell_completion(subcommand_parsed_arguments)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn generate_manpage(subcommand_arguments: &ArgMatches) -> Result<(), DynError> {
|
|
let default_output_directory = PathBuf::from(DEFAULT_OUTPUT_DIRECTORY);
|
|
let output_directory = subcommand_arguments
|
|
.get_one::<PathBuf>("output")
|
|
.unwrap_or(&default_output_directory);
|
|
let cmd = ncspot::program_arguments();
|
|
let man = clap_mangen::Man::new(cmd);
|
|
let mut buffer: Vec<u8> = Default::default();
|
|
|
|
if *output_directory == default_output_directory {
|
|
fs::create_dir_all(DEFAULT_OUTPUT_DIRECTORY)?;
|
|
}
|
|
|
|
man.render(&mut buffer)?;
|
|
std::fs::write(output_directory.join("ncspot.1"), buffer)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn generate_shell_completion(subcommand_arguments: &ArgMatches) -> Result<(), DynError> {
|
|
let default_output_directory = PathBuf::from(DEFAULT_OUTPUT_DIRECTORY);
|
|
let output_directory = subcommand_arguments
|
|
.get_one::<PathBuf>("output")
|
|
.unwrap_or(&default_output_directory);
|
|
let shells = subcommand_arguments
|
|
.get_many::<String>("shells")
|
|
.map(|shells| {
|
|
shells
|
|
.map(|shell| match shell.as_str() {
|
|
"bash" => Shell::Bash,
|
|
"zsh" => Shell::Zsh,
|
|
"fish" => Shell::Fish,
|
|
"elvish" => Shell::Elvish,
|
|
"powershell" => Shell::PowerShell,
|
|
_ => {
|
|
eprintln!("Unrecognized shell: {}", shell);
|
|
std::process::exit(-1);
|
|
}
|
|
})
|
|
.collect()
|
|
})
|
|
.unwrap_or(vec![Shell::Bash, Shell::Zsh, Shell::Fish]);
|
|
|
|
if *output_directory == default_output_directory {
|
|
fs::create_dir_all(DEFAULT_OUTPUT_DIRECTORY)?;
|
|
}
|
|
|
|
for shell in shells {
|
|
clap_complete::generate_to(
|
|
shell,
|
|
&mut ncspot::program_arguments(),
|
|
BIN_NAME,
|
|
output_directory,
|
|
)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|