From e34e24e04943e6cce8564295587bbf426c58077f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 14 Apr 2015 17:17:21 +0200 Subject: [PATCH] feat(CLI):required arg parsing + first doit() call 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 --- etc/api/shared.yaml | 5 +++ etc/api/type-api.yaml | 5 --- etc/api/type-cli.yaml | 4 +- src/mako/cli/lib/cli.py | 4 ++ src/mako/cli/lib/engine.mako | 82 +++++++++++++++++++++++++++++++----- src/mako/cli/main.rs.mako | 1 + src/rust/cli/cmn.rs | 4 +- 7 files changed, 87 insertions(+), 18 deletions(-) diff --git a/etc/api/shared.yaml b/etc/api/shared.yaml index c9f5c22496..4a6a1f6cff 100644 --- a/etc/api/shared.yaml +++ b/etc/api/shared.yaml @@ -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 diff --git a/etc/api/type-api.yaml b/etc/api/type-api.yaml index 320a2868a7..a109a3ace8 100644 --- a/etc/api/type-api.yaml +++ b/etc/api/type-api.yaml @@ -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' diff --git a/etc/api/type-cli.yaml b/etc/api/type-cli.yaml index 5aedc05bb4..785063fe53 100644 --- a/etc/api/type-cli.yaml +++ b/etc/api/type-cli.yaml @@ -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 = "*" diff --git a/src/mako/cli/lib/cli.py b/src/mako/cli/lib/cli.py index 89a29a88eb..03e6983961 100644 --- a/src/mako/cli/lib/cli.py +++ b/src/mako/cli/lib/cli.py @@ -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)) diff --git a/src/mako/cli/lib/engine.mako b/src/mako/cli/lib/engine.mako index d8b5a9e9bd..1bc09d67e6 100644 --- a/src/mako/cli/lib/engine.mako +++ b/src/mako/cli/lib/engine.mako @@ -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 %>\ @@ -12,13 +12,14 @@ 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}>, } @@ -26,15 +27,16 @@ struct Engine { 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 { - ${self._method_call_impl(c, resource, method)}\ + fn ${call_method_ident(resource, method)}(&self, dry_run: bool, err: &mut InvalidOptionsError) + -> Option { + ${self._method_call_impl(c, resource, method) | indent_all_but_first_by(2)} } % endfor # each method % endfor fn _doit(&self, dry_run: bool) -> (Option, Option) { let mut err = InvalidOptionsError::new(); - let mut call_result: Option = None; + let mut call_result: Option; let mut err_opt: Option = None; ## RESOURCE LOOP: check for set primary subcommand @@ -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), }; @@ -113,6 +114,67 @@ self.opt.${cmd_ident(method)} { } -<%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 +}\ \ No newline at end of file diff --git a/src/mako/cli/main.rs.mako b/src/mako/cli/main.rs.mako index 51de7cf663..f120f5592d 100644 --- a/src/mako/cli/main.rs.mako +++ b/src/mako/cli/main.rs.mako @@ -12,6 +12,7 @@ #![feature(plugin, exit_status)] #![plugin(docopt_macros)] +#![allow(unused_variables, unused_imports, dead_code)] extern crate docopt; extern crate yup_oauth2 as oauth2; diff --git a/src/rust/cli/cmn.rs b/src/rust/cli/cmn.rs index de0d1977ab..4d722c2277 100644 --- a/src/rust/cli/cmn.rs +++ b/src/rust/cli/cmn.rs @@ -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), } } }