Skip to content

Commit

Permalink
feat(make): cli depends on API, generically
Browse files Browse the repository at this point in the history
This allows us to build efficiently. CLI programs can now have their
own cmn.rs implementation, which we can test standalone with
`cargo test`.

The primary makefile currently just explicitly pulls in the type-*.yaml,
one day we could possibly put it into a loop.

Fixes #11
  • Loading branch information
Byron committed Mar 24, 2015
1 parent caaf62e commit cefd606
Show file tree
Hide file tree
Showing 37 changed files with 3,014 additions and 2,483 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
.pyenv
.virtualenv
gen/doc/
gen/*-cli/
*.go
*.pyc
**target/
.api.deps
.*.deps
**Cargo.lock
*.sublime-workspace
21 changes: 14 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: json-to-xml clean help api-deps regen-apis license
.PHONY: clean help deps regen-apis license
.SUFFIXES:

VENV = .virtualenv/virtualenv.py
Expand All @@ -13,9 +13,11 @@ MAKO_SRC = src/mako
RUST_SRC = src/rust
API_DEPS_TPL = $(MAKO_SRC)/deps.mako
API_DEPS = .api.deps
CLI_DEPS = .cli.deps
API_DIR = etc/api
API_SHARED_INFO = $(API_DIR)/shared.yaml
TYPE_API_INFO = $(API_DIR)/type-api.yaml
TYPE_CLI_INFO = $(API_DIR)/type-cli.yaml
API_LIST = $(API_DIR)/
ifdef TRAVIS
API_LIST := $(API_LIST)api-list_travis.yaml
Expand All @@ -33,13 +35,14 @@ help:
$(info )
$(info Targets)
$(info help-api - show all api targets to build individually)
$(info help-cli - show all cli targets to build individually)
$(info docs-all - cargo-doc on all APIs and associates, assemble them together and generate index)
$(info docs-all-clean - remove the entire set of generated documentation)
$(info github-pages - invoke ghp-import on all documentation)
$(info regen-apis - clear out all generated apis, and regenerate them)
$(info license - regenerate the main license file)
$(info update-json - rediscover API schema json files and update api-list.yaml with latest versions)
$(info api-deps - generate a file to tell make what API file dependencies will be)
$(info deps - generate a file to tell how to build libraries and programs)
$(info help - print this help)

$(VENV):
Expand All @@ -56,19 +59,23 @@ $(MAKO_RENDER): $(PYTHON)
# Explicitly NOT depending on $(MAKO_LIB_FILES), as it's quite stable and now takes 'too long' thanks
# to a URL get call to the google discovery service
$(API_DEPS): $(API_DEPS_TPL) $(API_SHARED_INFO) $(MAKO_RENDER) $(TYPE_API_INFO) $(API_LIST)
$(MAKO) -io $(API_DEPS_TPL)=$@ --var TYPE=api --data-files $(API_SHARED_INFO) $(TYPE_API_INFO) $(API_LIST)
$(MAKO) -io $(API_DEPS_TPL)=$@ --data-files $(API_SHARED_INFO) $(TYPE_API_INFO) $(API_LIST)

api-deps: $(API_DEPS)
$(CLI_DEPS): $(API_DEPS_TPL) $(API_SHARED_INFO) $(MAKO_RENDER) $(TYPE_CLI_INFO) $(API_LIST)
$(MAKO) -io $(API_DEPS_TPL)=$@ --data-files $(API_SHARED_INFO) $(TYPE_CLI_INFO) $(API_LIST)

deps: $(API_DEPS) $(CLI_DEPS)

include $(API_DEPS)
include $(CLI_DEPS)

LICENSE.md: $(MAKO_SRC)/LICENSE.md.mako $(API_SHARED_INFO) $(MAKO_RENDER)
$(MAKO) -io $<=$@ --data-files $(API_SHARED_INFO)

license: LICENSE.md

regen-apis: clean-apis apis license
regen-apis: | clean-all-api clean-all-cli gen-all-api gen-all-cli license

clean: clean-apis
clean: clean-all-api clean-all-cli
-rm -Rf $(VENV_DIR)
-rm $(API_DEPS)
-rm $(API_DEPS) $(CLI_DEPS)
12 changes: 0 additions & 12 deletions etc/api/api-list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ api:
- v1
calendar:
- v3
# Does not build yet, see serde issue: https://github.com/erickt/rust-serde/issues/45
# civicinfo:
# - v2
cloudlatencytest:
- v2
cloudmonitoring:
Expand All @@ -62,9 +59,6 @@ api:
- v2beta1
dfareporting:
- v2.0
# Does not build yet, see serde issue: https://github.com/erickt/rust-serde/issues/45
# discovery:
# - v1
dns:
- v1beta1
doubleclickbidmanager:
Expand All @@ -85,9 +79,6 @@ api:
- v1configuration
gamesmanagement:
- v1management
# Does not build yet, see serde issue: https://github.com/erickt/rust-serde/issues/45
# gan:
# - v1beta1
genomics:
- v1beta2
gmail:
Expand All @@ -110,9 +101,6 @@ api:
- v2
pagespeedonline:
- v2
# Does not build yet, see serde issue: https://github.com/erickt/rust-serde/issues/45
# plus:
# - v1
plusdomains:
- v1
prediction:
Expand Down
8 changes: 8 additions & 0 deletions etc/api/shared.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
api:
blacklist:
# All of these require Box<> support in serde
# See https://github.com/erickt/rust-serde/issues/45
- civicinfo
- discovery
- gan
- plus
# Contains values shared among all API implementations
directories:
# directory under which all generated sources should reside
Expand Down
3 changes: 2 additions & 1 deletion etc/api/type-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ api:
# custom scopes for authentication
scopes: '_scopes'
make:
id: api
target_name: APIs
target_suffix: ''
aggregated_target_suffix: -api
depends_on:
depends_on_suffix:
global_targets: Yes
templates:
# all output directories are relative to the one set for the respective API
Expand Down
3 changes: 2 additions & 1 deletion etc/api/type-cli.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
make:
id: cli
target_name: CLIs
target_suffix: -cli
aggregated_target_suffix: -cli
depends_on: api
depends_on_suffix: ''
templates:
- source: ../LICENSE.md
- source: ../Cargo.toml
Expand Down
22 changes: 0 additions & 22 deletions gen/Cargo.toml

This file was deleted.

2 changes: 1 addition & 1 deletion gen/drive2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ keywords = ["drive", "google", "protocol", "web", "api"]
[dependencies]
hyper = "*"
mime = "*"
yup-oauth2 = "*"
url = "*"
serde = "*"
serde_macros = "*"
yup-oauth2 = "*"
35 changes: 21 additions & 14 deletions gen/drive2/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!---
DO NOT EDIT !
This file was generated automatically from 'src/mako/README.md.mako'
This file was generated automatically from 'src/mako/api/README.md.mako'
DO NOT EDIT !
-->
The `google-drive2` library allows access to all features of the *Google drive* service.
Expand Down Expand Up @@ -69,6 +69,8 @@ The API is structured into the following primary items:

* **[Hub](http://byron.github.io/google-apis-rs/google-drive2/struct.Drive.html)**
* a central object to maintain state and allow accessing all *Activities*
* creates [*Method Builders*](http://byron.github.io/google-apis-rs/google-drive2/trait.MethodsBuilder.html) which in turn
allow access to individual [*Call Builders*](http://byron.github.io/google-apis-rs/google-drive2/trait.CallBuilder.html)
* **[Resources](http://byron.github.io/google-apis-rs/google-drive2/trait.Resource.html)**
* primary types that you can apply *Activities* to
* a collection of properties and *Parts*
Expand All @@ -78,6 +80,8 @@ The API is structured into the following primary items:
* **[Activities](http://byron.github.io/google-apis-rs/google-drive2/trait.CallBuilder.html)**
* operations to apply to *Resources*

All *structures* are marked with applicable traits to further categorize them and ease browsing.

Generally speaking, you can invoke *Activities* like this:

```Rust,ignore
Expand Down Expand Up @@ -124,7 +128,7 @@ extern crate hyper;
extern crate "yup-oauth2" as oauth2;
extern crate "google-drive2" as drive2;
use drive2::File;
use drive2::Result;
use drive2::{Result, Error};
use std::default::Default;
use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage};
use drive2::Drive;
Expand Down Expand Up @@ -165,15 +169,17 @@ let result = hub.files().patch(&req, "fileId")
.doit();

match result {
Result::HttpError(err) => println!("HTTPERROR: {:?}", err),
Result::MissingAPIKey => println!("Auth: Missing API Key - used if there are no scopes"),
Result::MissingToken => println!("OAuth2: Missing Token"),
Result::Cancelled => println!("Operation cancelled by user"),
Result::UploadSizeLimitExceeded(size, max_size) => println!("Upload size too big: {} of {}", size, max_size),
Result::Failure(_) => println!("General Failure (hyper::client::Response doesn't print)"),
Result::FieldClash(clashed_field) => println!("You added custom parameter which is part of builder: {:?}", clashed_field),
Result::JsonDecodeError(err) => println!("Couldn't understand server reply - maybe API needs update: {:?}", err),
Result::Success(_) => println!("Success (value doesn't print)"),
Err(e) => match e {
Error::HttpError(err) => println!("HTTPERROR: {:?}", err),
Error::MissingAPIKey => println!("Auth: Missing API Key - used if there are no scopes"),
Error::MissingToken => println!("OAuth2: Missing Token"),
Error::Cancelled => println!("Operation canceled by user"),
Error::UploadSizeLimitExceeded(size, max_size) => println!("Upload size too big: {} of {}", size, max_size),
Error::Failure(_) => println!("General Failure (hyper::client::Response doesn't print)"),
Error::FieldClash(clashed_field) => println!("You added custom parameter which is part of builder: {:?}", clashed_field),
Error::JsonDecodeError(err) => println!("Couldn't understand server reply - maybe API needs update: {:?}", err),
},
Ok(_) => println!("Success (value doesn't print)"),
}

```
Expand All @@ -186,7 +192,7 @@ the doit() methods, or handed as possibly intermediate results to either the
When delegates handle errors or intermediate values, they may have a chance to instruct the system to retry. This
makes the system potentially resilient to all kinds of errors.

## Uploads and Downlods
## Uploads and Downloads
If a method supports downloads, the response body, which is part of the [Result](http://byron.github.io/google-apis-rs/google-drive2/enum.Result.html), should be
read by you to obtain the media.
If such a method also supports a [Response Result](http://byron.github.io/google-apis-rs/google-drive2/trait.ResponseResult.html), it will return that by default.
Expand All @@ -209,8 +215,9 @@ The [delegate trait](http://byron.github.io/google-apis-rs/google-drive2/trait.D
## Optional Parts in Server-Requests

All structures provided by this library are made to be [enocodable](http://byron.github.io/google-apis-rs/google-drive2/trait.RequestValue.html) and
[decodable](http://byron.github.io/google-apis-rs/google-drive2/trait.ResponseResult.html) via json. Optionals are used to indicate that partial requests are responses are valid.
Most optionals are are considered [Parts](http://byron.github.io/google-apis-rs/google-drive2/trait.Part.html) which are identifyable by name, which will be sent to
[decodable](http://byron.github.io/google-apis-rs/google-drive2/trait.ResponseResult.html) via *json*. Optionals are used to indicate that partial requests are responses
are valid.
Most optionals are are considered [Parts](http://byron.github.io/google-apis-rs/google-drive2/trait.Part.html) which are identifiable by name, which will be sent to
the server to indicate either the set parts of the request or the desired parts in the response.

## Builder Arguments
Expand Down
42 changes: 24 additions & 18 deletions gen/drive2/src/cmn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use serde;
pub trait Hub: MarkerTrait {}

/// Identifies types for building methods of a particular resource type
pub trait ResourceMethodsBuilder: MarkerTrait {}
pub trait MethodsBuilder: MarkerTrait {}

/// Identifies types which represent builders for a particular resource method
pub trait CallBuilder: MarkerTrait {}
Expand Down Expand Up @@ -105,12 +105,15 @@ pub trait Delegate {
/// information if he is interesting in knowing more context when further calls to it
/// are made.
/// The matching `finished()` call will always be made, no matter whether or not the API
/// request was sucessfull. That way, the delgate may easily maintain a clean state
/// request was successful. That way, the delegate may easily maintain a clean state
/// between various API calls.
fn begin(&mut self, MethodInfo) {}

/// Called whenever there is an [HttpError](http://hyperium.github.io/hyper/hyper/error/enum.HttpError.html), usually if there are network problems.
///
/// If you choose to retry after a duration, the duration should be chosen using the
/// [exponential backoff algorithm](http://en.wikipedia.org/wiki/Exponential_backoff).
///
/// Return retry information.
fn http_error(&mut self, &hyper::HttpError) -> Retry {
Retry::Abort
Expand All @@ -133,7 +136,7 @@ pub trait Delegate {
/// Called during resumable uploads to provide a URL for the impending upload.
/// It was saved after a previous call to `store_upload_url(...)`, and if not None,
/// will be used instead of asking the server for a new upload URL.
/// This is useful in case a previous resumable upload was aborted/cancelled, but should now
/// This is useful in case a previous resumable upload was aborted/canceled, but should now
/// be resumed.
/// The returned URL will be used exactly once - if it fails again and the delegate allows
/// to retry, we will ask the server for a new upload URL.
Expand All @@ -154,8 +157,8 @@ pub trait Delegate {
///
/// # Arguments
///
/// `json_encoded_value` - The json-encoded value which failed to decode.
/// `json_decode_error` - The decoder error
/// * `json_encoded_value` - The json-encoded value which failed to decode.
/// * `json_decode_error` - The decoder error
fn response_json_decode_error(&mut self, json_encoded_value: &str, json_decode_error: &serde::json::Error) {
let _ = json_encoded_value;
let _ = json_decode_error;
Expand All @@ -166,6 +169,9 @@ pub trait Delegate {
/// depends on the used API method.
/// The delegate should check the status, header and decoded json error to decide
/// whether to retry or not. In the latter case, the underlying call will fail.
///
/// If you choose to retry after a duration, the duration should be chosen using the
/// [exponential backoff algorithm](http://en.wikipedia.org/wiki/Exponential_backoff).
fn http_failure(&mut self, _: &hyper::client::Response, Option<JsonServerError>) -> Retry {
Retry::Abort
}
Expand Down Expand Up @@ -197,8 +203,8 @@ pub trait Delegate {
///
/// # Arguments
///
/// `is_success` - a true value indicates the operation was successful. If false, you should
/// discard all values stored during `store_upload_url`.
/// * `is_success` - a true value indicates the operation was successful. If false, you should
/// discard all values stored during `store_upload_url`.
fn finished(&mut self, is_success: bool) {
let _ = is_success;
}
Expand All @@ -212,8 +218,8 @@ pub struct DefaultDelegate;
impl Delegate for DefaultDelegate {}


/// A universal result type used as return for all action method results.
pub enum Result<T = ()> {

pub enum Error {
/// The http connection failed
HttpError(hyper::HttpError),

Expand All @@ -240,11 +246,11 @@ pub enum Result<T = ()> {

/// Indicates an HTTP repsonse with a non-success status code
Failure(hyper::client::Response),

/// It worked !
Success(T),
}

/// A universal result type used as return for all calls.
pub type Result<T> = std::result::Result<T, Error>;

/// Contains information about an API request.
pub struct MethodInfo {
pub id: &'static str,
Expand Down Expand Up @@ -499,7 +505,7 @@ impl<'a, NC, A> ResumableUploadHelper<'a, NC, A>
where NC: hyper::net::NetworkConnector,
A: oauth2::GetToken {

fn query_transfer_status(&mut self) -> (Option<u64>, hyper::HttpResult<hyper::client::Response>) {
fn query_transfer_status(&mut self) -> std::result::Result<u64, hyper::HttpResult<hyper::client::Response>> {
loop {
match self.client.post(self.url)
.header(UserAgent(self.user_agent.to_string()))
Expand All @@ -516,17 +522,17 @@ impl<'a, NC, A> ResumableUploadHelper<'a, NC, A>
sleep(d);
continue;
}
return (None, Ok(r))
return Err(Ok(r))
}
};
return (Some(h.0.last), Ok(r))
return Ok(h.0.last)
}
Err(err) => {
if let Retry::After(d) = self.delegate.http_error(&err) {
sleep(d);
continue;
}
return (None, Err(err))
return Err(Err(err))
}
}
}
Expand All @@ -539,8 +545,8 @@ impl<'a, NC, A> ResumableUploadHelper<'a, NC, A>
let mut start = match self.start_at {
Some(s) => s,
None => match self.query_transfer_status() {
(Some(s), _) => s,
(_, result) => return Some(result)
Ok(s) => s,
Err(result) => return Some(result)
}
};

Expand Down
Loading

0 comments on commit cefd606

Please sign in to comment.