From 94dd9bfb03a64ea0f03a6c1e6035efc459b4ac87 Mon Sep 17 00:00:00 2001 From: Chase Wilson Date: Sun, 3 May 2020 12:43:32 -0500 Subject: [PATCH 1/5] Added tests for json serialization --- src/docbuilder/limits.rs | 2 +- src/web/builds.rs | 213 +++++++++++++++++++++++++++++++++++++++ src/web/crate_details.rs | 157 +++++++++++++++++++++++++++++ src/web/mod.rs | 75 ++++++++++++-- src/web/page.rs | 127 +++++++++++++++++++++++ src/web/releases.rs | 85 ++++++++++++++-- src/web/rustdoc.rs | 109 ++++++++++++++++++++ src/web/source.rs | 209 +++++++++++++++++++++++++++++++++++++- 8 files changed, 960 insertions(+), 17 deletions(-) diff --git a/src/docbuilder/limits.rs b/src/docbuilder/limits.rs index 317f3c47f..c0a368434 100644 --- a/src/docbuilder/limits.rs +++ b/src/docbuilder/limits.rs @@ -3,7 +3,7 @@ use postgres::Connection; use std::collections::BTreeMap; use std::time::Duration; -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub(crate) struct Limits { memory: usize, targets: usize, diff --git a/src/web/builds.rs b/src/web/builds.rs index ffc00cf58..9b4bae620 100644 --- a/src/web/builds.rs +++ b/src/web/builds.rs @@ -144,3 +144,216 @@ pub fn build_list_handler(req: &mut Request) -> IronResult { .to_resp("builds") } } + +#[cfg(test)] +mod tests { + use super::*; + use rustc_serialize::json::Json; + + #[test] + fn serialize_build() { + let time = time::get_time(); + let mut build = Build { + id: 22, + rustc_version: "rustc 1.43.0 (4fb7144ed 2020-04-20)".to_string(), + cratesfyi_version: "docsrs 0.6.0 (3dd32ec 2020-05-01)".to_string(), + build_status: true, + build_time: time, + output: None, + }; + + let correct_json = format!( + r#"{{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{}", + "build_time_relative": "{}", + "output": null, + "build_status": true + }}"#, + time::at(time).rfc3339().to_string(), + duration_to_str(time), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes the `id`s unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + build.to_json().to_string() + ); + + build.output = Some("some random stuff".to_string()); + let correct_json = format!( + r#"{{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{}", + "build_time_relative": "{}", + "output": "some random stuff", + "build_status": true + }}"#, + time::at(time).rfc3339().to_string(), + duration_to_str(time), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes the `id`s unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + build.to_json().to_string() + ); + } + + #[test] + fn serialize_build_page() { + let time = time::get_time(); + let build = Build { + id: 22, + rustc_version: "rustc 1.43.0 (4fb7144ed 2020-04-20)".to_string(), + cratesfyi_version: "docsrs 0.6.0 (3dd32ec 2020-05-01)".to_string(), + build_status: true, + build_time: time, + output: None, + }; + let limits = Limits::default(); + let mut builds = BuildsPage { + metadata: Some(MetaData { + name: "serde".to_string(), + version: "1.0.0".to_string(), + description: Some("serde does stuff".to_string()), + target_name: None, + rustdoc_status: true, + default_target: "x86_64-unknown-linux-gnu".to_string(), + }), + builds: vec![build.clone()], + build_details: Some(build.clone()), + limits: limits.clone(), + }; + + let correct_json = format!( + r#"{{ + "metadata": {{ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }}, + "builds": [{{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{time}", + "build_time_relative": "{time_rel}", + "output": null, + "build_status": true + }}], + "build_details": {{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{time}", + "build_time_relative": "{time_rel}", + "output": null, + "build_status": true + }}, + "limits": {} + }}"#, + limits.for_website().to_json().to_string(), + time = time::at(time).rfc3339().to_string(), + time_rel = duration_to_str(time), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes the `id`s unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + builds.to_json().to_string() + ); + + builds.metadata = None; + let correct_json = format!( + r#"{{ + "metadata": null, + "builds": [{{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{time}", + "build_time_relative": "{time_rel}", + "output": null, + "build_status": true + }}], + "build_details": {{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{time}", + "build_time_relative": "{time_rel}", + "output": null, + "build_status": true + }}, + "limits": {} + }}"#, + limits.for_website().to_json().to_string(), + time = time::at(time).rfc3339().to_string(), + time_rel = duration_to_str(time), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes the `id`s unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + builds.to_json().to_string() + ); + + builds.builds = Vec::new(); + let correct_json = format!( + r#"{{ + "metadata": null, + "builds": [], + "build_details": {{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": "{time}", + "build_time_relative": "{time_rel}", + "output": null, + "build_status": true + }}, + "limits": {} + }}"#, + limits.for_website().to_json().to_string(), + time = time::at(time).rfc3339().to_string(), + time_rel = duration_to_str(time), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes the `id`s unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + builds.to_json().to_string() + ); + + builds.build_details = None; + let correct_json = format!( + r#"{{ + "metadata": null, + "builds": [], + "build_details": null, + "limits": {} + }}"#, + limits.for_website().to_json().to_string(), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes the `id`s unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + builds.to_json().to_string() + ); + } +} diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 022ea7891..51d2bb34d 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -284,6 +284,47 @@ impl CrateDetails { .find(|release| !release.yanked) .unwrap_or(&self.releases[0]) } + + #[cfg(test)] + pub fn default_tester(release_time: time::Timespec) -> Self { + Self { + name: "rcc".to_string(), + version: "100.0.0".to_string(), + description: None, + authors: vec![], + owners: vec![], + authors_json: None, + dependencies: None, + readme: None, + rustdoc: None, + release_time, + build_status: true, + last_successful_build: None, + rustdoc_status: true, + repository_url: None, + homepage_url: None, + keywords: None, + have_examples: true, + target_name: "x86_64-unknown-linux-gnu".to_string(), + releases: vec![], + github: true, + github_stars: None, + github_forks: None, + github_issues: None, + metadata: MetaData { + name: "serde".to_string(), + version: "1.0.0".to_string(), + description: Some("serde does stuff".to_string()), + target_name: None, + rustdoc_status: true, + default_target: "x86_64-unknown-linux-gnu".to_string(), + }, + is_library: true, + doc_targets: vec![], + license: None, + documentation_url: None, + } + } } fn map_to_release(conn: &Connection, crate_id: i32, version: String) -> Release { @@ -587,4 +628,120 @@ mod tests { Ok(()) }) } + + #[test] + fn serialize_crate_details() { + let time = time::get_time(); + let mut details = CrateDetails::default_tester(time); + + let correct_json = Json::from_str(&format!( + r#"{{ + "name": "rcc", + "version": "100.0.0", + "description": null, + "authors": [], + "owners": [], + "authors_json": null, + "dependencies": null, + "release_time": "{}", + "build_status": true, + "last_successful_build": null, + "rustdoc_status": true, + "repository_url": null, + "homepage_url": null, + "keywords": null, + "have_examples": true, + "target_name": "x86_64-unknown-linux-gnu", + "releases": [], + "github": true, + "github_stars": null, + "github_forks": null, + "github_issues": null, + "metadata": {{ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }}, + "is_library": true, + "doc_targets": [], + "license": null, + "documentation_url": null + }}"#, + super::super::duration_to_str(time), + )) + .unwrap(); + + assert_eq!(correct_json, details.to_json()); + + details.description = Some("serde does stuff".to_string()); + details.owners = vec![("Owner".to_string(), "owner@ownsstuff.com".to_string())]; + + let authors = vec![("Somebody".to_string(), "somebody@somebody.com".to_string())]; + details.authors_json = Some(authors.to_json()); + details.authors = authors; + + let correct_json = Json::from_str(&format!( + r#"{{ + "name": "rcc", + "version": "100.0.0", + "description": "serde does stuff", + "authors": [["Somebody", "somebody@somebody.com"]], + "owners": [["Owner", "owner@ownsstuff.com"]], + "authors_json": [["Somebody", "somebody@somebody.com"]], + "dependencies": null, + "release_time": "{}", + "build_status": true, + "last_successful_build": null, + "rustdoc_status": true, + "repository_url": null, + "homepage_url": null, + "keywords": null, + "have_examples": true, + "target_name": "x86_64-unknown-linux-gnu", + "releases": [], + "github": true, + "github_stars": null, + "github_forks": null, + "github_issues": null, + "metadata": {{ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }}, + "is_library": true, + "doc_targets": [], + "license": null, + "documentation_url": null + }}"#, + super::super::duration_to_str(time), + )) + .unwrap(); + + assert_eq!(correct_json, details.to_json()); + } + + #[test] + fn serialize_releases() { + let release = Release { + version: "idkman".to_string(), + build_status: true, + yanked: true, + }; + + let correct_json = Json::from_str( + r#"{ + "version": "idkman", + "build_status": true + }"#, + ) + .unwrap(); + + assert_eq!(correct_json, release.to_json()); + } } diff --git a/src/web/mod.rs b/src/web/mod.rs index c782e3dab..eba5a328a 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -516,12 +516,12 @@ fn ico_handler(req: &mut Request) -> IronResult { /// MetaData used in header #[derive(Debug)] pub(crate) struct MetaData { - name: String, - version: String, - description: Option, - target_name: Option, - rustdoc_status: bool, - pub default_target: String, + pub(crate) name: String, + pub(crate) version: String, + pub(crate) description: Option, + pub(crate) target_name: Option, + pub(crate) rustdoc_status: bool, + pub(crate) default_target: String, } impl MetaData { @@ -570,9 +570,13 @@ impl ToJson for MetaData { #[cfg(test)] mod test { - use crate::test::*; - use crate::web::{handlebars_engine, match_version}; + use super::*; + use crate::{ + test::*, + web::{handlebars_engine, match_version}, + }; use html5ever::tendril::TendrilSink; + use rustc_serialize::json::Json; fn release(version: &str, db: &TestDatabase) -> i32 { db.fake_release() @@ -783,4 +787,59 @@ mod test { fn test_templates_are_valid() { handlebars_engine().expect("Failed to load handlebar templates"); } + + fn serialize_metadata() { + let mut metadata = MetaData { + name: "serde".to_string(), + version: "1.0.0".to_string(), + description: Some("serde does stuff".to_string()), + target_name: None, + rustdoc_status: true, + default_target: "x86_64-unknown-linux-gnu".to_string(), + }; + + let correct_json = Json::from_str( + r#"{ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }"#, + ) + .unwrap(); + + assert_eq!(correct_json, metadata.to_json()); + + metadata.target_name = Some("x86_64-apple-darwin".to_string()); + let correct_json = Json::from_str( + r#"{ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": "x86_64-apple-darwin", + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }"#, + ) + .unwrap(); + + assert_eq!(correct_json, metadata.to_json()); + + metadata.description = None; + let correct_json = Json::from_str( + r#"{ + "name": "serde", + "version": "1.0.0", + "description": null, + "target_name": "x86_64-apple-darwin", + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }"#, + ) + .unwrap(); + + assert_eq!(correct_json, metadata.to_json()); + } } diff --git a/src/web/page.rs b/src/web/page.rs index 46b8f0615..85cfbceaa 100644 --- a/src/web/page.rs +++ b/src/web/page.rs @@ -31,6 +31,7 @@ fn load_rustc_resource_suffix() -> Result { failure::bail!("failed to parse the rustc version"); } +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct GlobalAlert { pub(crate) url: &'static str, pub(crate) text: &'static str, @@ -49,6 +50,7 @@ impl ToJson for GlobalAlert { } } +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Page { title: Option, content: T, @@ -158,3 +160,128 @@ impl ToJson for Page { Json::Object(tree) } } + +#[cfg(test)] +mod tests { + use super::super::releases::{self, Release}; + use super::*; + use rustc_serialize::json::Json; + + #[test] + fn serialize_page() { + let time = time::get_time(); + + let mut release = Release::default(); + release.name = "lasso".into(); + release.version = "0.1.0".into(); + release.release_time = time.clone(); + + let mut varss = BTreeMap::new(); + varss.insert("test".into(), "works".into()); + let mut varsb = BTreeMap::new(); + varsb.insert("test2".into(), true); + let mut varsi = BTreeMap::new(); + varsi.insert("test3".into(), 1337); + + let page = Page { + title: None, + content: vec![release.clone()], + status: status::Status::Ok, + varss, + varsb, + varsi, + rustc_resource_suffix: &*RUSTC_RESOURCE_SUFFIX, + }; + + let correct_json = format!( + r#"{{ + "content": [{{ + "name": "lasso", + "version": "0.1.0", + "description": null, + "target_name": null, + "rustdoc_status": false, + "release_time": "{}", + "release_time_rfc3339": "{}", + "stars": 0 + }}], + "varss": {{ "test": "works" }}, + "varsb": {{ "test2": true }}, + "varsi": {{ "test3": 1337 }}, + "rustc_resource_suffix": "{}", + "cratesfyi_version": "{}", + "cratesfyi_version_safe": "{}", + "has_global_alert": {} + }}"#, + super::super::duration_to_str(time.clone()), + time::at(time).rfc3339().to_string(), + &*RUSTC_RESOURCE_SUFFIX, + crate::BUILD_VERSION, + crate::BUILD_VERSION + .replace(" ", "-") + .replace("(", "") + .replace(")", ""), + crate::GLOBAL_ALERT.is_some(), + ); + + // Have to call `.to_string()` here because for some reason rustc_serialize defaults to + // u64s for `Json::from_str`, which makes everything in the respective `varsi` unequal + assert_eq!( + Json::from_str(&correct_json).unwrap().to_string(), + page.to_json().to_string() + ); + } + + #[test] + fn load_page_from_releases() { + crate::test::wrapper(|env| { + let db = env.db(); + db.fake_release().name("foo").version("0.1.0").create()?; + let packages = releases::get_releases(&db.conn(), 1, 1, releases::Order::ReleaseTime); + + let mut varsb = BTreeMap::new(); + varsb.insert("show_search_form".into(), true); + varsb.insert("hide_package_navigation".into(), true); + + let correct_page = Page { + title: None, + content: packages.clone(), + status: status::Status::Ok, + varss: BTreeMap::new(), + varsb, + varsi: BTreeMap::new(), + rustc_resource_suffix: &RUSTC_RESOURCE_SUFFIX, + }; + + let page = Page::new(packages) + .set_true("show_search_form") + .set_true("hide_package_navigation"); + + assert_eq!(page, correct_page); + + Ok(()) + }) + } + + #[test] + fn serialize_global_alert() { + let alert = GlobalAlert { + url: "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/", + text: "THE WORLD IS ENDING", + css_class: "THE END IS NEAR", + fa_icon: "https://gph.is/1uOvmqR", + }; + + let correct_json = Json::from_str( + r#"{ + "url": "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/", + "text": "THE WORLD IS ENDING", + "css_class": "THE END IS NEAR", + "fa_icon": "https://gph.is/1uOvmqR" + }"#, + ) + .unwrap(); + + assert_eq!(correct_json, alert.to_json()); + } +} diff --git a/src/web/releases.rs b/src/web/releases.rs index b9fa2c6c0..cbce9e04b 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -20,12 +20,12 @@ const RELEASES_IN_FEED: i64 = 150; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Release { - name: String, - version: String, + pub(crate) name: String, + pub(crate) version: String, description: Option, target_name: Option, rustdoc_status: bool, - release_time: time::Timespec, + pub(crate) release_time: time::Timespec, stars: i32, } @@ -57,7 +57,7 @@ impl ToJson for Release { ); m.insert( "release_time_rfc3339".to_string(), - format!("{}", time::at(self.release_time).rfc3339()).to_json(), + time::at(self.release_time).rfc3339().to_string().to_json(), ); m.insert("stars".to_string(), self.stars.to_json()); m.to_json() @@ -65,7 +65,7 @@ impl ToJson for Release { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum Order { +pub(crate) enum Order { ReleaseTime, // this is default order GithubStars, RecentFailures, @@ -78,7 +78,7 @@ impl Default for Order { } } -fn get_releases(conn: &Connection, page: i64, limit: i64, order: Order) -> Vec { +pub(crate) fn get_releases(conn: &Connection, page: i64, limit: i64, order: Order) -> Vec { let offset = (page - 1) * limit; // TODO: This function changed so much during development and current version have code @@ -1001,4 +1001,77 @@ mod tests { Ok(()) }) } + + #[test] + fn serialize_releases() { + let time = time::get_time(); + let mut release = Release { + name: "serde".to_string(), + version: "0.0.0".to_string(), + description: Some("serde makes things other things".to_string()), + target_name: Some("x86_64-pc-windows-msvc".to_string()), + rustdoc_status: true, + release_time: time, + stars: 100, + }; + + let correct_json = Json::from_str(&format!( + r#"{{ + "name": "serde", + "version": "0.0.0", + "description": "serde makes things other things", + "target_name": "x86_64-pc-windows-msvc", + "rustdoc_status": true, + "release_time": "{}", + "release_time_rfc3339": "{}", + "stars": 100 + }}"#, + duration_to_str(time), + time::at(time).rfc3339().to_string(), + )) + .unwrap(); + + // Have to call `.to_string()` here because of how `rustc_serialize` handles integers + assert_eq!(correct_json.to_string(), release.to_json().to_string()); + + release.target_name = None; + let correct_json = Json::from_str(&format!( + r#"{{ + "name": "serde", + "version": "0.0.0", + "description": "serde makes things other things", + "target_name": null, + "rustdoc_status": true, + "release_time": "{}", + "release_time_rfc3339": "{}", + "stars": 100 + }}"#, + duration_to_str(time), + time::at(time).rfc3339().to_string(), + )) + .unwrap(); + + // Have to call `.to_string()` here because of how `rustc_serialize` handles integers + assert_eq!(correct_json.to_string(), release.to_json().to_string()); + + release.description = None; + let correct_json = Json::from_str(&format!( + r#"{{ + "name": "serde", + "version": "0.0.0", + "description": null, + "target_name": null, + "rustdoc_status": true, + "release_time": "{}", + "release_time_rfc3339": "{}", + "stars": 100 + }}"#, + duration_to_str(time), + time::at(time).rfc3339().to_string(), + )) + .unwrap(); + + // Have to call `.to_string()` here because of how `rustc_serialize` handles integers + assert_eq!(correct_json.to_string(), release.to_json().to_string()); + } } diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 0e2a7c34a..6600a9ad8 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -541,6 +541,7 @@ impl Handler for SharedResourceHandler { #[cfg(test)] mod test { + use super::*; use crate::test::*; use reqwest::StatusCode; use std::{collections::BTreeMap, iter::FromIterator}; @@ -1343,4 +1344,112 @@ mod test { Ok(()) }) } + + fn serialize_rustdoc_page() { + let time = time::get_time(); + let details = format!( + r#"{{ + "name": "rcc", + "version": "100.0.0", + "description": null, + "authors": [], + "owners": [], + "authors_json": null, + "dependencies": null, + "release_time": "{}", + "build_status": true, + "last_successful_build": null, + "rustdoc_status": true, + "repository_url": null, + "homepage_url": null, + "keywords": null, + "have_examples": true, + "target_name": "x86_64-unknown-linux-gnu", + "releases": [], + "github": true, + "github_stars": null, + "github_forks": null, + "github_issues": null, + "metadata": {{ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }}, + "is_library": true, + "doc_targets": [], + "license": null, + "documentation_url": null + }}"#, + super::super::duration_to_str(time), + ); + + let mut page = RustdocPage { + head: "Whee".to_string(), + body: "

