mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-19 01:40:05 +01:00
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:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,7 +2,6 @@
|
||||
.pyenv
|
||||
.virtualenv
|
||||
gen/doc/
|
||||
gen/*-cli/
|
||||
*.go
|
||||
*.pyc
|
||||
**target/
|
||||
|
||||
30
gen/adexchangebuyer1d3-cli/Cargo.toml
Normal file
30
gen/adexchangebuyer1d3-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-adexchangebuyer1d3-cli"
|
||||
version = "0.0.1+20150323"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with Ad Exchange Buyer (protocol v1.3)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/adexchangebuyer1d3-cli"
|
||||
homepage = "https://developers.google.com/ad-exchange/buyer-rest"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_adexchangebuyer1d3_cli"
|
||||
license = "MIT"
|
||||
keywords = ["adexchangebuyer", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "adexchangebuyer1d3"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-adexchangebuyer1d3]
|
||||
path = "../adexchangebuyer1d3"
|
||||
30
gen/adexchangebuyer1d3-cli/LICENSE.md
Normal file
30
gen/adexchangebuyer1d3-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/adexchangebuyer1d3-cli/README.md
Normal file
4
gen/adexchangebuyer1d3-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADEXCHANGEBUYER:V1.3
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
37
gen/adexchangebuyer1d3-cli/mkdocs.yml
Normal file
37
gen/adexchangebuyer1d3-cli/mkdocs.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
site_name: Ad Exchange Buyer v0.0.1+20150323
|
||||
site_url: http://byron.github.io/google-apis-rs/google-adexchangebuyer1d3-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/adexchangebuyer1d3-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['accounts_get.md', 'Accounts', 'Get']
|
||||
- ['accounts_list.md', 'Accounts', 'List']
|
||||
- ['accounts_patch.md', 'Accounts', 'Patch']
|
||||
- ['accounts_update.md', 'Accounts', 'Update']
|
||||
- ['billing-info_get.md', 'Billing Info', 'Get']
|
||||
- ['billing-info_list.md', 'Billing Info', 'List']
|
||||
- ['budget_get.md', 'Budget', 'Get']
|
||||
- ['budget_patch.md', 'Budget', 'Patch']
|
||||
- ['budget_update.md', 'Budget', 'Update']
|
||||
- ['creatives_get.md', 'Creatives', 'Get']
|
||||
- ['creatives_insert.md', 'Creatives', 'Insert']
|
||||
- ['creatives_list.md', 'Creatives', 'List']
|
||||
- ['direct-deals_get.md', 'Direct Deals', 'Get']
|
||||
- ['direct-deals_list.md', 'Direct Deals', 'List']
|
||||
- ['performance-report_list.md', 'Performance Report', 'List']
|
||||
- ['pretargeting-config_delete.md', 'Pretargeting Config', 'Delete']
|
||||
- ['pretargeting-config_get.md', 'Pretargeting Config', 'Get']
|
||||
- ['pretargeting-config_insert.md', 'Pretargeting Config', 'Insert']
|
||||
- ['pretargeting-config_list.md', 'Pretargeting Config', 'List']
|
||||
- ['pretargeting-config_patch.md', 'Pretargeting Config', 'Patch']
|
||||
- ['pretargeting-config_update.md', 'Pretargeting Config', 'Update']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/adexchangebuyer1d3-cli/src/cmn.rs
Normal file
439
gen/adexchangebuyer1d3-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
1742
gen/adexchangebuyer1d3-cli/src/main.rs
Normal file
1742
gen/adexchangebuyer1d3-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/adexchangeseller2-cli/Cargo.toml
Normal file
30
gen/adexchangeseller2-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-adexchangeseller2-cli"
|
||||
version = "0.0.1+20150326"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with Ad Exchange Seller (protocol v2.0)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/adexchangeseller2-cli"
|
||||
homepage = "https://developers.google.com/ad-exchange/seller-rest/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_adexchangeseller2_cli"
|
||||
license = "MIT"
|
||||
keywords = ["adexchangeseller", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "adexchangeseller2"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-adexchangeseller2]
|
||||
path = "../adexchangeseller2"
|
||||
30
gen/adexchangeseller2-cli/LICENSE.md
Normal file
30
gen/adexchangeseller2-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/adexchangeseller2-cli/README.md
Normal file
4
gen/adexchangeseller2-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADEXCHANGESELLER:V2.0
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
30
gen/adexchangeseller2-cli/mkdocs.yml
Normal file
30
gen/adexchangeseller2-cli/mkdocs.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
site_name: Ad Exchange Seller v0.0.1+20150326
|
||||
site_url: http://byron.github.io/google-apis-rs/google-adexchangeseller2-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/adexchangeseller2-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['accounts_adclients-list.md', 'Accounts', 'Adclients List']
|
||||
- ['accounts_alerts-list.md', 'Accounts', 'Alerts List']
|
||||
- ['accounts_customchannels-get.md', 'Accounts', 'Customchannels Get']
|
||||
- ['accounts_customchannels-list.md', 'Accounts', 'Customchannels List']
|
||||
- ['accounts_get.md', 'Accounts', 'Get']
|
||||
- ['accounts_list.md', 'Accounts', 'List']
|
||||
- ['accounts_metadata-dimensions-list.md', 'Accounts', 'Metadata Dimensions List']
|
||||
- ['accounts_metadata-metrics-list.md', 'Accounts', 'Metadata Metrics List']
|
||||
- ['accounts_preferreddeals-get.md', 'Accounts', 'Preferreddeals Get']
|
||||
- ['accounts_preferreddeals-list.md', 'Accounts', 'Preferreddeals List']
|
||||
- ['accounts_reports-generate.md', 'Accounts', 'Reports Generate']
|
||||
- ['accounts_reports-saved-generate.md', 'Accounts', 'Reports Saved Generate']
|
||||
- ['accounts_reports-saved-list.md', 'Accounts', 'Reports Saved List']
|
||||
- ['accounts_urlchannels-list.md', 'Accounts', 'Urlchannels List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/adexchangeseller2-cli/src/cmn.rs
Normal file
439
gen/adexchangeseller2-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
855
gen/adexchangeseller2-cli/src/main.rs
Normal file
855
gen/adexchangeseller2-cli/src/main.rs
Normal file
@@ -0,0 +1,855 @@
|
||||
// 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_adexchangeseller2 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
adexchangeseller2 [options] accounts adclients-list <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts alerts-list <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts customchannels-get <account-id> <ad-client-id> <custom-channel-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts customchannels-list <account-id> <ad-client-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts get <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts list [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts metadata-dimensions-list <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts metadata-metrics-list <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts preferreddeals-get <account-id> <deal-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts preferreddeals-list <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts reports-generate <account-id> <start-date> <end-date> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts reports-saved-generate <account-id> <saved-report-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts reports-saved-list <account-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 [options] accounts urlchannels-list <account-id> <ad-client-id> [-p <v>]... [-o <out>]
|
||||
adexchangeseller2 --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::AdExchangeSeller<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _accounts_adclients_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().adclients_list(&self.opt.arg_account_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"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 _accounts_alerts_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().alerts_list(&self.opt.arg_account_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"locale" => {
|
||||
call = call.locale(value.unwrap_or(""));
|
||||
},
|
||||
"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 _accounts_customchannels_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().customchannels_get(&self.opt.arg_account_id, &self.opt.arg_ad_client_id, &self.opt.arg_custom_channel_id);
|
||||
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 _accounts_customchannels_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().customchannels_list(&self.opt.arg_account_id, &self.opt.arg_ad_client_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"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 _accounts_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().get(&self.opt.arg_account_id);
|
||||
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 _accounts_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().list();
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"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 _accounts_metadata_dimensions_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().metadata_dimensions_list(&self.opt.arg_account_id);
|
||||
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 _accounts_metadata_metrics_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().metadata_metrics_list(&self.opt.arg_account_id);
|
||||
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 _accounts_preferreddeals_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().preferreddeals_get(&self.opt.arg_account_id, &self.opt.arg_deal_id);
|
||||
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 _accounts_preferreddeals_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().preferreddeals_list(&self.opt.arg_account_id);
|
||||
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 _accounts_reports_generate(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut download_mode = false;
|
||||
let mut call = self.hub.accounts().reports_generate(&self.opt.arg_account_id, &self.opt.arg_start_date, &self.opt.arg_end_date);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"start-index" => {
|
||||
call = call.start_index(arg_from_str(value.unwrap_or("-0"), err, "start-index", "integer"));
|
||||
},
|
||||
"sort" => {
|
||||
call = call.add_sort(value.unwrap_or(""));
|
||||
},
|
||||
"metric" => {
|
||||
call = call.add_metric(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"locale" => {
|
||||
call = call.locale(value.unwrap_or(""));
|
||||
},
|
||||
"filter" => {
|
||||
call = call.add_filter(value.unwrap_or(""));
|
||||
},
|
||||
"dimension" => {
|
||||
call = call.add_dimension(value.unwrap_or(""));
|
||||
},
|
||||
"alt"
|
||||
|"fields"
|
||||
|"key"
|
||||
|"oauth-token"
|
||||
|"pretty-print"
|
||||
|"quota-user"
|
||||
|"user-ip" => {
|
||||
if key == "alt" && value.unwrap_or("unset") == "media" {
|
||||
download_mode = true;
|
||||
}
|
||||
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);
|
||||
if !download_mode {
|
||||
serde::json::to_writer(&mut ostream, &output_schema).unwrap();
|
||||
} else {
|
||||
io::copy(&mut response, &mut ostream).unwrap();
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _accounts_reports_saved_generate(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().reports_saved_generate(&self.opt.arg_account_id, &self.opt.arg_saved_report_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"start-index" => {
|
||||
call = call.start_index(arg_from_str(value.unwrap_or("-0"), err, "start-index", "integer"));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"locale" => {
|
||||
call = call.locale(value.unwrap_or(""));
|
||||
},
|
||||
"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 _accounts_reports_saved_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().reports_saved_list(&self.opt.arg_account_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"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 _accounts_urlchannels_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.accounts().urlchannels_list(&self.opt.arg_account_id, &self.opt.arg_ad_client_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"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 _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_accounts {
|
||||
if self.opt.cmd_adclients_list {
|
||||
call_result = self._accounts_adclients_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_alerts_list {
|
||||
call_result = self._accounts_alerts_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_customchannels_get {
|
||||
call_result = self._accounts_customchannels_get(dry_run, &mut err);
|
||||
} else if self.opt.cmd_customchannels_list {
|
||||
call_result = self._accounts_customchannels_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_get {
|
||||
call_result = self._accounts_get(dry_run, &mut err);
|
||||
} else if self.opt.cmd_list {
|
||||
call_result = self._accounts_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_metadata_dimensions_list {
|
||||
call_result = self._accounts_metadata_dimensions_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_metadata_metrics_list {
|
||||
call_result = self._accounts_metadata_metrics_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_preferreddeals_get {
|
||||
call_result = self._accounts_preferreddeals_get(dry_run, &mut err);
|
||||
} else if self.opt.cmd_preferreddeals_list {
|
||||
call_result = self._accounts_preferreddeals_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_reports_generate {
|
||||
call_result = self._accounts_reports_generate(dry_run, &mut err);
|
||||
} else if self.opt.cmd_reports_saved_generate {
|
||||
call_result = self._accounts_reports_saved_generate(dry_run, &mut err);
|
||||
} else if self.opt.cmd_reports_saved_list {
|
||||
call_result = self._accounts_reports_saved_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_urlchannels_list {
|
||||
call_result = self._accounts_urlchannels_list(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, "adexchangeseller2-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: "adexchangeseller2",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::AdExchangeSeller::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/admin1_directory-cli/Cargo.toml
Normal file
30
gen/admin1_directory-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-admin1_directory-cli"
|
||||
version = "0.0.1+20150309"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with directory (protocol directory_v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/admin1_directory-cli"
|
||||
homepage = "https://developers.google.com/admin-sdk/directory/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_admin1_directory_cli"
|
||||
license = "MIT"
|
||||
keywords = ["admin", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "admin1-directory"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-admin1_directory]
|
||||
path = "../admin1_directory"
|
||||
30
gen/admin1_directory-cli/LICENSE.md
Normal file
30
gen/admin1_directory-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/admin1_directory-cli/README.md
Normal file
4
gen/admin1_directory-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADMIN:DIRECTORY_V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
83
gen/admin1_directory-cli/mkdocs.yml
Normal file
83
gen/admin1_directory-cli/mkdocs.yml
Normal file
@@ -0,0 +1,83 @@
|
||||
site_name: directory v0.0.1+20150309
|
||||
site_url: http://byron.github.io/google-apis-rs/google-admin1_directory-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/admin1_directory-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['asps_delete.md', 'Asps', 'Delete']
|
||||
- ['asps_get.md', 'Asps', 'Get']
|
||||
- ['asps_list.md', 'Asps', 'List']
|
||||
- ['channels_stop.md', 'Channels', 'Stop']
|
||||
- ['chromeosdevices_get.md', 'Chromeosdevices', 'Get']
|
||||
- ['chromeosdevices_list.md', 'Chromeosdevices', 'List']
|
||||
- ['chromeosdevices_patch.md', 'Chromeosdevices', 'Patch']
|
||||
- ['chromeosdevices_update.md', 'Chromeosdevices', 'Update']
|
||||
- ['groups_aliases-delete.md', 'Groups', 'Aliases Delete']
|
||||
- ['groups_aliases-insert.md', 'Groups', 'Aliases Insert']
|
||||
- ['groups_aliases-list.md', 'Groups', 'Aliases List']
|
||||
- ['groups_delete.md', 'Groups', 'Delete']
|
||||
- ['groups_get.md', 'Groups', 'Get']
|
||||
- ['groups_insert.md', 'Groups', 'Insert']
|
||||
- ['groups_list.md', 'Groups', 'List']
|
||||
- ['groups_patch.md', 'Groups', 'Patch']
|
||||
- ['groups_update.md', 'Groups', 'Update']
|
||||
- ['members_delete.md', 'Members', 'Delete']
|
||||
- ['members_get.md', 'Members', 'Get']
|
||||
- ['members_insert.md', 'Members', 'Insert']
|
||||
- ['members_list.md', 'Members', 'List']
|
||||
- ['members_patch.md', 'Members', 'Patch']
|
||||
- ['members_update.md', 'Members', 'Update']
|
||||
- ['mobiledevices_action.md', 'Mobiledevices', 'Action']
|
||||
- ['mobiledevices_delete.md', 'Mobiledevices', 'Delete']
|
||||
- ['mobiledevices_get.md', 'Mobiledevices', 'Get']
|
||||
- ['mobiledevices_list.md', 'Mobiledevices', 'List']
|
||||
- ['notifications_delete.md', 'Notifications', 'Delete']
|
||||
- ['notifications_get.md', 'Notifications', 'Get']
|
||||
- ['notifications_list.md', 'Notifications', 'List']
|
||||
- ['notifications_patch.md', 'Notifications', 'Patch']
|
||||
- ['notifications_update.md', 'Notifications', 'Update']
|
||||
- ['orgunits_delete.md', 'Orgunits', 'Delete']
|
||||
- ['orgunits_get.md', 'Orgunits', 'Get']
|
||||
- ['orgunits_insert.md', 'Orgunits', 'Insert']
|
||||
- ['orgunits_list.md', 'Orgunits', 'List']
|
||||
- ['orgunits_patch.md', 'Orgunits', 'Patch']
|
||||
- ['orgunits_update.md', 'Orgunits', 'Update']
|
||||
- ['schemas_delete.md', 'Schemas', 'Delete']
|
||||
- ['schemas_get.md', 'Schemas', 'Get']
|
||||
- ['schemas_insert.md', 'Schemas', 'Insert']
|
||||
- ['schemas_list.md', 'Schemas', 'List']
|
||||
- ['schemas_patch.md', 'Schemas', 'Patch']
|
||||
- ['schemas_update.md', 'Schemas', 'Update']
|
||||
- ['tokens_delete.md', 'Tokens', 'Delete']
|
||||
- ['tokens_get.md', 'Tokens', 'Get']
|
||||
- ['tokens_list.md', 'Tokens', 'List']
|
||||
- ['users_aliases-delete.md', 'Users', 'Aliases Delete']
|
||||
- ['users_aliases-insert.md', 'Users', 'Aliases Insert']
|
||||
- ['users_aliases-list.md', 'Users', 'Aliases List']
|
||||
- ['users_aliases-watch.md', 'Users', 'Aliases Watch']
|
||||
- ['users_delete.md', 'Users', 'Delete']
|
||||
- ['users_get.md', 'Users', 'Get']
|
||||
- ['users_insert.md', 'Users', 'Insert']
|
||||
- ['users_list.md', 'Users', 'List']
|
||||
- ['users_make-admin.md', 'Users', 'Make Admin']
|
||||
- ['users_patch.md', 'Users', 'Patch']
|
||||
- ['users_photos-delete.md', 'Users', 'Photos Delete']
|
||||
- ['users_photos-get.md', 'Users', 'Photos Get']
|
||||
- ['users_photos-patch.md', 'Users', 'Photos Patch']
|
||||
- ['users_photos-update.md', 'Users', 'Photos Update']
|
||||
- ['users_undelete.md', 'Users', 'Undelete']
|
||||
- ['users_update.md', 'Users', 'Update']
|
||||
- ['users_watch.md', 'Users', 'Watch']
|
||||
- ['verification-codes_generate.md', 'Verification Codes', 'Generate']
|
||||
- ['verification-codes_invalidate.md', 'Verification Codes', 'Invalidate']
|
||||
- ['verification-codes_list.md', 'Verification Codes', 'List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/admin1_directory-cli/src/cmn.rs
Normal file
439
gen/admin1_directory-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
4769
gen/admin1_directory-cli/src/main.rs
Normal file
4769
gen/admin1_directory-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/admin1_reports-cli/Cargo.toml
Normal file
30
gen/admin1_reports-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-admin1_reports-cli"
|
||||
version = "0.0.1+20150115"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with reports (protocol reports_v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/admin1_reports-cli"
|
||||
homepage = "https://developers.google.com/admin-sdk/reports/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_admin1_reports_cli"
|
||||
license = "MIT"
|
||||
keywords = ["admin", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "admin1-reports"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-admin1_reports]
|
||||
path = "../admin1_reports"
|
||||
30
gen/admin1_reports-cli/LICENSE.md
Normal file
30
gen/admin1_reports-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/admin1_reports-cli/README.md
Normal file
4
gen/admin1_reports-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADMIN:REPORTS_V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
21
gen/admin1_reports-cli/mkdocs.yml
Normal file
21
gen/admin1_reports-cli/mkdocs.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
site_name: reports v0.0.1+20150115
|
||||
site_url: http://byron.github.io/google-apis-rs/google-admin1_reports-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/admin1_reports-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['activities_list.md', 'Activities', 'List']
|
||||
- ['activities_watch.md', 'Activities', 'Watch']
|
||||
- ['channels_stop.md', 'Channels', 'Stop']
|
||||
- ['customer-usage-reports_get.md', 'Customer Usage Reports', 'Get']
|
||||
- ['user-usage-report_get.md', 'User Usage Report', 'Get']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/admin1_reports-cli/src/cmn.rs
Normal file
439
gen/admin1_reports-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
535
gen/admin1_reports-cli/src/main.rs
Normal file
535
gen/admin1_reports-cli/src/main.rs
Normal file
@@ -0,0 +1,535 @@
|
||||
// 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_admin1_reports as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
admin1-reports [options] activities list <user-key> <application-name> [-p <v>]... [-o <out>]
|
||||
admin1-reports [options] activities watch <user-key> <application-name> -r <kv>... [-p <v>]... [-o <out>]
|
||||
admin1-reports [options] channels stop -r <kv>... [-p <v>]...
|
||||
admin1-reports [options] customer-usage-reports get <date> [-p <v>]... [-o <out>]
|
||||
admin1-reports [options] user-usage-report get <user-key> <date> [-p <v>]... [-o <out>]
|
||||
admin1-reports --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::Reports<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _activities_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.activities().list(&self.opt.arg_user_key, &self.opt.arg_application_name);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"start-time" => {
|
||||
call = call.start_time(value.unwrap_or(""));
|
||||
},
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"filters" => {
|
||||
call = call.filters(value.unwrap_or(""));
|
||||
},
|
||||
"event-name" => {
|
||||
call = call.event_name(value.unwrap_or(""));
|
||||
},
|
||||
"end-time" => {
|
||||
call = call.end_time(value.unwrap_or(""));
|
||||
},
|
||||
"customer-id" => {
|
||||
call = call.customer_id(value.unwrap_or(""));
|
||||
},
|
||||
"actor-ip-address" => {
|
||||
call = call.actor_ip_address(value.unwrap_or(""));
|
||||
},
|
||||
"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 _activities_watch(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::Channel = Default::default();
|
||||
let mut call = self.hub.activities().watch(&request, &self.opt.arg_user_key, &self.opt.arg_application_name);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"start-time" => {
|
||||
call = call.start_time(value.unwrap_or(""));
|
||||
},
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"filters" => {
|
||||
call = call.filters(value.unwrap_or(""));
|
||||
},
|
||||
"event-name" => {
|
||||
call = call.event_name(value.unwrap_or(""));
|
||||
},
|
||||
"end-time" => {
|
||||
call = call.end_time(value.unwrap_or(""));
|
||||
},
|
||||
"customer-id" => {
|
||||
call = call.customer_id(value.unwrap_or(""));
|
||||
},
|
||||
"actor-ip-address" => {
|
||||
call = call.actor_ip_address(value.unwrap_or(""));
|
||||
},
|
||||
"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()[..] {
|
||||
"resource-uri" => {
|
||||
request.resource_uri = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"kind" => {
|
||||
request.kind = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"resource-id" => {
|
||||
request.resource_id = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"payload" => {
|
||||
request.payload = Some(arg_from_str(value.unwrap_or("false"), err, "payload", "boolean"));
|
||||
},
|
||||
"token" => {
|
||||
request.token = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"params" => {
|
||||
if request.params.is_none() {
|
||||
request.params = Some(Default::default());
|
||||
}
|
||||
request.params.as_mut().unwrap().push(value.unwrap_or("").to_string());
|
||||
},
|
||||
"expiration" => {
|
||||
request.expiration = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"address" => {
|
||||
request.address = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"type" => {
|
||||
request.type_ = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"id" => {
|
||||
request.id = 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 _channels_stop(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::Channel = Default::default();
|
||||
let mut call = self.hub.channels().stop(&request);
|
||||
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()[..] {
|
||||
"resource-uri" => {
|
||||
request.resource_uri = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"kind" => {
|
||||
request.kind = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"resource-id" => {
|
||||
request.resource_id = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"payload" => {
|
||||
request.payload = Some(arg_from_str(value.unwrap_or("false"), err, "payload", "boolean"));
|
||||
},
|
||||
"token" => {
|
||||
request.token = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"params" => {
|
||||
if request.params.is_none() {
|
||||
request.params = Some(Default::default());
|
||||
}
|
||||
request.params.as_mut().unwrap().push(value.unwrap_or("").to_string());
|
||||
},
|
||||
"expiration" => {
|
||||
request.expiration = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"address" => {
|
||||
request.address = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"type" => {
|
||||
request.type_ = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"id" => {
|
||||
request.id = 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);
|
||||
match match protocol {
|
||||
"standard-request" => call.doit(),
|
||||
_ => unreachable!(),
|
||||
} {
|
||||
Err(api_err) => Some(api_err),
|
||||
Ok(mut response) => {
|
||||
println!("DEBUG: REMOVE ME {:?}", response);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _customer_usage_reports_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.customer_usage_reports().get(&self.opt.arg_date);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"parameters" => {
|
||||
call = call.parameters(value.unwrap_or(""));
|
||||
},
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"customer-id" => {
|
||||
call = call.customer_id(value.unwrap_or(""));
|
||||
},
|
||||
"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 _user_usage_report_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.user_usage_report().get(&self.opt.arg_user_key, &self.opt.arg_date);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"parameters" => {
|
||||
call = call.parameters(value.unwrap_or(""));
|
||||
},
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"filters" => {
|
||||
call = call.filters(value.unwrap_or(""));
|
||||
},
|
||||
"customer-id" => {
|
||||
call = call.customer_id(value.unwrap_or(""));
|
||||
},
|
||||
"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 _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_activities {
|
||||
if self.opt.cmd_list {
|
||||
call_result = self._activities_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_watch {
|
||||
call_result = self._activities_watch(dry_run, &mut err);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else if self.opt.cmd_channels {
|
||||
if self.opt.cmd_stop {
|
||||
call_result = self._channels_stop(dry_run, &mut err);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else if self.opt.cmd_customer_usage_reports {
|
||||
if self.opt.cmd_get {
|
||||
call_result = self._customer_usage_reports_get(dry_run, &mut err);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else if self.opt.cmd_user_usage_report {
|
||||
if self.opt.cmd_get {
|
||||
call_result = self._user_usage_report_get(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, "admin1-reports-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: "admin1-reports",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::Reports::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/admin2_email_migration-cli/Cargo.toml
Normal file
30
gen/admin2_email_migration-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-admin2_email_migration-cli"
|
||||
version = "0.0.1+20150303"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with admin (protocol email_migration_v2)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/admin2_email_migration-cli"
|
||||
homepage = "https://developers.google.com/admin-sdk/email-migration/v2/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_admin2_email_migration_cli"
|
||||
license = "MIT"
|
||||
keywords = ["admin", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "admin2-email-migration"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-admin2_email_migration]
|
||||
path = "../admin2_email_migration"
|
||||
30
gen/admin2_email_migration-cli/LICENSE.md
Normal file
30
gen/admin2_email_migration-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/admin2_email_migration-cli/README.md
Normal file
4
gen/admin2_email_migration-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADMIN:EMAIL_MIGRATION_V2
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
17
gen/admin2_email_migration-cli/mkdocs.yml
Normal file
17
gen/admin2_email_migration-cli/mkdocs.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
site_name: admin v0.0.1+20150303
|
||||
site_url: http://byron.github.io/google-apis-rs/google-admin2_email_migration-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/admin2_email_migration-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['mail_insert.md', 'Mail', 'Insert']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/admin2_email_migration-cli/src/cmn.rs
Normal file
439
gen/admin2_email_migration-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
224
gen/admin2_email_migration-cli/src/main.rs
Normal file
224
gen/admin2_email_migration-cli/src/main.rs
Normal file
@@ -0,0 +1,224 @@
|
||||
// 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_admin2_email_migration as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
admin2-email-migration [options] mail insert <user-key> -r <kv>... -u (simple|resumable) <file> <mime> [-p <v>]...
|
||||
admin2-email-migration --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::Admin<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _mail_insert(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::MailItem = Default::default();
|
||||
let mut call = self.hub.mail().insert(&request, &self.opt.arg_user_key);
|
||||
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()[..] {
|
||||
"is-trash" => {
|
||||
request.is_trash = Some(arg_from_str(value.unwrap_or("false"), err, "is-trash", "boolean"));
|
||||
},
|
||||
"kind" => {
|
||||
request.kind = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"labels" => {
|
||||
if request.labels.is_none() {
|
||||
request.labels = Some(Default::default());
|
||||
}
|
||||
request.labels.as_mut().unwrap().push(value.unwrap_or("").to_string());
|
||||
},
|
||||
"is-draft" => {
|
||||
request.is_draft = Some(arg_from_str(value.unwrap_or("false"), err, "is-draft", "boolean"));
|
||||
},
|
||||
"is-inbox" => {
|
||||
request.is_inbox = Some(arg_from_str(value.unwrap_or("false"), err, "is-inbox", "boolean"));
|
||||
},
|
||||
"is-sent" => {
|
||||
request.is_sent = Some(arg_from_str(value.unwrap_or("false"), err, "is-sent", "boolean"));
|
||||
},
|
||||
"is-starred" => {
|
||||
request.is_starred = Some(arg_from_str(value.unwrap_or("false"), err, "is-starred", "boolean"));
|
||||
},
|
||||
"is-unread" => {
|
||||
request.is_unread = Some(arg_from_str(value.unwrap_or("false"), err, "is-unread", "boolean"));
|
||||
},
|
||||
"is-deleted" => {
|
||||
request.is_deleted = Some(arg_from_str(value.unwrap_or("false"), err, "is-deleted", "boolean"));
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(field_name.to_string())));
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol =
|
||||
if self.opt.cmd_simple {
|
||||
"simple"
|
||||
} else if self.opt.cmd_resumable {
|
||||
"resumable"
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let mut input_file = input_file_from_opts(&self.opt.arg_file, err);
|
||||
let mime_type = input_mime_from_opts(&self.opt.arg_mime, err);
|
||||
if dry_run {
|
||||
None
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
match match protocol {
|
||||
"simple" => call.upload(input_file.unwrap(), mime_type.unwrap()),
|
||||
"resumable" => call.upload_resumable(input_file.unwrap(), mime_type.unwrap()),
|
||||
_ => unreachable!(),
|
||||
} {
|
||||
Err(api_err) => Some(api_err),
|
||||
Ok(mut response) => {
|
||||
println!("DEBUG: REMOVE ME {:?}", response);
|
||||
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_mail {
|
||||
if self.opt.cmd_insert {
|
||||
call_result = self._mail_insert(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, "admin2-email-migration-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: "admin2-email-migration",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::Admin::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/adsense1d4-cli/Cargo.toml
Normal file
30
gen/adsense1d4-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-adsense1d4-cli"
|
||||
version = "0.0.1+20150326"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with AdSense (protocol v1.4)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/adsense1d4-cli"
|
||||
homepage = "https://developers.google.com/adsense/management/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_adsense1d4_cli"
|
||||
license = "MIT"
|
||||
keywords = ["adsense", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "adsense1d4"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-adsense1d4]
|
||||
path = "../adsense1d4"
|
||||
30
gen/adsense1d4-cli/LICENSE.md
Normal file
30
gen/adsense1d4-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/adsense1d4-cli/README.md
Normal file
4
gen/adsense1d4-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADSENSE:V1.4
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
54
gen/adsense1d4-cli/mkdocs.yml
Normal file
54
gen/adsense1d4-cli/mkdocs.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
site_name: AdSense v0.0.1+20150326
|
||||
site_url: http://byron.github.io/google-apis-rs/google-adsense1d4-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/adsense1d4-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['accounts_adclients-list.md', 'Accounts', 'Adclients List']
|
||||
- ['accounts_adunits-customchannels-list.md', 'Accounts', 'Adunits Customchannels List']
|
||||
- ['accounts_adunits-get.md', 'Accounts', 'Adunits Get']
|
||||
- ['accounts_adunits-get-ad-code.md', 'Accounts', 'Adunits Get Ad Code']
|
||||
- ['accounts_adunits-list.md', 'Accounts', 'Adunits List']
|
||||
- ['accounts_alerts-delete.md', 'Accounts', 'Alerts Delete']
|
||||
- ['accounts_alerts-list.md', 'Accounts', 'Alerts List']
|
||||
- ['accounts_customchannels-adunits-list.md', 'Accounts', 'Customchannels Adunits List']
|
||||
- ['accounts_customchannels-get.md', 'Accounts', 'Customchannels Get']
|
||||
- ['accounts_customchannels-list.md', 'Accounts', 'Customchannels List']
|
||||
- ['accounts_get.md', 'Accounts', 'Get']
|
||||
- ['accounts_list.md', 'Accounts', 'List']
|
||||
- ['accounts_payments-list.md', 'Accounts', 'Payments List']
|
||||
- ['accounts_reports-generate.md', 'Accounts', 'Reports Generate']
|
||||
- ['accounts_reports-saved-generate.md', 'Accounts', 'Reports Saved Generate']
|
||||
- ['accounts_reports-saved-list.md', 'Accounts', 'Reports Saved List']
|
||||
- ['accounts_savedadstyles-get.md', 'Accounts', 'Savedadstyles Get']
|
||||
- ['accounts_savedadstyles-list.md', 'Accounts', 'Savedadstyles List']
|
||||
- ['accounts_urlchannels-list.md', 'Accounts', 'Urlchannels List']
|
||||
- ['adclients_list.md', 'Adclients', 'List']
|
||||
- ['adunits_customchannels-list.md', 'Adunits', 'Customchannels List']
|
||||
- ['adunits_get.md', 'Adunits', 'Get']
|
||||
- ['adunits_get-ad-code.md', 'Adunits', 'Get Ad Code']
|
||||
- ['adunits_list.md', 'Adunits', 'List']
|
||||
- ['alerts_delete.md', 'Alerts', 'Delete']
|
||||
- ['alerts_list.md', 'Alerts', 'List']
|
||||
- ['customchannels_adunits-list.md', 'Customchannels', 'Adunits List']
|
||||
- ['customchannels_get.md', 'Customchannels', 'Get']
|
||||
- ['customchannels_list.md', 'Customchannels', 'List']
|
||||
- ['metadata_dimensions-list.md', 'Metadata', 'Dimensions List']
|
||||
- ['metadata_metrics-list.md', 'Metadata', 'Metrics List']
|
||||
- ['payments_list.md', 'Payments', 'List']
|
||||
- ['reports_generate.md', 'Reports', 'Generate']
|
||||
- ['reports_saved-generate.md', 'Reports', 'Saved Generate']
|
||||
- ['reports_saved-list.md', 'Reports', 'Saved List']
|
||||
- ['savedadstyles_get.md', 'Savedadstyles', 'Get']
|
||||
- ['savedadstyles_list.md', 'Savedadstyles', 'List']
|
||||
- ['urlchannels_list.md', 'Urlchannels', 'List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/adsense1d4-cli/src/cmn.rs
Normal file
439
gen/adsense1d4-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
2158
gen/adsense1d4-cli/src/main.rs
Normal file
2158
gen/adsense1d4-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/adsensehost4d1-cli/Cargo.toml
Normal file
30
gen/adsensehost4d1-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-adsensehost4d1-cli"
|
||||
version = "0.0.1+20150326"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with AdSense Host (protocol v4.1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/adsensehost4d1-cli"
|
||||
homepage = "https://developers.google.com/adsense/host/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_adsensehost4d1_cli"
|
||||
license = "MIT"
|
||||
keywords = ["adsensehost", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "adsensehost4d1"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-adsensehost4d1]
|
||||
path = "../adsensehost4d1"
|
||||
30
gen/adsensehost4d1-cli/LICENSE.md
Normal file
30
gen/adsensehost4d1-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/adsensehost4d1-cli/README.md
Normal file
4
gen/adsensehost4d1-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ADSENSEHOST:V4.1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
42
gen/adsensehost4d1-cli/mkdocs.yml
Normal file
42
gen/adsensehost4d1-cli/mkdocs.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
site_name: AdSense Host v0.0.1+20150326
|
||||
site_url: http://byron.github.io/google-apis-rs/google-adsensehost4d1-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/adsensehost4d1-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['accounts_adclients-get.md', 'Accounts', 'Adclients Get']
|
||||
- ['accounts_adclients-list.md', 'Accounts', 'Adclients List']
|
||||
- ['accounts_adunits-delete.md', 'Accounts', 'Adunits Delete']
|
||||
- ['accounts_adunits-get.md', 'Accounts', 'Adunits Get']
|
||||
- ['accounts_adunits-get-ad-code.md', 'Accounts', 'Adunits Get Ad Code']
|
||||
- ['accounts_adunits-insert.md', 'Accounts', 'Adunits Insert']
|
||||
- ['accounts_adunits-list.md', 'Accounts', 'Adunits List']
|
||||
- ['accounts_adunits-patch.md', 'Accounts', 'Adunits Patch']
|
||||
- ['accounts_adunits-update.md', 'Accounts', 'Adunits Update']
|
||||
- ['accounts_get.md', 'Accounts', 'Get']
|
||||
- ['accounts_list.md', 'Accounts', 'List']
|
||||
- ['accounts_reports-generate.md', 'Accounts', 'Reports Generate']
|
||||
- ['adclients_get.md', 'Adclients', 'Get']
|
||||
- ['adclients_list.md', 'Adclients', 'List']
|
||||
- ['associationsessions_start.md', 'Associationsessions', 'Start']
|
||||
- ['associationsessions_verify.md', 'Associationsessions', 'Verify']
|
||||
- ['customchannels_delete.md', 'Customchannels', 'Delete']
|
||||
- ['customchannels_get.md', 'Customchannels', 'Get']
|
||||
- ['customchannels_insert.md', 'Customchannels', 'Insert']
|
||||
- ['customchannels_list.md', 'Customchannels', 'List']
|
||||
- ['customchannels_patch.md', 'Customchannels', 'Patch']
|
||||
- ['customchannels_update.md', 'Customchannels', 'Update']
|
||||
- ['reports_generate.md', 'Reports', 'Generate']
|
||||
- ['urlchannels_delete.md', 'Urlchannels', 'Delete']
|
||||
- ['urlchannels_insert.md', 'Urlchannels', 'Insert']
|
||||
- ['urlchannels_list.md', 'Urlchannels', 'List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/adsensehost4d1-cli/src/cmn.rs
Normal file
439
gen/adsensehost4d1-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
1906
gen/adsensehost4d1-cli/src/main.rs
Normal file
1906
gen/adsensehost4d1-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/analytics3-cli/Cargo.toml
Normal file
30
gen/analytics3-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-analytics3-cli"
|
||||
version = "0.0.1+20150308"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with analytics (protocol v3)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/analytics3-cli"
|
||||
homepage = "https://developers.google.com/analytics/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_analytics3_cli"
|
||||
license = "MIT"
|
||||
keywords = ["analytics", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "analytics3"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-analytics3]
|
||||
path = "../analytics3"
|
||||
30
gen/analytics3-cli/LICENSE.md
Normal file
30
gen/analytics3-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/analytics3-cli/README.md
Normal file
4
gen/analytics3-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ANALYTICS:V3
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
94
gen/analytics3-cli/mkdocs.yml
Normal file
94
gen/analytics3-cli/mkdocs.yml
Normal file
@@ -0,0 +1,94 @@
|
||||
site_name: analytics v0.0.1+20150308
|
||||
site_url: http://byron.github.io/google-apis-rs/google-analytics3-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/analytics3-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['data_ga-get.md', 'Data', 'Ga Get']
|
||||
- ['data_mcf-get.md', 'Data', 'Mcf Get']
|
||||
- ['data_realtime-get.md', 'Data', 'Realtime Get']
|
||||
- ['management_account-summaries-list.md', 'Management', 'Account Summaries List']
|
||||
- ['management_account-user-links-delete.md', 'Management', 'Account User Links Delete']
|
||||
- ['management_account-user-links-insert.md', 'Management', 'Account User Links Insert']
|
||||
- ['management_account-user-links-list.md', 'Management', 'Account User Links List']
|
||||
- ['management_account-user-links-update.md', 'Management', 'Account User Links Update']
|
||||
- ['management_accounts-list.md', 'Management', 'Accounts List']
|
||||
- ['management_custom-data-sources-list.md', 'Management', 'Custom Data Sources List']
|
||||
- ['management_custom-dimensions-get.md', 'Management', 'Custom Dimensions Get']
|
||||
- ['management_custom-dimensions-insert.md', 'Management', 'Custom Dimensions Insert']
|
||||
- ['management_custom-dimensions-list.md', 'Management', 'Custom Dimensions List']
|
||||
- ['management_custom-dimensions-patch.md', 'Management', 'Custom Dimensions Patch']
|
||||
- ['management_custom-dimensions-update.md', 'Management', 'Custom Dimensions Update']
|
||||
- ['management_custom-metrics-get.md', 'Management', 'Custom Metrics Get']
|
||||
- ['management_custom-metrics-insert.md', 'Management', 'Custom Metrics Insert']
|
||||
- ['management_custom-metrics-list.md', 'Management', 'Custom Metrics List']
|
||||
- ['management_custom-metrics-patch.md', 'Management', 'Custom Metrics Patch']
|
||||
- ['management_custom-metrics-update.md', 'Management', 'Custom Metrics Update']
|
||||
- ['management_experiments-delete.md', 'Management', 'Experiments Delete']
|
||||
- ['management_experiments-get.md', 'Management', 'Experiments Get']
|
||||
- ['management_experiments-insert.md', 'Management', 'Experiments Insert']
|
||||
- ['management_experiments-list.md', 'Management', 'Experiments List']
|
||||
- ['management_experiments-patch.md', 'Management', 'Experiments Patch']
|
||||
- ['management_experiments-update.md', 'Management', 'Experiments Update']
|
||||
- ['management_filters-delete.md', 'Management', 'Filters Delete']
|
||||
- ['management_filters-get.md', 'Management', 'Filters Get']
|
||||
- ['management_filters-insert.md', 'Management', 'Filters Insert']
|
||||
- ['management_filters-list.md', 'Management', 'Filters List']
|
||||
- ['management_filters-patch.md', 'Management', 'Filters Patch']
|
||||
- ['management_filters-update.md', 'Management', 'Filters Update']
|
||||
- ['management_goals-get.md', 'Management', 'Goals Get']
|
||||
- ['management_goals-insert.md', 'Management', 'Goals Insert']
|
||||
- ['management_goals-list.md', 'Management', 'Goals List']
|
||||
- ['management_goals-patch.md', 'Management', 'Goals Patch']
|
||||
- ['management_goals-update.md', 'Management', 'Goals Update']
|
||||
- ['management_profile-filter-links-delete.md', 'Management', 'Profile Filter Links Delete']
|
||||
- ['management_profile-filter-links-get.md', 'Management', 'Profile Filter Links Get']
|
||||
- ['management_profile-filter-links-insert.md', 'Management', 'Profile Filter Links Insert']
|
||||
- ['management_profile-filter-links-list.md', 'Management', 'Profile Filter Links List']
|
||||
- ['management_profile-filter-links-patch.md', 'Management', 'Profile Filter Links Patch']
|
||||
- ['management_profile-filter-links-update.md', 'Management', 'Profile Filter Links Update']
|
||||
- ['management_profile-user-links-delete.md', 'Management', 'Profile User Links Delete']
|
||||
- ['management_profile-user-links-insert.md', 'Management', 'Profile User Links Insert']
|
||||
- ['management_profile-user-links-list.md', 'Management', 'Profile User Links List']
|
||||
- ['management_profile-user-links-update.md', 'Management', 'Profile User Links Update']
|
||||
- ['management_profiles-delete.md', 'Management', 'Profiles Delete']
|
||||
- ['management_profiles-get.md', 'Management', 'Profiles Get']
|
||||
- ['management_profiles-insert.md', 'Management', 'Profiles Insert']
|
||||
- ['management_profiles-list.md', 'Management', 'Profiles List']
|
||||
- ['management_profiles-patch.md', 'Management', 'Profiles Patch']
|
||||
- ['management_profiles-update.md', 'Management', 'Profiles Update']
|
||||
- ['management_segments-list.md', 'Management', 'Segments List']
|
||||
- ['management_unsampled-reports-get.md', 'Management', 'Unsampled Reports Get']
|
||||
- ['management_unsampled-reports-insert.md', 'Management', 'Unsampled Reports Insert']
|
||||
- ['management_unsampled-reports-list.md', 'Management', 'Unsampled Reports List']
|
||||
- ['management_uploads-delete-upload-data.md', 'Management', 'Uploads Delete Upload Data']
|
||||
- ['management_uploads-get.md', 'Management', 'Uploads Get']
|
||||
- ['management_uploads-list.md', 'Management', 'Uploads List']
|
||||
- ['management_uploads-upload-data.md', 'Management', 'Uploads Upload Data']
|
||||
- ['management_web-property-ad-words-links-delete.md', 'Management', 'Web Property Ad Words Links Delete']
|
||||
- ['management_web-property-ad-words-links-get.md', 'Management', 'Web Property Ad Words Links Get']
|
||||
- ['management_web-property-ad-words-links-insert.md', 'Management', 'Web Property Ad Words Links Insert']
|
||||
- ['management_web-property-ad-words-links-list.md', 'Management', 'Web Property Ad Words Links List']
|
||||
- ['management_web-property-ad-words-links-patch.md', 'Management', 'Web Property Ad Words Links Patch']
|
||||
- ['management_web-property-ad-words-links-update.md', 'Management', 'Web Property Ad Words Links Update']
|
||||
- ['management_webproperties-get.md', 'Management', 'Webproperties Get']
|
||||
- ['management_webproperties-insert.md', 'Management', 'Webproperties Insert']
|
||||
- ['management_webproperties-list.md', 'Management', 'Webproperties List']
|
||||
- ['management_webproperties-patch.md', 'Management', 'Webproperties Patch']
|
||||
- ['management_webproperties-update.md', 'Management', 'Webproperties Update']
|
||||
- ['management_webproperty-user-links-delete.md', 'Management', 'Webproperty User Links Delete']
|
||||
- ['management_webproperty-user-links-insert.md', 'Management', 'Webproperty User Links Insert']
|
||||
- ['management_webproperty-user-links-list.md', 'Management', 'Webproperty User Links List']
|
||||
- ['management_webproperty-user-links-update.md', 'Management', 'Webproperty User Links Update']
|
||||
- ['metadata_columns-list.md', 'Metadata', 'Columns List']
|
||||
- ['provisioning_create-account-ticket.md', 'Provisioning', 'Create Account Ticket']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/analytics3-cli/src/cmn.rs
Normal file
439
gen/analytics3-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
8003
gen/analytics3-cli/src/main.rs
Normal file
8003
gen/analytics3-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
29
gen/androidenterprise1-cli/Cargo.toml
Normal file
29
gen/androidenterprise1-cli/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-androidenterprise1-cli"
|
||||
version = "0.0.1+20150309"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with Android Enterprise (protocol v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/androidenterprise1-cli"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_androidenterprise1_cli"
|
||||
license = "MIT"
|
||||
keywords = ["androidenterprise", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "androidenterprise1"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-androidenterprise1]
|
||||
path = "../androidenterprise1"
|
||||
30
gen/androidenterprise1-cli/LICENSE.md
Normal file
30
gen/androidenterprise1-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/androidenterprise1-cli/README.md
Normal file
4
gen/androidenterprise1-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ANDROIDENTERPRISE:V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
60
gen/androidenterprise1-cli/mkdocs.yml
Normal file
60
gen/androidenterprise1-cli/mkdocs.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
site_name: Android Enterprise v0.0.1+20150309
|
||||
site_url: http://byron.github.io/google-apis-rs/google-androidenterprise1-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/androidenterprise1-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['collections_delete.md', 'Collections', 'Delete']
|
||||
- ['collections_get.md', 'Collections', 'Get']
|
||||
- ['collections_insert.md', 'Collections', 'Insert']
|
||||
- ['collections_list.md', 'Collections', 'List']
|
||||
- ['collections_patch.md', 'Collections', 'Patch']
|
||||
- ['collections_update.md', 'Collections', 'Update']
|
||||
- ['collectionviewers_delete.md', 'Collectionviewers', 'Delete']
|
||||
- ['collectionviewers_get.md', 'Collectionviewers', 'Get']
|
||||
- ['collectionviewers_list.md', 'Collectionviewers', 'List']
|
||||
- ['collectionviewers_patch.md', 'Collectionviewers', 'Patch']
|
||||
- ['collectionviewers_update.md', 'Collectionviewers', 'Update']
|
||||
- ['devices_get.md', 'Devices', 'Get']
|
||||
- ['devices_get-state.md', 'Devices', 'Get State']
|
||||
- ['devices_list.md', 'Devices', 'List']
|
||||
- ['devices_set-state.md', 'Devices', 'Set State']
|
||||
- ['enterprises_delete.md', 'Enterprises', 'Delete']
|
||||
- ['enterprises_enroll.md', 'Enterprises', 'Enroll']
|
||||
- ['enterprises_get.md', 'Enterprises', 'Get']
|
||||
- ['enterprises_insert.md', 'Enterprises', 'Insert']
|
||||
- ['enterprises_list.md', 'Enterprises', 'List']
|
||||
- ['enterprises_set-account.md', 'Enterprises', 'Set Account']
|
||||
- ['enterprises_unenroll.md', 'Enterprises', 'Unenroll']
|
||||
- ['entitlements_delete.md', 'Entitlements', 'Delete']
|
||||
- ['entitlements_get.md', 'Entitlements', 'Get']
|
||||
- ['entitlements_list.md', 'Entitlements', 'List']
|
||||
- ['entitlements_patch.md', 'Entitlements', 'Patch']
|
||||
- ['entitlements_update.md', 'Entitlements', 'Update']
|
||||
- ['grouplicenses_get.md', 'Grouplicenses', 'Get']
|
||||
- ['grouplicenses_list.md', 'Grouplicenses', 'List']
|
||||
- ['grouplicenseusers_list.md', 'Grouplicenseusers', 'List']
|
||||
- ['installs_delete.md', 'Installs', 'Delete']
|
||||
- ['installs_get.md', 'Installs', 'Get']
|
||||
- ['installs_list.md', 'Installs', 'List']
|
||||
- ['installs_patch.md', 'Installs', 'Patch']
|
||||
- ['installs_update.md', 'Installs', 'Update']
|
||||
- ['permissions_get.md', 'Permissions', 'Get']
|
||||
- ['products_get.md', 'Products', 'Get']
|
||||
- ['products_get-app-restrictions-schema.md', 'Products', 'Get App Restrictions Schema']
|
||||
- ['products_get-permissions.md', 'Products', 'Get Permissions']
|
||||
- ['products_update-permissions.md', 'Products', 'Update Permissions']
|
||||
- ['users_generate-token.md', 'Users', 'Generate Token']
|
||||
- ['users_get.md', 'Users', 'Get']
|
||||
- ['users_list.md', 'Users', 'List']
|
||||
- ['users_revoke-token.md', 'Users', 'Revoke Token']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/androidenterprise1-cli/src/cmn.rs
Normal file
439
gen/androidenterprise1-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
2573
gen/androidenterprise1-cli/src/main.rs
Normal file
2573
gen/androidenterprise1-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/androidpublisher2-cli/Cargo.toml
Normal file
30
gen/androidpublisher2-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-androidpublisher2-cli"
|
||||
version = "0.0.1+20150323"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with Android Publisher (protocol v2)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/androidpublisher2-cli"
|
||||
homepage = "https://developers.google.com/android-publisher"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_androidpublisher2_cli"
|
||||
license = "MIT"
|
||||
keywords = ["androidpublisher", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "androidpublisher2"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-androidpublisher2]
|
||||
path = "../androidpublisher2"
|
||||
30
gen/androidpublisher2-cli/LICENSE.md
Normal file
30
gen/androidpublisher2-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/androidpublisher2-cli/README.md
Normal file
4
gen/androidpublisher2-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO ANDROIDPUBLISHER:V2
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
67
gen/androidpublisher2-cli/mkdocs.yml
Normal file
67
gen/androidpublisher2-cli/mkdocs.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
site_name: Android Publisher v0.0.1+20150323
|
||||
site_url: http://byron.github.io/google-apis-rs/google-androidpublisher2-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/androidpublisher2-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['edits_apklistings-delete.md', 'Edits', 'Apklistings Delete']
|
||||
- ['edits_apklistings-deleteall.md', 'Edits', 'Apklistings Deleteall']
|
||||
- ['edits_apklistings-get.md', 'Edits', 'Apklistings Get']
|
||||
- ['edits_apklistings-list.md', 'Edits', 'Apklistings List']
|
||||
- ['edits_apklistings-patch.md', 'Edits', 'Apklistings Patch']
|
||||
- ['edits_apklistings-update.md', 'Edits', 'Apklistings Update']
|
||||
- ['edits_apks-addexternallyhosted.md', 'Edits', 'Apks Addexternallyhosted']
|
||||
- ['edits_apks-list.md', 'Edits', 'Apks List']
|
||||
- ['edits_apks-upload.md', 'Edits', 'Apks Upload']
|
||||
- ['edits_commit.md', 'Edits', 'Commit']
|
||||
- ['edits_delete.md', 'Edits', 'Delete']
|
||||
- ['edits_details-get.md', 'Edits', 'Details Get']
|
||||
- ['edits_details-patch.md', 'Edits', 'Details Patch']
|
||||
- ['edits_details-update.md', 'Edits', 'Details Update']
|
||||
- ['edits_expansionfiles-get.md', 'Edits', 'Expansionfiles Get']
|
||||
- ['edits_expansionfiles-patch.md', 'Edits', 'Expansionfiles Patch']
|
||||
- ['edits_expansionfiles-update.md', 'Edits', 'Expansionfiles Update']
|
||||
- ['edits_expansionfiles-upload.md', 'Edits', 'Expansionfiles Upload']
|
||||
- ['edits_get.md', 'Edits', 'Get']
|
||||
- ['edits_images-delete.md', 'Edits', 'Images Delete']
|
||||
- ['edits_images-deleteall.md', 'Edits', 'Images Deleteall']
|
||||
- ['edits_images-list.md', 'Edits', 'Images List']
|
||||
- ['edits_images-upload.md', 'Edits', 'Images Upload']
|
||||
- ['edits_insert.md', 'Edits', 'Insert']
|
||||
- ['edits_listings-delete.md', 'Edits', 'Listings Delete']
|
||||
- ['edits_listings-deleteall.md', 'Edits', 'Listings Deleteall']
|
||||
- ['edits_listings-get.md', 'Edits', 'Listings Get']
|
||||
- ['edits_listings-list.md', 'Edits', 'Listings List']
|
||||
- ['edits_listings-patch.md', 'Edits', 'Listings Patch']
|
||||
- ['edits_listings-update.md', 'Edits', 'Listings Update']
|
||||
- ['edits_testers-get.md', 'Edits', 'Testers Get']
|
||||
- ['edits_testers-patch.md', 'Edits', 'Testers Patch']
|
||||
- ['edits_testers-update.md', 'Edits', 'Testers Update']
|
||||
- ['edits_tracks-get.md', 'Edits', 'Tracks Get']
|
||||
- ['edits_tracks-list.md', 'Edits', 'Tracks List']
|
||||
- ['edits_tracks-patch.md', 'Edits', 'Tracks Patch']
|
||||
- ['edits_tracks-update.md', 'Edits', 'Tracks Update']
|
||||
- ['edits_validate.md', 'Edits', 'Validate']
|
||||
- ['inappproducts_batch.md', 'Inappproducts', 'Batch']
|
||||
- ['inappproducts_delete.md', 'Inappproducts', 'Delete']
|
||||
- ['inappproducts_get.md', 'Inappproducts', 'Get']
|
||||
- ['inappproducts_insert.md', 'Inappproducts', 'Insert']
|
||||
- ['inappproducts_list.md', 'Inappproducts', 'List']
|
||||
- ['inappproducts_patch.md', 'Inappproducts', 'Patch']
|
||||
- ['inappproducts_update.md', 'Inappproducts', 'Update']
|
||||
- ['purchases_products-get.md', 'Purchases', 'Products Get']
|
||||
- ['purchases_subscriptions-cancel.md', 'Purchases', 'Subscriptions Cancel']
|
||||
- ['purchases_subscriptions-defer.md', 'Purchases', 'Subscriptions Defer']
|
||||
- ['purchases_subscriptions-get.md', 'Purchases', 'Subscriptions Get']
|
||||
- ['purchases_subscriptions-refund.md', 'Purchases', 'Subscriptions Refund']
|
||||
- ['purchases_subscriptions-revoke.md', 'Purchases', 'Subscriptions Revoke']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/androidpublisher2-cli/src/cmn.rs
Normal file
439
gen/androidpublisher2-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
3207
gen/androidpublisher2-cli/src/main.rs
Normal file
3207
gen/androidpublisher2-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/appsactivity1-cli/Cargo.toml
Normal file
30
gen/appsactivity1-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-appsactivity1-cli"
|
||||
version = "0.0.1+20140828"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with appsactivity (protocol v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/appsactivity1-cli"
|
||||
homepage = "https://developers.google.com/google-apps/activity/"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_appsactivity1_cli"
|
||||
license = "MIT"
|
||||
keywords = ["appsactivity", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "appsactivity1"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-appsactivity1]
|
||||
path = "../appsactivity1"
|
||||
30
gen/appsactivity1-cli/LICENSE.md
Normal file
30
gen/appsactivity1-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/appsactivity1-cli/README.md
Normal file
4
gen/appsactivity1-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO APPSACTIVITY:V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
17
gen/appsactivity1-cli/mkdocs.yml
Normal file
17
gen/appsactivity1-cli/mkdocs.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
site_name: appsactivity v0.0.1+20140828
|
||||
site_url: http://byron.github.io/google-apis-rs/google-appsactivity1-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/appsactivity1-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['activities_list.md', 'Activities', 'List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/appsactivity1-cli/src/cmn.rs
Normal file
439
gen/appsactivity1-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
194
gen/appsactivity1-cli/src/main.rs
Normal file
194
gen/appsactivity1-cli/src/main.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
// 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_appsactivity1 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
appsactivity1 [options] activities list [-p <v>]... [-o <out>]
|
||||
appsactivity1 --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::Appsactivity<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _activities_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.activities().list();
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"user-id" => {
|
||||
call = call.user_id(value.unwrap_or(""));
|
||||
},
|
||||
"source" => {
|
||||
call = call.source(value.unwrap_or(""));
|
||||
},
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"page-size" => {
|
||||
call = call.page_size(arg_from_str(value.unwrap_or("-0"), err, "page-size", "integer"));
|
||||
},
|
||||
"grouping-strategy" => {
|
||||
call = call.grouping_strategy(value.unwrap_or(""));
|
||||
},
|
||||
"drive-file-id" => {
|
||||
call = call.drive_file_id(value.unwrap_or(""));
|
||||
},
|
||||
"drive-ancestor-id" => {
|
||||
call = call.drive_ancestor_id(value.unwrap_or(""));
|
||||
},
|
||||
"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 _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_activities {
|
||||
if self.opt.cmd_list {
|
||||
call_result = self._activities_list(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, "appsactivity1-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: "appsactivity1",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::Appsactivity::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/appstate1-cli/Cargo.toml
Normal file
30
gen/appstate1-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-appstate1-cli"
|
||||
version = "0.0.1+20150326"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with App State (protocol v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/appstate1-cli"
|
||||
homepage = "https://developers.google.com/games/services/web/api/states"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_appstate1_cli"
|
||||
license = "MIT"
|
||||
keywords = ["appstate", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "appstate1"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-appstate1]
|
||||
path = "../appstate1"
|
||||
30
gen/appstate1-cli/LICENSE.md
Normal file
30
gen/appstate1-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/appstate1-cli/README.md
Normal file
4
gen/appstate1-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO APPSTATE:V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
21
gen/appstate1-cli/mkdocs.yml
Normal file
21
gen/appstate1-cli/mkdocs.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
site_name: App State v0.0.1+20150326
|
||||
site_url: http://byron.github.io/google-apis-rs/google-appstate1-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/appstate1-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['states_clear.md', 'States', 'Clear']
|
||||
- ['states_delete.md', 'States', 'Delete']
|
||||
- ['states_get.md', 'States', 'Get']
|
||||
- ['states_list.md', 'States', 'List']
|
||||
- ['states_update.md', 'States', 'Update']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/appstate1-cli/src/cmn.rs
Normal file
439
gen/appstate1-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
391
gen/appstate1-cli/src/main.rs
Normal file
391
gen/appstate1-cli/src/main.rs
Normal file
@@ -0,0 +1,391 @@
|
||||
// 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_appstate1 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
appstate1 [options] states clear <state-key> [-p <v>]... [-o <out>]
|
||||
appstate1 [options] states delete <state-key> [-p <v>]...
|
||||
appstate1 [options] states get <state-key> [-p <v>]... [-o <out>]
|
||||
appstate1 [options] states list [-p <v>]... [-o <out>]
|
||||
appstate1 [options] states update <state-key> -r <kv>... [-p <v>]... [-o <out>]
|
||||
appstate1 --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::AppState<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _states_clear(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let state_key: i32 = arg_from_str(&self.opt.arg_state_key, err, "<state-key>", "integer");
|
||||
let mut call = self.hub.states().clear(state_key);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"current-data-version" => {
|
||||
call = call.current_data_version(value.unwrap_or(""));
|
||||
},
|
||||
"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 _states_delete(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let state_key: i32 = arg_from_str(&self.opt.arg_state_key, err, "<state-key>", "integer");
|
||||
let mut call = self.hub.states().delete(state_key);
|
||||
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 _states_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let state_key: i32 = arg_from_str(&self.opt.arg_state_key, err, "<state-key>", "integer");
|
||||
let mut call = self.hub.states().get(state_key);
|
||||
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 _states_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.states().list();
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"include-data" => {
|
||||
call = call.include_data(arg_from_str(value.unwrap_or("false"), err, "include-data", "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 _states_update(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::UpdateRequest = Default::default();
|
||||
let state_key: i32 = arg_from_str(&self.opt.arg_state_key, err, "<state-key>", "integer");
|
||||
let mut call = self.hub.states().update(&request, state_key);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"current-state-version" => {
|
||||
call = call.current_state_version(value.unwrap_or(""));
|
||||
},
|
||||
"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());
|
||||
},
|
||||
"data" => {
|
||||
request.data = 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_states {
|
||||
if self.opt.cmd_clear {
|
||||
call_result = self._states_clear(dry_run, &mut err);
|
||||
} else if self.opt.cmd_delete {
|
||||
call_result = self._states_delete(dry_run, &mut err);
|
||||
} else if self.opt.cmd_get {
|
||||
call_result = self._states_get(dry_run, &mut err);
|
||||
} else if self.opt.cmd_list {
|
||||
call_result = self._states_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_update {
|
||||
call_result = self._states_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, "appstate1-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: "appstate1",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::AppState::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/audit1-cli/Cargo.toml
Normal file
30
gen/audit1-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-audit1-cli"
|
||||
version = "0.0.1+20130108"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with audit (protocol v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/audit1-cli"
|
||||
homepage = "https://developers.google.com/google-apps/admin-audit/get_started"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_audit1_cli"
|
||||
license = "MIT"
|
||||
keywords = ["audit", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "audit1"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-audit1]
|
||||
path = "../audit1"
|
||||
30
gen/audit1-cli/LICENSE.md
Normal file
30
gen/audit1-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/audit1-cli/README.md
Normal file
4
gen/audit1-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO AUDIT:V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
17
gen/audit1-cli/mkdocs.yml
Normal file
17
gen/audit1-cli/mkdocs.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
site_name: audit v0.0.1+20130108
|
||||
site_url: http://byron.github.io/google-apis-rs/google-audit1-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/audit1-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['activities_list.md', 'Activities', 'List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/audit1-cli/src/cmn.rs
Normal file
439
gen/audit1-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
196
gen/audit1-cli/src/main.rs
Normal file
196
gen/audit1-cli/src/main.rs
Normal file
@@ -0,0 +1,196 @@
|
||||
// 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_audit1 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
audit1 [options] activities list <customer-id> <application-id> [-p <v>]... [-o <out>]
|
||||
audit1 --help
|
||||
|
||||
All documentation details can be found TODO: <URL to github.io docs here, see #51>
|
||||
|
||||
Configuration:
|
||||
--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::Audit<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _activities_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.activities().list(&self.opt.arg_customer_id, &self.opt.arg_application_id);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"start-time" => {
|
||||
call = call.start_time(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"event-name" => {
|
||||
call = call.event_name(value.unwrap_or(""));
|
||||
},
|
||||
"end-time" => {
|
||||
call = call.end_time(value.unwrap_or(""));
|
||||
},
|
||||
"continuation-token" => {
|
||||
call = call.continuation_token(value.unwrap_or(""));
|
||||
},
|
||||
"caller" => {
|
||||
call = call.caller(value.unwrap_or(""));
|
||||
},
|
||||
"actor-ip-address" => {
|
||||
call = call.actor_ip_address(value.unwrap_or(""));
|
||||
},
|
||||
"actor-email" => {
|
||||
call = call.actor_email(value.unwrap_or(""));
|
||||
},
|
||||
"actor-application-id" => {
|
||||
call = call.actor_application_id(value.unwrap_or(""));
|
||||
},
|
||||
"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 _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_activities {
|
||||
if self.opt.cmd_list {
|
||||
call_result = self._activities_list(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, "audit1-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: "audit1",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::Audit::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/autoscaler1_beta2-cli/Cargo.toml
Normal file
30
gen/autoscaler1_beta2-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-autoscaler1_beta2-cli"
|
||||
version = "0.0.1+20141112"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with autoscaler (protocol v1beta2)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/autoscaler1_beta2-cli"
|
||||
homepage = "http://developers.google.com/compute/docs/autoscaler"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_autoscaler1_beta2_cli"
|
||||
license = "MIT"
|
||||
keywords = ["autoscaler", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "autoscaler1-beta2"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-autoscaler1_beta2]
|
||||
path = "../autoscaler1_beta2"
|
||||
30
gen/autoscaler1_beta2-cli/LICENSE.md
Normal file
30
gen/autoscaler1_beta2-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/autoscaler1_beta2-cli/README.md
Normal file
4
gen/autoscaler1_beta2-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO AUTOSCALER:V1BETA2
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
26
gen/autoscaler1_beta2-cli/mkdocs.yml
Normal file
26
gen/autoscaler1_beta2-cli/mkdocs.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
site_name: autoscaler v0.0.1+20141112
|
||||
site_url: http://byron.github.io/google-apis-rs/google-autoscaler1_beta2-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/autoscaler1_beta2-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['autoscalers_delete.md', 'Autoscalers', 'Delete']
|
||||
- ['autoscalers_get.md', 'Autoscalers', 'Get']
|
||||
- ['autoscalers_insert.md', 'Autoscalers', 'Insert']
|
||||
- ['autoscalers_list.md', 'Autoscalers', 'List']
|
||||
- ['autoscalers_patch.md', 'Autoscalers', 'Patch']
|
||||
- ['autoscalers_update.md', 'Autoscalers', 'Update']
|
||||
- ['zone-operations_delete.md', 'Zone Operations', 'Delete']
|
||||
- ['zone-operations_get.md', 'Zone Operations', 'Get']
|
||||
- ['zone-operations_list.md', 'Zone Operations', 'List']
|
||||
- ['zones_list.md', 'Zones', 'List']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/autoscaler1_beta2-cli/src/cmn.rs
Normal file
439
gen/autoscaler1_beta2-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
824
gen/autoscaler1_beta2-cli/src/main.rs
Normal file
824
gen/autoscaler1_beta2-cli/src/main.rs
Normal file
@@ -0,0 +1,824 @@
|
||||
// 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_autoscaler1_beta2 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
|
||||
docopt!(Options derive Debug, "
|
||||
Usage:
|
||||
autoscaler1-beta2 [options] autoscalers delete <project> <zone> <autoscaler> [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] autoscalers get <project> <zone> <autoscaler> [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] autoscalers insert <project> <zone> -r <kv>... [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] autoscalers list <project> <zone> [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] autoscalers patch <project> <zone> <autoscaler> -r <kv>... [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] autoscalers update <project> <zone> <autoscaler> -r <kv>... [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] zone-operations delete <project> <zone> <operation> [-p <v>]...
|
||||
autoscaler1-beta2 [options] zone-operations get <project> <zone> <operation> [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] zone-operations list <project> <zone> [-p <v>]... [-o <out>]
|
||||
autoscaler1-beta2 [options] zones list <project> [-p <v>]... [-o <out>]
|
||||
autoscaler1-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::AutoscalerHub<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
}
|
||||
|
||||
|
||||
impl Engine {
|
||||
fn _autoscalers_delete(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.autoscalers().delete(&self.opt.arg_project, &self.opt.arg_zone, &self.opt.arg_autoscaler);
|
||||
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 _autoscalers_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.autoscalers().get(&self.opt.arg_project, &self.opt.arg_zone, &self.opt.arg_autoscaler);
|
||||
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 _autoscalers_insert(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::Autoscaler = Default::default();
|
||||
let mut call = self.hub.autoscalers().insert(&request, &self.opt.arg_project, &self.opt.arg_zone);
|
||||
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);
|
||||
}
|
||||
fn request_autoscaling_policy_init(request: &mut api::Autoscaler) {
|
||||
if request.autoscaling_policy.is_none() {
|
||||
request.autoscaling_policy = Some(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
match &field_name.to_string()[..] {
|
||||
"kind" => {
|
||||
request.kind = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"description" => {
|
||||
request.description = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"autoscaling-policy.max-num-replicas" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().max_num_replicas = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.max-num-replicas", "integer");
|
||||
},
|
||||
"autoscaling-policy.cpu-utilization.utilization-target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().cpu_utilization.utilization_target = arg_from_str(value.unwrap_or("0.0"), err, "autoscaling-policy.cpu-utilization.utilization-target", "number");
|
||||
},
|
||||
"autoscaling-policy.min-num-replicas" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().min_num_replicas = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.min-num-replicas", "integer");
|
||||
},
|
||||
"autoscaling-policy.cool-down-period-sec" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().cool_down_period_sec = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.cool-down-period-sec", "integer");
|
||||
},
|
||||
"autoscaling-policy.load-balancing-utilization.utilization-target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().load_balancing_utilization.utilization_target = arg_from_str(value.unwrap_or("0.0"), err, "autoscaling-policy.load-balancing-utilization.utilization-target", "number");
|
||||
},
|
||||
"target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.target = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"creation-timestamp" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.creation_timestamp = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"id" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.id = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"self-link" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.self_link = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"name" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.name = 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 _autoscalers_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.autoscalers().list(&self.opt.arg_project, &self.opt.arg_zone);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"filter" => {
|
||||
call = call.filter(value.unwrap_or(""));
|
||||
},
|
||||
"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 _autoscalers_patch(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::Autoscaler = Default::default();
|
||||
let mut call = self.hub.autoscalers().patch(&request, &self.opt.arg_project, &self.opt.arg_zone, &self.opt.arg_autoscaler);
|
||||
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);
|
||||
}
|
||||
fn request_autoscaling_policy_init(request: &mut api::Autoscaler) {
|
||||
if request.autoscaling_policy.is_none() {
|
||||
request.autoscaling_policy = Some(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
match &field_name.to_string()[..] {
|
||||
"kind" => {
|
||||
request.kind = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"description" => {
|
||||
request.description = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"autoscaling-policy.max-num-replicas" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().max_num_replicas = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.max-num-replicas", "integer");
|
||||
},
|
||||
"autoscaling-policy.cpu-utilization.utilization-target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().cpu_utilization.utilization_target = arg_from_str(value.unwrap_or("0.0"), err, "autoscaling-policy.cpu-utilization.utilization-target", "number");
|
||||
},
|
||||
"autoscaling-policy.min-num-replicas" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().min_num_replicas = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.min-num-replicas", "integer");
|
||||
},
|
||||
"autoscaling-policy.cool-down-period-sec" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().cool_down_period_sec = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.cool-down-period-sec", "integer");
|
||||
},
|
||||
"autoscaling-policy.load-balancing-utilization.utilization-target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().load_balancing_utilization.utilization_target = arg_from_str(value.unwrap_or("0.0"), err, "autoscaling-policy.load-balancing-utilization.utilization-target", "number");
|
||||
},
|
||||
"target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.target = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"creation-timestamp" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.creation_timestamp = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"id" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.id = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"self-link" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.self_link = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"name" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.name = 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 _autoscalers_update(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut request: api::Autoscaler = Default::default();
|
||||
let mut call = self.hub.autoscalers().update(&request, &self.opt.arg_project, &self.opt.arg_zone, &self.opt.arg_autoscaler);
|
||||
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);
|
||||
}
|
||||
fn request_autoscaling_policy_init(request: &mut api::Autoscaler) {
|
||||
if request.autoscaling_policy.is_none() {
|
||||
request.autoscaling_policy = Some(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
match &field_name.to_string()[..] {
|
||||
"kind" => {
|
||||
request.kind = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"description" => {
|
||||
request.description = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"autoscaling-policy.max-num-replicas" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().max_num_replicas = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.max-num-replicas", "integer");
|
||||
},
|
||||
"autoscaling-policy.cpu-utilization.utilization-target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().cpu_utilization.utilization_target = arg_from_str(value.unwrap_or("0.0"), err, "autoscaling-policy.cpu-utilization.utilization-target", "number");
|
||||
},
|
||||
"autoscaling-policy.min-num-replicas" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().min_num_replicas = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.min-num-replicas", "integer");
|
||||
},
|
||||
"autoscaling-policy.cool-down-period-sec" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().cool_down_period_sec = arg_from_str(value.unwrap_or("-0"), err, "autoscaling-policy.cool-down-period-sec", "integer");
|
||||
},
|
||||
"autoscaling-policy.load-balancing-utilization.utilization-target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.autoscaling_policy.as_mut().unwrap().load_balancing_utilization.utilization_target = arg_from_str(value.unwrap_or("0.0"), err, "autoscaling-policy.load-balancing-utilization.utilization-target", "number");
|
||||
},
|
||||
"target" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.target = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"creation-timestamp" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.creation_timestamp = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"id" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.id = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"self-link" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.self_link = Some(value.unwrap_or("").to_string());
|
||||
},
|
||||
"name" => {
|
||||
request_autoscaling_policy_init(&mut request);
|
||||
request.name = 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 _zone_operations_delete(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.zone_operations().delete(&self.opt.arg_project, &self.opt.arg_zone, &self.opt.arg_operation);
|
||||
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 _zone_operations_get(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.zone_operations().get(&self.opt.arg_project, &self.opt.arg_zone, &self.opt.arg_operation);
|
||||
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 _zone_operations_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.zone_operations().list(&self.opt.arg_project, &self.opt.arg_zone);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"filter" => {
|
||||
call = call.filter(value.unwrap_or(""));
|
||||
},
|
||||
"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 _zones_list(&self, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Option<api::Error> {
|
||||
let mut call = self.hub.zones().list(&self.opt.arg_project);
|
||||
for parg in self.opt.arg_v.iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err);
|
||||
match key {
|
||||
"page-token" => {
|
||||
call = call.page_token(value.unwrap_or(""));
|
||||
},
|
||||
"max-results" => {
|
||||
call = call.max_results(arg_from_str(value.unwrap_or("-0"), err, "max-results", "integer"));
|
||||
},
|
||||
"filter" => {
|
||||
call = call.filter(value.unwrap_or(""));
|
||||
},
|
||||
"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 _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_autoscalers {
|
||||
if self.opt.cmd_delete {
|
||||
call_result = self._autoscalers_delete(dry_run, &mut err);
|
||||
} else if self.opt.cmd_get {
|
||||
call_result = self._autoscalers_get(dry_run, &mut err);
|
||||
} else if self.opt.cmd_insert {
|
||||
call_result = self._autoscalers_insert(dry_run, &mut err);
|
||||
} else if self.opt.cmd_list {
|
||||
call_result = self._autoscalers_list(dry_run, &mut err);
|
||||
} else if self.opt.cmd_patch {
|
||||
call_result = self._autoscalers_patch(dry_run, &mut err);
|
||||
} else if self.opt.cmd_update {
|
||||
call_result = self._autoscalers_update(dry_run, &mut err);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else if self.opt.cmd_zone_operations {
|
||||
if self.opt.cmd_delete {
|
||||
call_result = self._zone_operations_delete(dry_run, &mut err);
|
||||
} else if self.opt.cmd_get {
|
||||
call_result = self._zone_operations_get(dry_run, &mut err);
|
||||
} else if self.opt.cmd_list {
|
||||
call_result = self._zone_operations_list(dry_run, &mut err);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else if self.opt.cmd_zones {
|
||||
if self.opt.cmd_list {
|
||||
call_result = self._zones_list(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, "autoscaler1-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: "autoscaler1-beta2",
|
||||
db_dir: config_dir.clone(),
|
||||
}, None);
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::AutoscalerHub::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
gen/bigquery2-cli/Cargo.toml
Normal file
30
gen/bigquery2-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-bigquery2-cli"
|
||||
version = "0.0.1+20150326"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with bigquery (protocol v2)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/bigquery2-cli"
|
||||
homepage = "https://developers.google.com/bigquery/docs/overview"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_bigquery2_cli"
|
||||
license = "MIT"
|
||||
keywords = ["bigquery", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "bigquery2"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-bigquery2]
|
||||
path = "../bigquery2"
|
||||
30
gen/bigquery2-cli/LICENSE.md
Normal file
30
gen/bigquery2-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/bigquery2-cli/README.md
Normal file
4
gen/bigquery2-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO BIGQUERY:V2
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
36
gen/bigquery2-cli/mkdocs.yml
Normal file
36
gen/bigquery2-cli/mkdocs.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
site_name: bigquery v0.0.1+20150326
|
||||
site_url: http://byron.github.io/google-apis-rs/google-bigquery2-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/bigquery2-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['datasets_delete.md', 'Datasets', 'Delete']
|
||||
- ['datasets_get.md', 'Datasets', 'Get']
|
||||
- ['datasets_insert.md', 'Datasets', 'Insert']
|
||||
- ['datasets_list.md', 'Datasets', 'List']
|
||||
- ['datasets_patch.md', 'Datasets', 'Patch']
|
||||
- ['datasets_update.md', 'Datasets', 'Update']
|
||||
- ['jobs_get.md', 'Jobs', 'Get']
|
||||
- ['jobs_get-query-results.md', 'Jobs', 'Get Query Results']
|
||||
- ['jobs_insert.md', 'Jobs', 'Insert']
|
||||
- ['jobs_list.md', 'Jobs', 'List']
|
||||
- ['jobs_query.md', 'Jobs', 'Query']
|
||||
- ['projects_list.md', 'Projects', 'List']
|
||||
- ['tabledata_insert-all.md', 'Tabledata', 'Insert All']
|
||||
- ['tabledata_list.md', 'Tabledata', 'List']
|
||||
- ['tables_delete.md', 'Tables', 'Delete']
|
||||
- ['tables_get.md', 'Tables', 'Get']
|
||||
- ['tables_insert.md', 'Tables', 'Insert']
|
||||
- ['tables_list.md', 'Tables', 'List']
|
||||
- ['tables_patch.md', 'Tables', 'Patch']
|
||||
- ['tables_update.md', 'Tables', 'Update']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/bigquery2-cli/src/cmn.rs
Normal file
439
gen/bigquery2-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
2008
gen/bigquery2-cli/src/main.rs
Normal file
2008
gen/bigquery2-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/blogger3-cli/Cargo.toml
Normal file
30
gen/blogger3-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-blogger3-cli"
|
||||
version = "0.0.1+20150208"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with blogger (protocol v3)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/blogger3-cli"
|
||||
homepage = "https://developers.google.com/blogger/docs/3.0/getting_started"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_blogger3_cli"
|
||||
license = "MIT"
|
||||
keywords = ["blogger", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "blogger3"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-blogger3]
|
||||
path = "../blogger3"
|
||||
30
gen/blogger3-cli/LICENSE.md
Normal file
30
gen/blogger3-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/blogger3-cli/README.md
Normal file
4
gen/blogger3-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO BLOGGER:V3
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
49
gen/blogger3-cli/mkdocs.yml
Normal file
49
gen/blogger3-cli/mkdocs.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
site_name: blogger v0.0.1+20150208
|
||||
site_url: http://byron.github.io/google-apis-rs/google-blogger3-cli
|
||||
site_description: Write integrating applications with bcore
|
||||
|
||||
repo_url: https://github.com/Byron/google-apis-rs/tree/master/gen/blogger3-cli
|
||||
|
||||
docs_dir: docs
|
||||
site_dir: build_html
|
||||
|
||||
pages:
|
||||
- ['index.md', 'Home']
|
||||
- ['blog-user-infos_get.md', 'Blog User Infos', 'Get']
|
||||
- ['blogs_get.md', 'Blogs', 'Get']
|
||||
- ['blogs_get-by-url.md', 'Blogs', 'Get By Url']
|
||||
- ['blogs_list-by-user.md', 'Blogs', 'List By User']
|
||||
- ['comments_approve.md', 'Comments', 'Approve']
|
||||
- ['comments_delete.md', 'Comments', 'Delete']
|
||||
- ['comments_get.md', 'Comments', 'Get']
|
||||
- ['comments_list.md', 'Comments', 'List']
|
||||
- ['comments_list-by-blog.md', 'Comments', 'List By Blog']
|
||||
- ['comments_mark-as-spam.md', 'Comments', 'Mark As Spam']
|
||||
- ['comments_remove-content.md', 'Comments', 'Remove Content']
|
||||
- ['page-views_get.md', 'Page Views', 'Get']
|
||||
- ['pages_delete.md', 'Pages', 'Delete']
|
||||
- ['pages_get.md', 'Pages', 'Get']
|
||||
- ['pages_insert.md', 'Pages', 'Insert']
|
||||
- ['pages_list.md', 'Pages', 'List']
|
||||
- ['pages_patch.md', 'Pages', 'Patch']
|
||||
- ['pages_publish.md', 'Pages', 'Publish']
|
||||
- ['pages_revert.md', 'Pages', 'Revert']
|
||||
- ['pages_update.md', 'Pages', 'Update']
|
||||
- ['post-user-infos_get.md', 'Post User Infos', 'Get']
|
||||
- ['post-user-infos_list.md', 'Post User Infos', 'List']
|
||||
- ['posts_delete.md', 'Posts', 'Delete']
|
||||
- ['posts_get.md', 'Posts', 'Get']
|
||||
- ['posts_get-by-path.md', 'Posts', 'Get By Path']
|
||||
- ['posts_insert.md', 'Posts', 'Insert']
|
||||
- ['posts_list.md', 'Posts', 'List']
|
||||
- ['posts_patch.md', 'Posts', 'Patch']
|
||||
- ['posts_publish.md', 'Posts', 'Publish']
|
||||
- ['posts_revert.md', 'Posts', 'Revert']
|
||||
- ['posts_search.md', 'Posts', 'Search']
|
||||
- ['posts_update.md', 'Posts', 'Update']
|
||||
- ['users_get.md', 'Users', 'Get']
|
||||
|
||||
theme: readthedocs
|
||||
|
||||
copyright: Copyright © 2015, `Sebastian Thiel`
|
||||
|
||||
439
gen/blogger3-cli/src/cmn.rs
Normal file
439
gen/blogger3-cli/src/cmn.rs
Normal 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!();
|
||||
}
|
||||
2581
gen/blogger3-cli/src/main.rs
Normal file
2581
gen/blogger3-cli/src/main.rs
Normal file
File diff suppressed because it is too large
Load Diff
30
gen/books1-cli/Cargo.toml
Normal file
30
gen/books1-cli/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# DO NOT EDIT !
|
||||
# This file was generated automatically from 'src/mako/Cargo.toml.mako'
|
||||
# DO NOT EDIT !
|
||||
[package]
|
||||
|
||||
name = "google-books1-cli"
|
||||
version = "0.0.1+20150309"
|
||||
authors = ["Sebastian Thiel <byronimo@gmail>"]
|
||||
description = "A complete library to interact with books (protocol v1)"
|
||||
repository = "https://github.com/Byron/google-apis-rs/tree/master/gen/books1-cli"
|
||||
homepage = "https://developers.google.com/books/docs/v1/getting_started"
|
||||
documentation = "http://byron.github.io/google-apis-rs/google_books1_cli"
|
||||
license = "MIT"
|
||||
keywords = ["books", "google", "cli"]
|
||||
|
||||
[[bin]]
|
||||
name = "books1"
|
||||
|
||||
[dependencies]
|
||||
hyper = "*"
|
||||
mime = "*"
|
||||
yup-oauth2 = "*"
|
||||
docopt = "= 0.6.59"
|
||||
docopt_macros = "= 0.6.59"
|
||||
rustc-serialize = "*"
|
||||
serde = ">= 0.3.0"
|
||||
serde_macros = "*"
|
||||
|
||||
[dependencies.google-books1]
|
||||
path = "../books1"
|
||||
30
gen/books1-cli/LICENSE.md
Normal file
30
gen/books1-cli/LICENSE.md
Normal file
@@ -0,0 +1,30 @@
|
||||
<!---
|
||||
DO NOT EDIT !
|
||||
This file was generated automatically from 'src/mako/LICENSE.md.mako'
|
||||
DO NOT EDIT !
|
||||
-->
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © `2015` `Sebastian Thiel`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
4
gen/books1-cli/README.md
Normal file
4
gen/books1-cli/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# HELLO BOOKS:V1
|
||||
|
||||
|
||||
Include information about application secret files, and how we automatically write a default one.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user