From 455a1482d92a26e109ccb0b723136c09bb4eff2e Mon Sep 17 00:00:00 2001 From: softprops Date: Sun, 3 Jan 2016 18:06:21 -0500 Subject: migrate builder interfaces into interfaces that just build options to improve testability --- examples/containers.rs | 8 +--- examples/events.rs | 2 +- examples/info.rs | 2 +- src/builder.rs | 127 +++++++++++++++++++++++++++---------------------- src/lib.rs | 31 ++++++++---- 5 files changed, 97 insertions(+), 73 deletions(-) diff --git a/examples/containers.rs b/examples/containers.rs index e4df6b3..60990a4 100644 --- a/examples/containers.rs +++ b/examples/containers.rs @@ -1,15 +1,11 @@ extern crate shiplift; -use shiplift::{ContainerFilter, Docker}; +use shiplift::Docker; fn main() { let docker = Docker::new(); for c in docker.containers(). - list() - .sized() - .filter(vec![ - ContainerFilter::Label("foo".to_owned(), "bar".to_owned()) - ]).build().unwrap() { + list(&Default::default()).unwrap() { println!("container -> {:?}", c) } } diff --git a/examples/events.rs b/examples/events.rs index 8e70f70..f1518d3 100644 --- a/examples/events.rs +++ b/examples/events.rs @@ -5,7 +5,7 @@ use shiplift::Docker; fn main() { let docker = Docker::new(); println!("listening for events"); - for e in docker.events().build().unwrap() { + for e in docker.events(&Default::default()).unwrap() { println!("event -> {:?}", e) } } diff --git a/examples/info.rs b/examples/info.rs index 85f2128..c3ad9d6 100644 --- a/examples/info.rs +++ b/examples/info.rs @@ -3,6 +3,6 @@ extern crate shiplift; use shiplift::Docker; fn main() { - let mut docker = Docker::new(); + let docker = Docker::new(); println!("info {:?}", docker.info().unwrap()); } diff --git a/src/builder.rs b/src/builder.rs index de83b6a..8df0d12 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -6,18 +6,32 @@ extern crate url; use self::super::{Docker, Result}; use self::super::transport::Body; -use self::super::rep::{ContainerCreateInfo, Event}; -use self::super::rep::Container as ContainerRep; +use self::super::rep::ContainerCreateInfo; use std::collections::{BTreeMap, HashMap}; use rustc_serialize::json::{self, Json, ToJson}; use url::form_urlencoded; -/// Interface for building container list request -pub struct ContainerListBuilder<'a> { - docker: &'a Docker, - params: HashMap<&'static str, String>, +#[derive(Default)] +pub struct ContainerListOptions { + params: HashMap<&'static str, String> } +impl ContainerListOptions { + /// return a new instance of a builder for options + pub fn builder() -> ContainerListOptionsBuilder { + ContainerListOptionsBuilder::new() + } + + /// serialize options as a string. returns None if no options are defined + pub fn serialize(&self) -> Option { + if self.params.is_empty() { None } + else { + Some(form_urlencoded::serialize(&self.params)) + } + } +} + +/// Filter options for container listings pub enum ContainerFilter { ExitCode(u64), Status(String), @@ -25,15 +39,20 @@ pub enum ContainerFilter { Label(String, String) } -impl<'a> ContainerListBuilder<'a> { - pub fn new(docker: &'a Docker) -> ContainerListBuilder<'a> { - ContainerListBuilder { - docker: docker, - params: HashMap::new(), +/// Interface for building container list request +#[derive(Default)] +pub struct ContainerListOptionsBuilder { + params: HashMap<&'static str, String>, +} + +impl ContainerListOptionsBuilder { + pub fn new() -> ContainerListOptionsBuilder { + ContainerListOptionsBuilder { + ..Default::default() } } - pub fn filter(&mut self, filters: Vec) -> &mut ContainerListBuilder<'a> { + pub fn filter(&mut self, filters: Vec) -> &mut ContainerListOptionsBuilder { let mut param = HashMap::new(); for f in filters { match f { @@ -50,34 +69,30 @@ impl<'a> ContainerListBuilder<'a> { self } - pub fn all(&mut self) -> &mut ContainerListBuilder<'a> { + pub fn all(&mut self) -> &mut ContainerListOptionsBuilder { self.params.insert("all", "true".to_owned()); self } - pub fn since(&mut self, since: &str) -> &mut ContainerListBuilder<'a> { + pub fn since(&mut self, since: &str) -> &mut ContainerListOptionsBuilder { self.params.insert("since", since.to_owned()); self } - pub fn before(&mut self, before: &str) -> &mut ContainerListBuilder<'a> { + pub fn before(&mut self, before: &str) -> &mut ContainerListOptionsBuilder { self.params.insert("before", before.to_owned()); self } - pub fn sized(&mut self) -> &mut ContainerListBuilder<'a> { + pub fn sized(&mut self) -> &mut ContainerListOptionsBuilder { self.params.insert("size", "true".to_owned()); self } - pub fn build(&self) -> Result> { - let mut path = vec!["/containers/json".to_owned()]; - if !self.params.is_empty() { - let encoded = form_urlencoded::serialize(&self.params); - path.push(encoded) + pub fn build(&self) -> ContainerListOptions {//Result> { + ContainerListOptions { + params: self.params.clone() } - let raw = try!(self.docker.get(&path.join("?"))); - Ok(try!(json::decode::>(&raw))) } } @@ -124,54 +139,52 @@ impl<'a, 'b> ContainerBuilder<'a, 'b> { } } +#[derive(Default)] +pub struct EventsOptions { + params: HashMap<&'static str, String> +} + +impl EventsOptions { + pub fn builder() -> EventsOptionsBuilder { + EventsOptionsBuilder::new() + } + + pub fn serialize(&self) -> Option { + if self.params.is_empty() { None } + else { + Some(form_urlencoded::serialize(&self.params)) + } + } +} + /// Interface for buiding an events request -pub struct EventsBuilder<'a, 'b, 'c> { - docker: &'a Docker, - since: Option<&'b u64>, - until: Option<&'c u64>, +#[derive(Default)] +pub struct EventsOptionsBuilder { + params: HashMap<&'static str, String> } -impl<'a, 'b, 'c> EventsBuilder<'a, 'b, 'c> { - pub fn new(docker: &'a Docker) -> EventsBuilder<'a, 'b, 'c> { - EventsBuilder { - docker: docker, - since: None, - until: None, +impl EventsOptionsBuilder { + pub fn new() -> EventsOptionsBuilder { + EventsOptionsBuilder { + ..Default::default() } } /// Filter events since a given timestamp - pub fn since(&mut self, ts: &'b u64) -> &mut EventsBuilder<'a, 'b, 'c> { - self.since = Some(ts); + pub fn since(&mut self, ts: &u64) -> &mut EventsOptionsBuilder { + self.params.insert("since", ts.to_string()); self } /// Filter events until a given timestamp - pub fn until(&mut self, ts: &'c u64) -> &mut EventsBuilder<'a, 'b, 'c> { - self.until = Some(ts); + pub fn until(&mut self, ts: &u64) -> &mut EventsOptionsBuilder { + self.params.insert("until", ts.to_string()); self } - /// Returns an interator over streamed docker events - pub fn build(&self) -> Result>> { - let mut params = Vec::new(); - if let Some(s) = self.since { - params.push(("since", s.to_string())); - } - if let Some(u) = self.until { - params.push(("until", u.to_string())); - } - let mut path = vec!["/events".to_owned()]; - if !params.is_empty() { - let encoded = form_urlencoded::serialize(params); - path.push(encoded) + pub fn build(&self) -> EventsOptions { + EventsOptions { + params: self.params.clone() } - let raw = try!(self.docker.stream_get(&path.join("?")[..])); - let it = jed::Iter::new(raw).into_iter().map(|j| { - // fixme: better error handling - let s = json::encode(&j).unwrap(); - json::decode::(&s).unwrap() - }); - Ok(Box::new(it)) } } diff --git a/src/lib.rs b/src/lib.rs index 95743bb..b347a53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,9 +26,9 @@ pub mod transport; pub mod errors; pub use errors::Error; -pub use builder::ContainerFilter; +pub use builder::{ContainerListOptions, ContainerFilter, EventsOptions}; -use builder::{ContainerBuilder, ContainerListBuilder, EventsBuilder}; +use builder::ContainerBuilder; use hyper::{Client, Url}; use hyper::net::{HttpsConnector, Openssl}; use hyper::method::Method; @@ -36,7 +36,7 @@ use hyperlocal::UnixSocketConnector; use openssl::x509::X509FileType; use openssl::ssl::{SslContext, SslMethod}; use rep::Image as ImageRep; -use rep::{Change, ContainerDetails, Exit, History, ImageDetails, Info, SearchResult, Stats, +use rep::{Change, ContainerDetails, Container as ContainerRep, Event, Exit, History, ImageDetails, Info, SearchResult, Stats, Status, Top, Version}; use rustc_serialize::json::{self, Json}; use std::env::{self, VarError}; @@ -283,8 +283,13 @@ impl<'a> Containers<'a> { } /// Lists the container instances on the docker host - pub fn list(&self) -> ContainerListBuilder<'a> { - ContainerListBuilder::new(self.docker) + pub fn list(&self, opts: &ContainerListOptions) -> Result> { + let mut path = vec!["/containers/json".to_owned()]; + if let Some(query) = opts.serialize() { + path.push(query) + } + let raw = try!(self.docker.get(&path.join("?"))); + Ok(try!(json::decode::>(&raw))) } /// Returns a reference to a set of operations available to a specific container instance @@ -395,9 +400,19 @@ impl Docker { self.get("/_ping") } - /// Retruns a stream of events ocurring on the current docker host - pub fn events(&self) -> EventsBuilder { - EventsBuilder::new(self) + /// Returns an interator over streamed docker events + pub fn events(&self, opts: &EventsOptions) -> Result>> { + let mut path = vec!["/events".to_owned()]; + if let Some(query) = opts.serialize() { + path.push(query); + } + let raw = try!(self.stream_get(&path.join("?")[..])); + let it = jed::Iter::new(raw).into_iter().map(|j| { + // fixme: better error handling + let s = json::encode(&j).unwrap(); + json::decode::(&s).unwrap() + }); + Ok(Box::new(it)) } fn get(&self, endpoint: &str) -> Result { -- cgit v1.2.3