mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-20 10:17:00 +01:00
prepare release of version 2.0, regen all APIs
This commit is contained in:
@@ -1,27 +1,26 @@
|
||||
// COPY OF 'src/rust/cli/cmn.rs'
|
||||
// COPY OF 'src/rust/cli/client.rs'
|
||||
// DO NOT EDIT
|
||||
use oauth2::{ApplicationSecret, ConsoleApplicationSecret, TokenStorage, Token};
|
||||
use clap::{App, SubCommand};
|
||||
use mime::Mime;
|
||||
use oauth2::{ApplicationSecret, ConsoleApplicationSecret};
|
||||
use serde_json as json;
|
||||
use serde_json::value::Value;
|
||||
use mime::Mime;
|
||||
use clap::{App, SubCommand};
|
||||
use strsim;
|
||||
|
||||
use std::fs;
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::io::{stdout, Read, Write};
|
||||
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 = '.';
|
||||
|
||||
|
||||
pub enum ComplexType {
|
||||
Pod,
|
||||
Vec,
|
||||
@@ -83,12 +82,11 @@ pub fn remove_json_null_values(value: &mut Value) {
|
||||
}
|
||||
|
||||
fn did_you_mean<'a>(v: &str, possible_values: &[&'a str]) -> Option<&'a str> {
|
||||
|
||||
let mut candidate: Option<(f64, &str)> = None;
|
||||
for pv in possible_values {
|
||||
let confidence = strsim::jaro_winkler(v, pv);
|
||||
if confidence > 0.8 &&
|
||||
(candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) {
|
||||
if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
|
||||
{
|
||||
candidate = Some((confidence, pv));
|
||||
}
|
||||
}
|
||||
@@ -103,10 +101,10 @@ pub enum CallType {
|
||||
Standard,
|
||||
}
|
||||
|
||||
arg_enum!{
|
||||
arg_enum! {
|
||||
pub enum UploadProtocol {
|
||||
Simple,
|
||||
Resumable
|
||||
// Resumable // This seems to be lost during the async conversion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +112,7 @@ impl AsRef<str> for UploadProtocol {
|
||||
fn as_ref(&self) -> &str {
|
||||
match *self {
|
||||
UploadProtocol::Simple => "simple",
|
||||
UploadProtocol::Resumable => "resumable",
|
||||
// UploadProtocol::Resumable => "resumable",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,7 +129,7 @@ impl AsRef<str> for CallType {
|
||||
#[derive(Clone, Default)]
|
||||
pub struct FieldCursor(Vec<String>);
|
||||
|
||||
impl ToString for FieldCursor {
|
||||
impl ToString for FieldCursor {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.join(".")
|
||||
}
|
||||
@@ -208,7 +206,9 @@ impl FieldCursor {
|
||||
fields.truncate(0);
|
||||
}
|
||||
if char_count > 1 && num_conscutive_field_seps == 1 {
|
||||
return Err(CLIError::Field(FieldError::TrailingFieldSep(value.to_string())));
|
||||
return Err(CLIError::Field(FieldError::TrailingFieldSep(
|
||||
value.to_string(),
|
||||
)));
|
||||
}
|
||||
|
||||
self.0 = fields;
|
||||
@@ -257,20 +257,20 @@ impl FieldCursor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_json_value(&self,
|
||||
mut object: &mut Value,
|
||||
value: &str,
|
||||
type_info: JsonTypeInfo,
|
||||
err: &mut InvalidOptionsError,
|
||||
orig_cursor: &FieldCursor) {
|
||||
pub fn set_json_value(
|
||||
&self,
|
||||
mut object: &mut Value,
|
||||
value: &str,
|
||||
type_info: JsonTypeInfo,
|
||||
err: &mut InvalidOptionsError,
|
||||
orig_cursor: &FieldCursor,
|
||||
) {
|
||||
assert!(self.0.len() > 0);
|
||||
|
||||
for field in &self.0[..self.0.len() - 1] {
|
||||
let tmp = object;
|
||||
object = match *tmp {
|
||||
Value::Object(ref mut mapping) => {
|
||||
assure_entry(mapping, &field)
|
||||
}
|
||||
Value::Object(ref mut mapping) => assure_entry(mapping, &field),
|
||||
_ => panic!("We don't expect non-object Values here ..."),
|
||||
};
|
||||
}
|
||||
@@ -278,58 +278,55 @@ impl FieldCursor {
|
||||
match *object {
|
||||
Value::Object(ref mut mapping) => {
|
||||
let field = &self.0[self.0.len() - 1];
|
||||
let to_jval = |value: &str,
|
||||
jtype: JsonType,
|
||||
err: &mut InvalidOptionsError|
|
||||
-> Value {
|
||||
match jtype {
|
||||
JsonType::Boolean =>
|
||||
Value::Bool(arg_from_str(value, err, &field, "boolean")),
|
||||
JsonType::Int =>
|
||||
Value::Number(json::Number::from_f64(arg_from_str(value,
|
||||
err,
|
||||
&field,
|
||||
"int"))
|
||||
.expect("valid f64")),
|
||||
JsonType::Uint =>
|
||||
Value::Number(json::Number::from_f64(arg_from_str(value,
|
||||
err,
|
||||
&field,
|
||||
"uint"))
|
||||
.expect("valid f64")),
|
||||
JsonType::Float =>
|
||||
Value::Number(json::Number::from_f64(arg_from_str(value,
|
||||
err,
|
||||
&field,
|
||||
"float"))
|
||||
.expect("valid f64")),
|
||||
JsonType::String => Value::String(value.to_owned()),
|
||||
}
|
||||
};
|
||||
let to_jval =
|
||||
|value: &str, jtype: JsonType, err: &mut InvalidOptionsError| -> Value {
|
||||
match jtype {
|
||||
JsonType::Boolean => {
|
||||
Value::Bool(arg_from_str(value, err, &field, "boolean"))
|
||||
}
|
||||
JsonType::Int => Value::Number(
|
||||
json::Number::from_f64(arg_from_str(value, err, &field, "int"))
|
||||
.expect("valid f64"),
|
||||
),
|
||||
JsonType::Uint => Value::Number(
|
||||
json::Number::from_f64(arg_from_str(value, err, &field, "uint"))
|
||||
.expect("valid f64"),
|
||||
),
|
||||
JsonType::Float => Value::Number(
|
||||
json::Number::from_f64(arg_from_str(value, err, &field, "float"))
|
||||
.expect("valid f64"),
|
||||
),
|
||||
JsonType::String => Value::String(value.to_owned()),
|
||||
}
|
||||
};
|
||||
|
||||
match type_info.ctype {
|
||||
ComplexType::Pod => {
|
||||
if mapping.insert(field.to_owned(), to_jval(value, type_info.jtype, err))
|
||||
.is_some() {
|
||||
err.issues.push(CLIError::Field(FieldError::Duplicate(orig_cursor.to_string())));
|
||||
if mapping
|
||||
.insert(field.to_owned(), to_jval(value, type_info.jtype, err))
|
||||
.is_some()
|
||||
{
|
||||
err.issues.push(CLIError::Field(FieldError::Duplicate(
|
||||
orig_cursor.to_string(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
ComplexType::Vec => {
|
||||
match *assure_entry(mapping, field) {
|
||||
Value::Array(ref mut values) =>
|
||||
values.push(to_jval(value, type_info.jtype, err)),
|
||||
_ => unreachable!(),
|
||||
ComplexType::Vec => match *assure_entry(mapping, field) {
|
||||
Value::Array(ref mut values) => {
|
||||
values.push(to_jval(value, type_info.jtype, err))
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
ComplexType::Map => {
|
||||
let (key, value) = parse_kv_arg(value, err, true);
|
||||
let jval = to_jval(value.unwrap_or(""), type_info.jtype, err);
|
||||
|
||||
match *assure_entry(mapping, &field) {
|
||||
|
||||
Value::Object(ref mut value_map) => {
|
||||
if value_map.insert(key.to_owned(), jval).is_some() {
|
||||
err.issues.push(CLIError::Field(FieldError::Duplicate(orig_cursor.to_string())));
|
||||
err.issues.push(CLIError::Field(FieldError::Duplicate(
|
||||
orig_cursor.to_string(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@@ -346,12 +343,14 @@ impl FieldCursor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_kv_arg<'a>(kv: &'a str,
|
||||
err: &mut InvalidOptionsError,
|
||||
for_hashmap: bool)
|
||||
-> (&'a str, Option<&'a str>) {
|
||||
pub fn parse_kv_arg<'a>(
|
||||
kv: &'a str,
|
||||
err: &mut InvalidOptionsError,
|
||||
for_hashmap: bool,
|
||||
) -> (&'a str, Option<&'a str>) {
|
||||
let mut add_err = || {
|
||||
err.issues.push(CLIError::InvalidKeyValueSyntax(kv.to_string(), for_hashmap))
|
||||
err.issues
|
||||
.push(CLIError::InvalidKeyValueSyntax(kv.to_string(), for_hashmap))
|
||||
};
|
||||
match kv.find('=') {
|
||||
None => {
|
||||
@@ -369,14 +368,18 @@ pub fn parse_kv_arg<'a>(kv: &'a str,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calltype_from_str(name: &str,
|
||||
valid_protocols: Vec<String>,
|
||||
err: &mut InvalidOptionsError)
|
||||
-> CallType {
|
||||
pub fn calltype_from_str(
|
||||
name: &str,
|
||||
valid_protocols: Vec<String>,
|
||||
err: &mut InvalidOptionsError,
|
||||
) -> CallType {
|
||||
CallType::Upload(match UploadProtocol::from_str(name) {
|
||||
Ok(up) => up,
|
||||
Err(msg) => {
|
||||
err.issues.push(CLIError::InvalidUploadProtocol(name.to_string(), valid_protocols));
|
||||
err.issues.push(CLIError::InvalidUploadProtocol(
|
||||
name.to_string(),
|
||||
valid_protocols,
|
||||
));
|
||||
UploadProtocol::Simple
|
||||
}
|
||||
})
|
||||
@@ -386,7 +389,10 @@ pub fn input_file_from_opts(file_path: &str, err: &mut InvalidOptionsError) -> O
|
||||
match fs::File::open(file_path) {
|
||||
Ok(f) => Some(f),
|
||||
Err(io_err) => {
|
||||
err.issues.push(CLIError::Input(InputError::Io((file_path.to_string(), io_err))));
|
||||
err.issues.push(CLIError::Input(InputError::Io((
|
||||
file_path.to_string(),
|
||||
io_err,
|
||||
))));
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -396,7 +402,8 @@ pub fn input_mime_from_opts(mime: &str, err: &mut InvalidOptionsError) -> Option
|
||||
match mime.parse() {
|
||||
Ok(m) => Some(m),
|
||||
Err(_) => {
|
||||
err.issues.push(CLIError::Input(InputError::Mime(mime.to_string())));
|
||||
err.issues
|
||||
.push(CLIError::Input(InputError::Mime(mime.to_string())));
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -406,120 +413,42 @@ pub fn writer_from_opts(arg: Option<&str>) -> Result<Box<dyn Write>, io::Error>
|
||||
let f = arg.unwrap_or("-");
|
||||
match f {
|
||||
"-" => Ok(Box::new(stdout())),
|
||||
_ => match fs::OpenOptions::new().create(true).truncate(true).write(true).open(f) {
|
||||
_ => match fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(f)
|
||||
{
|
||||
Ok(f) => Ok(Box::new(f)),
|
||||
Err(io_err) => Err(io_err),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn arg_from_str<'a, T>(arg: &str,
|
||||
err: &mut InvalidOptionsError,
|
||||
arg_name: &'a str,
|
||||
arg_type: &'a str)
|
||||
-> T
|
||||
where T: FromStr + Default,
|
||||
<T as FromStr>::Err: fmt::Display
|
||||
pub fn arg_from_str<'a, T>(
|
||||
arg: &str,
|
||||
err: &mut InvalidOptionsError,
|
||||
arg_name: &'a str,
|
||||
arg_type: &'a 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.to_owned(),
|
||||
arg_type.to_owned(),
|
||||
arg.to_string(),
|
||||
format!("{}", perr)));
|
||||
err.issues.push(CLIError::ParseError(
|
||||
arg_name.to_owned(),
|
||||
arg_type.to_owned(),
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TokenStorageError {
|
||||
Json(json::Error),
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for TokenStorageError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
TokenStorageError::Json(ref err) => writeln!(f, "Could not serialize secrets: {}", err),
|
||||
TokenStorageError::Io(ref err) => writeln!(f, "Failed to write secret token: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for TokenStorageError {
|
||||
fn description(&self) -> &str {
|
||||
"Failure when getting or setting the token storage"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl TokenStorage for JsonTokenStorage {
|
||||
type Error = TokenStorageError;
|
||||
|
||||
// NOTE: logging might be interesting, currently we swallow all errors
|
||||
fn set(&mut self,
|
||||
scope_hash: u64,
|
||||
_: &Vec<&str>,
|
||||
token: Option<Token>)
|
||||
-> Result<(), TokenStorageError> {
|
||||
match token {
|
||||
None => {
|
||||
match fs::remove_file(self.path(scope_hash)) {
|
||||
Err(err) => match err.kind() {
|
||||
io::ErrorKind::NotFound => Ok(()),
|
||||
_ => Err(TokenStorageError::Io(err)),
|
||||
},
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
Some(token) => {
|
||||
match fs::OpenOptions::new().create(true).write(true).truncate(true).open(&self.path(scope_hash)) {
|
||||
Ok(mut f) => {
|
||||
match json::to_writer_pretty(&mut f, &token) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(serde_err) => Err(TokenStorageError::Json(serde_err)),
|
||||
}
|
||||
}
|
||||
Err(io_err) => Err(TokenStorageError::Io(io_err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, TokenStorageError> {
|
||||
match fs::File::open(&self.path(scope_hash)) {
|
||||
Ok(f) => {
|
||||
match json::de::from_reader(f) {
|
||||
Ok(token) => Ok(Some(token)),
|
||||
Err(err) => Err(TokenStorageError::Json(err)),
|
||||
}
|
||||
}
|
||||
Err(io_err) => {
|
||||
match io_err.kind() {
|
||||
io::ErrorKind::NotFound => Ok(None),
|
||||
_ => Err(TokenStorageError::Io(io_err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ApplicationSecretError {
|
||||
DecoderError((String, json::Error)),
|
||||
@@ -529,15 +458,16 @@ pub enum ApplicationSecretError {
|
||||
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),
|
||||
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
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,22 +484,23 @@ pub enum ConfigurationError {
|
||||
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::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::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::Io((ref path, ref err)) =>
|
||||
writeln!(f,
|
||||
"IO operation failed on path '{}' with error: {}.",
|
||||
path,
|
||||
err),
|
||||
ConfigurationError::Io((ref path, ref err)) => writeln!(
|
||||
f,
|
||||
"IO operation failed on path '{}' with error: {}.",
|
||||
path, err
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -583,11 +514,11 @@ pub enum InputError {
|
||||
impl fmt::Display for InputError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
InputError::Io((ref file_path, ref io_err)) =>
|
||||
writeln!(f,
|
||||
"Failed to open '{}' for reading with error: {}.",
|
||||
file_path,
|
||||
io_err),
|
||||
InputError::Io((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),
|
||||
}
|
||||
}
|
||||
@@ -602,16 +533,17 @@ pub enum FieldError {
|
||||
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::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, ref suggestion, ref value) => {
|
||||
let suffix = match *suggestion {
|
||||
Some(ref s) => {
|
||||
@@ -625,14 +557,14 @@ impl fmt::Display for FieldError {
|
||||
};
|
||||
writeln!(f, "Field '{}' does not exist.{}", field, suffix)
|
||||
}
|
||||
FieldError::Duplicate(ref cursor) =>
|
||||
writeln!(f, "Value at '{}' was already set", cursor),
|
||||
FieldError::Duplicate(ref cursor) => {
|
||||
writeln!(f, "Value at '{}' was already set", cursor)
|
||||
}
|
||||
FieldError::Empty => writeln!(f, "Field names must not be empty."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CLIError {
|
||||
Configuration(ConfigurationError),
|
||||
@@ -652,18 +584,17 @@ impl fmt::Display for CLIError {
|
||||
CLIError::Configuration(ref err) => write!(f, "Configuration -> {}", err),
|
||||
CLIError::Input(ref err) => write!(f, "Input -> {}", err),
|
||||
CLIError::Field(ref err) => write!(f, "Field -> {}", err),
|
||||
CLIError::InvalidUploadProtocol(ref proto_name, ref valid_names) =>
|
||||
writeln!(f,
|
||||
"'{}' is not a valid upload protocol. Choose from one of {}.",
|
||||
proto_name,
|
||||
valid_names.join(", ")),
|
||||
CLIError::ParseError(ref arg_name, ref 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::InvalidUploadProtocol(ref proto_name, ref valid_names) => writeln!(
|
||||
f,
|
||||
"'{}' is not a valid upload protocol. Choose from one of {}.",
|
||||
proto_name,
|
||||
valid_names.join(", ")
|
||||
),
|
||||
CLIError::ParseError(ref arg_name, ref 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, ref possible_values) => {
|
||||
let suffix = match did_you_mean(param_name, &possible_values) {
|
||||
Some(v) => format!(" Did you mean '{}' ?", v),
|
||||
@@ -672,21 +603,19 @@ impl fmt::Display for CLIError {
|
||||
write!(f, "Parameter '{}' is unknown.{}\n", param_name, suffix)
|
||||
}
|
||||
CLIError::InvalidKeyValueSyntax(ref kv, is_hashmap) => {
|
||||
let hashmap_info = if is_hashmap {
|
||||
"hashmap "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
writeln!(f,
|
||||
"'{}' does not match {}pattern <key>=<value>.",
|
||||
kv,
|
||||
hashmap_info)
|
||||
let hashmap_info = if is_hashmap { "hashmap " } else { "" };
|
||||
writeln!(
|
||||
f,
|
||||
"'{}' does not match {}pattern <key>=<value>.",
|
||||
kv, hashmap_info
|
||||
)
|
||||
}
|
||||
CLIError::MissingCommandError => writeln!(f, "Please specify the main sub-command."),
|
||||
CLIError::MissingMethodError(ref cmd) =>
|
||||
writeln!(f,
|
||||
"Please specify the method to call on the '{}' command.",
|
||||
cmd),
|
||||
CLIError::MissingMethodError(ref cmd) => writeln!(
|
||||
f,
|
||||
"Please specify the method to call on the '{}' command.",
|
||||
cmd
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,7 +659,11 @@ pub fn assure_config_dir_exists(dir: &str) -> Result<String, CLIError> {
|
||||
|
||||
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()))),
|
||||
None => {
|
||||
return Err(CLIError::Configuration(
|
||||
ConfigurationError::HomeExpansionFailed(trdir.to_string()),
|
||||
))
|
||||
}
|
||||
Some(mut user) => {
|
||||
user.push_str(&trdir[1..]);
|
||||
user
|
||||
@@ -743,21 +676,26 @@ pub fn assure_config_dir_exists(dir: &str) -> Result<String, CLIError> {
|
||||
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))));
|
||||
ConfigurationError::DirectoryCreationFailed((expanded_config_dir, err)),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(expanded_config_dir)
|
||||
}
|
||||
|
||||
pub fn application_secret_from_directory(dir: &str,
|
||||
secret_basename: &str,
|
||||
json_console_secret: &str)
|
||||
-> Result<ApplicationSecret, CLIError> {
|
||||
pub fn application_secret_from_directory(
|
||||
dir: &str,
|
||||
secret_basename: &str,
|
||||
json_console_secret: &str,
|
||||
) -> Result<ApplicationSecret, CLIError> {
|
||||
let secret_path = Path::new(dir).join(secret_basename);
|
||||
let secret_str = || secret_path.as_path().to_str().unwrap().to_string();
|
||||
let secret_io_error = |io_err: io::Error| {
|
||||
Err(CLIError::Configuration(ConfigurationError::Io((secret_str(), io_err))))
|
||||
Err(CLIError::Configuration(ConfigurationError::Io((
|
||||
secret_str(),
|
||||
io_err,
|
||||
))))
|
||||
};
|
||||
|
||||
for _ in 0..2 {
|
||||
@@ -767,18 +705,20 @@ pub fn application_secret_from_directory(dir: &str,
|
||||
// Write our built-in one - user may adjust the written file at will
|
||||
|
||||
err = match fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&secret_path) {
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&secret_path)
|
||||
{
|
||||
Err(cfe) => cfe,
|
||||
Ok(mut f) => {
|
||||
// Assure we convert 'ugly' json string into pretty one
|
||||
let console_secret: ConsoleApplicationSecret =
|
||||
json::from_str(json_console_secret).unwrap();
|
||||
match json::to_writer_pretty(&mut f, &console_secret) {
|
||||
Err(serde_err) =>
|
||||
panic!("Unexpected serde error: {:#?}", serde_err),
|
||||
Err(serde_err) => {
|
||||
panic!("Unexpected serde error: {:#?}", serde_err)
|
||||
}
|
||||
Ok(_) => continue,
|
||||
}
|
||||
}
|
||||
@@ -787,24 +727,21 @@ pub fn application_secret_from_directory(dir: &str,
|
||||
}
|
||||
return secret_io_error(err);
|
||||
}
|
||||
Ok(f) => {
|
||||
match json::de::from_reader::<_, ConsoleApplicationSecret>(f) {
|
||||
Err(json_err) =>
|
||||
return Err(CLIError::Configuration(
|
||||
ConfigurationError::Secret(
|
||||
ApplicationSecretError::DecoderError(
|
||||
(secret_str(), json_err)
|
||||
)))),
|
||||
Ok(console_secret) => match console_secret.installed {
|
||||
Some(secret) => return Ok(secret),
|
||||
None => return Err(
|
||||
CLIError::Configuration(
|
||||
ConfigurationError::Secret(
|
||||
ApplicationSecretError::FormatError(secret_str())
|
||||
))),
|
||||
},
|
||||
Ok(f) => match json::de::from_reader::<_, ConsoleApplicationSecret>(f) {
|
||||
Err(json_err) => {
|
||||
return Err(CLIError::Configuration(ConfigurationError::Secret(
|
||||
ApplicationSecretError::DecoderError((secret_str(), json_err)),
|
||||
)))
|
||||
}
|
||||
}
|
||||
Ok(console_secret) => match console_secret.installed {
|
||||
Some(secret) => return Ok(secret),
|
||||
None => {
|
||||
return Err(CLIError::Configuration(ConfigurationError::Secret(
|
||||
ApplicationSecretError::FormatError(secret_str()),
|
||||
)))
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
unreachable!();
|
||||
@@ -3,50 +3,46 @@
|
||||
// DO NOT EDIT !
|
||||
#![allow(unused_variables, unused_imports, dead_code, unused_mut)]
|
||||
|
||||
extern crate tokio;
|
||||
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate yup_oauth2 as oauth2;
|
||||
extern crate yup_hyper_mock as mock;
|
||||
extern crate hyper_rustls;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate hyper;
|
||||
extern crate mime;
|
||||
extern crate strsim;
|
||||
extern crate google_cloudshell1 as api;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use clap::{App, SubCommand, Arg};
|
||||
|
||||
mod cmn;
|
||||
use google_cloudshell1::{api, Error};
|
||||
|
||||
use cmn::{InvalidOptionsError, CLIError, JsonTokenStorage, arg_from_str, writer_from_opts, parse_kv_arg,
|
||||
mod client;
|
||||
|
||||
use client::{InvalidOptionsError, CLIError, arg_from_str, writer_from_opts, parse_kv_arg,
|
||||
input_file_from_opts, input_mime_from_opts, FieldCursor, FieldError, CallType, UploadProtocol,
|
||||
calltype_from_str, remove_json_null_values, ComplexType, JsonType, JsonTypeInfo};
|
||||
|
||||
use std::default::Default;
|
||||
use std::str::FromStr;
|
||||
|
||||
use oauth2::{Authenticator, DefaultAuthenticatorDelegate, FlowType};
|
||||
use serde_json as json;
|
||||
use clap::ArgMatches;
|
||||
|
||||
enum DoitError {
|
||||
IoError(String, io::Error),
|
||||
ApiError(api::Error),
|
||||
ApiError(Error),
|
||||
}
|
||||
|
||||
struct Engine<'n> {
|
||||
opt: ArgMatches<'n>,
|
||||
hub: api::CloudShell<hyper::Client, Authenticator<DefaultAuthenticatorDelegate, JsonTokenStorage, hyper::Client>>,
|
||||
hub: api::CloudShell<hyper::Client<hyper_rustls::HttpsConnector<hyper::client::connect::HttpConnector>, hyper::body::Body>
|
||||
>,
|
||||
gp: Vec<&'static str>,
|
||||
gpm: Vec<(&'static str, &'static str)>,
|
||||
}
|
||||
|
||||
|
||||
impl<'n> Engine<'n> {
|
||||
fn _operations_cancel(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
async fn _operations_cancel(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
@@ -115,7 +111,7 @@ impl<'n> Engine<'n> {
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit(),
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
@@ -130,7 +126,7 @@ impl<'n> Engine<'n> {
|
||||
}
|
||||
}
|
||||
|
||||
fn _operations_delete(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
async fn _operations_delete(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
let mut call = self.hub.operations().delete(opt.value_of("name").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
@@ -167,7 +163,7 @@ impl<'n> Engine<'n> {
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit(),
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
@@ -182,7 +178,7 @@ impl<'n> Engine<'n> {
|
||||
}
|
||||
}
|
||||
|
||||
fn _operations_get(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
async fn _operations_get(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
let mut call = self.hub.operations().get(opt.value_of("name").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
@@ -219,7 +215,7 @@ impl<'n> Engine<'n> {
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit(),
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
@@ -234,7 +230,7 @@ impl<'n> Engine<'n> {
|
||||
}
|
||||
}
|
||||
|
||||
fn _operations_list(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
async fn _operations_list(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
let mut call = self.hub.operations().list(opt.value_of("name").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
@@ -262,7 +258,7 @@ impl<'n> Engine<'n> {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
{let mut v = Vec::new();
|
||||
v.extend(self.gp.iter().map(|v|*v));
|
||||
v.extend(["filter", "page-token", "page-size"].iter().map(|v|*v));
|
||||
v.extend(["filter", "page-size", "page-token"].iter().map(|v|*v));
|
||||
v } ));
|
||||
}
|
||||
}
|
||||
@@ -281,7 +277,7 @@ impl<'n> Engine<'n> {
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit(),
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
@@ -296,7 +292,402 @@ impl<'n> Engine<'n> {
|
||||
}
|
||||
}
|
||||
|
||||
fn _doit(&self, dry_run: bool) -> Result<Result<(), DoitError>, Option<InvalidOptionsError>> {
|
||||
async fn _users_environments_add_public_key(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
let mut object = json::value::Value::Object(Default::default());
|
||||
|
||||
for kvarg in opt.values_of("kv").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let last_errc = err.issues.len();
|
||||
let (key, value) = parse_kv_arg(&*kvarg, err, false);
|
||||
let mut temp_cursor = field_cursor.clone();
|
||||
if let Err(field_err) = temp_cursor.set(&*key) {
|
||||
err.issues.push(field_err);
|
||||
}
|
||||
if value.is_none() {
|
||||
field_cursor = temp_cursor.clone();
|
||||
if err.issues.len() > last_errc {
|
||||
err.issues.remove(last_errc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let type_info: Option<(&'static str, JsonTypeInfo)> =
|
||||
match &temp_cursor.to_string()[..] {
|
||||
"key" => Some(("key", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Pod })),
|
||||
_ => {
|
||||
let suggestion = FieldCursor::did_you_mean(key, &vec!["key"]);
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string(), suggestion, value.map(|v| v.to_string()))));
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some((field_cursor_str, type_info)) = type_info {
|
||||
FieldCursor::from(field_cursor_str).set_json_value(&mut object, value.unwrap(), type_info, err, &temp_cursor);
|
||||
}
|
||||
}
|
||||
let mut request: api::AddPublicKeyRequest = json::value::from_value(object).unwrap();
|
||||
let mut call = self.hub.users().environments_add_public_key(request, opt.value_of("environment").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
{let mut v = Vec::new();
|
||||
v.extend(self.gp.iter().map(|v|*v));
|
||||
v } ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
for scope in self.opt.values_of("url").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
let mut value = json::value::to_value(&output_schema).expect("serde to work");
|
||||
remove_json_null_values(&mut value);
|
||||
json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
ostream.flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _users_environments_authorize(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
let mut object = json::value::Value::Object(Default::default());
|
||||
|
||||
for kvarg in opt.values_of("kv").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let last_errc = err.issues.len();
|
||||
let (key, value) = parse_kv_arg(&*kvarg, err, false);
|
||||
let mut temp_cursor = field_cursor.clone();
|
||||
if let Err(field_err) = temp_cursor.set(&*key) {
|
||||
err.issues.push(field_err);
|
||||
}
|
||||
if value.is_none() {
|
||||
field_cursor = temp_cursor.clone();
|
||||
if err.issues.len() > last_errc {
|
||||
err.issues.remove(last_errc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let type_info: Option<(&'static str, JsonTypeInfo)> =
|
||||
match &temp_cursor.to_string()[..] {
|
||||
"access-token" => Some(("accessToken", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Pod })),
|
||||
"expire-time" => Some(("expireTime", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Pod })),
|
||||
"id-token" => Some(("idToken", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Pod })),
|
||||
_ => {
|
||||
let suggestion = FieldCursor::did_you_mean(key, &vec!["access-token", "expire-time", "id-token"]);
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string(), suggestion, value.map(|v| v.to_string()))));
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some((field_cursor_str, type_info)) = type_info {
|
||||
FieldCursor::from(field_cursor_str).set_json_value(&mut object, value.unwrap(), type_info, err, &temp_cursor);
|
||||
}
|
||||
}
|
||||
let mut request: api::AuthorizeEnvironmentRequest = json::value::from_value(object).unwrap();
|
||||
let mut call = self.hub.users().environments_authorize(request, opt.value_of("name").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
{let mut v = Vec::new();
|
||||
v.extend(self.gp.iter().map(|v|*v));
|
||||
v } ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
for scope in self.opt.values_of("url").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
let mut value = json::value::to_value(&output_schema).expect("serde to work");
|
||||
remove_json_null_values(&mut value);
|
||||
json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
ostream.flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _users_environments_get(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
let mut call = self.hub.users().environments_get(opt.value_of("name").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
{let mut v = Vec::new();
|
||||
v.extend(self.gp.iter().map(|v|*v));
|
||||
v } ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
for scope in self.opt.values_of("url").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
let mut value = json::value::to_value(&output_schema).expect("serde to work");
|
||||
remove_json_null_values(&mut value);
|
||||
json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
ostream.flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _users_environments_remove_public_key(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
let mut object = json::value::Value::Object(Default::default());
|
||||
|
||||
for kvarg in opt.values_of("kv").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let last_errc = err.issues.len();
|
||||
let (key, value) = parse_kv_arg(&*kvarg, err, false);
|
||||
let mut temp_cursor = field_cursor.clone();
|
||||
if let Err(field_err) = temp_cursor.set(&*key) {
|
||||
err.issues.push(field_err);
|
||||
}
|
||||
if value.is_none() {
|
||||
field_cursor = temp_cursor.clone();
|
||||
if err.issues.len() > last_errc {
|
||||
err.issues.remove(last_errc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let type_info: Option<(&'static str, JsonTypeInfo)> =
|
||||
match &temp_cursor.to_string()[..] {
|
||||
"key" => Some(("key", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Pod })),
|
||||
_ => {
|
||||
let suggestion = FieldCursor::did_you_mean(key, &vec!["key"]);
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string(), suggestion, value.map(|v| v.to_string()))));
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some((field_cursor_str, type_info)) = type_info {
|
||||
FieldCursor::from(field_cursor_str).set_json_value(&mut object, value.unwrap(), type_info, err, &temp_cursor);
|
||||
}
|
||||
}
|
||||
let mut request: api::RemovePublicKeyRequest = json::value::from_value(object).unwrap();
|
||||
let mut call = self.hub.users().environments_remove_public_key(request, opt.value_of("environment").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
{let mut v = Vec::new();
|
||||
v.extend(self.gp.iter().map(|v|*v));
|
||||
v } ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
for scope in self.opt.values_of("url").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
let mut value = json::value::to_value(&output_schema).expect("serde to work");
|
||||
remove_json_null_values(&mut value);
|
||||
json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
ostream.flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _users_environments_start(&self, opt: &ArgMatches<'n>, dry_run: bool, err: &mut InvalidOptionsError)
|
||||
-> Result<(), DoitError> {
|
||||
|
||||
let mut field_cursor = FieldCursor::default();
|
||||
let mut object = json::value::Value::Object(Default::default());
|
||||
|
||||
for kvarg in opt.values_of("kv").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let last_errc = err.issues.len();
|
||||
let (key, value) = parse_kv_arg(&*kvarg, err, false);
|
||||
let mut temp_cursor = field_cursor.clone();
|
||||
if let Err(field_err) = temp_cursor.set(&*key) {
|
||||
err.issues.push(field_err);
|
||||
}
|
||||
if value.is_none() {
|
||||
field_cursor = temp_cursor.clone();
|
||||
if err.issues.len() > last_errc {
|
||||
err.issues.remove(last_errc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let type_info: Option<(&'static str, JsonTypeInfo)> =
|
||||
match &temp_cursor.to_string()[..] {
|
||||
"access-token" => Some(("accessToken", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Pod })),
|
||||
"public-keys" => Some(("publicKeys", JsonTypeInfo { jtype: JsonType::String, ctype: ComplexType::Vec })),
|
||||
_ => {
|
||||
let suggestion = FieldCursor::did_you_mean(key, &vec!["access-token", "public-keys"]);
|
||||
err.issues.push(CLIError::Field(FieldError::Unknown(temp_cursor.to_string(), suggestion, value.map(|v| v.to_string()))));
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some((field_cursor_str, type_info)) = type_info {
|
||||
FieldCursor::from(field_cursor_str).set_json_value(&mut object, value.unwrap(), type_info, err, &temp_cursor);
|
||||
}
|
||||
}
|
||||
let mut request: api::StartEnvironmentRequest = json::value::from_value(object).unwrap();
|
||||
let mut call = self.hub.users().environments_start(request, opt.value_of("name").unwrap_or(""));
|
||||
for parg in opt.values_of("v").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
let (key, value) = parse_kv_arg(&*parg, err, false);
|
||||
match key {
|
||||
_ => {
|
||||
let mut found = false;
|
||||
for param in &self.gp {
|
||||
if key == *param {
|
||||
found = true;
|
||||
call = call.param(self.gpm.iter().find(|t| t.0 == key).unwrap_or(&("", key)).1, value.unwrap_or("unset"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
err.issues.push(CLIError::UnknownParameter(key.to_string(),
|
||||
{let mut v = Vec::new();
|
||||
v.extend(self.gp.iter().map(|v|*v));
|
||||
v } ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let protocol = CallType::Standard;
|
||||
if dry_run {
|
||||
Ok(())
|
||||
} else {
|
||||
assert!(err.issues.len() == 0);
|
||||
for scope in self.opt.values_of("url").map(|i|i.collect()).unwrap_or(Vec::new()).iter() {
|
||||
call = call.add_scope(scope);
|
||||
}
|
||||
let mut ostream = match writer_from_opts(opt.value_of("out")) {
|
||||
Ok(mut f) => f,
|
||||
Err(io_err) => return Err(DoitError::IoError(opt.value_of("out").unwrap_or("-").to_string(), io_err)),
|
||||
};
|
||||
match match protocol {
|
||||
CallType::Standard => call.doit().await,
|
||||
_ => unreachable!()
|
||||
} {
|
||||
Err(api_err) => Err(DoitError::ApiError(api_err)),
|
||||
Ok((mut response, output_schema)) => {
|
||||
let mut value = json::value::to_value(&output_schema).expect("serde to work");
|
||||
remove_json_null_values(&mut value);
|
||||
json::to_writer_pretty(&mut ostream, &value).unwrap();
|
||||
ostream.flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _doit(&self, dry_run: bool) -> Result<Result<(), DoitError>, Option<InvalidOptionsError>> {
|
||||
let mut err = InvalidOptionsError::new();
|
||||
let mut call_result: Result<(), DoitError> = Ok(());
|
||||
let mut err_opt: Option<InvalidOptionsError> = None;
|
||||
@@ -304,16 +695,16 @@ impl<'n> Engine<'n> {
|
||||
("operations", Some(opt)) => {
|
||||
match opt.subcommand() {
|
||||
("cancel", Some(opt)) => {
|
||||
call_result = self._operations_cancel(opt, dry_run, &mut err);
|
||||
call_result = self._operations_cancel(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("delete", Some(opt)) => {
|
||||
call_result = self._operations_delete(opt, dry_run, &mut err);
|
||||
call_result = self._operations_delete(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("get", Some(opt)) => {
|
||||
call_result = self._operations_get(opt, dry_run, &mut err);
|
||||
call_result = self._operations_get(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("list", Some(opt)) => {
|
||||
call_result = self._operations_list(opt, dry_run, &mut err);
|
||||
call_result = self._operations_list(opt, dry_run, &mut err).await;
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::MissingMethodError("operations".to_string()));
|
||||
@@ -321,6 +712,29 @@ impl<'n> Engine<'n> {
|
||||
}
|
||||
}
|
||||
},
|
||||
("users", Some(opt)) => {
|
||||
match opt.subcommand() {
|
||||
("environments-add-public-key", Some(opt)) => {
|
||||
call_result = self._users_environments_add_public_key(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("environments-authorize", Some(opt)) => {
|
||||
call_result = self._users_environments_authorize(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("environments-get", Some(opt)) => {
|
||||
call_result = self._users_environments_get(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("environments-remove-public-key", Some(opt)) => {
|
||||
call_result = self._users_environments_remove_public_key(opt, dry_run, &mut err).await;
|
||||
},
|
||||
("environments-start", Some(opt)) => {
|
||||
call_result = self._users_environments_start(opt, dry_run, &mut err).await;
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::MissingMethodError("users".to_string()));
|
||||
writeln!(io::stderr(), "{}\n", opt.usage()).ok();
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
err.issues.push(CLIError::MissingCommandError);
|
||||
writeln!(io::stderr(), "{}\n", self.opt.usage()).ok();
|
||||
@@ -338,41 +752,26 @@ impl<'n> Engine<'n> {
|
||||
}
|
||||
|
||||
// Please note that this call will fail if any part of the opt can't be handled
|
||||
fn new(opt: ArgMatches<'n>) -> Result<Engine<'n>, InvalidOptionsError> {
|
||||
async fn new(opt: ArgMatches<'n>) -> Result<Engine<'n>, InvalidOptionsError> {
|
||||
let (config_dir, secret) = {
|
||||
let config_dir = match cmn::assure_config_dir_exists(opt.value_of("folder").unwrap_or("~/.google-service-cli")) {
|
||||
let config_dir = match client::assure_config_dir_exists(opt.value_of("folder").unwrap_or("~/.google-service-cli")) {
|
||||
Err(e) => return Err(InvalidOptionsError::single(e, 3)),
|
||||
Ok(p) => p,
|
||||
};
|
||||
|
||||
match cmn::application_secret_from_directory(&config_dir, "cloudshell1-secret.json",
|
||||
match client::application_secret_from_directory(&config_dir, "cloudshell1-secret.json",
|
||||
"{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"hCsslbCUyfehWMmbkG8vTYxG\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"620010449518-9ngf7o4dhs0dka470npqvor6dc5lqb9b.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}") {
|
||||
Ok(secret) => (config_dir, secret),
|
||||
Err(e) => return Err(InvalidOptionsError::single(e, 4))
|
||||
}
|
||||
};
|
||||
|
||||
let auth = Authenticator::new( &secret, DefaultAuthenticatorDelegate,
|
||||
if opt.is_present("debug-auth") {
|
||||
hyper::Client::with_connector(mock::TeeConnector {
|
||||
connector: hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
|
||||
})
|
||||
} else {
|
||||
hyper::Client::with_connector(hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new()))
|
||||
},
|
||||
JsonTokenStorage {
|
||||
program_name: "cloudshell1",
|
||||
db_dir: config_dir.clone(),
|
||||
}, Some(FlowType::InstalledRedirect(54324)));
|
||||
let auth = yup_oauth2::InstalledFlowAuthenticator::builder(
|
||||
secret,
|
||||
yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect,
|
||||
).persist_tokens_to_disk(format!("{}/cloudshell1", config_dir)).build().await.unwrap();
|
||||
|
||||
let client =
|
||||
if opt.is_present("debug") {
|
||||
hyper::Client::with_connector(mock::TeeConnector {
|
||||
connector: hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new())
|
||||
})
|
||||
} else {
|
||||
hyper::Client::with_connector(hyper::net::HttpsConnector::new(hyper_rustls::TlsClient::new()))
|
||||
};
|
||||
let client = hyper::Client::builder().build(hyper_rustls::HttpsConnector::with_native_roots());
|
||||
let engine = Engine {
|
||||
opt: opt,
|
||||
hub: api::CloudShell::new(client, auth),
|
||||
@@ -388,36 +787,28 @@ impl<'n> Engine<'n> {
|
||||
]
|
||||
};
|
||||
|
||||
match engine._doit(true) {
|
||||
match engine._doit(true).await {
|
||||
Err(Some(err)) => Err(err),
|
||||
Err(None) => Ok(engine),
|
||||
Ok(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn doit(&self) -> Result<(), DoitError> {
|
||||
match self._doit(false) {
|
||||
async fn doit(&self) -> Result<(), DoitError> {
|
||||
match self._doit(false).await {
|
||||
Ok(res) => res,
|
||||
Err(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut exit_status = 0i32;
|
||||
let arg_data = [
|
||||
("operations", "methods: 'cancel', 'delete', 'get' and 'list'", vec![
|
||||
("cancel",
|
||||
Some(r##"Starts asynchronous cancellation on a long-running operation. The server
|
||||
makes a best effort to cancel the operation, but success is not
|
||||
guaranteed. If the server doesn't support this method, it returns
|
||||
`google.rpc.Code.UNIMPLEMENTED`. Clients can use
|
||||
Operations.GetOperation or
|
||||
other methods to check whether the cancellation succeeded or whether the
|
||||
operation completed despite cancellation. On successful cancellation,
|
||||
the operation is not deleted; instead, it becomes an operation with
|
||||
an Operation.error value with a google.rpc.Status.code of 1,
|
||||
corresponding to `Code.CANCELLED`."##),
|
||||
Some(r##"Starts asynchronous cancellation on a long-running operation. The server makes a best effort to cancel the operation, but success is not guaranteed. If the server doesn't support this method, it returns `google.rpc.Code.UNIMPLEMENTED`. Clients can use Operations.GetOperation or other methods to check whether the cancellation succeeded or whether the operation completed despite cancellation. On successful cancellation, the operation is not deleted; instead, it becomes an operation with an Operation.error value with a google.rpc.Status.code of 1, corresponding to `Code.CANCELLED`."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/operations_cancel",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
@@ -445,10 +836,7 @@ fn main() {
|
||||
Some(false)),
|
||||
]),
|
||||
("delete",
|
||||
Some(r##"Deletes a long-running operation. This method indicates that the client is
|
||||
no longer interested in the operation result. It does not cancel the
|
||||
operation. If the server doesn't support this method, it returns
|
||||
`google.rpc.Code.UNIMPLEMENTED`."##),
|
||||
Some(r##"Deletes a long-running operation. This method indicates that the client is no longer interested in the operation result. It does not cancel the operation. If the server doesn't support this method, it returns `google.rpc.Code.UNIMPLEMENTED`."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/operations_delete",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
@@ -470,9 +858,7 @@ fn main() {
|
||||
Some(false)),
|
||||
]),
|
||||
("get",
|
||||
Some(r##"Gets the latest state of a long-running operation. Clients can use this
|
||||
method to poll the operation result at intervals as recommended by the API
|
||||
service."##),
|
||||
Some(r##"Gets the latest state of a long-running operation. Clients can use this method to poll the operation result at intervals as recommended by the API service."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/operations_get",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
@@ -494,16 +880,7 @@ fn main() {
|
||||
Some(false)),
|
||||
]),
|
||||
("list",
|
||||
Some(r##"Lists operations that match the specified filter in the request. If the
|
||||
server doesn't support this method, it returns `UNIMPLEMENTED`.
|
||||
|
||||
NOTE: the `name` binding allows API services to override the binding
|
||||
to use different resource name schemes, such as `users/*/operations`. To
|
||||
override the binding, API services can add a binding such as
|
||||
`"/v1/{name=users/*}/operations"` to their service configuration.
|
||||
For backwards compatibility, the default name includes the operations
|
||||
collection id, however overriding users must ensure the name binding
|
||||
is the parent resource, without the operations collection id."##),
|
||||
Some(r##"Lists operations that match the specified filter in the request. If the server doesn't support this method, it returns `UNIMPLEMENTED`. NOTE: the `name` binding allows API services to override the binding to use different resource name schemes, such as `users/*/operations`. To override the binding, API services can add a binding such as `"/v1/{name=users/*}/operations"` to their service configuration. For backwards compatibility, the default name includes the operations collection id, however overriding users must ensure the name binding is the parent resource, without the operations collection id."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/operations_list",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
@@ -526,13 +903,149 @@ fn main() {
|
||||
]),
|
||||
]),
|
||||
|
||||
("users", "methods: 'environments-add-public-key', 'environments-authorize', 'environments-get', 'environments-remove-public-key' and 'environments-start'", vec![
|
||||
("environments-add-public-key",
|
||||
Some(r##"Adds a public SSH key to an environment, allowing clients with the corresponding private key to connect to that environment via SSH. If a key with the same content already exists, this will error with ALREADY_EXISTS."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/users_environments-add-public-key",
|
||||
vec![
|
||||
(Some(r##"environment"##),
|
||||
None,
|
||||
Some(r##"Environment this key should be added to, e.g. `users/me/environments/default`."##),
|
||||
Some(true),
|
||||
Some(false)),
|
||||
|
||||
(Some(r##"kv"##),
|
||||
Some(r##"r"##),
|
||||
Some(r##"Set various fields of the request structure, matching the key=value form"##),
|
||||
Some(true),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
("environments-authorize",
|
||||
Some(r##"Sends OAuth credentials to a running environment on behalf of a user. When this completes, the environment will be authorized to run various Google Cloud command line tools without requiring the user to manually authenticate."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/users_environments-authorize",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
None,
|
||||
Some(r##"Name of the resource that should receive the credentials, for example `users/me/environments/default` or `users/someone@example.com/environments/default`."##),
|
||||
Some(true),
|
||||
Some(false)),
|
||||
|
||||
(Some(r##"kv"##),
|
||||
Some(r##"r"##),
|
||||
Some(r##"Set various fields of the request structure, matching the key=value form"##),
|
||||
Some(true),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
("environments-get",
|
||||
Some(r##"Gets an environment. Returns NOT_FOUND if the environment does not exist."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/users_environments-get",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
None,
|
||||
Some(r##"Required. Name of the requested resource, for example `users/me/environments/default` or `users/someone@example.com/environments/default`."##),
|
||||
Some(true),
|
||||
Some(false)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
("environments-remove-public-key",
|
||||
Some(r##"Removes a public SSH key from an environment. Clients will no longer be able to connect to the environment using the corresponding private key. If a key with the same content is not present, this will error with NOT_FOUND."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/users_environments-remove-public-key",
|
||||
vec![
|
||||
(Some(r##"environment"##),
|
||||
None,
|
||||
Some(r##"Environment this key should be removed from, e.g. `users/me/environments/default`."##),
|
||||
Some(true),
|
||||
Some(false)),
|
||||
|
||||
(Some(r##"kv"##),
|
||||
Some(r##"r"##),
|
||||
Some(r##"Set various fields of the request structure, matching the key=value form"##),
|
||||
Some(true),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
("environments-start",
|
||||
Some(r##"Starts an existing environment, allowing clients to connect to it. The returned operation will contain an instance of StartEnvironmentMetadata in its metadata field. Users can wait for the environment to start by polling this operation via GetOperation. Once the environment has finished starting and is ready to accept connections, the operation will contain a StartEnvironmentResponse in its response field."##),
|
||||
"Details at http://byron.github.io/google-apis-rs/google_cloudshell1_cli/users_environments-start",
|
||||
vec![
|
||||
(Some(r##"name"##),
|
||||
None,
|
||||
Some(r##"Name of the resource that should be started, for example `users/me/environments/default` or `users/someone@example.com/environments/default`."##),
|
||||
Some(true),
|
||||
Some(false)),
|
||||
|
||||
(Some(r##"kv"##),
|
||||
Some(r##"r"##),
|
||||
Some(r##"Set various fields of the request structure, matching the key=value form"##),
|
||||
Some(true),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"v"##),
|
||||
Some(r##"p"##),
|
||||
Some(r##"Set various optional parameters, matching the key=value form"##),
|
||||
Some(false),
|
||||
Some(true)),
|
||||
|
||||
(Some(r##"out"##),
|
||||
Some(r##"o"##),
|
||||
Some(r##"Specify the file into which to write the program's output"##),
|
||||
Some(false),
|
||||
Some(false)),
|
||||
]),
|
||||
]),
|
||||
|
||||
];
|
||||
|
||||
let mut app = App::new("cloudshell1")
|
||||
.author("Sebastian Thiel <byronimo@gmail.com>")
|
||||
.version("1.0.14+20200704")
|
||||
.about("Allows users to start, configure, and connect to interactive shell sessions running in the cloud.
|
||||
")
|
||||
.version("2.0.0+20210326")
|
||||
.about("Allows users to start, configure, and connect to interactive shell sessions running in the cloud. ")
|
||||
.after_help("All documentation details can be found at http://byron.github.io/google-apis-rs/google_cloudshell1_cli")
|
||||
.arg(Arg::with_name("url")
|
||||
.long("scope")
|
||||
@@ -546,12 +1059,7 @@ fn main() {
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("debug")
|
||||
.long("debug")
|
||||
.help("Output all server communication to standard error. `tx` and `rx` are placed into the same stream.")
|
||||
.multiple(false)
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("debug-auth")
|
||||
.long("debug-auth")
|
||||
.help("Output all communication related to authentication to standard error. `tx` and `rx` are placed into the same stream.")
|
||||
.help("Debug print all errors")
|
||||
.multiple(false)
|
||||
.takes_value(false));
|
||||
|
||||
@@ -599,13 +1107,13 @@ fn main() {
|
||||
let matches = app.get_matches();
|
||||
|
||||
let debug = matches.is_present("debug");
|
||||
match Engine::new(matches) {
|
||||
match Engine::new(matches).await {
|
||||
Err(err) => {
|
||||
exit_status = err.exit_code;
|
||||
writeln!(io::stderr(), "{}", err).ok();
|
||||
},
|
||||
Ok(engine) => {
|
||||
if let Err(doit_err) = engine.doit() {
|
||||
if let Err(doit_err) = engine.doit().await {
|
||||
exit_status = 1;
|
||||
match doit_err {
|
||||
DoitError::IoError(path, err) => {
|
||||
@@ -624,4 +1132,4 @@ fn main() {
|
||||
}
|
||||
|
||||
std::process::exit(exit_status);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user