Cleanups including creating a static list of commands
This commit is contained in:
parent
815a98be4d
commit
48d42e7b3c
@ -1,15 +1,15 @@
|
||||
use super::{Cmd, ECHO, FALSE, HEAD, HOSTNAME, SHITBOX, SLEEP, TRUE, NOLOGIN};
|
||||
use super::{Cmd, Commands};
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use clap_complete::{generate_to, shells, Generator};
|
||||
use clap_complete::shells;
|
||||
use clap_complete_nushell::Nushell;
|
||||
use clap_mangen::Man;
|
||||
use std::{
|
||||
error::Error,
|
||||
fs,
|
||||
io::{self, ErrorKind},
|
||||
path::{Path, PathBuf},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Bootstrap {
|
||||
name: &'static str,
|
||||
path: Option<crate::Path>,
|
||||
@ -20,6 +20,104 @@ pub const BOOTSTRAP: Bootstrap = Bootstrap {
|
||||
path: None,
|
||||
};
|
||||
|
||||
impl Bootstrap {
|
||||
fn all() -> clap::Command {
|
||||
Command::new("all").about("Install everything").args([
|
||||
Arg::new("soft")
|
||||
.help("Install soft links instead of hardlinks")
|
||||
.short('s')
|
||||
.long("soft")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("all")
|
||||
.help("Install completions for all supported shells")
|
||||
.short('a')
|
||||
.long("all")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("bash")
|
||||
.help("Bash shell completions")
|
||||
.short('b')
|
||||
.long("bash")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("fish")
|
||||
.help("Fish shell completions")
|
||||
.short('f')
|
||||
.long("fish")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("nu")
|
||||
.help("Nushell completions")
|
||||
.short('n')
|
||||
.long("nu")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("pwsh")
|
||||
.help("PowerShell completions")
|
||||
.short('p')
|
||||
.long("pwsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("zsh")
|
||||
.help("Zshell completions")
|
||||
.short('z')
|
||||
.long("zsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
])
|
||||
}
|
||||
|
||||
fn links() -> clap::Command {
|
||||
Command::new("links")
|
||||
.about("Install links for each applet")
|
||||
.arg(
|
||||
Arg::new("soft")
|
||||
.help("Install soft links instead of hardlinks")
|
||||
.short('s')
|
||||
.long("soft")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
||||
fn manpages() -> clap::Command {
|
||||
Command::new("manpages")
|
||||
.about("Install Unix man pages")
|
||||
.alias("man")
|
||||
}
|
||||
|
||||
fn completions() -> clap::Command {
|
||||
Command::new("completions")
|
||||
.about("Install shell completions")
|
||||
.alias("comp")
|
||||
.args([
|
||||
Arg::new("all")
|
||||
.help("Install completions for all supported shells")
|
||||
.short('a')
|
||||
.long("all")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("bash")
|
||||
.help("Bash shell completions")
|
||||
.short('b')
|
||||
.long("bash")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("fish")
|
||||
.help("Fish shell completions")
|
||||
.short('f')
|
||||
.long("fish")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("nu")
|
||||
.help("Nushell completions")
|
||||
.short('n')
|
||||
.long("nu")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("pwsh")
|
||||
.help("PowerShell completions")
|
||||
.short('p')
|
||||
.long("pwsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("zsh")
|
||||
.help("Zshell completions")
|
||||
.short('z')
|
||||
.long("zsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl Cmd for Bootstrap {
|
||||
fn name(&self) -> &str {
|
||||
self.name
|
||||
@ -55,91 +153,10 @@ impl Cmd for Bootstrap {
|
||||
.action(ArgAction::SetTrue),
|
||||
])
|
||||
.subcommands([
|
||||
Command::new("all").about("Install everything")
|
||||
.args([
|
||||
Arg::new("soft")
|
||||
.help("Install soft links instead of hardlinks")
|
||||
.short('s')
|
||||
.long("soft")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("all")
|
||||
.help("Install completions for all supported shells")
|
||||
.short('a')
|
||||
.long("all")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("bash")
|
||||
.help("Bash shell completions")
|
||||
.short('b')
|
||||
.long("bash")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("fish")
|
||||
.help("Fish shell completions")
|
||||
.short('f')
|
||||
.long("fish")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("nu")
|
||||
.help("Nushell completions")
|
||||
.short('n')
|
||||
.long("nu")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("pwsh")
|
||||
.help("PowerShell completions")
|
||||
.short('p')
|
||||
.long("pwsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("zsh")
|
||||
.help("Zshell completions")
|
||||
.short('z')
|
||||
.long("zsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
]),
|
||||
Command::new("links")
|
||||
.about("Install links for each applet")
|
||||
.arg(
|
||||
Arg::new("soft")
|
||||
.help("Install soft links instead of hardlinks")
|
||||
.short('s')
|
||||
.long("soft")
|
||||
.action(ArgAction::SetTrue),
|
||||
),
|
||||
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")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("bash")
|
||||
.help("Bash shell completions")
|
||||
.short('b')
|
||||
.long("bash")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("fish")
|
||||
.help("Fish shell completions")
|
||||
.short('f')
|
||||
.long("fish")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("nu")
|
||||
.help("Nushell completions")
|
||||
.short('n')
|
||||
.long("nu")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("pwsh")
|
||||
.help("PowerShell completions")
|
||||
.short('p')
|
||||
.long("pwsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("zsh")
|
||||
.help("Zshell completions")
|
||||
.short('z')
|
||||
.long("zsh")
|
||||
.action(ArgAction::SetTrue),
|
||||
]),
|
||||
Self::all(),
|
||||
Self::links(),
|
||||
Self::manpages(),
|
||||
Self::completions(),
|
||||
])
|
||||
}
|
||||
|
||||
@ -150,11 +167,9 @@ impl Cmd for Bootstrap {
|
||||
return Err(io::Error::new(ErrorKind::Other, "No input").into());
|
||||
};
|
||||
if let Some(prefix) = matches.get_one::<String>("prefix") {
|
||||
let commands: Commands = Commands {
|
||||
items: vec![
|
||||
&BOOTSTRAP, &ECHO, &FALSE, &HEAD, &HOSTNAME, &NOLOGIN, &TRUE, &SLEEP, &SHITBOX,
|
||||
],
|
||||
};
|
||||
let commands = super::COMMANDS
|
||||
.get()
|
||||
.ok_or_else(|| io::Error::new(ErrorKind::Other, "Cannot get commands list"))?;
|
||||
let usr = matches.get_flag("usr");
|
||||
if let Some(progpath) = crate::progpath() {
|
||||
let mut outpath = PathBuf::from(prefix);
|
||||
@ -166,7 +181,11 @@ impl Cmd for Bootstrap {
|
||||
}
|
||||
outpath.push(env!("CARGO_PKG_NAME"));
|
||||
fs::copy(&progpath, &outpath)?;
|
||||
println!(" install: {} -> {}", progpath.display(), outpath.display());
|
||||
println!(
|
||||
" install: {} -> {}",
|
||||
progpath.display(),
|
||||
outpath.display()
|
||||
);
|
||||
}
|
||||
match matches.subcommand() {
|
||||
Some(("links", matches)) => {
|
||||
@ -194,47 +213,16 @@ impl Cmd for Bootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
struct Commands<'a> {
|
||||
items: Vec<&'a dyn Cmd>,
|
||||
pub trait Bootstrappable {
|
||||
fn manpages(&self, prefix: &str) -> Result<(), io::Error>;
|
||||
fn completions(&self, prefix: &str, matches: &ArgMatches) -> Result<(), io::Error>;
|
||||
fn links(&self, prefix: &str, usr: bool, cmd: &ArgMatches) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl<'a> Commands<'a> {
|
||||
impl<'a> Bootstrappable for Commands<'a> {
|
||||
fn manpages(&self, prefix: &str) -> Result<(), io::Error> {
|
||||
println!("Generating Unix man pages:");
|
||||
self.items
|
||||
.iter()
|
||||
.try_for_each(|cmd| Self::manpage(prefix, cmd))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn manpage(prefix: &str, cmd: &&dyn Cmd) -> Result<(), io::Error> {
|
||||
let command = cmd.cli();
|
||||
let fname = match cmd.name() {
|
||||
"bootstrap" => "shitbox-bootstrap.1".to_string(),
|
||||
s => format!("{s}.1"),
|
||||
};
|
||||
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(command);
|
||||
let mut buffer: Vec<u8> = vec![];
|
||||
man.render(&mut buffer)?;
|
||||
fs::write(&outfile, buffer)?;
|
||||
println!(" {}", outfile.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn completion(outdir: &Path, cmd: &&dyn Cmd, gen: impl Generator) -> Result<(), io::Error> {
|
||||
let name = cmd.name();
|
||||
let mut cmd = cmd.cli();
|
||||
if !outdir.exists() {
|
||||
fs::create_dir_all(outdir)?;
|
||||
}
|
||||
let path = generate_to(gen, &mut cmd, name, outdir)?;
|
||||
println!(" {}", path.display());
|
||||
self.items.iter().try_for_each(|cmd| cmd.manpage(prefix))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ use crate::Path;
|
||||
use clap::{Arg, Command};
|
||||
use std::{env, error::Error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Echo {
|
||||
name: &'static str,
|
||||
path: Option<Path>,
|
||||
|
@ -3,6 +3,7 @@ use crate::Path;
|
||||
use clap::Command;
|
||||
use std::{error::Error, process};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct False {
|
||||
name: &'static str,
|
||||
path: Option<Path>,
|
||||
|
@ -8,6 +8,7 @@ use std::{
|
||||
process,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Head {
|
||||
name: &'static str,
|
||||
path: Option<Path>,
|
||||
|
@ -3,6 +3,7 @@ use crate::Path;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use std::{error::Error, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Hostname {
|
||||
name: &'static str,
|
||||
path: Option<Path>,
|
||||
|
@ -1,5 +1,13 @@
|
||||
use clap::ArgMatches;
|
||||
use std::{error::Error, fs, os::unix::fs::symlink, path::PathBuf};
|
||||
use clap_complete::{generate_to, Generator};
|
||||
use clap_mangen::Man;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt, fs, io,
|
||||
os::unix::fs::symlink,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub mod bootstrap;
|
||||
mod cat;
|
||||
@ -29,14 +37,35 @@ pub use {
|
||||
self::hostname::{Hostname, HOSTNAME},
|
||||
bootstrap::{Bootstrap, BOOTSTRAP},
|
||||
echo::{Echo, ECHO},
|
||||
r#false::{False, FALSE},
|
||||
head::{Head, HEAD},
|
||||
nologin::{Nologin, NOLOGIN},
|
||||
r#false::{False, FALSE},
|
||||
r#true::{True, TRUE},
|
||||
shitbox::{Shitbox, SHITBOX},
|
||||
sleep::{Sleep, SLEEP},
|
||||
};
|
||||
pub trait Cmd {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Commands<'a> {
|
||||
pub items: Vec<&'a dyn Cmd>,
|
||||
}
|
||||
|
||||
pub static COMMANDS: OnceCell<Commands> = OnceCell::new();
|
||||
|
||||
impl<'a> Commands<'a> {
|
||||
fn completion(outdir: &Path, cmd: &&dyn Cmd, gen: impl Generator) -> Result<(), io::Error> {
|
||||
let name = cmd.name();
|
||||
let mut cmd = cmd.cli();
|
||||
if !outdir.exists() {
|
||||
fs::create_dir_all(outdir)?;
|
||||
}
|
||||
let path = generate_to(gen, &mut cmd, name, outdir)?;
|
||||
println!(" {}", path.display());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Cmd: fmt::Debug + Sync {
|
||||
fn name(&self) -> &str;
|
||||
fn cli(&self) -> clap::Command;
|
||||
fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box<dyn Error>>;
|
||||
@ -87,8 +116,8 @@ pub trait Cmd {
|
||||
}
|
||||
}
|
||||
};
|
||||
symlink(&binpath, &linkpath)?;
|
||||
println!(" symlink: {} -> {}", binpath, linkpath.display());
|
||||
symlink(binpath, &linkpath)?;
|
||||
println!(" symlink: {binpath} -> {}", linkpath.display());
|
||||
} else {
|
||||
let mut binpath = PathBuf::from(prefix);
|
||||
binpath.push("bin");
|
||||
@ -99,4 +128,24 @@ pub trait Cmd {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn manpage(&self, prefix: &str) -> Result<(), io::Error> {
|
||||
let command = self.cli();
|
||||
let fname = match self.name() {
|
||||
"bootstrap" => "shitbox-bootstrap.1".to_string(),
|
||||
s => format!("{s}.1"),
|
||||
};
|
||||
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(command);
|
||||
let mut buffer: Vec<u8> = vec![];
|
||||
man.render(&mut buffer)?;
|
||||
fs::write(&outfile, buffer)?;
|
||||
println!(" {}", outfile.display());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use super::Cmd;
|
||||
use clap::Command;
|
||||
use std::process;
|
||||
use super::Cmd;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Nologin {
|
||||
name: &'static str,
|
||||
path: Option<crate::Path>,
|
||||
|
@ -1,10 +1,11 @@
|
||||
use super::{Cmd, BOOTSTRAP, ECHO, FALSE, HEAD, HOSTNAME, SLEEP, TRUE, NOLOGIN};
|
||||
use super::{Cmd, BOOTSTRAP, ECHO, FALSE, HEAD, HOSTNAME, NOLOGIN, SLEEP, TRUE};
|
||||
use clap::Command;
|
||||
use std::{
|
||||
error::Error,
|
||||
io::{self, ErrorKind},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Shitbox {
|
||||
name: &'static str,
|
||||
path: Option<crate::Path>,
|
||||
|
@ -3,6 +3,7 @@ use crate::Path;
|
||||
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command};
|
||||
use std::{env, error::Error, thread, time::Duration};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sleep {
|
||||
name: &'static str,
|
||||
path: Option<Path>,
|
||||
|
@ -3,6 +3,7 @@ use crate::Path;
|
||||
use clap::Command;
|
||||
use std::{error::Error, process};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct True {
|
||||
name: &'static str,
|
||||
path: Option<Path>,
|
||||
|
11
src/lib.rs
11
src/lib.rs
@ -2,7 +2,7 @@
|
||||
use std::{env, error::Error, path::PathBuf, string::ToString};
|
||||
|
||||
pub mod cmd;
|
||||
use cmd::{Cmd, ECHO, FALSE, HEAD, HOSTNAME, SHITBOX, SLEEP, TRUE, NOLOGIN};
|
||||
use cmd::{Cmd, Commands, BOOTSTRAP, ECHO, FALSE, HEAD, HOSTNAME, NOLOGIN, SHITBOX, SLEEP, TRUE};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Path {
|
||||
@ -33,6 +33,15 @@ pub fn progpath() -> Option<PathBuf> {
|
||||
}
|
||||
|
||||
pub fn run() -> Result<(), Box<dyn Error>> {
|
||||
if cmd::COMMANDS.get().is_none() {
|
||||
cmd::COMMANDS
|
||||
.set(Commands {
|
||||
items: vec![
|
||||
&BOOTSTRAP, &ECHO, &FALSE, &HEAD, &HOSTNAME, &NOLOGIN, &TRUE, &SLEEP, &SHITBOX,
|
||||
],
|
||||
})
|
||||
.expect("Cannot register commands");
|
||||
}
|
||||
if let Some(progname) = progname() {
|
||||
match progname.as_str() {
|
||||
"echo" => ECHO.run(None)?,
|
||||
|
Loading…
Reference in New Issue
Block a user