Skip to content

Commit

Permalink
fix(CLI): optimze argument handling and conversion
Browse files Browse the repository at this point in the history
* Thanks to a generic function, we save a lot of code within main.rs
* more effcient signature for ParseError

Fixes #65
  • Loading branch information
Byron committed Apr 14, 2015
1 parent e34e24e commit 76841da
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 25 deletions.
32 changes: 13 additions & 19 deletions src/mako/cli/lib/engine.mako
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
cmd_ident, call_method_ident, arg_ident, POD_TYPES)
v_arg = '<%s>' % VALUE_ARG
def to_opt_ident(p):
return 'self.opt.' + arg_ident(p.name)
%>\
<%def name="new(c)">\
<%
hub_type_name = 'api::' + hub_type(c.schemas, util.canonical_name())
%>\
mod cmn;
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage};
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage, arg_from_str};
use std::default::Default;
use std::str::FromStr;
Expand Down Expand Up @@ -126,35 +128,26 @@ self.opt.${cmd_ident(method)} {
<%
prop_name = mangle_ident(p.name)
prop_type = activity_rust_type(c.schemas, p, allow_optionals=False)
opt_ident = 'self.opt.' + arg_ident(p.name)
opt_ident = to_opt_ident(p)
%>\
% if is_request_value_property(mc, p):
let ${prop_name}: api::${prop_type} = Default::default();
% else:
let ${prop_name}: ${prop_type} = \
% if p.type == 'string':
${opt_ident}.clone();
% else:
match FromStr::from_str(&${opt_ident}) {
Err(perr) => {
err.issues.push(CLIError::ParseError(format!("Failed to parse argument <${mangle_subcommand(p.name)}> as ${p.type} with error: {}", perr)));
Default::default()
},
Ok(v) => v,
};
% endif # handle argument type
% elif p.type != 'string':
let ${prop_name}: ${prop_type} = arg_from_str(&${opt_ident}, err, "<${mangle_subcommand(p.name)}>", "${p.type}");
% endif # handle request value
% endfor # each required parameter
<%
call_args = list()
for p in mc.required_props:
borrow = ''
# if type is not available, we know it's the request value, which should also be borrowed
ptype = p.get('type', 'string')
if ptype not in POD_TYPES or ptype == 'string':
ptype = p.get('type', None)
if ptype not in POD_TYPES or ptype in ('string', None):
borrow = '&'
call_args.append(borrow + mangle_ident(p.name))
arg_name = mangle_ident(p.name)
if ptype == 'string':
arg_name = to_opt_ident(p)
call_args.append(borrow + arg_name)
# end for each required prop
%>\
let call = self.hub.${mangle_ident(resource)}().${mangle_ident(method)}(${', '.join(call_args)});
Expand All @@ -163,6 +156,7 @@ let call = self.hub.${mangle_ident(resource)}().${mangle_ident(method)}(${', '.j
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
## Make the call, handle uploads, handle downloads (also media downloads|json decoding)
## TODO: unify error handling
% if mc.media_params:
Expand Down
31 changes: 25 additions & 6 deletions src/rust/cli/cmn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,29 @@ use std::env;
use std::io;
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use std::io::{Write, Read};

use std::default::Default;


pub fn arg_from_str<T>(arg: &str, err: &mut InvalidOptionsError,
arg_name: &'static str,
arg_type: &'static str) -> T
where T: FromStr + Default,
<T as FromStr>::Err: fmt::Display {
match FromStr::from_str(arg) {
Err(perr) => {
err.issues.push(
CLIError::ParseError((arg_name, arg_type, format!("{}", perr)))
);
Default::default()
},
Ok(v) => v,
}
}

pub struct JsonTokenStorage {
pub program_name: &'static str,
pub db_dir: String,
Expand Down Expand Up @@ -57,11 +74,11 @@ impl fmt::Display for ApplicationSecretError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
ApplicationSecretError::DecoderError((ref path, ref err))
=> writeln!(f, "Could not decode file at '{}' with error: {}"
, path, err),
=> writeln!(f, "Could not decode file at '{}' with error: {}",
path, err),
ApplicationSecretError::FormatError(ref path)
=> writeln!(f, "'installed' field is unset in secret file at '{}'"
, path),
=> writeln!(f, "'installed' field is unset in secret file at '{}'",
path),
}
}
}
Expand Down Expand Up @@ -95,14 +112,16 @@ impl fmt::Display for ConfigurationError {
#[derive(Debug)]
pub enum CLIError {
Configuration(ConfigurationError),
ParseError(String),
ParseError((&'static str, &'static str, String)),
}

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::ParseError(ref desc) => desc.fmt(f),
CLIError::ParseError((arg_name, type_name, ref err_desc))
=> writeln!(f, "Failed to parse argument {} as {} with error: {}",
arg_name, type_name, err_desc),
}
}
}
Expand Down

0 comments on commit 76841da

Please sign in to comment.