Skip to content

Commit bdaf33b

Browse files
authored
Mostly switch to chrono (#781)
Most of the stuff can be switched to chrono, but iron-related timeouts require time and won't be able to be removed until iron is.
1 parent c869379 commit bdaf33b

22 files changed

+188
-124
lines changed

Diff for: Cargo.lock

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ log = "0.4"
1313
regex = "1"
1414
structopt = "0.3"
1515
crates-index-diff = "7"
16-
time = "0.1"
1716
reqwest = "0.9"
1817
semver = "0.9"
1918
slug = "=0.1.1"
@@ -59,6 +58,10 @@ tera = { version = "1.3.0", features = ["builtins"] }
5958
arc-swap = "0.4.6"
6059
notify = "4.0.15"
6160

61+
# Date and Time utilities
62+
chrono = { version = "0.4.11", features = ["serde"] }
63+
time = "0.1" # TODO: Remove once `iron` is removed
64+
6265
[target.'cfg(not(windows))'.dependencies]
6366
libc = "0.2"
6467

@@ -70,7 +73,7 @@ path-slash = "0.1.1"
7073

7174
[dependencies.postgres]
7275
version = "0.15"
73-
features = ["with-time", "with-serde_json"]
76+
features = ["with-chrono", "with-serde_json"]
7477

7578
[dev-dependencies]
7679
once_cell = "1.2.0"

Diff for: src/db/add_package.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub(crate) fn add_package_into_database(
8585
&[
8686
&crate_id,
8787
&metadata_pkg.version,
88-
&cratesio_data.release_time,
88+
&cratesio_data.release_time.naive_utc(),
8989
&serde_json::to_value(&dependencies)?,
9090
&metadata_pkg.package_name(),
9191
&cratesio_data.yanked,

Diff for: src/db/file.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::path::{Path, PathBuf};
1313

1414
pub(crate) use crate::storage::Blob;
1515

16-
pub(crate) fn get_path(conn: &Connection, path: &str) -> Option<Blob> {
17-
Storage::new(conn).get(path).ok()
16+
pub(crate) fn get_path(conn: &Connection, path: &str) -> Result<Blob> {
17+
Storage::new(conn).get(path)
1818
}
1919

2020
/// Store all files in a directory and return [[mimetype, filename]] as Json

Diff for: src/index/api.rs

+15-17
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
use std::io::Read;
2-
31
use crate::{error::Result, utils::MetadataPackage};
4-
2+
use chrono::{DateTime, Utc};
53
use failure::err_msg;
64
use reqwest::{header::ACCEPT, Client};
5+
use semver::Version;
76
use serde_json::Value;
8-
use time::Timespec;
7+
use std::io::Read;
98

109
pub(crate) struct RegistryCrateData {
11-
pub(crate) release_time: Timespec,
10+
pub(crate) release_time: DateTime<Utc>,
1211
pub(crate) yanked: bool,
1312
pub(crate) downloads: i32,
1413
pub(crate) owners: Vec<CrateOwner>,
@@ -36,18 +35,17 @@ impl RegistryCrateData {
3635
}
3736

3837
/// Get release_time, yanked and downloads from the registry's API
39-
fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(time::Timespec, bool, i32)> {
38+
fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(DateTime<Utc>, bool, i32)> {
4039
let url = format!("https://crates.io/api/v1/crates/{}/versions", pkg.name);
4140
// FIXME: There is probably better way to do this
4241
// and so many unwraps...
4342
let client = Client::new();
44-
let mut res = client
45-
.get(&url[..])
46-
.header(ACCEPT, "application/json")
47-
.send()?;
43+
let mut res = client.get(&url).header(ACCEPT, "application/json").send()?;
44+
4845
let mut body = String::new();
49-
res.read_to_string(&mut body).unwrap();
50-
let json: Value = serde_json::from_str(&body[..])?;
46+
res.read_to_string(&mut body)?;
47+
48+
let json: Value = serde_json::from_str(&body)?;
5149
let versions = json
5250
.as_object()
5351
.and_then(|o| o.get("versions"))
@@ -65,15 +63,15 @@ fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(time::Tim
6563
.and_then(|v| v.as_str())
6664
.ok_or_else(|| err_msg("Not a JSON object"))?;
6765

68-
if semver::Version::parse(version_num).unwrap().to_string() == pkg.version {
66+
if Version::parse(version_num)?.to_string() == pkg.version {
6967
let release_time_raw = version
7068
.get("created_at")
7169
.and_then(|c| c.as_str())
7270
.ok_or_else(|| err_msg("Not a JSON object"))?;
71+
7372
release_time = Some(
74-
time::strptime(release_time_raw, "%Y-%m-%dT%H:%M:%S")
75-
.unwrap()
76-
.to_timespec(),
73+
DateTime::parse_from_str(release_time_raw, "%Y-%m-%dT%H:%M:%S%.f%:z")?
74+
.with_timezone(&Utc),
7775
);
7876

7977
yanked = Some(
@@ -95,7 +93,7 @@ fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(time::Tim
9593
}
9694

9795
Ok((
98-
release_time.unwrap_or_else(time::get_time),
96+
release_time.unwrap_or_else(Utc::now),
9997
yanked.unwrap_or(false),
10098
downloads.unwrap_or(0),
10199
))

Diff for: src/storage/database.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::Blob;
2+
use chrono::{DateTime, NaiveDateTime, Utc};
23
use failure::{Error, Fail};
34
use postgres::{transaction::Transaction, Connection};
45

@@ -28,11 +29,12 @@ impl<'a> DatabaseBackend<'a> {
2829
Ok(Blob {
2930
path: row.get("path"),
3031
mime: row.get("mime"),
31-
date_updated: row.get("date_updated"),
32+
date_updated: DateTime::from_utc(row.get::<_, NaiveDateTime>("date_updated"), Utc),
3233
content: row.get("content"),
3334
})
3435
}
3536
}
37+
3638
pub(super) fn store_batch(&self, batch: &[Blob], trans: &Transaction) -> Result<(), Error> {
3739
for blob in batch {
3840
trans.query(
@@ -50,21 +52,22 @@ impl<'a> DatabaseBackend<'a> {
5052
#[cfg(test)]
5153
mod tests {
5254
use super::*;
53-
use time::Timespec;
55+
use chrono::{SubsecRound, Utc};
5456

5557
#[test]
5658
fn test_path_get() {
5759
crate::test::wrapper(|env| {
5860
let conn = env.db().conn();
5961
let backend = DatabaseBackend::new(&conn);
62+
let now = Utc::now();
6063

6164
// Add a test file to the database
6265
conn.execute(
6366
"INSERT INTO files (path, mime, date_updated, content) VALUES ($1, $2, $3, $4);",
6467
&[
6568
&"dir/foo.txt",
6669
&"text/plain",
67-
&Timespec::new(42, 0),
70+
&now.naive_utc(),
6871
&"Hello world!".as_bytes(),
6972
],
7073
)?;
@@ -74,7 +77,7 @@ mod tests {
7477
Blob {
7578
path: "dir/foo.txt".into(),
7679
mime: "text/plain".into(),
77-
date_updated: Timespec::new(42, 0),
80+
date_updated: now.trunc_subsecs(6),
7881
content: "Hello world!".bytes().collect(),
7982
},
8083
backend.get("dir/foo.txt")?

Diff for: src/storage/mod.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ pub(crate) mod s3;
33

44
pub(crate) use self::database::DatabaseBackend;
55
pub(crate) use self::s3::S3Backend;
6-
use failure::Error;
7-
use time::Timespec;
8-
9-
use failure::err_msg;
6+
use chrono::{DateTime, Utc};
7+
use failure::{err_msg, Error};
108
use postgres::{transaction::Transaction, Connection};
119
use std::collections::HashMap;
1210
use std::ffi::OsStr;
@@ -20,7 +18,7 @@ const MAX_CONCURRENT_UPLOADS: usize = 1000;
2018
pub(crate) struct Blob {
2119
pub(crate) path: String,
2220
pub(crate) mime: String,
23-
pub(crate) date_updated: Timespec,
21+
pub(crate) date_updated: DateTime<Utc>,
2422
pub(crate) content: Vec<u8>,
2523
}
2624

@@ -130,7 +128,7 @@ impl<'a> Storage<'a> {
130128
mime: mime.to_string(),
131129
content,
132130
// this field is ignored by the backend
133-
date_updated: Timespec::new(0, 0),
131+
date_updated: Utc::now(),
134132
})
135133
});
136134
loop {
@@ -281,9 +279,10 @@ mod test {
281279
mime: "text/rust".into(),
282280
content: "fn main() {}".into(),
283281
path: format!("{}.rs", i),
284-
date_updated: Timespec::new(42, 0),
282+
date_updated: Utc::now(),
285283
})
286284
.collect();
285+
287286
test_roundtrip(&uploads);
288287
}
289288

@@ -297,6 +296,7 @@ mod test {
297296
let files = get_file_list(env::current_dir().unwrap().join("Cargo.toml")).unwrap();
298297
assert_eq!(files[0], std::path::Path::new("Cargo.toml"));
299298
}
299+
300300
#[test]
301301
fn test_mime_types() {
302302
check_mime(".gitignore", "text/plain");

Diff for: src/storage/s3.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::Blob;
2+
use chrono::{DateTime, NaiveDateTime, Utc};
23
use failure::Error;
34
use futures::Future;
45
use log::{error, warn};
@@ -7,7 +8,6 @@ use rusoto_credential::DefaultCredentialsProvider;
78
use rusoto_s3::{GetObjectRequest, PutObjectRequest, S3Client, S3};
89
use std::convert::TryInto;
910
use std::io::Read;
10-
use time::Timespec;
1111
use tokio::runtime::Runtime;
1212

1313
#[cfg(test)]
@@ -100,9 +100,13 @@ impl<'a> S3Backend<'a> {
100100
}
101101
}
102102

103-
fn parse_timespec(raw: &str) -> Result<Timespec, Error> {
104-
const TIME_FMT: &str = "%a, %d %b %Y %H:%M:%S %Z";
105-
Ok(time::strptime(raw, TIME_FMT)?.to_timespec())
103+
fn parse_timespec(mut raw: &str) -> Result<DateTime<Utc>, Error> {
104+
raw = raw.trim_end_matches(" GMT");
105+
106+
Ok(DateTime::from_utc(
107+
NaiveDateTime::parse_from_str(raw, "%a, %d %b %Y %H:%M:%S")?,
108+
Utc,
109+
))
106110
}
107111

108112
pub(crate) fn s3_client() -> Option<S3Client> {
@@ -111,13 +115,15 @@ pub(crate) fn s3_client() -> Option<S3Client> {
111115
if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() && std::env::var_os("FORCE_S3").is_none() {
112116
return None;
113117
}
118+
114119
let creds = match DefaultCredentialsProvider::new() {
115120
Ok(creds) => creds,
116121
Err(err) => {
117122
warn!("failed to retrieve AWS credentials: {}", err);
118123
return None;
119124
}
120125
};
126+
121127
Some(S3Client::new_with(
122128
rusoto_core::request::HttpClient::new().unwrap(),
123129
creds,
@@ -135,18 +141,19 @@ pub(crate) fn s3_client() -> Option<S3Client> {
135141
pub(crate) mod tests {
136142
use super::*;
137143
use crate::test::*;
144+
use chrono::TimeZone;
138145
use std::slice;
139146

140147
#[test]
141148
fn test_parse_timespec() {
142149
// Test valid conversions
143150
assert_eq!(
144151
parse_timespec("Thu, 1 Jan 1970 00:00:00 GMT").unwrap(),
145-
Timespec::new(0, 0)
152+
Utc.ymd(1970, 1, 1).and_hms(0, 0, 0),
146153
);
147154
assert_eq!(
148155
parse_timespec("Mon, 16 Apr 2018 04:33:50 GMT").unwrap(),
149-
Timespec::new(1523853230, 0)
156+
Utc.ymd(2018, 4, 16).and_hms(4, 33, 50),
150157
);
151158

152159
// Test invalid conversion
@@ -159,7 +166,7 @@ pub(crate) mod tests {
159166
let blob = Blob {
160167
path: "dir/foo.txt".into(),
161168
mime: "text/plain".into(),
162-
date_updated: Timespec::new(42, 0),
169+
date_updated: Utc::now(),
163170
content: "Hello world!".into(),
164171
};
165172

@@ -189,15 +196,17 @@ pub(crate) mod tests {
189196
"parent/child",
190197
"h/i/g/h/l/y/_/n/e/s/t/e/d/_/d/i/r/e/c/t/o/r/i/e/s",
191198
];
199+
192200
let blobs: Vec<_> = names
193201
.iter()
194202
.map(|&path| Blob {
195203
path: path.into(),
196204
mime: "text/plain".into(),
197-
date_updated: Timespec::new(42, 0),
205+
date_updated: Utc::now(),
198206
content: "Hello world!".into(),
199207
})
200208
.collect();
209+
201210
s3.upload(&blobs).unwrap();
202211
for blob in &blobs {
203212
s3.assert_blob(blob, &blob.path);

Diff for: src/test/fakes.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::TestDatabase;
22
use crate::docbuilder::BuildResult;
33
use crate::index::api::RegistryCrateData;
44
use crate::utils::{Dependency, MetadataPackage, Target};
5+
use chrono::{DateTime, Utc};
56
use failure::Error;
67

78
#[must_use = "FakeRelease does nothing until you call .create()"]
@@ -54,7 +55,7 @@ impl<'a> FakeRelease<'a> {
5455
doc_targets: Vec::new(),
5556
default_target: None,
5657
registry_crate_data: RegistryCrateData {
57-
release_time: time::get_time(),
58+
release_time: Utc::now(),
5859
yanked: false,
5960
downloads: 0,
6061
owners: Vec::new(),
@@ -74,7 +75,7 @@ impl<'a> FakeRelease<'a> {
7475
self
7576
}
7677

77-
pub(crate) fn release_time(mut self, new: time::Timespec) -> Self {
78+
pub(crate) fn release_time(mut self, new: DateTime<Utc>) -> Self {
7879
self.registry_crate_data.release_time = new;
7980
self
8081
}

Diff for: src/utils/daemon.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
utils::{github_updater, pubsubhubbub, update_release_activity},
88
DocBuilder, DocBuilderOptions,
99
};
10+
use chrono::{Timelike, Utc};
1011
use log::{debug, error, info, warn};
1112
use std::panic::{catch_unwind, AssertUnwindSafe};
1213
use std::path::PathBuf;
@@ -221,8 +222,9 @@ pub fn start_daemon(background: bool) {
221222
.name("release activity updater".to_string())
222223
.spawn(move || loop {
223224
thread::sleep(Duration::from_secs(60));
224-
let now = time::now();
225-
if now.tm_hour == 23 && now.tm_min == 55 {
225+
let now = Utc::now();
226+
227+
if now.hour() == 23 && now.minute() == 55 {
226228
info!("Updating release activity");
227229
if let Err(e) = update_release_activity() {
228230
error!("Failed to update release activity: {}", e);

0 commit comments

Comments
 (0)