Skip to content

Commit

Permalink
fix(clap): generate command data structure
Browse files Browse the repository at this point in the history
We do this in the hopes to circumvent a stack overflow.
This means we will setup the parser entirely at runtime, which actually
saves a little bit of code.
  • Loading branch information
Byron committed Apr 29, 2015
1 parent 9a8ae4b commit 8ac8d3b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 27 deletions.
58 changes: 33 additions & 25 deletions src/mako/cli/lib/argparse.mako
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
def rust_boolean(v):
return v and 'true' or 'false'
def rust_optional(v):
if v is None:
return 'None'
if isinstance(v, bool):
v = v and 'true' or 'false'
elif isinstance(v, basestring):
v = '"%s"' % v
return 'Some(%s)' % v
%>\
<%def name="grammar(c)">\
% for resource in sorted(c.rta_map.keys()):
Expand Down Expand Up @@ -109,7 +118,7 @@ Configuration:
None
))
%>\
App::new("${util.program_name()}")
let mut app = App::new("${util.program_name()}")
<%block filter="indent_by(7)">\
.author("${', '.join(cargo.authors)}")
.version("${cargo.build_version}")
Expand All @@ -121,11 +130,17 @@ App::new("${util.program_name()}")
.arg(Arg::with_name("${arg_name or flag}")
.long("${flag}")
.help("${desc}")
.takes_value(${rust_boolean(arg_name)}))
.takes_value(${rust_boolean(arg_name)}))\
% if loop.last:
;
% else:
% endif
% endfor
let arg_data = [
% for resource in sorted(c.rta_map.keys()):
.subcommand(
SubCommand::new("${mangle_subcommand(resource)}")
<%block filter="indent_by(4)">\
("${mangle_subcommand(resource)}", vec![
% for method in sorted(c.rta_map[resource]):
<%
mc = new_method_context(resource, method, c)
Expand Down Expand Up @@ -193,30 +208,23 @@ App::new("${util.program_name()}")
))
# handle output
%>\
.subcommand(
SubCommand::new("${mangle_subcommand(method)}")
% if mc.m.get('description') is not None:
.about("${mc.m.description}")
% endif
("${mangle_subcommand(method)}", ${rust_optional(mc.m.get('description'))},
vec![
% for flag, desc, arg_name, required, multi in args:
.arg(
Arg::with_name("${arg_name or flag}")
% if flag:
.short("${flag}")
% endif
% if desc:
.help("${desc}")
% endif
% if flag is not None:
.takes_value(${rust_boolean(arg_name)})
% endif
.required(${rust_boolean(required)})
.multiple(${rust_boolean(multi)}))
(${rust_optional(arg_name)},
${rust_optional(flag)},
${rust_optional(desc)},
${rust_optional(required)},
${rust_optional(multi)}),
% if not loop.last:
% endif
% endfor
)
]),
% endfor # each method
)
]),
</%block>
% endfor # end for each resource
.get_matches();
];
</%block>
</%def>
2 changes: 1 addition & 1 deletion src/mako/cli/lib/engine.mako
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
%>\
mod cmn;
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage, arg_from_str, writer_from_opts, parse_kv_arg,
input_file_from_opts, input_mime_from_opts, FieldCursor, FieldError};
input_file_from_opts, input_mime_from_opts, FieldCursor, FieldError, make_subcommand};
use std::default::Default;
use std::str::FromStr;
Expand Down
1 change: 0 additions & 1 deletion src/mako/cli/main.rs.mako
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use clap::{App, SubCommand, Arg};
## ${engine.new(c)}\

fn main() {
let matches =
${argparse.new(c) | indent_all_but_first_by(1)}\

## let opts: Options = Options::docopt().decode().unwrap_or_else(|e| e.exit());
Expand Down
17 changes: 17 additions & 0 deletions src/rust/cli/cmn.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use oauth2::{ApplicationSecret, ConsoleApplicationSecret, TokenStorage, Token};
use rustc_serialize::json;
use mime::Mime;
use clap::{App, SubCommand};

use std::fs;
use std::env;
Expand All @@ -15,6 +16,22 @@ use std::default::Default;

const FIELD_SEP: char = '.';


fn make_subcommand(command_name: &str, desc: Option<&str>,
args: &Vec<(Option<&str>, Option<&str>, Option<&str>,
Option<bool>, Option<bool>)>)
-> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
// arg_name: Option<&str>,
// short_name: Option<&str>,
// help: Option<&str>,
// % if flag is not None:
// .takes_value(${rust_boolean(arg_name)})
// required: Option<bool>,
// multiple: Option<bool>
SubCommand::new(command_name)
}


#[derive(Clone, Default)]
pub struct FieldCursor(Vec<String>);

Expand Down

0 comments on commit 8ac8d3b

Please sign in to comment.