Skip to content

Commit

Permalink
feat(CLI):required arg parsing + first doit() call
Browse files Browse the repository at this point in the history
We are parsing required scalar values and handle parse-errors correctly,
to the point were we make a simple, non-upload doit() call.

It shows that we seem to build invalid calls, for now,but that's nothing
we can't fix once the time is ripe.

Next goals will be related to finalizing the argument parsing code.

Fixes #60
  • Loading branch information
Byron committed Apr 14, 2015
1 parent d6919f1 commit e34e24e
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 18 deletions.
5 changes: 5 additions & 0 deletions etc/api/shared.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ api:
# exclude APIs which currently don't build correctly. State the reason for the exclusion as well
# to allow looking at it at a later point.
-
terms:
# how to actually do something with the API
action: doit
# when a resource is supposed to be uploaded
upload_action: upload
# Contains values shared among all API implementations
directories:
# directory under which all generated sources should reside
Expand Down
5 changes: 0 additions & 5 deletions etc/api/type-api.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
api:
base_path: "etc/api"
terms:
# how to actually do something with the API
action: doit
# when a resource is supposed to be uploaded
upload_action: upload
properties:
# additional fields specified by the user
params: '_additional_params'
Expand Down
4 changes: 2 additions & 2 deletions etc/api/type-cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ cargo:
keywords: [cli]
is_executable: YES
dependencies:
- docopt = "*"
- docopt_macros = "*"
- docopt = "= 0.6.59"
- docopt_macros = "= 0.6.59"
- rustc-serialize = "*"
4 changes: 4 additions & 0 deletions src/mako/cli/lib/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ def ident(name):
def cmd_ident(name):
return 'cmd_' + ident(name)

# Similar to cmd_ident, but for arguments
def arg_ident(name):
return 'arg_' + ident(name)

# Returns identifier for method dealing with options for the given resource-method pair
def call_method_ident(resource, method):
return '_%s_%s' % (ident(resource), ident(method))
Expand Down
82 changes: 72 additions & 10 deletions src/mako/cli/lib/engine.mako
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<%namespace name="util" file="../../lib/util.mako"/>\
<%!
from util import hub_type
from util import (hub_type, mangle_ident, indent_all_but_first_by, activity_rust_type)
from cli import (mangle_subcommand, new_method_context, PARAM_FLAG, STRUCT_FLAG, UPLOAD_FLAG, OUTPUT_FLAG, VALUE_ARG,
CONFIG_DIR, SCOPE_FLAG, is_request_value_property, FIELD_SEP, docopt_mode, FILE_ARG, MIME_ARG, OUT_ARG,
cmd_ident, call_method_ident)
cmd_ident, call_method_ident, arg_ident, POD_TYPES)
v_arg = '<%s>' % VALUE_ARG
%>\
Expand All @@ -12,29 +12,31 @@
hub_type_name = 'api::' + hub_type(c.schemas, util.canonical_name())
%>\
mod cmn;
use cmn::{InvalidOptionsError, JsonTokenStorage};
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage};
use std::default::Default;
use std::str::FromStr;
use oauth2::{Authenticator, DefaultAuthenticatorDelegate};
struct Engine {
opt: Options,
config_dir: String,
hub: ${hub_type_name}<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
}
impl Engine {
% for resource in sorted(c.rta_map.keys()):
% for method in sorted(c.rta_map[resource]):
fn ${call_method_ident(resource, method)}(&self, dry_run: bool, err: &mut InvalidOptionsError) -> Option<api::Error> {
${self._method_call_impl(c, resource, method)}\
fn ${call_method_ident(resource, method)}(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
${self._method_call_impl(c, resource, method) | indent_all_but_first_by(2)}
}
% endfor # each method
% endfor
fn _doit(&self, dry_run: bool) -> (Option<api::Error>, Option<InvalidOptionsError>) {
let mut err = InvalidOptionsError::new();
let mut call_result: Option<api::Error> = None;
let mut call_result: Option<api::Error>;
let mut err_opt: Option<InvalidOptionsError> = None;
## RESOURCE LOOP: check for set primary subcommand
Expand Down Expand Up @@ -95,7 +97,6 @@ self.opt.${cmd_ident(method)} {
}, None);
let engine = Engine {
opt: opt,
config_dir: config_dir,
hub: ${hub_type_name}::new(hyper::Client::new(), auth),
};
Expand All @@ -113,6 +114,67 @@ self.opt.${cmd_ident(method)} {
}
</%def>

<%def name="_method_call_impl(c, resource, method)">\
None
<%def name="_method_call_impl(c, resource, method)" buffered="True">\
<%
mc = new_method_context(resource, method, c)
## if is_request_value_property(mc, p):
## continue
## args.append('<%s>' % mangle_subcommand(p.name))
%>\
## REQUIRED PARAMETERS
% for p in mc.required_props:
<%
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)
%>\
% 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
% 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':
borrow = '&'
call_args.append(borrow + mangle_ident(p.name))
# end for each required prop
%>\
let call = self.hub.${mangle_ident(resource)}().${mangle_ident(method)}(${', '.join(call_args)});
## TODO: set parameters
## TODO: parse upload and output information
if dry_run {
None
} else {
## Make the call, handle uploads, handle downloads (also media downloads|json decoding)
## TODO: unify error handling
% if mc.media_params:
return None
% else:
match call.${api.terms.action}() {
Err(api_err) => Some(api_err),
Ok(res) => {
println!("DEBUG: {:?}", res);
None
}
}
% endif
}\
</%def>
1 change: 1 addition & 0 deletions src/mako/cli/main.rs.mako
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
</%block>
#![feature(plugin, exit_status)]
#![plugin(docopt_macros)]
#![allow(unused_variables, unused_imports, dead_code)]

extern crate docopt;
extern crate yup_oauth2 as oauth2;
Expand Down
4 changes: 3 additions & 1 deletion src/rust/cli/cmn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,14 @@ impl fmt::Display for ConfigurationError {
#[derive(Debug)]
pub enum CLIError {
Configuration(ConfigurationError),
ParseError(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::Configuration(ref err) => writeln!(f, "Configuration -> {}", err),
CLIError::ParseError(ref desc) => desc.fmt(f),
}
}
}
Expand Down

0 comments on commit e34e24e

Please sign in to comment.