Improve CLI argument handling for subcommand use

This commit is contained in:
timvisee 2018-03-08 19:10:24 +01:00
parent 188b0cb2e1
commit fb7fd69400
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
7 changed files with 110 additions and 45 deletions

1
Cargo.lock generated
View file

@ -175,6 +175,7 @@ dependencies = [
"clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",

View file

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

View file

@ -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
src/cmd/cmd_upload.rs Normal file
View file

@ -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
src/cmd/handler.rs Normal file
View file

@ -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
src/cmd/mod.rs Normal file
View file

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

View file

@ -1,4 +1,5 @@
extern crate hyper; extern crate hyper;
extern crate lazy_static;
extern crate mime_guess; extern crate mime_guess;
extern crate open; extern crate open;
extern crate openssl; extern crate openssl;
@ -8,7 +9,7 @@ extern crate reqwest;
extern crate serde_derive; extern crate serde_derive;
mod app; mod app;
mod arg_handler; mod cmd;
mod b64; mod b64;
mod crypto; mod crypto;
mod metadata; mod metadata;
@ -24,17 +25,41 @@ use reqwest::header::Authorization;
use reqwest::mime::APPLICATION_OCTET_STREAM; use reqwest::mime::APPLICATION_OCTET_STREAM;
use reqwest::multipart::Part; 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 crypto::{derive_auth_key, derive_file_key, derive_meta_key};
use metadata::{Metadata, XFileMetadata}; use metadata::{Metadata, XFileMetadata};
use reader::EncryptedFileReaderTagged; use reader::EncryptedFileReaderTagged;
/// Application entrypoint.
fn main() { fn main() {
// Parse CLI arguments // 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 // Get the path
let path = Path::new(arg_handler.file()); let path = Path::new(cmd_upload.file());
// Make sure the path is a file // Make sure the path is a file
if !path.is_file() { if !path.is_file() {