Skip to content

Commit e34e24e

Browse files
committed
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
1 parent d6919f1 commit e34e24e

7 files changed

Lines changed: 87 additions & 18 deletions

File tree

etc/api/shared.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ api:
33
# exclude APIs which currently don't build correctly. State the reason for the exclusion as well
44
# to allow looking at it at a later point.
55
-
6+
terms:
7+
# how to actually do something with the API
8+
action: doit
9+
# when a resource is supposed to be uploaded
10+
upload_action: upload
611
# Contains values shared among all API implementations
712
directories:
813
# directory under which all generated sources should reside

etc/api/type-api.yaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
api:
22
base_path: "etc/api"
3-
terms:
4-
# how to actually do something with the API
5-
action: doit
6-
# when a resource is supposed to be uploaded
7-
upload_action: upload
83
properties:
94
# additional fields specified by the user
105
params: '_additional_params'

etc/api/type-cli.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ cargo:
2626
keywords: [cli]
2727
is_executable: YES
2828
dependencies:
29-
- docopt = "*"
30-
- docopt_macros = "*"
29+
- docopt = "= 0.6.59"
30+
- docopt_macros = "= 0.6.59"
3131
- rustc-serialize = "*"

src/mako/cli/lib/cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ def ident(name):
8181
def cmd_ident(name):
8282
return 'cmd_' + ident(name)
8383

84+
# Similar to cmd_ident, but for arguments
85+
def arg_ident(name):
86+
return 'arg_' + ident(name)
87+
8488
# Returns identifier for method dealing with options for the given resource-method pair
8589
def call_method_ident(resource, method):
8690
return '_%s_%s' % (ident(resource), ident(method))

