mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-06 11:34:34 +01:00
chore(code-up): latest version of all code
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
// COPY OF 'src/rust/cli/cmn.rs'
|
||||
// DO NOT EDIT
|
||||
use oauth2::{ApplicationSecret, ConsoleApplicationSecret, TokenStorage, Token};
|
||||
use rustc_serialize::json;
|
||||
use serde::json;
|
||||
use mime::Mime;
|
||||
use clap::{App, SubCommand};
|
||||
use strsim;
|
||||
|
||||
use std::fs;
|
||||
use std::env;
|
||||
@@ -17,6 +19,74 @@ use std::default::Default;
|
||||
|
||||
const FIELD_SEP: char = '.';
|
||||
|
||||
// Based on @erickt user comment. Thanks for the idea !
|
||||
// Remove all keys whose values are null from given value (changed in place)
|
||||
pub fn remove_json_null_values(value: &mut json::value::Value) {
|
||||
match *value {
|
||||
json::value::Value::Object(ref mut map) => {
|
||||
let mut for_removal = Vec::new();
|
||||
|
||||
for (key, mut value) in map.iter_mut() {
|
||||
if value.is_null() {
|
||||
for_removal.push(key.clone());
|
||||
} else {
|
||||
remove_json_null_values(&mut value);
|
||||
}
|
||||
}
|
||||
|
||||
for key in &for_removal {
|
||||
map.remove(key);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn did_you_mean<'a>(v: &str, possible_values: &[&'a str]) -> Option<&'a str> {
|
||||
|
||||
let mut candidate: Option<(f64, &str)> = None;
|
||||
for pv in possible_values {
|
||||
let confidence = strsim::jaro_winkler(v, pv);
|
||||
if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) {
|
||||
candidate = Some((confidence, pv));
|
||||
}
|
||||
}
|
||||
match candidate {
|
||||
None => None,
|
||||
Some((_, candidate)) => Some(candidate),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CallType {
|
||||
Upload(UploadProtocol),
|
||||
Standard,
|
||||
}
|
||||
|
||||
arg_enum!{
|
||||
pub enum UploadProtocol {
|
||||
Simple,
|
||||
Resumable
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for UploadProtocol {
|
||||
fn as_ref(&self) -> &str {
|
||||
match *self {
|
||||
UploadProtocol::Simple => "simple",
|
||||
UploadProtocol::Resumable => "resumable"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for CallType {
|
||||
fn as_ref(&self) -> &str {
|
||||
match *self {
|
||||
CallType::Upload(ref proto) => proto.as_ref(),
|
||||
CallType::Standard => "standard-request"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct FieldCursor(Vec<String>);
|
||||
|
||||
@@ -88,6 +158,49 @@ impl FieldCursor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn did_you_mean(value: &str, possible_values: &[&str]) -> Option<String> {
|
||||
if value.len() == 0 {
|
||||
return None
|
||||
}
|
||||
|
||||
let mut last_c = FIELD_SEP;
|
||||
|
||||
let mut field = String::new();
|
||||
let mut output = String::new();
|
||||
|
||||
let push_field = |fs: &mut String, f: &mut String| {
|
||||
if f.len() > 0 {
|
||||
fs.push_str(
|
||||
match did_you_mean(&f, possible_values) {
|
||||
Some(candidate) => candidate,
|
||||
None => &f,
|
||||
});
|
||||
f.truncate(0);
|
||||
}
|
||||
};
|
||||
|
||||
for (cid, c) in value.chars().enumerate() {
|
||||
if c == FIELD_SEP {
|
||||
if last_c != FIELD_SEP {
|
||||
push_field(&mut output, &mut field);
|
||||
}
|
||||
output.push(c);
|
||||
} else {
|
||||
field.push(c);
|
||||
}
|
||||
|
||||
last_c = c;
|
||||
}
|
||||
|
||||
push_field(&mut output, &mut field);
|
||||
|
||||
if &output == value {
|
||||
None
|
||||
} else {
|
||||
Some(output)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_fields(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
@@ -112,6 +225,17 @@ pub fn parse_kv_arg<'a>(kv: &'a str, err: &mut InvalidOptionsError, for_hashmap:
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calltype_from_str(name: &str, valid_protocols: Vec<String>, err: &mut InvalidOptionsError) -> CallType {
|
||||
CallType::Upload(
|
||||
match UploadProtocol::from_str(name) {
|
||||
Ok(up) => up,
|
||||
Err(msg) => {
|
||||
err.issues.push(CLIError::InvalidUploadProtocol(name.to_string(), valid_protocols));
|
||||
UploadProtocol::Simple
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn input_file_from_opts(file_path: &str, err: &mut InvalidOptionsError) -> Option<fs::File> {
|
||||
match fs::File::open(file_path) {
|
||||
Ok(f) => Some(f),
|
||||
@@ -132,13 +256,14 @@ pub fn input_mime_from_opts(mime: &str, err: &mut InvalidOptionsError) -> Option
|
||||
}
|
||||
}
|
||||
|
||||
// May panic if we can't open the file - this is anticipated, we can't currently communicate this
|
||||
// kind of error: TODO: fix this architecture :)
|
||||
pub fn writer_from_opts(flag: bool, arg: &str) -> Box<Write> {
|
||||
if !flag || arg == "-" {
|
||||
Box::new(stdout())
|
||||
} else {
|
||||
Box::new(fs::OpenOptions::new().create(true).write(true).open(arg).unwrap())
|
||||
pub fn writer_from_opts(arg: Option<&str>) -> Result<Box<Write>, io::Error> {
|
||||
let f = arg.unwrap_or("-");
|
||||
match f {
|
||||
"-" => Ok(Box::new(stdout())),
|
||||
_ => match fs::OpenOptions::new().create(true).write(true).open(f) {
|
||||
Ok(f) => Ok(Box::new(f)),
|
||||
Err(io_err) => Err(io_err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +276,7 @@ pub fn arg_from_str<T>(arg: &str, err: &mut InvalidOptionsError,
|
||||
match FromStr::from_str(arg) {
|
||||
Err(perr) => {
|
||||
err.issues.push(
|
||||
CLIError::ParseError((arg_name, arg_type, arg.to_string(), format!("{}", perr)))
|
||||
CLIError::ParseError(arg_name, arg_type, arg.to_string(), format!("{}", perr))
|
||||
);
|
||||
Default::default()
|
||||
},
|
||||
@@ -171,49 +296,47 @@ impl JsonTokenStorage {
|
||||
}
|
||||
|
||||
impl TokenStorage for JsonTokenStorage {
|
||||
type Error = io::Error;
|
||||
type Error = json::Error;
|
||||
|
||||
// NOTE: logging might be interesting, currently we swallow all errors
|
||||
fn set(&mut self, scope_hash: u64, _: &Vec<&str>, token: Option<Token>) -> Option<io::Error> {
|
||||
fn set(&mut self, scope_hash: u64, _: &Vec<&str>, token: Option<Token>) -> Result<(), json::Error> {
|
||||
match token {
|
||||
None => {
|
||||
match fs::remove_file(self.path(scope_hash)) {
|
||||
Err(err) =>
|
||||
match err.kind() {
|
||||
io::ErrorKind::NotFound => None,
|
||||
_ => Some(err)
|
||||
io::ErrorKind::NotFound => Ok(()),
|
||||
_ => Err(json::Error::IoError(err))
|
||||
},
|
||||
Ok(_) => None
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
Some(token) => {
|
||||
let json_token = json::encode(&token).unwrap();
|
||||
match fs::OpenOptions::new().create(true).write(true).open(&self.path(scope_hash)) {
|
||||
Ok(mut f) => {
|
||||
match f.write(json_token.as_bytes()) {
|
||||
Ok(_) => None,
|
||||
Err(io_err) => Some(io_err),
|
||||
match json::to_writer_pretty(&mut f, &token) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(io_err) => Err(json::Error::IoError(io_err)),
|
||||
}
|
||||
},
|
||||
Err(io_err) => Some(io_err)
|
||||
Err(io_err) => Err(json::Error::IoError(io_err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, io::Error> {
|
||||
fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, json::Error> {
|
||||
match fs::File::open(&self.path(scope_hash)) {
|
||||
Ok(mut f) => {
|
||||
let mut json_string = String::new();
|
||||
match f.read_to_string(&mut json_string) {
|
||||
Ok(_) => Ok(Some(json::decode::<Token>(&json_string).unwrap())),
|
||||
Err(io_err) => Err(io_err),
|
||||
match json::de::from_reader(f) {
|
||||
Ok(token) => Ok(Some(token)),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
},
|
||||
Err(io_err) => {
|
||||
match io_err.kind() {
|
||||
io::ErrorKind::NotFound => Ok(None),
|
||||
_ => Err(io_err)
|
||||
_ => Err(json::Error::IoError(io_err))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +346,7 @@ impl TokenStorage for JsonTokenStorage {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ApplicationSecretError {
|
||||
DecoderError((String, json::DecoderError)),
|
||||
DecoderError((String, json::Error)),
|
||||
FormatError(String),
|
||||
}
|
||||
|
||||
@@ -231,10 +354,10 @@ impl fmt::Display for ApplicationSecretError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
ApplicationSecretError::DecoderError((ref path, ref err))
|
||||
=> writeln!(f, "Could not decode file at '{}' with error: {}",
|
||||
=> writeln!(f, "Could not decode file at '{}' with error: {}.",
|
||||
path, err),
|
||||
ApplicationSecretError::FormatError(ref path)
|
||||
=> writeln!(f, "'installed' field is unset in secret file at '{}'",
|
||||
=> writeln!(f, "'installed' field is unset in secret file at '{}'.",
|
||||
path),
|
||||
}
|
||||
}
|
||||
@@ -253,15 +376,15 @@ impl fmt::Display for ConfigurationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
ConfigurationError::DirectoryCreationFailed((ref dir, ref err))
|
||||
=> writeln!(f, "Directory '{}' could not be created with error: {}", dir, err),
|
||||
=> writeln!(f, "Directory '{}' could not be created with error: {}.", dir, err),
|
||||
ConfigurationError::DirectoryUnset
|
||||
=> writeln!(f, "--config-dir was unset or empty"),
|
||||
=> writeln!(f, "--config-dir was unset or empty."),
|
||||
ConfigurationError::HomeExpansionFailed(ref dir)
|
||||
=> writeln!(f, "Couldn't find HOME directory of current user, failed to expand '{}'", dir),
|
||||
=> writeln!(f, "Couldn't find HOME directory of current user, failed to expand '{}'.", dir),
|
||||
ConfigurationError::Secret(ref err)
|
||||
=> writeln!(f, "Secret -> {}", err),
|
||||
ConfigurationError::IOError((ref path, ref err))
|
||||
=> writeln!(f, "IO operation failed on path '{}' with error: {}", path, err),
|
||||
=> writeln!(f, "IO operation failed on path '{}' with error: {}.", path, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,9 +399,9 @@ impl fmt::Display for InputError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
InputError::IOError((ref file_path, ref io_err))
|
||||
=> writeln!(f, "Failed to open '{}' for reading with error: {}", file_path, io_err),
|
||||
=> writeln!(f, "Failed to open '{}' for reading with error: {}.", file_path, io_err),
|
||||
InputError::Mime(ref mime)
|
||||
=> writeln!(f, "'{}' is not a known mime-type", mime),
|
||||
=> writeln!(f, "'{}' is not a known mime-type.", mime),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,7 +410,7 @@ impl fmt::Display for InputError {
|
||||
pub enum FieldError {
|
||||
PopOnEmpty(String),
|
||||
TrailingFieldSep(String),
|
||||
Unknown(String),
|
||||
Unknown(String, Option<String>, Option<String>),
|
||||
Empty,
|
||||
}
|
||||
|
||||
@@ -296,13 +419,26 @@ impl fmt::Display for FieldError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
FieldError::PopOnEmpty(ref field)
|
||||
=> writeln!(f, "'{}': Cannot move up on empty field cursor", field),
|
||||
=> writeln!(f, "'{}': Cannot move up on empty field cursor.", field),
|
||||
FieldError::TrailingFieldSep(ref field)
|
||||
=> writeln!(f, "'{}': Single field separator may not be last character", field),
|
||||
FieldError::Unknown(ref field)
|
||||
=> writeln!(f, "Field '{}' does not exist", field),
|
||||
=> writeln!(f, "'{}': Single field separator may not be last character.", field),
|
||||
FieldError::Unknown(ref field, ref suggestion, ref value) => {
|
||||
let suffix =
|
||||
match *suggestion {
|
||||
Some(ref s) => {
|
||||
let kv =
|
||||
match *value {
|
||||
Some(ref v) => format!("{}={}", s, v),
|
||||
None => s.clone(),
|
||||
};
|
||||
format!(" Did you mean '{}' ?", kv)
|
||||
},
|
||||
None => String::new(),
|
||||
};
|
||||
writeln!(f, "Field '{}' does not exist.{}", field, suffix)
|
||||
},
|
||||
FieldError::Empty
|
||||
=> writeln!(f, "Field names must not be empty"),
|
||||
=> writeln!(f, "Field names must not be empty."),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,11 +447,14 @@ impl fmt::Display for FieldError {
|
||||
#[derive(Debug)]
|
||||
pub enum CLIError {
|
||||
Configuration(ConfigurationError),
|
||||
ParseError((&'static str, &'static str, String, String)),
|
||||
UnknownParameter(String),
|
||||
ParseError(&'static str, &'static str, String, String),
|
||||
UnknownParameter(String, Vec<&'static str>),
|
||||
InvalidUploadProtocol(String, Vec<String>),
|
||||
InvalidKeyValueSyntax(String, bool),
|
||||
Input(InputError),
|
||||
Field(FieldError),
|
||||
MissingCommandError,
|
||||
MissingMethodError(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for CLIError {
|
||||
@@ -324,15 +463,25 @@ impl fmt::Display for CLIError {
|
||||
CLIError::Configuration(ref err) => write!(f, "Configuration -> {}", err),
|
||||
CLIError::Input(ref err) => write!(f, "Input -> {}", err),
|
||||
CLIError::Field(ref err) => write!(f, "Field -> {}", err),
|
||||
CLIError::ParseError((arg_name, type_name, ref value, ref err_desc))
|
||||
=> writeln!(f, "Failed to parse argument '{}' with value '{}' as {} with error: {}",
|
||||
CLIError::InvalidUploadProtocol(ref proto_name, ref valid_names)
|
||||
=> writeln!(f, "'{}' is not a valid upload protocol. Choose from one of {}.", proto_name, valid_names.connect(", ")),
|
||||
CLIError::ParseError(arg_name, type_name, ref value, ref err_desc)
|
||||
=> writeln!(f, "Failed to parse argument '{}' with value '{}' as {} with error: {}.",
|
||||
arg_name, value, type_name, err_desc),
|
||||
CLIError::UnknownParameter(ref param_name)
|
||||
=> writeln!(f, "Parameter '{}' is unknown.", param_name),
|
||||
CLIError::UnknownParameter(ref param_name, ref possible_values) => {
|
||||
let mut suffix =
|
||||
match did_you_mean(param_name, &possible_values) {
|
||||
Some(v) => format!(" Did you mean '{}' ?", v),
|
||||
None => String::new(),
|
||||
};
|
||||
write!(f, "Parameter '{}' is unknown.{}\n", param_name, suffix)
|
||||
},
|
||||
CLIError::InvalidKeyValueSyntax(ref kv, is_hashmap) => {
|
||||
let hashmap_info = if is_hashmap { "hashmap " } else { "" };
|
||||
writeln!(f, "'{}' does not match {}pattern <key>=<value>", kv, hashmap_info)
|
||||
writeln!(f, "'{}' does not match {}pattern <key>=<value>.", kv, hashmap_info)
|
||||
},
|
||||
CLIError::MissingCommandError => writeln!(f, "Please specify the main sub-command."),
|
||||
CLIError::MissingMethodError(ref cmd) => writeln!(f, "Please specify the method to call on the '{}' command.", cmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +548,7 @@ pub fn assure_config_dir_exists(dir: &str) -> Result<String, CLIError> {
|
||||
|
||||
pub fn application_secret_from_directory(dir: &str,
|
||||
secret_basename: &str,
|
||||
json_app_secret: &str)
|
||||
json_console_secret: &str)
|
||||
-> Result<ApplicationSecret, CLIError> {
|
||||
let secret_path = Path::new(dir).join(secret_basename);
|
||||
let secret_str = || secret_path.as_path().to_str().unwrap().to_string();
|
||||
@@ -418,7 +567,10 @@ pub fn application_secret_from_directory(dir: &str,
|
||||
err = match fs::OpenOptions::new().create(true).write(true).open(&secret_path) {
|
||||
Err(cfe) => cfe,
|
||||
Ok(mut f) => {
|
||||
match f.write(json_app_secret.as_bytes()) {
|
||||
// Assure we convert 'ugly' json string into pretty one
|
||||
let console_secret: ConsoleApplicationSecret
|
||||
= json::from_str(json_console_secret).unwrap();
|
||||
match json::to_writer_pretty(&mut f, &console_secret) {
|
||||
Err(io_err) => io_err,
|
||||
Ok(_) => continue,
|
||||
}
|
||||
@@ -429,23 +581,24 @@ pub fn application_secret_from_directory(dir: &str,
|
||||
return secret_io_error(err)
|
||||
},
|
||||
Ok(mut f) => {
|
||||
let mut json_encoded_secret = String::new();
|
||||
if let Err(io_err) = f.read_to_string(&mut json_encoded_secret) {
|
||||
return secret_io_error(io_err)
|
||||
}
|
||||
match json::decode::<ConsoleApplicationSecret>(&json_encoded_secret) {
|
||||
Err(json_decode_error) => return Err(CLIError::Configuration(
|
||||
ConfigurationError::Secret(ApplicationSecretError::DecoderError(
|
||||
(secret_str(), json_decode_error)
|
||||
match json::de::from_reader::<_, ConsoleApplicationSecret>(f) {
|
||||
Err(json::Error::IoError(err)) =>
|
||||
return secret_io_error(err),
|
||||
Err(json_err) =>
|
||||
return Err(CLIError::Configuration(
|
||||
ConfigurationError::Secret(
|
||||
ApplicationSecretError::DecoderError(
|
||||
(secret_str(), json_err)
|
||||
)))),
|
||||
Ok(console_secret) => match console_secret.installed {
|
||||
Some(secret) => return Ok(secret),
|
||||
None => return Err(
|
||||
CLIError::Configuration(
|
||||
ConfigurationError::Secret(
|
||||
ApplicationSecretError::FormatError(secret_str())
|
||||
)))
|
||||
},
|
||||
Ok(console_secret) =>
|
||||
match console_secret.installed {
|
||||
Some(secret) => return Ok(secret),
|
||||
None => return Err(
|
||||
CLIError::Configuration(
|
||||
ConfigurationError::Secret(
|
||||
ApplicationSecretError::FormatError(secret_str())
|
||||
)))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,70 +2,55 @@
|
||||
// This file was generated automatically from 'src/mako/cli/main.rs.mako'
|
||||
// DO NOT EDIT !
|
||||
#![feature(plugin, exit_status)]
|
||||
#![plugin(docopt_macros)]
|
||||
#![allow(unused_variables, unused_imports, dead_code, unused_mut)]
|
||||
|
||||
extern crate docopt;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate yup_oauth2 as oauth2;
|
||||
extern crate yup_hyper_mock as mock;
|
||||
extern crate rustc_serialize;
|
||||
extern crate serde;
|
||||
extern crate hyper;
|
||||
extern crate mime;
|
||||
extern crate strsim;
|
||||
extern crate google_cloudlatencytest2 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
cloudlatencytest2 [options] statscollection updateaggregatedstats -r <kv>... [-p <v>...] [-o <out>]
|
||||
cloudlatencytest2 [options] statscollection updatestats -r <kv>... [-p <v>...] [-o <out>]
|
||||
cloudlatencytest2 --help
|
||||
|
||||
All documentation details can be found at
|
||||
http://byron.github.io/google-apis-rs/google_cloudlatencytest2_cli/index.html
|
||||
|
||||
Configuration:
|
||||
--scope <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.
|
||||
--config-dir <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: ~/.google-service-cli]
|
||||
--debug
|
||||
Output all server communication to standard error. `tx` and `rx` are placed
|
||||
into the same stream.
|
||||
--debug-auth
|
||||
Output all communication related to authentication to standard error. `tx`
|
||||
and `rx` are placed into the same stream.
|
||||
");
|
||||
use clap::{App, SubCommand, Arg};
|
||||
|
||||
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, CallType, UploadProtocol,
|
||||
calltype_from_str, remove_json_null_values};
|
||||
|
||||
use std::default::Default;
|
||||
use std::str::FromStr;
|
||||
|
||||
use oauth2::{Authenticator, DefaultAuthenticatorDelegate};
|
||||
use rustc_serialize::json;
|
||||
use serde::json;
|
||||
use clap::ArgMatches;
|
||||
|
||||
struct Engine {
|
||||
opt: Options,
|
||||
enum DoitError {
|
||||
IoError(String, io::Error),
|
||||
ApiError(api::Error),
|
||||
}
|
||||
|
||||
struct Engine<'n, 'a> {
|
||||
opt: ArgMatches<'n, 'a>,
|
||||
hub: api::Cloudlatencytest<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
gp: Vec<&'static str>,
|
||||
gpm: Vec<(&'static str, &'static str)>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _statscollection_updateaggregatedstats(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
impl<'n, 'a> Engine<'n, 'a> {
|
||||
fn _statscollection_updateaggregatedstats(&self, opt: &ArgMatches<'n, 'a>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut request = api::AggregatedStats::default();
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
for kvarg in self.opt.arg_kv.iter() {
|
||||
for kvarg in opt.values_of("kv").unwrap_or(Vec::new()).iter() {
|
||||
let last_errc = err.issues.len();
|
||||
let (key, value) = parse_kv_arg(&*kvarg, err, false);
|
||||
let mut temp_cursor = field_cursor.clone();
|
||||
@@ -81,60 +66,65 @@ impl Engine {
|
||||
}
|
||||
match &temp_cursor.to_string()[..] {
|
||||
_ => {
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string())));
|
||||
let suggestion = FieldCursor::did_you_mean(key, &vec![]);
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string(), suggestion, value.map(|v| v.to_string()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut call = self.hub.statscollection().updateaggregatedstats(request);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
for parg in opt.values_of("v").unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
"alt"
|
||||
|"fields"
|
||||
|"key"
|
||||
|"oauth-token"
|
||||
|"pretty-print"
|
||||
|"quota-user"
|
||||
|"user-ip" => {
|
||||
let map = [
|
||||
("oauth-token", "oauth_token"),
|
||||
("pretty-print", "prettyPrint"),
|
||||
("quota-user", "quotaUser"),
|
||||
("user-ip", "userIp"),
|
||||
];
|
||||
call = call.param(map.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"))
|
||||
},
|
||||
_ => err.issues.push(CLIError::UnknownParameter(key.to_string())),
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
Vec::new() + &self.gp + &[]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = "standard-request";
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
None
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
if self.opt.flag_scope.len() > 0 {
|
||||
call = call.add_scope(&self.opt.flag_scope);
|
||||
for scope in self.opt.values_of("url").unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
"standard-request" => call.doit(),
|
||||
_ => unreachable!(),
|
||||
CallType::Standard => call.doit(),
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Some(api_err),
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
serde::json::to_writer_pretty(&mut ostream, &output_schema).unwrap();
|
||||
None
|
||||
let mut value = json::value::to_value(&output_schema);
|
||||
remove_json_null_values(&mut value);
|
||||
serde::json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _statscollection_updatestats(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
fn _statscollection_updatestats(&self, opt: &ArgMatches<'n, 'a>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut request = api::Stats::default();
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
for kvarg in self.opt.arg_kv.iter() {
|
||||
for kvarg in opt.values_of("kv").unwrap_or(Vec::new()).iter() {
|
||||
let last_errc = err.issues.len();
|
||||
let (key, value) = parse_kv_arg(&*kvarg, err, false);
|
||||
let mut temp_cursor = field_cursor.clone();
|
||||
@@ -153,83 +143,98 @@ impl Engine {
|
||||
request.time = Some(arg_from_str(value.unwrap_or("0.0"), err, "time", "number"));
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string())));
|
||||
let suggestion = FieldCursor::did_you_mean(key, &vec!["time"]);
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string(), suggestion, value.map(|v| v.to_string()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut call = self.hub.statscollection().updatestats(request);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
for parg in opt.values_of("v").unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
"alt"
|
||||
|"fields"
|
||||
|"key"
|
||||
|"oauth-token"
|
||||
|"pretty-print"
|
||||
|"quota-user"
|
||||
|"user-ip" => {
|
||||
let map = [
|
||||
("oauth-token", "oauth_token"),
|
||||
("pretty-print", "prettyPrint"),
|
||||
("quota-user", "quotaUser"),
|
||||
("user-ip", "userIp"),
|
||||
];
|
||||
call = call.param(map.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"))
|
||||
},
|
||||
_ => err.issues.push(CLIError::UnknownParameter(key.to_string())),
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
Vec::new() + &self.gp + &[]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = "standard-request";
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
None
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
if self.opt.flag_scope.len() > 0 {
|
||||
call = call.add_scope(&self.opt.flag_scope);
|
||||
for scope in self.opt.values_of("url").unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
"standard-request" => call.doit(),
|
||||
_ => unreachable!(),
|
||||
CallType::Standard => call.doit(),
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Some(api_err),
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
serde::json::to_writer_pretty(&mut ostream, &output_schema).unwrap();
|
||||
None
|
||||
let mut value = json::value::to_value(&output_schema);
|
||||
remove_json_null_values(&mut value);
|
||||
serde::json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _doit(&self, dry_run: bool) -> (Option<api::Error>, Option<InvalidOptionsError>) {
|
||||
fn _doit(&self, dry_run: bool) -> Result<Result<(), DoitError>, Option<InvalidOptionsError>> {
|
||||
let mut err = InvalidOptionsError::new();
|
||||
let mut call_result: Option<api::Error>;
|
||||
let mut call_result: Result<(), DoitError> = Ok(());
|
||||
let mut err_opt: Option<InvalidOptionsError> = None;
|
||||
|
||||
if self.opt.cmd_statscollection {
|
||||
if self.opt.cmd_updateaggregatedstats {
|
||||
call_result = self._statscollection_updateaggregatedstats(dry_run, &mut err);
|
||||
} else if self.opt.cmd_updatestats {
|
||||
call_result = self._statscollection_updatestats(dry_run, &mut err);
|
||||
} else {
|
||||
unreachable!();
|
||||
match self.opt.subcommand() {
|
||||
("statscollection", Some(opt)) => {
|
||||
match opt.subcommand() {
|
||||
("updateaggregatedstats", Some(opt)) => {
|
||||
call_result = self._statscollection_updateaggregatedstats(opt, dry_run, &mut err);
|
||||
},
|
||||
("updatestats", Some(opt)) => {
|
||||
call_result = self._statscollection_updatestats(opt, dry_run, &mut err);
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::MissingMethodError("statscollection".to_string()));
|
||||
writeln!(io::stderr(), "{}\n", opt.usage()).ok();
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::MissingCommandError);
|
||||
writeln!(io::stderr(), "{}\n", self.opt.usage()).ok();
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
if dry_run {
|
||||
if err.issues.len() > 0 {
|
||||
err_opt = Some(err);
|
||||
}
|
||||
Err(err_opt)
|
||||
} else {
|
||||
Ok(call_result)
|
||||
}
|
||||
(call_result, err_opt)
|
||||
}
|
||||
|
||||
// Please note that this call will fail if any part of the opt can't be handled
|
||||
fn new(opt: Options) -> Result<Engine, InvalidOptionsError> {
|
||||
fn new(opt: ArgMatches<'a, 'n>) -> Result<Engine<'a, 'n>, InvalidOptionsError> {
|
||||
let (config_dir, secret) = {
|
||||
let config_dir = match cmn::assure_config_dir_exists(&opt.flag_config_dir) {
|
||||
let config_dir = match cmn::assure_config_dir_exists(opt.value_of("folder").unwrap_or("~/.google-service-cli")) {
|
||||
Err(e) => return Err(InvalidOptionsError::single(e, 3)),
|
||||
Ok(p) => p,
|
||||
};
|
||||
@@ -242,7 +247,7 @@ impl Engine {
|
||||
};
|
||||
|
||||
let auth = Authenticator::new( &secret, DefaultAuthenticatorDelegate,
|
||||
if opt.flag_debug_auth {
|
||||
if opt.is_present("debug-auth") {
|
||||
hyper::Client::with_connector(mock::TeeConnector {
|
||||
connector: hyper::net::HttpConnector(None)
|
||||
})
|
||||
@@ -255,7 +260,7 @@ impl Engine {
|
||||
}, None);
|
||||
|
||||
let client =
|
||||
if opt.flag_debug {
|
||||
if opt.is_present("debug") {
|
||||
hyper::Client::with_connector(mock::TeeConnector {
|
||||
connector: hyper::net::HttpConnector(None)
|
||||
})
|
||||
@@ -265,37 +270,170 @@ impl Engine {
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::Cloudlatencytest::new(client, auth),
|
||||
gp: vec!["alt", "fields", "key", "oauth-token", "pretty-print", "quota-user", "user-ip"],
|
||||
gpm: vec![
|
||||
("oauth-token", "oauth_token"),
|
||||
("pretty-print", "prettyPrint"),
|
||||
("quota-user", "quotaUser"),
|
||||
("user-ip", "userIp"),
|
||||
]
|
||||
};
|
||||
|
||||
match engine._doit(true) {
|
||||
(_, Some(err)) => Err(err),
|
||||
_ => Ok(engine),
|
||||
Err(Some(err)) => Err(err),
|
||||
Err(None) => Ok(engine),
|
||||
Ok(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the call with all the bells and whistles, informing the caller only if there was an error.
|
||||
// The absense of one indicates success.
|
||||
fn doit(&self) -> Option<api::Error> {
|
||||
self._doit(false).0
|
||||
fn doit(&self) -> Result<(), DoitError> {
|
||||
match self._doit(false) {
|
||||
Ok(res) => res,
|
||||
Err(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let opts: Options = Options::docopt().decode().unwrap_or_else(|e| e.exit());
|
||||
let debug = opts.flag_debug;
|
||||
match Engine::new(opts) {
|
||||
let arg_data = [
|
||||
("statscollection", "methods: 'updateaggregatedstats' and 'updatestats'", vec![
|
||||
("updateaggregatedstats",
|
||||
Some(r##"RPC to update the new TCP stats."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudlatencytest2_cli/statscollection_updateaggregatedstats",
|
||||
vec![
|
||||
(Some(r##"kv"##),
|
||||
Some(r##"r"##),
|
||||
Some(r##"Set various fields of the request structure, matching the key=value form"##),
|
||||
Some(true),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
("updatestats",
|
||||
Some(r##"RPC to update the new TCP stats."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudlatencytest2_cli/statscollection_updatestats",
|
||||
vec![
|
||||
(Some(r##"kv"##),
|
||||
Some(r##"r"##),
|
||||
Some(r##"Set various fields of the request structure, matching the key=value form"##),
|
||||
Some(true),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
]),
|
||||
|
||||
];
|
||||
|
||||
let mut app = App::new("cloudlatencytest2")
|
||||
.author("Sebastian Thiel <byronimo@gmail.com>")
|
||||
.version("0.2.0+20150206")
|
||||
.about("A Test API to report latency data.")
|
||||
.after_help("All documentation details can be found at http://byron.github.io/google-apis-rs/google_cloudlatencytest2_cli")
|
||||
.arg(Arg::with_name("url")
|
||||
.long("scope")
|
||||
.help("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.")
|
||||
.multiple(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("folder")
|
||||
.long("config-dir")
|
||||
.help("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: ~/.google-service-cli")
|
||||
.multiple(false)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("debug")
|
||||
.long("debug")
|
||||
.help("Output all server communication to standard error. `tx` and `rx` are placed into the same stream.")
|
||||
.multiple(false)
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("debug-auth")
|
||||
.long("debug-auth")
|
||||
.help("Output all communication related to authentication to standard error. `tx` and `rx` are placed into the same stream.")
|
||||
.multiple(false)
|
||||
.takes_value(false));
|
||||
|
||||
for &(main_command_name, ref about, ref subcommands) in arg_data.iter() {
|
||||
let mut mcmd = SubCommand::new(main_command_name).about(about);
|
||||
|
||||
for &(sub_command_name, ref desc, url_info, ref args) in subcommands {
|
||||
let mut scmd = SubCommand::new(sub_command_name);
|
||||
if let &Some(desc) = desc {
|
||||
scmd = scmd.about(desc);
|
||||
}
|
||||
scmd = scmd.after_help(url_info);
|
||||
|
||||
for &(ref arg_name, ref flag, ref desc, ref required, ref multi) in args {
|
||||
let arg_name_str =
|
||||
match (arg_name, flag) {
|
||||
(&Some(an), _ ) => an,
|
||||
(_ , &Some(f)) => f,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let mut arg = Arg::with_name(arg_name_str);
|
||||
if let &Some(short_flag) = flag {
|
||||
arg = arg.short(short_flag);
|
||||
}
|
||||
if let &Some(desc) = desc {
|
||||
arg = arg.help(desc);
|
||||
}
|
||||
if arg_name.is_some() && flag.is_some() {
|
||||
arg = arg.takes_value(true);
|
||||
}
|
||||
if let &Some(required) = required {
|
||||
arg = arg.required(required);
|
||||
}
|
||||
if let &Some(multi) = multi {
|
||||
arg = arg.multiple(multi);
|
||||
}
|
||||
scmd = scmd.arg(arg);
|
||||
}
|
||||
mcmd = mcmd.subcommand(scmd);
|
||||
}
|
||||
app = app.subcommand(mcmd);
|
||||
}
|
||||
|
||||
let matches = app.get_matches();
|
||||
|
||||
let debug = matches.is_present("debug");
|
||||
match Engine::new(matches) {
|
||||
Err(err) => {
|
||||
writeln!(io::stderr(), "{}", err).ok();
|
||||
env::set_exit_status(err.exit_code);
|
||||
writeln!(io::stderr(), "{}", err).ok();
|
||||
},
|
||||
Ok(engine) => {
|
||||
if let Some(err) = engine.doit() {
|
||||
if debug {
|
||||
writeln!(io::stderr(), "{:?}", err).ok();
|
||||
} else {
|
||||
writeln!(io::stderr(), "{}", err).ok();
|
||||
}
|
||||
if let Err(doit_err) = engine.doit() {
|
||||
env::set_exit_status(1);
|
||||
match doit_err {
|
||||
DoitError::IoError(path, err) => {
|
||||
writeln!(io::stderr(), "Failed to open output file '{}': {}", path, err).ok();
|
||||
},
|
||||
DoitError::ApiError(err) => {
|
||||
if debug {
|
||||
writeln!(io::stderr(), "{:?}", err).ok();
|
||||
} else {
|
||||
writeln!(io::stderr(), "{}", err).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user