From 63ef2b3b66616055535d9ad43253de1df83ab527 Mon Sep 17 00:00:00 2001 From: Marc Schreiber Date: Sat, 14 Sep 2019 11:07:09 +0200 Subject: feat: use chrono to deserialize date times (#190) --- CHANGELOG.md | 4 ++++ Cargo.toml | 3 ++- examples/images.rs | 3 ++- src/builder.rs | 40 ++++++++++++++++++++++++++++++++++++ src/rep.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6320ce4..6809071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.6.0 + +* add chrono as an optional feature [#190](https://github.com/softprops/shiplift/pull/190) + # 0.5.0 * make tls an optional dependency [#130](https://github.com/softprops/shiplift/pull/130) diff --git a/Cargo.toml b/Cargo.toml index 6447b99..81f1c6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ maintenance = { status = "actively-developed" } base64 = "0.10" byteorder = "1.3.1" bytes = "0.4" +chrono = { version = "0.4", optional = true, features = ["serde"] } flate2 = "1.0" futures = "0.1" http = "0.1" @@ -42,6 +43,6 @@ url = "1.7" env_logger = "0.6" [features] -default = ["unix-socket", "tls"] +default = ["chrono", "unix-socket", "tls"] unix-socket = ["hyperlocal"] tls = ["openssl", "hyper-openssl"] diff --git a/examples/images.rs b/examples/images.rs index de04ab9..7a8a094 100644 --- a/examples/images.rs +++ b/examples/images.rs @@ -10,8 +10,9 @@ fn main() { .map(|images| { for i in images { println!( - "{} {:?}", + "{} {} {:?}", i.id, + i.created, i.repo_tags.unwrap_or_else(|| vec!["none".into()]) ); } diff --git a/src/builder.rs b/src/builder.rs index ea9bd32..cb924ac 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1190,6 +1190,20 @@ impl LogsOptionsBuilder { self } + #[cfg(feature = "chrono")] + pub fn since( + &mut self, + timestamp: &chrono::DateTime, + ) -> &mut Self + where + Tz: chrono::TimeZone, + { + self.params + .insert("since", timestamp.timestamp().to_string()); + self + } + + #[cfg(not(feature = "chrono"))] pub fn since( &mut self, timestamp: i64, @@ -1712,6 +1726,32 @@ mod tests { ); } + #[cfg(feature = "chrono")] + #[test] + fn logs_options() { + let timestamp = chrono::NaiveDateTime::from_timestamp(2_147_483_647, 0); + let since = chrono::DateTime::::from_utc(timestamp, chrono::Utc); + + let options = LogsOptionsBuilder::default() + .follow(true) + .stdout(true) + .stderr(true) + .timestamps(true) + .tail("all") + .since(&since) + .build(); + + let serialized = options.serialize().unwrap(); + + assert!(serialized.contains("follow=true")); + assert!(serialized.contains("stdout=true")); + assert!(serialized.contains("stderr=true")); + assert!(serialized.contains("timestamps=true")); + assert!(serialized.contains("tail=all")); + assert!(serialized.contains("since=2147483647")); + } + + #[cfg(not(feature = "chrono"))] #[test] fn logs_options() { let options = LogsOptionsBuilder::default() diff --git a/src/rep.rs b/src/rep.rs index d5771d9..80815da 100644 --- a/src/rep.rs +++ b/src/rep.rs @@ -1,5 +1,7 @@ //! Rust representations of docker json structures +#[cfg(feature = "chrono")] +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -15,6 +17,10 @@ pub struct SearchResult { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Image { + #[cfg(feature = "chrono")] + #[serde(deserialize_with = "datetime_from_unix_timestamp")] + pub created: DateTime, + #[cfg(not(feature = "chrono"))] pub created: u64, pub id: String, pub parent_id: String, @@ -31,6 +37,9 @@ pub struct ImageDetails { pub author: String, pub comment: String, pub config: Config, + #[cfg(feature = "chrono")] + pub created: DateTime, + #[cfg(not(feature = "chrono"))] pub created: String, pub docker_version: String, pub id: String, @@ -43,6 +52,10 @@ pub struct ImageDetails { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Container { + #[cfg(feature = "chrono")] + #[serde(deserialize_with = "datetime_from_unix_timestamp")] + pub created: DateTime, + #[cfg(not(feature = "chrono"))] pub created: u64, pub command: String, pub id: String, @@ -61,6 +74,9 @@ pub struct ContainerDetails { pub app_armor_profile: String, pub args: Vec, pub config: Config, + #[cfg(feature = "chrono")] + pub created: DateTime, + #[cfg(not(feature = "chrono"))] pub created: String, pub driver: String, // pub ExecIDs: ?? @@ -96,6 +112,9 @@ pub struct Mount { pub struct State { pub error: String, pub exit_code: u64, + #[cfg(feature = "chrono")] + pub finished_at: DateTime, + #[cfg(not(feature = "chrono"))] pub finished_at: String, #[serde(rename = "OOMKilled")] pub oom_killed: bool, @@ -103,6 +122,9 @@ pub struct State { pub pid: u64, pub restarting: bool, pub running: bool, + #[cfg(feature = "chrono")] + pub started_at: DateTime, + #[cfg(not(feature = "chrono"))] pub started_at: String, } @@ -420,6 +442,10 @@ pub struct ContainerCreateInfo { #[serde(rename_all = "PascalCase")] pub struct History { pub id: String, + #[cfg(feature = "chrono")] + #[serde(deserialize_with = "datetime_from_unix_timestamp")] + pub created: DateTime, + #[cfg(not(feature = "chrono"))] pub created: u64, pub created_by: String, } @@ -441,7 +467,15 @@ pub struct Event { pub status: Option, pub id: Option, pub from: Option, + #[cfg(feature = "chrono")] + #[serde(deserialize_with = "datetime_from_unix_timestamp")] + pub time: DateTime, + #[cfg(not(feature = "chrono"))] pub time: u64, + #[cfg(feature = "chrono")] + #[serde(deserialize_with = "datetime_from_nano_timestamp", rename = "timeNano")] + pub time_nano: DateTime, + #[cfg(not(feature = "chrono"))] #[serde(rename = "timeNano")] pub time_nano: u64, } @@ -476,6 +510,9 @@ pub struct Volumes { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Volume { + #[cfg(feature = "chrono")] + pub created_at: DateTime, + #[cfg(not(feature = "chrono"))] pub created_at: String, pub driver: String, pub labels: Option>, @@ -484,3 +521,25 @@ pub struct Volume { pub options: Option>, pub scope: String, } + +#[cfg(feature = "chrono")] +fn datetime_from_unix_timestamp<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let timestamp = chrono::NaiveDateTime::from_timestamp(i64::deserialize(deserializer)?, 0); + Ok(DateTime::::from_utc(timestamp, Utc)) +} + +#[cfg(feature = "chrono")] +fn datetime_from_nano_timestamp<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let timestamp_nano = u64::deserialize(deserializer)?; + let timestamp = chrono::NaiveDateTime::from_timestamp( + (timestamp_nano / 1_000_000_000) as i64, + (timestamp_nano % 1_000_000_000) as u32, + ); + Ok(DateTime::::from_utc(timestamp, Utc)) +} -- cgit v1.2.3