mirror of
https://github.com/jht5945/rust_util.git
synced 2026-01-13 15:50:05 +08:00
Compare commits
4 Commits
f0bd9a719a
...
5df135fda9
| Author | SHA1 | Date | |
|---|---|---|---|
| 5df135fda9 | |||
| 249d7ee36e | |||
| 19d967ef0e | |||
| 9d9423cfec |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
target/
|
||||
|
||||
Cargo.lock
|
||||
# These are backup files generated by rustfmt
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rust_util"
|
||||
version = "0.6.25"
|
||||
version = "0.6.26"
|
||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "Hatter's Rust Util"
|
||||
@@ -10,11 +10,13 @@ readme = "README.md"
|
||||
[features]
|
||||
default = [] #["serde", "serde_json"]
|
||||
# use_serde = ["serde", "serde_json"]
|
||||
use_clap = ["clap"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.65"
|
||||
term = "0.5.2"
|
||||
term_size = "0.3.1"
|
||||
lazy_static = "1.3.0"
|
||||
clap = { version = "2.0", optional = true }
|
||||
# serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
# serde_json = { version = "1.0", optional = true }
|
||||
|
||||
11
demo/test_clap/Cargo.toml
Normal file
11
demo/test_clap/Cargo.toml
Normal 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"
|
||||
24
demo/test_clap/src/main.rs
Normal file
24
demo/test_clap/src/main.rs
Normal 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();
|
||||
}
|
||||
@@ -21,6 +21,8 @@ pub mod util_time;
|
||||
pub mod util_net;
|
||||
pub mod util_term;
|
||||
pub mod util_git;
|
||||
#[cfg(feature = "use_clap")]
|
||||
pub mod util_clap;
|
||||
|
||||
/// iff!(condition, result_when_true, result_when_false)
|
||||
#[macro_export] macro_rules! iff {
|
||||
|
||||
81
src/util_clap.rs
Normal file
81
src/util_clap.rs
Normal 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) -> XResult<()> {
|
||||
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(()),
|
||||
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(()),
|
||||
Some(code) => process::exit(code),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user