feat(CLI): added first versions of all CLI

That way, changes can be tracked.
Also, we make it official.

Future checkins will only be made if major changes were done,
similar to how the APIs are handled.

Related to #64
This commit is contained in:
Sebastian Thiel
2015-04-16 22:44:40 +02:00
parent fa278a99c7
commit f5f12c5594
476 changed files with 190441 additions and 1038 deletions

View File

@@ -0,0 +1,439 @@
// COPY OF 'src/rust/cli/cmn.rs'
// DO NOT EDIT
use oauth2::{ApplicationSecret, ConsoleApplicationSecret, TokenStorage, Token};
use rustc_serialize::json;
use mime::Mime;
use std::fs;
use std::env;
use std::io;
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::string::ToString;
use std::io::{Write, Read, stdout};
use std::default::Default;
const FIELD_SEP: char = '.';
#[derive(Clone, Default)]
pub struct FieldCursor(Vec<String>);
impl ToString for FieldCursor {
fn to_string(&self) -> String {
self.0.connect(".")
}
}
impl FieldCursor {
pub fn set(&mut self, value: &str) -> Result<(), CLIError> {
if value.len() == 0 {
return Err(CLIError::Field(FieldError::Empty))
}
let mut first_is_field_sep = false;
let mut char_count: usize = 0;
let mut last_c = FIELD_SEP;
let mut num_conscutive_field_seps = 0;
let mut field = String::new();
let mut fields = self.0.clone();
let push_field = |fs: &mut Vec<String>, f: &mut String| {
if f.len() > 0 {
fs.push(f.clone());
f.truncate(0);
}
};
for (cid, c) in value.chars().enumerate() {
char_count += 1;
if c == FIELD_SEP {
if cid == 0 {
first_is_field_sep = true;
}
num_conscutive_field_seps += 1;
if cid > 0 && last_c == FIELD_SEP {
if fields.pop().is_none() {
return Err(CLIError::Field(FieldError::PopOnEmpty(value.to_string())))
}
} else {
push_field(&mut fields, &mut field);
}
} else {
num_conscutive_field_seps = 0;
if cid == 1 {
if first_is_field_sep {
fields.truncate(0);
}
}
field.push(c);
}
last_c = c;
}
push_field(&mut fields, &mut field);
if char_count == 1 && first_is_field_sep {
fields.truncate(0);
}
if char_count > 1 && num_conscutive_field_seps == 1 {
return Err(CLIError::Field(FieldError::TrailingFieldSep(value.to_string())))
}
self.0 = fields;
Ok(())
}
pub fn num_fields(&self) -> usize {
self.0.len()
}
}
pub fn parse_kv_arg<'a>(kv: &'a str, err: &mut InvalidOptionsError)
-> (&'a str, Option<&'a str>) {
let mut add_err = || err.issues.push(CLIError::InvalidKeyValueSyntax(kv.to_string()));
match kv.rfind('=') {
None => {
add_err();
return (kv, None)
},
Some(pos) => {
let key = &kv[..pos];
if kv.len() <= pos + 1 {
add_err();
return (key, None)
}
(key, Some(&kv[pos+1..]))
}
}
}
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),
Err(io_err) => {
err.issues.push(CLIError::Input(InputError::IOError((file_path.to_string(), io_err))));
None
}
}
}
pub fn input_mime_from_opts(mime: &str, err: &mut InvalidOptionsError) -> Option<Mime> {
match mime.parse() {
Ok(m) => Some(m),
Err(_) => {
err.issues.push(CLIError::Input(InputError::Mime(mime.to_string())));
None
}
}
}
// 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 arg_from_str<T>(arg: &str, err: &mut InvalidOptionsError,
arg_name: &'static str,
arg_type: &'static str) -> T
where T: FromStr + Default,
<T as FromStr>::Err: fmt::Display {
match FromStr::from_str(arg) {
Err(perr) => {
err.issues.push(
CLIError::ParseError((arg_name, arg_type, arg.to_string(), format!("{}", perr)))
);
Default::default()
},
Ok(v) => v,
}
}
pub struct JsonTokenStorage {
pub program_name: &'static str,
pub db_dir: String,
}
impl JsonTokenStorage {
fn path(&self, scope_hash: u64) -> PathBuf {
Path::new(&self.db_dir).join(&format!("{}-token-{}.json", self.program_name, scope_hash))
}
}
impl TokenStorage for JsonTokenStorage {
// NOTE: logging might be interesting, currently we swallow all errors
fn set(&mut self, scope_hash: u64, token: Option<Token>) {
let json_token = json::encode(&token).unwrap();
let res = fs::OpenOptions::new().create(true).write(true).open(&self.path(scope_hash));
if let Ok(mut f) = res {
f.write(json_token.as_bytes()).ok();
}
}
fn get(&self, scope_hash: u64) -> Option<Token> {
if let Ok(mut f) = fs::File::open(&self.path(scope_hash)) {
let mut json_string = String::new();
if let Ok(_) = f.read_to_string(&mut json_string) {
if let Ok(token) = json::decode::<Token>(&json_string) {
return Some(token)
}
}
}
None
}
}
#[derive(Debug)]
pub enum ApplicationSecretError {
DecoderError((String, json::DecoderError)),
FormatError(String),
}
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: {}",
path, err),
ApplicationSecretError::FormatError(ref path)
=> writeln!(f, "'installed' field is unset in secret file at '{}'",
path),
}
}
}
#[derive(Debug)]
pub enum ConfigurationError {
DirectoryCreationFailed((String, io::Error)),
DirectoryUnset,
HomeExpansionFailed(String),
Secret(ApplicationSecretError),
IOError((String, io::Error)),
}
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),
ConfigurationError::DirectoryUnset
=> 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),
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),
}
}
}
#[derive(Debug)]
pub enum InputError {
IOError((String, io::Error)),
Mime(String),
}
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),
InputError::Mime(ref mime)
=> writeln!(f, "'{}' is not a known mime-type", mime),
}
}
}
#[derive(Debug)]
pub enum FieldError {
PopOnEmpty(String),
TrailingFieldSep(String),
Unknown(String),
Empty,
}
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),
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),
FieldError::Empty
=> writeln!(f, "Field names must not be empty"),
}
}
}
#[derive(Debug)]
pub enum CLIError {
Configuration(ConfigurationError),
ParseError((&'static str, &'static str, String, String)),
UnknownParameter(String),
InvalidKeyValueSyntax(String),
Input(InputError),
Field(FieldError),
}
impl fmt::Display for CLIError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
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: {}",
arg_name, value, type_name, err_desc),
CLIError::UnknownParameter(ref param_name)
=> writeln!(f, "Parameter '{}' is unknown.", param_name),
CLIError::InvalidKeyValueSyntax(ref kv)
=> writeln!(f, "'{}' does not match pattern <key>=<value>", kv),
}
}
}
#[derive(Debug)]
pub struct InvalidOptionsError {
pub issues: Vec<CLIError>,
pub exit_code: i32,
}
impl fmt::Display for InvalidOptionsError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
for issue in &self.issues {
try!(issue.fmt(f));
}
Ok(())
}
}
impl InvalidOptionsError {
pub fn single(err: CLIError, exit_code: i32) -> InvalidOptionsError {
InvalidOptionsError {
issues: vec![err],
exit_code: exit_code,
}
}
pub fn new() -> InvalidOptionsError {
InvalidOptionsError {
issues: Vec::new(),
exit_code: 1,
}
}
}
pub fn assure_config_dir_exists(dir: &str) -> Result<String, CLIError> {
let trdir = dir.trim();
if trdir.len() == 0 {
return Err(CLIError::Configuration(ConfigurationError::DirectoryUnset))
}
let expanded_config_dir =
if trdir.as_bytes()[0] == b'~' {
match env::var("HOME").ok().or(env::var("UserProfile").ok()) {
None => return Err(CLIError::Configuration(ConfigurationError::HomeExpansionFailed(trdir.to_string()))),
Some(mut user) => {
user.push_str(&trdir[1..]);
user
}
}
} else {
trdir.to_string()
};
if let Err(err) = fs::create_dir(&expanded_config_dir) {
if err.kind() != io::ErrorKind::AlreadyExists {
return Err(CLIError::Configuration(
ConfigurationError::DirectoryCreationFailed((expanded_config_dir, err))))
}
}
Ok(expanded_config_dir)
}
pub fn application_secret_from_directory(dir: &str, secret_basename: &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();
let secret_io_error = |io_err: io::Error| {
Err(CLIError::Configuration(ConfigurationError::IOError(
(secret_str(), io_err)
)))
};
for _ in 0..2 {
match fs::File::open(&secret_path) {
Err(mut err) => {
if err.kind() == io::ErrorKind::NotFound {
// Write our built-in one - user may adjust the written file at will
let secret = ApplicationSecret {
client_id: "14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com".to_string(),
client_secret: "UqkDJd5RFwnHoiG5x5Rub8SI".to_string(),
token_uri: "https://accounts.google.com/o/oauth2/token".to_string(),
auth_uri: Default::default(),
redirect_uris: Default::default(),
client_email: None,
auth_provider_x509_cert_url: None,
client_x509_cert_url: Some("https://www.googleapis.com/oauth2/v1/certs".to_string())
};
let app_secret = ConsoleApplicationSecret {
installed: Some(secret),
web: None,
};
let json_enocded_secret = json::encode(&app_secret).unwrap();
err = match fs::OpenOptions::new().create(true).write(true).open(&secret_path) {
Err(cfe) => cfe,
Ok(mut f) => {
match f.write(json_enocded_secret.as_bytes()) {
Err(io_err) => io_err,
Ok(_) => continue,
}
}
};
// fall through to IO error handling
}
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)
)))),
Ok(console_secret) => match console_secret.installed {
Some(secret) => return Ok(secret),
None => return Err(
CLIError::Configuration(
ConfigurationError::Secret(
ApplicationSecretError::FormatError(secret_str())
)))
},
}
}
}
}
unreachable!();
}

