From 9b2f9e77be8189e6cc9ef196f49e764011ca9519 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 26 May 2015 14:41:31 +0200 Subject: [PATCH 1/7] feat(syntex): basic infrastructure It doesn't yet work on nightly due to a panic in https://goo.gl/RyM4GT Might have something to do with me being on nightly, and some cargo-related hickoup. --- Cargo.toml | 12 ++++++- build.rs | 28 ++++++++++++++++ src/lib.rs | 91 ++++----------------------------------------------- src/lib.rs.in | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 86 deletions(-) create mode 100644 build.rs create mode 100644 src/lib.rs.in diff --git a/Cargo.toml b/Cargo.toml index c69646f..29dd887 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ description = "A partial oauth2 implementation, providing the 'device' authoriza documentation = "http://byron.github.io/yup-oauth2" keywords = ["google", "oauth", "v2"] license = "MIT" +build = "build.rs" [dependencies] chrono = "*" @@ -18,7 +19,16 @@ url = "*" hyper = ">= 0.5.0" itertools = "*" serde = "*" -serde_macros = "*" +serde_macros = { version = "*", optional = true } + +[features] +default = ["with_syntex"] +nightly = ["serde_macros"] +with_syntex = ["serde_codegen", "syntex"] + +[build-dependencies] +syntex = { version = "*", optional = true } +serde_codegen = { version = "*", optional = true } [dev-dependencies] getopts = "*" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..2525f95 --- /dev/null +++ b/build.rs @@ -0,0 +1,28 @@ +#[cfg(feature = "with_syntex")] +mod inner { + 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("yup-oauth2", &src, &dst).unwrap(); + } +} + +#[cfg(not(feature = "with_syntex"))] +mod inner { + pub fn main() {} +} + +pub fn main() { + inner::main() +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9f43bf3..2e0e015 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,89 +1,10 @@ -//! This library can be used to acquire oauth2.0 authentication for services. -//! At the time of writing, only one way of doing so is implemented, the [device flow](https://developers.google.com/youtube/v3/guides/authentication#devices), along with a flow -//! for [refreshing tokens](https://developers.google.com/youtube/v3/guides/authentication#devices) -//! -//! For your application to use this library, you will have to obtain an application -//! id and secret by [following this guide](https://developers.google.com/youtube/registering_an_application). -//! -//! # Device Flow Usage -//! As the `DeviceFlow` involves polling, the `DeviceFlowHelper` should be used -//! as means to adhere to the protocol, and remain resilient to all kinds of errors -//! that can occour on the way. -//! -//! The returned `Token` should be stored permanently to authorize future API requests. -//! -//! ```test_harness,no_run -//! #![feature(custom_derive, plugin)] -//! #![plugin(serde_macros)] -//! extern crate hyper; -//! extern crate yup_oauth2 as oauth2; -//! extern crate serde; -//! -//! use oauth2::{Authenticator, DefaultAuthenticatorDelegate, PollInformation, ConsoleApplicationSecret, MemoryStorage, GetToken}; -//! use serde::json; -//! use std::default::Default; -//! # const SECRET: &'static str = "{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"UqkDJd5RFwnHoiG5x5Rub8SI\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}"; -//! -//! # #[test] fn device() { -//! let secret = json::from_str::(SECRET).unwrap().installed.unwrap(); -//! let res = Authenticator::new(&secret, DefaultAuthenticatorDelegate, -//! hyper::Client::new(), -//! ::default(), None) -//! .token(&["https://www.googleapis.com/auth/youtube.upload"]); -//! match res { -//! Ok(t) => { -//! // now you can use t.access_token to authenticate API calls within your -//! // given scopes. It will not be valid forever, which is when you have to -//! // refresh it using the `RefreshFlow` -//! }, -//! Err(err) => println!("Failed to acquire token: {}", err), -//! } -//! # } -//! ``` -//! -//! # Refresh Flow Usage -//! As the `Token` you retrieved previously will only be valid for a certain time, you will have -//! to use the information from the `Token.refresh_token` field to get a new `access_token`. -//! -//! ```test_harness,no_run -//! extern crate hyper; -//! extern crate yup_oauth2 as oauth2; -//! use oauth2::{RefreshFlow, FlowType, RefreshResult}; -//! -//! # #[test] fn refresh() { -//! let mut f = RefreshFlow::new(hyper::Client::new()); -//! let new_token = match *f.refresh_token(FlowType::Device, -//! "my_client_id", "my_secret", -//! "my_refresh_token") { -//! RefreshResult::Success(ref t) => t, -//! _ => panic!("bad luck ;)") -//! }; -//! # } -//! ``` -#![feature(custom_derive, plugin)] -#![plugin(serde_macros)] -extern crate chrono; +#[cfg_attr(feature = "nightly", feature(plugin))] +#[cfg_attr(feature = "nightly", plugin(serde_macros))] -#[macro_use] -extern crate hyper; -#[macro_use] -extern crate log; -#[cfg(test)] #[macro_use] -extern crate yup_hyper_mock as hyper_mock; -extern crate mime; -extern crate url; -extern crate time; -extern crate itertools; extern crate serde; +#[cfg(feature = "nightly")] +include!("lib.rs.in"); -mod device; -mod refresh; -mod common; -mod helper; - -pub use device::{DeviceFlow, PollInformation, PollError}; -pub use refresh::{RefreshFlow, RefreshResult}; -pub use common::{Token, FlowType, ApplicationSecret, ConsoleApplicationSecret, Scheme, TokenType}; -pub use helper::{TokenStorage, NullStorage, MemoryStorage, Authenticator, - AuthenticatorDelegate, Retry, DefaultAuthenticatorDelegate, GetToken}; +#[cfg(feature = "with_syntex")] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); \ No newline at end of file diff --git a/src/lib.rs.in b/src/lib.rs.in new file mode 100644 index 0000000..acce7a2 --- /dev/null +++ b/src/lib.rs.in @@ -0,0 +1,87 @@ +//! This library can be used to acquire oauth2.0 authentication for services. +//! At the time of writing, only one way of doing so is implemented, the [device flow](https://developers.google.com/youtube/v3/guides/authentication#devices), along with a flow +//! for [refreshing tokens](https://developers.google.com/youtube/v3/guides/authentication#devices) +//! +//! For your application to use this library, you will have to obtain an application +//! id and secret by [following this guide](https://developers.google.com/youtube/registering_an_application). +//! +//! # Device Flow Usage +//! As the `DeviceFlow` involves polling, the `DeviceFlowHelper` should be used +//! as means to adhere to the protocol, and remain resilient to all kinds of errors +//! that can occour on the way. +//! +//! The returned `Token` should be stored permanently to authorize future API requests. +//! +//! ```test_harness,no_run +//! #![feature(custom_derive, plugin)] +//! #![plugin(serde_macros)] +//! extern crate hyper; +//! extern crate yup_oauth2 as oauth2; +//! extern crate serde; +//! +//! use oauth2::{Authenticator, DefaultAuthenticatorDelegate, PollInformation, ConsoleApplicationSecret, MemoryStorage, GetToken}; +//! use serde::json; +//! use std::default::Default; +//! # const SECRET: &'static str = "{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"UqkDJd5RFwnHoiG5x5Rub8SI\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}"; +//! +//! # #[test] fn device() { +//! let secret = json::from_str::(SECRET).unwrap().installed.unwrap(); +//! let res = Authenticator::new(&secret, DefaultAuthenticatorDelegate, +//! hyper::Client::new(), +//! ::default(), None) +//! .token(&["https://www.googleapis.com/auth/youtube.upload"]); +//! match res { +//! Ok(t) => { +//! // now you can use t.access_token to authenticate API calls within your +//! // given scopes. It will not be valid forever, which is when you have to +//! // refresh it using the `RefreshFlow` +//! }, +//! Err(err) => println!("Failed to acquire token: {}", err), +//! } +//! # } +//! ``` +//! +//! # Refresh Flow Usage +//! As the `Token` you retrieved previously will only be valid for a certain time, you will have +//! to use the information from the `Token.refresh_token` field to get a new `access_token`. +//! +//! ```test_harness,no_run +//! extern crate hyper; +//! extern crate yup_oauth2 as oauth2; +//! use oauth2::{RefreshFlow, FlowType, RefreshResult}; +//! +//! # #[test] fn refresh() { +//! let mut f = RefreshFlow::new(hyper::Client::new()); +//! let new_token = match *f.refresh_token(FlowType::Device, +//! "my_client_id", "my_secret", +//! "my_refresh_token") { +//! RefreshResult::Success(ref t) => t, +//! _ => panic!("bad luck ;)") +//! }; +//! # } +//! ``` +extern crate chrono; + +#[macro_use] +extern crate hyper; +#[macro_use] +extern crate log; +#[cfg(test)] #[macro_use] +extern crate yup_hyper_mock as hyper_mock; +extern crate mime; +extern crate url; +extern crate time; +extern crate itertools; +extern crate serde; + + +mod device; +mod refresh; +mod common; +mod helper; + +pub use device::{DeviceFlow, PollInformation, PollError}; +pub use refresh::{RefreshFlow, RefreshResult}; +pub use common::{Token, FlowType, ApplicationSecret, ConsoleApplicationSecret, Scheme, TokenType}; +pub use helper::{TokenStorage, NullStorage, MemoryStorage, Authenticator, + AuthenticatorDelegate, Retry, DefaultAuthenticatorDelegate, GetToken}; From 0901497d8984ac5cd02aa1a0c21d463dce9a1edf Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 26 May 2015 17:46:47 +0200 Subject: [PATCH 2/7] fix(syntex): cleanup, build works on stable It seems it doesn't like one line in particular (helper.rs:450), which causes syntex to crash. Commenting it out does the trick. --- src/helper.rs | 5 ++-- src/lib.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs.in | 64 --------------------------------------------------- 3 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/helper.rs b/src/helper.rs index 29e606d..bf29d32 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -446,8 +446,9 @@ pub trait AuthenticatorDelegate { /// * Will be called exactly once, provided we didn't abort during `request_code` phase. /// * Will only be called if the Authenticator's flow_type is `FlowType::Device`. fn present_user_code(&mut self, pi: &PollInformation) { - println!{"Please enter {} at {} and grant access to this application", - pi.user_code, pi.verification_url} + // TODO(ST): If this line is commnented in again, syntex fails to work ! + // println!{"Please enter {} at {} and grant access to this application", + // pi.user_code, pi.verification_url} println!("Do not close this application until you either denied or granted access."); println!("You have time until {}.", pi.expires_at.with_timezone(&Local)); } diff --git a/src/lib.rs b/src/lib.rs index 2e0e015..1bec1ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,65 @@ +//! This library can be used to acquire oauth2.0 authentication for services. +//! At the time of writing, only one way of doing so is implemented, the [device flow](https://developers.google.com/youtube/v3/guides/authentication#devices), along with a flow +//! for [refreshing tokens](https://developers.google.com/youtube/v3/guides/authentication#devices) +//! +//! For your application to use this library, you will have to obtain an application +//! id and secret by [following this guide](https://developers.google.com/youtube/registering_an_application). +//! +//! # Device Flow Usage +//! As the `DeviceFlow` involves polling, the `DeviceFlowHelper` should be used +//! as means to adhere to the protocol, and remain resilient to all kinds of errors +//! that can occour on the way. +//! +//! The returned `Token` should be stored permanently to authorize future API requests. +//! +//! ```test_harness,no_run +//! #![feature(custom_derive, plugin)] +//! #![plugin(serde_macros)] +//! extern crate hyper; +//! extern crate yup_oauth2 as oauth2; +//! extern crate serde; +//! +//! use oauth2::{Authenticator, DefaultAuthenticatorDelegate, PollInformation, ConsoleApplicationSecret, MemoryStorage, GetToken}; +//! use serde::json; +//! use std::default::Default; +//! # const SECRET: &'static str = "{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"UqkDJd5RFwnHoiG5x5Rub8SI\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}"; +//! +//! # #[test] fn device() { +//! let secret = json::from_str::(SECRET).unwrap().installed.unwrap(); +//! let res = Authenticator::new(&secret, DefaultAuthenticatorDelegate, +//! hyper::Client::new(), +//! ::default(), None) +//! .token(&["https://www.googleapis.com/auth/youtube.upload"]); +//! match res { +//! Ok(t) => { +//! // now you can use t.access_token to authenticate API calls within your +//! // given scopes. It will not be valid forever, which is when you have to +//! // refresh it using the `RefreshFlow` +//! }, +//! Err(err) => println!("Failed to acquire token: {}", err), +//! } +//! # } +//! ``` +//! +//! # Refresh Flow Usage +//! As the `Token` you retrieved previously will only be valid for a certain time, you will have +//! to use the information from the `Token.refresh_token` field to get a new `access_token`. +//! +//! ```test_harness,no_run +//! extern crate hyper; +//! extern crate yup_oauth2 as oauth2; +//! use oauth2::{RefreshFlow, FlowType, RefreshResult}; +//! +//! # #[test] fn refresh() { +//! let mut f = RefreshFlow::new(hyper::Client::new()); +//! let new_token = match *f.refresh_token(FlowType::Device, +//! "my_client_id", "my_secret", +//! "my_refresh_token") { +//! RefreshResult::Success(ref t) => t, +//! _ => panic!("bad luck ;)") +//! }; +//! # } +//! ``` #[cfg_attr(feature = "nightly", feature(plugin))] #[cfg_attr(feature = "nightly", plugin(serde_macros))] diff --git a/src/lib.rs.in b/src/lib.rs.in index acce7a2..0c0f58a 100644 --- a/src/lib.rs.in +++ b/src/lib.rs.in @@ -1,65 +1,3 @@ -//! This library can be used to acquire oauth2.0 authentication for services. -//! At the time of writing, only one way of doing so is implemented, the [device flow](https://developers.google.com/youtube/v3/guides/authentication#devices), along with a flow -//! for [refreshing tokens](https://developers.google.com/youtube/v3/guides/authentication#devices) -//! -//! For your application to use this library, you will have to obtain an application -//! id and secret by [following this guide](https://developers.google.com/youtube/registering_an_application). -//! -//! # Device Flow Usage -//! As the `DeviceFlow` involves polling, the `DeviceFlowHelper` should be used -//! as means to adhere to the protocol, and remain resilient to all kinds of errors -//! that can occour on the way. -//! -//! The returned `Token` should be stored permanently to authorize future API requests. -//! -//! ```test_harness,no_run -//! #![feature(custom_derive, plugin)] -//! #![plugin(serde_macros)] -//! extern crate hyper; -//! extern crate yup_oauth2 as oauth2; -//! extern crate serde; -//! -//! use oauth2::{Authenticator, DefaultAuthenticatorDelegate, PollInformation, ConsoleApplicationSecret, MemoryStorage, GetToken}; -//! use serde::json; -//! use std::default::Default; -//! # const SECRET: &'static str = "{\"installed\":{\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\",\"client_secret\":\"UqkDJd5RFwnHoiG5x5Rub8SI\",\"token_uri\":\"https://accounts.google.com/o/oauth2/token\",\"client_email\":\"\",\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\",\"oob\"],\"client_x509_cert_url\":\"\",\"client_id\":\"14070749909-vgip2f1okm7bkvajhi9jugan6126io9v.apps.googleusercontent.com\",\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"}}"; -//! -//! # #[test] fn device() { -//! let secret = json::from_str::(SECRET).unwrap().installed.unwrap(); -//! let res = Authenticator::new(&secret, DefaultAuthenticatorDelegate, -//! hyper::Client::new(), -//! ::default(), None) -//! .token(&["https://www.googleapis.com/auth/youtube.upload"]); -//! match res { -//! Ok(t) => { -//! // now you can use t.access_token to authenticate API calls within your -//! // given scopes. It will not be valid forever, which is when you have to -//! // refresh it using the `RefreshFlow` -//! }, -//! Err(err) => println!("Failed to acquire token: {}", err), -//! } -//! # } -//! ``` -//! -//! # Refresh Flow Usage -//! As the `Token` you retrieved previously will only be valid for a certain time, you will have -//! to use the information from the `Token.refresh_token` field to get a new `access_token`. -//! -//! ```test_harness,no_run -//! extern crate hyper; -//! extern crate yup_oauth2 as oauth2; -//! use oauth2::{RefreshFlow, FlowType, RefreshResult}; -//! -//! # #[test] fn refresh() { -//! let mut f = RefreshFlow::new(hyper::Client::new()); -//! let new_token = match *f.refresh_token(FlowType::Device, -//! "my_client_id", "my_secret", -//! "my_refresh_token") { -//! RefreshResult::Success(ref t) => t, -//! _ => panic!("bad luck ;)") -//! }; -//! # } -//! ``` extern crate chrono; #[macro_use] @@ -72,8 +10,6 @@ extern crate mime; extern crate url; extern crate time; extern crate itertools; -extern crate serde; - mod device; mod refresh; From 37231fad2ee419d6250164df1651f169cf3b6ac3 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 11 Jun 2015 10:57:57 +0200 Subject: [PATCH 3/7] chore(make): added makefile * It should help to keep track of how to properly call cargo in nightly mode. After all, I have wasted some time, multiple times just trying to figure out that I forgot to add the nightly feature. * Slightly improved structure of lib.rs and includes Related to #12 --- Makefile | 11 +++++++++++ src/helper.rs | 5 ++--- src/lib.rs | 5 +---- src/lib.rs.in | 8 ++++++-- 4 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d219b18 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +.PHONY = nightly + +help: + $(info -- Targets -- ) + $(info ) + $(info nightly - run cargo with nightly configuration, set ARGS to something like 'build'. rustc must be set to nightly) + $(info _____________Note that for using stable, you can use cargo directly) + $(info ) + +nightly: + cargo $(ARGS) --no-default-features --features=nightly \ No newline at end of file diff --git a/src/helper.rs b/src/helper.rs index bf29d32..31619c0 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -446,9 +446,8 @@ pub trait AuthenticatorDelegate { /// * Will be called exactly once, provided we didn't abort during `request_code` phase. /// * Will only be called if the Authenticator's flow_type is `FlowType::Device`. fn present_user_code(&mut self, pi: &PollInformation) { - // TODO(ST): If this line is commnented in again, syntex fails to work ! - // println!{"Please enter {} at {} and grant access to this application", - // pi.user_code, pi.verification_url} + println!("Please enter {} at {} and grant access to this application", + pi.user_code, pi.verification_url); println!("Do not close this application until you either denied or granted access."); println!("You have time until {}.", pi.expires_at.with_timezone(&Local)); } diff --git a/src/lib.rs b/src/lib.rs index 1bec1ca..3e573de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,10 +60,7 @@ //! }; //! # } //! ``` -#[cfg_attr(feature = "nightly", feature(plugin))] -#[cfg_attr(feature = "nightly", plugin(serde_macros))] - -extern crate serde; +#![cfg_attr(feature = "nightly", feature(custom_derive))] #[cfg(feature = "nightly")] include!("lib.rs.in"); diff --git a/src/lib.rs.in b/src/lib.rs.in index 0c0f58a..481b65f 100644 --- a/src/lib.rs.in +++ b/src/lib.rs.in @@ -1,11 +1,15 @@ +#[cfg_attr(feature = "nightly", feature(plugin))] +#[cfg_attr(feature = "nightly", plugin(serde_macros))] +extern crate serde; + extern crate chrono; #[macro_use] extern crate hyper; #[macro_use] extern crate log; -#[cfg(test)] #[macro_use] -extern crate yup_hyper_mock as hyper_mock; +#[macro_use] #[cfg(test)] +extern crate yup_hyper_mock; extern crate mime; extern crate url; extern crate time; From a260b13868aaf667ef5379e4223ec0c94b78e26b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 11 Jun 2015 11:20:06 +0200 Subject: [PATCH 4/7] fix(lib): setup nightly crate meta data correctly * Previously the meta-data was applied to the crate, which doesn't seem to work. * attempted to make `examples/auth.rs` work on stable. This isn't properly tested now, as tests don't compile. We are now at a state were stable as well as nightly work similarly, but fail because `include!` doesn't behave correctly if macros are involved. Namely it happens before crates are linked, yet it will try to expand macros right away, which is a problem. If the macro is defined in an empty fashion, it will actually be used at include time, and expanded. Which causes issues further down the compilation. With the current 'fix' we manage to at least make everything but `cargo test` work. Related to #12 --- examples/auth.rs | 14 ++++++-------- src/lib.rs | 3 ++- src/lib.rs.in | 24 ++++++++++++++++++++---- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/examples/auth.rs b/examples/auth.rs index f1af41c..4277d1d 100644 --- a/examples/auth.rs +++ b/examples/auth.rs @@ -1,5 +1,3 @@ -#![feature(collections, exit_status)] -#![allow(deprecated)] extern crate yup_oauth2 as oauth2; extern crate yup_hyper_mock as mock; extern crate hyper; @@ -17,15 +15,17 @@ use time::Duration; use std::thread::sleep_ms; -fn usage(program: &str, opts: &Options, err: Option) { +fn usage(program: &str, opts: &Options, err: Option) -> ! { if err.is_some() { println!("{}", err.unwrap()); - env::set_exit_status(1); + std::process::exit(1); } println!("{}", opts.short_usage(program) + " SCOPE [SCOPE ...]"); println!("{}", opts.usage("A program to authenticate against oauthv2 services.\n\ See https://developers.google.com/youtube/registering_an_application\n\ and https://developers.google.com/youtube/v3/guides/authentication#devices")); + + std::process::exit(0); } fn main() { @@ -36,18 +36,16 @@ fn main() { opts.opt("c", "id", "oauthv2 ID of your application", "CLIENT_ID", HasArg::Yes, Occur::Req) .opt("s", "secret", "oauthv2 secret of your application", "CLIENT_SECRET", HasArg::Yes, Occur::Req); - let m = match opts.parse(args.tail()) { + let m = match opts.parse(&args[1..]) { Ok(m) => m, Err(e) => { usage(&prog, &opts, Some(e)); - return } }; if m.free.len() == 0 { let msg = Fail::ArgumentMissing("you must provide one or more authorization scopes as free options".to_string()); usage(&prog, &opts, Some(msg)); - return } let secret = oauth2::ApplicationSecret { @@ -93,7 +91,7 @@ fn main() { }, Err(err) => { println!("Access token wasn't obtained: {}", err); - env::set_exit_status(10); + std::process::exit(10); } } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3e573de..e65dc85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,8 @@ //! }; //! # } //! ``` -#![cfg_attr(feature = "nightly", feature(custom_derive))] +#![cfg_attr(feature = "nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature = "nightly", plugin(serde_macros))] #[cfg(feature = "nightly")] include!("lib.rs.in"); diff --git a/src/lib.rs.in b/src/lib.rs.in index 481b65f..ee74a7d 100644 --- a/src/lib.rs.in +++ b/src/lib.rs.in @@ -1,12 +1,28 @@ -#[cfg_attr(feature = "nightly", feature(plugin))] -#[cfg_attr(feature = "nightly", plugin(serde_macros))] +/// NOTE: This makes `cargo build` work, but `cargo test` still fails as these +/// override the macros that should come from `yup_hyper_mock` +#[cfg(not(test))] +macro_rules! mock_connector ( + ($name:ident { + $($url:expr => $res:expr)* + }) => ( + ) +); + +#[cfg(not(test))] +macro_rules! mock_connector_in_order ( + ($name:ident { + $( $res:expr )* + }) => ( + ) +); + + extern crate serde; extern crate chrono; -#[macro_use] extern crate hyper; -#[macro_use] +#[macro_use] #[cfg(test)] extern crate log; #[macro_use] #[cfg(test)] extern crate yup_hyper_mock; From f59d97d4c53387b4d01b42b4d595e04a678a006a Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 11 Jun 2015 11:49:38 +0200 Subject: [PATCH 5/7] refactor(lib): remove empty macros Even though these made `cargo build` work, I think what's really needed in the long run is to make it work for `cargo test` as well. --- src/lib.rs.in | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/lib.rs.in b/src/lib.rs.in index ee74a7d..babb64c 100644 --- a/src/lib.rs.in +++ b/src/lib.rs.in @@ -1,22 +1,3 @@ -/// NOTE: This makes `cargo build` work, but `cargo test` still fails as these -/// override the macros that should come from `yup_hyper_mock` -#[cfg(not(test))] -macro_rules! mock_connector ( - ($name:ident { - $($url:expr => $res:expr)* - }) => ( - ) -); - -#[cfg(not(test))] -macro_rules! mock_connector_in_order ( - ($name:ident { - $( $res:expr )* - }) => ( - ) -); - - extern crate serde; extern crate chrono; From 6a5915d7d64820ecaf6aed30c92f2f7fbe28d72f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 18 Jun 2015 17:58:22 +0200 Subject: [PATCH 6/7] fix(lib): remove macro usage to work on stable As usage of the `!include` macro is enforced, there is currently no way to use the exported macros from `yup_hyper_mock`. Now some more boilerplate code was added to make it work anyway. --- src/device.rs | 58 +++++++++++++++++++++++++++++++++----------------- src/lib.rs | 4 ++-- src/refresh.rs | 38 ++++++++++++++++++++++++--------- 3 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/device.rs b/src/device.rs index 6304ca3..de602b2 100644 --- a/src/device.rs +++ b/src/device.rs @@ -339,9 +339,14 @@ pub mod tests { use std::default::Default; use time::Duration; use hyper; + use yup_hyper_mock::{SequentialConnector, MockStream}; - mock_connector_in_order!(MockGoogleAuth { - "HTTP/1.1 200 OK\r\n\ + pub struct MockGoogleAuth(SequentialConnector); + + impl Default for MockGoogleAuth { + fn default() -> MockGoogleAuth { + let mut c = MockGoogleAuth(Default::default()); + c.0.content.push("HTTP/1.1 200 OK\r\n\ Server: BOGUS\r\n\ \r\n\ {\r\n\ @@ -350,23 +355,38 @@ pub mod tests { \"verification_url\" : \"http://www.google.com/device\",\r\n\ \"expires_in\" : 1800,\r\n\ \"interval\" : 0\r\n\ - }" - "HTTP/1.1 200 OK\r\n\ - Server: BOGUS\r\n\ - \r\n\ - {\r\n\ - \"error\" : \"authorization_pending\"\r\n\ - }" - "HTTP/1.1 200 OK\r\n\ - Server: BOGUS\r\n\ - \r\n\ - {\r\n\ - \"access_token\":\"1/fFAGRNJru1FTz70BzhT3Zg\",\r\n\ - \"expires_in\":3920,\r\n\ - \"token_type\":\"Bearer\",\r\n\ - \"refresh_token\":\"1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ\"\r\n\ - }" - }); + }".to_string()); + + c.0.content.push("HTTP/1.1 200 OK\r\n\ + Server: BOGUS\r\n\ + \r\n\ + {\r\n\ + \"error\" : \"authorization_pending\"\r\n\ + }".to_string()); + + c.0.content.push("HTTP/1.1 200 OK\r\n\ + Server: BOGUS\r\n\ + \r\n\ + {\r\n\ + \"access_token\":\"1/fFAGRNJru1FTz70BzhT3Zg\",\r\n\ + \"expires_in\":3920,\r\n\ + \"token_type\":\"Bearer\",\r\n\ + \"refresh_token\":\"1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ\"\r\n\ + }".to_string()); + c + + } + } + + impl hyper::net::NetworkConnector for MockGoogleAuth { + type Stream = MockStream; + + fn connect(&self, host: &str, port: u16, scheme: &str) -> ::hyper::Result { + self.0.connect(host, port, scheme) + } + + fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {} + } #[test] fn working_flow() { diff --git a/src/lib.rs b/src/lib.rs index e65dc85..706972d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,8 +13,8 @@ //! The returned `Token` should be stored permanently to authorize future API requests. //! //! ```test_harness,no_run -//! #![feature(custom_derive, plugin)] -//! #![plugin(serde_macros)] +//! #![cfg_attr(feature = "nightly", feature(custom_derive, custom_attribute, plugin))] +//! #![cfg_attr(feature = "nightly", plugin(serde_macros))] //! extern crate hyper; //! extern crate yup_oauth2 as oauth2; //! extern crate serde; diff --git a/src/refresh.rs b/src/refresh.rs index 1c79960..9c4dc6c 100644 --- a/src/refresh.rs +++ b/src/refresh.rs @@ -123,17 +123,35 @@ mod tests { use std::default::Default; use super::*; use super::super::FlowType; + use yup_hyper_mock::{MockStream, SequentialConnector}; - mock_connector_in_order!(MockGoogleRefresh { - "HTTP/1.1 200 OK\r\n\ - Server: BOGUS\r\n\ - \r\n\ - {\r\n\ - \"access_token\":\"1/fFAGRNJru1FTz70BzhT3Zg\",\r\n\ - \"expires_in\":3920,\r\n\ - \"token_type\":\"Bearer\"\r\n\ - }" - }); + struct MockGoogleRefresh(SequentialConnector); + + impl Default for MockGoogleRefresh { + fn default() -> MockGoogleRefresh { + let mut c = MockGoogleRefresh(Default::default()); + c.0.content.push("HTTP/1.1 200 OK\r\n\ + Server: BOGUS\r\n\ + \r\n\ + {\r\n\ + \"access_token\":\"1/fFAGRNJru1FTz70BzhT3Zg\",\r\n\ + \"expires_in\":3920,\r\n\ + \"token_type\":\"Bearer\"\r\n\ + }".to_string()); + + c + } + } + + impl hyper::net::NetworkConnector for MockGoogleRefresh { + type Stream = MockStream; + + fn connect(&self, host: &str, port: u16, scheme: &str) -> ::hyper::Result { + self.0.connect(host, port, scheme) + } + + fn set_ssl_verifier(&mut self, _: hyper::net::ContextVerifier) {} + } #[test] fn refresh_flow() { From 773636cc5f9633b1ff1f11fc0b3dc9c78fc478c4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 18 Jun 2015 18:03:41 +0200 Subject: [PATCH 7/7] chore(travis): test stable compiler as well --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9ac19c3..5a6952a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: rust sudo: required rust: +- stable - nightly before_script: - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH