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 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/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/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/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/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/helper.rs b/src/helper.rs index 29e606d..31619c0 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -446,8 +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) { - 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 9f43bf3..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; @@ -60,30 +60,11 @@ //! }; //! # } //! ``` -#![feature(custom_derive, plugin)] -#![plugin(serde_macros)] -extern crate chrono; +#![cfg_attr(feature = "nightly", feature(custom_derive, custom_attribute, 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..babb64c --- /dev/null +++ b/src/lib.rs.in @@ -0,0 +1,24 @@ +extern crate serde; + +extern crate chrono; + +extern crate hyper; +#[macro_use] #[cfg(test)] +extern crate log; +#[macro_use] #[cfg(test)] +extern crate yup_hyper_mock; +extern crate mime; +extern crate url; +extern crate time; +extern crate itertools; + +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}; 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() {