From 988d37f0dfaf8a1725bf92364e965c1f32e6802f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 28 Apr 2015 16:33:16 +0200 Subject: [PATCH] feat(clap): setup infrastructure This allows us to setup clap and see if it compiles, which is the prime goal of the current workflow step. Related to #81 --- etc/api/type-cli.yaml | 3 +- src/mako/cli/README.md.mako | 4 +- .../cli/lib/{docopt.mako => argparse.mako} | 85 +++++++++++++++++-- src/mako/cli/main.rs.mako | 52 ++++++------ 4 files changed, 106 insertions(+), 38 deletions(-) rename src/mako/cli/lib/{docopt.mako => argparse.mako} (51%) diff --git a/etc/api/type-cli.yaml b/etc/api/type-cli.yaml index f2de6e9642..0d5b64edb1 100644 --- a/etc/api/type-cli.yaml +++ b/etc/api/type-cli.yaml @@ -26,8 +26,7 @@ cargo: keywords: [cli] is_executable: YES dependencies: - - docopt = "*" - - docopt_macros = "*" + - clap = "*" - rustc-serialize = "*" - yup-hyper-mock = "*" - serde = ">= 0.3.0" diff --git a/src/mako/cli/README.md.mako b/src/mako/cli/README.md.mako index 4595cd5382..e1216af898 100644 --- a/src/mako/cli/README.md.mako +++ b/src/mako/cli/README.md.mako @@ -5,7 +5,7 @@ c = new_context(schemas, resources, context.get('methods')) %>\ <%namespace name="util" file="../lib/util.mako"/>\ -<%namespace name="docopt" file="lib/docopt.mako"/>\ +<%namespace name="argparse" file="lib/argparse.mako"/>\ <%block filter="markdown_comment">\ <%util:gen_info source="${self.uri}" />\ @@ -26,7 +26,7 @@ Everything else about the *${util.canonical_name()}* API can be found at the This documentation was generated from the *${util.canonical_name()}* API at revision *${revision is UNDEFINED and '00000000' or revision}*. The CLI is at version *${cargo.build_version}*. ```bash -${docopt.new(c, usage_only=True)} +${argparse.grammar(c)} ``` # Configuration diff --git a/src/mako/cli/lib/docopt.mako b/src/mako/cli/lib/argparse.mako similarity index 51% rename from src/mako/cli/lib/docopt.mako rename to src/mako/cli/lib/argparse.mako index 5d68c9a207..ac4a5f5556 100644 --- a/src/mako/cli/lib/docopt.mako +++ b/src/mako/cli/lib/argparse.mako @@ -1,21 +1,17 @@ <%namespace name="util" file="../../lib/util.mako"/>\ <%! - from util import (put_and, supports_scopes, api_index) + from util import (put_and, supports_scopes, api_index, indent_by) 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, CONFIG_DIR_FLAG, KEY_VALUE_ARG, to_docopt_arg, DEBUG_FLAG, DEBUG_AUTH_FLAG) %>\ -<%def name="new(c, usage_only=False)">\ +<%def name="grammar(c)">\ <% param_used = False struct_used = False upload_protocols_used = set() output_used = False %>\ -% if not usage_only: -docopt!(Options derive Debug, " -Usage: -% endif % for resource in sorted(c.rta_map.keys()): % for method in sorted(c.rta_map[resource]): <% @@ -75,7 +71,78 @@ Configuration: --${DEBUG_AUTH_FLAG} Output all communication related to authentication to standard error. `tx` and `rx` are placed into the same stream. -% if not usage_only: -"); -% endif + + + + +<%def name="new(c)" buffered="True">\ +<% + param_used = False + struct_used = False + upload_protocols_used = set() + output_used = False +%>\ +App::new("${util.program_name()}") +<%block filter="indent_by(4)"> +% for resource in sorted(c.rta_map.keys()): + % for method in sorted(c.rta_map[resource]): +<% + mc = new_method_context(resource, method, c) + + args = list() + for p in mc.required_props: + if is_request_value_property(mc, p): + continue + args.append(to_docopt_arg(p)) + # end for each required property + + if mc.request_value: + args.append('-%s %s...' % (STRUCT_FLAG, '<%s>' % KEY_VALUE_ARG)) + struct_used = True + # end request_value + + if mc.media_params: + upload_protocols = [mp.protocol for mp in mc.media_params] + mode = docopt_mode(upload_protocols) + args.append('-%s %s %s %s' % (UPLOAD_FLAG, mode, FILE_ARG, MIME_ARG)) + upload_protocols_used = upload_protocols_used|set(upload_protocols) + # end upload handling + + if mc.optional_props or parameters is not UNDEFINED: + args.append('[-%s %s...]' % (PARAM_FLAG, '<%s>' % VALUE_ARG)) + param_used = True + # end paramters + + if mc.response_schema or mc.m.get('supportsMediaDownload', False): + args.append('[-%s %s]' % (OUTPUT_FLAG, OUT_ARG)) + output_used = True + # handle output +%>\ + ${util.program_name()} [options] ${mangle_subcommand(resource)} ${mangle_subcommand(method)} ${' '.join(args)} + % endfor # each method +% endfor # end for each resource + ${util.program_name()} --help + +All documentation details can be found at +${cargo.doc_base_url + '/' + api_index(cargo.doc_base_url, name, version, make, check_exists=False)} + +Configuration: +% if supports_scopes(auth): + --${SCOPE_FLAG} + Specify the authentication a method should be executed in. Each scope + requires the user to grant this application permission to use it. + If unset, it defaults to the shortest scope url for a particular method. +% endif scopes + --${CONFIG_DIR_FLAG} + A directory into which we will store our persistent data. Defaults to + a user-writable directory that we will create during the first invocation. + [default: ${CONFIG_DIR}] + --${DEBUG_FLAG} + Output all server communication to standard error. `tx` and `rx` are placed + into the same stream. + --${DEBUG_AUTH_FLAG} + Output all communication related to authentication to standard error. `tx` + and `rx` are placed into the same stream. +.get_matches(); + \ No newline at end of file diff --git a/src/mako/cli/main.rs.mako b/src/mako/cli/main.rs.mako index 549e531fe3..442c1ba941 100644 --- a/src/mako/cli/main.rs.mako +++ b/src/mako/cli/main.rs.mako @@ -1,8 +1,9 @@ -<%namespace name="docopt" file="lib/docopt.mako"/>\ +<%namespace name="argparse" file="lib/argparse.mako"/>\ <%namespace name="engine" file="lib/engine.mako"/>\ <%namespace name="util" file="../lib/util.mako"/>\ <% - from util import (new_context, rust_comment, to_extern_crate_name, library_to_crate_name, library_name) + from util import (new_context, rust_comment, to_extern_crate_name, library_to_crate_name, library_name, + indent_all_but_first_by) c = new_context(schemas, resources, context.get('methods')) default_user_agent = "google-cli-rust-client/" + cargo.build_version @@ -11,10 +12,9 @@ <%util:gen_info source="${self.uri}" />\ #![feature(plugin, exit_status)] -#![plugin(docopt_macros)] #![allow(unused_variables, unused_imports, dead_code, unused_mut)] -extern crate docopt; +extern crate clap; extern crate yup_oauth2 as oauth2; extern crate yup_hyper_mock as mock; extern crate rustc_serialize; @@ -25,28 +25,30 @@ extern crate ${to_extern_crate_name(library_to_crate_name(library_name(name, ver use std::env; use std::io::{self, Write}; +use clap::{App, SubCommand}; -${docopt.new(c)}\ - -${engine.new(c)}\ +## ${engine.new(c)}\ fn main() { - let opts: Options = Options::docopt().decode().unwrap_or_else(|e| e.exit()); - let debug = opts.flag_debug; - match Engine::new(opts) { - Err(err) => { - writeln!(io::stderr(), "{}", err).ok(); - env::set_exit_status(err.exit_code); - }, - Ok(engine) => { - if let Some(err) = engine.doit() { - if debug { - writeln!(io::stderr(), "{:?}", err).ok(); - } else { - writeln!(io::stderr(), "{}", err).ok(); - } - env::set_exit_status(1); - } - } - } + let matches = + ${argparse.new(c) | indent_all_but_first_by(1)}\ + + ## let opts: Options = Options::docopt().decode().unwrap_or_else(|e| e.exit()); + ## let debug = opts.flag_debug; + ## match Engine::new(opts) { + ## Err(err) => { + ## writeln!(io::stderr(), "{}", err).ok(); + ## env::set_exit_status(err.exit_code); + ## }, + ## Ok(engine) => { + ## if let Some(err) = engine.doit() { + ## if debug { + ## writeln!(io::stderr(), "{:?}", err).ok(); + ## } else { + ## writeln!(io::stderr(), "{}", err).ok(); + ## } + ## env::set_exit_status(1); + ## } + ## } + ## } } \ No newline at end of file