From 04e2fb71b8a6ed549296d317a7742a32d5a518db Mon Sep 17 00:00:00 2001 From: Joxit Date: Fri, 20 Oct 2023 01:52:56 +0200 Subject: [PATCH] chore: move from structopt to clap v4 with derive --- Cargo.toml | 26 +++++++++++++++++----- src/commands/build/mod.rs | 10 ++++----- src/commands/build/postgres.rs | 32 +++++++++++++-------------- src/commands/build/shapefile.rs | 29 +++++++++++++------------ src/commands/build/sqlite.rs | 19 +++++++++-------- src/commands/completion.rs | 20 +++++++++-------- src/commands/export.rs | 31 ++++++++++++++------------- src/commands/fetch.rs | 15 +++++++------ src/commands/fix.rs | 6 +++--- src/commands/install.rs | 24 --------------------- src/commands/list.rs | 14 ++++++------ src/commands/mod.rs | 38 +++++++++------------------------ src/commands/patch.rs | 8 +++---- src/commands/print.rs | 16 +++++++------- src/main.rs | 20 +++++++++++------ 15 files changed, 148 insertions(+), 160 deletions(-) delete mode 100644 src/commands/install.rs diff --git a/Cargo.toml b/Cargo.toml index 3316b38..abc08b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,12 @@ homepage = "https://github.com/Joxit/wof-cli" documentation = "https://docs.rs/wof/" readme = "README.md" keywords = ["cli"] -categories = ["command-line-utilities", "database-implementations", "data-structures", "parser-implementations"] +categories = [ + "command-line-utilities", + "database-implementations", + "data-structures", + "parser-implementations", +] [[bin]] name = "wof" @@ -29,10 +34,11 @@ postgres = "^0.19.3" lazy_static = "^1.4.0" which = { version = "^4.4.2", optional = true } tar = { version = "^0.4.26", optional = true } -flate2 = { version ="^1.0.13", optional = true } -structopt = { version = "^0.3", optional = true } +flate2 = { version = "^1.0.13", optional = true } attohttpc = { version = "^0.26.1", optional = true } chrono = { version = "^0.4.10", optional = true } +clap = { version = "^4.4", features = ["derive", "env"], optional = true } +clap_complete = { version = "^4.4", optional = true } [dependencies.gdal] version = "^0.16" @@ -54,5 +60,15 @@ version = "0.29.0" features = ["bundled"] [features] -cli = ["which", "tar", "flate2", "structopt", "attohttpc", "chrono", "log", "git2"] -with-gdal = ["gdal"] \ No newline at end of file +cli = [ + "which", + "tar", + "flate2", + "clap", + "clap_complete", + "attohttpc", + "chrono", + "log", + "git2", +] +with-gdal = ["gdal"] diff --git a/src/commands/build/mod.rs b/src/commands/build/mod.rs index b0f7ffa..1356c46 100644 --- a/src/commands/build/mod.rs +++ b/src/commands/build/mod.rs @@ -2,25 +2,25 @@ pub use crate::commands::build::postgres::Postgres; pub use crate::commands::build::shapefile::Shapefile; pub use crate::commands::build::sqlite::SQLite; use crate::repo::Walk; +use clap::Parser; use log::{error, info}; use std::path::PathBuf; use std::time::SystemTime; -use structopt::StructOpt; mod postgres; mod shapefile; mod sqlite; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub enum Build { /// Who's On First documents to PostgreSQL database. - #[structopt(name = "postgres")] + #[command(name = "postgres")] Postgres(Postgres), /// Who's On First documents to ESRI shapefiles. - #[structopt(name = "shapefile")] + #[command(name = "shapefile")] Shapefile(Shapefile), /// Who's On First documents to SQLite database. - #[structopt(name = "sqlite")] + #[command(name = "sqlite")] SQLite(SQLite), } diff --git a/src/commands/build/postgres.rs b/src/commands/build/postgres.rs index e83126d..95e0860 100644 --- a/src/commands/build/postgres.rs +++ b/src/commands/build/postgres.rs @@ -1,59 +1,59 @@ use crate::postgres; use crate::utils::ResultExit; +use clap::Parser; use log::info; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct Postgres { /// WOF data directories to import - #[structopt(default_value = ".")] + #[arg(default_value = ".")] pub directories: Vec, /// The IP or hostname of the postgreSQL database. - #[structopt(long = "host", default_value = "127.0.0.1", env = "WOF_PG_HOST")] + #[arg(long = "host", default_value = "127.0.0.1", env = "WOF_PG_HOST")] pub host: String, /// The postgreSQL user name to use. - #[structopt( - short = "u", + #[arg( + short = 'u', long = "user", default_value = "wof", env = "WOF_PG_USERNAME" )] pub user: String, /// The postgreSQL database name to use. - #[structopt( - short = "d", + #[arg( + short = 'd', long = "dbname", default_value = "gis", env = "WOF_PG_DBNAME" )] pub dbname: String, /// The postgreSQL database port to use. - #[structopt( - short = "p", + #[arg( + short = 'p', long = "port", default_value = "5432", env = "WOF_PG_DBNAME" )] pub port: u16, /// The postgreSQL database port to use. - #[structopt(short = "W", long = "password", env = "WOF_PG_PASSWORD")] + #[arg(short = 'W', long = "password", env = "WOF_PG_PASSWORD")] pub password: Option, /// The SIRID to use for geometry storage. Default value is 4326, common usage is also 3857. - #[structopt( - short = "s", + #[arg( + short = 's', long = "srid", default_value = "4326", env = "WOF_PG_SRID" )] pub srid: i32, /// Don't insert deprecated features. - #[structopt(long = "no-deprecated")] + #[arg(long = "no-deprecated")] pub no_deprecated: bool, /// Display timings during the build process, implies verbose. - #[structopt(long = "timings")] + #[arg(long = "timings")] pub timings: bool, /// Activate verbose mode. - #[structopt(short = "v", long = "verbose")] + #[arg(short = 'v', long = "verbose")] pub verbose: bool, } diff --git a/src/commands/build/shapefile.rs b/src/commands/build/shapefile.rs index 57a9667..db07da4 100644 --- a/src/commands/build/shapefile.rs +++ b/src/commands/build/shapefile.rs @@ -2,45 +2,46 @@ use crate::shapefile; use crate::utils::ResultExit; use crate::wof::WOFGeoJSON; use crate::JsonValue; +use clap::builder::PossibleValuesParser; +use clap::Parser; use log::{error, info}; use std::path::Path; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct Shapefile { - #[structopt(default_value = ".")] + #[arg(default_value = ".")] pub directories: Vec, /// Include only records that belong to this ID. You may pass multiple -belongs-to flags. - #[structopt(long = "belongs-to")] + #[arg(long = "belongs-to")] pub belongs_to: Option>, /// Exclude records of this placetype. You may pass multiple -exclude-placetype flags. - #[structopt(long = "exclude-placetype")] + #[arg(long = "exclude-placetype")] pub exclude: Option>, /// Include only records of this placetype. You may pass multiple -include-placetype flags. - #[structopt(long = "include-placetype")] + #[arg(long = "include-placetype")] pub include: Option>, /// The mode to use importing data. - #[structopt( + #[arg( long = "mode", - possible_values = &["directory", "feature", "feature-collection", "files", "geojson-ls", "meta", "path", "repo", "sqlite"], + value_parser = PossibleValuesParser::new(&["directory", "feature", "feature-collection", "files", "geojson-ls", "meta", "path", "repo", "sqlite"]), default_value = "repo")] pub mode: String, /// Where to write the new shapefile. - #[structopt(long = "out", default_value = "whosonfirst-data-latest.shp")] + #[arg(long = "out", default_value = "whosonfirst-data-latest.shp")] pub out: String, // todo: "MULTIPOINT" /// The shapefile type to use indexing data. - #[structopt( + #[arg( long = "shapetype", - possible_values = &["POINT", "POLYLINE", "POLYGON"], - case_insensitive = false, + value_parser = PossibleValuesParser::new(&["POINT", "POLYLINE", "POLYGON"]), + ignore_case = false, default_value = "POLYGON")] pub shapetype: String, /// Activate verbose mode. - #[structopt(short = "v", long = "verbose")] + #[arg(short = 'v', long = "verbose")] pub verbose: bool, /// Display timings during and after indexing - #[structopt(long = "timings")] + #[arg(long = "timings")] pub timings: bool, } diff --git a/src/commands/build/sqlite.rs b/src/commands/build/sqlite.rs index 91accea..6f64272 100644 --- a/src/commands/build/sqlite.rs +++ b/src/commands/build/sqlite.rs @@ -1,32 +1,33 @@ use crate::commands::assert_directory_exists; use crate::sqlite; use crate::utils::ResultExit; +use clap::builder::PossibleValuesParser; +use clap::Parser; use log::info; use std::path::Path; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct SQLite { /// WOF data directories - #[structopt(default_value = ".")] + #[arg(default_value = ".")] pub directories: Vec, /// Where to store the final build file. If empty the code will attempt to create whosonfirst-data-latest.db the current working directory. - #[structopt(long = "out", default_value = "whosonfirst-data-latest.db")] + #[arg(long = "out", default_value = "whosonfirst-data-latest.db")] pub out: String, /// Don't insert deprecated features. - #[structopt(long = "no-deprecated")] + #[arg(long = "no-deprecated")] pub no_deprecated: bool, /// Don't prettify the geojson. - #[structopt(long = "no-pretty")] + #[arg(long = "no-pretty")] pub no_pretty: bool, /// Preset for pelias use. Will insert only in geojson and spr tables. - #[structopt(long = "preset", possible_values = &["pelias"])] + #[arg(long = "preset", value_parser = PossibleValuesParser::new(&["pelias"]))] pub preset: Option, /// Display timings during the build process, implies verbose. - #[structopt(long = "timings")] + #[arg(long = "timings")] pub timings: bool, /// Activate verbose mode. - #[structopt(short = "v", long = "verbose")] + #[arg(short = 'v', long = "verbose")] pub verbose: bool, } diff --git a/src/commands/completion.rs b/src/commands/completion.rs index 010f2bd..458c3b1 100644 --- a/src/commands/completion.rs +++ b/src/commands/completion.rs @@ -1,21 +1,21 @@ -use crate::ApplicationArguments; -use structopt::clap::Shell; -use structopt::StructOpt; +use crate::Wof; +use clap::{CommandFactory, Parser}; +use clap_complete::{generate, Shell}; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub enum Completion { /// Generates a .bash completion file for the Bourne Again SHell (BASH) /// Save the output in `/etc/bash_completion.d/wof` or `~/.local/share/bash-completion/completions/wof` - #[structopt(name = "bash")] + #[command(name = "bash")] Bash, /// Generates a .fish completion file for the Friendly Interactive SHell (fish) - #[structopt(name = "fish")] + #[command(name = "fish")] Fish, /// Generates a completion file for the Z SHell (ZSH) - #[structopt(name = "zsh")] + #[command(name = "zsh")] Zsh, /// Generates a completion file for Elvish - #[structopt(name = "elvish")] + #[command(name = "elvish")] Elvish, } @@ -27,6 +27,8 @@ impl Completion { Completion::Zsh => Shell::Zsh, Completion::Elvish => Shell::Elvish, }; - ApplicationArguments::clap().gen_completions_to("wof", shell, &mut std::io::stdout()); + let mut cli = Wof::command(); + let bin_name = cli.get_name().to_string(); + generate(shell, &mut cli, &bin_name, &mut std::io::stdout()); } } diff --git a/src/commands/export.rs b/src/commands/export.rs index bca01d1..35de42e 100644 --- a/src/commands/export.rs +++ b/src/commands/export.rs @@ -1,47 +1,48 @@ use crate::commands::Command; use crate::git::Git; use crate::utils::ResultExit; +use clap::builder::PossibleValuesParser; +use clap::Parser; use std::default::Default; -use structopt::StructOpt; static BINARY: &'static str = "wof-exportify"; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct Export { /// Where to write the export, on stdout or flatfile (needs source) - #[structopt(short = "e", long = "exporter", possible_values = &["flatfile", "stdout"])] + #[arg(short = 'e', long = "exporter", value_parser = PossibleValuesParser::new(&["flatfile", "stdout"]))] pub exporter: Option, /// WOF data folder where are stored GeoJSONs to exportify - #[structopt(short = "s", long = "source")] + #[arg(short = 's', long = "source")] pub source: Option, /// The WOF id of the object to export - #[structopt(short = "i", long = "id")] + #[arg(short = 'i', long = "id")] pub id: Option, /// Path of the object to export - #[structopt(short = "p", long = "path")] + #[arg(short = 'p', long = "path")] pub path: Option, - #[structopt(short = "c", long = "collection")] + #[arg(short = 'c', long = "collection")] pub collection: bool, - #[structopt(short = "a", long = "alt")] + #[arg(short = 'a', long = "alt")] pub alt: Option, - #[structopt(short = "d", long = "display")] + #[arg(short = 'd', long = "display")] pub display: Option, /// Read stdin for the object to export - #[structopt(long = "stdin")] + #[arg(long = "stdin")] pub stdin: bool, /// Run export on all files of a specific commit/ref (needs git repository) - #[structopt(long = "commit")] + #[arg(long = "commit")] pub commit: Option, /// Run export on all stagged files (needs git repository) - #[structopt(long = "stagged")] + #[arg(long = "stagged")] pub stagged: bool, /// Activate debug mode - #[structopt(long = "debug")] + #[arg(long = "debug")] pub debug: bool, /// Activate verbose mode - #[structopt(short = "v", long = "verbose")] + #[arg(short = 'v', long = "verbose")] pub verbose: bool, - #[structopt(skip)] + #[arg(skip)] pub exit: bool, } diff --git a/src/commands/fetch.rs b/src/commands/fetch.rs index 845a825..364ece7 100644 --- a/src/commands/fetch.rs +++ b/src/commands/fetch.rs @@ -1,29 +1,30 @@ use crate::commands::{download_tar_gz_stream_geojson, download_tar_gz_strip, output_pipe}; use crate::utils; use crate::utils::ResultExit; +use clap::builder::PossibleValuesParser; +use clap::Parser; use log::{error, info}; use std::path::Path; use std::time::SystemTime; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct Fetch { /// Ouput directory to download WOF documents - #[structopt(short = "o", long = "out", default_value = ".")] + #[arg(short = 'o', long = "out", default_value = ".")] pub out: String, /// Should download postalcodes repositories - #[structopt(long = "postalcode", possible_values = &["true", "false"])] + #[arg(long = "postalcode", value_parser = PossibleValuesParser::new(&["true", "false"]))] pub postalcode: Option, /// Should download admin repositories, default true - #[structopt(long = "admin", possible_values = &["true", "false"])] + #[arg(long = "admin", value_parser =PossibleValuesParser::new( &["true", "false"]))] pub admin: Option, /// Two letters country code to download. No values will download all repositories. pub countries: Vec, /// Display timings during the download process, implies verbose. - #[structopt(long = "timings")] + #[arg(long = "timings")] pub timings: bool, /// Activate verbose mode. - #[structopt(short = "v", long = "verbose")] + #[arg(short = 'v', long = "verbose")] pub verbose: bool, } diff --git a/src/commands/fix.rs b/src/commands/fix.rs index 928c3d8..6b3d1cc 100644 --- a/src/commands/fix.rs +++ b/src/commands/fix.rs @@ -1,15 +1,15 @@ use crate::fix::Fix; use crate::repo::Walk; use crate::utils::ResultExit; +use clap::Parser; use log::error; use std::fs::File; use std::io::{stdin, stdout, Read}; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct FixCommand { /// Paths to WOF documents. - #[structopt(default_value = ".")] + #[arg(default_value = ".")] pub directories: Vec, } diff --git a/src/commands/install.rs b/src/commands/install.rs deleted file mode 100644 index abfde14..0000000 --- a/src/commands/install.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::commands::export::Export; -use crate::utils::ResultExit; -use log::error; -use structopt::StructOpt; - -#[derive(Debug, StructOpt)] -pub struct Install { - /// Name of the package to install (saved in ~/.wof directory) - #[structopt(possible_values = &["export"])] - pub package: String, -} - -impl Install { - pub fn exec(&self) { - crate::utils::logger::set_verbose(false, "wof::install").expect_exit("Can't init logger."); - match self.package.as_ref() { - "export" => Export::install(), - _ => { - error!("Incorrect package to install."); - std::process::exit(127) - } - } - } -} diff --git a/src/commands/list.rs b/src/commands/list.rs index e7c43a5..eeb9a17 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -2,28 +2,28 @@ use crate::expression::{Evaluate, Predicate}; use crate::repo::Walk; use crate::sqlite; use crate::utils::ResultExit; +use clap::Parser; use log::error; use std::convert::TryFrom; use std::io::{Read, Write}; use std::path::Path; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct List { /// Paths to WOF documents. - #[structopt(default_value = ".")] + #[arg(default_value = ".")] pub directories: Vec, /// List also alternate geometries. - #[structopt(long = "alt")] + #[arg(long = "alt")] pub alt: bool, /// Don't print deprecated features. - #[structopt(long = "no-deprecated")] + #[arg(long = "no-deprecated")] pub no_deprecated: bool, /// Print minified geojson instead of path. - #[structopt(long = "print-geojson")] + #[arg(long = "print-geojson")] pub print_geojson: bool, /// Filter lister geojson with expression. - #[structopt(long = "filter")] + #[arg(long = "filter")] pub filter: Option, } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 052a9d8..04d9f44 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -3,17 +3,16 @@ use crate::commands::completion::Completion; use crate::commands::export::Export; use crate::commands::fetch::Fetch; use crate::commands::fix::FixCommand; -use crate::commands::install::Install; use crate::commands::list::List; use crate::commands::patch::Patch; use crate::commands::print::Print; use crate::std::StringifyError; use crate::utils::ResultExit; +use clap::Parser; use flate2::read::GzDecoder; use regex::Regex; use std::path::Path; use std::result::Result; -use structopt::StructOpt; use tar::Archive; mod build; @@ -21,52 +20,42 @@ mod completion; mod export; mod fetch; mod fix; -mod install; mod list; mod patch; mod print; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub enum Command { /// Build a WOF database (sqlite or shapefile). - #[structopt(name = "build")] + #[command(name = "build", subcommand)] Build(Build), /// Export tools for the Who's On First documents. - #[structopt(name = "export")] + #[command(name = "export")] Export(Export), - /// Install what you need to use this CLI (needs python2 and go). - #[structopt(name = "install")] - Install(Install), /// Generate autocompletion file for your shell. - #[structopt(name = "completion")] + #[command(name = "completion", subcommand)] Completion(Completion), /// Fetch WOF data from github. - #[structopt(name = "fetch")] + #[command(name = "fetch")] Fetch(Fetch), /// Patch WOF documents with json. Can be via stdin or cmd argument. - #[structopt(name = "patch")] + #[command(name = "patch")] Patch(Patch), /// Print to stdout WOF document by id. Can be via stdin or cmd argument. - #[structopt(name = "print")] + #[command(name = "print")] Print(Print), /// List all WOF document in the directory. - #[structopt(name = "list")] + #[command(name = "list")] List(List), /// Fix WOF data with some custom rules. - #[structopt(name = "fix")] + #[command(name = "fix")] Fix(FixCommand), } impl Command { pub fn exec(&self) { - let home = std::env::var("HOME").expect("No $HOME found in environment variables"); - - std::env::set_var("PATH", Command::get_path_env(home.clone())); - std::env::set_var("PYTHONUSERBASE", format!("{}/.wof/", home)); - match self { Command::Export(executable) => executable.exec(), - Command::Install(executable) => executable.exec(), Command::Completion(executable) => executable.exec(), Command::Fetch(executable) => executable.exec(), Command::Patch(executable) => executable.exec(), @@ -116,13 +105,6 @@ impl Command { cmd_args.push(opt.to_string()); } - pub fn get_path_env(home: String) -> String { - match std::env::var("PATH") { - Ok(val) => format!("{}/.wof/bin:{}", home, val), - Err(_) => format!("{}/.wof/bin:{}/bin:/bin", home, home), - } - } - pub fn assert_cmd_exists(binary: &'static str, install: &'static str) { which::which(binary).expect_exit_code( format!( diff --git a/src/commands/patch.rs b/src/commands/patch.rs index 39c941d..c7fe69c 100644 --- a/src/commands/patch.rs +++ b/src/commands/patch.rs @@ -5,21 +5,21 @@ use crate::sqlite::{SQLite, SQLiteOpts}; use crate::std::StringifyError; use crate::utils::{self, JsonUtils, ResultExit}; use crate::{JsonObject, JsonValue, WOFGeoJSON}; +use clap::Parser; use std::fs::File; use std::io::Read; use std::path::Path; use std::string::String; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct Patch { /// The original file where we apply patches. pub original: String, /// The patch file or directory to apply, read from standard input by default. - #[structopt(short = "i", long = "input")] + #[arg(short = 'i', long = "input")] pub patchfile: Option, /// Don't prettify the geojson. - #[structopt(long = "no-pretty")] + #[arg(long = "no-pretty")] pub no_pretty: bool, } diff --git a/src/commands/print.rs b/src/commands/print.rs index 2664a10..6655f1d 100644 --- a/src/commands/print.rs +++ b/src/commands/print.rs @@ -2,33 +2,33 @@ use crate::ser::{json_to_writer, json_to_writer_pretty}; use crate::sqlite::{SQLite, SQLiteOpts}; use crate::utils::ResultExit; use crate::utils::{self, JsonUtils}; +use clap::Parser; use json::JsonValue; use log::error; use std::io::{Read, Write}; use std::string::String; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct Print { /// Ids or paths to WOF documents to print pub ids: Vec, /// Remove the geometry before pretty print. - #[structopt(long = "no-geom")] + #[arg(long = "no-geom")] pub no_geom: bool, /// Print minified json. - #[structopt(long = "no-pretty")] + #[arg(long = "no-pretty")] pub no_pretty: bool, /// Send the raw data, do not pretty print it. You can't use filters with this. - #[structopt(short = "r", long = "raw")] + #[arg(short = 'r', long = "raw")] pub raw: bool, /// Exclude some properties from the input. `wof:` will exclude all properties starting with `wof:` - #[structopt(short = "e", long = "exclude")] + #[arg(short = 'e', long = "exclude")] pub excludes: Vec, /// Include some properties from the input. `wof:` will include only properties starting with `wof:` - #[structopt(short = "i", long = "include")] + #[arg(short = 'i', long = "include")] pub includes: Vec, /// Print geojson from SQLite database instead of repository - #[structopt(long = "sqlite")] + #[arg(long = "sqlite")] pub sqlite: Option, } diff --git a/src/main.rs b/src/main.rs index c30bc70..575d737 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use crate::commands::Command; -use structopt::StructOpt; +use clap::{Args, CommandFactory, Parser}; #[macro_use] extern crate lazy_static; @@ -26,15 +26,23 @@ pub use self::wof::WOFGeoJSON; pub use json::object::Object as JsonObject; pub use json::JsonValue; -#[derive(Debug, StructOpt)] -#[structopt(name = "wof", author, about)] -pub struct ApplicationArguments { - #[structopt(subcommand)] +#[derive(Parser, Debug)] +#[structopt(name = "wof", author, version, about)] +pub struct Wof { + #[command(subcommand)] pub command: Command, } +impl Wof { + pub fn display_help(cmd: &str) { + let clap = Self::augment_args(Self::command()); + let args = format!("{} {} --help", clap, cmd); + clap.get_matches_from(args.split(" ")); + } +} + fn main() { - let opt = ApplicationArguments::from_args(); + let opt = Wof::parse(); opt.command.exec(); }