ソースを参照

Improve CLI argument handling for subcommand use

timvisee 7 年 前
コミット
fb7fd69400
7 ファイル変更110 行追加45 行削除
  1. 1 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 0 41
      src/arg_handler.rs
  4. 37 0
      src/cmd/cmd_upload.rs
  5. 35 0
      src/cmd/handler.rs
  6. 7 0
      src/cmd/mod.rs
  7. 29 4
      src/main.rs

+ 1 - 0
Cargo.lock

@@ -175,6 +175,7 @@ dependencies = [
  "clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "hkdf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.11.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime_guess 2.0.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",

+ 1 - 0
Cargo.toml

@@ -8,6 +8,7 @@ base64 = "0.9"
 clap = "2.31"
 hkdf = "0.3"
 hyper = "0.11.9" # same as reqwest
+lazy_static = "1.0"
 mime_guess = "2.0.0-alpha.2"
 open = "1"
 openssl = "0.10"

+ 0 - 41
src/arg_handler.rs

@@ -1,41 +0,0 @@
-extern crate clap;
-
-use self::clap::{Arg, ArgMatches, App};
-
-use app::*;
-
-/// CLI argument handler.
-pub struct ArgHandler<'a> {
-    matches: ArgMatches<'a>,
-}
-
-impl<'a: 'b, 'b> ArgHandler<'a> {
-    /// Parse CLI arguments.
-    pub fn parse() -> ArgHandler<'a> {
-        // Handle/parse arguments
-        let matches = App::new(APP_NAME)
-            .version(APP_VERSION)
-            .author(APP_AUTHOR)
-            .about(APP_ABOUT)
-            .arg(Arg::with_name("file")
-                .short("f")
-                .long("file")
-                .value_name("PATH")
-                .help("The file to upload")
-                .required(true)
-                .multiple(false))
-            .get_matches();
-
-        // Instantiate
-        ArgHandler {
-            matches,
-        }
-    }
-
-    /// Get the selected file to upload.
-    pub fn file(&'a self) -> &'a str {
-        self.matches.value_of("file")
-            .expect("please specify a file to upload")
-    }
-}
-

+ 37 - 0
src/cmd/cmd_upload.rs

@@ -0,0 +1,37 @@
+use super::clap::{App, Arg, ArgMatches, SubCommand};
+
+/// The sub command name.
+const CMD_NAME: &'static str = "upload";
+
+/// The upload command.
+pub struct CmdUpload<'a> {
+    matches: &'a ArgMatches<'a>,
+}
+
+impl<'a: 'b, 'b> CmdUpload<'a> {
+    /// Build the sub command definition.
+    pub fn build<'y, 'z>() -> App<'y, 'z> {
+        SubCommand::with_name(CMD_NAME)
+            .about("Upload files")
+            .visible_alias("u")
+            .visible_alias("up")
+            .arg(
+                Arg::with_name("FILE")
+                    .help("The file to upload")
+                    .required(true)
+                    .multiple(false)
+            )
+    }
+
+    /// Parse CLI arguments, from the given parent command matches.
+    pub fn parse(parent: &'a ArgMatches<'a>) -> Option<CmdUpload<'a>> {
+        parent.subcommand_matches(CMD_NAME)
+            .map(|matches| CmdUpload { matches })
+    }
+
+    /// Get the selected file to upload.
+    pub fn file(&'a self) -> &'a str {
+        self.matches.value_of("FILE")
+            .expect("please specify a file to upload")
+    }
+}

+ 35 - 0
src/cmd/handler.rs

@@ -0,0 +1,35 @@
+use super::clap::{App, ArgMatches};
+
+use app::*;
+
+use super::cmd_upload::CmdUpload;
+
+/// CLI argument handler.
+pub struct Handler<'a> {
+    /// The CLI matches.
+    matches: ArgMatches<'a>,
+}
+
+impl<'a: 'b, 'b> Handler<'a> {
+    /// Build the application CLI definition.
+    pub fn build() -> App<'a, 'b> {
+        App::new(APP_NAME)
+            .version(APP_VERSION)
+            .author(APP_AUTHOR)
+            .about(APP_ABOUT)
+            .subcommand(CmdUpload::build().display_order(1))
+    }
+
+    /// Parse CLI arguments.
+    pub fn parse() -> Handler<'a> {
+        // Build the application CLI definition, get the matches
+        Handler {
+            matches: Handler::build().get_matches(),
+        }
+    }
+
+    /// Get the upload sub command, if matched.
+    pub fn upload(&'a self) -> Option<CmdUpload<'a>> {
+        CmdUpload::parse(&self.matches)
+    }
+}

+ 7 - 0
src/cmd/mod.rs

@@ -0,0 +1,7 @@
+extern crate clap;
+
+pub mod cmd_upload;
+pub mod handler;
+
+// Reexport modules
+pub use self::handler::Handler;

+ 29 - 4
src/main.rs

@@ -1,4 +1,5 @@
 extern crate hyper;
+extern crate lazy_static;
 extern crate mime_guess;
 extern crate open;
 extern crate openssl;
@@ -8,7 +9,7 @@ extern crate reqwest;
 extern crate serde_derive;
 
 mod app;
-mod arg_handler;
+mod cmd;
 mod b64;
 mod crypto;
 mod metadata;
@@ -24,17 +25,41 @@ use reqwest::header::Authorization;
 use reqwest::mime::APPLICATION_OCTET_STREAM;
 use reqwest::multipart::Part;
 
-use arg_handler::ArgHandler;
+use cmd::Handler;
+use cmd::cmd_upload::CmdUpload;
 use crypto::{derive_auth_key, derive_file_key, derive_meta_key};
 use metadata::{Metadata, XFileMetadata};
 use reader::EncryptedFileReaderTagged;
 
+/// Application entrypoint.
 fn main() {
     // Parse CLI arguments
-    let arg_handler = ArgHandler::parse();
+    let cmd_handler = Handler::parse();
 
+    // Invoke the proper action
+    invoke_action(&cmd_handler);
+}
+
+/// Invoke the proper action based on the CLI input.
+///
+/// If no proper action is selected, the program will quit with an error
+/// message.
+fn invoke_action(handler: &Handler) {
+    // Match the upload command
+    if let Some(cmd) = handler.upload() {
+        return action_upload(&cmd);
+    }
+
+    // No subcommand was selected, show general help
+    Handler::build()
+        .print_help()
+        .expect("failed to print command help");
+}
+
+/// The upload action.
+fn action_upload(cmd_upload: &CmdUpload) {
     // Get the path
-    let path = Path::new(arg_handler.file());
+    let path = Path::new(cmd_upload.file());
 
     // Make sure the path is a file
     if !path.is_file() {