idk

".to_string(), + body_class: "docsrs-body".to_string(), + name: "rcc".to_string(), + full: "??".to_string(), + version: "100.0.100".to_string(), + description: Some("a Rust compiler in C. Wait, maybe the other way around".to_string()), + crate_details: Some(CrateDetails::default_tester(time)), + }; + + let correct_json = Json::from_str(&format!( + r#"{{ + "rustdoc_head": "Whee", + "rustdoc_body": "

idk

", + "rustdoc_body_class": "docsrs-body", + "rustdoc_full": "??", + "rustdoc_status": true, + "name": "rcc", + "version": "100.0.100", + "description": "a Rust compiler in C. Wait, maybe the other way around", + "crate_details": {} + }}"#, + details, + )) + .unwrap(); + + assert_eq!(correct_json, page.to_json()); + + page.description = None; + let correct_json = Json::from_str(&format!( + r#"{{ + "rustdoc_head": "Whee", + "rustdoc_body": "

idk

", + "rustdoc_body_class": "docsrs-body", + "rustdoc_full": "??", + "rustdoc_status": true, + "name": "rcc", + "version": "100.0.100", + "description": null, + "crate_details": {} + }}"#, + details, + )) + .unwrap(); + + assert_eq!(correct_json, page.to_json()); + + page.crate_details = None; + let correct_json = Json::from_str( + r#"{ + "rustdoc_head": "Whee", + "rustdoc_body": "

idk

", + "rustdoc_body_class": "docsrs-body", + "rustdoc_full": "??", + "rustdoc_status": true, + "name": "rcc", + "version": "100.0.100", + "description": null, + "crate_details": null + }"#, + ) + .unwrap(); + + assert_eq!(correct_json, page.to_json()); + } } diff --git a/src/web/source.rs b/src/web/source.rs index b746555f9..98f62e82a 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -9,8 +9,17 @@ use postgres::Connection; use router::Router; use rustc_serialize::json::{Json, ToJson}; use std::cmp::Ordering; -use std::collections::BTreeMap; - +use std::{collections::BTreeMap, iter::FromIterator}; + +/// A source file's type +/// +/// When serialized into json it takes this form +/// +/// * `FileType::Dir`: `{ "file_type_dir": true }` +/// * `FileType::Text`: `{ "file_type_text": true }` +/// * `FileType::Binary`: `{ "file_type_binary": true }` +/// * `FileType::RustSource`: `{ "file_type_rust_source": true }` +/// #[derive(PartialEq, PartialOrd)] enum FileType { Dir, @@ -19,12 +28,116 @@ enum FileType { RustSource, } +impl ToJson for FileType { + fn to_json(&self) -> Json { + let key = match self { + Self::Dir => "file_type_dir", + Self::Text => "file_type_text", + Self::Binary => "file_type_binary", + Self::RustSource => "file_type_rust_source", + }; + + Json::Object(BTreeMap::from_iter(vec![( + key.to_string(), + Json::Boolean(true), + )])) + } +} + +/// A source file +/// +/// Rust: +/// +/// ```ignore +/// struct File { +/// name: "main.rs", +/// file_type: FileType::RustSource, +/// } +/// ``` +/// +/// Json: +/// +/// ```json +/// { +/// "name": "main.rs", +/// "file_type_rust_source": true, +/// } +/// ``` +/// #[derive(PartialEq, PartialOrd)] struct File { name: String, file_type: FileType, } +impl ToJson for File { + fn to_json(&self) -> Json { + let mut file_m: BTreeMap = BTreeMap::new(); + file_m.insert("name".to_string(), self.name.to_json()); + + let file_type = match self.file_type { + FileType::Dir => "file_type_dir", + FileType::Text => "file_type_text", + FileType::Binary => "file_type_binary", + FileType::RustSource => "file_type_rust_source", + }; + + file_m.insert(file_type.to_string(), true.to_json()); + + Json::Object(file_m) + } +} + +/// A list of source files +/// +/// +/// Rust: +/// +/// ```ignore +/// FileList { +/// metadata: MetaData { +/// name: "rcc", +/// version: "0.0.0", +/// description: Some("it compiles an unholy language"), +/// target_name: None, +/// rustdoc_status: true, +/// default_target: "x86_64-unknown-linux-gnu", +/// }, +/// files: vec![ +/// File { +/// name: "main.rs", +/// file_type: FileType::RustSource, +/// }, +/// File { +/// name: "lib.rs", +/// file_type: FileType::RustSource, +/// }, +/// ], +/// } +/// ``` +/// +/// Json: +/// +/// ```json +/// { +/// "metadata": { +/// "name": "rcc", +/// "version": "0.0.0", +/// "description": "it compiles an unholy language", +/// "target_name": null, +/// "rustdoc_status": true, +/// "default_target": "x86_64-unknown-linux-gnu", +/// }, +/// "files": [{ +/// "name": "main.rs", +/// "file_type_rust_source": true, +/// }, { +/// "name": "lib.rs", +/// "file_type_rust_source": true, +/// }], +/// } +/// ``` +/// struct FileList { metadata: MetaData, files: Vec, @@ -36,6 +149,8 @@ impl ToJson for FileList { m.insert("metadata".to_string(), self.metadata.to_json()); + // TODO: file_vec from iter + let mut file_vec: Vec = Vec::new(); for file in &self.files { @@ -249,3 +364,93 @@ pub fn source_browser_handler(req: &mut Request) -> IronResult { page.to_resp("source") } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn serialize_file_types() { + assert_eq!( + Json::from_str(r#"{ "file_type_dir": true }"#).unwrap(), + FileType::Dir.to_json(), + ); + assert_eq!( + Json::from_str(r#"{ "file_type_text": true }"#).unwrap(), + FileType::Text.to_json(), + ); + assert_eq!( + Json::from_str(r#"{ "file_type_binary": true }"#).unwrap(), + FileType::Binary.to_json(), + ); + assert_eq!( + Json::from_str(r#"{ "file_type_rust_source": true }"#).unwrap(), + FileType::RustSource.to_json(), + ); + } + + #[test] + fn serialize_file() { + assert_eq!( + Json::from_str( + r#"{ + "name": "main.rs", + "file_type_rust_source": true + }"# + ) + .unwrap(), + File { + name: "main.rs".to_string(), + file_type: FileType::RustSource + } + .to_json(), + ); + } + + #[test] + fn serialize_file_list() { + assert_eq!( + Json::from_str( + r#"{ + "metadata": { + "name": "rcc", + "version": "0.0.0", + "description": "it compiles an unholy language", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }, + "files": [{ + "name": "main.rs", + "file_type_rust_source": true + }, { + "name": "lib.rs", + "file_type_rust_source": true + }] + }"# + ) + .unwrap(), + FileList { + metadata: MetaData { + name: "rcc".to_string(), + version: "0.0.0".to_string(), + description: Some("it compiles an unholy language".to_string()), + target_name: None, + rustdoc_status: true, + default_target: "x86_64-unknown-linux-gnu".to_string(), + }, + files: vec![ + File { + name: "main.rs".to_string(), + file_type: FileType::RustSource + }, + File { + name: "lib.rs".to_string(), + file_type: FileType::RustSource + } + ], + } + .to_json(), + ); + } +} From 83f3814636396e02bfac01d012177e374e107042 Mon Sep 17 00:00:00 2001 From: Chase Wilson Date: Sun, 3 May 2020 16:47:10 -0500 Subject: [PATCH 2/5] Fixed serde by rewriting everything --- Cargo.lock | 40 ++-- Cargo.toml | 9 +- src/db/add_package.rs | 20 +- src/db/file.rs | 21 +- src/docbuilder/crates.rs | 17 +- src/docbuilder/limits.rs | 2 +- src/docbuilder/rustwide_builder.rs | 4 +- src/index/api.rs | 20 +- src/utils/cargo_metadata.rs | 17 +- src/utils/github_updater.rs | 11 +- src/utils/release_activity_updater.rs | 13 +- src/web/builds.rs | 318 +++++++++++--------------- src/web/crate_details.rs | 276 +++++++++++----------- src/web/mod.rs | 88 +++---- src/web/page.rs | 140 +++++------- src/web/releases.rs | 94 ++++---- src/web/rustdoc.rs | 189 ++++++++------- src/web/sitemap.rs | 10 +- src/web/source.rs | 221 +++++------------- 19 files changed, 633 insertions(+), 877 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19f7b5680..943335c34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -363,7 +363,7 @@ dependencies = [ "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars-iron 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars-iron 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "kuchiki 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -386,12 +386,13 @@ dependencies = [ "rusoto_core 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusoto_credential 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusoto_s3 0.40.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustwide 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sass-rs 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "schemamama 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "schemamama_postgres 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -846,7 +847,7 @@ dependencies = [ [[package]] name = "handlebars" -version = "0.24.2" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -854,20 +855,22 @@ dependencies = [ "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "handlebars-iron" -version = "0.22.0" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "handlebars 0.24.2 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1859,7 +1862,7 @@ dependencies = [ "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2464,6 +2467,15 @@ name = "safemem" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3434,10 +3446,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "walkdir" -version = "0.1.8" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3686,8 +3699,8 @@ dependencies = [ "checksum gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" "checksum git2 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)" = "11e4b2082980e751c4bf4273e9cbb4a02c655729c8ee8a79f66cad03c8f4d31e" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" -"checksum handlebars 0.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1060eaf359ded4fc5827db4591949fff18b0b736821c94c347a441d7019c2545" -"checksum handlebars-iron 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8e885e22dfcf8fbb0ce797cb402b82b6cafea35100a42790bd84c32b718040" +"checksum handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc" +"checksum handlebars-iron 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b8ad7259b5bfcc65da1f1f3525eb5e4d5c4c6c7ce2d3b9c9945165e7e083c9c" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" @@ -3856,6 +3869,7 @@ dependencies = [ "checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum sass-rs 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cabcf7c6e55053f359911187ac401409aad2dc14338cae972dec266fee486abd" "checksum sass-sys 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "dd454d3c8fa19fe6c66df5d6ced4933f3a40b29d5875114eacc469451136226d" @@ -3966,7 +3980,7 @@ dependencies = [ "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c66c0b9792f0a765345452775f3adbd28dde9d33f30d13e5dcc5ae17cf6f3780" +"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/Cargo.toml b/Cargo.toml index 6023f66e2..4bb824643 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ edition = "2018" [dependencies] log = "0.4" -rustc-serialize = "0.3" regex = "1" structopt = "0.3" crates-index-diff = "7" @@ -41,10 +40,14 @@ rustwide = "=0.7.0" mime_guess = "2" dotenv = "0.15" +# Data serialization and deserialization +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + # iron dependencies iron = "0.5" router = "0.5" -handlebars-iron = "0.22" +handlebars-iron = "0.25" params = "0.8" staticfile = { version = "0.4", features = [ "cache" ] } tempfile = "3.1.0" @@ -60,7 +63,7 @@ path-slash = "0.1.1" [dependencies.postgres] version = "0.15" -features = [ "with-time", "with-rustc-serialize" ] +features = ["with-time", "with-serde_json"] [dev-dependencies] once_cell = "1.2.0" diff --git a/src/db/add_package.rs b/src/db/add_package.rs index 34e5ea15b..2c30f751b 100644 --- a/src/db/add_package.rs +++ b/src/db/add_package.rs @@ -10,12 +10,11 @@ use crate::{ index::api::{CrateOwner, RegistryCrateData}, utils::MetadataPackage, }; - use log::debug; use postgres::Connection; use regex::Regex; -use rustc_serialize::json::{Json, ToJson}; use semver::Version; +use serde_json::Value; use slug::slugify; /// Adds a package into database. @@ -31,7 +30,7 @@ pub(crate) fn add_package_into_database( source_dir: &Path, res: &BuildResult, default_target: &str, - source_files: Option, + source_files: Option, doc_targets: Vec, cratesio_data: &RegistryCrateData, has_docs: bool, @@ -88,7 +87,7 @@ pub(crate) fn add_package_into_database( &crate_id, &metadata_pkg.version, &cratesio_data.release_time, - &dependencies.to_json(), + &serde_json::to_value(&dependencies)?, &metadata_pkg.package_name(), &cratesio_data.yanked, &res.successful, @@ -100,12 +99,12 @@ pub(crate) fn add_package_into_database( &metadata_pkg.description, &rustdoc, &readme, - &metadata_pkg.authors.to_json(), - &metadata_pkg.keywords.to_json(), + &serde_json::to_value(&metadata_pkg.authors)?, + &serde_json::to_value(&metadata_pkg.keywords)?, &has_examples, &cratesio_data.downloads, &source_files, - &doc_targets.to_json(), + &serde_json::to_value(&doc_targets)?, &is_library, &res.rustc_version, &metadata_pkg.documentation, @@ -122,20 +121,21 @@ pub(crate) fn add_package_into_database( // Update versions { let metadata_version = Version::parse(&metadata_pkg.version)?; - let mut versions: Json = conn + let mut versions: Value = conn .query("SELECT versions FROM crates WHERE id = $1", &[&crate_id])? .get(0) .get(0); if let Some(versions_array) = versions.as_array_mut() { let mut found = false; for version in versions_array.clone() { - let version = Version::parse(version.as_string().unwrap())?; + let version = Version::parse(version.as_str().unwrap())?; if version == metadata_version { found = true; } } + if !found { - versions_array.push(metadata_pkg.version.to_string().to_json()); + versions_array.push(Value::String(metadata_pkg.version.clone())); } } let _ = conn.query( diff --git a/src/db/file.rs b/src/db/file.rs index d82e32900..3280d1e40 100644 --- a/src/db/file.rs +++ b/src/db/file.rs @@ -8,7 +8,7 @@ use crate::error::Result; use crate::storage::Storage; use postgres::Connection; -use rustc_serialize::json::{Json, ToJson}; +use serde_json::Value; use std::path::{Path, PathBuf}; pub(crate) use crate::storage::Blob; @@ -30,21 +30,24 @@ pub fn add_path_into_database>( conn: &Connection, prefix: &str, path: P, -) -> Result { +) -> Result { let mut backend = Storage::new(conn); let file_list = backend.store_all(conn, prefix, path.as_ref())?; file_list_to_json(file_list.into_iter().collect()) } -fn file_list_to_json(file_list: Vec<(PathBuf, String)>) -> Result { - let mut file_list_json: Vec = Vec::new(); +fn file_list_to_json(file_list: Vec<(PathBuf, String)>) -> Result { + let mut file_list_json: Vec = Vec::new(); for file in file_list { - let mut v: Vec = Vec::with_capacity(2); - v.push(file.1); - v.push(file.0.into_os_string().into_string().unwrap()); - file_list_json.push(v.to_json()); + let mut v = Vec::with_capacity(2); + v.push(Value::String(file.1)); + v.push(Value::String( + file.0.into_os_string().into_string().unwrap(), + )); + + file_list_json.push(Value::Array(v)); } - Ok(file_list_json.to_json()) + Ok(Value::Array(file_list_json)) } diff --git a/src/docbuilder/crates.rs b/src/docbuilder/crates.rs index 0c3a8db71..08de1d100 100644 --- a/src/docbuilder/crates.rs +++ b/src/docbuilder/crates.rs @@ -1,10 +1,9 @@ use crate::error::Result; use failure::err_msg; -use rustc_serialize::json::Json; -use std::fs; +use serde_json::Value; use std::io::prelude::*; use std::io::BufReader; -use std::path::PathBuf; +use std::{fs, path::PathBuf, str::FromStr}; fn crates_from_file(path: &PathBuf, func: &mut F) -> Result<()> where @@ -24,7 +23,7 @@ where continue; }; - let data = if let Ok(data) = Json::from_str(line.trim()) { + let data = if let Ok(data) = Value::from_str(line.trim()) { data } else { continue; @@ -35,19 +34,15 @@ where .ok_or_else(|| err_msg("Not a JSON object"))?; let crate_name = obj .get("name") - .and_then(|n| n.as_string()) + .and_then(|n| n.as_str()) .ok_or_else(|| err_msg("`name` not found in JSON object"))?; let vers = obj .get("vers") - .and_then(|n| n.as_string()) + .and_then(|n| n.as_str()) .ok_or_else(|| err_msg("`vers` not found in JSON object"))?; // Skip yanked crates - if obj - .get("yanked") - .and_then(|n| n.as_boolean()) - .unwrap_or(false) - { + if obj.get("yanked").and_then(|n| n.as_bool()).unwrap_or(false) { continue; } diff --git a/src/docbuilder/limits.rs b/src/docbuilder/limits.rs index c0a368434..3db3c45fc 100644 --- a/src/docbuilder/limits.rs +++ b/src/docbuilder/limits.rs @@ -3,7 +3,7 @@ use postgres::Connection; use std::collections::BTreeMap; use std::time::Duration; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct Limits { memory: usize, targets: usize, diff --git a/src/docbuilder/rustwide_builder.rs b/src/docbuilder/rustwide_builder.rs index 437e542df..5b9e05251 100644 --- a/src/docbuilder/rustwide_builder.rs +++ b/src/docbuilder/rustwide_builder.rs @@ -10,11 +10,11 @@ use crate::utils::{copy_doc_dir, parse_rustc_version, CargoMetadata}; use failure::ResultExt; use log::{debug, info, warn, LevelFilter}; use postgres::Connection; -use rustc_serialize::json::ToJson; use rustwide::cmd::{Command, SandboxBuilder}; use rustwide::logging::{self, LogStorage}; use rustwide::toolchain::ToolchainError; use rustwide::{Build, Crate, Toolchain, Workspace, WorkspaceBuilder}; +use serde_json::Value; use std::borrow::Cow; use std::collections::HashSet; use std::path::Path; @@ -246,7 +246,7 @@ impl RustwideBuilder { conn.query( "INSERT INTO config (name, value) VALUES ('rustc_version', $1) \ ON CONFLICT (name) DO UPDATE SET value = $1;", - &[&self.rustc_version.to_json()], + &[&Value::String(self.rustc_version.clone())], )?; Ok(()) diff --git a/src/index/api.rs b/src/index/api.rs index d85e8d7db..3dd480d34 100644 --- a/src/index/api.rs +++ b/src/index/api.rs @@ -4,7 +4,7 @@ use crate::{error::Result, utils::MetadataPackage}; use failure::err_msg; use reqwest::{header::ACCEPT, Client}; -use rustc_serialize::json::Json; +use serde_json::Value; use time::Timespec; pub(crate) struct RegistryCrateData { @@ -47,7 +47,7 @@ fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(time::Tim .send()?; let mut body = String::new(); res.read_to_string(&mut body).unwrap(); - let json = Json::from_str(&body[..]).unwrap(); + let json: Value = serde_json::from_str(&body[..])?; let versions = json .as_object() .and_then(|o| o.get("versions")) @@ -62,13 +62,13 @@ fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(time::Tim .ok_or_else(|| err_msg("Not a JSON object"))?; let version_num = version .get("num") - .and_then(|v| v.as_string()) + .and_then(|v| v.as_str()) .ok_or_else(|| err_msg("Not a JSON object"))?; if semver::Version::parse(version_num).unwrap().to_string() == pkg.version { let release_time_raw = version .get("created_at") - .and_then(|c| c.as_string()) + .and_then(|c| c.as_str()) .ok_or_else(|| err_msg("Not a JSON object"))?; release_time = Some( time::strptime(release_time_raw, "%Y-%m-%dT%H:%M:%S") @@ -79,7 +79,7 @@ fn get_release_time_yanked_downloads(pkg: &MetadataPackage) -> Result<(time::Tim yanked = Some( version .get("yanked") - .and_then(|c| c.as_boolean()) + .and_then(|c| c.as_bool()) .ok_or_else(|| err_msg("Not a JSON object"))?, ); @@ -114,7 +114,7 @@ fn get_owners(pkg: &MetadataPackage) -> Result> { // and so many unwraps... let mut body = String::new(); res.read_to_string(&mut body).unwrap(); - let json = Json::from_str(&body[..])?; + let json: Value = serde_json::from_str(&body[..])?; let mut result = Vec::new(); if let Some(owners) = json @@ -127,22 +127,22 @@ fn get_owners(pkg: &MetadataPackage) -> Result> { let avatar = owner .as_object() .and_then(|o| o.get("avatar")) - .and_then(|o| o.as_string()) + .and_then(|o| o.as_str()) .unwrap_or(""); let email = owner .as_object() .and_then(|o| o.get("email")) - .and_then(|o| o.as_string()) + .and_then(|o| o.as_str()) .unwrap_or(""); let login = owner .as_object() .and_then(|o| o.get("login")) - .and_then(|o| o.as_string()) + .and_then(|o| o.as_str()) .unwrap_or(""); let name = owner .as_object() .and_then(|o| o.get("name")) - .and_then(|o| o.as_string()) + .and_then(|o| o.as_str()) .unwrap_or(""); if login.is_empty() { diff --git a/src/utils/cargo_metadata.rs b/src/utils/cargo_metadata.rs index 769c01f3e..0894f1ddf 100644 --- a/src/utils/cargo_metadata.rs +++ b/src/utils/cargo_metadata.rs @@ -1,5 +1,6 @@ use crate::error::Result; use rustwide::{cmd::Command, Toolchain, Workspace}; +use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; use std::path::Path; @@ -23,7 +24,7 @@ impl CargoMetadata { let mut iter = res.stdout_lines().iter(); let metadata = if let (Some(serialized), None) = (iter.next(), iter.next()) { - ::rustc_serialize::json::decode::(serialized)? + serde_json::from_str::(serialized)? } else { return Err(::failure::err_msg( "invalid output returned by `cargo metadata`", @@ -61,7 +62,7 @@ impl CargoMetadata { } } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] pub(crate) struct Package { pub(crate) id: String, pub(crate) name: String, @@ -104,7 +105,7 @@ impl Package { } } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] pub(crate) struct Target { pub(crate) name: String, #[cfg(not(test))] @@ -125,32 +126,32 @@ impl Target { } } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] pub(crate) struct Dependency { pub(crate) name: String, pub(crate) req: String, pub(crate) kind: Option, } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] struct DeserializedMetadata { packages: Vec, resolve: DeserializedResolve, } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] struct DeserializedResolve { root: String, nodes: Vec, } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] struct DeserializedResolveNode { id: String, deps: Vec, } -#[derive(RustcDecodable)] +#[derive(Deserialize, Serialize)] struct DeserializedResolveDep { pkg: String, } diff --git a/src/utils/github_updater.rs b/src/utils/github_updater.rs index 8cd96fd14..557343f42 100644 --- a/src/utils/github_updater.rs +++ b/src/utils/github_updater.rs @@ -2,6 +2,7 @@ use crate::{db::connect_db, error::Result}; use failure::err_msg; use log::debug; use regex::Regex; +use std::str::FromStr; /// Fields we need use in cratesfyi #[derive(Debug)] @@ -72,7 +73,7 @@ pub fn github_updater() -> Result<()> { } fn get_github_fields(path: &str) -> Result { - use rustc_serialize::json::Json; + use serde_json::Value; let body = { use reqwest::header::USER_AGENT; @@ -105,13 +106,13 @@ fn get_github_fields(path: &str) -> Result { body }; - let json = Json::from_str(&body[..])?; + let json = Value::from_str(&body[..])?; let obj = json.as_object().unwrap(); Ok(GitHubFields { description: obj .get("description") - .and_then(|d| d.as_string()) + .and_then(|d| d.as_str()) .unwrap_or("") .to_string(), stars: obj @@ -121,9 +122,7 @@ fn get_github_fields(path: &str) -> Result { forks: obj.get("forks_count").and_then(|d| d.as_i64()).unwrap_or(0), issues: obj.get("open_issues").and_then(|d| d.as_i64()).unwrap_or(0), last_commit: time::strptime( - obj.get("pushed_at") - .and_then(|d| d.as_string()) - .unwrap_or(""), + obj.get("pushed_at").and_then(|d| d.as_str()).unwrap_or(""), "%Y-%m-%dT%H:%M:%S", ) .unwrap_or_else(|_| time::now()) diff --git a/src/utils/release_activity_updater.rs b/src/utils/release_activity_updater.rs index 693d7f7be..c6d21caf0 100644 --- a/src/utils/release_activity_updater.rs +++ b/src/utils/release_activity_updater.rs @@ -1,7 +1,6 @@ use crate::db::connect_db; use crate::error::Result; -use rustc_serialize::json::ToJson; -use std::collections::BTreeMap; +use serde_json::{Map, Value}; use time::{now, Duration}; pub fn update_release_activity() -> Result<()> { @@ -52,12 +51,12 @@ pub fn update_release_activity() -> Result<()> { failure_counts.reverse(); let map = { - let mut map = BTreeMap::new(); - map.insert("dates".to_owned(), dates.to_json()); - map.insert("counts".to_owned(), crate_counts.to_json()); - map.insert("failures".to_owned(), failure_counts.to_json()); + let mut map = Map::new(); + map.insert("dates".to_owned(), serde_json::to_value(dates)?); + map.insert("counts".to_owned(), serde_json::to_value(crate_counts)?); + map.insert("failures".to_owned(), serde_json::to_value(failure_counts)?); - map.to_json() + Value::Object(map) }; conn.query( diff --git a/src/web/builds.rs b/src/web/builds.rs index 9b4bae620..b223a8c51 100644 --- a/src/web/builds.rs +++ b/src/web/builds.rs @@ -5,10 +5,9 @@ use super::MetaData; use crate::docbuilder::Limits; use iron::prelude::*; use router::Router; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; +use serde::ser::{Serialize, SerializeStruct, Serializer}; -#[derive(Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] struct Build { id: i32, rustc_version: String, @@ -18,6 +17,28 @@ struct Build { output: Option, } +impl Serialize for Build { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("Build", 7)?; + state.serialize_field("id", &self.id)?; + state.serialize_field("rustc_version", &self.rustc_version)?; + state.serialize_field("cratesfyi_version", &self.cratesfyi_version)?; + state.serialize_field("build_status", &self.build_status)?; + state.serialize_field( + "build_time", + &time::at(self.build_time).rfc3339().to_string(), + )?; + state.serialize_field("build_time_relative", &duration_to_str(self.build_time))?; + state.serialize_field("output", &self.output)?; + + state.end() + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] struct BuildsPage { metadata: Option, builds: Vec, @@ -25,37 +46,18 @@ struct BuildsPage { limits: Limits, } -impl ToJson for Build { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("id".to_owned(), self.id.to_json()); - m.insert("rustc_version".to_owned(), self.rustc_version.to_json()); - m.insert( - "cratesfyi_version".to_owned(), - self.cratesfyi_version.to_json(), - ); - m.insert("build_status".to_owned(), self.build_status.to_json()); - m.insert( - "build_time".to_owned(), - format!("{}", time::at(self.build_time).rfc3339()).to_json(), - ); - m.insert( - "build_time_relative".to_owned(), - duration_to_str(self.build_time).to_json(), - ); - m.insert("output".to_owned(), self.output.to_json()); - m.to_json() - } -} +impl Serialize for BuildsPage { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("Buildspage", 4)?; + state.serialize_field("metadata", &self.metadata)?; + state.serialize_field("builds", &self.builds)?; + state.serialize_field("build_details", &self.build_details)?; + state.serialize_field("limits", &self.limits.for_website())?; -impl ToJson for BuildsPage { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("metadata".to_owned(), self.metadata.to_json()); - m.insert("builds".to_owned(), self.builds.to_json()); - m.insert("build_details".to_owned(), self.build_details.to_json()); - m.insert("limits".into(), self.limits.for_website().to_json()); - m.to_json() + state.end() } } @@ -120,7 +122,7 @@ pub fn build_list_handler(req: &mut Request) -> IronResult { build.output = None; } - let mut resp = Response::with((status::Ok, build_list.to_json().to_string())); + let mut resp = Response::with((status::Ok, serde_json::to_string(&build_list).unwrap())); resp.headers .set(ContentType("application/json".parse().unwrap())); resp.headers.set(Expires(HttpDate(time::now()))); @@ -148,7 +150,7 @@ pub fn build_list_handler(req: &mut Request) -> IronResult { #[cfg(test)] mod tests { use super::*; - use rustc_serialize::json::Json; + use serde_json::json; #[test] fn serialize_build() { @@ -162,48 +164,30 @@ mod tests { output: None, }; - let correct_json = format!( - r#"{{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{}", - "build_time_relative": "{}", - "output": null, - "build_status": true - }}"#, - time::at(time).rfc3339().to_string(), - duration_to_str(time), - ); + let correct_json = json!({ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": null, + "build_status": true + }); - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes the `id`s unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - build.to_json().to_string() - ); + assert_eq!(correct_json, serde_json::to_value(&build).unwrap()); build.output = Some("some random stuff".to_string()); - let correct_json = format!( - r#"{{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{}", - "build_time_relative": "{}", - "output": "some random stuff", - "build_status": true - }}"#, - time::at(time).rfc3339().to_string(), - duration_to_str(time), - ); + let correct_json = json!({ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": "some random stuff", + "build_status": true + }); - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes the `id`s unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - build.to_json().to_string() - ); + assert_eq!(correct_json, serde_json::to_value(&build).unwrap()); } #[test] @@ -232,128 +216,90 @@ mod tests { limits: limits.clone(), }; - let correct_json = format!( - r#"{{ - "metadata": {{ - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }}, - "builds": [{{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{time}", - "build_time_relative": "{time_rel}", - "output": null, - "build_status": true - }}], - "build_details": {{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{time}", - "build_time_relative": "{time_rel}", - "output": null, - "build_status": true - }}, - "limits": {} - }}"#, - limits.for_website().to_json().to_string(), - time = time::at(time).rfc3339().to_string(), - time_rel = duration_to_str(time), - ); + let correct_json = json!({ + "metadata": { + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }, + "builds": [{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": null, + "build_status": true + }], + "build_details": { + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": null, + "build_status": true + }, + "limits": limits.for_website(), + }); - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes the `id`s unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - builds.to_json().to_string() - ); + assert_eq!(correct_json, serde_json::to_value(&builds).unwrap()); builds.metadata = None; - let correct_json = format!( - r#"{{ - "metadata": null, - "builds": [{{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{time}", - "build_time_relative": "{time_rel}", - "output": null, - "build_status": true - }}], - "build_details": {{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{time}", - "build_time_relative": "{time_rel}", - "output": null, - "build_status": true - }}, - "limits": {} - }}"#, - limits.for_website().to_json().to_string(), - time = time::at(time).rfc3339().to_string(), - time_rel = duration_to_str(time), - ); + let correct_json = json!({ + "metadata": null, + "builds": [{ + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": null, + "build_status": true + }], + "build_details": { + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": null, + "build_status": true + }, + "limits": limits.for_website(), + }); - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes the `id`s unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - builds.to_json().to_string() - ); + assert_eq!(correct_json, serde_json::to_value(&builds).unwrap()); builds.builds = Vec::new(); - let correct_json = format!( - r#"{{ - "metadata": null, - "builds": [], - "build_details": {{ - "id": 22, - "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", - "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", - "build_time": "{time}", - "build_time_relative": "{time_rel}", - "output": null, - "build_status": true - }}, - "limits": {} - }}"#, - limits.for_website().to_json().to_string(), - time = time::at(time).rfc3339().to_string(), - time_rel = duration_to_str(time), - ); + let correct_json = json!({ + "metadata": null, + "builds": [], + "build_details": { + "id": 22, + "rustc_version": "rustc 1.43.0 (4fb7144ed 2020-04-20)", + "cratesfyi_version": "docsrs 0.6.0 (3dd32ec 2020-05-01)", + "build_time": time::at(time).rfc3339().to_string(), + "build_time_relative": duration_to_str(time), + "output": null, + "build_status": true + }, + "limits": limits.for_website() + }); - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes the `id`s unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - builds.to_json().to_string() - ); + assert_eq!(correct_json, serde_json::to_value(&builds).unwrap()); builds.build_details = None; - let correct_json = format!( - r#"{{ - "metadata": null, - "builds": [], - "build_details": null, - "limits": {} - }}"#, - limits.for_website().to_json().to_string(), - ); + let correct_json = json!({ + "metadata": null, + "builds": [], + "build_details": null, + "limits": limits.for_website(), + }); - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes the `id`s unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - builds.to_json().to_string() - ); + assert_eq!(correct_json, serde_json::to_value(&builds).unwrap()); } } diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 51d2bb34d..95345c9e5 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -8,8 +8,8 @@ use iron::prelude::*; use iron::{status, Url}; use postgres::Connection; use router::Router; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; +use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde_json::Value; // TODO: Add target name and versions @@ -20,8 +20,8 @@ pub struct CrateDetails { description: Option, authors: Vec<(String, String)>, owners: Vec<(String, String)>, - authors_json: Option, - dependencies: Option, + authors_json: Option, + dependencies: Option, readme: Option, rustdoc: Option, // this is description_long in database release_time: time::Timespec, @@ -30,7 +30,7 @@ pub struct CrateDetails { rustdoc_status: bool, repository_url: Option, homepage_url: Option, - keywords: Option, + keywords: Option, have_examples: bool, // need to check this manually pub target_name: String, releases: Vec, @@ -46,72 +46,61 @@ pub struct CrateDetails { documentation_url: Option, } -impl ToJson for CrateDetails { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("name".to_string(), self.name.to_json()); - m.insert("version".to_string(), self.version.to_json()); - m.insert("description".to_string(), self.description.to_json()); - m.insert("authors".to_string(), self.authors.to_json()); - m.insert("owners".to_string(), self.owners.to_json()); - m.insert("authors_json".to_string(), self.authors_json.to_json()); - m.insert("dependencies".to_string(), self.dependencies.to_json()); +impl Serialize for CrateDetails { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("CrateDetails", 28)?; + state.serialize_field("metadata", &self.metadata)?; + state.serialize_field("name", &self.name)?; + state.serialize_field("version", &self.version)?; + state.serialize_field("description", &self.description)?; + state.serialize_field("authors", &self.authors)?; + state.serialize_field("owners", &self.owners)?; + state.serialize_field("authors_json", &self.authors_json)?; + state.serialize_field("dependencies", &self.dependencies)?; + if let Some(ref readme) = self.readme { - m.insert("readme".to_string(), render_markdown(&readme).to_json()); + state.serialize_field("readme", &render_markdown(&readme))?; } + if let Some(ref rustdoc) = self.rustdoc { - m.insert("rustdoc".to_string(), render_markdown(&rustdoc).to_json()); + state.serialize_field("rustdoc", &render_markdown(&rustdoc))?; } - m.insert( - "release_time".to_string(), - duration_to_str(self.release_time).to_json(), - ); - m.insert("build_status".to_string(), self.build_status.to_json()); - m.insert( - "last_successful_build".to_string(), - self.last_successful_build.to_json(), - ); - m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json()); - m.insert("repository_url".to_string(), self.repository_url.to_json()); - m.insert("homepage_url".to_string(), self.homepage_url.to_json()); - m.insert("keywords".to_string(), self.keywords.to_json()); - m.insert("have_examples".to_string(), self.have_examples.to_json()); - m.insert("target_name".to_string(), self.target_name.to_json()); - m.insert("releases".to_string(), self.releases.to_json()); - m.insert("github".to_string(), self.github.to_json()); - m.insert("github_stars".to_string(), self.github_stars.to_json()); - m.insert("github_forks".to_string(), self.github_forks.to_json()); - m.insert("github_issues".to_string(), self.github_issues.to_json()); - m.insert("metadata".to_string(), self.metadata.to_json()); - m.insert("is_library".to_string(), self.is_library.to_json()); - m.insert("yanked".to_string(), self.yanked.to_json()); - m.insert("doc_targets".to_string(), self.doc_targets.to_json()); - m.insert("license".to_string(), self.license.to_json()); - m.insert( - "documentation_url".to_string(), - self.documentation_url.to_json(), - ); - m.to_json() + + state.serialize_field("release_time", &duration_to_str(self.release_time))?; + state.serialize_field("build_status", &self.build_status)?; + state.serialize_field("last_successful_build", &self.last_successful_build)?; + state.serialize_field("rustdoc_status", &self.rustdoc_status)?; + state.serialize_field("repository_url", &self.repository_url)?; + state.serialize_field("homepage_url", &self.homepage_url)?; + state.serialize_field("keywords", &self.keywords)?; + state.serialize_field("have_examples", &self.have_examples)?; + state.serialize_field("target_name", &self.target_name)?; + state.serialize_field("releases", &self.releases)?; + state.serialize_field("github", &self.github)?; + state.serialize_field("github_stars", &self.github_stars)?; + state.serialize_field("github_forks", &self.github_forks)?; + state.serialize_field("github_issues", &self.github_issues)?; + state.serialize_field("metadata", &self.metadata)?; + state.serialize_field("is_library", &self.is_library)?; + state.serialize_field("doc_targets", &self.doc_targets)?; + state.serialize_field("yanked", &self.yanked)?; + state.serialize_field("license", &self.license)?; + state.serialize_field("documentation_url", &self.documentation_url)?; + + state.end() } } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, serde::Serialize)] pub struct Release { pub version: String, pub build_status: bool, pub yanked: bool, } -impl ToJson for Release { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("version".to_string(), self.version.to_json()); - m.insert("build_status".to_string(), self.build_status.to_json()); - m.insert("yanked".to_string(), self.yanked.to_json()); - m.to_json() - } -} - impl CrateDetails { pub fn new(conn: &Connection, name: &str, version: &str) -> Option { // get all stuff, I love you rustfmt @@ -158,11 +147,11 @@ impl CrateDetails { // sort versions with semver let releases = { let mut versions: Vec = Vec::new(); - let versions_from_db: Json = rows.get(0).get(17); + let versions_from_db: Value = rows.get(0).get(17); if let Some(vers) = versions_from_db.as_array() { for version in vers { - if let Some(version) = version.as_string() { + if let Some(version) = version.as_str() { if let Ok(sem_ver) = semver::Version::parse(&version) { versions.push(sem_ver); } @@ -188,12 +177,12 @@ impl CrateDetails { }; let doc_targets = { - let data: Json = rows.get(0).get(23); + let data: Value = rows.get(0).get(23); data.as_array() .map(|array| { array .iter() - .filter_map(|item| item.as_string().map(|s| s.to_owned())) + .filter_map(|item| item.as_str().map(|s| s.to_owned())) .collect() }) .unwrap_or_else(Vec::new) @@ -308,6 +297,7 @@ impl CrateDetails { target_name: "x86_64-unknown-linux-gnu".to_string(), releases: vec![], github: true, + yanked: false, github_stars: None, github_forks: None, github_issues: None, @@ -384,6 +374,7 @@ mod tests { use super::*; use crate::test::TestDatabase; use failure::Error; + use serde_json::json; fn assert_last_successful_build_equals( db: &TestDatabase, @@ -634,96 +625,88 @@ mod tests { let time = time::get_time(); let mut details = CrateDetails::default_tester(time); - let correct_json = Json::from_str(&format!( - r#"{{ - "name": "rcc", - "version": "100.0.0", - "description": null, - "authors": [], - "owners": [], - "authors_json": null, - "dependencies": null, - "release_time": "{}", - "build_status": true, - "last_successful_build": null, + let correct_json = json!({ + "name": "rcc", + "version": "100.0.0", + "description": null, + "authors": [], + "owners": [], + "authors_json": null, + "dependencies": null, + "release_time": super::super::duration_to_str(time), + "build_status": true, + "last_successful_build": null, + "rustdoc_status": true, + "repository_url": null, + "homepage_url": null, + "keywords": null, + "have_examples": true, + "target_name": "x86_64-unknown-linux-gnu", + "releases": [], + "github": true, + "github_stars": null, + "github_forks": null, + "github_issues": null, + "metadata": { + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, "rustdoc_status": true, - "repository_url": null, - "homepage_url": null, - "keywords": null, - "have_examples": true, - "target_name": "x86_64-unknown-linux-gnu", - "releases": [], - "github": true, - "github_stars": null, - "github_forks": null, - "github_issues": null, - "metadata": {{ - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }}, - "is_library": true, - "doc_targets": [], - "license": null, - "documentation_url": null - }}"#, - super::super::duration_to_str(time), - )) - .unwrap(); + "default_target": "x86_64-unknown-linux-gnu" + }, + "is_library": true, + "doc_targets": [], + "license": null, + "documentation_url": null + }); - assert_eq!(correct_json, details.to_json()); + assert_eq!(correct_json, serde_json::to_value(&details).unwrap()); details.description = Some("serde does stuff".to_string()); details.owners = vec![("Owner".to_string(), "owner@ownsstuff.com".to_string())]; let authors = vec![("Somebody".to_string(), "somebody@somebody.com".to_string())]; - details.authors_json = Some(authors.to_json()); + details.authors_json = Some(serde_json::to_value(&authors).unwrap()); details.authors = authors; - let correct_json = Json::from_str(&format!( - r#"{{ - "name": "rcc", - "version": "100.0.0", + let correct_json = json!({ + "name": "rcc", + "version": "100.0.0", + "description": "serde does stuff", + "authors": [["Somebody", "somebody@somebody.com"]], + "owners": [["Owner", "owner@ownsstuff.com"]], + "authors_json": [["Somebody", "somebody@somebody.com"]], + "dependencies": null, + "release_time": super::super::duration_to_str(time), + "build_status": true, + "last_successful_build": null, + "rustdoc_status": true, + "repository_url": null, + "homepage_url": null, + "keywords": null, + "have_examples": true, + "target_name": "x86_64-unknown-linux-gnu", + "releases": [], + "github": true, + "github_stars": null, + "github_forks": null, + "github_issues": null, + "metadata": { + "name": "serde", + "version": "1.0.0", "description": "serde does stuff", - "authors": [["Somebody", "somebody@somebody.com"]], - "owners": [["Owner", "owner@ownsstuff.com"]], - "authors_json": [["Somebody", "somebody@somebody.com"]], - "dependencies": null, - "release_time": "{}", - "build_status": true, - "last_successful_build": null, + "target_name": null, "rustdoc_status": true, - "repository_url": null, - "homepage_url": null, - "keywords": null, - "have_examples": true, - "target_name": "x86_64-unknown-linux-gnu", - "releases": [], - "github": true, - "github_stars": null, - "github_forks": null, - "github_issues": null, - "metadata": {{ - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }}, - "is_library": true, - "doc_targets": [], - "license": null, - "documentation_url": null - }}"#, - super::super::duration_to_str(time), - )) - .unwrap(); + "default_target": "x86_64-unknown-linux-gnu" + }, + "is_library": true, + "doc_targets": [], + "license": null, + "documentation_url": null + }); - assert_eq!(correct_json, details.to_json()); + assert_eq!(correct_json, serde_json::to_value(&details).unwrap()); } #[test] @@ -734,14 +717,11 @@ mod tests { yanked: true, }; - let correct_json = Json::from_str( - r#"{ - "version": "idkman", - "build_status": true - }"#, - ) - .unwrap(); + let correct_json = json!({ + "version": "idkman", + "build_status": true + }); - assert_eq!(correct_json, release.to_json()); + assert_eq!(correct_json, serde_json::to_value(&release).unwrap()); } } diff --git a/src/web/mod.rs b/src/web/mod.rs index eba5a328a..88dc7e980 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -63,14 +63,10 @@ use iron::prelude::*; use iron::{self, status, Handler, Listening, Url}; use postgres::Connection; use router::NoRoute; -use rustc_serialize::json::{Json, ToJson}; use semver::{Version, VersionReq}; use staticfile::Static; -use std::collections::BTreeMap; use std::net::SocketAddr; -use std::path::PathBuf; -use std::time::Duration; -use std::{env, fmt}; +use std::{env, fmt, path::PathBuf, time::Duration}; #[cfg(test)] use std::sync::{Arc, Mutex}; @@ -514,7 +510,7 @@ fn ico_handler(req: &mut Request) -> IronResult { } /// MetaData used in header -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] pub(crate) struct MetaData { pub(crate) name: String, pub(crate) version: String, @@ -554,20 +550,6 @@ impl MetaData { } } -impl ToJson for MetaData { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("name".to_owned(), self.name.to_json()); - m.insert("version".to_owned(), self.version.to_json()); - m.insert("description".to_owned(), self.description.to_json()); - m.insert("target_name".to_owned(), self.target_name.to_json()); - m.insert("rustdoc_status".to_owned(), self.rustdoc_status.to_json()); - m.insert("default_target".to_owned(), self.default_target.to_json()); - - m.to_json() - } -} - #[cfg(test)] mod test { use super::*; @@ -576,7 +558,7 @@ mod test { web::{handlebars_engine, match_version}, }; use html5ever::tendril::TendrilSink; - use rustc_serialize::json::Json; + use serde_json::json; fn release(version: &str, db: &TestDatabase) -> i32 { db.fake_release() @@ -788,6 +770,7 @@ mod test { handlebars_engine().expect("Failed to load handlebar templates"); } + #[test] fn serialize_metadata() { let mut metadata = MetaData { name: "serde".to_string(), @@ -798,48 +781,39 @@ mod test { default_target: "x86_64-unknown-linux-gnu".to_string(), }; - let correct_json = Json::from_str( - r#"{ - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }"#, - ) - .unwrap(); + let correct_json = json!({ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }); - assert_eq!(correct_json, metadata.to_json()); + assert_eq!(correct_json, serde_json::to_value(&metadata).unwrap()); metadata.target_name = Some("x86_64-apple-darwin".to_string()); - let correct_json = Json::from_str( - r#"{ - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": "x86_64-apple-darwin", - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }"#, - ) - .unwrap(); + let correct_json = json!({ + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": "x86_64-apple-darwin", + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }); - assert_eq!(correct_json, metadata.to_json()); + assert_eq!(correct_json, serde_json::to_value(&metadata).unwrap()); metadata.description = None; - let correct_json = Json::from_str( - r#"{ - "name": "serde", - "version": "1.0.0", - "description": null, - "target_name": "x86_64-apple-darwin", - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }"#, - ) - .unwrap(); + let correct_json = json!({ + "name": "serde", + "version": "1.0.0", + "description": null, + "target_name": "x86_64-apple-darwin", + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }); - assert_eq!(correct_json, metadata.to_json()); + assert_eq!(correct_json, serde_json::to_value(&metadata).unwrap()); } } diff --git a/src/web/page.rs b/src/web/page.rs index 85cfbceaa..f09b386ee 100644 --- a/src/web/page.rs +++ b/src/web/page.rs @@ -3,7 +3,8 @@ use handlebars_iron::Template; use iron::response::Response; use iron::{status, IronResult, Set}; -use rustc_serialize::json::{Json, ToJson}; +use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde_json::Value; use std::collections::BTreeMap; lazy_static::lazy_static! { @@ -22,8 +23,8 @@ fn load_rustc_resource_suffix() -> Result { failure::bail!("missing rustc version"); } - if let Some(Ok(vers)) = res.get(0).get_opt::<_, Json>("value") { - if let Some(vers_str) = vers.as_string() { + if let Some(Ok(vers)) = res.get(0).get_opt::<_, Value>("value") { + if let Some(vers_str) = vers.as_str() { return Ok(crate::utils::parse_rustc_version(vers_str)?); } } @@ -31,7 +32,7 @@ fn load_rustc_resource_suffix() -> Result { failure::bail!("failed to parse the rustc version"); } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize)] pub(crate) struct GlobalAlert { pub(crate) url: &'static str, pub(crate) text: &'static str, @@ -39,19 +40,8 @@ pub(crate) struct GlobalAlert { pub(crate) fa_icon: &'static str, } -impl ToJson for GlobalAlert { - fn to_json(&self) -> Json { - let mut map = BTreeMap::new(); - map.insert("url".to_string(), self.url.to_json()); - map.insert("text".to_string(), self.text.to_json()); - map.insert("css_class".to_string(), self.css_class.to_json()); - map.insert("fa_icon".to_string(), self.fa_icon.to_json()); - Json::Object(map) - } -} - #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Page { +pub struct Page { title: Option, content: T, status: status::Status, @@ -61,7 +51,7 @@ pub struct Page { rustc_resource_suffix: &'static str, } -impl Page { +impl Page { pub fn new(content: T) -> Page { Page { title: None, @@ -121,43 +111,37 @@ impl Page { } } -impl ToJson for Page { - fn to_json(&self) -> Json { - let mut tree = BTreeMap::new(); +impl Serialize for Page { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("Page", 10)?; if let Some(ref title) = self.title { - tree.insert("title".to_owned(), title.to_json()); + state.serialize_field("title", title)?; } - tree.insert( - "has_global_alert".to_owned(), - crate::GLOBAL_ALERT.is_some().to_json(), - ); + state.serialize_field("has_global_alert", &crate::GLOBAL_ALERT.is_some())?; if let Some(ref global_alert) = crate::GLOBAL_ALERT { - tree.insert("global_alert".to_owned(), global_alert.to_json()); + state.serialize_field("global_alert", global_alert)?; } - tree.insert("content".to_owned(), self.content.to_json()); - tree.insert( - "rustc_resource_suffix".to_owned(), - self.rustc_resource_suffix.to_json(), - ); - tree.insert( - "cratesfyi_version".to_owned(), - crate::BUILD_VERSION.to_json(), - ); - tree.insert( - "cratesfyi_version_safe".to_owned(), - crate::BUILD_VERSION + state.serialize_field("content", &self.content)?; + state.serialize_field("rustc_resource_suffix", self.rustc_resource_suffix)?; + state.serialize_field("cratesfyi_version", crate::BUILD_VERSION)?; + state.serialize_field( + "cratesfyi_version_safe", + &crate::BUILD_VERSION .replace(" ", "-") .replace("(", "") - .replace(")", "") - .to_json(), - ); - tree.insert("varss".to_owned(), self.varss.to_json()); - tree.insert("varsb".to_owned(), self.varsb.to_json()); - tree.insert("varsi".to_owned(), self.varsi.to_json()); - Json::Object(tree) + .replace(")", ""), + )?; + state.serialize_field("varss", &self.varss)?; + state.serialize_field("varsb", &self.varsb)?; + state.serialize_field("varsi", &self.varsi)?; + + state.end() } } @@ -165,7 +149,7 @@ impl ToJson for Page { mod tests { use super::super::releases::{self, Release}; use super::*; - use rustc_serialize::json::Json; + use serde_json::json; #[test] fn serialize_page() { @@ -193,43 +177,30 @@ mod tests { rustc_resource_suffix: &*RUSTC_RESOURCE_SUFFIX, }; - let correct_json = format!( - r#"{{ - "content": [{{ - "name": "lasso", - "version": "0.1.0", - "description": null, - "target_name": null, - "rustdoc_status": false, - "release_time": "{}", - "release_time_rfc3339": "{}", - "stars": 0 - }}], - "varss": {{ "test": "works" }}, - "varsb": {{ "test2": true }}, - "varsi": {{ "test3": 1337 }}, - "rustc_resource_suffix": "{}", - "cratesfyi_version": "{}", - "cratesfyi_version_safe": "{}", - "has_global_alert": {} - }}"#, - super::super::duration_to_str(time.clone()), - time::at(time).rfc3339().to_string(), - &*RUSTC_RESOURCE_SUFFIX, - crate::BUILD_VERSION, - crate::BUILD_VERSION + let correct_json = json!({ + "content": [{ + "name": "lasso", + "version": "0.1.0", + "description": null, + "target_name": null, + "rustdoc_status": false, + "release_time": super::super::duration_to_str(time), + "release_time_rfc3339": time::at(time).rfc3339().to_string(), + "stars": 0 + }], + "varss": { "test": "works" }, + "varsb": { "test2": true }, + "varsi": { "test3": 1337 }, + "rustc_resource_suffix": &*RUSTC_RESOURCE_SUFFIX, + "cratesfyi_version": crate::BUILD_VERSION, + "cratesfyi_version_safe": crate::BUILD_VERSION .replace(" ", "-") .replace("(", "") .replace(")", ""), - crate::GLOBAL_ALERT.is_some(), - ); - - // Have to call `.to_string()` here because for some reason rustc_serialize defaults to - // u64s for `Json::from_str`, which makes everything in the respective `varsi` unequal - assert_eq!( - Json::from_str(&correct_json).unwrap().to_string(), - page.to_json().to_string() - ); + "has_global_alert": crate::GLOBAL_ALERT.is_some() + }); + + assert_eq!(correct_json, serde_json::to_value(&page).unwrap()); } #[test] @@ -272,16 +243,13 @@ mod tests { fa_icon: "https://gph.is/1uOvmqR", }; - let correct_json = Json::from_str( - r#"{ + let correct_json = json!({ "url": "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/", "text": "THE WORLD IS ENDING", "css_class": "THE END IS NEAR", "fa_icon": "https://gph.is/1uOvmqR" - }"#, - ) - .unwrap(); + }); - assert_eq!(correct_json, alert.to_json()); + assert_eq!(correct_json, serde_json::to_value(&alert).unwrap()); } } diff --git a/src/web/releases.rs b/src/web/releases.rs index cbce9e04b..2cbaa60d9 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -8,8 +8,8 @@ use iron::prelude::*; use iron::status; use postgres::Connection; use router::Router; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; +use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde_json::Value; /// Number of release in home page const RELEASES_IN_HOME: i64 = 15; @@ -43,24 +43,25 @@ impl Default for Release { } } -impl ToJson for Release { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("name".to_string(), self.name.to_json()); - m.insert("version".to_string(), self.version.to_json()); - m.insert("description".to_string(), self.description.to_json()); - m.insert("target_name".to_string(), self.target_name.to_json()); - m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json()); - m.insert( - "release_time".to_string(), - duration_to_str(self.release_time).to_json(), - ); - m.insert( - "release_time_rfc3339".to_string(), - time::at(self.release_time).rfc3339().to_string().to_json(), - ); - m.insert("stars".to_string(), self.stars.to_json()); - m.to_json() +impl Serialize for Release { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("Release", 8)?; + state.serialize_field("name", &self.name)?; + state.serialize_field("version", &self.version)?; + state.serialize_field("description", &self.description)?; + state.serialize_field("target_name", &self.target_name)?; + state.serialize_field("rustdoc_status", &self.rustdoc_status)?; + state.serialize_field("release_time", &duration_to_str(self.release_time))?; + state.serialize_field( + "release_time_rfc3339", + &time::at(self.release_time).rfc3339().to_string(), + )?; + state.serialize_field("stars", &self.stars)?; + + state.end() } } @@ -619,7 +620,7 @@ pub fn search_handler(req: &mut Request) -> IronResult { pub fn activity_handler(req: &mut Request) -> IronResult { let conn = extension!(req, Pool).get()?; - let release_activity_data: Json = ctry!(conn.query( + let release_activity_data: Value = ctry!(conn.query( "SELECT value FROM config WHERE name = 'release_activity'", &[] )) @@ -670,6 +671,7 @@ pub fn build_queue_handler(req: &mut Request) -> IronResult { mod tests { use super::*; use crate::test::wrapper; + use serde_json::json; #[test] fn database_search() { @@ -1015,63 +1017,45 @@ mod tests { stars: 100, }; - let correct_json = Json::from_str(&format!( - r#"{{ + let correct_json = json!({ "name": "serde", "version": "0.0.0", "description": "serde makes things other things", "target_name": "x86_64-pc-windows-msvc", "rustdoc_status": true, - "release_time": "{}", - "release_time_rfc3339": "{}", + "release_time": duration_to_str(time), + "release_time_rfc3339": time::at(time).rfc3339().to_string(), "stars": 100 - }}"#, - duration_to_str(time), - time::at(time).rfc3339().to_string(), - )) - .unwrap(); + }); - // Have to call `.to_string()` here because of how `rustc_serialize` handles integers - assert_eq!(correct_json.to_string(), release.to_json().to_string()); + assert_eq!(correct_json, serde_json::to_value(&release).unwrap()); release.target_name = None; - let correct_json = Json::from_str(&format!( - r#"{{ + let correct_json = json!({ "name": "serde", "version": "0.0.0", "description": "serde makes things other things", "target_name": null, "rustdoc_status": true, - "release_time": "{}", - "release_time_rfc3339": "{}", + "release_time": duration_to_str(time), + "release_time_rfc3339": time::at(time).rfc3339().to_string(), "stars": 100 - }}"#, - duration_to_str(time), - time::at(time).rfc3339().to_string(), - )) - .unwrap(); + }); - // Have to call `.to_string()` here because of how `rustc_serialize` handles integers - assert_eq!(correct_json.to_string(), release.to_json().to_string()); + assert_eq!(correct_json, serde_json::to_value(&release).unwrap()); release.description = None; - let correct_json = Json::from_str(&format!( - r#"{{ + let correct_json = json!({ "name": "serde", "version": "0.0.0", "description": null, "target_name": null, "rustdoc_status": true, - "release_time": "{}", - "release_time_rfc3339": "{}", + "release_time": duration_to_str(time), + "release_time_rfc3339": time::at(time).rfc3339().to_string(), "stars": 100 - }}"#, - duration_to_str(time), - time::at(time).rfc3339().to_string(), - )) - .unwrap(); - - // Have to call `.to_string()` here because of how `rustc_serialize` handles integers - assert_eq!(correct_json.to_string(), release.to_json().to_string()); + }); + + assert_eq!(correct_json, serde_json::to_value(&release).unwrap()); } } diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 6600a9ad8..e07b40a5f 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -15,8 +15,7 @@ use iron::Handler; use iron::{status, Url}; use postgres::Connection; use router::Router; -use rustc_serialize::json::{Json, ToJson}; -use std::collections::BTreeMap; +use serde::ser::{Serialize, SerializeStruct, Serializer}; #[derive(Debug, Default)] struct RustdocPage { @@ -30,19 +29,23 @@ struct RustdocPage { crate_details: Option, } -impl ToJson for RustdocPage { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - m.insert("rustdoc_head".to_string(), self.head.to_json()); - m.insert("rustdoc_body".to_string(), self.body.to_json()); - m.insert("rustdoc_body_class".to_string(), self.body_class.to_json()); - m.insert("rustdoc_full".to_string(), self.full.to_json()); - m.insert("rustdoc_status".to_string(), true.to_json()); - m.insert("name".to_string(), self.name.to_json()); - m.insert("version".to_string(), self.version.to_json()); - m.insert("description".to_string(), self.description.to_json()); - m.insert("crate_details".to_string(), self.crate_details.to_json()); - m.to_json() +impl Serialize for RustdocPage { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("RustdocPage", 9)?; + state.serialize_field("rustdoc_head", &self.head)?; + state.serialize_field("rustdoc_body", &self.body)?; + state.serialize_field("rustdoc_body_class", &self.body_class)?; + state.serialize_field("rustdoc_full", &self.full)?; + state.serialize_field("rustdoc_status", &true)?; + state.serialize_field("name", &self.name)?; + state.serialize_field("version", &self.version)?; + state.serialize_field("description", &self.description)?; + state.serialize_field("crate_details", &self.crate_details)?; + + state.end() } } @@ -544,6 +547,7 @@ mod test { use super::*; use crate::test::*; use reqwest::StatusCode; + use serde_json::json; use std::{collections::BTreeMap, iter::FromIterator}; fn try_latest_version_redirect( @@ -1345,46 +1349,44 @@ mod test { }) } + #[test] fn serialize_rustdoc_page() { let time = time::get_time(); - let details = format!( - r#"{{ - "name": "rcc", - "version": "100.0.0", - "description": null, - "authors": [], - "owners": [], - "authors_json": null, - "dependencies": null, - "release_time": "{}", - "build_status": true, - "last_successful_build": null, + let details = json!({ + "name": "rcc", + "version": "100.0.0", + "description": null, + "authors": [], + "owners": [], + "authors_json": null, + "dependencies": null, + "release_time": super::super::duration_to_str(time), + "build_status": true, + "last_successful_build": null, + "rustdoc_status": true, + "repository_url": null, + "homepage_url": null, + "keywords": null, + "have_examples": true, + "target_name": "x86_64-unknown-linux-gnu", + "releases": [], + "github": true, + "github_stars": null, + "github_forks": null, + "github_issues": null, + "metadata": { + "name": "serde", + "version": "1.0.0", + "description": "serde does stuff", + "target_name": null, "rustdoc_status": true, - "repository_url": null, - "homepage_url": null, - "keywords": null, - "have_examples": true, - "target_name": "x86_64-unknown-linux-gnu", - "releases": [], - "github": true, - "github_stars": null, - "github_forks": null, - "github_issues": null, - "metadata": {{ - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }}, - "is_library": true, - "doc_targets": [], - "license": null, - "documentation_url": null - }}"#, - super::super::duration_to_str(time), - ); + "default_target": "x86_64-unknown-linux-gnu" + }, + "is_library": true, + "doc_targets": [], + "license": null, + "documentation_url": null + }); let mut page = RustdocPage { head: "Whee".to_string(), @@ -1397,59 +1399,48 @@ mod test { crate_details: Some(CrateDetails::default_tester(time)), }; - let correct_json = Json::from_str(&format!( - r#"{{ - "rustdoc_head": "Whee", - "rustdoc_body": "

idk

", - "rustdoc_body_class": "docsrs-body", - "rustdoc_full": "??", - "rustdoc_status": true, - "name": "rcc", - "version": "100.0.100", - "description": "a Rust compiler in C. Wait, maybe the other way around", - "crate_details": {} - }}"#, - details, - )) - .unwrap(); + let correct_json = json!({ + "rustdoc_head": "Whee", + "rustdoc_body": "

idk

", + "rustdoc_body_class": "docsrs-body", + "rustdoc_full": "??", + "rustdoc_status": true, + "name": "rcc", + "version": "100.0.100", + "description": "a Rust compiler in C. Wait, maybe the other way around", + "crate_details": details + }); - assert_eq!(correct_json, page.to_json()); + assert_eq!(correct_json, serde_json::to_value(&page).unwrap()); page.description = None; - let correct_json = Json::from_str(&format!( - r#"{{ - "rustdoc_head": "Whee", - "rustdoc_body": "

idk

", - "rustdoc_body_class": "docsrs-body", - "rustdoc_full": "??", - "rustdoc_status": true, - "name": "rcc", - "version": "100.0.100", - "description": null, - "crate_details": {} - }}"#, - details, - )) - .unwrap(); + let correct_json = json!({ + "rustdoc_head": "Whee", + "rustdoc_body": "

idk

", + "rustdoc_body_class": "docsrs-body", + "rustdoc_full": "??", + "rustdoc_status": true, + "name": "rcc", + "version": "100.0.100", + "description": null, + "crate_details": details + }); - assert_eq!(correct_json, page.to_json()); + assert_eq!(correct_json, serde_json::to_value(&page).unwrap()); page.crate_details = None; - let correct_json = Json::from_str( - r#"{ - "rustdoc_head": "Whee", - "rustdoc_body": "

idk

", - "rustdoc_body_class": "docsrs-body", - "rustdoc_full": "??", - "rustdoc_status": true, - "name": "rcc", - "version": "100.0.100", - "description": null, - "crate_details": null - }"#, - ) - .unwrap(); + let correct_json = json!({ + "rustdoc_head": "Whee", + "rustdoc_body": "

idk

", + "rustdoc_body_class": "docsrs-body", + "rustdoc_full": "??", + "rustdoc_status": true, + "name": "rcc", + "version": "100.0.100", + "description": null, + "crate_details": null + }); - assert_eq!(correct_json, page.to_json()); + assert_eq!(correct_json, serde_json::to_value(&page).unwrap()); } } diff --git a/src/web/sitemap.rs b/src/web/sitemap.rs index 2eea4cd7d..fb1ffe7cc 100644 --- a/src/web/sitemap.rs +++ b/src/web/sitemap.rs @@ -2,7 +2,7 @@ use super::page::Page; use super::pool::Pool; use iron::headers::ContentType; use iron::prelude::*; -use rustc_serialize::json::{Json, ToJson}; +use serde_json::Value; use std::collections::BTreeMap; pub fn sitemap_handler(req: &mut Request) -> IronResult { @@ -41,16 +41,16 @@ pub fn about_handler(req: &mut Request) -> IronResult { let res = ctry!(conn.query("SELECT value FROM config WHERE name = 'rustc_version'", &[])); if let Some(row) = res.iter().next() { - if let Some(Ok::(res)) = row.get_opt(0) { - if let Some(vers) = res.as_string() { - content.insert("rustc_version".to_string(), vers.to_json()); + if let Some(Ok::(res)) = row.get_opt(0) { + if let Some(vers) = res.as_str() { + content.insert("rustc_version".to_string(), Value::String(vers.to_string())); } } } content.insert( "limits".to_string(), - crate::docbuilder::Limits::default().for_website().to_json(), + serde_json::to_value(&crate::docbuilder::Limits::default().for_website()).unwrap(), ); Page::new(content).title("About Docs.rs").to_resp("about") diff --git a/src/web/source.rs b/src/web/source.rs index 98f62e82a..0acff011b 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -7,19 +7,12 @@ use super::MetaData; use iron::prelude::*; use postgres::Connection; use router::Router; -use rustc_serialize::json::{Json, ToJson}; +use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde_json::Value; use std::cmp::Ordering; -use std::{collections::BTreeMap, iter::FromIterator}; +use std::collections::HashMap; /// A source file's type -/// -/// When serialized into json it takes this form -/// -/// * `FileType::Dir`: `{ "file_type_dir": true }` -/// * `FileType::Text`: `{ "file_type_text": true }` -/// * `FileType::Binary`: `{ "file_type_binary": true }` -/// * `FileType::RustSource`: `{ "file_type_rust_source": true }` -/// #[derive(PartialEq, PartialOrd)] enum FileType { Dir, @@ -28,66 +21,13 @@ enum FileType { RustSource, } -impl ToJson for FileType { - fn to_json(&self) -> Json { - let key = match self { - Self::Dir => "file_type_dir", - Self::Text => "file_type_text", - Self::Binary => "file_type_binary", - Self::RustSource => "file_type_rust_source", - }; - - Json::Object(BTreeMap::from_iter(vec![( - key.to_string(), - Json::Boolean(true), - )])) - } -} - /// A source file -/// -/// Rust: -/// -/// ```ignore -/// struct File { -/// name: "main.rs", -/// file_type: FileType::RustSource, -/// } -/// ``` -/// -/// Json: -/// -/// ```json -/// { -/// "name": "main.rs", -/// "file_type_rust_source": true, -/// } -/// ``` -/// #[derive(PartialEq, PartialOrd)] struct File { name: String, file_type: FileType, } -impl ToJson for File { - fn to_json(&self) -> Json { - let mut file_m: BTreeMap = BTreeMap::new(); - file_m.insert("name".to_string(), self.name.to_json()); - - let file_type = match self.file_type { - FileType::Dir => "file_type_dir", - FileType::Text => "file_type_text", - FileType::Binary => "file_type_binary", - FileType::RustSource => "file_type_rust_source", - }; - - file_m.insert(file_type.to_string(), true.to_json()); - - Json::Object(file_m) - } -} - /// A list of source files /// /// @@ -143,19 +83,18 @@ struct FileList { files: Vec, } -impl ToJson for FileList { - fn to_json(&self) -> Json { - let mut m: BTreeMap = BTreeMap::new(); - - m.insert("metadata".to_string(), self.metadata.to_json()); - - // TODO: file_vec from iter - - let mut file_vec: Vec = Vec::new(); +impl Serialize for FileList { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("FileList", 2)?; + state.serialize_field("metadata", &self.metadata)?; + let mut files = Vec::with_capacity(self.files.len()); for file in &self.files { - let mut file_m: BTreeMap = BTreeMap::new(); - file_m.insert("name".to_string(), file.name.to_json()); + let mut map = HashMap::with_capacity(3); + map.insert("name", Value::String(file.name.to_owned())); let file_type = match file.file_type { FileType::Dir => "file_type_dir", @@ -163,13 +102,13 @@ impl ToJson for FileList { FileType::Binary => "file_type_binary", FileType::RustSource => "file_type_rust_source", }; + map.insert(file_type, Value::Bool(true)); - file_m.insert(file_type.to_string(), true.to_json()); - file_vec.push(file_m.to_json()); + files.push(map); } + state.serialize_field("files", &files)?; - m.insert("files".to_string(), file_vec.to_json()); - m.to_json() + state.end() } } @@ -212,15 +151,15 @@ impl FileList { return None; } - let files: Json = rows.get(0).get_opt(5).unwrap().ok()?; + let files: Value = rows.get(0).get_opt(5).unwrap().ok()?; let mut file_list: Vec = Vec::new(); if let Some(files) = files.as_array() { for file in files { if let Some(file) = file.as_array() { - let mime = file[0].as_string().unwrap(); - let path = file[1].as_string().unwrap(); + let mime = file[0].as_str().unwrap(); + let path = file[1].as_str().unwrap(); // skip .cargo-ok generated by cargo if path == ".cargo-ok" { @@ -368,89 +307,49 @@ pub fn source_browser_handler(req: &mut Request) -> IronResult { #[cfg(test)] mod tests { use super::*; - - #[test] - fn serialize_file_types() { - assert_eq!( - Json::from_str(r#"{ "file_type_dir": true }"#).unwrap(), - FileType::Dir.to_json(), - ); - assert_eq!( - Json::from_str(r#"{ "file_type_text": true }"#).unwrap(), - FileType::Text.to_json(), - ); - assert_eq!( - Json::from_str(r#"{ "file_type_binary": true }"#).unwrap(), - FileType::Binary.to_json(), - ); - assert_eq!( - Json::from_str(r#"{ "file_type_rust_source": true }"#).unwrap(), - FileType::RustSource.to_json(), - ); - } - - #[test] - fn serialize_file() { - assert_eq!( - Json::from_str( - r#"{ - "name": "main.rs", - "file_type_rust_source": true - }"# - ) - .unwrap(), - File { - name: "main.rs".to_string(), - file_type: FileType::RustSource - } - .to_json(), - ); - } + use serde_json::json; #[test] fn serialize_file_list() { - assert_eq!( - Json::from_str( - r#"{ - "metadata": { - "name": "rcc", - "version": "0.0.0", - "description": "it compiles an unholy language", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }, - "files": [{ - "name": "main.rs", - "file_type_rust_source": true - }, { - "name": "lib.rs", - "file_type_rust_source": true - }] - }"# - ) - .unwrap(), - FileList { - metadata: MetaData { - name: "rcc".to_string(), - version: "0.0.0".to_string(), - description: Some("it compiles an unholy language".to_string()), - target_name: None, - rustdoc_status: true, - default_target: "x86_64-unknown-linux-gnu".to_string(), + let file_list = FileList { + metadata: MetaData { + name: "rcc".to_string(), + version: "0.0.0".to_string(), + description: Some("it compiles an unholy language".to_string()), + target_name: None, + rustdoc_status: true, + default_target: "x86_64-unknown-linux-gnu".to_string(), + }, + files: vec![ + File { + name: "main.rs".to_string(), + file_type: FileType::RustSource, }, - files: vec![ - File { - name: "main.rs".to_string(), - file_type: FileType::RustSource - }, - File { - name: "lib.rs".to_string(), - file_type: FileType::RustSource - } - ], - } - .to_json(), - ); + File { + name: "lib.rs".to_string(), + file_type: FileType::RustSource, + }, + ], + }; + + let correct_json = json!({ + "metadata": { + "name": "rcc", + "version": "0.0.0", + "description": "it compiles an unholy language", + "target_name": null, + "rustdoc_status": true, + "default_target": "x86_64-unknown-linux-gnu" + }, + "files": [{ + "name": "main.rs", + "file_type_rust_source": true + }, { + "name": "lib.rs", + "file_type_rust_source": true + }], + }); + + assert_eq!(correct_json, serde_json::to_value(&file_list).unwrap(),); } } From 9655e92f3ced780853385d1452ca722d7b0adca2 Mon Sep 17 00:00:00 2001 From: Chase Wilson Date: Thu, 7 May 2020 14:07:09 -0500 Subject: [PATCH 3/5] Rebase cleanup --- src/web/crate_details.rs | 6 +++++- src/web/rustdoc.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 95345c9e5..c62a85ac9 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -293,6 +293,7 @@ impl CrateDetails { repository_url: None, homepage_url: None, keywords: None, + yanked: false, have_examples: true, target_name: "x86_64-unknown-linux-gnu".to_string(), releases: vec![], @@ -644,6 +645,7 @@ mod tests { "target_name": "x86_64-unknown-linux-gnu", "releases": [], "github": true, + "yanked": false, "github_stars": null, "github_forks": null, "github_issues": null, @@ -689,6 +691,7 @@ mod tests { "target_name": "x86_64-unknown-linux-gnu", "releases": [], "github": true, + "yanked": false, "github_stars": null, "github_forks": null, "github_issues": null, @@ -719,7 +722,8 @@ mod tests { let correct_json = json!({ "version": "idkman", - "build_status": true + "build_status": true, + "yanked": true, }); assert_eq!(correct_json, serde_json::to_value(&release).unwrap()); diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index e07b40a5f..8aada3783 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -1371,6 +1371,7 @@ mod test { "target_name": "x86_64-unknown-linux-gnu", "releases": [], "github": true, + "yanked": false, "github_stars": null, "github_forks": null, "github_issues": null, From f5f198217d87631c2d2148b3b73b6e8cdd76d998 Mon Sep 17 00:00:00 2001 From: Chase Wilson Date: Tue, 26 May 2020 21:59:36 -0500 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Joshua Nelson --- src/web/crate_details.rs | 69 +++++++++++++++------------------------- src/web/page.rs | 35 +++++++++++++------- src/web/releases.rs | 18 ++++++----- src/web/source.rs | 59 +++------------------------------- 4 files changed, 64 insertions(+), 117 deletions(-) diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index c62a85ac9..8fe34ba65 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -8,7 +8,10 @@ use iron::prelude::*; use iron::{status, Url}; use postgres::Connection; use router::Router; -use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde::{ + ser::{SerializeStruct, Serializer}, + Serialize, +}; use serde_json::Value; // TODO: Add target name and versions @@ -51,7 +54,15 @@ impl Serialize for CrateDetails { where S: Serializer, { - let mut state = serializer.serialize_struct("CrateDetails", 28)?; + // Make sure that the length parameter passed to serde is correct by + // adding the someness of `readme` and `rustdoc` to the total. `true` + // is 1 and `false` is 0, so it increments if the value is some (and therefore + // needs to be serialized) + let mut state = serializer.serialize_struct( + "CrateDetails", + 26 + self.readme.is_some() as usize + self.rustdoc.is_some() as usize, + )?; + state.serialize_field("metadata", &self.metadata)?; state.serialize_field("name", &self.name)?; state.serialize_field("version", &self.version)?; @@ -94,7 +105,7 @@ impl Serialize for CrateDetails { } } -#[derive(Debug, Eq, PartialEq, serde::Serialize)] +#[derive(Debug, Eq, PartialEq, Serialize)] pub struct Release { pub version: String, pub build_status: bool, @@ -626,7 +637,7 @@ mod tests { let time = time::get_time(); let mut details = CrateDetails::default_tester(time); - let correct_json = json!({ + let mut correct_json = json!({ "name": "rcc", "version": "100.0.0", "description": null, @@ -665,50 +676,20 @@ mod tests { assert_eq!(correct_json, serde_json::to_value(&details).unwrap()); - details.description = Some("serde does stuff".to_string()); - details.owners = vec![("Owner".to_string(), "owner@ownsstuff.com".to_string())]; - let authors = vec![("Somebody".to_string(), "somebody@somebody.com".to_string())]; + let owners = vec![("Owner".to_string(), "owner@ownsstuff.com".to_string())]; + let description = "serde does stuff".to_string(); + + correct_json["description"] = Value::String(description.clone()); + correct_json["owners"] = serde_json::to_value(&owners).unwrap(); + correct_json["authors_json"] = serde_json::to_value(&authors).unwrap(); + correct_json["authors"] = serde_json::to_value(&authors).unwrap(); + + details.description = Some(description); + details.owners = owners; details.authors_json = Some(serde_json::to_value(&authors).unwrap()); details.authors = authors; - let correct_json = json!({ - "name": "rcc", - "version": "100.0.0", - "description": "serde does stuff", - "authors": [["Somebody", "somebody@somebody.com"]], - "owners": [["Owner", "owner@ownsstuff.com"]], - "authors_json": [["Somebody", "somebody@somebody.com"]], - "dependencies": null, - "release_time": super::super::duration_to_str(time), - "build_status": true, - "last_successful_build": null, - "rustdoc_status": true, - "repository_url": null, - "homepage_url": null, - "keywords": null, - "have_examples": true, - "target_name": "x86_64-unknown-linux-gnu", - "releases": [], - "github": true, - "yanked": false, - "github_stars": null, - "github_forks": null, - "github_issues": null, - "metadata": { - "name": "serde", - "version": "1.0.0", - "description": "serde does stuff", - "target_name": null, - "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" - }, - "is_library": true, - "doc_targets": [], - "license": null, - "documentation_url": null - }); - assert_eq!(correct_json, serde_json::to_value(&details).unwrap()); } diff --git a/src/web/page.rs b/src/web/page.rs index f09b386ee..ef10f01c9 100644 --- a/src/web/page.rs +++ b/src/web/page.rs @@ -116,7 +116,12 @@ impl Serialize for Page { where S: Serializer, { - let mut state = serializer.serialize_struct("Page", 10)?; + // Make sure that the length parameter passed to serde is correct by + // adding the someness of the global alert to the total. `true` + // is 1 and `false` is 0, so it increments if the value is some (and therefore + // needs to be serialized) + let mut state = + serializer.serialize_struct("Page", 9 + crate::GLOBAL_ALERT.is_some() as usize)?; if let Some(ref title) = self.title { state.serialize_field("title", title)?; @@ -132,10 +137,7 @@ impl Serialize for Page { state.serialize_field("cratesfyi_version", crate::BUILD_VERSION)?; state.serialize_field( "cratesfyi_version_safe", - &crate::BUILD_VERSION - .replace(" ", "-") - .replace("(", "") - .replace(")", ""), + &build_version_safe(crate::BUILD_VERSION), )?; state.serialize_field("varss", &self.varss)?; state.serialize_field("varsb", &self.varsb)?; @@ -145,10 +147,15 @@ impl Serialize for Page { } } +fn build_version_safe(version: &str) -> String { + version.replace(" ", "-").replace("(", "").replace(")", "") +} + #[cfg(test)] mod tests { use super::super::releases::{self, Release}; use super::*; + use iron::Url; use serde_json::json; #[test] @@ -193,10 +200,7 @@ mod tests { "varsi": { "test3": 1337 }, "rustc_resource_suffix": &*RUSTC_RESOURCE_SUFFIX, "cratesfyi_version": crate::BUILD_VERSION, - "cratesfyi_version_safe": crate::BUILD_VERSION - .replace(" ", "-") - .replace("(", "") - .replace(")", ""), + "cratesfyi_version_safe": build_version_safe(crate::BUILD_VERSION), "has_global_alert": crate::GLOBAL_ALERT.is_some() }); @@ -238,18 +242,27 @@ mod tests { fn serialize_global_alert() { let alert = GlobalAlert { url: "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/", - text: "THE WORLD IS ENDING", + text: "THE WORLD WILL SOON END", css_class: "THE END IS NEAR", fa_icon: "https://gph.is/1uOvmqR", }; let correct_json = json!({ "url": "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/", - "text": "THE WORLD IS ENDING", + "text": "THE WORLD WILL SOON END", "css_class": "THE END IS NEAR", "fa_icon": "https://gph.is/1uOvmqR" }); assert_eq!(correct_json, serde_json::to_value(&alert).unwrap()); } + + #[test] + fn build_version_url_safe() { + let safe = format!( + "https://docs.rs/builds/{}", + build_version_safe(crate::BUILD_VERSION) + ); + assert!(Url::parse(&safe).is_ok()); + } } diff --git a/src/web/releases.rs b/src/web/releases.rs index 2cbaa60d9..f45928491 100644 --- a/src/web/releases.rs +++ b/src/web/releases.rs @@ -1006,14 +1006,16 @@ mod tests { #[test] fn serialize_releases() { - let time = time::get_time(); + let current_time = time::get_time(); + let now = time::at(current_time); + let mut release = Release { name: "serde".to_string(), version: "0.0.0".to_string(), description: Some("serde makes things other things".to_string()), target_name: Some("x86_64-pc-windows-msvc".to_string()), rustdoc_status: true, - release_time: time, + release_time: current_time, stars: 100, }; @@ -1023,8 +1025,8 @@ mod tests { "description": "serde makes things other things", "target_name": "x86_64-pc-windows-msvc", "rustdoc_status": true, - "release_time": duration_to_str(time), - "release_time_rfc3339": time::at(time).rfc3339().to_string(), + "release_time": duration_to_str(current_time), + "release_time_rfc3339": now.rfc3339().to_string(), "stars": 100 }); @@ -1037,8 +1039,8 @@ mod tests { "description": "serde makes things other things", "target_name": null, "rustdoc_status": true, - "release_time": duration_to_str(time), - "release_time_rfc3339": time::at(time).rfc3339().to_string(), + "release_time": duration_to_str(current_time), + "release_time_rfc3339": now.rfc3339().to_string(), "stars": 100 }); @@ -1051,8 +1053,8 @@ mod tests { "description": null, "target_name": null, "rustdoc_status": true, - "release_time": duration_to_str(time), - "release_time_rfc3339": time::at(time).rfc3339().to_string(), + "release_time": duration_to_str(current_time), + "release_time_rfc3339": now.rfc3339().to_string(), "stars": 100 }); diff --git a/src/web/source.rs b/src/web/source.rs index 0acff011b..a1fd60a65 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -29,55 +29,6 @@ struct File { } /// A list of source files -/// -/// -/// Rust: -/// -/// ```ignore -/// FileList { -/// metadata: MetaData { -/// name: "rcc", -/// version: "0.0.0", -/// description: Some("it compiles an unholy language"), -/// target_name: None, -/// rustdoc_status: true, -/// default_target: "x86_64-unknown-linux-gnu", -/// }, -/// files: vec![ -/// File { -/// name: "main.rs", -/// file_type: FileType::RustSource, -/// }, -/// File { -/// name: "lib.rs", -/// file_type: FileType::RustSource, -/// }, -/// ], -/// } -/// ``` -/// -/// Json: -/// -/// ```json -/// { -/// "metadata": { -/// "name": "rcc", -/// "version": "0.0.0", -/// "description": "it compiles an unholy language", -/// "target_name": null, -/// "rustdoc_status": true, -/// "default_target": "x86_64-unknown-linux-gnu", -/// }, -/// "files": [{ -/// "name": "main.rs", -/// "file_type_rust_source": true, -/// }, { -/// "name": "lib.rs", -/// "file_type_rust_source": true, -/// }], -/// } -/// ``` -/// struct FileList { metadata: MetaData, files: Vec, @@ -93,7 +44,7 @@ impl Serialize for FileList { let mut files = Vec::with_capacity(self.files.len()); for file in &self.files { - let mut map = HashMap::with_capacity(3); + let mut map = HashMap::with_capacity(2); map.insert("name", Value::String(file.name.to_owned())); let file_type = match file.file_type { @@ -119,10 +70,10 @@ impl FileList { /// /// ```text /// [ - /// ["text/plain",".gitignore"], - /// ["text/x-c","src/reseeding.rs"], - /// ["text/x-c","src/lib.rs"], - /// ["text/x-c","README.md"], + /// ["text/plain", ".gitignore"], + /// ["text/x-c", "src/reseeding.rs"], + /// ["text/x-c", "src/lib.rs"], + /// ["text/x-c", "README.md"], /// ... /// ] /// ``` From 20dcf0b8420ffff997283b4721c1c7b6e25f4896 Mon Sep 17 00:00:00 2001 From: Chase Wilson Date: Wed, 27 May 2020 10:23:45 -0500 Subject: [PATCH 5/5] Yanked yanked --- src/web/crate_details.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 8fe34ba65..c646a1cc0 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -309,7 +309,6 @@ impl CrateDetails { target_name: "x86_64-unknown-linux-gnu".to_string(), releases: vec![], github: true, - yanked: false, github_stars: None, github_forks: None, github_issues: None,