View File

@@ -0,0 +1,628 @@
// DO NOT EDIT !
// 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;
extern crate yup_oauth2 as oauth2;
extern crate rustc_serialize;
extern crate serde;
extern crate hyper;
extern crate mime;
extern crate google_taskqueue1_beta2 as api;
use std::env;
use std::io::{self, Write};
docopt!(Options derive Debug, "
Usage:
taskqueue1-beta2 [options] taskqueues get <project> <taskqueue> [-p <v>]... [-o <out>]
taskqueue1-beta2 [options] tasks delete <project> <taskqueue> <task> [-p <v>]...
taskqueue1-beta2 [options] tasks get <project> <taskqueue> <task> [-p <v>]... [-o <out>]
taskqueue1-beta2 [options] tasks insert <project> <taskqueue> -r <kv>... [-p <v>]... [-o <out>]
taskqueue1-beta2 [options] tasks lease <project> <taskqueue> <num-tasks> <lease-secs> [-p <v>]... [-o <out>]
taskqueue1-beta2 [options] tasks list <project> <taskqueue> [-p <v>]... [-o <out>]
taskqueue1-beta2 [options] tasks patch <project> <taskqueue> <task> <new-lease-seconds> -r <kv>... [-p <v>]... [-o <out>]
taskqueue1-beta2 [options] tasks update <project> <taskqueue> <task> <new-lease-seconds> -r <kv>... [-p <v>]... [-o <out>]
taskqueue1-beta2 --help
All documentation details can be found TODO: <URL to github.io docs here, see #51>
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]
");
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};
use std::default::Default;
use std::str::FromStr;
use oauth2::{Authenticator, DefaultAuthenticatorDelegate};
use rustc_serialize::json;
struct Engine {
opt: Options,
hub: api::Taskqueue<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
}
impl Engine {
fn _taskqueues_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut call = self.hub.taskqueues().get(&self.opt.arg_project, &self.opt.arg_taskqueue);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
match key {
"get-stats" => {
call = call.get_stats(arg_from_str(value.unwrap_or("false"), err, "get-stats", "boolean"));
},
"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 protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _tasks_delete(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut call = self.hub.tasks().delete(&self.opt.arg_project, &self.opt.arg_taskqueue, &self.opt.arg_task);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
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 protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok(mut response) => {
println!("DEBUG: REMOVE ME {:?}", response);
None
}
}
}
}
fn _tasks_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut call = self.hub.tasks().get(&self.opt.arg_project, &self.opt.arg_taskqueue, &self.opt.arg_task);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
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 protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _tasks_insert(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut request: api::Task = Default::default();
let mut call = self.hub.tasks().insert(&request, &self.opt.arg_project, &self.opt.arg_taskqueue);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
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 field_name: FieldCursor = Default::default();
for kvarg in self.opt.arg_kv.iter() {
let (key, value) = parse_kv_arg(&*kvarg, err);
if let Err(field_err) = field_name.set(&*key) {
err.issues.push(field_err);
}
match &field_name.to_string()[..] {
"kind" => {
request.kind = Some(value.unwrap_or("").to_string());
},
"lease-timestamp" => {
request.lease_timestamp = Some(value.unwrap_or("").to_string());
},
"id" => {
request.id = Some(value.unwrap_or("").to_string());
},
"retry-count" => {
request.retry_count = Some(arg_from_str(value.unwrap_or("-0"), err, "retry-count", "integer"));
},
"tag" => {
request.tag = Some(value.unwrap_or("").to_string());
},
"payload-base64" => {
request.payload_base64 = Some(value.unwrap_or("").to_string());
},
"queue-name" => {
request.queue_name = Some(value.unwrap_or("").to_string());
},
"enqueue-timestamp" => {
request.enqueue_timestamp = Some(value.unwrap_or("").to_string());
},
_ => {
err.issues.push(CLIError::Field(FieldError::Unknown(field_name.to_string())));
}
}
}
let protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _tasks_lease(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let num_tasks: i32 = arg_from_str(&self.opt.arg_num_tasks, err, "<num-tasks>", "integer");
let lease_secs: i32 = arg_from_str(&self.opt.arg_lease_secs, err, "<lease-secs>", "integer");
let mut call = self.hub.tasks().lease(&self.opt.arg_project, &self.opt.arg_taskqueue, num_tasks, lease_secs);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
match key {
"tag" => {
call = call.tag(value.unwrap_or(""));
},
"group-by-tag" => {
call = call.group_by_tag(arg_from_str(value.unwrap_or("false"), err, "group-by-tag", "boolean"));
},
"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 protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _tasks_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut call = self.hub.tasks().list(&self.opt.arg_project, &self.opt.arg_taskqueue);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
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 protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _tasks_patch(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut request: api::Task = Default::default();
let new_lease_seconds: i32 = arg_from_str(&self.opt.arg_new_lease_seconds, err, "<new-lease-seconds>", "integer");
let mut call = self.hub.tasks().patch(&request, &self.opt.arg_project, &self.opt.arg_taskqueue, &self.opt.arg_task, new_lease_seconds);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
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 field_name: FieldCursor = Default::default();
for kvarg in self.opt.arg_kv.iter() {
let (key, value) = parse_kv_arg(&*kvarg, err);
if let Err(field_err) = field_name.set(&*key) {
err.issues.push(field_err);
}
match &field_name.to_string()[..] {
"kind" => {
request.kind = Some(value.unwrap_or("").to_string());
},
"lease-timestamp" => {
request.lease_timestamp = Some(value.unwrap_or("").to_string());
},
"id" => {
request.id = Some(value.unwrap_or("").to_string());
},
"retry-count" => {
request.retry_count = Some(arg_from_str(value.unwrap_or("-0"), err, "retry-count", "integer"));
},
"tag" => {
request.tag = Some(value.unwrap_or("").to_string());
},
"payload-base64" => {
request.payload_base64 = Some(value.unwrap_or("").to_string());
},
"queue-name" => {
request.queue_name = Some(value.unwrap_or("").to_string());
},
"enqueue-timestamp" => {
request.enqueue_timestamp = Some(value.unwrap_or("").to_string());
},
_ => {
err.issues.push(CLIError::Field(FieldError::Unknown(field_name.to_string())));
}
}
}
let protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _tasks_update(&self, dry_run: bool, err: &mut InvalidOptionsError)
-> Option<api::Error> {
let mut request: api::Task = Default::default();
let new_lease_seconds: i32 = arg_from_str(&self.opt.arg_new_lease_seconds, err, "<new-lease-seconds>", "integer");
let mut call = self.hub.tasks().update(&request, &self.opt.arg_project, &self.opt.arg_taskqueue, &self.opt.arg_task, new_lease_seconds);
for parg in self.opt.arg_v.iter() {
let (key, value) = parse_kv_arg(&*parg, err);
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 field_name: FieldCursor = Default::default();
for kvarg in self.opt.arg_kv.iter() {
let (key, value) = parse_kv_arg(&*kvarg, err);
if let Err(field_err) = field_name.set(&*key) {
err.issues.push(field_err);
}
match &field_name.to_string()[..] {
"kind" => {
request.kind = Some(value.unwrap_or("").to_string());
},
"lease-timestamp" => {
request.lease_timestamp = Some(value.unwrap_or("").to_string());
},
"id" => {
request.id = Some(value.unwrap_or("").to_string());
},
"retry-count" => {
request.retry_count = Some(arg_from_str(value.unwrap_or("-0"), err, "retry-count", "integer"));
},
"tag" => {
request.tag = Some(value.unwrap_or("").to_string());
},
"payload-base64" => {
request.payload_base64 = Some(value.unwrap_or("").to_string());
},
"queue-name" => {
request.queue_name = Some(value.unwrap_or("").to_string());
},
"enqueue-timestamp" => {
request.enqueue_timestamp = Some(value.unwrap_or("").to_string());
},
_ => {
err.issues.push(CLIError::Field(FieldError::Unknown(field_name.to_string())));
}
}
}
let protocol = "standard-request";
if dry_run {
None
} else {
assert!(err.issues.len() == 0);
let mut ostream = writer_from_opts(self.opt.flag_o, &self.opt.arg_out);
match match protocol {
"standard-request" => call.doit(),
_ => unreachable!(),
} {
Err(api_err) => Some(api_err),
Ok((mut response, output_schema)) => {
println!("DEBUG: REMOVE ME {:?}", response);
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
None
}
}
}
}
fn _doit(&self, dry_run: bool) -> (Option<api::Error>, Option<InvalidOptionsError>) {
let mut err = InvalidOptionsError::new();
let mut call_result: Option<api::Error>;
let mut err_opt: Option<InvalidOptionsError> = None;
if self.opt.cmd_taskqueues {
if self.opt.cmd_get {
call_result = self._taskqueues_get(dry_run, &mut err);
} else {
unreachable!();
}
} else if self.opt.cmd_tasks {
if self.opt.cmd_delete {
call_result = self._tasks_delete(dry_run, &mut err);
} else if self.opt.cmd_get {
call_result = self._tasks_get(dry_run, &mut err);
} else if self.opt.cmd_insert {
call_result = self._tasks_insert(dry_run, &mut err);
} else if self.opt.cmd_lease {
call_result = self._tasks_lease(dry_run, &mut err);
} else if self.opt.cmd_list {
call_result = self._tasks_list(dry_run, &mut err);
} else if self.opt.cmd_patch {
call_result = self._tasks_patch(dry_run, &mut err);
} else if self.opt.cmd_update {
call_result = self._tasks_update(dry_run, &mut err);
} else {
unreachable!();
}
} else {
unreachable!();
}
if dry_run {
if err.issues.len() > 0 {
err_opt = Some(err);
}
}
(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> {
let (config_dir, secret) = {
let config_dir = match cmn::assure_config_dir_exists(&opt.flag_config_dir) {
Err(e) => return Err(InvalidOptionsError::single(e, 3)),
Ok(p) => p,
};
match cmn::application_secret_from_directory(&config_dir, "taskqueue1-beta2-secret.json") {
Ok(secret) => (config_dir, secret),
Err(e) => return Err(InvalidOptionsError::single(e, 4))
}
};
let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate,
hyper::Client::new(),
JsonTokenStorage {
program_name: "taskqueue1-beta2",
db_dir: config_dir.clone(),
}, None);
let engine = Engine {
opt: opt,
hub: api::Taskqueue::new(hyper::Client::new(), auth),
};
match engine._doit(true) {
(_, Some(err)) => Err(err),
_ => Ok(engine),
}
}
// 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 main() {
let opts: Options = Options::docopt().decode().unwrap_or_else(|e| e.exit());
match Engine::new(opts) {
Err(err) => {
write!(io::stderr(), "{}", err).ok();
env::set_exit_status(err.exit_code);
},
Ok(engine) => {
if let Some(err) = engine.doit() {
write!(io::stderr(), "{}", err).ok();
env::set_exit_status(1);
}
}
}
}