src/mako/cli/lib/engine.mako

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<%namespace name="util" file="../../lib/util.mako"/>\
22
<%!
3-
from util import hub_type
3+
from util import (hub_type, mangle_ident, indent_all_but_first_by, activity_rust_type)
44
from cli import (mangle_subcommand, new_method_context, PARAM_FLAG, STRUCT_FLAG, UPLOAD_FLAG, OUTPUT_FLAG, VALUE_ARG,
55
CONFIG_DIR, SCOPE_FLAG, is_request_value_property, FIELD_SEP, docopt_mode, FILE_ARG, MIME_ARG, OUT_ARG,
6-
cmd_ident, call_method_ident)
6+
cmd_ident, call_method_ident, arg_ident, POD_TYPES)
77
88
v_arg = '<%s>' % VALUE_ARG
99
%>\
@@ -12,29 +12,31 @@
1212
hub_type_name = 'api::' + hub_type(c.schemas, util.canonical_name())
1313
%>\
1414
mod cmn;
15-
use cmn::{InvalidOptionsError, JsonTokenStorage};
15+
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage};
16+
use std::default::Default;
17+
use std::str::FromStr;
1618
1719
use oauth2::{Authenticator, DefaultAuthenticatorDelegate};
1820
1921
struct Engine {
2022
opt: Options,
21-
config_dir: String,
2223
hub: ${hub_type_name}<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
2324
}
2425
2526
2627
impl Engine {
2728
% for resource in sorted(c.rta_map.keys()):
2829
% for method in sorted(c.rta_map[resource]):
29-
fn ${call_method_ident(resource, method)}(&self, dry_run: bool, err: &mut InvalidOptionsError) -> Option<api::Error> {
30-
${self._method_call_impl(c, resource, method)}\
30+
fn ${call_method_ident(resource, method)}(&self, dry_run: bool, err: &mut InvalidOptionsError)
31+
-> Option<api::Error> {
32+
${self._method_call_impl(c, resource, method) | indent_all_but_first_by(2)}
3133
}
3234
3335
% endfor # each method
3436
% endfor
3537
fn _doit(&self, dry_run: bool) -> (Option<api::Error>, Option<InvalidOptionsError>) {
3638
let mut err = InvalidOptionsError::new();
37-
let mut call_result: Option<api::Error> = None;
39+
let mut call_result: Option<api::Error>;
3840
let mut err_opt: Option<InvalidOptionsError> = None;
3941
4042
## RESOURCE LOOP: check for set primary subcommand
@@ -95,7 +97,6 @@ self.opt.${cmd_ident(method)} {
9597
}, None);
9698
let engine = Engine {
9799
opt: opt,
98-
config_dir: config_dir,
99100
hub: ${hub_type_name}::new(hyper::Client::new(), auth),
100101
};
101102
@@ -113,6 +114,67 @@ self.opt.${cmd_ident(method)} {
113114
}
114115
</%def>
115116

116-
<%def name="_method_call_impl(c, resource, method)">\
117-
None
117+
<%def name="_method_call_impl(c, resource, method)" buffered="True">\
118+
<%
119+
mc = new_method_context(resource, method, c)
120+
## if is_request_value_property(mc, p):
121+
## continue
122+
## args.append('<%s>' % mangle_subcommand(p.name))
123+
%>\
124+
## REQUIRED PARAMETERS
125+
% for p in mc.required_props:
126+
<%
127+
prop_name = mangle_ident(p.name)
128+
prop_type = activity_rust_type(c.schemas, p, allow_optionals=False)
129+
opt_ident = 'self.opt.' + arg_ident(p.name)
130+
%>\
131+
% if is_request_value_property(mc, p):
132+
let ${prop_name}: api::${prop_type} = Default::default();
133+
% else:
134+
let ${prop_name}: ${prop_type} = \
135+
% if p.type == 'string':
136+
${opt_ident}.clone();
137+
% else:
138+
139+
match FromStr::from_str(&${opt_ident}) {
140+
Err(perr) => {
141+
err.issues.push(CLIError::ParseError(format!("Failed to parse argument <${mangle_subcommand(p.name)}> as ${p.type} with error: {}", perr)));
142+
Default::default()
143+
},
144+
Ok(v) => v,
145+
};
146+
% endif # handle argument type
147+
% endif # handle request value
148+
% endfor # each required parameter
149+
<%
150+
call_args = list()
151+
for p in mc.required_props:
152+
borrow = ''
153+
# if type is not available, we know it's the request value, which should also be borrowed
154+
ptype = p.get('type', 'string')
155+
if ptype not in POD_TYPES or ptype == 'string':
156+
borrow = '&'
157+
call_args.append(borrow + mangle_ident(p.name))
158+
# end for each required prop
159+
%>\
160+
let call = self.hub.${mangle_ident(resource)}().${mangle_ident(method)}(${', '.join(call_args)});
161+
## TODO: set parameters
162+
## TODO: parse upload and output information
163+
if dry_run {
164+
None
165+
} else {
166+
## Make the call, handle uploads, handle downloads (also media downloads|json decoding)
167+
## TODO: unify error handling
168+
% if mc.media_params:
169+
return None
170+
% else:
171+
match call.${api.terms.action}() {
172+
Err(api_err) => Some(api_err),
173+
Ok(res) => {
174+
println!("DEBUG: {:?}", res);
175+
None
176+
}
177+
}
178+
% endif
179+
}\
118180
</%def>

src/mako/cli/main.rs.mako

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
</%block>
1313
#![feature(plugin, exit_status)]
1414
#![plugin(docopt_macros)]
15+
#![allow(unused_variables, unused_imports, dead_code)]
1516

1617
extern crate docopt;
1718
extern crate yup_oauth2 as oauth2;

src/rust/cli/cmn.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,14 @@ impl fmt::Display for ConfigurationError {
9595
#[derive(Debug)]
9696
pub enum CLIError {
9797
Configuration(ConfigurationError),
98+
ParseError(String),
9899
}
99100

100101
impl fmt::Display for CLIError {
101102
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
102103
match *self {
103-
CLIError::Configuration(ref err) => writeln!(f, "Configuration -> {}", err)
104+
CLIError::Configuration(ref err) => writeln!(f, "Configuration -> {}", err),
105+
CLIError::ParseError(ref desc) => desc.fmt(f),
104106
}
105107
}
106108
}

0 commit comments

Comments
 (0)