mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-02-23 15:49:49 +01:00
feat(clap): initial version of command generation
It compiles and works, even though there are many things we want to improve. One big question is how to define multi-arguments, like -u foo bar baz.
This commit is contained in:
@@ -22,7 +22,7 @@ make:
|
|||||||
- source: main.rs
|
- source: main.rs
|
||||||
output_dir: src
|
output_dir: src
|
||||||
cargo:
|
cargo:
|
||||||
build_version: "0.1.0"
|
build_version: "0.2.0"
|
||||||
keywords: [cli]
|
keywords: [cli]
|
||||||
is_executable: YES
|
is_executable: YES
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
<%namespace name="util" file="../../lib/util.mako"/>\
|
<%namespace name="util" file="../../lib/util.mako"/>\
|
||||||
<%!
|
<%!
|
||||||
from util import (put_and, supports_scopes, api_index, indent_by)
|
from util import (put_and, supports_scopes, api_index, indent_by, enclose_in)
|
||||||
from cli import (mangle_subcommand, new_method_context, PARAM_FLAG, STRUCT_FLAG, UPLOAD_FLAG, OUTPUT_FLAG, VALUE_ARG,
|
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, 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)
|
CONFIG_DIR_FLAG, KEY_VALUE_ARG, to_docopt_arg, DEBUG_FLAG, DEBUG_AUTH_FLAG)
|
||||||
|
|
||||||
|
def rust_boolean(v):
|
||||||
|
return v and 'true' or 'false'
|
||||||
%>\
|
%>\
|
||||||
<%def name="grammar(c)">\
|
<%def name="grammar(c)">\
|
||||||
<%
|
|
||||||
param_used = False
|
|
||||||
struct_used = False
|
|
||||||
upload_protocols_used = set()
|
|
||||||
output_used = False
|
|
||||||
%>\
|
|
||||||
% for resource in sorted(c.rta_map.keys()):
|
% for resource in sorted(c.rta_map.keys()):
|
||||||
% for method in sorted(c.rta_map[resource]):
|
% for method in sorted(c.rta_map[resource]):
|
||||||
<%
|
<%
|
||||||
@@ -26,24 +23,20 @@
|
|||||||
|
|
||||||
if mc.request_value:
|
if mc.request_value:
|
||||||
args.append('-%s %s...' % (STRUCT_FLAG, '<%s>' % KEY_VALUE_ARG))
|
args.append('-%s %s...' % (STRUCT_FLAG, '<%s>' % KEY_VALUE_ARG))
|
||||||
struct_used = True
|
|
||||||
# end request_value
|
# end request_value
|
||||||
|
|
||||||
if mc.media_params:
|
if mc.media_params:
|
||||||
upload_protocols = [mp.protocol for mp in mc.media_params]
|
upload_protocols = [mp.protocol for mp in mc.media_params]
|
||||||
mode = docopt_mode(upload_protocols)
|
mode = docopt_mode(upload_protocols)
|
||||||
args.append('-%s %s %s %s' % (UPLOAD_FLAG, mode, FILE_ARG, MIME_ARG))
|
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
|
# end upload handling
|
||||||
|
|
||||||
if mc.optional_props or parameters is not UNDEFINED:
|
if mc.optional_props or parameters is not UNDEFINED:
|
||||||
args.append('[-%s %s...]' % (PARAM_FLAG, '<%s>' % VALUE_ARG))
|
args.append('[-%s %s...]' % (PARAM_FLAG, '<%s>' % VALUE_ARG))
|
||||||
param_used = True
|
|
||||||
# end paramters
|
# end paramters
|
||||||
|
|
||||||
if mc.response_schema or mc.m.get('supportsMediaDownload', False):
|
if mc.response_schema or mc.m.get('supportsMediaDownload', False):
|
||||||
args.append('[-%s %s]' % (OUTPUT_FLAG, OUT_ARG))
|
args.append('[-%s %s]' % (OUTPUT_FLAG, OUT_ARG))
|
||||||
output_used = True
|
|
||||||
# handle output
|
# handle output
|
||||||
%>\
|
%>\
|
||||||
${util.program_name()} [options] ${mangle_subcommand(resource)} ${mangle_subcommand(method)} ${' '.join(args)}
|
${util.program_name()} [options] ${mangle_subcommand(resource)} ${mangle_subcommand(method)} ${' '.join(args)}
|
||||||
@@ -77,72 +70,153 @@ Configuration:
|
|||||||
|
|
||||||
<%def name="new(c)" buffered="True">\
|
<%def name="new(c)" buffered="True">\
|
||||||
<%
|
<%
|
||||||
param_used = False
|
url_info = "All documentation details can be found at" + \
|
||||||
struct_used = False
|
cargo.doc_base_url + '/' + api_index(cargo.doc_base_url, name, version, make, check_exists=False)
|
||||||
upload_protocols_used = set()
|
|
||||||
output_used = False
|
# list of tuples
|
||||||
|
# (0) = long name
|
||||||
|
# (1) = description
|
||||||
|
# (2) = argument name, no argument if no argument
|
||||||
|
global_args = list()
|
||||||
|
if supports_scopes(auth):
|
||||||
|
global_args.append((
|
||||||
|
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.",
|
||||||
|
'url'
|
||||||
|
))
|
||||||
|
# end add scope arg
|
||||||
|
global_args.append((
|
||||||
|
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}]",
|
||||||
|
'folder',
|
||||||
|
))
|
||||||
|
|
||||||
|
global_args.append((
|
||||||
|
DEBUG_FLAG,
|
||||||
|
"Output all server communication to standard error. `tx` and `rx` are placed "
|
||||||
|
"into the same stream.",
|
||||||
|
None
|
||||||
|
))
|
||||||
|
|
||||||
|
global_args.append((
|
||||||
|
DEBUG_AUTH_FLAG,
|
||||||
|
"Output all communication related to authentication to standard error. `tx` "
|
||||||
|
"and `rx` are placed into the same stream.",
|
||||||
|
None
|
||||||
|
))
|
||||||
%>\
|
%>\
|
||||||
App::new("${util.program_name()}")
|
App::new("${util.program_name()}")
|
||||||
<%block filter="indent_by(4)">
|
<%block filter="indent_by(7)">\
|
||||||
|
.author("${', '.join(cargo.authors)}")
|
||||||
|
.version("${cargo.build_version}")
|
||||||
|
% if description is not UNDEFINED:
|
||||||
|
.about("${description}")
|
||||||
|
% endif
|
||||||
|
.after_help("${url_info}")
|
||||||
|
% for flag, desc, arg_name in global_args:
|
||||||
|
.arg(Arg::with_name("${arg_name or flag}")
|
||||||
|
.long("${flag}")
|
||||||
|
.help("${desc}")
|
||||||
|
.takes_value(${rust_boolean(arg_name)}))
|
||||||
|
% endfor
|
||||||
% for resource in sorted(c.rta_map.keys()):
|
% for resource in sorted(c.rta_map.keys()):
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::new("${mangle_subcommand(resource)}")
|
||||||
% for method in sorted(c.rta_map[resource]):
|
% for method in sorted(c.rta_map[resource]):
|
||||||
<%
|
<%
|
||||||
mc = new_method_context(resource, method, c)
|
mc = new_method_context(resource, method, c)
|
||||||
|
|
||||||
|
# A list of tuples
|
||||||
|
# (0) = short flag, like -c
|
||||||
|
# (1) = param description or None
|
||||||
|
# (2) = argument name, or None if there is no argument
|
||||||
|
# (3) = is required (bool)
|
||||||
|
# (4) = allow multi-use
|
||||||
args = list()
|
args = list()
|
||||||
for p in mc.required_props:
|
for p in mc.required_props:
|
||||||
if is_request_value_property(mc, p):
|
if is_request_value_property(mc, p):
|
||||||
continue
|
continue
|
||||||
args.append(to_docopt_arg(p))
|
args.append((
|
||||||
|
None,
|
||||||
|
p.get('description'),
|
||||||
|
mangle_subcommand(p.name),
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
))
|
||||||
# end for each required property
|
# end for each required property
|
||||||
|
|
||||||
if mc.request_value:
|
if mc.request_value:
|
||||||
args.append('-%s %s...' % (STRUCT_FLAG, '<%s>' % KEY_VALUE_ARG))
|
args.append((
|
||||||
struct_used = True
|
STRUCT_FLAG,
|
||||||
|
"Set various fields of the request structure",
|
||||||
|
KEY_VALUE_ARG,
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
))
|
||||||
# end request_value
|
# end request_value
|
||||||
|
|
||||||
if mc.media_params:
|
if mc.media_params:
|
||||||
upload_protocols = [mp.protocol for mp in mc.media_params]
|
upload_protocols = [mp.protocol for mp in mc.media_params]
|
||||||
mode = docopt_mode(upload_protocols)
|
# TODO: figure out how to have a group of arguments
|
||||||
args.append('-%s %s %s %s' % (UPLOAD_FLAG, mode, FILE_ARG, MIME_ARG))
|
# NOTE: use possible_values() to specify 'mode'
|
||||||
upload_protocols_used = upload_protocols_used|set(upload_protocols)
|
args.append((
|
||||||
|
UPLOAD_FLAG,
|
||||||
|
"Specify which file to upload",
|
||||||
|
"mode",
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
))
|
||||||
|
## args.append('-%s %s %s %s' % (UPLOAD_FLAG, mode, FILE_ARG, MIME_ARG))
|
||||||
# end upload handling
|
# end upload handling
|
||||||
|
|
||||||
if mc.optional_props or parameters is not UNDEFINED:
|
if mc.optional_props or parameters is not UNDEFINED:
|
||||||
args.append('[-%s %s...]' % (PARAM_FLAG, '<%s>' % VALUE_ARG))
|
args.append((
|
||||||
param_used = True
|
PARAM_FLAG,
|
||||||
|
"Set various fields of the request structure",
|
||||||
|
VALUE_ARG,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
))
|
||||||
# end paramters
|
# end paramters
|
||||||
|
|
||||||
if mc.response_schema or mc.m.get('supportsMediaDownload', False):
|
if mc.response_schema or mc.m.get('supportsMediaDownload', False):
|
||||||
args.append('[-%s %s]' % (OUTPUT_FLAG, OUT_ARG))
|
args.append((
|
||||||
output_used = True
|
OUTPUT_FLAG,
|
||||||
|
"Specify the file into which to write the programs output",
|
||||||
|
OUT_ARG,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
))
|
||||||
# handle output
|
# handle output
|
||||||
%>\
|
%>\
|
||||||
${util.program_name()} [options] ${mangle_subcommand(resource)} ${mangle_subcommand(method)} ${' '.join(args)}
|
.subcommand(
|
||||||
|
SubCommand::new("${mangle_subcommand(method)}")
|
||||||
|
% if mc.m.get('description') is not None:
|
||||||
|
.about("${mc.m.description}")
|
||||||
|
% endif
|
||||||
|
% 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)}))
|
||||||
|
% endfor
|
||||||
|
)
|
||||||
% endfor # each method
|
% endfor # each method
|
||||||
|
)
|
||||||
% endfor # end for each resource
|
% 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} <url>
|
|
||||||
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} <folder>
|
|
||||||
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();
|
.get_matches();
|
||||||
</%block>
|
</%block>
|
||||||
</%def>
|
</%def>
|
||||||
@@ -25,7 +25,7 @@ extern crate ${to_extern_crate_name(library_to_crate_name(library_name(name, ver
|
|||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use clap::{App, SubCommand};
|
use clap::{App, SubCommand, Arg};
|
||||||
|
|
||||||
## ${engine.new(c)}\
|
## ${engine.new(c)}\
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user