1
0
mirror of https://github.com/jht5945/rust_util.git synced 2025-12-27 15:40:03 +08:00

feat: add use clap

This commit is contained in:
2021-01-03 01:19:34 +08:00
parent 9d9423cfec
commit 19d967ef0e
4 changed files with 117 additions and 1 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,6 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ target/
Cargo.lock Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt

11
demo/test_clap/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "test_clap"
version = "0.1.0"
authors = ["Hatter Jiang <jht5945@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rust_util = { version = "0.6", path = "../../", features = ["use_clap"] }
clap = "2.0"

View File

@@ -0,0 +1,24 @@
use clap::{App, SubCommand, ArgMatches};
use rust_util::util_clap::Command;
use rust_util::util_clap::CommandError;
use rust_util::util_clap::CommandExecutor;
struct TestCommand{}
impl Command for TestCommand {
fn name(&self) -> &str { "test" }
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("Test subcommand")
}
fn run(&self, _arg_matches: &ArgMatches, _: &ArgMatches) -> CommandError {
println!("hello test!");
Ok(None)
}
}
fn main() {
let mut c = CommandExecutor::new(None);
c.add(Box::new(TestCommand{}));
c.run().unwrap();
}

81
src/util_clap.rs Normal file
View File

@@ -0,0 +1,81 @@
use std::process;
use clap::{App, Arg, ArgMatches};
use crate::XResult;
use crate::util_msg;
pub type CommandError = XResult<Option<i32>>;
pub trait Command {
fn name(&self) -> &str;
fn subcommand<'a>(&self) -> App<'a, 'a>;
fn run(&self, arg_matches: &ArgMatches, _: &ArgMatches) -> CommandError;
}
pub trait DefaultCommand {
fn process_command<'a>(&self, app: App<'a, 'a>) -> App<'a, 'a>;
fn run(&self, arg_matches: &ArgMatches) -> CommandError;
}
pub struct DefaultCommandImpl {}
impl DefaultCommand for DefaultCommandImpl {
fn process_command<'a>(&self, app: App<'a, 'a>) -> App<'a, 'a> {
app.arg(Arg::with_name("verbose").long("verbose").short("v").multiple(true).help("Show verbose info"))
}
fn run(&self, arg_matches: &ArgMatches) -> CommandError {
let verbose_count = arg_matches.occurrences_of("verbose");
util_msg::print_info(&format!("Verbose count: {}", verbose_count));
util_msg::print_info("This is default command cli, please run with help (--help)");
Ok(None)
}
}
pub struct CommandExecutor {
default_cmd: Option<Box<dyn DefaultCommand>>,
commands: Vec<Box<dyn Command>>,
}
impl CommandExecutor {
pub fn new(default_cmd: Option<Box<dyn DefaultCommand>>) -> Self {
CommandExecutor{
default_cmd,
commands: Vec::new(),
}
}
pub fn add(&mut self, cmd: Box<dyn Command>) -> &mut Self {
self.commands.push(cmd);
self
}
pub fn run(&self) -> CommandError {
let mut app = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.about(env!("CARGO_PKG_DESCRIPTION"));
if let Some(default_cmd) = &self.default_cmd {
app = default_cmd.process_command(app);
}
for command in &self.commands {
app = app.subcommand(command.subcommand());
}
let matches = app.get_matches();
for command in &self.commands {
if let Some(sub_cmd_matches) = matches.subcommand_matches(command.name()) {
match command.run(&matches, sub_cmd_matches)? {
None => return Ok(None),
Some(code) => process::exit(code),
}
}
}
match &self.default_cmd {
None => {
util_msg::print_error("No default command, please try help (--help)");
process::exit(1);
},
Some(default_cmd) => match default_cmd.run(&matches)? {
None => return Ok(None),
Some(code) => process::exit(code),
},
}
}
}