use crate::cmd; use clap::{value_parser, Arg, ArgMatches, Command}; use clap_mangen::Man; use std::{fs, io, path::PathBuf, process}; const programs: [&str; 8] = [ "shitbox", "bootstrap", "echo", "false", "head", "hostname", "true", "sleep", ]; #[must_use] pub fn cli() -> Command { Command::new("bootstrap") .version(env!("CARGO_PKG_VERSION")) .author("Nathan Fisher") .about("Install shitbox into the filesystem") .long_about("Install symlinks, manpages and shell completions") .args([ Arg::new("prefix") .help("The directory path under which to install") .short('p') .long("prefix") .num_args(1) .default_value("/") .required(false), Arg::new("usr") .help("Use /usr") .long_help( "Split the installation so that some applets go into /bin | /sbin\n\ while others are placed into /usr/bin | /usr/sbin", ) .short('u') .long("usr") .default_value("true") .value_parser(value_parser!(bool)), ]) .subcommands([ Command::new("all").about("Install everything"), Command::new("links") .about("Install links for each applet") .arg( Arg::new("soft") .help("Install soft links instead of hardlinks") .short('s') .long("soft"), ), Command::new("manpages") .about("Install Unix man pages") .alias("man"), Command::new("completions") .about("Install shell completions") .alias("comp") .args([ Arg::new("all") .help("Install completions for all supported shells") .short('a') .long("all"), Arg::new("bash") .help("Bash shell completions") .short('b') .long("bash"), Arg::new("fish") .help("Fish shell completions") .short('f') .long("fish"), Arg::new("nu") .help("Nushell completions") .short('n') .long("nu"), Arg::new("pwsh") .help("PowerShell completions") .short('p') .long("pwsh"), ]), ]) } fn manpage(prefix: &str, cmd: &str) -> Result<(), io::Error> { let (fname, cmd) = match cmd { "shitbox" => ("shitbox.1", crate::cli::cli()), "bootstrap" => ("shitbox-bootstrap.1", cli()), "echo" => ("echo.1", cmd::echo::cli()), "false" => ("false.1", cmd::r#false::cli()), "head" => ("head.1", cmd::head::cli()), "hostname" => ("hostname.1", cmd::hostname::cli()), "true" => ("true.1", cmd::r#true::cli()), "sleep" => ("sleep.1", cmd::sleep::cli()), _ => unimplemented!(), }; let outdir: PathBuf = [prefix, "usr", "share", "man", "man1"].iter().collect(); if !outdir.exists() { fs::create_dir_all(&outdir)?; } let mut outfile = outdir; outfile.push(fname); let man = Man::new(cmd); let mut buffer: Vec = vec![]; man.render(&mut buffer)?; fs::write(&outfile, buffer)?; println!(" {}", outfile.display()); Ok(()) } fn manpages(prefix: &str) -> Result<(), io::Error> { println!("Generating Unix man pages:"); programs.iter().try_for_each(|cmd| manpage(prefix, cmd))?; Ok(()) } pub fn run(matches: &ArgMatches) { if let Some(prefix) = matches.get_one::("prefix") { match matches.subcommand() { Some(("manpages", _matches)) => { if let Err(e) = manpages(&prefix) { eprintln!("{e}"); process::exit(1); } } _ => {} } } }