From 9142859612e00fd81a3644f587f6abb9a8d837a9 Mon Sep 17 00:00:00 2001 From: philippeitis <33013301+philippeitis@users.noreply.github.com> Date: Tue, 27 Sep 2022 21:48:31 -0700 Subject: [PATCH] Move client.rs to common dependency --- Cargo.toml | 35 -- google-apis-common/Cargo.toml | 3 +- google-apis-common/src/lib.rs | 84 +++ src/generator/templates/Cargo.toml.mako | 4 +- src/generator/templates/cli/main.rs.mako | 4 +- src/generator/templates/deps.mako | 7 +- src/rust/api/client.rs | 2 - src/rust/cli/client.rs | 746 ----------------------- src/rust/cli/mod.rs | 1 - src/rust/lib.rs | 153 ----- 10 files changed, 92 insertions(+), 947 deletions(-) delete mode 100644 Cargo.toml delete mode 100644 src/rust/api/client.rs delete mode 100644 src/rust/cli/client.rs delete mode 100644 src/rust/cli/mod.rs delete mode 100644 src/rust/lib.rs diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index e6102dc7aa..0000000000 --- a/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -# DO NOT PUBLISH -# This library is just to try out the code that should ultimately go into the code generator ! -[package] - -name = "client" -version = "0.0.1" -authors = ["Sebastian Thiel "] -description = "A library to facilitate interacting with your youtube account" -repository = "https://github.com/Byron/google-apis-rs" -license = "MIT/Apache-2.0" -keywords = ["youtube", "google", "protocol", "not-for-use"] -edition = "2018" -publish = false - -[lib] -# The common client code, used by all generated implementations -name = "client" -path = "src/rust/lib.rs" - -[dependencies] -google-apis-common = { version = "4.0", path = "google-apis-common" } -clap = "2" -http = "^0.2" -hyper = "0.14" -mime = "0.2" -rustc-serialize = "*" -yup-oauth2 = "^ 7.0" -serde = "1" -serde_json = "1" -serde_derive = "1" -strsim = "*" -tokio = "^ 1.0" -hyper-rustls = "^0.22" -itertools = "^ 0.10" -tower-service = "^0.3" diff --git a/google-apis-common/Cargo.toml b/google-apis-common/Cargo.toml index 8c444448ca..1502269297 100644 --- a/google-apis-common/Cargo.toml +++ b/google-apis-common/Cargo.toml @@ -26,4 +26,5 @@ http = "^0.2" tokio = "^1.0" tower-service = "^0.3.1" - +[dev-dependencies] +serde = { version = "^ 1.0", features = ["derive"] } diff --git a/google-apis-common/src/lib.rs b/google-apis-common/src/lib.rs index b593198145..788fd3c0a0 100644 --- a/google-apis-common/src/lib.rs +++ b/google-apis-common/src/lib.rs @@ -861,3 +861,87 @@ mod yup_oauth2_impl { } } } + +#[cfg(test)] +mod test_api { + use super::*; + use hyper; + use std::default::Default; + use std::io::Read; + use std::str::FromStr; + + use serde_json as json; + use serde::{Serialize, Deserialize}; + + const EXPECTED: &'static str = "\r\n--MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\ +Content-Length: 50\r\n\ +Content-Type: application/json\r\n\ +\r\n\ +foo\r\n\ +--MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\ +Content-Length: 25\r\n\ +Content-Type: application/plain\r\n\ +\r\n\ +bar\r\n\ +--MDuXWGyeE33QFXGchb2VFWc4Z7945d--"; + + const EXPECTED_LEN: usize = 223; + + #[test] + fn serde() { + #[derive(Default, Serialize, Deserialize)] + struct Foo { + opt: Option, + req: u32, + opt_vec: Option>, + vec: Vec, + } + + let f: Foo = Default::default(); + json::to_string(&f).unwrap(); // should work + + let j = "{\"opt\":null,\"req\":0,\"vec\":[]}"; + let f: Foo = json::from_str(j).unwrap(); + + // This fails, unless 'vec' is optional + // let j = "{\"opt\":null,\"req\":0}"; + // let f: Foo = json::from_str(j).unwrap(); + + #[derive(Default, Serialize, Deserialize)] + struct Bar { + #[serde(rename = "snooSnoo")] + snoo_snoo: String, + } + json::to_string(&::default()).unwrap(); + + let j = "{\"snooSnoo\":\"foo\"}"; + let b: Bar = json::from_str(&j).unwrap(); + assert_eq!(b.snoo_snoo, "foo"); + + // We can't have unknown fields with structs. + // #[derive(Default, Serialize, Deserialize)] + // struct BarOpt { + // #[serde(rename="snooSnoo")] + // snoo_snoo: Option + // } + // let j = "{\"snooSnoo\":\"foo\",\"foo\":\"bar\"}"; + // let b: BarOpt = json::from_str(&j).unwrap(); + } + + #[test] + fn byte_range_from_str() { + assert_eq!( + ::from_str("2-42"), + Ok(Chunk { first: 2, last: 42 }) + ) + } + + #[test] + fn dyn_delegate_is_send() { + fn with_send(x: impl Send) {} + + let mut dd = DefaultDelegate::default(); + let dlg: &mut dyn Delegate = &mut dd; + with_send(dlg); + } +} diff --git a/src/generator/templates/Cargo.toml.mako b/src/generator/templates/Cargo.toml.mako index 584e9755fe..f49e115c6c 100644 --- a/src/generator/templates/Cargo.toml.mako +++ b/src/generator/templates/Cargo.toml.mako @@ -34,7 +34,9 @@ mime = "^ 0.2.0" serde = { version = "^ 1.0", features = ["derive"] } serde_json = "^ 1.0" itertools = "^ 0.10" -% if 'is_executable' not in cargo: +% if cargo.get('is_executable', False): +google-clis-common = { path = "../../google-clis-common", version = "4.0" } +% else: google-apis-common = { path = "../../google-apis-common", version = "4.0" } % endif % for dep in cargo.get('dependencies', list()): diff --git a/src/generator/templates/cli/main.rs.mako b/src/generator/templates/cli/main.rs.mako index c7efb11d65..fcdc9d9108 100644 --- a/src/generator/templates/cli/main.rs.mako +++ b/src/generator/templates/cli/main.rs.mako @@ -14,8 +14,6 @@ #![allow(unused_variables, unused_imports, dead_code, unused_mut)] -extern crate tokio; - #[macro_use] extern crate clap; @@ -25,7 +23,7 @@ use clap::{App, SubCommand, Arg}; use ${to_extern_crate_name(library_to_crate_name(library_name(name, version), make.depends_on_suffix))}::{api, Error, oauth2}; -mod client; +use google_clis_common as client; ${engine.new(c)}\ diff --git a/src/generator/templates/deps.mako b/src/generator/templates/deps.mako index 7185757a94..d875a6724d 100644 --- a/src/generator/templates/deps.mako +++ b/src/generator/templates/deps.mako @@ -105,12 +105,9 @@ print('Could not open JSON file at {}'.format(api_json)) print(e) %>\ -${api_common}: $(RUST_SRC)/${make.id}/client.rs $(lastword $(MAKEFILE_LIST)) ${gen_root_stamp} - @ echo "// COPY OF '$<'" > $@ - @ echo "// DO NOT EDIT" >> $@ - @cat $< >> $@ +${api_common}: ${gen_root_stamp} -${gen_root_stamp}: $(MAKO_RENDER) ${' '.join(i[0] for i in sds)} ${api_json_inputs} $(MAKO_STANDARD_DEPENDENCIES) ${depends_on_target} +${gen_root_stamp}: $(MAKO_RENDER) ${' '.join(i[0] for i in sds)} ${api_json_inputs} $(MAKO_STANDARD_DEPENDENCIES) @echo Generating ${api_target} $(MAKO) -io ${' '.join("%s=%s" % (s, d) for s, d in sds)} ${post_processor_arg} --data-files ${api_json_inputs} @touch $@ diff --git a/src/rust/api/client.rs b/src/rust/api/client.rs deleted file mode 100644 index c7ad4dd216..0000000000 --- a/src/rust/api/client.rs +++ /dev/null @@ -1,2 +0,0 @@ -//! This file serves on purpose and is an artifact of the buildsystem. -//! Its content can now be found in the `google-apis-common` crate. \ No newline at end of file diff --git a/src/rust/cli/client.rs b/src/rust/cli/client.rs deleted file mode 100644 index 1bfb75ccea..0000000000 --- a/src/rust/cli/client.rs +++ /dev/null @@ -1,746 +0,0 @@ -use clap::{App, SubCommand}; -use mime::Mime; -use crate::oauth2::{ApplicationSecret, ConsoleApplicationSecret}; -use serde_json as json; -use serde_json::value::Value; - -use std::env; -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::default::Default; - -const FIELD_SEP: char = '.'; - -pub enum ComplexType { - Pod, - Vec, - Map, -} - -// Null, -// Bool(bool), -// I64(i64), -// U64(u64), -// F64(f64), -// String(String), - -pub enum JsonType { - Boolean, - Int, - Uint, - Float, - String, -} - -pub struct JsonTypeInfo { - pub jtype: JsonType, - pub ctype: ComplexType, -} - -// Based on @erickt user comment. Thanks for the idea ! -// Remove all keys whose values are null from given value (changed in place) -pub fn remove_json_null_values(value: &mut Value) { - match *value { - Value::Object(ref mut map) => { - let mut for_removal = Vec::new(); - - for (key, mut value) in map.iter_mut() { - if value.is_null() { - for_removal.push(key.clone()); - } else { - remove_json_null_values(&mut value); - } - } - - for key in &for_removal { - map.remove(key); - } - } - json::value::Value::Array(ref mut arr) => { - let mut i = 0; - while i < arr.len() { - if arr[i].is_null() { - arr.remove(i); - } else { - remove_json_null_values(&mut arr[i]); - i += 1; - } - } - } - _ => {} - } -} - -fn did_you_mean<'a>(v: &str, possible_values: &[&'a str]) -> Option<&'a str> { - let mut candidate: Option<(f64, &str)> = None; - for pv in possible_values { - let confidence = strsim::jaro_winkler(v, pv); - if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) - { - candidate = Some((confidence, pv)); - } - } - match candidate { - None => None, - Some((_, candidate)) => Some(candidate), - } -} - -pub enum CallType { - Upload(UploadProtocol), - Standard, -} - -arg_enum! { - pub enum UploadProtocol { - Simple, - // Resumable // This seems to be lost during the async conversion - } -} - -impl AsRef for UploadProtocol { - fn as_ref(&self) -> &str { - match *self { - UploadProtocol::Simple => "simple", - // UploadProtocol::Resumable => "resumable", - } - } -} - -impl AsRef for CallType { - fn as_ref(&self) -> &str { - match *self { - CallType::Upload(ref proto) => proto.as_ref(), - CallType::Standard => "standard-request", - } - } -} - -#[derive(Clone, Default)] -pub struct FieldCursor(Vec); - -impl ToString for FieldCursor { - fn to_string(&self) -> String { - self.0.join(".") - } -} - -impl From<&'static str> for FieldCursor { - fn from(value: &'static str) -> FieldCursor { - let mut res = FieldCursor::default(); - res.set(value).unwrap(); - res - } -} - -fn assure_entry<'a>(m: &'a mut json::Map, k: &str) -> &'a mut Value { - if m.contains_key(k) { - return m.get_mut(k).expect("value to exist"); - } - m.insert(k.to_owned(), Value::Object(Default::default())); - m.get_mut(k).expect("value to exist") -} - -impl FieldCursor { - pub fn set(&mut self, value: &str) -> Result<(), CLIError> { - if value.is_empty() { - 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, f: &mut String| { - if !f.is_empty() { - 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 && 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 did_you_mean(value: &str, possible_values: &[&str]) -> Option { - if value.is_empty() { - return None; - } - - let mut last_c = FIELD_SEP; - - let mut field = String::new(); - let mut output = String::new(); - - let push_field = |fs: &mut String, f: &mut String| { - if !f.is_empty() { - fs.push_str(match did_you_mean(&f, possible_values) { - Some(candidate) => candidate, - None => &f, - }); - f.truncate(0); - } - }; - - for (cid, c) in value.chars().enumerate() { - if c == FIELD_SEP { - if last_c != FIELD_SEP { - push_field(&mut output, &mut field); - } - output.push(c); - } else { - field.push(c); - } - - last_c = c; - } - - push_field(&mut output, &mut field); - - if output == value { - None - } else { - Some(output) - } - } - - pub fn set_json_value( - &self, - mut object: &mut Value, - value: &str, - type_info: JsonTypeInfo, - err: &mut InvalidOptionsError, - orig_cursor: &FieldCursor, - ) { - assert!(!self.0.is_empty()); - - for field in &self.0[..self.0.len() - 1] { - let tmp = object; - object = match *tmp { - Value::Object(ref mut mapping) => assure_entry(mapping, &field), - _ => panic!("We don't expect non-object Values here ..."), - }; - } - - 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()), - } - }; - - 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(), - ))); - } - } - 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(), - ))); - } - } - _ => unreachable!(), - } - } - } - } - _ => unreachable!(), - } - } - - pub fn num_fields(&self) -> usize { - self.0.len() - } -} - -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)) - }; - match kv.find('=') { - None => { - add_err(); - (kv, None) - } - Some(pos) => { - let key = &kv[..pos]; - if kv.len() <= pos + 1 { - add_err(); - return (key, Some("")); - } - (key, Some(&kv[pos + 1..])) - } - } -} - -pub fn calltype_from_str( - name: &str, - valid_protocols: Vec, - err: &mut InvalidOptionsError, -) -> CallType { - CallType::Upload(match UploadProtocol::from_str(name) { - Ok(up) => up, - Err(msg) => { - err.issues.push(CLIError::InvalidUploadProtocol( - name.to_string(), - valid_protocols, - )); - UploadProtocol::Simple - } - }) -} - -pub fn input_file_from_opts(file_path: &str, err: &mut InvalidOptionsError) -> Option { - 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, - )))); - None - } - } -} - -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()))); - None - } - } -} - -pub fn writer_from_opts(arg: Option<&str>) -> Result, 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) - { - 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, - ::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), - )); - Default::default() - } - Ok(v) => v, - } -} - -#[derive(Debug)] -pub enum ApplicationSecretError { - DecoderError((String, json::Error)), - 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), - Io((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::Io((ref path, ref err)) => writeln!( - f, - "IO operation failed on path '{}' with error: {}.", - path, err - ), - } - } -} - -#[derive(Debug)] -pub enum InputError { - Io((String, io::Error)), - Mime(String), -} - -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::Mime(ref mime) => writeln!(f, "'{}' is not a known mime-type.", mime), - } - } -} - -#[derive(Debug)] -pub enum FieldError { - PopOnEmpty(String), - TrailingFieldSep(String), - Unknown(String, Option, Option), - Duplicate(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, ref suggestion, ref value) => { - let suffix = match *suggestion { - Some(ref s) => { - let kv = match *value { - Some(ref v) => format!("{}={}", s, v), - None => s.clone(), - }; - format!(" Did you mean '{}' ?", kv) - } - None => String::new(), - }; - writeln!(f, "Field '{}' does not exist.{}", field, suffix) - } - FieldError::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), - ParseError(String, String, String, String), - UnknownParameter(String, Vec<&'static str>), - InvalidUploadProtocol(String, Vec), - InvalidKeyValueSyntax(String, bool), - Input(InputError), - Field(FieldError), - MissingCommandError, - MissingMethodError(String), -} - -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::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), - None => String::new(), - }; - writeln!(f, "Parameter '{}' is unknown.{}", param_name, suffix) - } - CLIError::InvalidKeyValueSyntax(ref kv, is_hashmap) => { - let hashmap_info = if is_hashmap { "hashmap " } else { "" }; - writeln!( - f, - "'{}' does not match {}pattern =.", - 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 - ), - } - } -} - -#[derive(Debug)] -pub struct InvalidOptionsError { - pub issues: Vec, - pub exit_code: i32, -} - -impl fmt::Display for InvalidOptionsError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - for issue in &self.issues { - issue.fmt(f)?; - } - Ok(()) - } -} - -impl InvalidOptionsError { - pub fn single(err: CLIError, exit_code: i32) -> InvalidOptionsError { - InvalidOptionsError { - issues: vec![err], - exit_code, - } - } - - pub fn new() -> InvalidOptionsError { - InvalidOptionsError { - issues: Vec::new(), - exit_code: 1, - } - } -} - -pub fn assure_config_dir_exists(dir: &str) -> Result { - let trdir = dir.trim(); - if trdir.is_empty() { - return Err(CLIError::Configuration(ConfigurationError::DirectoryUnset)); - } - - let expanded_config_dir = if trdir.as_bytes()[0] == b'~' { - match env::var("HOME") - .ok() - .or_else(|| 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, - json_console_secret: &str, -) -> Result { - 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, - )))) - }; - - 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 - - err = match fs::OpenOptions::new() - .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) - } - Ok(_) => continue, - } - } - }; - // fall through to IO error handling - } - 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()), - ))) - } - }, - }, - } - } - unreachable!(); -} diff --git a/src/rust/cli/mod.rs b/src/rust/cli/mod.rs deleted file mode 100644 index b9babe5bc1..0000000000 --- a/src/rust/cli/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod client; diff --git a/src/rust/lib.rs b/src/rust/lib.rs deleted file mode 100644 index 185b0c27b7..0000000000 --- a/src/rust/lib.rs +++ /dev/null @@ -1,153 +0,0 @@ -#![allow( - dead_code, - deprecated, - unused_features, - unused_variables, - unused_imports -)] - -#[macro_use] -extern crate clap; - -#[macro_use] -extern crate hyper; -extern crate mime; -extern crate rustc_serialize; -extern crate serde; -extern crate serde_json; -extern crate yup_oauth2 as oauth2; -#[macro_use] -extern crate serde_derive; -extern crate strsim; - -// just pull it in the check if it compiles -mod cli; -use google_apis_common as api; - -/// This module is for testing only, its code is used in mako templates -#[cfg(test)] -mod test_api { - use super::api::*; - use hyper; - use std::default::Default; - use std::io::Read; - use std::str::FromStr; - - use serde_json as json; - - const EXPECTED: &'static str = "\r\n--MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\ -Content-Length: 50\r\n\ -Content-Type: application/json\r\n\ -\r\n\ -foo\r\n\ ---MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\ -Content-Length: 25\r\n\ -Content-Type: application/plain\r\n\ -\r\n\ -bar\r\n\ ---MDuXWGyeE33QFXGchb2VFWc4Z7945d--"; - - const EXPECTED_LEN: usize = 223; - - #[test] - fn serde() { - #[derive(Default, Serialize, Deserialize)] - struct Foo { - opt: Option, - req: u32, - opt_vec: Option>, - vec: Vec, - } - - let f: Foo = Default::default(); - json::to_string(&f).unwrap(); // should work - - let j = "{\"opt\":null,\"req\":0,\"vec\":[]}"; - let f: Foo = json::from_str(j).unwrap(); - - // This fails, unless 'vec' is optional - // let j = "{\"opt\":null,\"req\":0}"; - // let f: Foo = json::from_str(j).unwrap(); - - #[derive(Default, Serialize, Deserialize)] - struct Bar { - #[serde(rename = "snooSnoo")] - snoo_snoo: String, - } - json::to_string(&::default()).unwrap(); - - let j = "{\"snooSnoo\":\"foo\"}"; - let b: Bar = json::from_str(&j).unwrap(); - assert_eq!(b.snoo_snoo, "foo"); - - // We can't have unknown fields with structs. - // #[derive(Default, Serialize, Deserialize)] - // struct BarOpt { - // #[serde(rename="snooSnoo")] - // snoo_snoo: Option - // } - // let j = "{\"snooSnoo\":\"foo\",\"foo\":\"bar\"}"; - // let b: BarOpt = json::from_str(&j).unwrap(); - } - - #[test] - fn byte_range_from_str() { - assert_eq!( - ::from_str("2-42"), - Ok(Chunk { first: 2, last: 42 }) - ) - } - - #[test] - fn dyn_delegate_is_send() { - fn with_send(x: impl Send) {} - - let mut dd = DefaultDelegate::default(); - let dlg: &mut dyn Delegate = &mut dd; - with_send(dlg); - } -} - -#[cfg(test)] -mod test_cli { - use super::cli::client::*; - - use std::default::Default; - - #[test] - fn cursor() { - let mut c: FieldCursor = Default::default(); - - assert_eq!(c.to_string(), ""); - assert_eq!(c.num_fields(), 0); - assert!(c.set("").is_err()); - assert!(c.set(".").is_ok()); - assert!(c.set("..").is_err()); - assert_eq!(c.num_fields(), 0); - - assert!(c.set("foo").is_ok()); - assert_eq!(c.to_string(), "foo"); - assert_eq!(c.num_fields(), 1); - assert!(c.set("..").is_ok()); - assert_eq!(c.num_fields(), 0); - assert_eq!(c.to_string(), ""); - - assert!(c.set("foo.").is_err()); - - assert!(c.set("foo.bar").is_ok()); - assert_eq!(c.num_fields(), 2); - assert_eq!(c.to_string(), "foo.bar"); - assert!(c.set("sub.level").is_ok()); - assert_eq!(c.num_fields(), 4); - assert_eq!(c.to_string(), "foo.bar.sub.level"); - assert!(c.set("...other").is_ok()); - assert_eq!(c.to_string(), "foo.bar.other"); - assert_eq!(c.num_fields(), 3); - assert!(c.set(".one.two.three...beer").is_ok()); - assert_eq!(c.num_fields(), 2); - assert_eq!(c.to_string(), "one.beer"); - assert!(c.set("one.two.three...").is_ok()); - assert_eq!(c.num_fields(), 3); - assert_eq!(c.to_string(), "one.beer.one"); - } -}