Skip to content

Commit

Permalink
feat(CLI): upload flag parsing
Browse files Browse the repository at this point in the history
We handle errors gracefully with costum types and minimal amount of
code. Unfortunately, Mime type parsing is very 'flexible', allowing
nonesense types to be passed easily.

Related to #62
  • Loading branch information
Byron committed Apr 15, 2015
1 parent 306852d commit 9eed405
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 6 deletions.
22 changes: 20 additions & 2 deletions src/mako/cli/lib/engine.mako
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
hub_type_name = 'api::' + hub_type(c.schemas, util.canonical_name())
%>\
mod cmn;
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage, arg_from_str, writer_from_opts, parse_kv_arg};
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage, arg_from_str, writer_from_opts, parse_kv_arg,
input_file_from_opts, input_mime_from_opts};
use std::default::Default;
use std::str::FromStr;
Expand Down Expand Up @@ -227,7 +229,23 @@ ${value_unwrap}\
}
}
% endif # handle call parameters
## TODO: parse upload
% if mc.media_params:
let protocol =
% for p in mc.media_params:
% if loop.first:
if \
% else:
} else if \
% endif
${SOPT + cmd_ident(p.protocol)} {
"${p.protocol}"
% endfor # each media param
} else {
unreachable!()
};
let mut input_file = input_file_from_opts(&${SOPT + arg_ident(FILE_ARG[1:-1])}, err);
let mime_type = input_mime_from_opts(&${SOPT + arg_ident(MIME_ARG[1:-1])}, err);
% endif # support upload
if dry_run {
None
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/mako/cli/main.rs.mako
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@
</%block>
#![feature(plugin, exit_status)]
#![plugin(docopt_macros)]
#![allow(unused_variables, unused_imports, dead_code, unsed_mut)]
#![allow(unused_variables, unused_imports, dead_code, unused_mut)]

extern crate docopt;
extern crate yup_oauth2 as oauth2;
extern crate rustc_serialize;
extern crate serde;
extern crate hyper;
extern crate mime;
extern crate ${to_extern_crate_name(library_to_crate_name(library_name(name, version), make.depends_on_suffix))} as api;

use std::io;
use std::env;
use std::io::Write;
use std::io::{self, Write};

${docopt.new(c)}\

Expand Down
42 changes: 41 additions & 1 deletion src/rust/cli/cmn.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use oauth2::{ApplicationSecret, ConsoleApplicationSecret, TokenStorage, Token};
use rustc_serialize::json;
use mime::Mime;

use std::fs;
use std::env;
Expand Down Expand Up @@ -31,6 +32,26 @@ pub fn parse_kv_arg<'a>(kv: &'a str, err: &mut InvalidOptionsError)
}
}

pub fn input_file_from_opts(file_path: &str, err: &mut InvalidOptionsError) -> Option<fs::File> {
match fs::File::open(file_path) {
Ok(f) => Some(f),
Err(io_err) => {
err.issues.push(CLIError::Input(InputError::IOError((file_path.to_string(), io_err))));
None
}
}
}

pub fn input_mime_from_opts(mime: &str, err: &mut InvalidOptionsError) -> Option<Mime> {
match mime.parse() {
Ok(m) => Some(m),
Err(_) => {
err.issues.push(CLIError::Input(InputError::Mime(mime.to_string())));
None
}
}
}

// May panic if we can't open the file - this is anticipated, we can't currently communicate this
// kind of error: TODO: fix this architecture :)
pub fn writer_from_opts(flag: bool, arg: &str) -> Box<Write> {
Expand Down Expand Up @@ -138,18 +159,37 @@ impl fmt::Display for ConfigurationError {
}
}

#[derive(Debug)]
pub enum InputError {
IOError((String, io::Error)),
Mime(String),
}

impl fmt::Display for InputError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
InputError::IOError((ref file_path, ref io_err))
=> writeln!(f, "Failed to open '{}' for reading with error: {}", file_path, io_err),
InputError::Mime(ref mime)
=> writeln!(f, "'{}' is not a known mime-type", mime),
}
}
}

#[derive(Debug)]
pub enum CLIError {
Configuration(ConfigurationError),
ParseError((&'static str, &'static str, String, String)),
UnknownParameter(String),
InvalidKeyValueSyntax(String),
Input(InputError),
}

impl fmt::Display for CLIError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
CLIError::Configuration(ref err) => writeln!(f, "Configuration -> {}", err),
CLIError::Configuration(ref err) => write!(f, "Configuration -> {}", err),
CLIError::Input(ref err) => write!(f, "Input -> {}", err),
CLIError::ParseError((arg_name, type_name, ref value, ref err_desc))
=> writeln!(f, "Failed to parse argument '{}' with value '{}' as {} with error: {}",
arg_name, value, type_name, err_desc),
Expand Down

0 comments on commit 9eed405

Please sign in to comment.