diff --git a/.travis.yml b/.travis.yml index 293ce2e328..c209fc5973 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: rust +rust: +- stable script: - make docs-all gen-all-cli cargo-api ARGS=test env: diff --git a/README.md b/README.md index 5fe1caa249..efda4a32d0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ To find a library of your interest, you might want to proceed looking at the [AP * first-class documentation with cross-links and complete code-examples * support all features, including downloads and resumable uploads * safety and resilience are built-in, allowing you to create highly available tools on top of it. For example, you can trigger retries for all operations that may temporarily fail, e.g. due to network outage. -* *(soon)* Feature-complete command line tool to interact with each API. # Live-Development @@ -46,6 +45,9 @@ To generate the APIs yourself, you will need to meet the following prerequisites * As [*mako*][mako] is a python program, you will need python installed on your system to run it. Some other programs we call depend on python being present as well. * **an internet connection and wget** * Make will download all other prerequisites automatically into hidden directories within this repository, which requires it to make some downloads via wget. +* **Rust Stable** + * This project compiles on *stable* Rust only. You might consider using [Multirust][multirust] to control + the toolchain on a per-project basis ## Using Make @@ -229,4 +231,5 @@ The license of everything not explicitly under a different license are licensed [issues]: https://github.com/Byron/google-apis-rs/issues [playlist]: https://www.youtube.com/playlist?list=PLMHbQxe1e9Mnnqj3Hs1hRDUXFEK-TgCnz [playlist-thumb]: http://img.youtube.com/vi/aGXuGEl90Mo/0.jpg -[milestones]: https://github.com/Byron/google-apis-rs/milestones \ No newline at end of file +[milestones]: https://github.com/Byron/google-apis-rs/milestones +[multirust]: https://github.com/brson/multirust \ No newline at end of file diff --git a/etc/api/type-api.yaml b/etc/api/type-api.yaml index 4e681ee659..6f1847fcb6 100644 --- a/etc/api/type-api.yaml +++ b/etc/api/type-api.yaml @@ -18,11 +18,15 @@ make: - source: README.md - source: ../LICENSE.md - source: ../Cargo.toml + - source: lib.rs.in + output_dir: src - source: lib.rs output_dir: src + - source: build.rs + output_dir: src cargo: - build_version: "0.1.7" + build_version: "0.1.8" + build_script: src/build.rs keywords: [protocol, web, api] dependencies: - url = "*" - - json-tools = ">= 0.3.0" diff --git a/etc/api/type-cli.yaml b/etc/api/type-cli.yaml index 7232a6f01d..11c0f53e1a 100644 --- a/etc/api/type-cli.yaml +++ b/etc/api/type-cli.yaml @@ -22,7 +22,7 @@ make: - source: main.rs output_dir: src cargo: - build_version: "0.2.0" + build_version: "0.3.0" keywords: [cli] is_executable: YES dependencies: diff --git a/gen/discovery1-cli/Cargo.toml b/gen/discovery1-cli/Cargo.toml index 421b04bb8f..f64a0c3756 100644 --- a/gen/discovery1-cli/Cargo.toml +++ b/gen/discovery1-cli/Cargo.toml @@ -17,14 +17,20 @@ keywords = ["discovery", "google", "cli"] name = "discovery1" [dependencies] -hyper = ">= 0.4.0" +hyper = ">= 0.5.0" mime = "*" -yup-oauth2 = "*" -strsim = "*" -yup-hyper-mock = "*" serde = ">= 0.3.0" serde_macros = "*" -clap = "*" +strsim = "*" +yup-hyper-mock = ">=1.0.0" +clap = ">= 0.9.1" + +# to adapt to hyper changes ... +[dependencies.yup-oauth2] +version = "*" +git = "https://github.com/Byron/yup-oauth2" +rev = "598f5ed496077e9edca36ff95e2ab352c5b22d0f" + [dependencies.google-discovery1] path = "../discovery1" diff --git a/gen/discovery1-cli/src/cmn.rs b/gen/discovery1-cli/src/cmn.rs index 3335e7b6bd..56051cab08 100644 --- a/gen/discovery1-cli/src/cmn.rs +++ b/gen/discovery1-cli/src/cmn.rs @@ -2,6 +2,7 @@ // DO NOT EDIT use oauth2::{ApplicationSecret, ConsoleApplicationSecret, TokenStorage, Token}; use serde::json; +use serde::json::value::Value; use mime::Mime; use clap::{App, SubCommand}; use strsim; @@ -19,11 +20,38 @@ 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 json::value::Value) { +pub fn remove_json_null_values(value: &mut Value) { match *value { - json::value::Value::Object(ref mut map) => { + Value::Object(ref mut map) => { let mut for_removal = Vec::new(); for (key, mut value) in map.iter_mut() { @@ -96,6 +124,14 @@ impl ToString for FieldCursor { } } +impl From<&'static str> for FieldCursor { + fn from(value: &'static str) -> FieldCursor { + let mut res = FieldCursor::default(); + res.set(value).unwrap(); + res + } +} + impl FieldCursor { pub fn set(&mut self, value: &str) -> Result<(), CLIError> { if value.len() == 0 { @@ -201,6 +237,78 @@ impl 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) => { + mapping.entry(field.to_owned()).or_insert( + Value::Object(Default::default()) + ) + }, + _ => 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::I64(arg_from_str(value, err, &field, "int")), + JsonType::Uint => + Value::U64(arg_from_str(value, err, &field, "uint")), + JsonType::Float => + Value::F64(arg_from_str(value, err, &field, "float")), + 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 *mapping.entry(field.to_owned()) + .or_insert(Value::Array(Default::default())) { + 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 *mapping.entry(field.to_owned()) + .or_insert(Value::Object(Default::default())) { + 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() } @@ -268,15 +376,15 @@ pub fn writer_from_opts(arg: Option<&str>) -> Result, io::Error> { } -pub fn arg_from_str(arg: &str, err: &mut InvalidOptionsError, - arg_name: &'static str, - arg_type: &'static str) -> T +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, arg_type, arg.to_string(), format!("{}", perr)) + CLIError::ParseError(arg_name.to_owned(), arg_type.to_owned(), arg.to_string(), format!("{}", perr)) ); Default::default() }, @@ -411,6 +519,7 @@ pub enum FieldError { PopOnEmpty(String), TrailingFieldSep(String), Unknown(String, Option, Option), + Duplicate(String), Empty, } @@ -437,6 +546,8 @@ 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::Empty => writeln!(f, "Field names must not be empty."), } @@ -447,7 +558,7 @@ impl fmt::Display for FieldError { #[derive(Debug)] pub enum CLIError { Configuration(ConfigurationError), - ParseError(&'static str, &'static str, String, String), + ParseError(String, String, String, String), UnknownParameter(String, Vec<&'static str>), InvalidUploadProtocol(String, Vec), InvalidKeyValueSyntax(String, bool), @@ -465,7 +576,7 @@ impl fmt::Display for CLIError { 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.connect(", ")), - CLIError::ParseError(arg_name, type_name, ref value, ref err_desc) + 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) => { diff --git a/gen/discovery1-cli/src/main.rs b/gen/discovery1-cli/src/main.rs index ce64a21fe3..a4ce87df76 100644 --- a/gen/discovery1-cli/src/main.rs +++ b/gen/discovery1-cli/src/main.rs @@ -22,7 +22,7 @@ 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, CallType, UploadProtocol, - calltype_from_str, remove_json_null_values}; + calltype_from_str, remove_json_null_values, ComplexType, JsonType, JsonTypeInfo}; use std::default::Default; use std::str::FromStr; @@ -61,9 +61,11 @@ impl<'n, 'a> Engine<'n, 'a> { } } if !found { - err.issues.push(CLIError::UnknownParameter(key.to_string(), - Vec::new() + &self.gp + &[] - )); + err.issues.push(CLIError::UnknownParameter(key.to_string(), + {let mut v = Vec::new(); + v.extend(self.gp.iter().map(|v|*v)); + v.extend([].iter().map(|v|*v)); + v } )); } } } @@ -114,9 +116,11 @@ impl<'n, 'a> Engine<'n, 'a> { } } if !found { - err.issues.push(CLIError::UnknownParameter(key.to_string(), - Vec::new() + &self.gp + &["name", "preferred"] - )); + err.issues.push(CLIError::UnknownParameter(key.to_string(), + {let mut v = Vec::new(); + v.extend(self.gp.iter().map(|v|*v)); + v.extend(["name", "preferred"].iter().map(|v|*v)); + v } )); } } } @@ -332,7 +336,8 @@ fn main() { (_ , &Some(f)) => f, _ => unreachable!(), }; - let mut arg = Arg::with_name(arg_name_str); + let mut arg = Arg::with_name(arg_name_str) + .empty_values(false); if let &Some(short_flag) = flag { arg = arg.short(short_flag); } diff --git a/gen/discovery1/Cargo.toml b/gen/discovery1/Cargo.toml index 250ccd2b04..dad66fb739 100644 --- a/gen/discovery1/Cargo.toml +++ b/gen/discovery1/Cargo.toml @@ -12,13 +12,17 @@ homepage = "https://developers.google.com/discovery/" documentation = "http://byron.github.io/google-apis-rs/google_discovery1" license = "MIT" keywords = ["discovery", "google", "protocol", "web", "api"] +build = "src/build.rs" [dependencies] -hyper = ">= 0.4.0" +hyper = ">= 0.5.0" mime = "*" +serde = ">= 0.3.0" yup-oauth2 = "*" url = "*" -serde = ">= 0.3.0" -serde_macros = "*" -json-tools = ">= 0.3.0" + +[build-dependencies] +syntex = { version = "*" } +serde_codegen = { version = "*" } + diff --git a/gen/discovery1/src/cmn.rs b/gen/discovery1/src/cmn.rs index 908bef39dc..9146b800cb 100644 --- a/gen/discovery1/src/cmn.rs +++ b/gen/discovery1/src/cmn.rs @@ -290,7 +290,7 @@ impl Display for Error { writeln!(f, "The media size {} exceeds the maximum allowed upload size of {}" , resource_size, max_size), Error::MissingAPIKey => { - writeln!(f, "The application's API key was not found in the configuration").ok(); + (writeln!(f, "The application's API key was not found in the configuration")).ok(); writeln!(f, "It is used as there are no Scopes defined for this method.") }, Error::BadRequest(ref err) => { @@ -424,8 +424,8 @@ impl<'a> Read for MultiPartReader<'a> { (n, true, _) if n > 0 => { let (headers, reader) = self.raw_parts.remove(0); let mut c = Cursor::new(Vec::::new()); - write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING, - headers, LINE_ENDING).unwrap(); + (write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING, + headers, LINE_ENDING)).unwrap(); c.seek(SeekFrom::Start(0)).unwrap(); self.current_part = Some((c, reader)); } @@ -471,7 +471,7 @@ impl<'a> Read for MultiPartReader<'a> { } } -header!{ +header!( #[doc="The `X-Upload-Content-Type` header."] (XUploadContentType, "X-Upload-Content-Type") => [Mime] @@ -484,7 +484,7 @@ header!{ ))); } -} +); #[derive(Clone, PartialEq, Debug)] pub struct Chunk { @@ -494,7 +494,7 @@ pub struct Chunk { impl fmt::Display for Chunk { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}-{}", self.first, self.last).ok(); + (write!(fmt, "{}-{}", self.first, self.last)).ok(); Ok(()) } } @@ -549,7 +549,7 @@ impl HeaderFormat for ContentRange { Some(ref c) => try!(c.fmt(fmt)), None => try!(fmt.write_str("*")) } - write!(fmt, "/{}", self.total_length).ok(); + (write!(fmt, "/{}", self.total_length)).ok(); Ok(()) } } @@ -668,12 +668,14 @@ impl<'a, A> ResumableUploadHelper<'a, A> if self.delegate.cancel_chunk_upload(&range_header) { return None } - match self.client.post(self.url) - .header(range_header) - .header(ContentType(self.media_type.clone())) - .header(UserAgent(self.user_agent.to_string())) - .body(&mut section_reader) - .send() { + // workaround https://github.com/rust-lang/rust/issues/22252 + let res = self.client.post(self.url) + .header(range_header) + .header(ContentType(self.media_type.clone())) + .header(UserAgent(self.user_agent.to_string())) + .body(&mut section_reader) + .send(); + match res { Ok(mut res) => { if res.status == StatusCode::PermanentRedirect { continue @@ -700,4 +702,28 @@ impl<'a, A> ResumableUploadHelper<'a, A> } } } -} \ No newline at end of file +} + +use serde::json::value::Value; +// Copy of src/rust/cli/cmn.rs +// TODO(ST): Allow sharing common code between program types +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); + } + } + _ => {} + } +} diff --git a/gen/discovery1/src/lib.rs b/gen/discovery1/src/lib.rs index 72f0cb0da2..16c41fdd4a 100644 --- a/gen/discovery1/src/lib.rs +++ b/gen/discovery1/src/lib.rs @@ -167,1114 +167,11 @@ //! [google-go-api]: https://github.com/google/google-api-go-client //! //! + // Unused attributes happen thanks to defined, but unused structures // We don't warn about this, as depending on the API, some data structures or facilities are never used. // Instead of pre-determining this, we just disable the lint. It's manually tuned to not have any // unused imports in fully featured APIs. Same with unused_mut ... . #![allow(unused_imports, unused_mut, dead_code)] -// Required for serde annotations -#![feature(custom_derive, custom_attribute, plugin, slice_patterns)] -#![plugin(serde_macros)] - -#[macro_use] -extern crate hyper; -extern crate serde; -extern crate yup_oauth2 as oauth2; -extern crate mime; -extern crate url; -extern crate json_tools; - -mod cmn; - -use std::collections::HashMap; -use std::cell::RefCell; -use std::borrow::BorrowMut; -use std::default::Default; -use std::collections::BTreeMap; -use serde::json; -use std::io; -use std::fs; -use std::thread::sleep_ms; - -pub use cmn::{MultiPartReader, ToParts, MethodInfo, Result, Error, CallBuilder, Hub, ReadSeek, Part, ResponseResult, RequestValue, NestedType, Delegate, DefaultDelegate, MethodsBuilder, Resource, ErrorResponse}; - - -// ############## -// UTILITIES ### -// ############ - - - - -// ######## -// HUB ### -// ###### - -/// Central instance to access all Discovery related resource activities -/// -/// # Examples -/// -/// Instantiate a new hub -/// -/// ```test_harness,no_run -/// extern crate hyper; -/// extern crate yup_oauth2 as oauth2; -/// extern crate google_discovery1 as discovery1; -/// use discovery1::{Result, Error}; -/// # #[test] fn egal() { -/// use std::default::Default; -/// use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage}; -/// use discovery1::Discovery; -/// -/// // Get an ApplicationSecret instance by some means. It contains the `client_id` and -/// // `client_secret`, among other things. -/// let secret: ApplicationSecret = Default::default(); -/// // Instantiate the authenticator. It will choose a suitable authentication flow for you, -/// // unless you replace `None` with the desired Flow. -/// // Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about -/// // what's going on. You probably want to bring in your own `TokenStorage` to persist tokens and -/// // retrieve them from storage. -/// let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate, -/// hyper::Client::new(), -/// ::default(), None); -/// let mut hub = Discovery::new(hyper::Client::new(), auth); -/// // You can configure optional parameters by calling the respective setters at will, and -/// // execute the final call using `doit()`. -/// // Values shown here are possibly random and not representative ! -/// let result = hub.apis().get_rest("api", "version") -/// .doit(); -/// -/// match result { -/// Err(e) => match e { -/// // The Error enum provides details about what exactly happened. -/// // You can also just use its `Debug`, `Display` or `Error` traits -/// Error::HttpError(_) -/// |Error::MissingAPIKey -/// |Error::MissingToken(_) -/// |Error::Cancelled -/// |Error::UploadSizeLimitExceeded(_, _) -/// |Error::Failure(_) -/// |Error::BadRequest(_) -/// |Error::FieldClash(_) -/// |Error::JsonDecodeError(_, _) => println!("{}", e), -/// }, -/// Ok(res) => println!("Success: {:?}", res), -/// } -/// # } -/// ``` -pub struct Discovery { - client: RefCell, - auth: RefCell, - _user_agent: String, -} - -impl<'a, C, A> Hub for Discovery {} - -impl<'a, C, A> Discovery - where C: BorrowMut, A: oauth2::GetToken { - - pub fn new(client: C, authenticator: A) -> Discovery { - Discovery { - client: RefCell::new(client), - auth: RefCell::new(authenticator), - _user_agent: "google-api-rust-client/0.1.7".to_string(), - } - } - - pub fn apis(&'a self) -> ApiMethods<'a, C, A> { - ApiMethods { hub: &self } - } - - /// Set the user-agent header field to use in all requests to the server. - /// It defaults to `google-api-rust-client/0.1.7`. - /// - /// Returns the previously set user-agent. - pub fn user_agent(&mut self, agent_name: String) -> String { - let prev = self._user_agent.clone(); - self._user_agent = agent_name; - prev - } -} - - -// ############ -// SCHEMAS ### -// ########## -/// OAuth 2.0 authentication information. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestDescriptionAuthOauth2 { - /// Available OAuth 2.0 scopes. - pub scopes: Option>, -} - -impl NestedType for RestDescriptionAuthOauth2 {} -impl Part for RestDescriptionAuthOauth2 {} - - -/// The schema for the response. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethodResponse { - /// Schema ID for the response schema. - #[serde(rename="$ref")] - pub ref_: Option, -} - -impl NestedType for RestMethodResponse {} -impl Part for RestMethodResponse {} - - -/// In a variant data type, the value of one property is used to determine how to interpret the entire entity. Its value must exist in a map of descriminant values to schema names. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct JsonSchemaVariant { - /// The map of discriminant value to schema to use for parsing.. - pub map: Option>, - /// The name of the type discriminant property. - pub discriminant: Option, -} - -impl NestedType for JsonSchemaVariant {} -impl Part for JsonSchemaVariant {} - - -/// Supported upload protocols. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethodMediaUploadProtocols { - /// Supports uploading as a single HTTP request. - pub simple: Option, - /// Supports the Resumable Media Upload protocol. - pub resumable: Option, -} - -impl NestedType for RestMethodMediaUploadProtocols {} -impl Part for RestMethodMediaUploadProtocols {} - - -/// Supports the Resumable Media Upload protocol. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethodMediaUploadProtocolsResumable { - /// The URI path to be used for upload. Should be used in conjunction with the basePath property at the api-level. - pub path: Option, - /// True if this endpoint supports uploading multipart media. - pub multipart: Option, -} - -impl NestedType for RestMethodMediaUploadProtocolsResumable {} -impl Part for RestMethodMediaUploadProtocolsResumable {} - - -/// Additional information about this property. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct JsonSchemaAnnotations { - /// A list of methods for which this property is required on requests. - pub required: Option>, -} - -impl NestedType for JsonSchemaAnnotations {} -impl Part for JsonSchemaAnnotations {} - - -/// The map of discriminant value to schema to use for parsing.. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct JsonSchemaVariantMap { - /// no description provided - pub type_value: Option, - /// no description provided - #[serde(rename="$ref")] - pub ref_: Option, -} - -impl NestedType for JsonSchemaVariantMap {} -impl Part for JsonSchemaVariantMap {} - - -/// Links to 16x16 and 32x32 icons representing the API. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestDescriptionIcons { - /// The URL of the 32x32 icon. - pub x32: Option, - /// The URL of the 16x16 icon. - pub x16: Option, -} - -impl NestedType for RestDescriptionIcons {} -impl Part for RestDescriptionIcons {} - - -/// There is no detailed description. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethod { - /// OAuth 2.0 scopes applicable to this method. - pub scopes: Option>, - /// Description of this method. - pub description: Option, - /// Details for all parameters in this method. - pub parameters: Option>, - /// Whether this method supports media uploads. - #[serde(rename="supportsMediaUpload")] - pub supports_media_upload: Option, - /// Whether this method requires an ETag to be specified. The ETag is sent as an HTTP If-Match or If-None-Match header. - #[serde(rename="etagRequired")] - pub etag_required: Option, - /// Media upload parameters. - #[serde(rename="mediaUpload")] - pub media_upload: Option, - /// The schema for the request. - pub request: Option, - /// Indicates that downloads from this method should use the download service URL (i.e. "/download"). Only applies if the method supports media download. - #[serde(rename="useMediaDownloadService")] - pub use_media_download_service: Option, - /// HTTP method used by this method. - #[serde(rename="httpMethod")] - pub http_method: Option, - /// Whether this method supports subscriptions. - #[serde(rename="supportsSubscription")] - pub supports_subscription: Option, - /// Ordered list of required parameters, serves as a hint to clients on how to structure their method signatures. The array is ordered such that the "most-significant" parameter appears first. - #[serde(rename="parameterOrder")] - pub parameter_order: Option>, - /// A unique ID for this method. This property can be used to match methods between different versions of Discovery. - pub id: Option, - /// The URI path of this REST method. Should be used in conjunction with the basePath property at the api-level. - pub path: Option, - /// The schema for the response. - pub response: Option, - /// Whether this method supports media downloads. - #[serde(rename="supportsMediaDownload")] - pub supports_media_download: Option, -} - -impl Part for RestMethod {} - - -/// There is no detailed description. -/// -/// # Activities -/// -/// This type is used in activities, which are methods you may call on this type or where this type is involved in. -/// The list links the activity name, along with information about where it is used (one of *request* and *response*). -/// -/// * [get rest apis](struct.ApiGetRestCall.html) (response) -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestDescription { - /// The protocol described by this document. - pub protocol: Option, - /// API-level methods for this API. - pub methods: Option>, - /// Labels for the status of this API, such as labs or deprecated. - pub labels: Option>, - /// The kind for this response. - pub kind: Option, - /// Indicates how the API name should be capitalized and split into various parts. Useful for generating pretty class names. - #[serde(rename="canonicalName")] - pub canonical_name: Option, - /// The name of the owner of this API. See ownerDomain. - #[serde(rename="ownerName")] - pub owner_name: Option, - /// A link to human readable documentation for the API. - #[serde(rename="documentationLink")] - pub documentation_link: Option, - /// Authentication information. - pub auth: Option, - /// The package of the owner of this API. See ownerDomain. - #[serde(rename="packagePath")] - pub package_path: Option, - /// The path for REST batch requests. - #[serde(rename="batchPath")] - pub batch_path: Option, - /// The ID of this API. - pub id: Option, - /// A list of supported features for this API. - pub features: Option>, - /// The domain of the owner of this API. Together with the ownerName and a packagePath values, this can be used to generate a library for this API which would have a unique fully qualified name. - #[serde(rename="ownerDomain")] - pub owner_domain: Option, - /// The root URL under which all API services live. - #[serde(rename="rootUrl")] - pub root_url: Option, - /// The name of this API. - pub name: Option, - /// Common parameters that apply across all apis. - pub parameters: Option>, - /// Links to 16x16 and 32x32 icons representing the API. - pub icons: Option, - /// The description of this API. - pub description: Option, - /// The title of this API. - pub title: Option, - /// [DEPRECATED] The base URL for REST requests. - #[serde(rename="baseUrl")] - pub base_url: Option, - /// The ETag for this response. - pub etag: Option, - /// The version of this API. - pub version: Option, - /// The base path for all REST requests. - #[serde(rename="servicePath")] - pub service_path: Option, - /// Indicate the version of the Discovery API used to generate this doc. - #[serde(rename="discoveryVersion")] - pub discovery_version: Option, - /// The schemas for this API. - pub schemas: Option>, - /// [DEPRECATED] The base path for REST requests. - #[serde(rename="basePath")] - pub base_path: Option, - /// The resources in this API. - pub resources: Option>, - /// The version of this API. - pub revision: Option, -} - -impl ResponseResult for RestDescription {} - - -/// Media upload parameters. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethodMediaUpload { - /// Maximum size of a media upload, such as "1MB", "2GB" or "3TB". - #[serde(rename="maxSize")] - pub max_size: Option, - /// MIME Media Ranges for acceptable media uploads to this method. - pub accept: Option>, - /// Supported upload protocols. - pub protocols: Option, -} - -impl NestedType for RestMethodMediaUpload {} -impl Part for RestMethodMediaUpload {} - - -/// There is no detailed description. -/// -/// # Activities -/// -/// This type is used in activities, which are methods you may call on this type or where this type is involved in. -/// The list links the activity name, along with information about where it is used (one of *request* and *response*). -/// -/// * [list apis](struct.ApiListCall.html) (response) -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct DirectoryList { - /// The individual directory entries. One entry per api/version pair. - pub items: Option>, - /// Indicate the version of the Discovery API used to generate this doc. - #[serde(rename="discoveryVersion")] - pub discovery_version: Option, - /// The kind for this response. - pub kind: Option, -} - -impl ResponseResult for DirectoryList {} - - -/// There is no detailed description. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct JsonSchema { - /// A description of this object. - pub description: Option, - /// An additional regular expression or key that helps constrain the value. For more details see: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.23 - pub format: Option, - /// Values this parameter may take (if it is an enum). - #[serde(rename="enum")] - pub enum_: Option>, - /// In a variant data type, the value of one property is used to determine how to interpret the entire entity. Its value must exist in a map of descriminant values to schema names. - pub variant: Option, - /// The descriptions for the enums. Each position maps to the corresponding value in the "enum" array. - #[serde(rename="enumDescriptions")] - pub enum_descriptions: Option>, - /// The value is read-only, generated by the service. The value cannot be modified by the client. If the value is included in a POST, PUT, or PATCH request, it is ignored by the service. - #[serde(rename="readOnly")] - pub read_only: Option, - /// The minimum value of this parameter. - pub minimum: Option, - /// Whether this parameter may appear multiple times. - pub repeated: Option, - /// Unique identifier for this schema. - pub id: Option, - /// A reference to another schema. The value of this property is the "id" of another schema. - #[serde(rename="$ref")] - pub ref_: Option, - /// The default value of this property (if one exists). - pub default: Option, - /// If this is a schema for an array, this property is the schema for each element in the array. - pub items: Option>>, - /// Whether the parameter is required. - pub required: Option, - /// The maximum value of this parameter. - pub maximum: Option, - /// If this is a schema for an object, list the schema for each property of this object. - pub properties: Option>, - /// Whether this parameter goes in the query or the path for REST requests. - pub location: Option, - /// The regular expression this parameter must conform to. Uses Java 6 regex format: http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html - pub pattern: Option, - /// If this is a schema for an object, this property is the schema for any additional properties with dynamic keys on this object. - #[serde(rename="additionalProperties")] - pub additional_properties: Option>>, - /// The value type for this schema. A list of values can be found here: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 - #[serde(rename="type")] - pub type_: Option, - /// Additional information about this property. - pub annotations: Option, -} - -impl Part for JsonSchema {} - - -/// The individual directory entries. One entry per api/version pair. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct DirectoryListItems { - /// The kind for this response. - pub kind: Option, - /// The URL for the discovery REST document. - #[serde(rename="discoveryRestUrl")] - pub discovery_rest_url: Option, - /// The description of this API. - pub description: Option, - /// Links to 16x16 and 32x32 icons representing the API. - pub icons: Option, - /// Labels for the status of this API, such as labs or deprecated. - pub labels: Option>, - /// True if this version is the preferred version to use. - pub preferred: Option, - /// A link to the discovery document. - #[serde(rename="discoveryLink")] - pub discovery_link: Option, - /// The version of the API. - pub version: Option, - /// The title of this API. - pub title: Option, - /// A link to human readable documentation for the API. - #[serde(rename="documentationLink")] - pub documentation_link: Option, - /// The id of this API. - pub id: Option, - /// The name of the API. - pub name: Option, -} - -impl NestedType for DirectoryListItems {} -impl Part for DirectoryListItems {} - - -/// Authentication information. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestDescriptionAuth { - /// OAuth 2.0 authentication information. - pub oauth2: Option, -} - -impl NestedType for RestDescriptionAuth {} -impl Part for RestDescriptionAuth {} - - -/// The scope value. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestDescriptionAuthOauth2Scopes { - /// Description of scope. - pub description: Option, -} - -impl NestedType for RestDescriptionAuthOauth2Scopes {} -impl Part for RestDescriptionAuthOauth2Scopes {} - - -/// Links to 16x16 and 32x32 icons representing the API. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct DirectoryListItemsIcons { - /// The URL of the 32x32 icon. - pub x32: Option, - /// The URL of the 16x16 icon. - pub x16: Option, -} - -impl NestedType for DirectoryListItemsIcons {} -impl Part for DirectoryListItemsIcons {} - - -/// The schema for the request. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethodRequest { - /// parameter name. - #[serde(rename="parameterName")] - pub parameter_name: Option, - /// Schema ID for the request schema. - #[serde(rename="$ref")] - pub ref_: Option, -} - -impl NestedType for RestMethodRequest {} -impl Part for RestMethodRequest {} - - -/// There is no detailed description. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestResource { - /// Methods on this resource. - pub methods: Option>, - /// Sub-resources on this resource. - pub resources: Option>, -} - -impl Part for RestResource {} - - -/// Supports uploading as a single HTTP request. -/// -/// This type is not used in any activity, and only used as *part* of another schema. -/// -#[derive(Default, Clone, Debug, Serialize, Deserialize)] -pub struct RestMethodMediaUploadProtocolsSimple { - /// The URI path to be used for upload. Should be used in conjunction with the basePath property at the api-level. - pub path: Option, - /// True if this endpoint supports upload multipart media. - pub multipart: Option, -} - -impl NestedType for RestMethodMediaUploadProtocolsSimple {} -impl Part for RestMethodMediaUploadProtocolsSimple {} - - - -// ################### -// MethodBuilders ### -// ################# - -/// A builder providing access to all methods supported on *api* resources. -/// It is not used directly, but through the `Discovery` hub. -/// -/// # Example -/// -/// Instantiate a resource builder -/// -/// ```test_harness,no_run -/// extern crate hyper; -/// extern crate yup_oauth2 as oauth2; -/// extern crate google_discovery1 as discovery1; -/// -/// # #[test] fn egal() { -/// use std::default::Default; -/// use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage}; -/// use discovery1::Discovery; -/// -/// let secret: ApplicationSecret = Default::default(); -/// let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate, -/// hyper::Client::new(), -/// ::default(), None); -/// let mut hub = Discovery::new(hyper::Client::new(), auth); -/// // Usually you wouldn't bind this to a variable, but keep calling *CallBuilders* -/// // like `get_rest(...)` and `list(...)` -/// // to build up your call. -/// let rb = hub.apis(); -/// # } -/// ``` -pub struct ApiMethods<'a, C, A> - where C: 'a, A: 'a { - - hub: &'a Discovery, -} - -impl<'a, C, A> MethodsBuilder for ApiMethods<'a, C, A> {} - -impl<'a, C, A> ApiMethods<'a, C, A> { - - /// Create a builder to help you perform the following task: - /// - /// Retrieve the description of a particular version of an api. - /// - /// # Arguments - /// - /// * `api` - The name of the API. - /// * `version` - The version of the API. - pub fn get_rest(&self, api: &str, version: &str) -> ApiGetRestCall<'a, C, A> { - ApiGetRestCall { - hub: self.hub, - _api: api.to_string(), - _version: version.to_string(), - _delegate: Default::default(), - _additional_params: Default::default(), - } - } - - /// Create a builder to help you perform the following task: - /// - /// Retrieve the list of APIs supported at this endpoint. - pub fn list(&self) -> ApiListCall<'a, C, A> { - ApiListCall { - hub: self.hub, - _preferred: Default::default(), - _name: Default::default(), - _delegate: Default::default(), - _additional_params: Default::default(), - } - } -} - - - - - -// ################### -// CallBuilders ### -// ################# - -/// Retrieve the description of a particular version of an api. -/// -/// A builder for the *getRest* method supported by a *api* resource. -/// It is not used directly, but through a `ApiMethods` instance. -/// -/// # Example -/// -/// Instantiate a resource method builder -/// -/// ```test_harness,no_run -/// # extern crate hyper; -/// # extern crate yup_oauth2 as oauth2; -/// # extern crate google_discovery1 as discovery1; -/// # #[test] fn egal() { -/// # use std::default::Default; -/// # use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage}; -/// # use discovery1::Discovery; -/// -/// # let secret: ApplicationSecret = Default::default(); -/// # let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate, -/// # hyper::Client::new(), -/// # ::default(), None); -/// # let mut hub = Discovery::new(hyper::Client::new(), auth); -/// // You can configure optional parameters by calling the respective setters at will, and -/// // execute the final call using `doit()`. -/// // Values shown here are possibly random and not representative ! -/// let result = hub.apis().get_rest("api", "version") -/// .doit(); -/// # } -/// ``` -pub struct ApiGetRestCall<'a, C, A> - where C: 'a, A: 'a { - - hub: &'a Discovery, - _api: String, - _version: String, - _delegate: Option<&'a mut Delegate>, - _additional_params: HashMap, -} - -impl<'a, C, A> CallBuilder for ApiGetRestCall<'a, C, A> {} - -impl<'a, C, A> ApiGetRestCall<'a, C, A> where C: BorrowMut, A: oauth2::GetToken { - - - /// Perform the operation you have build so far. - pub fn doit(mut self) -> Result<(hyper::client::Response, RestDescription)> { - use std::io::{Read, Seek}; - use hyper::header::{ContentType, ContentLength, Authorization, UserAgent, Location}; - let mut dd = DefaultDelegate; - let mut dlg: &mut Delegate = match self._delegate { - Some(d) => d, - None => &mut dd - }; - dlg.begin(MethodInfo { id: "discovery.apis.getRest", - http_method: hyper::method::Method::Get }); - let mut params: Vec<(&str, String)> = Vec::with_capacity((4 + self._additional_params.len())); - params.push(("api", self._api.to_string())); - params.push(("version", self._version.to_string())); - for &field in ["alt", "api", "version"].iter() { - if self._additional_params.contains_key(field) { - dlg.finished(false); - return Err(Error::FieldClash(field)); - } - } - for (name, value) in self._additional_params.iter() { - params.push((&name, value.clone())); - } - - params.push(("alt", "json".to_string())); - - let mut url = "https://www.googleapis.com/discovery/v1/apis/{api}/{version}/rest".to_string(); - - for &(find_this, param_name) in [("{api}", "api"), ("{version}", "version")].iter() { - let mut replace_with: Option<&str> = None; - for &(name, ref value) in params.iter() { - if name == param_name { - replace_with = Some(value); - break; - } - } - url = url.replace(find_this, replace_with.expect("to find substitution value in params")); - } - { - let mut indices_for_removal: Vec = Vec::with_capacity(2); - for param_name in ["api", "version"].iter() { - for (index, &(ref name, _)) in params.iter().rev().enumerate() { - if name == param_name { - indices_for_removal.push(params.len() - index - 1); - break; - } - } - } - for &index in indices_for_removal.iter() { - params.remove(index); - } - } - - if params.len() > 0 { - url.push('?'); - url.push_str(&url::form_urlencoded::serialize(params)); - } - - - - loop { - let mut req_result = { - let mut client = &mut *self.hub.client.borrow_mut(); - let mut req = client.borrow_mut().request(hyper::method::Method::Get, &url) - .header(UserAgent(self.hub._user_agent.clone())); - - dlg.pre_request(); - req.send() - }; - - match req_result { - Err(err) => { - if let oauth2::Retry::After(d) = dlg.http_error(&err) { - sleep_ms(d.num_milliseconds() as u32); - continue; - } - dlg.finished(false); - return Err(Error::HttpError(err)) - } - Ok(mut res) => { - if !res.status.is_success() { - let mut json_err = String::new(); - res.read_to_string(&mut json_err).unwrap(); - if let oauth2::Retry::After(d) = dlg.http_failure(&res, - json::from_str(&json_err).ok(), - json::from_str(&json_err).ok()) { - sleep_ms(d.num_milliseconds() as u32); - continue; - } - dlg.finished(false); - return match json::from_str::(&json_err){ - Err(_) => Err(Error::Failure(res)), - Ok(serr) => Err(Error::BadRequest(serr)) - } - } - let result_value = { - let mut json_response = String::new(); - res.read_to_string(&mut json_response).unwrap(); - match json::from_str(&json_response) { - Ok(decoded) => (res, decoded), - Err(err) => { - dlg.response_json_decode_error(&json_response, &err); - return Err(Error::JsonDecodeError(json_response, err)); - } - } - }; - - dlg.finished(true); - return Ok(result_value) - } - } - } - } - - - /// The name of the API. - /// - /// Sets the *api* path property to the given value. - /// - /// Even though the property as already been set when instantiating this call, - /// we provide this method for API completeness. - pub fn api(mut self, new_value: &str) -> ApiGetRestCall<'a, C, A> { - self._api = new_value.to_string(); - self - } - /// The version of the API. - /// - /// Sets the *version* path property to the given value. - /// - /// Even though the property as already been set when instantiating this call, - /// we provide this method for API completeness. - pub fn version(mut self, new_value: &str) -> ApiGetRestCall<'a, C, A> { - self._version = new_value.to_string(); - self - } - /// The delegate implementation is consulted whenever there is an intermediate result, or if something goes wrong - /// while executing the actual API request. - /// - /// It should be used to handle progress information, and to implement a certain level of resilience. - /// - /// Sets the *delegate* property to the given value. - pub fn delegate(mut self, new_value: &'a mut Delegate) -> ApiGetRestCall<'a, C, A> { - self._delegate = Some(new_value); - self - } - - /// Set any additional parameter of the query string used in the request. - /// It should be used to set parameters which are not yet available through their own - /// setters. - /// - /// Please note that this method must not be used to set any of the known paramters - /// which have their own setter method. If done anyway, the request will fail. - /// - /// # Additional Parameters - /// - /// * *quotaUser* (query-string) - Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided. - /// * *oauth_token* (query-string) - OAuth 2.0 token for the current user. - /// * *key* (query-string) - API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. - /// * *prettyPrint* (query-boolean) - Returns response with indentations and line breaks. - /// * *userIp* (query-string) - IP address of the site where the request originates. Use this if you want to enforce per-user limits. - /// * *fields* (query-string) - Selector specifying which fields to include in a partial response. - /// * *alt* (query-string) - Data format for the response. - pub fn param(mut self, name: T, value: T) -> ApiGetRestCall<'a, C, A> - where T: AsRef { - self._additional_params.insert(name.as_ref().to_string(), value.as_ref().to_string()); - self - } - -} - - -/// Retrieve the list of APIs supported at this endpoint. -/// -/// A builder for the *list* method supported by a *api* resource. -/// It is not used directly, but through a `ApiMethods` instance. -/// -/// # Example -/// -/// Instantiate a resource method builder -/// -/// ```test_harness,no_run -/// # extern crate hyper; -/// # extern crate yup_oauth2 as oauth2; -/// # extern crate google_discovery1 as discovery1; -/// # #[test] fn egal() { -/// # use std::default::Default; -/// # use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage}; -/// # use discovery1::Discovery; -/// -/// # let secret: ApplicationSecret = Default::default(); -/// # let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate, -/// # hyper::Client::new(), -/// # ::default(), None); -/// # let mut hub = Discovery::new(hyper::Client::new(), auth); -/// // You can configure optional parameters by calling the respective setters at will, and -/// // execute the final call using `doit()`. -/// // Values shown here are possibly random and not representative ! -/// let result = hub.apis().list() -/// .preferred(true) -/// .name("justo") -/// .doit(); -/// # } -/// ``` -pub struct ApiListCall<'a, C, A> - where C: 'a, A: 'a { - - hub: &'a Discovery, - _preferred: Option, - _name: Option, - _delegate: Option<&'a mut Delegate>, - _additional_params: HashMap, -} - -impl<'a, C, A> CallBuilder for ApiListCall<'a, C, A> {} - -impl<'a, C, A> ApiListCall<'a, C, A> where C: BorrowMut, A: oauth2::GetToken { - - - /// Perform the operation you have build so far. - pub fn doit(mut self) -> Result<(hyper::client::Response, DirectoryList)> { - use std::io::{Read, Seek}; - use hyper::header::{ContentType, ContentLength, Authorization, UserAgent, Location}; - let mut dd = DefaultDelegate; - let mut dlg: &mut Delegate = match self._delegate { - Some(d) => d, - None => &mut dd - }; - dlg.begin(MethodInfo { id: "discovery.apis.list", - http_method: hyper::method::Method::Get }); - let mut params: Vec<(&str, String)> = Vec::with_capacity((4 + self._additional_params.len())); - if let Some(value) = self._preferred { - params.push(("preferred", value.to_string())); - } - if let Some(value) = self._name { - params.push(("name", value.to_string())); - } - for &field in ["alt", "preferred", "name"].iter() { - if self._additional_params.contains_key(field) { - dlg.finished(false); - return Err(Error::FieldClash(field)); - } - } - for (name, value) in self._additional_params.iter() { - params.push((&name, value.clone())); - } - - params.push(("alt", "json".to_string())); - - let mut url = "https://www.googleapis.com/discovery/v1/apis".to_string(); - - - if params.len() > 0 { - url.push('?'); - url.push_str(&url::form_urlencoded::serialize(params)); - } - - - - loop { - let mut req_result = { - let mut client = &mut *self.hub.client.borrow_mut(); - let mut req = client.borrow_mut().request(hyper::method::Method::Get, &url) - .header(UserAgent(self.hub._user_agent.clone())); - - dlg.pre_request(); - req.send() - }; - - match req_result { - Err(err) => { - if let oauth2::Retry::After(d) = dlg.http_error(&err) { - sleep_ms(d.num_milliseconds() as u32); - continue; - } - dlg.finished(false); - return Err(Error::HttpError(err)) - } - Ok(mut res) => { - if !res.status.is_success() { - let mut json_err = String::new(); - res.read_to_string(&mut json_err).unwrap(); - if let oauth2::Retry::After(d) = dlg.http_failure(&res, - json::from_str(&json_err).ok(), - json::from_str(&json_err).ok()) { - sleep_ms(d.num_milliseconds() as u32); - continue; - } - dlg.finished(false); - return match json::from_str::(&json_err){ - Err(_) => Err(Error::Failure(res)), - Ok(serr) => Err(Error::BadRequest(serr)) - } - } - let result_value = { - let mut json_response = String::new(); - res.read_to_string(&mut json_response).unwrap(); - match json::from_str(&json_response) { - Ok(decoded) => (res, decoded), - Err(err) => { - dlg.response_json_decode_error(&json_response, &err); - return Err(Error::JsonDecodeError(json_response, err)); - } - } - }; - - dlg.finished(true); - return Ok(result_value) - } - } - } - } - - - /// Return only the preferred version of an API. - /// - /// Sets the *preferred* query property to the given value. - pub fn preferred(mut self, new_value: bool) -> ApiListCall<'a, C, A> { - self._preferred = Some(new_value); - self - } - /// Only include APIs with the given name. - /// - /// Sets the *name* query property to the given value. - pub fn name(mut self, new_value: &str) -> ApiListCall<'a, C, A> { - self._name = Some(new_value.to_string()); - self - } - /// The delegate implementation is consulted whenever there is an intermediate result, or if something goes wrong - /// while executing the actual API request. - /// - /// It should be used to handle progress information, and to implement a certain level of resilience. - /// - /// Sets the *delegate* property to the given value. - pub fn delegate(mut self, new_value: &'a mut Delegate) -> ApiListCall<'a, C, A> { - self._delegate = Some(new_value); - self - } - - /// Set any additional parameter of the query string used in the request. - /// It should be used to set parameters which are not yet available through their own - /// setters. - /// - /// Please note that this method must not be used to set any of the known paramters - /// which have their own setter method. If done anyway, the request will fail. - /// - /// # Additional Parameters - /// - /// * *quotaUser* (query-string) - Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Overrides userIp if both are provided. - /// * *oauth_token* (query-string) - OAuth 2.0 token for the current user. - /// * *key* (query-string) - API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. - /// * *prettyPrint* (query-boolean) - Returns response with indentations and line breaks. - /// * *userIp* (query-string) - IP address of the site where the request originates. Use this if you want to enforce per-user limits. - /// * *fields* (query-string) - Selector specifying which fields to include in a partial response. - /// * *alt* (query-string) - Data format for the response. - pub fn param(mut self, name: T, value: T) -> ApiListCall<'a, C, A> - where T: AsRef { - self._additional_params.insert(name.as_ref().to_string(), value.as_ref().to_string()); - self - } - -} - +include!(concat!(env!("OUT_DIR"), "/lib.rs")); \ No newline at end of file diff --git a/src/mako/Cargo.toml.mako b/src/mako/Cargo.toml.mako index 36da136bed..82203c3d5b 100644 --- a/src/mako/Cargo.toml.mako +++ b/src/mako/Cargo.toml.mako @@ -16,6 +16,9 @@ homepage = "${documentationLink}" documentation = "${cargo.doc_base_url}/${to_extern_crate_name(util.crate_name())}" license = "${copyright.license_abbrev}" keywords = ["${name[:20]}", ${", ".join(estr(cargo.keywords))}] +% if cargo.get('build_script'): +build = "${cargo.build_script}" +% endif % if cargo.get('is_executable', False): [[bin]] @@ -23,19 +26,18 @@ name = "${util.program_name()}" % endif [dependencies] -hyper = ">= 0.5.0" -mime = "*" -serde = ">= 0.3.0" -serde_macros = "*" +hyper = ">= 0.5.2" +## Must match the one hyper uses, otherwise there are duplicate similarly named `Mime` structs +mime = "0.0.11" +serde = ">= 0.4.1" +yup-oauth2 = "*" % for dep in cargo.get('dependencies', list()): ${dep} % endfor -# to adapt to hyper changes ... -[dependencies.yup-oauth2] -version = "*" -git = "https://github.com/Byron/yup-oauth2" -rev = "598f5ed496077e9edca36ff95e2ab352c5b22d0f" +[build-dependencies] +syntex = { version = "*" } +serde_codegen = { version = "*" } % if make.depends_on_suffix is not None: diff --git a/src/mako/api/build.rs.mako b/src/mako/api/build.rs.mako new file mode 100644 index 0000000000..03dd77aa65 --- /dev/null +++ b/src/mako/api/build.rs.mako @@ -0,0 +1,17 @@ +<%namespace name="util" file="../lib/util.mako"/>\ +extern crate syntex; +extern crate serde_codegen; + +use std::env; +use std::path::Path; + +pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/lib.rs.in"); + let dst = Path::new(&out_dir).join("lib.rs"); + + let mut registry = syntex::Registry::new(); + serde_codegen::register(&mut registry); + registry.expand("${util.crate_name()}", &src, &dst).unwrap(); +} diff --git a/src/mako/api/lib.rs.in.mako b/src/mako/api/lib.rs.in.mako new file mode 100644 index 0000000000..b7d6d63f1e --- /dev/null +++ b/src/mako/api/lib.rs.in.mako @@ -0,0 +1,133 @@ +<%namespace name="lib" file="lib/lib.mako"/>\ +<%namespace name="util" file="../lib/util.mako"/>\ +<%namespace name="rbuild" file="lib/rbuild.mako"/>\ +<%namespace name="mbuild" file="lib/mbuild.mako"/>\ +<%namespace name="schema" file="lib/schema.mako"/>\ +<% + from util import (new_context, rust_comment, rust_doc_comment, rust_module_doc_comment, + rb_type, hub_type, mangle_ident, hub_type_params_s, hub_type_bounds, + rb_type_params_s, find_fattest_resource, HUB_TYPE_PARAMETERS, METHODS_RESOURCE, + UNUSED_TYPE_MARKER, schema_markers) + + c = new_context(schemas, resources, context.get('methods')) + hub_type = hub_type(c.schemas, util.canonical_name()) + ht_params = hub_type_params_s() + + default_user_agent = "google-api-rust-client/" + cargo.build_version +%>\ +<%block filter="rust_comment">\ +<%util:gen_info source="${self.uri}" />\ + + +extern crate hyper; +extern crate serde; +extern crate yup_oauth2 as oauth2; +extern crate mime; +extern crate url; + +mod cmn; + +use std::collections::HashMap; +use std::cell::RefCell; +use std::borrow::BorrowMut; +use std::default::Default; +use std::collections::BTreeMap; +use serde::json; +use std::io; +use std::fs; +use std::thread::sleep_ms; + +pub use cmn::{MultiPartReader, ToParts, MethodInfo, Result, Error, CallBuilder, Hub, ReadSeek, Part, + ResponseResult, RequestValue, NestedType, Delegate, DefaultDelegate, MethodsBuilder, + Resource, ErrorResponse, remove_json_null_values}; + + +// ############## +// UTILITIES ### +// ############ + +${lib.scope_enum()} + + +// ######## +// HUB ### +// ###### + +/// Central instance to access all ${hub_type} related resource activities +/// +/// # Examples +/// +/// Instantiate a new hub +/// +<%block filter="rust_doc_comment">\ +${lib.hub_usage_example(c)}\ + +pub struct ${hub_type}${ht_params} { + client: RefCell, + auth: RefCell, + _user_agent: String, +} + +impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> Hub for ${hub_type}${ht_params} {} + +impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> ${hub_type}${ht_params} + where ${', '.join(hub_type_bounds())} { + + pub fn new(client: C, authenticator: A) -> ${hub_type}${ht_params} { + ${hub_type} { + client: RefCell::new(client), + auth: RefCell::new(authenticator), + _user_agent: "${default_user_agent}".to_string(), + } + } + + % for resource in sorted(c.rta_map.keys()): + pub fn ${mangle_ident(resource)}(&'a self) -> ${rb_type(resource)}${rb_type_params_s(resource, c)} { + ${rb_type(resource)} { hub: &self } + } + % endfor + + /// Set the user-agent header field to use in all requests to the server. + /// It defaults to `${default_user_agent}`. + /// + /// Returns the previously set user-agent. + pub fn user_agent(&mut self, agent_name: String) -> String { + let prev = self._user_agent.clone(); + self._user_agent = agent_name; + prev + } +} + + +% if c.schemas: +// ############ +// SCHEMAS ### +// ########## +% for s in c.schemas.values(): +% if UNUSED_TYPE_MARKER not in schema_markers(s, c, transitive=True): +${schema.new(s, c)} +% endif +% endfor +% endif + +// ################### +// MethodBuilders ### +// ################# + +% for resource in c.rta_map: +${rbuild.new(resource, c)} + + +% endfor + + +// ################### +// CallBuilders ### +// ################# + +% for resource, methods in c.rta_map.iteritems(): +% for method in methods: +${mbuild.new(resource, method, c)} + +% endfor ## method in methods +% endfor ## resource, methods \ No newline at end of file diff --git a/src/mako/api/lib.rs.mako b/src/mako/api/lib.rs.mako index b485218f39..b3466da3e6 100644 --- a/src/mako/api/lib.rs.mako +++ b/src/mako/api/lib.rs.mako @@ -1,19 +1,9 @@ <%namespace name="lib" file="lib/lib.mako"/>\ <%namespace name="util" file="../lib/util.mako"/>\ -<%namespace name="rbuild" file="lib/rbuild.mako"/>\ -<%namespace name="mbuild" file="lib/mbuild.mako"/>\ -<%namespace name="schema" file="lib/schema.mako"/>\ <% - from util import (new_context, rust_comment, rust_doc_comment, rust_module_doc_comment, - rb_type, hub_type, mangle_ident, hub_type_params_s, hub_type_bounds, - rb_type_params_s, find_fattest_resource, HUB_TYPE_PARAMETERS, METHODS_RESOURCE, - UNUSED_TYPE_MARKER, schema_markers) + from util import (new_context, rust_comment, rust_module_doc_comment) c = new_context(schemas, resources, context.get('methods')) - hub_type = hub_type(c.schemas, util.canonical_name()) - ht_params = hub_type_params_s() - - default_user_agent = "google-api-rust-client/" + cargo.build_version %>\ <%block filter="rust_comment">\ <%util:gen_info source="${self.uri}" />\ @@ -22,124 +12,11 @@ <%block filter="rust_module_doc_comment">\ ${lib.docs(c)} + // Unused attributes happen thanks to defined, but unused structures // We don't warn about this, as depending on the API, some data structures or facilities are never used. // Instead of pre-determining this, we just disable the lint. It's manually tuned to not have any // unused imports in fully featured APIs. Same with unused_mut ... . #![allow(unused_imports, unused_mut, dead_code)] -// Required for serde annotations -#![feature(custom_derive, custom_attribute, plugin, slice_patterns)] -#![plugin(serde_macros)] -#[macro_use] -extern crate hyper; -extern crate serde; -extern crate yup_oauth2 as oauth2; -extern crate mime; -extern crate url; -extern crate json_tools; - -mod cmn; - -use std::collections::HashMap; -use std::cell::RefCell; -use std::borrow::BorrowMut; -use std::default::Default; -use std::collections::BTreeMap; -use serde::json; -use std::io; -use std::fs; -use std::thread::sleep_ms; - -pub use cmn::{MultiPartReader, ToParts, MethodInfo, Result, Error, CallBuilder, Hub, ReadSeek, Part, ResponseResult, RequestValue, NestedType, Delegate, DefaultDelegate, MethodsBuilder, Resource, ErrorResponse}; - - -// ############## -// UTILITIES ### -// ############ - -${lib.scope_enum()} - - -// ######## -// HUB ### -// ###### - -/// Central instance to access all ${hub_type} related resource activities -/// -/// # Examples -/// -/// Instantiate a new hub -/// -<%block filter="rust_doc_comment">\ -${lib.hub_usage_example(c)}\ - -pub struct ${hub_type}${ht_params} { - client: RefCell, - auth: RefCell, - _user_agent: String, -} - -impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> Hub for ${hub_type}${ht_params} {} - -impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> ${hub_type}${ht_params} - where ${', '.join(hub_type_bounds())} { - - pub fn new(client: C, authenticator: A) -> ${hub_type}${ht_params} { - ${hub_type} { - client: RefCell::new(client), - auth: RefCell::new(authenticator), - _user_agent: "${default_user_agent}".to_string(), - } - } - - % for resource in sorted(c.rta_map.keys()): - pub fn ${mangle_ident(resource)}(&'a self) -> ${rb_type(resource)}${rb_type_params_s(resource, c)} { - ${rb_type(resource)} { hub: &self } - } - % endfor - - /// Set the user-agent header field to use in all requests to the server. - /// It defaults to `${default_user_agent}`. - /// - /// Returns the previously set user-agent. - pub fn user_agent(&mut self, agent_name: String) -> String { - let prev = self._user_agent.clone(); - self._user_agent = agent_name; - prev - } -} - - -% if c.schemas: -// ############ -// SCHEMAS ### -// ########## -% for s in c.schemas.values(): -% if UNUSED_TYPE_MARKER not in schema_markers(s, c, transitive=True): -${schema.new(s, c)} -% endif -% endfor -% endif - -// ################### -// MethodBuilders ### -// ################# - -% for resource in c.rta_map: -${rbuild.new(resource, c)} - - -% endfor - - -// ################### -// CallBuilders ### -// ################# - -% for resource, methods in c.rta_map.iteritems(): -% for method in methods: -${mbuild.new(resource, method, c)} - -% endfor ## method in methods -% endfor ## resource, methods \ No newline at end of file +include!(concat!(env!("OUT_DIR"), "/lib.rs")); \ No newline at end of file diff --git a/src/mako/api/lib/mbuild.mako b/src/mako/api/lib/mbuild.mako index 78cb303f22..a6b1860c8c 100644 --- a/src/mako/api/lib/mbuild.mako +++ b/src/mako/api/lib/mbuild.mako @@ -483,9 +483,6 @@ match result { % if URL_ENCODE in special_cases: use url::percent_encoding::{percent_encode, FORM_URLENCODED_ENCODE_SET}; % endif - % if request_value: - use json_tools::{TokenReader, Lexer, BufferType, TokenType, FilterTypedKeyValuePairs, IteratorExt}; - % endif use std::io::{Read, Seek}; use hyper::header::{ContentType, ContentLength, Authorization, UserAgent, Location}; let mut dd = DefaultDelegate; @@ -665,13 +662,11 @@ else { let mut json_mime_type = mime::Mime(mime::TopLevel::Application, mime::SubLevel::Json, Default::default()); let mut request_value_reader = { - let json_cache = json::to_string(&self.${property(REQUEST_VALUE_PROPERTY_NAME)}).unwrap(); - let mut mem_dst = io::Cursor::new(Vec::with_capacity(json_cache.len())); - io::copy(&mut Lexer::new(json_cache.bytes(), BufferType::Span) - .filter_key_value_by_type(TokenType::Null) - .reader(Some(&json_cache)), &mut mem_dst).unwrap(); - mem_dst.seek(io::SeekFrom::Start(0)).unwrap(); - mem_dst + let mut value = json::value::to_value(&self.${property(REQUEST_VALUE_PROPERTY_NAME)}); + remove_json_null_values(&mut value); + let mut dst = io::Cursor::new(Vec::with_capacity(128)); + json::to_writer(&mut dst, &value).unwrap(); + dst }; let request_size = request_value_reader.seek(io::SeekFrom::End(0)).unwrap(); request_value_reader.seek(io::SeekFrom::Start(0)).unwrap(); diff --git a/src/mako/cli/lib/engine.mako b/src/mako/cli/lib/engine.mako index 661d3c63db..2661125ee0 100644 --- a/src/mako/cli/lib/engine.mako +++ b/src/mako/cli/lib/engine.mako @@ -323,7 +323,7 @@ if dry_run { % if mc.response_schema: let mut value = json::value::to_value(&output_schema); remove_json_null_values(&mut value); - serde::json::to_writer_pretty(&mut ostream, &value).unwrap(); + json::to_writer_pretty(&mut ostream, &value).unwrap(); % endif % if track_download_flag: } else { diff --git a/src/mako/cli/main.rs.mako b/src/mako/cli/main.rs.mako index 35e1986fb4..3149e59ca4 100644 --- a/src/mako/cli/main.rs.mako +++ b/src/mako/cli/main.rs.mako @@ -12,7 +12,6 @@ <%block filter="rust_comment">\ <%util:gen_info source="${self.uri}" />\ -#![feature(plugin, exit_status)] #![allow(unused_variables, unused_imports, dead_code, unused_mut)] #[macro_use] @@ -34,18 +33,19 @@ mod cmn; ${engine.new(c)}\ fn main() { + let mut exit_status = 0i32; ${argparse.new(c) | indent_all_but_first_by(1)}\ let matches = app.get_matches(); let debug = matches.is_present("${DEBUG_FLAG}"); match Engine::new(matches) { Err(err) => { - env::set_exit_status(err.exit_code); + exit_status = err.exit_code; writeln!(io::stderr(), "{}", err).ok(); }, Ok(engine) => { if let Err(doit_err) = engine.doit() { - env::set_exit_status(1); + exit_status = 1; match doit_err { DoitError::IoError(path, err) => { writeln!(io::stderr(), "Failed to open output file '{}': {}", path, err).ok(); @@ -61,4 +61,6 @@ fn main() { } } } + + std::process::exit(exit_status); } \ No newline at end of file diff --git a/src/rust/api/cmn.rs b/src/rust/api/cmn.rs index c6d6b7185c..1422e1f554 100644 --- a/src/rust/api/cmn.rs +++ b/src/rust/api/cmn.rs @@ -288,7 +288,7 @@ impl Display for Error { writeln!(f, "The media size {} exceeds the maximum allowed upload size of {}" , resource_size, max_size), Error::MissingAPIKey => { - writeln!(f, "The application's API key was not found in the configuration").ok(); + (writeln!(f, "The application's API key was not found in the configuration")).ok(); writeln!(f, "It is used as there are no Scopes defined for this method.") }, Error::BadRequest(ref err) => { @@ -422,8 +422,8 @@ impl<'a> Read for MultiPartReader<'a> { (n, true, _) if n > 0 => { let (headers, reader) = self.raw_parts.remove(0); let mut c = Cursor::new(Vec::::new()); - write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING, - headers, LINE_ENDING).unwrap(); + (write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING, + headers, LINE_ENDING)).unwrap(); c.seek(SeekFrom::Start(0)).unwrap(); self.current_part = Some((c, reader)); } @@ -469,18 +469,51 @@ impl<'a> Read for MultiPartReader<'a> { } } -header!{ - #[doc="The `X-Upload-Content-Type` header."] - (XUploadContentType, "X-Upload-Content-Type") => [Mime] +// The following macro invocation needs to be expanded, as `include!` +// doens't support external macros +// header!{ +// #[doc="The `X-Upload-Content-Type` header."] +// (XUploadContentType, "X-Upload-Content-Type") => [Mime] - xupload_content_type { - test_header!( - test1, - vec![b"text/plain"], - Some(HeaderField( - vec![Mime(TopLevel::Text, SubLevel::Plain, Vec::new())] - ))); +// xupload_content_type { +// test_header!( +// test1, +// vec![b"text/plain"], +// Some(HeaderField( +// vec![Mime(TopLevel::Text, SubLevel::Plain, Vec::new())] +// ))); +// } +// } + +/// The `X-Upload-Content-Type` header. +/// +/// Generated via rustc --pretty expanded -Z unstable-options, and manually +/// processed to be more readable. +#[derive(PartialEq, Debug, Clone)] +pub struct XUploadContentType(pub Mime); + +impl ::std::ops::Deref for XUploadContentType { + type Target = Mime; + fn deref<'a>(&'a self) -> &'a Mime { &self.0 } +} +impl ::std::ops::DerefMut for XUploadContentType { + fn deref_mut<'a>(&'a mut self) -> &'a mut Mime { &mut self.0 } +} +impl Header for XUploadContentType { + fn header_name() -> &'static str { "X-Upload-Content-Type" } + fn parse_header(raw: &[Vec]) -> Option { + hyper::header::parsing::from_one_raw_str(raw).map(XUploadContentType) + } +} +impl HeaderFormat for XUploadContentType { + fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&**self, f) + } +} +impl Display for XUploadContentType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) } } @@ -492,7 +525,7 @@ pub struct Chunk { impl fmt::Display for Chunk { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}-{}", self.first, self.last).ok(); + (write!(fmt, "{}-{}", self.first, self.last)).ok(); Ok(()) } } @@ -534,7 +567,7 @@ impl Header for ContentRange { } /// We are not parsable, as parsing is done by the `Range` header - fn parse_header(_: &[Vec]) -> Option { + fn parse_header(_: &[Vec]) -> Option { None } } @@ -547,7 +580,7 @@ impl HeaderFormat for ContentRange { Some(ref c) => try!(c.fmt(fmt)), None => try!(fmt.write_str("*")) } - write!(fmt, "/{}", self.total_length).ok(); + (write!(fmt, "/{}", self.total_length)).ok(); Ok(()) } } @@ -560,8 +593,9 @@ impl Header for RangeResponseHeader { "Range" } - fn parse_header(raw: &[Vec]) -> Option { - if let [ref v] = raw { + fn parse_header(raw: &[Vec]) -> Option { + if raw.len() > 0 { + let v = &raw[0]; if let Ok(s) = std::str::from_utf8(v) { const PREFIX: &'static str = "bytes "; if s.starts_with(PREFIX) { @@ -700,4 +734,27 @@ impl<'a, A> ResumableUploadHelper<'a, A> } } } -} \ No newline at end of file +} + +// Copy of src/rust/cli/cmn.rs +// TODO(ST): Allow sharing common code between program types +pub fn remove_json_null_values(value: &mut serde::json::value::Value) { + match *value { + serde::json::value::Value::Object(ref mut map) => { + let mut for_removal = Vec::new(); + + for (key, mut value) in map.iter_mut() { + if value.is_null() { + for_removal.push(key.clone()); + } else { + remove_json_null_values(&mut value); + } + } + + for key in &for_removal { + map.remove(key); + } + } + _ => {} + } +}