From e3ee1ebc92f2303bc785959a4c0f3d7ff4dce16c Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Sun, 11 Jun 2017 13:54:40 -0400 Subject: [PATCH 01/29] Add diesel migration to add 'license' column to 'versions' table. --- migrations/20170611165120_add_license_to_versions/down.sql | 1 + migrations/20170611165120_add_license_to_versions/up.sql | 1 + 2 files changed, 2 insertions(+) create mode 100644 migrations/20170611165120_add_license_to_versions/down.sql create mode 100644 migrations/20170611165120_add_license_to_versions/up.sql diff --git a/migrations/20170611165120_add_license_to_versions/down.sql b/migrations/20170611165120_add_license_to_versions/down.sql new file mode 100644 index 00000000000..ad8340aee04 --- /dev/null +++ b/migrations/20170611165120_add_license_to_versions/down.sql @@ -0,0 +1 @@ +ALTER TABLE versions DROP COLUMN license; diff --git a/migrations/20170611165120_add_license_to_versions/up.sql b/migrations/20170611165120_add_license_to_versions/up.sql new file mode 100644 index 00000000000..5e8e580a54d --- /dev/null +++ b/migrations/20170611165120_add_license_to_versions/up.sql @@ -0,0 +1 @@ +ALTER TABLE versions ADD COLUMN license VARCHAR; From 9bb23878aadf2ec4433930ca3f06de187983c2cb Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Sun, 11 Jun 2017 21:36:33 -0400 Subject: [PATCH 02/29] Created update-licenses to update previous versions of crates to have their corresponding licenses. --- src/bin/update-licenses.rs | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/bin/update-licenses.rs diff --git a/src/bin/update-licenses.rs b/src/bin/update-licenses.rs new file mode 100644 index 00000000000..552975647a7 --- /dev/null +++ b/src/bin/update-licenses.rs @@ -0,0 +1,51 @@ +//! Updates all of the licenses from the existing crates into each of their +//! already existing versions. + +// +// Usage: +// cargo run --bin update-licenses + +extern crate cargo_registry; +extern crate postgres; + +use std::io::prelude::*; + +fn main() { + let conn = cargo_registry::db::connect_now(); + { + let tx = conn.transaction().unwrap(); + transfer(&tx); + tx.set_commit(); + tx.finish().unwrap(); + } +} + +fn transfer(tx: &postgres::transaction::Transaction) { + let stmt = tx.prepare("SELECT id, name, license FROM crates").unwrap(); + let rows = stmt.query(&[]).unwrap(); + + for row in rows.iter() { + let id: i32 = row.get("id"); + let name: String = row.get("name"); + let license: String = row.get("license"); + + println!("Setting the license for all versions of {} to {}.", name, license); + + let num_updated = tx.execute("UPDATE versions SET license = $1 WHERE crate_id = $2", &[&license, &id]).unwrap(); + assert!(num_updated > 0); + } + + get_confirm("Finish committing?"); +} + +fn get_confirm(msg: &str) { + print!("{} [y/N]: ", msg); + std::io::stdout().flush().unwrap(); + + let mut line = String::new(); + std::io::stdin().read_line(&mut line).unwrap(); + + if !line.starts_with("y") { + std::process::exit(0); + } +} \ No newline at end of file From 847959a8c21449f2022175091a48704db175e191 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 01:54:25 -0400 Subject: [PATCH 03/29] Removed NewKrate taking a license file. Now, NewVersion will accept the license and validate it. Additionally, Made NewCrate.crate_or_update take an immutable self instead of mutable because it was no longer necessary. --- src/krate.rs | 38 ++++++++++---------------------------- src/schema.rs | 1 + src/version.rs | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 70490b66f37..67e8e3e7645 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -110,20 +110,18 @@ pub struct NewCrate<'a> { pub documentation: Option<&'a str>, pub readme: Option<&'a str>, pub repository: Option<&'a str>, - pub license: Option<&'a str>, pub max_upload_size: Option, } impl<'a> NewCrate<'a> { pub fn create_or_update( - mut self, + self, conn: &PgConnection, - license_file: Option<&str>, uploader: i32, ) -> CargoResult { use diesel::update; - self.validate(license_file)?; + self.validate()?; self.ensure_name_not_reserved(conn)?; conn.transaction(|| { @@ -143,7 +141,7 @@ impl<'a> NewCrate<'a> { }) } - fn validate(&mut self, license_file: Option<&str>) -> CargoResult<()> { + fn validate(&self) -> CargoResult<()> { fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { let url = match url { Some(s) => s, @@ -167,24 +165,6 @@ impl<'a> NewCrate<'a> { validate_url(self.homepage, "homepage")?; validate_url(self.documentation, "documentation")?; validate_url(self.repository, "repository")?; - self.validate_license(license_file)?; - Ok(()) - } - - fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { - if let Some(license) = self.license { - for part in license.split('/') { - license_exprs::validate_license_expr(part) - .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ - for options, and http://spdx.org/licenses/ \ - for their identifiers", e)))?; - } - } else if license_file.is_some() { - // If no license is given, but a license file is given, flag this - // crate as having a nonstandard license. Note that we don't - // actually do anything else with license_file currently. - self.license = Some("non-standard"); - } Ok(()) } @@ -894,12 +874,11 @@ pub fn new(req: &mut Request) -> CargoResult { homepage: new_crate.homepage.as_ref().map(|s| &**s), documentation: new_crate.documentation.as_ref().map(|s| &**s), readme: new_crate.readme.as_ref().map(|s| &**s), - repository: new_crate.repository.as_ref().map(|s| &**s), - license: new_crate.license.as_ref().map(|s| &**s), + repository: new_crate.repository.as_ref().map(|s| &**s), max_upload_size: None, }; - let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, license_file, user.id)?; + + let krate = persist.create_or_update(&conn, user.id)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { @@ -920,8 +899,11 @@ pub fn new(req: &mut Request) -> CargoResult { return Err(human(&format_args!("max upload size is: {}", max))) } + let license = new_crate.license.clone(); + let license_file = new_crate.license_file.as_ref().map(|s| &**s); + // Persist the new version of this crate - let version = NewVersion::new(krate.id, vers, &features)? + let version = NewVersion::new(krate.id, vers, &features, license, license_file)? .save(&conn, &new_crate.authors)?; // Link this new version to all dependencies diff --git a/src/schema.rs b/src/schema.rs index 65ce72b7281..9f973a040ba 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -172,5 +172,6 @@ table! { downloads -> Int4, features -> Nullable, yanked -> Bool, + license -> Nullable, } } diff --git a/src/version.rs b/src/version.rs index 218d9b36b4b..e0226419bbc 100644 --- a/src/version.rs +++ b/src/version.rs @@ -23,6 +23,7 @@ use user::RequestUser; use util::errors::CargoError; use util::{RequestUtils, CargoResult, ChainError, internal, human}; use {Model, Crate}; +use license_exprs; #[derive(Clone, Identifiable, Associations)] #[belongs_to(Crate)] @@ -35,6 +36,7 @@ pub struct Version { pub downloads: i32, pub features: HashMap>, pub yanked: bool, + pub license: Option, } #[derive(Insertable)] @@ -43,6 +45,7 @@ pub struct NewVersion { crate_id: i32, num: String, features: String, + license: Option, } pub struct Author { @@ -186,13 +189,21 @@ impl NewVersion { crate_id: i32, num: &semver::Version, features: &HashMap>, + license: Option, + license_file: Option<&str>, ) -> CargoResult { let features = json::encode(features)?; - Ok(NewVersion { + + let mut new_version = NewVersion { crate_id: crate_id, num: num.to_string(), features: features, - }) + license: license, + }; + + new_version.validate_license(license_file)?; + + Ok(new_version) } pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult { @@ -221,6 +232,23 @@ impl NewVersion { Ok(version) }) } + + fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { + if let Some(ref license) = self.license { + for part in license.split('/') { + license_exprs::validate_license_expr(part) + .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + for options, and http://spdx.org/licenses/ \ + for their identifiers", e)))?; + } + } else if license_file.is_some() { + // If no license is given, but a license file is given, flag this + // crate as having a nonstandard license. Note that we don't + // actually do anything else with license_file currently. + self.license = Some(String::from("non-standard")); + } + Ok(()) + } } #[derive(Insertable)] @@ -231,7 +259,7 @@ struct NewAuthor<'a> { } impl Queryable for Version { - type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool); + type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool, Option); fn build(row: Self::Row) -> Self { let features = row.6.map(|s| { @@ -246,6 +274,7 @@ impl Queryable for Version { downloads: row.5, features: features, yanked: row.7, + license: row.8, } } } @@ -266,6 +295,7 @@ impl Model for Version { downloads: row.get("downloads"), features: features, yanked: row.get("yanked"), + license: row.get("license"), } } fn table_name(_: Option) -> &'static str { "versions" } From 965a340666a8c1343849b37b988d20b8392cb451 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:02:16 -0400 Subject: [PATCH 04/29] Stopped EncodableCrate from returning a license, and instead made EncodableVersion return it. --- src/krate.rs | 4 +--- src/version.rs | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 67e8e3e7645..723c18bc3a7 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -86,7 +86,6 @@ pub struct EncodableCrate { pub description: Option, pub homepage: Option, pub documentation: Option, - pub license: Option, pub repository: Option, pub links: CrateLinks, pub exact_match: bool, @@ -395,7 +394,7 @@ impl Crate { -> EncodableCrate { let Crate { name, created_at, updated_at, downloads, description, - homepage, documentation, license, repository, .. + homepage, documentation, repository, .. } = self; let versions_link = match versions { Some(..) => None, @@ -421,7 +420,6 @@ impl Crate { homepage: homepage, exact_match: exact_match, description: description, - license: license, repository: repository, links: CrateLinks { version_downloads: format!("/api/v1/crates/{}/downloads", name), diff --git a/src/version.rs b/src/version.rs index e0226419bbc..67bdbfddee7 100644 --- a/src/version.rs +++ b/src/version.rs @@ -63,6 +63,7 @@ pub struct EncodableVersion { pub downloads: i32, pub features: HashMap>, pub yanked: bool, + pub license: Option, pub links: VersionLinks, } @@ -113,7 +114,7 @@ impl Version { pub fn encodable(self, crate_name: &str) -> EncodableVersion { let Version { id, num, updated_at, created_at, - downloads, features, yanked, .. } = self; + downloads, features, yanked, license, .. } = self; let num = num.to_string(); EncodableVersion { dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num), @@ -125,6 +126,7 @@ impl Version { downloads: downloads, features: features, yanked: yanked, + license: license, links: VersionLinks { dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num), From 68d829e99970d639b78ed614fcf9acedb92be422 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:08:59 -0400 Subject: [PATCH 05/29] Updated the tests to pass. --- src/tests/all.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/all.rs b/src/tests/all.rs index 76bd088d768..28cdadf1764 100755 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -287,7 +287,7 @@ impl<'a> CrateBuilder<'a> { use diesel::update; let mut krate = self.krate - .create_or_update(connection, self.license_file, self.owner_id)?; + .create_or_update(connection, self.owner_id)?; // Since we are using `NewCrate`, we can't set all the // crate properties in a single DB call. @@ -301,7 +301,7 @@ impl<'a> CrateBuilder<'a> { } for version_num in &self.versions { - NewVersion::new(krate.id, version_num, &HashMap::new())? + NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file)? .save(connection, &[])?; } @@ -323,7 +323,7 @@ impl<'a> CrateBuilder<'a> { fn new_version(crate_id: i32, num: &str) -> NewVersion { let num = semver::Version::parse(num).unwrap(); - NewVersion::new(crate_id, &num, &HashMap::new()).unwrap() + NewVersion::new(crate_id, &num, &HashMap::new(), None, None).unwrap() } fn krate(name: &str) -> Crate { From 3f859bfe7f077cab53082631a59fd83891bb9174 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Sun, 11 Jun 2017 13:54:40 -0400 Subject: [PATCH 06/29] Add diesel migration to add 'license' column to 'versions' table. --- migrations/20170611165120_add_license_to_versions/down.sql | 1 + migrations/20170611165120_add_license_to_versions/up.sql | 1 + 2 files changed, 2 insertions(+) create mode 100644 migrations/20170611165120_add_license_to_versions/down.sql create mode 100644 migrations/20170611165120_add_license_to_versions/up.sql diff --git a/migrations/20170611165120_add_license_to_versions/down.sql b/migrations/20170611165120_add_license_to_versions/down.sql new file mode 100644 index 00000000000..ad8340aee04 --- /dev/null +++ b/migrations/20170611165120_add_license_to_versions/down.sql @@ -0,0 +1 @@ +ALTER TABLE versions DROP COLUMN license; diff --git a/migrations/20170611165120_add_license_to_versions/up.sql b/migrations/20170611165120_add_license_to_versions/up.sql new file mode 100644 index 00000000000..5e8e580a54d --- /dev/null +++ b/migrations/20170611165120_add_license_to_versions/up.sql @@ -0,0 +1 @@ +ALTER TABLE versions ADD COLUMN license VARCHAR; From 4e4531f527d5aa1da8f860326ecf64187c82e27e Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Sun, 11 Jun 2017 21:36:33 -0400 Subject: [PATCH 07/29] Created update-licenses to update previous versions of crates to have their corresponding licenses. --- src/bin/update-licenses.rs | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/bin/update-licenses.rs diff --git a/src/bin/update-licenses.rs b/src/bin/update-licenses.rs new file mode 100644 index 00000000000..552975647a7 --- /dev/null +++ b/src/bin/update-licenses.rs @@ -0,0 +1,51 @@ +//! Updates all of the licenses from the existing crates into each of their +//! already existing versions. + +// +// Usage: +// cargo run --bin update-licenses + +extern crate cargo_registry; +extern crate postgres; + +use std::io::prelude::*; + +fn main() { + let conn = cargo_registry::db::connect_now(); + { + let tx = conn.transaction().unwrap(); + transfer(&tx); + tx.set_commit(); + tx.finish().unwrap(); + } +} + +fn transfer(tx: &postgres::transaction::Transaction) { + let stmt = tx.prepare("SELECT id, name, license FROM crates").unwrap(); + let rows = stmt.query(&[]).unwrap(); + + for row in rows.iter() { + let id: i32 = row.get("id"); + let name: String = row.get("name"); + let license: String = row.get("license"); + + println!("Setting the license for all versions of {} to {}.", name, license); + + let num_updated = tx.execute("UPDATE versions SET license = $1 WHERE crate_id = $2", &[&license, &id]).unwrap(); + assert!(num_updated > 0); + } + + get_confirm("Finish committing?"); +} + +fn get_confirm(msg: &str) { + print!("{} [y/N]: ", msg); + std::io::stdout().flush().unwrap(); + + let mut line = String::new(); + std::io::stdin().read_line(&mut line).unwrap(); + + if !line.starts_with("y") { + std::process::exit(0); + } +} \ No newline at end of file From 54bbee436c4ef867b9a3ddb0553266a00d35f1c0 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 01:54:25 -0400 Subject: [PATCH 08/29] Removed NewKrate taking a license file. Now, NewVersion will accept the license and validate it. Additionally, Made NewCrate.crate_or_update take an immutable self instead of mutable because it was no longer necessary. --- src/krate.rs | 17 ++++++++++------- src/schema.rs | 1 + src/version.rs | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index d0a1809d623..003a7feadfb 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -135,8 +135,8 @@ impl<'a> NewCrate<'a> { pub fn create_or_update( mut self, conn: &PgConnection, - license_file: Option<&str>, uploader: i32, + license_file: Option<&str>, ) -> CargoResult { use diesel::update; @@ -1075,12 +1075,12 @@ pub fn new(req: &mut Request) -> CargoResult { homepage: new_crate.homepage.as_ref().map(|s| &**s), documentation: new_crate.documentation.as_ref().map(|s| &**s), readme: new_crate.readme.as_ref().map(|s| &**s), - repository: new_crate.repository.as_ref().map(|s| &**s), - license: new_crate.license.as_ref().map(|s| &**s), + repository: new_crate.repository.as_ref().map(|s| &**s), + license: new_crate.license.as_ref().map(|s| &**s), max_upload_size: None, }; let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, license_file, user.id)?; + let krate = persist.create_or_update(&conn, user.id, license_file)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { @@ -1107,11 +1107,14 @@ pub fn new(req: &mut Request) -> CargoResult { return Err(human(&format_args!("max upload size is: {}", max))); } + // This is only redundant for now. Eventually the duplication will be removed. + let license = new_crate.license.clone(); + // Persist the new version of this crate - let version = NewVersion::new(krate.id, vers, &features)?.save( - &conn, + let version = NewVersion::new(krate.id, vers, &features, license, license_file)?.save( + &conn, &new_crate - .authors, + .authors )?; // Link this new version to all dependencies diff --git a/src/schema.rs b/src/schema.rs index 65ce72b7281..9f973a040ba 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -172,5 +172,6 @@ table! { downloads -> Int4, features -> Nullable, yanked -> Bool, + license -> Nullable, } } diff --git a/src/version.rs b/src/version.rs index 9656cb34e15..319fafda576 100644 --- a/src/version.rs +++ b/src/version.rs @@ -23,6 +23,7 @@ use user::RequestUser; use util::errors::CargoError; use util::{RequestUtils, CargoResult, ChainError, internal, human}; use {Model, Crate}; +use license_exprs; #[derive(Clone, Identifiable, Associations)] #[belongs_to(Crate)] @@ -35,6 +36,7 @@ pub struct Version { pub downloads: i32, pub features: HashMap>, pub yanked: bool, + pub license: Option, } #[derive(Insertable)] @@ -43,6 +45,7 @@ pub struct NewVersion { crate_id: i32, num: String, features: String, + license: Option, } pub struct Author { @@ -205,13 +208,21 @@ impl NewVersion { crate_id: i32, num: &semver::Version, features: &HashMap>, + license: Option, + license_file: Option<&str>, ) -> CargoResult { let features = json::encode(features)?; - Ok(NewVersion { + + let mut new_version = NewVersion { crate_id: crate_id, num: num.to_string(), features: features, - }) + license: license, + }; + + new_version.validate_license(license_file)?; + + Ok(new_version) } pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult { @@ -249,6 +260,23 @@ impl NewVersion { Ok(version) }) } + + fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { + if let Some(ref license) = self.license { + for part in license.split('/') { + license_exprs::validate_license_expr(part) + .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + for options, and http://spdx.org/licenses/ \ + for their identifiers", e)))?; + } + } else if license_file.is_some() { + // If no license is given, but a license file is given, flag this + // crate as having a nonstandard license. Note that we don't + // actually do anything else with license_file currently. + self.license = Some(String::from("non-standard")); + } + Ok(()) + } } #[derive(Insertable)] @@ -259,7 +287,7 @@ struct NewAuthor<'a> { } impl Queryable for Version { - type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool); + type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool, Option); fn build(row: Self::Row) -> Self { let features = row.6.map(|s| json::decode(&s).unwrap()).unwrap_or_else( @@ -274,6 +302,7 @@ impl Queryable for Version { downloads: row.5, features: features, yanked: row.7, + license: row.8, } } } @@ -294,6 +323,7 @@ impl Model for Version { downloads: row.get("downloads"), features: features, yanked: row.get("yanked"), + license: row.get("license"), } } fn table_name(_: Option) -> &'static str { From 19366e8f7df3c788d47edb0dcdbbb6953d6cd5a3 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:02:16 -0400 Subject: [PATCH 09/29] Stopped EncodableCrate from returning a license, and instead made EncodableVersion return it. --- src/krate.rs | 3 --- src/version.rs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 003a7feadfb..e6dff1318d5 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -103,7 +103,6 @@ pub struct EncodableCrate { pub description: Option, pub homepage: Option, pub documentation: Option, - pub license: Option, pub repository: Option, pub links: CrateLinks, pub exact_match: bool, @@ -503,7 +502,6 @@ impl Crate { description, homepage, documentation, - license, repository, .. } = self; @@ -529,7 +527,6 @@ impl Crate { homepage: homepage, exact_match: exact_match, description: description, - license: license, repository: repository, links: CrateLinks { version_downloads: format!("/api/v1/crates/{}/downloads", name), diff --git a/src/version.rs b/src/version.rs index 319fafda576..8a9a1a3a51f 100644 --- a/src/version.rs +++ b/src/version.rs @@ -63,6 +63,7 @@ pub struct EncodableVersion { pub downloads: i32, pub features: HashMap>, pub yanked: bool, + pub license: Option, pub links: VersionLinks, } @@ -126,6 +127,7 @@ impl Version { downloads, features, yanked, + license, .. } = self; let num = num.to_string(); @@ -139,6 +141,7 @@ impl Version { downloads: downloads, features: features, yanked: yanked, + license: license, links: VersionLinks { dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num), version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num), From c917ac48c02eafd5a56045b8428f7bd42cef822f Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:08:59 -0400 Subject: [PATCH 10/29] Updated the tests to pass. --- src/krate.rs | 4 ++-- src/tests/all.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index e6dff1318d5..6888c76b208 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -134,8 +134,8 @@ impl<'a> NewCrate<'a> { pub fn create_or_update( mut self, conn: &PgConnection, - uploader: i32, license_file: Option<&str>, + uploader: i32, ) -> CargoResult { use diesel::update; @@ -1077,7 +1077,7 @@ pub fn new(req: &mut Request) -> CargoResult { max_upload_size: None, }; let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, user.id, license_file)?; + let krate = persist.create_or_update(&conn, license_file, user.id)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { diff --git a/src/tests/all.rs b/src/tests/all.rs index 61b4255a5e7..9c0265e0313 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -304,8 +304,8 @@ impl<'a> CrateBuilder<'a> { } for version_num in &self.versions { - NewVersion::new(krate.id, version_num, &HashMap::new())? - .save(connection, &[])?; + NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file)? + .save(connection, &[])?; } if !self.keywords.is_empty() { @@ -325,7 +325,7 @@ impl<'a> CrateBuilder<'a> { fn new_version(crate_id: i32, num: &str) -> NewVersion { let num = semver::Version::parse(num).unwrap(); - NewVersion::new(crate_id, &num, &HashMap::new()).unwrap() + NewVersion::new(crate_id, &num, &HashMap::new(), None, None).unwrap() } fn krate(name: &str) -> Crate { From 6542f3c25bd53d94e197fccd0508621d6333ab1e Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Thu, 15 Jun 2017 02:06:33 -0400 Subject: [PATCH 11/29] Added VersionBuilder and converted tests to use it. --- src/tests/all.rs | 57 ++++++++++++++++++++++++++++++++++---------- src/tests/krate.rs | 10 ++++---- src/tests/user.rs | 4 ++-- src/tests/version.rs | 4 ++-- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/tests/all.rs b/src/tests/all.rs index 08f8b9ab76e..95bb98544ff 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -214,12 +214,50 @@ fn user(login: &str) -> User { use cargo_registry::util::CargoResult; +struct VersionBuilder<'a> { + version: semver::Version, + license: Option<&'a str>, + license_file: Option<&'a str>, + features: HashMap>, +} + +impl<'a> VersionBuilder<'a> { + fn new(version: &str) -> VersionBuilder { + let version = semver::Version::parse(version).unwrap_or_else( + |e| { + panic!("The version {} is not valid: {}", version, e); + }, + ); + + VersionBuilder { + version: version, + license: None, + license_file: None, + features: HashMap::new(), + } + } + + fn build(self, connection: &PgConnection, crate_id: i32) -> CargoResult { + let license = match self.license { + Some(license) => Some(license.to_owned()), + None => None, + }; + + NewVersion::new( + crate_id, + &self.version, + &self.features, + license, + self.license_file, + )?.save(connection, &[]) + } +} + struct CrateBuilder<'a> { owner_id: i32, krate: NewCrate<'a>, - license_file: Option<&'a str>, downloads: Option, - versions: Vec, + versions: Vec>, keywords: Vec<&'a str>, } @@ -231,7 +269,6 @@ impl<'a> CrateBuilder<'a> { name: name, ..NewCrate::default() }, - license_file: None, downloads: None, versions: Vec::new(), keywords: Vec::new(), @@ -268,10 +305,7 @@ impl<'a> CrateBuilder<'a> { self } - fn version(mut self, version: &str) -> Self { - let version = semver::Version::parse(version).unwrap_or_else(|e| { - panic!("The version {} is not valid: {}", version, e); - }); + fn version(mut self, version: VersionBuilder<'a>) -> Self { self.versions.push(version); self } @@ -297,14 +331,11 @@ impl<'a> CrateBuilder<'a> { } if self.versions.is_empty() { - self.versions.push("0.99.0".parse().expect( - "invalid version number", - )); + self.versions.push(VersionBuilder::new("0.99.0")); } - for version_num in &self.versions { - NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file)? - .save(connection, &[])?; + for version in self.versions { + version.build(&connection, krate.id)?; } if !self.keywords.is_empty() { diff --git a/src/tests/krate.rs b/src/tests/krate.rs index 39c4203a05d..2130ed48d70 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -338,9 +338,9 @@ fn show() { .description("description") .documentation("https://example.com") .homepage("http://example.com") - .version("1.0.0") - .version("0.5.0") - .version("0.5.1") + .version(::VersionBuilder::new("1.0.0")) + .version(::VersionBuilder::new("0.5.0")) + .version(::VersionBuilder::new("0.5.1")) .keyword("kw1") .expect_build(&conn); } @@ -744,7 +744,7 @@ fn new_krate_duplicate_version() { ::sign_in_as(&mut req, &user); ::CrateBuilder::new("foo_dupe", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); @@ -930,7 +930,7 @@ fn download() { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_download", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); } let resp = t_resp!(middle.call(&mut req)); diff --git a/src/tests/user.rs b/src/tests/user.rs index 0e99b3d1246..c2f78b473ce 100644 --- a/src/tests/user.rs +++ b/src/tests/user.rs @@ -155,11 +155,11 @@ fn following() { ::sign_in_as(&mut req, &user); ::CrateBuilder::new("foo_fighters", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); ::CrateBuilder::new("bar_fighters", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); } diff --git a/src/tests/version.rs b/src/tests/version.rs index e6fe058299c..ee12ea89434 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -29,8 +29,8 @@ fn index() { let conn = app.diesel_database.get().unwrap(); let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) - .version("2.0.0") - .version("2.0.1") + .version(::VersionBuilder::new("2.0.0")) + .version(::VersionBuilder::new("2.0.1")) .expect_build(&conn); let ids = versions::table .select(versions::id) From db1ab7eddd328756fcb578ba0b55d173f5af04ea Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Thu, 15 Jun 2017 02:40:48 -0400 Subject: [PATCH 12/29] Created a test to make sure license can change between versions. --- src/tests/all.rs | 5 +++++ src/tests/version.rs | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tests/all.rs b/src/tests/all.rs index 95bb98544ff..053fa740cd6 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -237,6 +237,11 @@ impl<'a> VersionBuilder<'a> { } } + fn license(mut self, license: Option<&'a str>) -> Self { + self.license = license; + self + } + fn build(self, connection: &PgConnection, crate_id: i32) -> CargoResult { let license = match self.license { Some(license) => Some(license.to_owned()), diff --git a/src/tests/version.rs b/src/tests/version.rs index ee12ea89434..f259c33dae5 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -29,8 +29,10 @@ fn index() { let conn = app.diesel_database.get().unwrap(); let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) - .version(::VersionBuilder::new("2.0.0")) - .version(::VersionBuilder::new("2.0.1")) + .version(::VersionBuilder::new("2.0.0") + .license(Some("MIT"))) + .version(::VersionBuilder::new("2.0.1") + .license(Some("MIT/Apache-2.0"))) .expect_build(&conn); let ids = versions::table .select(versions::id) @@ -42,6 +44,14 @@ fn index() { let mut response = ok_resp!(middle.call(&mut req)); let json: VersionList = ::json(&mut response); assert_eq!(json.versions.len(), 2); + + for v in &json.versions { + match v.num.as_ref() { + "2.0.0" => assert_eq!(v.license, Some(String::from("MIT"))), + "2.0.1" => assert_eq!(v.license, Some(String::from("MIT/Apache-2.0"))), + _ => panic!("unexpected version") + } + } } #[test] From 7436b02f68f7b1878e657f6a61d6aafdd4c6fbbe Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Sun, 11 Jun 2017 13:54:40 -0400 Subject: [PATCH 13/29] Add diesel migration to add 'license' column to 'versions' table. --- migrations/20170611165120_add_license_to_versions/down.sql | 1 + migrations/20170611165120_add_license_to_versions/up.sql | 1 + 2 files changed, 2 insertions(+) create mode 100644 migrations/20170611165120_add_license_to_versions/down.sql create mode 100644 migrations/20170611165120_add_license_to_versions/up.sql diff --git a/migrations/20170611165120_add_license_to_versions/down.sql b/migrations/20170611165120_add_license_to_versions/down.sql new file mode 100644 index 00000000000..ad8340aee04 --- /dev/null +++ b/migrations/20170611165120_add_license_to_versions/down.sql @@ -0,0 +1 @@ +ALTER TABLE versions DROP COLUMN license; diff --git a/migrations/20170611165120_add_license_to_versions/up.sql b/migrations/20170611165120_add_license_to_versions/up.sql new file mode 100644 index 00000000000..5e8e580a54d --- /dev/null +++ b/migrations/20170611165120_add_license_to_versions/up.sql @@ -0,0 +1 @@ +ALTER TABLE versions ADD COLUMN license VARCHAR; From 4130c66259f2bf997c65b148537c1de5021ad9e2 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Sun, 11 Jun 2017 21:36:33 -0400 Subject: [PATCH 14/29] Created update-licenses to update previous versions of crates to have their corresponding licenses. --- src/bin/update-licenses.rs | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/bin/update-licenses.rs diff --git a/src/bin/update-licenses.rs b/src/bin/update-licenses.rs new file mode 100644 index 00000000000..552975647a7 --- /dev/null +++ b/src/bin/update-licenses.rs @@ -0,0 +1,51 @@ +//! Updates all of the licenses from the existing crates into each of their +//! already existing versions. + +// +// Usage: +// cargo run --bin update-licenses + +extern crate cargo_registry; +extern crate postgres; + +use std::io::prelude::*; + +fn main() { + let conn = cargo_registry::db::connect_now(); + { + let tx = conn.transaction().unwrap(); + transfer(&tx); + tx.set_commit(); + tx.finish().unwrap(); + } +} + +fn transfer(tx: &postgres::transaction::Transaction) { + let stmt = tx.prepare("SELECT id, name, license FROM crates").unwrap(); + let rows = stmt.query(&[]).unwrap(); + + for row in rows.iter() { + let id: i32 = row.get("id"); + let name: String = row.get("name"); + let license: String = row.get("license"); + + println!("Setting the license for all versions of {} to {}.", name, license); + + let num_updated = tx.execute("UPDATE versions SET license = $1 WHERE crate_id = $2", &[&license, &id]).unwrap(); + assert!(num_updated > 0); + } + + get_confirm("Finish committing?"); +} + +fn get_confirm(msg: &str) { + print!("{} [y/N]: ", msg); + std::io::stdout().flush().unwrap(); + + let mut line = String::new(); + std::io::stdin().read_line(&mut line).unwrap(); + + if !line.starts_with("y") { + std::process::exit(0); + } +} \ No newline at end of file From 691b61b39ae4411c0b78baf7c936ca62d45b35c1 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 01:54:25 -0400 Subject: [PATCH 15/29] Removed NewKrate taking a license file. Now, NewVersion will accept the license and validate it. Additionally, Made NewCrate.crate_or_update take an immutable self instead of mutable because it was no longer necessary. --- src/krate.rs | 18 +++++++++--------- src/schema.rs | 1 + src/version.rs | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 8c09683bc94..d7fb0b4309f 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -127,20 +127,18 @@ pub struct NewCrate<'a> { pub documentation: Option<&'a str>, pub readme: Option<&'a str>, pub repository: Option<&'a str>, - pub license: Option<&'a str>, pub max_upload_size: Option, } impl<'a> NewCrate<'a> { pub fn create_or_update( - mut self, + self, conn: &PgConnection, - license_file: Option<&str>, uploader: i32, ) -> CargoResult { use diesel::update; - self.validate(license_file)?; + self.validate()?; self.ensure_name_not_reserved(conn)?; conn.transaction(|| { @@ -161,7 +159,7 @@ impl<'a> NewCrate<'a> { }) } - fn validate(&mut self, license_file: Option<&str>) -> CargoResult<()> { + fn validate(&self) -> CargoResult<()> { fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { let url = match url { Some(s) => s, @@ -1080,11 +1078,10 @@ pub fn new(req: &mut Request) -> CargoResult { documentation: new_crate.documentation.as_ref().map(|s| &**s), readme: new_crate.readme.as_ref().map(|s| &**s), repository: new_crate.repository.as_ref().map(|s| &**s), - license: new_crate.license.as_ref().map(|s| &**s), max_upload_size: None, }; - let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, license_file, user.id)?; + + let krate = persist.create_or_update(&conn, user.id)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { @@ -1111,8 +1108,11 @@ pub fn new(req: &mut Request) -> CargoResult { return Err(human(&format_args!("max upload size is: {}", max))); } + let license = new_crate.license.clone(); + let license_file = new_crate.license_file.as_ref().map(|s| &**s); + // Persist the new version of this crate - let version = NewVersion::new(krate.id, vers, &features)?.save( + let version = NewVersion::new(krate.id, vers, &features, license, license_file)?.save( &conn, &new_crate .authors, diff --git a/src/schema.rs b/src/schema.rs index 65ce72b7281..9f973a040ba 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -172,5 +172,6 @@ table! { downloads -> Int4, features -> Nullable, yanked -> Bool, + license -> Nullable, } } diff --git a/src/version.rs b/src/version.rs index 9656cb34e15..319fafda576 100644 --- a/src/version.rs +++ b/src/version.rs @@ -23,6 +23,7 @@ use user::RequestUser; use util::errors::CargoError; use util::{RequestUtils, CargoResult, ChainError, internal, human}; use {Model, Crate}; +use license_exprs; #[derive(Clone, Identifiable, Associations)] #[belongs_to(Crate)] @@ -35,6 +36,7 @@ pub struct Version { pub downloads: i32, pub features: HashMap>, pub yanked: bool, + pub license: Option, } #[derive(Insertable)] @@ -43,6 +45,7 @@ pub struct NewVersion { crate_id: i32, num: String, features: String, + license: Option, } pub struct Author { @@ -205,13 +208,21 @@ impl NewVersion { crate_id: i32, num: &semver::Version, features: &HashMap>, + license: Option, + license_file: Option<&str>, ) -> CargoResult { let features = json::encode(features)?; - Ok(NewVersion { + + let mut new_version = NewVersion { crate_id: crate_id, num: num.to_string(), features: features, - }) + license: license, + }; + + new_version.validate_license(license_file)?; + + Ok(new_version) } pub fn save(&self, conn: &PgConnection, authors: &[String]) -> CargoResult { @@ -249,6 +260,23 @@ impl NewVersion { Ok(version) }) } + + fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { + if let Some(ref license) = self.license { + for part in license.split('/') { + license_exprs::validate_license_expr(part) + .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + for options, and http://spdx.org/licenses/ \ + for their identifiers", e)))?; + } + } else if license_file.is_some() { + // If no license is given, but a license file is given, flag this + // crate as having a nonstandard license. Note that we don't + // actually do anything else with license_file currently. + self.license = Some(String::from("non-standard")); + } + Ok(()) + } } #[derive(Insertable)] @@ -259,7 +287,7 @@ struct NewAuthor<'a> { } impl Queryable for Version { - type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool); + type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool, Option); fn build(row: Self::Row) -> Self { let features = row.6.map(|s| json::decode(&s).unwrap()).unwrap_or_else( @@ -274,6 +302,7 @@ impl Queryable for Version { downloads: row.5, features: features, yanked: row.7, + license: row.8, } } } @@ -294,6 +323,7 @@ impl Model for Version { downloads: row.get("downloads"), features: features, yanked: row.get("yanked"), + license: row.get("license"), } } fn table_name(_: Option) -> &'static str { From d5f0bdbe50fd6c1de59da2e06dddb753f8705135 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:02:16 -0400 Subject: [PATCH 16/29] Stopped EncodableCrate from returning a license, and instead made EncodableVersion return it. --- src/krate.rs | 2 -- src/version.rs | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index d7fb0b4309f..2a2d6dbc054 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -103,7 +103,6 @@ pub struct EncodableCrate { pub description: Option, pub homepage: Option, pub documentation: Option, - pub license: Option, pub repository: Option, pub links: CrateLinks, pub exact_match: bool, @@ -527,7 +526,6 @@ impl Crate { homepage: homepage, exact_match: exact_match, description: description, - license: license, repository: repository, links: CrateLinks { version_downloads: format!("/api/v1/crates/{}/downloads", name), diff --git a/src/version.rs b/src/version.rs index 319fafda576..e566a59bbb6 100644 --- a/src/version.rs +++ b/src/version.rs @@ -63,6 +63,7 @@ pub struct EncodableVersion { pub downloads: i32, pub features: HashMap>, pub yanked: bool, + pub license: Option, pub links: VersionLinks, } @@ -126,6 +127,7 @@ impl Version { downloads, features, yanked, + license, .. } = self; let num = num.to_string(); @@ -139,6 +141,7 @@ impl Version { downloads: downloads, features: features, yanked: yanked, + license: license, links: VersionLinks { dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num), version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num), @@ -219,7 +222,7 @@ impl NewVersion { features: features, license: license, }; - + new_version.validate_license(license_file)?; Ok(new_version) From 1747eeec356119e613f729744d2281d3c8cad735 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:08:59 -0400 Subject: [PATCH 17/29] Updated the tests to pass. --- src/tests/all.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/all.rs b/src/tests/all.rs index 61b4255a5e7..034fb50ddb8 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -304,7 +304,7 @@ impl<'a> CrateBuilder<'a> { } for version_num in &self.versions { - NewVersion::new(krate.id, version_num, &HashMap::new())? + NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file))? .save(connection, &[])?; } @@ -325,7 +325,7 @@ impl<'a> CrateBuilder<'a> { fn new_version(crate_id: i32, num: &str) -> NewVersion { let num = semver::Version::parse(num).unwrap(); - NewVersion::new(crate_id, &num, &HashMap::new()).unwrap() + NewVersion::new(crate_id, &num, &HashMap::new(), None, None).unwrap() } fn krate(name: &str) -> Crate { From 98f53351470d91674a38aaa0ca191c0b11af9ed2 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 01:54:25 -0400 Subject: [PATCH 18/29] Removed NewKrate taking a license file. Now, NewVersion will accept the license and validate it. Additionally, Made NewCrate.crate_or_update take an immutable self instead of mutable because it was no longer necessary. --- src/krate.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 2a2d6dbc054..e83793f92f4 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -134,6 +134,7 @@ impl<'a> NewCrate<'a> { self, conn: &PgConnection, uploader: i32, + license_file: Option<&str>, ) -> CargoResult { use diesel::update; @@ -1076,10 +1077,11 @@ pub fn new(req: &mut Request) -> CargoResult { documentation: new_crate.documentation.as_ref().map(|s| &**s), readme: new_crate.readme.as_ref().map(|s| &**s), repository: new_crate.repository.as_ref().map(|s| &**s), + license: new_crate.license.as_ref().map(|s| &**s), max_upload_size: None, }; - - let krate = persist.create_or_update(&conn, user.id)?; + let license_file = new_crate.license_file.as_ref().map(|s| &**s); + let krate = persist.create_or_update(&conn, user.id, license_file)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { @@ -1106,14 +1108,14 @@ pub fn new(req: &mut Request) -> CargoResult { return Err(human(&format_args!("max upload size is: {}", max))); } + // This is only redundant for now. Eventually the duplication will be removed. let license = new_crate.license.clone(); - let license_file = new_crate.license_file.as_ref().map(|s| &**s); // Persist the new version of this crate let version = NewVersion::new(krate.id, vers, &features, license, license_file)?.save( &conn, &new_crate - .authors, + .authors )?; // Link this new version to all dependencies From c404f14927274b90b98dfd85157e6f2f29773d86 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:02:16 -0400 Subject: [PATCH 19/29] Stopped EncodableCrate from returning a license, and instead made EncodableVersion return it. --- src/krate.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/krate.rs b/src/krate.rs index e83793f92f4..2e8ffe2d888 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -501,7 +501,6 @@ impl Crate { description, homepage, documentation, - license, repository, .. } = self; From 4e8f84ff939a02c0fd1bd37e8d17688a87f85c11 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 14 Jun 2017 02:08:59 -0400 Subject: [PATCH 20/29] Updated the tests to pass. --- src/krate.rs | 4 ++-- src/tests/all.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 2e8ffe2d888..2c2e815dc72 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -133,8 +133,8 @@ impl<'a> NewCrate<'a> { pub fn create_or_update( self, conn: &PgConnection, - uploader: i32, license_file: Option<&str>, + uploader: i32, ) -> CargoResult { use diesel::update; @@ -1080,7 +1080,7 @@ pub fn new(req: &mut Request) -> CargoResult { max_upload_size: None, }; let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, user.id, license_file)?; + let krate = persist.create_or_update(&conn, license_file, user.id)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { diff --git a/src/tests/all.rs b/src/tests/all.rs index 034fb50ddb8..9c0265e0313 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -304,8 +304,8 @@ impl<'a> CrateBuilder<'a> { } for version_num in &self.versions { - NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file))? - .save(connection, &[])?; + NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file)? + .save(connection, &[])?; } if !self.keywords.is_empty() { From a8b97d4bcb0e713bb8420b2fd327dd8bafbf3909 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Thu, 15 Jun 2017 02:06:33 -0400 Subject: [PATCH 21/29] Added VersionBuilder and converted tests to use it. --- src/tests/all.rs | 57 ++++++++++++++++++++++++++++++++++---------- src/tests/krate.rs | 10 ++++---- src/tests/user.rs | 4 ++-- src/tests/version.rs | 4 ++-- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/tests/all.rs b/src/tests/all.rs index 9c0265e0313..c0bbf292bed 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -214,12 +214,50 @@ fn user(login: &str) -> User { use cargo_registry::util::CargoResult; +struct VersionBuilder<'a> { + version: semver::Version, + license: Option<&'a str>, + license_file: Option<&'a str>, + features: HashMap>, +} + +impl<'a> VersionBuilder<'a> { + fn new(version: &str) -> VersionBuilder { + let version = semver::Version::parse(version).unwrap_or_else( + |e| { + panic!("The version {} is not valid: {}", version, e); + }, + ); + + VersionBuilder { + version: version, + license: None, + license_file: None, + features: HashMap::new(), + } + } + + fn build(self, connection: &PgConnection, crate_id: i32) -> CargoResult { + let license = match self.license { + Some(license) => Some(license.to_owned()), + None => None, + }; + + NewVersion::new( + crate_id, + &self.version, + &self.features, + license, + self.license_file, + )?.save(connection, &[]) + } +} + struct CrateBuilder<'a> { owner_id: i32, krate: NewCrate<'a>, - license_file: Option<&'a str>, downloads: Option, - versions: Vec, + versions: Vec>, keywords: Vec<&'a str>, } @@ -231,7 +269,6 @@ impl<'a> CrateBuilder<'a> { name: name, ..NewCrate::default() }, - license_file: None, downloads: None, versions: Vec::new(), keywords: Vec::new(), @@ -268,10 +305,7 @@ impl<'a> CrateBuilder<'a> { self } - fn version(mut self, version: &str) -> Self { - let version = semver::Version::parse(version).unwrap_or_else(|e| { - panic!("The version {} is not valid: {}", version, e); - }); + fn version(mut self, version: VersionBuilder<'a>) -> Self { self.versions.push(version); self } @@ -298,14 +332,11 @@ impl<'a> CrateBuilder<'a> { } if self.versions.is_empty() { - self.versions.push("0.99.0".parse().expect( - "invalid version number", - )); + self.versions.push(VersionBuilder::new("0.99.0")); } - for version_num in &self.versions { - NewVersion::new(krate.id, version_num, &HashMap::new(), None, self.license_file)? - .save(connection, &[])?; + for version in self.versions { + version.build(&connection, krate.id)?; } if !self.keywords.is_empty() { diff --git a/src/tests/krate.rs b/src/tests/krate.rs index 6875d7b478b..612d87e7be5 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -357,9 +357,9 @@ fn show() { .description("description") .documentation("https://example.com") .homepage("http://example.com") - .version("1.0.0") - .version("0.5.0") - .version("0.5.1") + .version(::VersionBuilder::new("1.0.0")) + .version(::VersionBuilder::new("0.5.0")) + .version(::VersionBuilder::new("0.5.1")) .keyword("kw1") .expect_build(&conn); } @@ -763,7 +763,7 @@ fn new_krate_duplicate_version() { ::sign_in_as(&mut req, &user); ::CrateBuilder::new("foo_dupe", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); @@ -949,7 +949,7 @@ fn download() { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_download", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); } let resp = t_resp!(middle.call(&mut req)); diff --git a/src/tests/user.rs b/src/tests/user.rs index 0e99b3d1246..c2f78b473ce 100644 --- a/src/tests/user.rs +++ b/src/tests/user.rs @@ -155,11 +155,11 @@ fn following() { ::sign_in_as(&mut req, &user); ::CrateBuilder::new("foo_fighters", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); ::CrateBuilder::new("bar_fighters", user.id) - .version("1.0.0") + .version(::VersionBuilder::new("1.0.0")) .expect_build(&conn); } diff --git a/src/tests/version.rs b/src/tests/version.rs index e6fe058299c..ee12ea89434 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -29,8 +29,8 @@ fn index() { let conn = app.diesel_database.get().unwrap(); let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) - .version("2.0.0") - .version("2.0.1") + .version(::VersionBuilder::new("2.0.0")) + .version(::VersionBuilder::new("2.0.1")) .expect_build(&conn); let ids = versions::table .select(versions::id) From 8ed3be0d11b4a75b1f13c8864d2c77d76c7ee3fa Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Thu, 15 Jun 2017 02:40:48 -0400 Subject: [PATCH 22/29] Created a test to make sure license can change between versions. --- src/tests/all.rs | 5 +++++ src/tests/version.rs | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tests/all.rs b/src/tests/all.rs index c0bbf292bed..57851b9b5a8 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -237,6 +237,11 @@ impl<'a> VersionBuilder<'a> { } } + fn license(mut self, license: Option<&'a str>) -> Self { + self.license = license; + self + } + fn build(self, connection: &PgConnection, crate_id: i32) -> CargoResult { let license = match self.license { Some(license) => Some(license.to_owned()), diff --git a/src/tests/version.rs b/src/tests/version.rs index ee12ea89434..f259c33dae5 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -29,8 +29,10 @@ fn index() { let conn = app.diesel_database.get().unwrap(); let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) - .version(::VersionBuilder::new("2.0.0")) - .version(::VersionBuilder::new("2.0.1")) + .version(::VersionBuilder::new("2.0.0") + .license(Some("MIT"))) + .version(::VersionBuilder::new("2.0.1") + .license(Some("MIT/Apache-2.0"))) .expect_build(&conn); let ids = versions::table .select(versions::id) @@ -42,6 +44,14 @@ fn index() { let mut response = ok_resp!(middle.call(&mut req)); let json: VersionList = ::json(&mut response); assert_eq!(json.versions.len(), 2); + + for v in &json.versions { + match v.num.as_ref() { + "2.0.0" => assert_eq!(v.license, Some(String::from("MIT"))), + "2.0.1" => assert_eq!(v.license, Some(String::from("MIT/Apache-2.0"))), + _ => panic!("unexpected version") + } + } } #[test] From e7c07fa18197ede277d0c1a57a88f2a5e3ec28a5 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Mon, 19 Jun 2017 18:27:51 -0400 Subject: [PATCH 23/29] Added the `license` fields back to the Crate/EncodableCrate so that they can still be used in production. --- src/krate.rs | 10 +++++++--- src/tests/all.rs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index 2c2e815dc72..0d62c9ebaac 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -103,6 +103,7 @@ pub struct EncodableCrate { pub description: Option, pub homepage: Option, pub documentation: Option, + pub license: Option, pub repository: Option, pub links: CrateLinks, pub exact_match: bool, @@ -127,18 +128,19 @@ pub struct NewCrate<'a> { pub readme: Option<&'a str>, pub repository: Option<&'a str>, pub max_upload_size: Option, + pub license: Option<&'a str>, } impl<'a> NewCrate<'a> { pub fn create_or_update( - self, + mut self, conn: &PgConnection, license_file: Option<&str>, uploader: i32, ) -> CargoResult { use diesel::update; - self.validate()?; + self.validate(license_file)?; self.ensure_name_not_reserved(conn)?; conn.transaction(|| { @@ -159,7 +161,7 @@ impl<'a> NewCrate<'a> { }) } - fn validate(&self) -> CargoResult<()> { + fn validate(&mut self, license_file: Option<&str>) -> CargoResult<()> { fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { let url = match url { Some(s) => s, @@ -501,6 +503,7 @@ impl Crate { description, homepage, documentation, + license, repository, .. } = self; @@ -526,6 +529,7 @@ impl Crate { homepage: homepage, exact_match: exact_match, description: description, + license: license, repository: repository, links: CrateLinks { version_downloads: format!("/api/v1/crates/{}/downloads", name), diff --git a/src/tests/all.rs b/src/tests/all.rs index 57851b9b5a8..0256ee0733e 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -325,7 +325,7 @@ impl<'a> CrateBuilder<'a> { let mut krate = self.krate.create_or_update( connection, - self.license_file, + None, self.owner_id, )?; From a1911e7a284f8fcb50453560effd310f377c8534 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Mon, 19 Jun 2017 18:40:14 -0400 Subject: [PATCH 24/29] Added back the functionality for the Crate's holding their licensing information. --- src/krate.rs | 30 ++++++++++++++++++++++++++---- src/tests/all.rs | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/krate.rs b/src/krate.rs index f72a33f43c9..851bbc63462 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -103,6 +103,7 @@ pub struct EncodableCrate { pub description: Option, pub homepage: Option, pub documentation: Option, + pub license: Option, pub repository: Option, pub links: CrateLinks, pub exact_match: bool, @@ -132,13 +133,14 @@ pub struct NewCrate<'a> { impl<'a> NewCrate<'a> { pub fn create_or_update( - self, + mut self, conn: &PgConnection, + license_file: Option<&'a str>, uploader: i32, ) -> CargoResult { use diesel::update; - self.validate()?; + self.validate(license_file)?; self.ensure_name_not_reserved(conn)?; conn.transaction(|| { @@ -159,7 +161,7 @@ impl<'a> NewCrate<'a> { }) } - fn validate(&self) -> CargoResult<()> { + fn validate(&mut self, license_file: Option<&'a str>) -> CargoResult<()> { fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { let url = match url { Some(s) => s, @@ -193,6 +195,24 @@ impl<'a> NewCrate<'a> { validate_url(self.homepage, "homepage")?; validate_url(self.documentation, "documentation")?; validate_url(self.repository, "repository")?; + self.validate_license(license_file)?; + Ok(()) + } + + fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { + if let Some(ref license) = self.license { + for part in license.split('/') { + license_exprs::validate_license_expr(part) + .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + for options, and http://spdx.org/licenses/ \ + for their identifiers", e)))?; + } + } else if license_file.is_some() { + // If no license is given, but a license file is given, flag this + // crate as having a nonstandard license. Note that we don't + // actually do anything else with license_file currently. + self.license = Some("non-standard"); + } Ok(()) } @@ -480,6 +500,7 @@ impl Crate { homepage, documentation, repository, + license, .. } = self; let versions_link = match versions { @@ -505,6 +526,7 @@ impl Crate { exact_match: exact_match, description: description, repository: repository, + license: license, links: CrateLinks { version_downloads: format!("/api/v1/crates/{}/downloads", name), versions: versions_link, @@ -1059,7 +1081,7 @@ pub fn new(req: &mut Request) -> CargoResult { }; let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, user.id)?; + let krate = persist.create_or_update(&conn, license_file, user.id)?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, &user)? < Rights::Publish { diff --git a/src/tests/all.rs b/src/tests/all.rs index 053fa740cd6..0256ee0733e 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -325,6 +325,7 @@ impl<'a> CrateBuilder<'a> { let mut krate = self.krate.create_or_update( connection, + None, self.owner_id, )?; From 1497b84a640f7319d527b1f78fb71c89a6423bfc Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Mon, 19 Jun 2017 18:48:35 -0400 Subject: [PATCH 25/29] Stopped taking a reference of a reference. --- src/krate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/krate.rs b/src/krate.rs index 851bbc63462..b46fb01ee44 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -200,7 +200,7 @@ impl<'a> NewCrate<'a> { } fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { - if let Some(ref license) = self.license { + if let Some(license) = self.license { for part in license.split('/') { license_exprs::validate_license_expr(part) .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ From 1be72f9af4c79677609bff3de4e4c69b4dbdd2d9 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Mon, 19 Jun 2017 19:30:57 -0400 Subject: [PATCH 26/29] Ran cargo fmt --- src/app.rs | 4 +- src/badge.rs | 26 +- src/bin/delete-crate.rs | 49 ++- src/bin/delete-version.rs | 14 +- src/bin/fill-in-user-id.rs | 22 +- src/bin/populate.rs | 12 +- src/bin/transfer-crates.rs | 15 +- src/bin/update-downloads.rs | 171 ++++---- src/bin/update-licenses.rs | 21 +- src/categories.rs | 50 ++- src/category.rs | 185 +++++---- src/db.rs | 16 +- src/dependency.rs | 98 ++--- src/dist.rs | 13 +- src/git.rs | 123 +++--- src/http.rs | 32 +- src/keyword.rs | 59 +-- src/krate.rs | 765 ++++++++++++++++++++---------------- src/lib.rs | 21 +- src/owner.rs | 56 +-- src/tests/all.rs | 122 +++--- src/tests/badge.rs | 14 +- src/tests/category.rs | 9 +- src/tests/git.rs | 17 +- src/tests/krate.rs | 302 ++++++++------ src/tests/record.rs | 161 ++++---- src/tests/team.rs | 12 +- src/tests/user.rs | 8 +- src/tests/version.rs | 12 +- src/upload.rs | 24 +- src/uploaders.rs | 72 ++-- src/user/middleware.rs | 10 +- src/user/mod.rs | 108 ++--- src/util/errors.rs | 75 ++-- src/util/head.rs | 18 +- src/util/io_util.rs | 11 +- src/util/mod.rs | 34 +- src/util/request_proxy.rs | 10 +- src/version.rs | 208 +++++----- 39 files changed, 1655 insertions(+), 1324 deletions(-) diff --git a/src/app.rs b/src/app.rs index cf99744f9e6..ae59e6a1a09 100644 --- a/src/app.rs +++ b/src/app.rs @@ -127,6 +127,8 @@ pub trait RequestApp { impl RequestApp for T { fn app(&self) -> &Arc { - self.extensions().find::>().expect("Missing app") + self.extensions() + .find::>() + .expect("Missing app") } } diff --git a/src/badge.rs b/src/badge.rs index bdbcea7fe11..f9b7b81a79f 100644 --- a/src/badge.rs +++ b/src/badge.rs @@ -100,22 +100,26 @@ impl Badge { let json = json!({"badge_type": k, "attributes": attributes_json}); if serde_json::from_value::(json).is_ok() { - new_badges.push(NewBadge { - crate_id: krate.id, - badge_type: &**k, - attributes: attributes_json, - }); + new_badges.push( + NewBadge { + crate_id: krate.id, + badge_type: &**k, + attributes: attributes_json, + }, + ); } else { invalid_badges.push(&**k); } } } - conn.transaction(|| { - delete(badges::table.filter(badges::crate_id.eq(krate.id))) - .execute(conn)?; - insert(&new_badges).into(badges::table).execute(conn)?; - Ok(invalid_badges) - }) + conn.transaction( + || { + delete(badges::table.filter(badges::crate_id.eq(krate.id))) + .execute(conn)?; + insert(&new_badges).into(badges::table).execute(conn)?; + Ok(invalid_badges) + }, + ) } } diff --git a/src/bin/delete-crate.rs b/src/bin/delete-crate.rs index 3e32cec3115..00887fccc5d 100644 --- a/src/bin/delete-crate.rs +++ b/src/bin/delete-crate.rs @@ -55,14 +55,16 @@ fn delete(tx: &postgres::transaction::Transaction) { for v in versions.iter() { println!("deleting version {} ({})", v.num, v.id); let n = tx.execute( - "DELETE FROM version_downloads WHERE version_id = $1", - &[&v.id], - ).unwrap(); + "DELETE FROM version_downloads WHERE version_id = $1", + &[&v.id], + ) + .unwrap(); println!(" {} download records deleted", n); let n = tx.execute( - "DELETE FROM version_authors WHERE version_id = $1", - &[&v.id], - ).unwrap(); + "DELETE FROM version_authors WHERE version_id = $1", + &[&v.id], + ) + .unwrap(); println!(" {} author records deleted", n); let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1", &[&v.id]) .unwrap(); @@ -78,9 +80,10 @@ fn delete(tx: &postgres::transaction::Transaction) { println!("deleting crate download records"); let n = tx.execute( - "DELETE FROM crate_downloads WHERE crate_id = $1", - &[&krate.id], - ).unwrap(); + "DELETE FROM crate_downloads WHERE crate_id = $1", + &[&krate.id], + ) + .unwrap(); println!(" {} deleted", n); println!("deleting crate owners"); @@ -90,29 +93,33 @@ fn delete(tx: &postgres::transaction::Transaction) { println!("disabling reserved crate name trigger"); let _ = tx.execute( - "ALTER TABLE crates DISABLE TRIGGER trigger_ensure_crate_name_not_reserved;", - &[], - ).unwrap(); + "ALTER TABLE crates DISABLE TRIGGER trigger_ensure_crate_name_not_reserved;", + &[], + ) + .unwrap(); println!("deleting crate keyword connections"); let n = tx.execute( - "DELETE FROM crates_keywords WHERE crate_id = $1", - &[&krate.id], - ).unwrap(); + "DELETE FROM crates_keywords WHERE crate_id = $1", + &[&krate.id], + ) + .unwrap(); println!(" {} deleted", n); println!("deleting crate category connections"); let n = tx.execute( - "DELETE FROM crates_categories WHERE crate_id = $1", - &[&krate.id], - ).unwrap(); + "DELETE FROM crates_categories WHERE crate_id = $1", + &[&krate.id], + ) + .unwrap(); println!(" {} deleted", n); println!("enabling reserved crate name trigger"); let _ = tx.execute( - "ALTER TABLE crates ENABLE TRIGGER trigger_ensure_crate_name_not_reserved;", - &[], - ).unwrap(); + "ALTER TABLE crates ENABLE TRIGGER trigger_ensure_crate_name_not_reserved;", + &[], + ) + .unwrap(); println!("deleting crate badges"); let n = tx.execute("DELETE FROM badges WHERE crate_id = $1", &[&krate.id]) diff --git a/src/bin/delete-version.rs b/src/bin/delete-version.rs index 9679323d59c..826cdc968d9 100644 --- a/src/bin/delete-version.rs +++ b/src/bin/delete-version.rs @@ -65,14 +65,16 @@ fn delete(tx: &postgres::transaction::Transaction) { println!("deleting version {} ({})", v.num, v.id); let n = tx.execute( - "DELETE FROM version_downloads WHERE version_id = $1", - &[&v.id], - ).unwrap(); + "DELETE FROM version_downloads WHERE version_id = $1", + &[&v.id], + ) + .unwrap(); println!(" {} download records deleted", n); let n = tx.execute( - "DELETE FROM version_authors WHERE version_id = $1", - &[&v.id], - ).unwrap(); + "DELETE FROM version_authors WHERE version_id = $1", + &[&v.id], + ) + .unwrap(); println!(" {} author records deleted", n); let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1", &[&v.id]) .unwrap(); diff --git a/src/bin/fill-in-user-id.rs b/src/bin/fill-in-user-id.rs index d3a907a2ca1..e8d2d26dd81 100644 --- a/src/bin/fill-in-user-id.rs +++ b/src/bin/fill-in-user-id.rs @@ -56,13 +56,15 @@ fn update(app: &App, tx: &postgres::transaction::Transaction) { let rows = tx.query(query, &[]) .unwrap() .into_iter() - .map(|row| { - let id: i32 = row.get("id"); - let login: String = row.get("gh_login"); - let token: String = row.get("gh_access_token"); - let avatar: Option = row.get("gh_avatar"); - (id, login, http::token(token), avatar) - }) + .map( + |row| { + let id: i32 = row.get("id"); + let login: String = row.get("gh_login"); + let token: String = row.get("gh_access_token"); + let avatar: Option = row.get("gh_avatar"); + (id, login, http::token(token), avatar) + }, + ) .collect::>(); for (id, login, token, avatar) in rows { @@ -78,9 +80,9 @@ fn update(app: &App, tx: &postgres::transaction::Transaction) { } if ghuser.login == login { tx.execute( - "UPDATE users SET gh_id = $1 WHERE id = $2", - &[&ghuser.id, &id], - )?; + "UPDATE users SET gh_id = $1 WHERE id = $2", + &[&ghuser.id, &id], + )?; Ok(()) } else { Err(human(&format_args!("different login: {}", ghuser.login))) diff --git a/src/bin/populate.rs b/src/bin/populate.rs index 8dfa0514f6f..84fe9a31d4e 100644 --- a/src/bin/populate.rs +++ b/src/bin/populate.rs @@ -27,9 +27,9 @@ fn main() { } fn update(tx: &postgres::transaction::Transaction) -> postgres::Result<()> { - let ids = env::args().skip(1).filter_map( - |arg| arg.parse::().ok(), - ); + let ids = env::args() + .skip(1) + .filter_map(|arg| arg.parse::().ok()); for id in ids { let now = time::now_utc().to_timespec(); let mut rng = StdRng::new().unwrap(); @@ -39,11 +39,11 @@ fn update(tx: &postgres::transaction::Transaction) -> postgres::Result<()> { let moment = now + Duration::days(-day); dls += rng.gen_range(-100, 100); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, date) \ VALUES ($1, $2, $3)", - &[&id, &dls, &moment], - )?; + &[&id, &dls, &moment], + )?; } } Ok(()) diff --git a/src/bin/transfer-crates.rs b/src/bin/transfer-crates.rs index 48e507757bb..1e1a4df89cb 100644 --- a/src/bin/transfer-crates.rs +++ b/src/bin/transfer-crates.rs @@ -69,11 +69,13 @@ fn transfer(tx: &postgres::transaction::Transaction) { let stmt = tx.prepare( - "SELECT * FROM crate_owners + "SELECT * FROM crate_owners WHERE owner_id = $1 AND owner_kind = $2", - ).unwrap(); - let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]).unwrap(); + ) + .unwrap(); + let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]) + .unwrap(); for row in rows.iter() { let id: i32 = row.get("id"); let krate = Crate::find(tx, row.get("crate_id")).unwrap(); @@ -83,10 +85,11 @@ fn transfer(tx: &postgres::transaction::Transaction) { println!("warning: not exactly one owner for {}", krate.name); } let n = tx.execute( - "UPDATE crate_owners SET owner_id = $1 + "UPDATE crate_owners SET owner_id = $1 WHERE id $2", - &[&to.id, &id], - ).unwrap(); + &[&to.id, &id], + ) + .unwrap(); assert_eq!(n, 1); } diff --git a/src/bin/update-downloads.rs b/src/bin/update-downloads.rs index 6360c715ee1..da157dc3232 100644 --- a/src/bin/update-downloads.rs +++ b/src/bin/update-downloads.rs @@ -40,11 +40,11 @@ fn update(conn: &postgres::GenericConnection) -> postgres::Result<()> { tx = conn.transaction()?; { let stmt = tx.prepare( - "SELECT * FROM version_downloads \ + "SELECT * FROM version_downloads \ WHERE processed = FALSE AND id > $1 ORDER BY id ASC LIMIT $2", - )?; + )?; let mut rows = stmt.query(&[&max, &LIMIT])?; match collect(&tx, &mut rows)? { None => break, @@ -94,11 +94,11 @@ fn collect( // Flag this row as having been processed if we're passed the cutoff, // and unconditionally increment the number of counted downloads. tx.execute( - "UPDATE version_downloads + "UPDATE version_downloads SET processed = $2, counted = counted + $3 WHERE id = $1", - &[id, &(download.date < cutoff), &amt], - )?; + &[id, &(download.date < cutoff), &amt], + )?; total += amt as i64; if amt == 0 { @@ -109,41 +109,41 @@ fn collect( // Update the total number of version downloads tx.execute( - "UPDATE versions + "UPDATE versions SET downloads = downloads + $1 WHERE id = $2", - &[&amt, &download.version_id], - )?; + &[&amt, &download.version_id], + )?; // Update the total number of crate downloads tx.execute( - "UPDATE crates SET downloads = downloads + $1 + "UPDATE crates SET downloads = downloads + $1 WHERE id = $2", - &[&amt, &crate_id], - )?; + &[&amt, &crate_id], + )?; // Update the total number of crate downloads for today let cnt = tx.execute( - "UPDATE crate_downloads + "UPDATE crate_downloads SET downloads = downloads + $2 WHERE crate_id = $1 AND date = $3", - &[&crate_id, &amt, &download.date], - )?; + &[&crate_id, &amt, &download.date], + )?; if cnt == 0 { tx.execute( - "INSERT INTO crate_downloads + "INSERT INTO crate_downloads (crate_id, downloads, date) VALUES ($1, $2, $3)", - &[&crate_id, &amt, &download.date], - )?; + &[&crate_id, &amt, &download.date], + )?; } } // After everything else is done, update the global counter of total // downloads. tx.execute( - "UPDATE metadata SET total_downloads = total_downloads + $1", - &[&total], - )?; + "UPDATE metadata SET total_downloads = total_downloads + $1", + &[&total], + )?; Ok(Some(max)) } @@ -171,12 +171,16 @@ mod test { fn crate_downloads(tx: &postgres::transaction::Transaction, id: i32, expected: usize) { let stmt = tx.prepare( - "SELECT * FROM crate_downloads + "SELECT * FROM crate_downloads WHERE crate_id = $1", - ).unwrap(); - let dl: i32 = stmt.query(&[&id]).unwrap().iter().next().unwrap().get( - "downloads", - ); + ) + .unwrap(); + let dl: i32 = stmt.query(&[&id]) + .unwrap() + .iter() + .next() + .unwrap() + .get("downloads"); assert_eq!(dl, expected as i32); } @@ -197,26 +201,30 @@ mod test { &None, &None, None, - ).unwrap(); + ) + .unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ).unwrap(); + ) + .unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id) VALUES ($1)", - &[&version.id], - ).unwrap(); + &[&version.id], + ) + .unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, date, processed) VALUES ($1, current_date - interval '1 day', true)", - &[&version.id], - ).unwrap(); + &[&version.id], + ) + .unwrap(); ::update(&tx).unwrap(); assert_eq!(Version::find(&tx, version.id).unwrap().downloads, 1); assert_eq!(Crate::find(&tx, krate.id).unwrap().downloads, 1); @@ -242,25 +250,29 @@ mod test { &None, &None, None, - ).unwrap(); + ) + .unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ).unwrap(); + ) + .unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 2, current_date - interval '2 days', false)", - &[&version.id], - ).unwrap(); + &[&version.id], + ) + .unwrap(); ::update(&tx).unwrap(); let stmt = tx.prepare( - "SELECT processed FROM version_downloads + "SELECT processed FROM version_downloads WHERE version_id = $1", - ).unwrap(); + ) + .unwrap(); let processed: bool = stmt.query(&[&version.id]) .unwrap() .iter() @@ -287,26 +299,30 @@ mod test { &None, &None, None, - ).unwrap(); + ) + .unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ).unwrap(); + ) + .unwrap(); let time = time::now_utc().to_timespec() - Duration::hours(2); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 2, date($2), false)", - &[&version.id, &time], - ).unwrap(); + &[&version.id, &time], + ) + .unwrap(); ::update(&tx).unwrap(); let stmt = tx.prepare( - "SELECT processed FROM version_downloads + "SELECT processed FROM version_downloads WHERE version_id = $1", - ).unwrap(); + ) + .unwrap(); let processed: bool = stmt.query(&[&version.id]) .unwrap() .iter() @@ -333,36 +349,42 @@ mod test { &None, &None, None, - ).unwrap(); + ) + .unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ).unwrap(); + ) + .unwrap(); tx.execute( - "UPDATE versions + "UPDATE versions SET updated_at = current_date - interval '2 hours'", - &[], - ).unwrap(); + &[], + ) + .unwrap(); tx.execute( - "UPDATE crates + "UPDATE crates SET updated_at = current_date - interval '2 hours'", - &[], - ).unwrap(); + &[], + ) + .unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 1, current_date, false)", - &[&version.id], - ).unwrap(); + &[&version.id], + ) + .unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, date) VALUES ($1, current_date - interval '1 day')", - &[&version.id], - ).unwrap(); + &[&version.id], + ) + .unwrap(); let version_before = Version::find(&tx, version.id).unwrap(); let krate_before = Crate::find(&tx, krate.id).unwrap(); @@ -395,30 +417,35 @@ mod test { &None, &None, None, - ).unwrap(); + ) + .unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ).unwrap(); + ) + .unwrap(); tx.execute( - "UPDATE versions + "UPDATE versions SET updated_at = current_date - interval '2 days'", - &[], - ).unwrap(); + &[], + ) + .unwrap(); tx.execute( - "UPDATE crates + "UPDATE crates SET updated_at = current_date - interval '2 days'", - &[], - ).unwrap(); + &[], + ) + .unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 2, current_date - interval '2 days', false)", - &[&version.id], - ).unwrap(); + &[&version.id], + ) + .unwrap(); let version_before = Version::find(&tx, version.id).unwrap(); let krate_before = Crate::find(&tx, krate.id).unwrap(); diff --git a/src/bin/update-licenses.rs b/src/bin/update-licenses.rs index 552975647a7..ac4c213d037 100644 --- a/src/bin/update-licenses.rs +++ b/src/bin/update-licenses.rs @@ -21,7 +21,8 @@ fn main() { } fn transfer(tx: &postgres::transaction::Transaction) { - let stmt = tx.prepare("SELECT id, name, license FROM crates").unwrap(); + let stmt = tx.prepare("SELECT id, name, license FROM crates") + .unwrap(); let rows = stmt.query(&[]).unwrap(); for row in rows.iter() { @@ -29,9 +30,17 @@ fn transfer(tx: &postgres::transaction::Transaction) { let name: String = row.get("name"); let license: String = row.get("license"); - println!("Setting the license for all versions of {} to {}.", name, license); - - let num_updated = tx.execute("UPDATE versions SET license = $1 WHERE crate_id = $2", &[&license, &id]).unwrap(); + println!( + "Setting the license for all versions of {} to {}.", + name, + license + ); + + let num_updated = tx.execute( + "UPDATE versions SET license = $1 WHERE crate_id = $2", + &[&license, &id], + ) + .unwrap(); assert!(num_updated > 0); } @@ -41,11 +50,11 @@ fn transfer(tx: &postgres::transaction::Transaction) { fn get_confirm(msg: &str) { print!("{} [y/N]: ", msg); std::io::stdout().flush().unwrap(); - + let mut line = String::new(); std::io::stdin().read_line(&mut line).unwrap(); if !line.starts_with("y") { std::process::exit(0); } -} \ No newline at end of file +} diff --git a/src/categories.rs b/src/categories.rs index 6a8024cd7a4..de2c068153f 100644 --- a/src/categories.rs +++ b/src/categories.rs @@ -39,16 +39,24 @@ impl Category { } fn required_string_from_toml<'a>(toml: &'a toml::Table, key: &str) -> CargoResult<&'a str> { - toml.get(key).and_then(toml::Value::as_str).chain_error(|| { - internal(&format_args!( + toml.get(key) + .and_then(toml::Value::as_str) + .chain_error( + || { + internal( + &format_args!( "Expected category TOML attribute '{}' to be a String", key - )) - }) + ), + ) + }, + ) } fn optional_string_from_toml<'a>(toml: &'a toml::Table, key: &str) -> &'a str { - toml.get(key).and_then(toml::Value::as_str).unwrap_or("") + toml.get(key) + .and_then(toml::Value::as_str) + .unwrap_or("") } fn categories_from_toml( @@ -70,12 +78,18 @@ fn categories_from_toml( ); if let Some(categories) = details.get("categories") { - let categories = categories.as_table().chain_error(|| { - internal(&format_args!( + let categories = categories + .as_table() + .chain_error( + || { + internal( + &format_args!( "child categories of {} were not a table", slug - )) - })?; + ), + ) + }, + )?; result.extend(categories_from_toml(categories, Some(&category))?); } @@ -91,23 +105,23 @@ pub fn sync() -> CargoResult<()> { let tx = conn.transaction().unwrap(); let categories = include_str!("./categories.toml"); - let toml = toml::Parser::new(categories).parse().expect( - "Could not parse categories.toml", - ); + let toml = toml::Parser::new(categories) + .parse() + .expect("Could not parse categories.toml"); let categories = categories_from_toml(&toml, None).expect("Could not convert categories from TOML"); for category in &categories { tx.execute( - "\ + "\ INSERT INTO categories (slug, category, description) \ VALUES (LOWER($1), $2, $3) \ ON CONFLICT (slug) DO UPDATE \ SET category = EXCLUDED.category, \ description = EXCLUDED.description;", - &[&category.slug, &category.name, &category.description], - )?; + &[&category.slug, &category.name, &category.description], + )?; } let in_clause = categories @@ -117,14 +131,14 @@ pub fn sync() -> CargoResult<()> { .join(","); tx.execute( - &format!( + &format!( "\ DELETE FROM categories \ WHERE slug NOT IN ({});", in_clause ), - &[], - )?; + &[], + )?; tx.set_commit(); tx.finish().unwrap(); Ok(()) diff --git a/src/category.rs b/src/category.rs index c1ea9677ed8..092de5c3a5e 100644 --- a/src/category.rs +++ b/src/category.rs @@ -59,24 +59,26 @@ pub struct EncodableCategoryWithSubcategories { impl Category { pub fn find_by_category(conn: &GenericConnection, name: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM categories \ + "SELECT * FROM categories \ WHERE category = $1", - )?; + )?; let rows = stmt.query(&[&name])?; - rows.iter().next().chain_error(|| NotFound).map(|row| { - Model::from_row(&row) - }) + rows.iter() + .next() + .chain_error(|| NotFound) + .map(|row| Model::from_row(&row)) } pub fn find_by_slug(conn: &GenericConnection, slug: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM categories \ + "SELECT * FROM categories \ WHERE slug = LOWER($1)", - )?; + )?; let rows = stmt.query(&[&slug])?; - rows.iter().next().chain_error(|| NotFound).map(|row| { - Model::from_row(&row) - }) + rows.iter() + .next() + .chain_error(|| NotFound) + .map(|row| Model::from_row(&row)) } pub fn encodable(self) -> EncodableCategory { @@ -105,31 +107,35 @@ impl Category { ) -> QueryResult> { use diesel::expression::dsl::any; - conn.transaction(|| { - let categories = categories::table - .filter(categories::slug.eq(any(slugs))) - .load::(conn)?; - let invalid_categories = slugs - .iter() - .cloned() - .filter(|s| !categories.iter().any(|c| c.slug == *s)) - .collect(); - let crate_categories = categories - .iter() - .map(|c| { - CrateCategory { - category_id: c.id, - crate_id: krate.id, - } - }) - .collect::>(); - - delete(CrateCategory::belonging_to(krate)).execute(conn)?; - insert(&crate_categories) - .into(crates_categories::table) - .execute(conn)?; - Ok(invalid_categories) - }) + conn.transaction( + || { + let categories = categories::table + .filter(categories::slug.eq(any(slugs))) + .load::(conn)?; + let invalid_categories = slugs + .iter() + .cloned() + .filter(|s| !categories.iter().any(|c| c.slug == *s)) + .collect(); + let crate_categories = categories + .iter() + .map( + |c| { + CrateCategory { + category_id: c.id, + crate_id: krate.id, + } + }, + ) + .collect::>(); + + delete(CrateCategory::belonging_to(krate)).execute(conn)?; + insert(&crate_categories) + .into(crates_categories::table) + .execute(conn)?; + Ok(invalid_categories) + }, + ) } pub fn update_crate_old( @@ -145,13 +151,15 @@ impl Category { let mut invalid_categories = vec![]; let new_categories: Vec = categories .iter() - .flat_map(|c| match Category::find_by_slug(conn, c) { - Ok(cat) => Some(cat), - Err(_) => { - invalid_categories.push(c.to_string()); - None - } - }) + .flat_map( + |c| match Category::find_by_slug(conn, c) { + Ok(cat) => Some(cat), + Err(_) => { + invalid_categories.push(c.to_string()); + None + } + }, + ) .collect(); let new_categories_ids: HashSet<_> = new_categories.iter().map(|cat| cat.id).collect(); @@ -167,11 +175,11 @@ impl Category { if !to_rm.is_empty() { conn.execute( - "DELETE FROM crates_categories \ + "DELETE FROM crates_categories \ WHERE category_id = ANY($1) \ AND crate_id = $2", - &[&to_rm, &krate.id], - )?; + &[&to_rm, &krate.id], + )?; } if !to_add.is_empty() { @@ -181,13 +189,13 @@ impl Category { .collect(); let insert = insert.join(", "); conn.execute( - &format!( + &format!( "INSERT INTO crates_categories \ (crate_id, category_id) VALUES {}", insert ), - &[], - )?; + &[], + )?; } Ok(invalid_categories) @@ -222,7 +230,9 @@ impl Category { // Collect all the top-level categories and sum up the crates_cnt of // the crates in all subcategories - select(sql::(&format!( + select( + sql::( + &format!( "c.id, c.category, c.slug, c.description, sum(c2.crates_cnt)::int as crates_cnt, c.created_at FROM categories as c @@ -233,7 +243,10 @@ impl Category { sort_sql, limit, offset - ))).load(conn) + ), + ), + ) + .load(conn) } pub fn toplevel_old( @@ -250,7 +263,8 @@ impl Category { // Collect all the top-level categories and sum up the crates_cnt of // the crates in all subcategories - let stmt = conn.prepare(&format!( + let stmt = conn.prepare( + &format!( "SELECT c.id, c.category, c.slug, c.description, c.created_at, sum(c2.crates_cnt)::int as crates_cnt FROM categories as c @@ -259,7 +273,8 @@ impl Category { GROUP BY c.id {} LIMIT $1 OFFSET $2", sort_sql - ))?; + ), + )?; let categories: Vec<_> = stmt.query(&[&limit, &offset])? .iter() @@ -271,7 +286,7 @@ impl Category { pub fn subcategories(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "\ + "\ SELECT c.id, c.category, c.slug, c.description, c.created_at, \ COALESCE (( \ SELECT sum(c2.crates_cnt)::int \ @@ -282,7 +297,7 @@ impl Category { FROM categories as c \ WHERE c.category ILIKE $1 || '::%' \ AND c.category NOT ILIKE $1 || '::%::%'", - )?; + )?; let rows = stmt.query(&[&self.category])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) @@ -338,7 +353,10 @@ pub fn index(req: &mut Request) -> CargoResult { let sort = query.get("sort").map_or("alpha", String::as_str); let categories = Category::toplevel_old(conn, sort, limit, offset)?; - let categories = categories.into_iter().map(Category::encodable).collect(); + let categories = categories + .into_iter() + .map(Category::encodable) + .collect(); // Query for the total count of categories let total = Category::count_toplevel(conn)?; @@ -353,10 +371,14 @@ pub fn index(req: &mut Request) -> CargoResult { total: i64, } - Ok(req.json(&R { - categories: categories, - meta: Meta { total: total }, - })) + Ok( + req.json( + &R { + categories: categories, + meta: Meta { total: total }, + }, + ), + ) } /// Handles the `GET /categories/:category_id` route. @@ -390,9 +412,9 @@ pub fn show(req: &mut Request) -> CargoResult { pub fn slugs(req: &mut Request) -> CargoResult { let conn = req.tx()?; let stmt = conn.prepare( - "SELECT slug FROM categories \ + "SELECT slug FROM categories \ ORDER BY slug", - )?; + )?; let rows = stmt.query(&[])?; #[derive(RustcEncodable)] @@ -402,13 +424,15 @@ pub fn slugs(req: &mut Request) -> CargoResult { } let slugs: Vec = rows.iter() - .map(|r| { - let slug: String = r.get("slug"); - Slug { - id: slug.clone(), - slug: slug, - } - }) + .map( + |r| { + let slug: String = r.get("slug"); + Slug { + id: slug.clone(), + slug: slug, + } + }, + ) .collect(); #[derive(RustcEncodable)] @@ -440,10 +464,11 @@ mod tests { fn category_toplevel_excludes_subcategories() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug) VALUES + "INSERT INTO categories (category, slug) VALUES ('Cat 2', 'cat2'), ('Cat 1', 'cat1'), ('Cat 1::sub', 'cat1::sub') ", - ).unwrap(); + ) + .unwrap(); let categories = Category::toplevel(&conn, "", 10, 0) .unwrap() @@ -458,10 +483,11 @@ mod tests { fn category_toplevel_orders_by_crates_cnt_when_sort_given() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug, crates_cnt) VALUES + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 0), ('Cat 2', 'cat2', 2), ('Cat 3', 'cat3', 1) ", - ).unwrap(); + ) + .unwrap(); let categories = Category::toplevel(&conn, "crates", 10, 0) .unwrap() @@ -480,10 +506,11 @@ mod tests { fn category_toplevel_applies_limit_and_offset() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug) VALUES + "INSERT INTO categories (category, slug) VALUES ('Cat 1', 'cat1'), ('Cat 2', 'cat2') ", - ).unwrap(); + ) + .unwrap(); let categories = Category::toplevel(&conn, "", 1, 0) .unwrap() @@ -506,12 +533,13 @@ mod tests { fn category_toplevel_includes_subcategories_in_crate_cnt() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug, crates_cnt) VALUES + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 1), ('Cat 1::sub', 'cat1::sub', 2), ('Cat 2', 'cat2', 3), ('Cat 2::Sub 1', 'cat2::sub1', 4), ('Cat 2::Sub 2', 'cat2::sub2', 5), ('Cat 3', 'cat3', 6) ", - ).unwrap(); + ) + .unwrap(); let categories = Category::toplevel(&conn, "crates", 10, 0) .unwrap() @@ -530,12 +558,13 @@ mod tests { fn category_toplevel_applies_limit_and_offset_after_grouping() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug, crates_cnt) VALUES + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 1), ('Cat 1::sub', 'cat1::sub', 2), ('Cat 2', 'cat2', 3), ('Cat 2::Sub 1', 'cat2::sub1', 4), ('Cat 2::Sub 2', 'cat2::sub2', 5), ('Cat 3', 'cat3', 6) ", - ).unwrap(); + ) + .unwrap(); let categories = Category::toplevel(&conn, "crates", 2, 0) .unwrap() diff --git a/src/db.rs b/src/db.rs index 8ed45a18517..715d67b6dca 100644 --- a/src/db.rs +++ b/src/db.rs @@ -150,8 +150,8 @@ impl Transaction { } pub fn conn( - &self, - ) -> CargoResult<&r2d2::PooledConnection> { + &self,) + -> CargoResult<&r2d2::PooledConnection> { if !self.slot.filled() { let conn = self.app.database.get().map_err(|e| { internal(&format_args!("failed to get a database connection: {}", e)) @@ -202,16 +202,16 @@ impl Middleware for TransactionMiddleware { req: &mut Request, res: Result>, ) -> Result> { - let tx = req.mut_extensions().pop::().expect( - "Transaction not present in request", - ); + let tx = req.mut_extensions() + .pop::() + .expect("Transaction not present in request"); if let Some(transaction) = tx.tx.into_inner() { if res.is_ok() && tx.commit.get() == Some(true) { transaction.set_commit(); } - transaction.finish().map_err( - |e| Box::new(e) as Box, - )?; + transaction + .finish() + .map_err(|e| Box::new(e) as Box)?; } res } diff --git a/src/dependency.rs b/src/dependency.rs index 39a148f49d5..6a2c229d4b6 100644 --- a/src/dependency.rs +++ b/src/dependency.rs @@ -85,24 +85,24 @@ impl Dependency { ) -> CargoResult { let req = req.to_string(); let stmt = conn.prepare( - "INSERT INTO dependencies + "INSERT INTO dependencies (version_id, crate_id, req, optional, default_features, features, target, kind) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *", - )?; + )?; let rows = stmt.query( - &[ - &version_id, - &crate_id, - &req, - &optional, - &default_features, - &features, - target, - &(kind as i32), - ], - )?; + &[ + &version_id, + &crate_id, + &req, + &optional, + &default_features, + &features, + target, + &(kind as i32), + ], + )?; Ok(Model::from_row(&rows.iter().next().unwrap())) } @@ -125,10 +125,8 @@ impl Dependency { impl ReverseDependency { pub fn encodable(self) -> EncodableDependency { - self.dependency.encodable( - &self.crate_name, - Some(self.crate_downloads), - ) + self.dependency + .encodable(&self.crate_name, Some(self.crate_downloads)) } } @@ -140,44 +138,48 @@ pub fn add_dependencies( use diesel::insert; let git_and_new_dependencies = deps.iter() - .map(|dep| { - let krate = Crate::by_name(&dep.name).first::(&*conn).map_err( + .map( + |dep| { + let krate = Crate::by_name(&dep.name).first::(&*conn).map_err( |_| { human(&format_args!("no known crate named `{}`", &*dep.name)) }, )?; - if dep.version_req == semver::VersionReq::parse("*").unwrap() { - return Err(human( - "wildcard (`*`) dependency constraints are not allowed \ + if dep.version_req == semver::VersionReq::parse("*").unwrap() { + return Err( + human( + "wildcard (`*`) dependency constraints are not allowed \ on crates.io. See http://doc.crates.io/faq.html#can-\ libraries-use--as-a-version-for-their-dependencies for more \ information", - )); - } - let features: Vec<_> = dep.features.iter().map(|s| &**s).collect(); - - Ok(( - git::Dependency { - name: dep.name.to_string(), - req: dep.version_req.to_string(), - features: features.iter().map(|s| s.to_string()).collect(), - optional: dep.optional, - default_features: dep.default_features, - target: dep.target.clone(), - kind: dep.kind.or(Some(Kind::Normal)), - }, - NewDependency { - version_id: version_id, - crate_id: krate.id, - req: dep.version_req.to_string(), - kind: dep.kind.unwrap_or(Kind::Normal) as i32, - optional: dep.optional, - default_features: dep.default_features, - features: features, - target: dep.target.as_ref().map(|s| &**s), - }, - )) - }) + ), + ); + } + let features: Vec<_> = dep.features.iter().map(|s| &**s).collect(); + + Ok( + (git::Dependency { + name: dep.name.to_string(), + req: dep.version_req.to_string(), + features: features.iter().map(|s| s.to_string()).collect(), + optional: dep.optional, + default_features: dep.default_features, + target: dep.target.clone(), + kind: dep.kind.or(Some(Kind::Normal)), + }, + NewDependency { + version_id: version_id, + crate_id: krate.id, + req: dep.version_req.to_string(), + kind: dep.kind.unwrap_or(Kind::Normal) as i32, + optional: dep.optional, + default_features: dep.default_features, + features: features, + target: dep.target.as_ref().map(|s| &**s), + }), + ) + }, + ) .collect::, _>>()?; let (git_deps, new_dependencies): (Vec<_>, Vec<_>) = diff --git a/src/dist.rs b/src/dist.rs index ba83b84d20f..1dff06dcb51 100644 --- a/src/dist.rs +++ b/src/dist.rs @@ -42,11 +42,14 @@ impl Handler for Middleware { .map(|accept| accept.iter().any(|s| s.contains("html"))) .unwrap_or(false); if wants_html { - self.dist.call(&mut RequestProxy { - other: req, - path: Some("/index.html"), - method: None, - }) + self.dist + .call( + &mut RequestProxy { + other: req, + path: Some("/index.html"), + method: None, + }, + ) } else { self.handler.as_ref().unwrap().call(req) } diff --git a/src/git.rs b/src/git.rs index 751bac4c8f5..04223c33ad1 100644 --- a/src/git.rs +++ b/src/git.rs @@ -51,26 +51,24 @@ pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> { let repo_path = repo.workdir().unwrap(); let dst = index_file(repo_path, &krate.name); - commit_and_push(repo, || { - // Add the crate to its relevant file - fs::create_dir_all(dst.parent().unwrap())?; - let mut prev = String::new(); - if fs::metadata(&dst).is_ok() { - File::open(&dst).and_then( - |mut f| f.read_to_string(&mut prev), - )?; + commit_and_push( + repo, || { + // Add the crate to its relevant file + fs::create_dir_all(dst.parent().unwrap())?; + let mut prev = String::new(); + if fs::metadata(&dst).is_ok() { + File::open(&dst) + .and_then(|mut f| f.read_to_string(&mut prev))?; + } + let s = json::encode(krate).unwrap(); + let new = prev + &s; + let mut f = File::create(&dst)?; + f.write_all(new.as_bytes())?; + f.write_all(b"\n")?; + + Ok((format!("Updating crate `{}#{}`", krate.name, krate.vers), dst.clone()),) } - let s = json::encode(krate).unwrap(); - let new = prev + &s; - let mut f = File::create(&dst)?; - f.write_all(new.as_bytes())?; - f.write_all(b"\n")?; - - Ok(( - format!("Updating crate `{}#{}`", krate.name, krate.vers), - dst.clone(), - )) - }) + ) } pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> { @@ -78,38 +76,41 @@ pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> let repo_path = repo.workdir().unwrap(); let dst = index_file(repo_path, krate); - commit_and_push(&repo, || { - let mut prev = String::new(); - File::open(&dst).and_then( - |mut f| f.read_to_string(&mut prev), - )?; - let new = prev.lines() - .map(|line| { - let mut git_crate = json::decode::(line).map_err(|_| { + commit_and_push( + &repo, || { + let mut prev = String::new(); + File::open(&dst) + .and_then(|mut f| f.read_to_string(&mut prev))?; + let new = prev.lines() + .map( + |line| { + let mut git_crate = json::decode::(line).map_err(|_| { internal(&format_args!("couldn't decode: `{}`", line)) })?; - if git_crate.name != krate || git_crate.vers != version.to_string() { - return Ok(line.to_string()); - } - git_crate.yanked = Some(yanked); - Ok(json::encode(&git_crate).unwrap()) - }) - .collect::>>(); - let new = new?.join("\n"); - let mut f = File::create(&dst)?; - f.write_all(new.as_bytes())?; - f.write_all(b"\n")?; - - Ok(( - format!( + if git_crate.name != krate || git_crate.vers != version.to_string() { + return Ok(line.to_string()); + } + git_crate.yanked = Some(yanked); + Ok(json::encode(&git_crate).unwrap()) + }, + ) + .collect::>>(); + let new = new?.join("\n"); + let mut f = File::create(&dst)?; + f.write_all(new.as_bytes())?; + f.write_all(b"\n")?; + + Ok( + (format!( "{} crate `{}#{}`", if yanked { "Yanking" } else { "Unyanking" }, krate, version ), - dst.clone(), - )) - }) + dst.clone()), + ) + } + ) } fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> @@ -140,14 +141,7 @@ where let head = repo.head()?; let parent = repo.find_commit(head.target().unwrap())?; let sig = repo.signature()?; - repo.commit( - Some("HEAD"), - &sig, - &sig, - &msg, - &tree, - &[&parent], - )?; + repo.commit(Some("HEAD"), &sig, &sig, &msg, &tree, &[&parent])?; // git push let mut ref_status = None; @@ -155,11 +149,13 @@ where let res = { let mut callbacks = git2::RemoteCallbacks::new(); callbacks.credentials(credentials); - callbacks.push_update_reference(|refname, status| { - assert_eq!(refname, "refs/heads/master"); - ref_status = status.map(|s| s.to_string()); - Ok(()) - }); + callbacks.push_update_reference( + |refname, status| { + assert_eq!(refname, "refs/heads/master"); + ref_status = status.map(|s| s.to_string()); + Ok(()) + }, + ); let mut opts = git2::PushOptions::new(); opts.remote_callbacks(callbacks); origin.push(&["refs/heads/master"], Some(&mut opts)) @@ -172,12 +168,13 @@ where let mut callbacks = git2::RemoteCallbacks::new(); callbacks.credentials(credentials); - origin.update_tips( - Some(&mut callbacks), - true, - git2::AutotagOption::Unspecified, - None, - )?; + origin + .update_tips( + Some(&mut callbacks), + true, + git2::AutotagOption::Unspecified, + None, + )?; // Ok, we need to update, so fetch and reset --hard origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?; diff --git a/src/http.rs b/src/http.rs index 4767239958a..4a638c0abfc 100644 --- a/src/http.rs +++ b/src/http.rs @@ -32,10 +32,12 @@ pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec), cur { let mut transfer = handle.transfer(); transfer - .write_function(|buf| { - data.extend_from_slice(buf); - Ok(buf.len()) - }) + .write_function( + |buf| { + data.extend_from_slice(buf); + Ok(buf.len()) + }, + ) .unwrap(); transfer.perform()?; } @@ -47,30 +49,36 @@ pub fn parse_github_response(mut resp: Easy, data: &[u8]) -> Cargo match resp.response_code().unwrap() { 200 => {} // Ok! 403 => { - return Err(human( - "It looks like you don't have permission \ + return Err( + human( + "It looks like you don't have permission \ to query a necessary property from Github \ to complete this request. \ You may need to re-authenticate on \ crates.io to grant permission to read \ github org memberships. Just go to \ https://crates.io/login", - )); + ), + ); } n => { let resp = String::from_utf8_lossy(data); - return Err(internal(&format_args!( + return Err( + internal( + &format_args!( "didn't get a 200 result from \ github, got {} with: {}", n, resp - ))); + ), + ), + ); } } - let json = str::from_utf8(data).ok().chain_error(|| { - internal("github didn't send a utf8-response") - })?; + let json = str::from_utf8(data) + .ok() + .chain_error(|| internal("github didn't send a utf8-response"))?; json::decode(json).chain_error(|| internal("github didn't send a valid json response")) } diff --git a/src/keyword.rs b/src/keyword.rs index 0b7990eac10..c34c207ffe2 100644 --- a/src/keyword.rs +++ b/src/keyword.rs @@ -79,9 +79,9 @@ impl Keyword { return false; } name.chars().next().unwrap().is_alphanumeric() && - name.chars().all( - |c| c.is_alphanumeric() || c == '_' || c == '-', - ) && name.chars().all(|c| c.is_ascii()) + name.chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && + name.chars().all(|c| c.is_ascii()) } pub fn encodable(self) -> EncodableKeyword { @@ -100,25 +100,28 @@ impl Keyword { } pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> { - conn.transaction(|| { - let keywords = Keyword::find_or_create_all(conn, keywords)?; - diesel::delete(CrateKeyword::belonging_to(krate)).execute( - conn, - )?; - let crate_keywords = keywords - .into_iter() - .map(|kw| { - CrateKeyword { - crate_id: krate.id, - keyword_id: kw.id, - } - }) - .collect::>(); - diesel::insert(&crate_keywords) - .into(crates_keywords::table) - .execute(conn)?; - Ok(()) - }) + conn.transaction( + || { + let keywords = Keyword::find_or_create_all(conn, keywords)?; + diesel::delete(CrateKeyword::belonging_to(krate)) + .execute(conn)?; + let crate_keywords = keywords + .into_iter() + .map( + |kw| { + CrateKeyword { + crate_id: krate.id, + keyword_id: kw.id, + } + }, + ) + .collect::>(); + diesel::insert(&crate_keywords) + .into(crates_keywords::table) + .execute(conn)?; + Ok(()) + }, + ) } } @@ -175,10 +178,14 @@ pub fn index(req: &mut Request) -> CargoResult { total: i64, } - Ok(req.json(&R { - keywords: kws, - meta: Meta { total: total }, - })) + Ok( + req.json( + &R { + keywords: kws, + meta: Meta { total: total }, + }, + ), + ) } /// Handles the `GET /keywords/:keyword_id` route. diff --git a/src/krate.rs b/src/krate.rs index b46fb01ee44..b6b0765d1eb 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -69,20 +69,18 @@ type AllColumns = (crates::id, crates::repository, crates::max_upload_size); -pub const ALL_COLUMNS: AllColumns = ( - crates::id, - crates::name, - crates::updated_at, - crates::created_at, - crates::downloads, - crates::description, - crates::homepage, - crates::documentation, - crates::readme, - crates::license, - crates::repository, - crates::max_upload_size, -); +pub const ALL_COLUMNS: AllColumns = (crates::id, + crates::name, + crates::updated_at, + crates::created_at, + crates::downloads, + crates::description, + crates::homepage, + crates::documentation, + crates::readme, + crates::license, + crates::repository, + crates::max_upload_size); pub const MAX_NAME_LENGTH: usize = 64; @@ -143,22 +141,24 @@ impl<'a> NewCrate<'a> { self.validate(license_file)?; self.ensure_name_not_reserved(conn)?; - conn.transaction(|| { - // To avoid race conditions, we try to insert - // first so we know whether to add an owner - if let Some(krate) = self.save_new_crate(conn, uploader)? { - return Ok(krate); - } + conn.transaction( + || { + // To avoid race conditions, we try to insert + // first so we know whether to add an owner + if let Some(krate) = self.save_new_crate(conn, uploader)? { + return Ok(krate); + } - let target = crates::table.filter(canon_crate_name(crates::name).eq( + let target = crates::table.filter(canon_crate_name(crates::name).eq( canon_crate_name(self.name), )); - update(target) - .set(&self) - .returning(ALL_COLUMNS) - .get_result(conn) - .map_err(Into::into) - }) + update(target) + .set(&self) + .returning(ALL_COLUMNS) + .get_result(conn) + .map_err(Into::into) + }, + ) } fn validate(&mut self, license_file: Option<&'a str>) -> CargoResult<()> { @@ -173,21 +173,29 @@ impl<'a> NewCrate<'a> { match &url.scheme()[..] { "http" | "https" => {} s => { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "`{}` has an invalid url \ scheme: `{}`", field, s - ))) + ), + ), + ) } } if url.cannot_be_a_base() { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "`{}` must have relative scheme \ data: {}", field, url - ))); + ), + ), + ); } Ok(()) } @@ -202,10 +210,16 @@ impl<'a> NewCrate<'a> { fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { if let Some(license) = self.license { for part in license.split('/') { - license_exprs::validate_license_expr(part) - .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + license_exprs::validate_license_expr(part) + .map_err( + |e| { + human( + &format_args!("{}; see http://opensource.org/licenses \ for options, and http://spdx.org/licenses/ \ - for their identifiers", e)))?; + for their identifiers", e), + ) + }, + )?; } } else if license_file.is_some() { // If no license is given, but a license file is given, flag this @@ -221,13 +235,15 @@ impl<'a> NewCrate<'a> { use diesel::select; use diesel::expression::dsl::exists; - let reserved_name = select(exists( - reserved_crate_names.filter(canon_crate_name(name).eq( - canon_crate_name( - self.name, + let reserved_name = select( + exists( + reserved_crate_names.filter( + canon_crate_name(name) + .eq(canon_crate_name(self.name)), ), - )), - )).get_result::(conn)?; + ), + ) + .get_result::(conn)?; if reserved_name { Err(human("cannot upload a crate with a reserved name")) } else { @@ -239,25 +255,27 @@ impl<'a> NewCrate<'a> { use schema::crates::dsl::*; use diesel::insert; - conn.transaction(|| { - let maybe_inserted = insert(&self.on_conflict_do_nothing()) - .into(crates) - .returning(ALL_COLUMNS) - .get_result::(conn) - .optional()?; - - if let Some(ref krate) = maybe_inserted { - let owner = CrateOwner { - crate_id: krate.id, - owner_id: user_id, - created_by: user_id, - owner_kind: OwnerKind::User as i32, - }; - insert(&owner).into(crate_owners::table).execute(conn)?; - } + conn.transaction( + || { + let maybe_inserted = insert(&self.on_conflict_do_nothing()) + .into(crates) + .returning(ALL_COLUMNS) + .get_result::(conn) + .optional()?; + + if let Some(ref krate) = maybe_inserted { + let owner = CrateOwner { + crate_id: krate.id, + owner_id: user_id, + created_by: user_id, + owner_kind: OwnerKind::User as i32, + }; + insert(&owner).into(crate_owners::table).execute(conn)?; + } - Ok(maybe_inserted) - }) + Ok(maybe_inserted) + }, + ) } } @@ -274,10 +292,10 @@ impl Crate { pub fn find_by_name(conn: &GenericConnection, name: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM crates \ + "SELECT * FROM crates \ WHERE canon_crate_name(name) = canon_crate_name($1) LIMIT 1", - )?; + )?; let rows = stmt.query(&[&name])?; let row = rows.iter().next(); let row = row.chain_error(|| NotFound)?; @@ -327,7 +345,7 @@ impl Crate { // TODO: like with users, this is sadly racy let stmt = conn.prepare( - "UPDATE crates + "UPDATE crates SET documentation = $1, homepage = $2, description = $3, @@ -337,62 +355,64 @@ impl Crate { WHERE canon_crate_name(name) = canon_crate_name($7) RETURNING *", - )?; + )?; let rows = stmt.query( - &[ - &documentation, - &homepage, - &description, - &readme, - &license, - &repository, - &name, - ], - )?; + &[ + &documentation, + &homepage, + &description, + &readme, + &license, + &repository, + &name, + ], + )?; if let Some(row) = rows.iter().next() { return Ok(Model::from_row(&row)); } let stmt = conn.prepare( - "SELECT 1 FROM reserved_crate_names + "SELECT 1 FROM reserved_crate_names WHERE canon_crate_name(name) = canon_crate_name($1)", - )?; + )?; let rows = stmt.query(&[&name])?; if !rows.is_empty() { return Err(human("cannot upload a crate with a reserved name")); } let stmt = conn.prepare( - "INSERT INTO crates + "INSERT INTO crates (name, description, homepage, documentation, readme, repository, license, max_upload_size) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *", - )?; + )?; let rows = stmt.query( - &[ - &name, - &description, - &homepage, - &documentation, - &readme, - &repository, - &license, - &max_upload_size, - ], - )?; - let ret: Crate = Model::from_row(&rows.iter().next().chain_error( - || internal("no crate returned"), - )?); + &[ + &name, + &description, + &homepage, + &documentation, + &readme, + &repository, + &license, + &max_upload_size, + ], + )?; + let ret: Crate = Model::from_row( + &rows.iter() + .next() + .chain_error(|| internal("no crate returned"))?, + ); conn.execute( - "INSERT INTO crate_owners + "INSERT INTO crate_owners (crate_id, owner_id, created_by, owner_kind) VALUES ($1, $2, $2, $3)", - &[&ret.id, &user_id, &(OwnerKind::User as i32)], - )?; + &[&ret.id, &user_id, &(OwnerKind::User as i32)], + )?; return Ok(ret); fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { @@ -406,21 +426,29 @@ impl Crate { match &url.scheme()[..] { "http" | "https" => {} s => { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "`{}` has an invalid url \ scheme: `{}`", field, s - ))) + ), + ), + ) } } if url.cannot_be_a_base() { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "`{}` must have relative scheme \ data: {}", field, url - ))); + ), + ), + ); } Ok(()) } @@ -432,14 +460,18 @@ impl Crate { .map(license_exprs::validate_license_expr) .collect::, _>>() .map(|_| ()) - .map_err(|e| { - human(&format_args!( + .map_err( + |e| { + human( + &format_args!( "{}; see http://opensource.org/licenses \ for options, and http://spdx.org/licenses/ \ for their identifiers", e - )) - }) + ), + ) + }, + ) } } @@ -454,9 +486,9 @@ impl Crate { return false; } name.chars().next().unwrap().is_alphabetic() && - name.chars().all( - |c| c.is_alphanumeric() || c == '_' || c == '-', - ) && name.chars().all(|c| c.is_ascii()) + name.chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && + name.chars().all(|c| c.is_ascii()) } pub fn valid_feature_name(name: &str) -> bool { @@ -550,22 +582,24 @@ impl Crate { pub fn max_version_old(&self, conn: &GenericConnection) -> CargoResult { let stmt = conn.prepare( - "SELECT num FROM versions WHERE crate_id = $1 + "SELECT num FROM versions WHERE crate_id = $1 AND yanked = 'f'", - )?; + )?; let rows = stmt.query(&[&self.id])?; - Ok(Version::max( - rows.iter().map(|r| r.get::<_, String>("num")).map(|s| { - semver::Version::parse(&s).unwrap() - }), - )) + Ok( + Version::max( + rows.iter() + .map(|r| r.get::<_, String>("num")) + .map(|s| semver::Version::parse(&s).unwrap()), + ), + ) } pub fn versions(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT * FROM versions \ + "SELECT * FROM versions \ WHERE crate_id = $1", - )?; + )?; let rows = stmt.query(&[&self.id])?; let mut ret = rows.iter() .map(|r| Model::from_row(&r)) @@ -596,28 +630,36 @@ impl Crate { pub fn owners_old(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT * FROM users + "SELECT * FROM users INNER JOIN crate_owners ON crate_owners.owner_id = users.id WHERE crate_owners.crate_id = $1 AND crate_owners.deleted = FALSE AND crate_owners.owner_kind = $2", - )?; + )?; let user_rows = stmt.query(&[&self.id, &(OwnerKind::User as i32)])?; let stmt = conn.prepare( - "SELECT * FROM teams + "SELECT * FROM teams INNER JOIN crate_owners ON crate_owners.owner_id = teams.id WHERE crate_owners.crate_id = $1 AND crate_owners.deleted = FALSE AND crate_owners.owner_kind = $2", - )?; + )?; let team_rows = stmt.query(&[&self.id, &(OwnerKind::Team as i32)])?; let mut owners = vec![]; - owners.extend(user_rows.iter().map(|r| Owner::User(Model::from_row(&r)))); - owners.extend(team_rows.iter().map(|r| Owner::Team(Model::from_row(&r)))); + owners.extend( + user_rows + .iter() + .map(|r| Owner::User(Model::from_row(&r))), + ); + owners.extend( + team_rows + .iter() + .map(|r| Owner::Team(Model::from_row(&r))), + ); Ok(owners) } @@ -634,11 +676,15 @@ impl Crate { if team.contains_user(app, req_user)? { Owner::Team(team) } else { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "only members of {} can add it as \ an owner", login - ))); + ), + ), + ); } } Err(err) => { @@ -656,11 +702,14 @@ impl Crate { created_by: req_user.id, owner_kind: owner.kind() as i32, }; - diesel::insert(&crate_owner.on_conflict( - crate_owners::table.primary_key(), - do_update().set(crate_owners::deleted.eq(false)), - )).into(crate_owners::table) - .execute(conn)?; + diesel::insert( + &crate_owner.on_conflict( + crate_owners::table.primary_key(), + do_update().set(crate_owners::deleted.eq(false)), + ), + ) + .into(crate_owners::table) + .execute(conn)?; Ok(()) } @@ -671,9 +720,9 @@ impl Crate { _req_user: &User, login: &str, ) -> CargoResult<()> { - let owner = Owner::find_by_login(conn, login).map_err(|_| { - human(&format_args!("could not find owner with login `{}`", login)) - })?; + let owner = + Owner::find_by_login(conn, login) + .map_err(|_| human(&format_args!("could not find owner with login `{}`", login)),)?; let target = crate_owners::table.find((self.id(), owner.id(), owner.kind() as i32)); diesel::update(target) .set(crate_owners::deleted.eq(true)) @@ -689,40 +738,38 @@ impl Crate { authors: &[String], ) -> CargoResult { if Version::find_by_num(conn, self.id, ver)?.is_some() { - return Err(human( - &format_args!("crate version `{}` is already uploaded", ver), - )); + return Err(human(&format_args!("crate version `{}` is already uploaded", ver)),); } Version::insert(conn, self.id, ver, features, authors) } pub fn keywords(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT keywords.* FROM keywords + "SELECT keywords.* FROM keywords LEFT JOIN crates_keywords ON keywords.id = crates_keywords.keyword_id WHERE crates_keywords.crate_id = $1", - )?; + )?; let rows = stmt.query(&[&self.id])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) } pub fn categories(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT categories.* FROM categories \ + "SELECT categories.* FROM categories \ LEFT JOIN crates_categories \ ON categories.id = \ crates_categories.category_id \ WHERE crates_categories.crate_id = $1", - )?; + )?; let rows = stmt.query(&[&self.id])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) } pub fn badges(&self, conn: &PgConnection) -> QueryResult> { - badges::table.filter(badges::crate_id.eq(self.id)).load( - conn, - ) + badges::table + .filter(badges::crate_id.eq(self.id)) + .load(conn) } /// Returns (dependency, dependent crate name, dependent crate downloads) @@ -780,11 +827,7 @@ pub fn index(req: &mut Request) -> CargoResult { let sort = params.get("sort").map(|s| &**s).unwrap_or("alpha"); let mut query = crates::table - .select(( - ALL_COLUMNS, - sql::("COUNT(*) OVER ()"), - sql::("false"), - )) + .select((ALL_COLUMNS, sql::("COUNT(*) OVER ()"), sql::("false")),) .limit(limit) .offset(offset) .into_boxed(); @@ -797,11 +840,10 @@ pub fn index(req: &mut Request) -> CargoResult { if let Some(q_string) = params.get("q") { let q = plainto_tsquery(q_string); - query = query.filter(q.matches(crates::textsearchable_index_col).or( - crates::name.eq( - q_string, - ), - )); + query = query.filter( + q.matches(crates::textsearchable_index_col) + .or(crates::name.eq(q_string)), + ); query = query.select(( ALL_COLUMNS, @@ -823,10 +865,18 @@ pub fn index(req: &mut Request) -> CargoResult { crates_categories::table .select(crates_categories::crate_id) .inner_join(categories::table) - .filter(categories::slug.eq(cat).or(categories::slug.like(format!( + .filter( + categories::slug + .eq(cat) + .or( + categories::slug.like( + format!( "{}::%", cat - )))), + ), + ), + ), + ), ), ); } @@ -853,19 +903,22 @@ pub fn index(req: &mut Request) -> CargoResult { query = query.filter(canon_crate_name(crates::name).like(pattern)); } else if let Some(user_id) = params.get("user_id").and_then(|s| s.parse::().ok()) { query = query.filter( - crates::id.eq_any( - crate_owners::table - .select(crate_owners::crate_id) - .filter(crate_owners::owner_id.eq(user_id)) - .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)), - ), + crates::id + .eq_any( + crate_owners::table + .select(crate_owners::crate_id) + .filter(crate_owners::owner_id.eq(user_id)) + .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)), + ), ); } else if params.get("following").is_some() { - query = query.filter(crates::id.eq_any( - follows::table.select(follows::crate_id).filter( - follows::user_id.eq(req.user()?.id), + query = query.filter( + crates::id.eq_any( + follows::table + .select(follows::crate_id) + .filter(follows::user_id.eq(req.user()?.id)), ), - )); + ); } let data = query.load::<(Crate, i64, bool)>(&*conn)?; @@ -884,18 +937,16 @@ pub fn index(req: &mut Request) -> CargoResult { let crates = versions .zip(crates) .zip(perfect_matches) - .map(|((max_version, krate), perfect_match)| { - // FIXME: If we add crate_id to the Badge enum we can eliminate - // this N+1 - let badges = badges::table - .filter(badges::crate_id.eq(krate.id)) - .load::(&*conn)?; - Ok(krate.minimal_encodable( - max_version, - Some(badges), - perfect_match, - )) - }) + .map( + |((max_version, krate), perfect_match)| { + // FIXME: If we add crate_id to the Badge enum we can eliminate + // this N+1 + let badges = badges::table + .filter(badges::crate_id.eq(krate.id)) + .load::(&*conn)?; + Ok(krate.minimal_encodable(max_version, Some(badges), perfect_match),) + }, + ) .collect::>()?; #[derive(RustcEncodable)] @@ -908,10 +959,14 @@ pub fn index(req: &mut Request) -> CargoResult { total: i64, } - Ok(req.json(&R { - crates: crates, - meta: Meta { total: total }, - })) + Ok( + req.json( + &R { + crates: crates, + meta: Meta { total: total }, + }, + ), + ) } /// Handles the `GET /summary` route. @@ -932,9 +987,7 @@ pub fn summary(req: &mut Request) -> CargoResult { .into_iter() .map(|versions| Version::max(versions.into_iter().map(|v| v.num))) .zip(krates) - .map(|(max_version, krate)| { - Ok(krate.minimal_encodable(max_version, None, false)) - }) + .map(|(max_version, krate)| Ok(krate.minimal_encodable(max_version, None, false)),) .collect() }; @@ -978,15 +1031,19 @@ pub fn summary(req: &mut Request) -> CargoResult { popular_keywords: Vec, popular_categories: Vec, } - Ok(req.json(&R { - num_downloads: num_downloads, - num_crates: num_crates, - new_crates: encode_crates(new_crates)?, - most_downloaded: encode_crates(most_downloaded)?, - just_updated: encode_crates(just_updated)?, - popular_keywords: popular_keywords, - popular_categories: popular_categories, - })) + Ok( + req.json( + &R { + num_downloads: num_downloads, + num_crates: num_crates, + new_crates: encode_crates(new_crates)?, + most_downloaded: encode_crates(most_downloaded)?, + just_updated: encode_crates(just_updated)?, + popular_keywords: popular_keywords, + popular_categories: popular_categories, + }, + ), + ) } /// Handles the `GET /crates/:crate_id` route. @@ -1008,9 +1065,9 @@ pub fn show(req: &mut Request) -> CargoResult { .select(categories::all_columns) .load(&*conn)?; - let badges = badges::table.filter(badges::crate_id.eq(krate.id)).load( - &*conn, - )?; + let badges = badges::table + .filter(badges::crate_id.eq(krate.id)) + .load(&*conn)?; let max_version = krate.max_version(&conn)?; #[derive(RustcEncodable)] @@ -1021,8 +1078,11 @@ pub fn show(req: &mut Request) -> CargoResult { categories: Vec, } Ok( - req.json(&R { - krate: krate.clone().encodable( + req.json( + &R { + krate: krate + .clone() + .encodable( max_version, Some(ids), Some(&kws), @@ -1030,13 +1090,14 @@ pub fn show(req: &mut Request) -> CargoResult { Some(badges), false, ), - versions: versions - .into_iter() - .map(|v| v.encodable(&krate.name)) - .collect(), - keywords: kws.into_iter().map(|k| k.encodable()).collect(), - categories: cats.into_iter().map(|k| k.encodable()).collect(), - }), + versions: versions + .into_iter() + .map(|v| v.encodable(&krate.name)) + .collect(), + keywords: kws.into_iter().map(|k| k.encodable()).collect(), + categories: cats.into_iter().map(|k| k.encodable()).collect(), + }, + ), ) } @@ -1050,12 +1111,7 @@ pub fn new(req: &mut Request) -> CargoResult { let features = new_crate .features .iter() - .map(|(k, v)| { - ( - k[..].to_string(), - v.iter().map(|v| v[..].to_string()).collect(), - ) - }) + .map(|(k, v)| (k[..].to_string(), v.iter().map(|v| v[..].to_string()).collect()),) .collect::>>(); let keywords = new_crate .keywords @@ -1063,120 +1119,132 @@ pub fn new(req: &mut Request) -> CargoResult { .map(|kws| kws.iter().map(|kw| &**kw).collect()) .unwrap_or_else(Vec::new); - let categories = new_crate.categories.as_ref().map(|s| &s[..]).unwrap_or(&[]); + let categories = new_crate + .categories + .as_ref() + .map(|s| &s[..]) + .unwrap_or(&[]); let categories: Vec<_> = categories.iter().map(|k| &**k).collect(); let conn = req.db_conn()?; - conn.transaction(|| { - // Persist the new crate, if it doesn't already exist - let persist = NewCrate { - name: name, - description: new_crate.description.as_ref().map(|s| &**s), - homepage: new_crate.homepage.as_ref().map(|s| &**s), - documentation: new_crate.documentation.as_ref().map(|s| &**s), - readme: new_crate.readme.as_ref().map(|s| &**s), - repository: new_crate.repository.as_ref().map(|s| &**s), - license: new_crate.license.as_ref().map(|s| &**s), - max_upload_size: None, - }; + conn.transaction( + || { + // Persist the new crate, if it doesn't already exist + let persist = NewCrate { + name: name, + description: new_crate.description.as_ref().map(|s| &**s), + homepage: new_crate.homepage.as_ref().map(|s| &**s), + documentation: new_crate.documentation.as_ref().map(|s| &**s), + readme: new_crate.readme.as_ref().map(|s| &**s), + repository: new_crate.repository.as_ref().map(|s| &**s), + license: new_crate.license.as_ref().map(|s| &**s), + max_upload_size: None, + }; - let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, license_file, user.id)?; + let license_file = new_crate.license_file.as_ref().map(|s| &**s); + let krate = persist.create_or_update(&conn, license_file, user.id)?; - let owners = krate.owners(&conn)?; - if rights(req.app(), &owners, &user)? < Rights::Publish { - return Err(human( - "crate name has already been claimed by \ + let owners = krate.owners(&conn)?; + if rights(req.app(), &owners, &user)? < Rights::Publish { + return Err( + human( + "crate name has already been claimed by \ another user", - )); - } + ), + ); + } - if krate.name != name { - return Err(human( - &format_args!("crate was previously named `{}`", krate.name), - )); - } + if krate.name != name { + return Err(human(&format_args!("crate was previously named `{}`", krate.name)),); + } - let length = req.content_length().chain_error(|| { - human("missing header: Content-Length") - })?; - let max = krate.max_upload_size.map(|m| m as u64).unwrap_or( - app.config - .max_upload_size, - ); - if length > max { - return Err(human(&format_args!("max upload size is: {}", max))); - } + let length = req.content_length() + .chain_error(|| human("missing header: Content-Length"))?; + let max = krate + .max_upload_size + .map(|m| m as u64) + .unwrap_or(app.config.max_upload_size); + if length > max { + return Err(human(&format_args!("max upload size is: {}", max))); + } - // This is only redundant for now. Eventually the duplication will be removed. - let license = new_crate.license.clone(); - - // Persist the new version of this crate - let version = NewVersion::new(krate.id, vers, &features, license, license_file)?.save( - &conn, - &new_crate - .authors - )?; - - // Link this new version to all dependencies - let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?; - - // Update all keywords for this crate - Keyword::update_crate(&conn, &krate, &keywords)?; - - // Update all categories for this crate, collecting any invalid categories - // in order to be able to warn about them - let ignored_invalid_categories = Category::update_crate(&conn, &krate, &categories)?; - - // Update all badges for this crate, collecting any invalid badges in - // order to be able to warn about them - let ignored_invalid_badges = Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?; - let max_version = krate.max_version(&conn)?; - - // Upload the crate, return way to delete the crate from the server - // If the git commands fail below, we shouldn't keep the crate on the - // server. - let (cksum, mut bomb) = app.config.uploader.upload(req, &krate, max, vers)?; - - // Register this crate in our local git repo. - let git_crate = git::Crate { - name: name.to_string(), - vers: vers.to_string(), - cksum: cksum.to_hex(), - features: features, - deps: git_deps, - yanked: Some(false), - }; - git::add_crate(&**req.app(), &git_crate).chain_error(|| { - internal(&format_args!( + // This is only redundant for now. Eventually the duplication will be removed. + let license = new_crate.license.clone(); + + // Persist the new version of this crate + let version = NewVersion::new(krate.id, vers, &features, license, license_file)? + .save(&conn, &new_crate.authors)?; + + // Link this new version to all dependencies + let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?; + + // Update all keywords for this crate + Keyword::update_crate(&conn, &krate, &keywords)?; + + // Update all categories for this crate, collecting any invalid categories + // in order to be able to warn about them + let ignored_invalid_categories = Category::update_crate(&conn, &krate, &categories)?; + + // Update all badges for this crate, collecting any invalid badges in + // order to be able to warn about them + let ignored_invalid_badges = + Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?; + let max_version = krate.max_version(&conn)?; + + // Upload the crate, return way to delete the crate from the server + // If the git commands fail below, we shouldn't keep the crate on the + // server. + let (cksum, mut bomb) = app.config.uploader.upload(req, &krate, max, vers)?; + + // Register this crate in our local git repo. + let git_crate = git::Crate { + name: name.to_string(), + vers: vers.to_string(), + cksum: cksum.to_hex(), + features: features, + deps: git_deps, + yanked: Some(false), + }; + git::add_crate(&**req.app(), &git_crate) + .chain_error( + || { + internal( + &format_args!( "could not add crate `{}` to the git repo", name - )) - })?; + ), + ) + }, + )?; - // Now that we've come this far, we're committed! - bomb.path = None; + // Now that we've come this far, we're committed! + bomb.path = None; - #[derive(RustcEncodable)] - struct Warnings<'a> { - invalid_categories: Vec<&'a str>, - invalid_badges: Vec<&'a str>, - } - let warnings = Warnings { - invalid_categories: ignored_invalid_categories, - invalid_badges: ignored_invalid_badges, - }; + #[derive(RustcEncodable)] + struct Warnings<'a> { + invalid_categories: Vec<&'a str>, + invalid_badges: Vec<&'a str>, + } + let warnings = Warnings { + invalid_categories: ignored_invalid_categories, + invalid_badges: ignored_invalid_badges, + }; - #[derive(RustcEncodable)] - struct R<'a> { - krate: EncodableCrate, - warnings: Warnings<'a>, - } - Ok(req.json(&R { - krate: krate.minimal_encodable(max_version, None, false), - warnings: warnings, - })) - }) + #[derive(RustcEncodable)] + struct R<'a> { + krate: EncodableCrate, + warnings: Warnings<'a>, + } + Ok( + req.json( + &R { + krate: krate.minimal_encodable(max_version, None, false), + warnings: warnings, + }, + ), + ) + }, + ) } fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> { @@ -1188,12 +1256,11 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> } let mut json = vec![0; amt as usize]; read_fill(req.body(), &mut json)?; - let json = String::from_utf8(json).map_err(|_| { - human("json body was not valid utf-8") - })?; - let new: upload::NewCrate = json::decode(&json).map_err(|e| { - human(&format_args!("invalid upload request: {:?}", e)) - })?; + let json = String::from_utf8(json) + .map_err(|_| human("json body was not valid utf-8"))?; + let new: upload::NewCrate = + json::decode(&json) + .map_err(|e| human(&format_args!("invalid upload request: {:?}", e)))?; // Make sure required fields are provided fn empty(s: Option<&String>) -> bool { @@ -1211,12 +1278,16 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> missing.push("authors"); } if !missing.is_empty() { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "missing or empty metadata fields: {}. Please \ see http://doc.crates.io/manifest.html#package-metadata for \ how to upload metadata", missing.join(", ") - ))); + ), + ), + ); } let user = req.user()?; @@ -1261,9 +1332,7 @@ fn increment_download_counts(req: &Request, crate_name: &str, version: &str) -> let conn = req.db_conn()?; let version_id = versions .select(id) - .filter(crate_id.eq_any( - Crate::by_name(crate_name).select(crates::id), - )) + .filter(crate_id.eq_any(Crate::by_name(crate_name).select(crates::id)),) .filter(num.eq(version)) .first(&*conn)?; @@ -1294,10 +1363,7 @@ pub fn downloads(req: &mut Request) -> CargoResult { let sum_downloads = sql::("SUM(version_downloads.downloads)"); let extra = VersionDownload::belonging_to(rest) - .select(( - to_char(version_downloads::date, "YYYY-MM-DD"), - sum_downloads, - )) + .select((to_char(version_downloads::date, "YYYY-MM-DD"), sum_downloads),) .filter(version_downloads::date.gt(date(now - 90.days()))) .group_by(version_downloads::date) .order(version_downloads::date.asc()) @@ -1318,10 +1384,14 @@ pub fn downloads(req: &mut Request) -> CargoResult { extra_downloads: Vec, } let meta = Meta { extra_downloads: extra }; - Ok(req.json(&R { - version_downloads: downloads, - meta: meta, - })) + Ok( + req.json( + &R { + version_downloads: downloads, + meta: meta, + }, + ), + ) } #[derive(Insertable, Queryable, Identifiable, Associations)] @@ -1337,11 +1407,15 @@ fn follow_target(req: &mut Request) -> CargoResult { let user = req.user()?; let conn = req.db_conn()?; let crate_name = &req.params()["crate_id"]; - let crate_id = Crate::by_name(crate_name).select(crates::id).first(&*conn)?; - Ok(Follow { - user_id: user.id, - crate_id: crate_id, - }) + let crate_id = Crate::by_name(crate_name) + .select(crates::id) + .first(&*conn)?; + Ok( + Follow { + user_id: user.id, + crate_id: crate_id, + }, + ) } /// Handles the `PUT /crates/:crate_id/follow` route. @@ -1438,9 +1512,8 @@ fn modify_owners(req: &mut Request, add: bool) -> CargoResult { req.body().read_to_string(&mut body)?; let user = req.user()?; let conn = req.db_conn()?; - let krate = Crate::by_name(&req.params()["crate_id"]).first::( - &*conn, - )?; + let krate = Crate::by_name(&req.params()["crate_id"]) + .first::(&*conn)?; let owners = krate.owners(&conn)?; match rights(req.app(), &owners, user)? { @@ -1460,13 +1533,13 @@ fn modify_owners(req: &mut Request, add: bool) -> CargoResult { owners: Option>, } - let request: Request = json::decode(&body).map_err( - |_| human("invalid json request"), - )?; + let request: Request = json::decode(&body) + .map_err(|_| human("invalid json request"))?; - let logins = request.owners.or(request.users).ok_or_else(|| { - human("invalid json request") - })?; + let logins = request + .owners + .or(request.users) + .ok_or_else(|| human("invalid json request"))?; for login in &logins { if add { @@ -1512,10 +1585,14 @@ pub fn reverse_dependencies(req: &mut Request) -> CargoResult { struct Meta { total: i64, } - Ok(req.json(&R { - dependencies: rev_deps, - meta: Meta { total: total }, - })) + Ok( + req.json( + &R { + dependencies: rev_deps, + meta: Meta { total: total }, + }, + ), + ) } use diesel::types::{Text, Date}; diff --git a/src/lib.rs b/src/lib.rs index db1d485e6c7..013592c0c02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -183,10 +183,7 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { m.around(util::Head::default()); m.add(conduit_conditional_get::ConditionalGet); m.add(conduit_cookie::Middleware::new(app.session_key.as_bytes())); - m.add(conduit_cookie::SessionMiddleware::new( - "cargo_session", - env == Env::Production, - )); + m.add(conduit_cookie::SessionMiddleware::new("cargo_session", env == Env::Production),); m.add(app::AppMiddleware::new(app)); if env != Env::Test { m.add(db::TransactionMiddleware); @@ -219,13 +216,15 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { _req: &mut conduit::Request, res: Result>, ) -> Result> { - res.map(|res| { - println!(" <- {:?}", res.status); - for (k, v) in &res.headers { - println!(" <- {} {:?}", k, v); - } - res - }) + res.map( + |res| { + println!(" <- {:?}", res.status); + for (k, v) in &res.headers { + println!(" <- {} {:?}", k, v); + } + res + }, + ) } } } diff --git a/src/owner.rs b/src/owner.rs index 407527055c2..8602e374211 100644 --- a/src/owner.rs +++ b/src/owner.rs @@ -87,19 +87,25 @@ impl Team { "github" => { // Ok to unwrap since we know one ":" is contained let org = chunks.next().unwrap(); - let team = chunks.next().ok_or_else(|| { - human( - "missing github team argument; \ + let team = chunks + .next() + .ok_or_else( + || { + human( + "missing github team argument; \ format is github:org:team", - ) - })?; + ) + }, + )?; Team::create_github_team(app, conn, login, org, team, req_user) } _ => { - Err(human( - "unknown organization handler, \ + Err( + human( + "unknown organization handler, \ only 'github:org:team' is supported", - )) + ), + ) } } } @@ -127,11 +133,15 @@ impl Team { } if let Some(c) = org_name.chars().find(whitelist) { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "organization cannot contain special \ characters like {}", c - ))); + ), + ), + ); } #[derive(RustcDecodable)] @@ -151,13 +161,17 @@ impl Team { let team = teams .into_iter() .find(|team| team.slug == team_name) - .ok_or_else(|| { - human(&format_args!( + .ok_or_else( + || { + human( + &format_args!( "could not find the github team {}/{}", org_name, team_name - )) - })?; + ), + ) + }, + )?; if !team_with_gh_id_contains_user(app, team.id, req_user)? { return Err(human("only members of a team can add it as an owner")); @@ -199,10 +213,8 @@ impl Team { avatar: avatar, }; - diesel::insert(&new_team.on_conflict( - teams::github_id, - do_update().set(&new_team), - )).into(teams::table) + diesel::insert(&new_team.on_conflict(teams::github_id, do_update().set(&new_team)),) + .into(teams::table) .get_result(conn) .map_err(Into::into) } @@ -267,17 +279,13 @@ impl Owner { .filter(teams::login.eq(name)) .first(conn) .map(Owner::Team) - .map_err(|_| { - human(&format_args!("could not find team with name {}", name)) - }) + .map_err(|_| human(&format_args!("could not find team with name {}", name)),) } else { users::table .filter(users::gh_login.eq(name)) .first(conn) .map(Owner::User) - .map_err(|_| { - human(&format_args!("could not find user with login `{}`", name)) - }) + .map_err(|_| human(&format_args!("could not find user with login `{}`", name)),) } } diff --git a/src/tests/all.rs b/src/tests/all.rs index 0256ee0733e..66906045bd0 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -162,9 +162,9 @@ fn json(r: &mut conduit::Response) -> T { let j = fixup(j); let s = j.to_string(); return match json::decode(&s) { - Ok(t) => t, - Err(e) => panic!("failed to decode: {:?}\n{}", e, s), - }; + Ok(t) => t, + Err(e) => panic!("failed to decode: {:?}\n{}", e, s), + }; fn fixup(json: Json) -> Json { @@ -173,10 +173,12 @@ fn json(r: &mut conduit::Response) -> T { Json::Object( object .into_iter() - .map(|(k, v)| { - let k = if k == "crate" { "krate".to_string() } else { k }; - (k, fixup(v)) - }) + .map( + |(k, v)| { + let k = if k == "crate" { "krate".to_string() } else { k }; + (k, fixup(v)) + }, + ) .collect(), ) } @@ -254,7 +256,8 @@ impl<'a> VersionBuilder<'a> { &self.features, license, self.license_file, - )?.save(connection, &[]) + )? + .save(connection, &[]) } } @@ -323,11 +326,8 @@ impl<'a> CrateBuilder<'a> { fn build(mut self, connection: &PgConnection) -> CargoResult { use diesel::update; - let mut krate = self.krate.create_or_update( - connection, - None, - self.owner_id, - )?; + let mut krate = self.krate + .create_or_update(connection, None, self.owner_id)?; // Since we are using `NewCrate`, we can't set all the // crate properties in a single DB call. @@ -353,9 +353,12 @@ impl<'a> CrateBuilder<'a> { fn expect_build(self, connection: &PgConnection) -> Crate { let name = self.krate.name; - self.build(connection).unwrap_or_else(|e| { - panic!("Unable to create crate {}: {:?}", name, e); - }) + self.build(connection) + .unwrap_or_else( + |e| { + panic!("Unable to create crate {}: {:?}", name, e); + }, + ) } } @@ -390,7 +393,8 @@ fn mock_user(req: &mut Request, u: User) -> User { u.name.as_ref().map(|s| &s[..]), u.gh_avatar.as_ref().map(|s| &s[..]), &u.gh_access_token, - ).unwrap(); + ) + .unwrap(); sign_in_as(req, &u); return u; } @@ -423,7 +427,8 @@ fn mock_crate_vers(req: &mut Request, krate: Crate, v: &semver::Version) -> (Cra &krate.license, &None, krate.max_upload_size, - ).unwrap(); + ) + .unwrap(); let v = krate.add_version(req.tx().unwrap(), v, &HashMap::new(), &[]); (krate, v.unwrap()) } @@ -461,7 +466,8 @@ fn mock_dep( true, &[], &target.map(|s| s.to_string()), - ).unwrap() + ) + .unwrap() } fn new_category<'a>(category: &'a str, slug: &'a str) -> NewCategory<'a> { @@ -475,11 +481,12 @@ fn new_category<'a>(category: &'a str, slug: &'a str) -> NewCategory<'a> { fn mock_category(req: &mut Request, name: &str, slug: &str) -> Category { let conn = req.tx().unwrap(); let stmt = conn.prepare( - " \ + " \ INSERT INTO categories (category, slug) \ VALUES ($1, $2) \ RETURNING *", - ).unwrap(); + ) + .unwrap(); let rows = stmt.query(&[&name, &slug]).unwrap(); Model::from_row(&rows.iter().next().unwrap()) } @@ -510,14 +517,7 @@ fn new_req_full( deps: Vec, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body( - krate, - version, - deps, - Vec::new(), - Vec::new(), - HashMap::new(), - )); + req.with_body(&new_req_body(krate, version, deps, Vec::new(), Vec::new(), HashMap::new()),); return req; } @@ -528,14 +528,7 @@ fn new_req_with_keywords( kws: Vec, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body( - krate, - version, - Vec::new(), - kws, - Vec::new(), - HashMap::new(), - )); + req.with_body(&new_req_body(krate, version, Vec::new(), kws, Vec::new(), HashMap::new()),); return req; } @@ -546,14 +539,7 @@ fn new_req_with_categories( cats: Vec, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body( - krate, - version, - Vec::new(), - Vec::new(), - cats, - HashMap::new(), - )); + req.with_body(&new_req_body(krate, version, Vec::new(), Vec::new(), cats, HashMap::new()),); return req; } @@ -564,14 +550,7 @@ fn new_req_with_badges( badges: HashMap>, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body( - krate, - version, - Vec::new(), - Vec::new(), - Vec::new(), - badges, - )); + req.with_body(&new_req_body(krate, version, Vec::new(), Vec::new(), Vec::new(), badges),); return req; } @@ -598,22 +577,22 @@ fn new_req_body( let cats = cats.into_iter().map(u::Category).collect(); new_crate_to_body( &u::NewCrate { - name: u::CrateName(krate.name), - vers: u::CrateVersion(semver::Version::parse(version).unwrap()), - features: HashMap::new(), - deps: deps, - authors: vec!["foo".to_string()], - description: Some("description".to_string()), - homepage: krate.homepage, - documentation: krate.documentation, - readme: krate.readme, - keywords: Some(u::KeywordList(kws)), - categories: Some(u::CategoryList(cats)), - license: Some("MIT".to_string()), - license_file: None, - repository: krate.repository, - badges: Some(badges), - }, + name: u::CrateName(krate.name), + vers: u::CrateVersion(semver::Version::parse(version).unwrap()), + features: HashMap::new(), + deps: deps, + authors: vec!["foo".to_string()], + description: Some("description".to_string()), + homepage: krate.homepage, + documentation: krate.documentation, + readme: krate.readme, + keywords: Some(u::KeywordList(kws)), + categories: Some(u::CategoryList(cats)), + license: Some("MIT".to_string()), + license_file: None, + repository: krate.repository, + badges: Some(badges), + }, &[], ) } @@ -627,8 +606,9 @@ fn new_crate_to_body(new_crate: &u::NewCrate, krate: &[u8]) -> Vec { (json.len() >> 8) as u8, (json.len() >> 16) as u8, (json.len() >> 24) as u8, - ].iter() - .cloned(), + ] + .iter() + .cloned(), ); body.extend(json.as_bytes().iter().cloned()); body.extend( diff --git a/src/tests/badge.rs b/src/tests/badge.rs index aa1b6f66089..6adc341c1f2 100644 --- a/src/tests/badge.rs +++ b/src/tests/badge.rs @@ -68,12 +68,8 @@ fn set_up() -> (Arc, Crate, BadgeRef) { Badge::IsItMaintainedOpenIssues { repository: String::from("rust-lang/rust") }; let mut badge_attributes_isitmaintained_open_issues = HashMap::new(); badge_attributes_isitmaintained_open_issues.insert( - String::from( - "repository", - ), - String::from( - "rust-lang/rust", - ), + String::from("repository"), + String::from("rust-lang/rust"), ); let codecov = Badge::Codecov { @@ -388,9 +384,9 @@ fn isitmaintained_open_issues_required_keys() { let mut badges = HashMap::new(); // Repository is a required key - test_badges.isitmaintained_open_issues_attributes.remove( - "repository", - ); + test_badges + .isitmaintained_open_issues_attributes + .remove("repository"); badges.insert( String::from("isitmaintained_open_issues"), test_badges.isitmaintained_open_issues_attributes, diff --git a/src/tests/category.rs b/src/tests/category.rs index 511b0b2c131..b251448a3eb 100644 --- a/src/tests/category.rs +++ b/src/tests/category.rs @@ -107,7 +107,8 @@ fn update_crate() { req.tx().unwrap(), &krate, &["cat1".to_string(), "category-2".to_string()], - ).unwrap(); + ) + .unwrap(); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "category-2"), 1); @@ -121,7 +122,8 @@ fn update_crate() { req.tx().unwrap(), &krate, &["cat1".to_string(), "catnope".to_string()], - ).unwrap(); + ) + .unwrap(); assert_eq!(invalid_categories, vec!["catnope".to_string()]); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "category-2"), 0); @@ -145,7 +147,8 @@ fn update_crate() { req.tx().unwrap(), &krate, &["cat1".to_string(), "cat1::bar".to_string()], - ).unwrap(); + ) + .unwrap(); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "cat1::bar"), 1); assert_eq!(cnt(&mut req, "category-2"), 0); diff --git a/src/tests/git.rs b/src/tests/git.rs index 3b26cd18c2e..36c893cf968 100644 --- a/src/tests/git.rs +++ b/src/tests/git.rs @@ -8,11 +8,10 @@ use git2; use url::Url; fn root() -> PathBuf { - env::current_dir().unwrap().join("tmp").join( - thread::current() - .name() - .unwrap(), - ) + env::current_dir() + .unwrap() + .join("tmp") + .join(thread::current().name().unwrap()) } pub fn checkout() -> PathBuf { @@ -27,9 +26,7 @@ pub fn init() { let _ = fs::remove_dir_all(&checkout()); let _ = fs::remove_dir_all(&bare()); - INIT.call_once(|| { - fs::create_dir_all(root().parent().unwrap()).unwrap(); - }); + INIT.call_once(|| { fs::create_dir_all(root().parent().unwrap()).unwrap(); },); // Prepare a bare remote repo { @@ -45,7 +42,9 @@ pub fn init() { // Setup the `origin` remote checkout.remote_set_url("origin", &url).unwrap(); - checkout.remote_set_pushurl("origin", Some(&url)).unwrap(); + checkout + .remote_set_pushurl("origin", Some(&url)) + .unwrap(); checkout .remote_add_push("origin", "refs/heads/master") .unwrap(); diff --git a/src/tests/krate.rs b/src/tests/krate.rs index 612d87e7be5..7997234f34d 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -248,9 +248,7 @@ fn exact_match_first_on_queries() { .expect_build(&conn); ::CrateBuilder::new("baz_exact", user.id) - .description( - "foo_exact bar_exact foo_exact bar_exact foo_exact bar_exact", - ) + .description("foo_exact bar_exact foo_exact bar_exact foo_exact bar_exact",) .expect_build(&conn); ::CrateBuilder::new("other_exact", user.id) @@ -301,9 +299,7 @@ fn exact_match_on_queries_with_sort() { .expect_build(&conn); ::CrateBuilder::new("baz_sort", user.id) - .description( - "foo_sort bar_sort foo_sort bar_sort foo_sort bar_sort const", - ) + .description("foo_sort bar_sort foo_sort bar_sort foo_sort bar_sort const",) .downloads(100000) .expect_build(&conn); @@ -473,9 +469,11 @@ fn new_krate_with_reserved_name() { let mut req = ::new_req(app, name, "1.0.0"); ::mock_user(&mut req, ::user("foo")); let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains( - "cannot upload a crate with a reserved name", - )); + assert!( + json.errors[0] + .detail + .contains("cannot upload a crate with a reserved name") + ); } test_bad_name("std"); @@ -924,9 +922,11 @@ fn new_krate_dependency_missing() { ::sign_in(&mut req, &app); let mut response = ok_resp!(middle.call(&mut req)); let json = ::json::<::Bad>(&mut response); - assert!(json.errors[0].detail.contains( - "no known crate named `bar_missing`", - )); + assert!( + json.errors[0] + .detail + .contains("no known crate named `bar_missing`") + ); } #[test] @@ -979,16 +979,12 @@ fn download() { let yesterday = now_utc() + Duration::days(-1); req.with_path("/api/v1/crates/FOO_DOWNLOAD/1.0.0/downloads"); - req.with_query( - &("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()), - ); + req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()),); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); assert_eq!(downloads.version_downloads.len(), 0); req.with_path("/api/v1/crates/FOO_DOWNLOAD/downloads"); - req.with_query( - &("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()), - ); + req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()),); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); // crate/downloads always returns the last 90 days and ignores date params @@ -996,16 +992,12 @@ fn download() { let tomorrow = now_utc() + Duration::days(1); req.with_path("/api/v1/crates/FOO_DOWNLOAD/1.0.0/downloads"); - req.with_query( - &("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()), - ); + req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()),); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); assert_eq!(downloads.version_downloads.len(), 1); req.with_path("/api/v1/crates/FOO_DOWNLOAD/downloads"); - req.with_query( - &("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()), - ); + req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()),); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); assert_eq!(downloads.version_downloads.len(), 1); @@ -1171,9 +1163,7 @@ fn owners() { assert_eq!(r.users.len(), 1); let body = r#"{"users":["foobar"]}"#; - let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body( - body.as_bytes(), - ))); + let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(req.with_method(Method::Get))); @@ -1181,9 +1171,12 @@ fn owners() { assert_eq!(r.users.len(), 2); let body = r#"{"users":["foobar"]}"#; - let mut response = ok_resp!(middle.call(req.with_method(Method::Delete).with_body( - body.as_bytes(), - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_body(body.as_bytes()), + ) + ); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(req.with_method(Method::Get))); @@ -1191,15 +1184,16 @@ fn owners() { assert_eq!(r.users.len(), 1); let body = r#"{"users":["foo"]}"#; - let mut response = ok_resp!(middle.call(req.with_method(Method::Delete).with_body( - body.as_bytes(), - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_body(body.as_bytes()), + ) + ); ::json::<::Bad>(&mut response); let body = r#"{"users":["foobar"]}"#; - let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body( - body.as_bytes(), - ))); + let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); assert!(::json::(&mut response).ok); } @@ -1229,15 +1223,21 @@ fn yank() { assert!(contents.contains("\"yanked\":false")); // make sure it's not yanked - let mut r = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk/1.0.0", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk/1.0.0"), + ) + ); assert!(!::json::(&mut r).version.yanked); // yank it - let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( - "/api/v1/crates/fyk/1.0.0/yank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_path("/api/v1/crates/fyk/1.0.0/yank"), + ) + ); assert!(::json::(&mut r).ok); let mut contents = String::new(); File::open(&path) @@ -1245,15 +1245,21 @@ fn yank() { .read_to_string(&mut contents) .unwrap(); assert!(contents.contains("\"yanked\":true")); - let mut r = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk/1.0.0", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk/1.0.0"), + ) + ); assert!(::json::(&mut r).version.yanked); // un-yank it - let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( - "/api/v1/crates/fyk/1.0.0/unyank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Put) + .with_path("/api/v1/crates/fyk/1.0.0/unyank"), + ) + ); assert!(::json::(&mut r).ok); let mut contents = String::new(); File::open(&path) @@ -1261,9 +1267,12 @@ fn yank() { .read_to_string(&mut contents) .unwrap(); assert!(contents.contains("\"yanked\":false")); - let mut r = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk/1.0.0", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk/1.0.0"), + ) + ); assert!(!::json::(&mut r).version.yanked); } @@ -1272,9 +1281,8 @@ fn yank_not_owner() { let (_b, app, middle) = ::app(); let mut req = ::request_with_user_and_mock_crate(&app, ::new_user("bar"), "foo_not"); ::sign_in(&mut req, &app); - req.with_method(Method::Delete).with_path( - "/api/v1/crates/foo_not/1.0.0/yank", - ); + req.with_method(Method::Delete) + .with_path("/api/v1/crates/foo_not/1.0.0/yank"); let mut response = ok_resp!(middle.call(&mut req)); ::json::<::Bad>(&mut response); } @@ -1309,68 +1317,104 @@ fn yank_max_version() { assert_eq!(json.krate.max_version, "2.0.0"); // yank version 1.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( - "/api/v1/crates/fyk_max/1.0.0/yank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_path("/api/v1/crates/fyk_max/1.0.0/yank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); // unyank version 1.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( - "/api/v1/crates/fyk_max/1.0.0/unyank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Put) + .with_path("/api/v1/crates/fyk_max/1.0.0/unyank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); // yank version 2.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( - "/api/v1/crates/fyk_max/2.0.0/yank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_path("/api/v1/crates/fyk_max/2.0.0/yank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "1.0.0"); // yank version 1.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( - "/api/v1/crates/fyk_max/1.0.0/yank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_path("/api/v1/crates/fyk_max/1.0.0/yank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "0.0.0"); // unyank version 2.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( - "/api/v1/crates/fyk_max/2.0.0/unyank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Put) + .with_path("/api/v1/crates/fyk_max/2.0.0/unyank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); // unyank version 1.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( - "/api/v1/crates/fyk_max/1.0.0/unyank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Put) + .with_path("/api/v1/crates/fyk_max/1.0.0/unyank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); } @@ -1393,13 +1437,19 @@ fn publish_after_yank_max_version() { assert_eq!(json.krate.max_version, "1.0.0"); // yank version 1.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( - "/api/v1/crates/fyk_max/1.0.0/yank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Delete) + .with_path("/api/v1/crates/fyk_max/1.0.0/yank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "0.0.0"); @@ -1416,13 +1466,19 @@ fn publish_after_yank_max_version() { assert_eq!(json.krate.max_version, "2.0.0"); // unyank version 1.0.0 - let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( - "/api/v1/crates/fyk_max/1.0.0/unyank", - ))); + let mut r = ok_resp!( + middle.call( + req.with_method(Method::Put) + .with_path("/api/v1/crates/fyk_max/1.0.0/unyank"), + ) + ); assert!(::json::(&mut r).ok); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/fyk_max", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/fyk_max"), + ) + ); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); } @@ -1518,9 +1574,12 @@ fn good_badges() { assert_eq!(json.krate.name, "foobadger"); assert_eq!(json.krate.max_version, "1.0.0"); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/foobadger", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/foobadger"), + ) + ); let json: CrateResponse = ::json(&mut response); @@ -1558,16 +1617,23 @@ fn ignored_badges() { assert_eq!(json.krate.name, "foo_ignored_badge"); assert_eq!(json.krate.max_version, "1.0.0"); assert_eq!(json.warnings.invalid_badges.len(), 2); - assert!(json.warnings.invalid_badges.contains( - &"travis-ci".to_string(), - )); - assert!(json.warnings.invalid_badges.contains( - &"not-a-badge".to_string(), - )); + assert!( + json.warnings + .invalid_badges + .contains(&"travis-ci".to_string()) + ); + assert!( + json.warnings + .invalid_badges + .contains(&"not-a-badge".to_string()) + ); - let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( - "/api/v1/crates/foo_ignored_badge", - ))); + let mut response = ok_resp!( + middle.call( + req.with_method(Method::Get) + .with_path("/api/v1/crates/foo_ignored_badge"), + ) + ); let json: CrateResponse = ::json(&mut response); @@ -1711,7 +1777,7 @@ fn author_license_and_description_required() { let json = bad_resp!(middle.call(&mut req)); assert!( json.errors[0].detail.contains("author") && json.errors[0].detail.contains("description") && - json.errors[0].detail.contains("license"), + json.errors[0].detail.contains("license"), "{:?}", json.errors ); @@ -1722,7 +1788,7 @@ fn author_license_and_description_required() { let json = bad_resp!(middle.call(&mut req)); assert!( json.errors[0].detail.contains("author") && json.errors[0].detail.contains("description") && - !json.errors[0].detail.contains("license"), + !json.errors[0].detail.contains("license"), "{:?}", json.errors ); @@ -1734,8 +1800,8 @@ fn author_license_and_description_required() { let json = bad_resp!(middle.call(&mut req)); assert!( !json.errors[0].detail.contains("author") && - json.errors[0].detail.contains("description") && - !json.errors[0].detail.contains("license"), + json.errors[0].detail.contains("description") && + !json.errors[0].detail.contains("license"), "{:?}", json.errors ); diff --git a/src/tests/record.rs b/src/tests/record.rs index de0d26a869f..b26008f235c 100644 --- a/src/tests/record.rs +++ b/src/tests/record.rs @@ -86,48 +86,50 @@ pub fn proxy() -> (String, Bomb) { let (quittx, quitrx) = channel(); - thread::spawn(move || { - let mut file = None; - for socket in a.incoming() { - if quitrx.try_recv().is_ok() { - break; - } - let socket = t!(socket); + thread::spawn( + move || { + let mut file = None; + for socket in a.incoming() { + if quitrx.try_recv().is_ok() { + break; + } + let socket = t!(socket); + + if file.is_none() { + let io = t!( + if record { + File::create(&data) + } else { + File::open(&data) + } + ); + file = Some(BufStream::new(io)); + } - if file.is_none() { - let io = t!(if record { - File::create(&data) + if record { + record_http(socket, file.as_mut().unwrap()); } else { - File::open(&data) - }); - file = Some(BufStream::new(io)); - } - - if record { - record_http(socket, file.as_mut().unwrap()); - } else { - replay_http(socket, file.as_mut().unwrap(), &mut sink2); + replay_http(socket, file.as_mut().unwrap(), &mut sink2); + } } - } - if !record { - if let Some(mut f) = file { - let mut s = String::new(); - t!(f.read_line(&mut s)); - assert_eq!(s, ""); + if !record { + if let Some(mut f) = file { + let mut s = String::new(); + t!(f.read_line(&mut s)); + assert_eq!(s, ""); + } } - } - tx.send(()).unwrap(); - }); - - ( - ret, - Bomb { - accept: a2, - rx: rx, - iorx: Sink(sink), - quit: quittx, + tx.send(()).unwrap(); }, - ) + ); + + (ret, + Bomb { + accept: a2, + rx: rx, + iorx: Sink(sink), + quit: quittx, + }) } fn record_http(mut socket: TcpStream, data: &mut BufStream) { @@ -139,14 +141,16 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { respond(handle, headers, body, &mut response); t!(socket.write_all(&response)); - t!(write!( - data, - "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n", - request.len(), - str::from_utf8(&request).unwrap(), - response.len(), - str::from_utf8(&response).unwrap() - )); + t!( + write!( + data, + "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n", + request.len(), + str::from_utf8(&request).unwrap(), + response.len(), + str::from_utf8(&response).unwrap() + ) + ); fn send(rdr: R) -> (Easy, Vec>, Vec) { let mut socket = BufReader::new(rdr); @@ -183,17 +187,23 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { let mut response = Vec::new(); { let mut transfer = handle.transfer(); - t!(transfer.header_function(|header| { - headers.push(header.to_owned()); - true - })); - t!(transfer.write_function(|data| { - response.extend(data); - Ok(data.len()) - })); - t!(transfer.read_function( - |buf| socket.read(buf).map_err(|_| ReadError::Abort), - )); + t!( + transfer.header_function( + |header| { + headers.push(header.to_owned()); + true + }, + ) + ); + t!( + transfer.write_function( + |data| { + response.extend(data); + Ok(data.len()) + }, + ) + ); + t!(transfer.read_function(|buf| socket.read(buf).map_err(|_| ReadError::Abort))); t!(transfer.perform()); } @@ -202,9 +212,7 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { } fn respond(mut handle: Easy, headers: Vec>, body: Vec, mut socket: W) { - t!(socket.write_all( - format!("HTTP/1.1 {}\r\n", t!(handle.response_code())).as_bytes(), - )); + t!(socket.write_all(format!("HTTP/1.1 {}\r\n", t!(handle.response_code())).as_bytes(),)); for header in headers { if header.starts_with(b"Transfer-Encoding: ") { continue; @@ -274,7 +282,9 @@ fn replay_http(socket: TcpStream, data: &mut BufStream, stdout: &mut Write assert_eq!(response.next().unwrap(), "===RESPONSE"); let response_size = response.next().unwrap().trim().parse().unwrap(); let mut response = Vec::new(); - data.take(response_size).read_to_end(&mut response).unwrap(); + data.take(response_size) + .read_to_end(&mut response) + .unwrap(); let lines = <[_]>::split(&response[..], |b| *b == b'\n').map(|s| str::from_utf8(s).unwrap()); for line in lines { if line.starts_with("Date:") { @@ -326,12 +336,15 @@ impl GhUser { self.login, password ); - let body = json::encode(&Authorization { - scopes: vec!["read:org".to_string()], - note: "crates.io test".to_string(), - client_id: ::env("GH_CLIENT_ID"), - client_secret: ::env("GH_CLIENT_SECRET"), - }).unwrap(); + let body = json::encode( + &Authorization { + scopes: vec!["read:org".to_string()], + note: "crates.io test".to_string(), + client_id: ::env("GH_CLIENT_ID"), + client_secret: ::env("GH_CLIENT_SECRET"), + }, + ) + .unwrap(); t!(handle.url(&url)); t!(handle.post(true)); @@ -344,13 +357,15 @@ impl GhUser { let mut response = Vec::new(); { let mut transfer = handle.transfer(); - t!(transfer.read_function( - |buf| body.read(buf).map_err(|_| ReadError::Abort), - )); - t!(transfer.write_function(|data| { - response.extend(data); - Ok(data.len()) - })); + t!(transfer.read_function(|buf| body.read(buf).map_err(|_| ReadError::Abort))); + t!( + transfer.write_function( + |data| { + response.extend(data); + Ok(data.len()) + }, + ) + ); t!(transfer.perform()) } diff --git a/src/tests/team.rs b/src/tests/team.rs index 9df3ac6f073..efa3d7946e9 100644 --- a/src/tests/team.rs +++ b/src/tests/team.rs @@ -70,9 +70,9 @@ fn weird_name() { ) ); assert!( - json.errors[0].detail.contains( - "organization cannot contain", - ), + json.errors[0] + .detail + .contains("organization cannot contain"), "{:?}", json.errors ); @@ -114,9 +114,9 @@ fn nonexistent_team() { ) ); assert!( - json.errors[0].detail.contains( - "could not find the github team", - ), + json.errors[0] + .detail + .contains("could not find the github team"), "{:?}", json.errors ); diff --git a/src/tests/user.rs b/src/tests/user.rs index c2f78b473ce..e513c3469ba 100644 --- a/src/tests/user.rs +++ b/src/tests/user.rs @@ -163,9 +163,7 @@ fn following() { .expect_build(&conn); } - let mut response = ok_resp!(middle.call( - req.with_path("/me/updates").with_method(Method::Get), - )); + let mut response = ok_resp!(middle.call(req.with_path("/me/updates").with_method(Method::Get))); let r = ::json::(&mut response); assert_eq!(r.versions.len(), 0); assert_eq!(r.meta.more, false); @@ -183,9 +181,7 @@ fn following() { ) ); - let mut response = ok_resp!(middle.call( - req.with_path("/me/updates").with_method(Method::Get), - )); + let mut response = ok_resp!(middle.call(req.with_path("/me/updates").with_method(Method::Get))); let r = ::json::(&mut response); assert_eq!(r.versions.len(), 2); assert_eq!(r.meta.more, false); diff --git a/src/tests/version.rs b/src/tests/version.rs index f259c33dae5..455bc0e786d 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -29,10 +29,8 @@ fn index() { let conn = app.diesel_database.get().unwrap(); let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) - .version(::VersionBuilder::new("2.0.0") - .license(Some("MIT"))) - .version(::VersionBuilder::new("2.0.1") - .license(Some("MIT/Apache-2.0"))) + .version(::VersionBuilder::new("2.0.0").license(Some("MIT"))) + .version(::VersionBuilder::new("2.0.1").license(Some("MIT/Apache-2.0")),) .expect_build(&conn); let ids = versions::table .select(versions::id) @@ -49,7 +47,7 @@ fn index() { match v.num.as_ref() { "2.0.0" => assert_eq!(v.license, Some(String::from("MIT"))), "2.0.1" => assert_eq!(v.license, Some(String::from("MIT/Apache-2.0"))), - _ => panic!("unexpected version") + _ => panic!("unexpected version"), } } } @@ -62,7 +60,9 @@ fn show() { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); let krate = ::CrateBuilder::new("foo_vers_show", user.id).expect_build(&conn); - ::new_version(krate.id, "2.0.0").save(&conn, &[]).unwrap() + ::new_version(krate.id, "2.0.0") + .save(&conn, &[]) + .unwrap() }; req.with_path(&format!("/api/v1/versions/{}", v.id)); let mut response = ok_resp!(middle.call(&mut req)); diff --git a/src/upload.rs b/src/upload.rs index b450b1d600c..59adef1ca53 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -52,14 +52,18 @@ impl Decodable for CrateName { fn decode(d: &mut D) -> Result { let s = d.read_str()?; if !Crate::valid_name(&s) { - return Err(d.error(&format!( + return Err( + d.error( + &format!( "invalid crate name specified: {}. \ Valid crate names must start with a letter; contain only \ letters, numbers, hyphens, or underscores; and have {} or \ fewer characters.", s, MAX_NAME_LENGTH - ))); + ), + ), + ); } Ok(CrateName(s)) } @@ -137,10 +141,12 @@ impl Decodable for KeywordList { } for val in &inner { if val.len() > 20 { - return Err(d.error( - "keywords must contain less than 20 \ + return Err( + d.error( + "keywords must contain less than 20 \ characters", - )); + ), + ); } } Ok(KeywordList(inner)) @@ -165,11 +171,15 @@ impl Decodable for DependencyKind { "build" => Ok(DependencyKind::Build), "normal" => Ok(DependencyKind::Normal), s => { - Err(d.error(&format!( + Err( + d.error( + &format!( "invalid dependency kind `{}`, must be \ one of dev, build, or normal", s - ))) + ), + ), + ) } } } diff --git a/src/uploaders.rs b/src/uploaders.rs index 8ad0beab834..26ee6797aa7 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -38,17 +38,21 @@ impl Uploader { pub fn crate_location(&self, crate_name: &str, version: &str) -> Option { match *self { Uploader::S3 { ref bucket, .. } => { - Some(format!( + Some( + format!( "https://{}/{}", bucket.host(), Uploader::crate_path(crate_name, version) - )) + ), + ) } Uploader::Local => { - Some(format!( + Some( + format!( "/local_uploads/{}", Uploader::crate_path(crate_name, version) - )) + ), + ) } Uploader::NoOp => None, } @@ -84,10 +88,12 @@ impl Uploader { length as u64, ); s3req - .write_function(|data| { - response.extend(data); - Ok(data.len()) - }) + .write_function( + |data| { + response.extend(data); + Ok(data.len()) + }, + ) .unwrap(); s3req.perform().chain_error(|| { internal(&format_args!("failed to upload to S3: `{}`", path)) @@ -97,19 +103,23 @@ impl Uploader { }; if handle.response_code().unwrap() != 200 { let response = String::from_utf8_lossy(&response); - return Err(internal(&format_args!( + return Err( + internal( + &format_args!( "failed to get a 200 response from S3: {}", response - ))); + ), + ), + ); } - Ok(( - cksum, - Bomb { - app: req.app().clone(), - path: Some(path), - }, - )) + Ok( + (cksum, + Bomb { + app: req.app().clone(), + path: Some(path), + }), + ) } Uploader::Local => { let path = Uploader::crate_path(&krate.name, &vers.to_string()); @@ -133,22 +143,22 @@ impl Uploader { body.finalize() }; - Ok(( - cksum, - Bomb { - app: req.app().clone(), - path: crate_filename.to_str().map(String::from), - }, - )) + Ok( + (cksum, + Bomb { + app: req.app().clone(), + path: crate_filename.to_str().map(String::from), + }), + ) } Uploader::NoOp => { - Ok(( - vec![], - Bomb { - app: req.app().clone(), - path: None, - }, - )) + Ok( + (vec![], + Bomb { + app: req.app().clone(), + path: None, + }), + ) } } } diff --git a/src/user/middleware.rs b/src/user/middleware.rs index 5c84c83aaf9..f97ddaffa79 100644 --- a/src/user/middleware.rs +++ b/src/user/middleware.rs @@ -15,7 +15,9 @@ impl conduit_middleware::Middleware for Middleware { fn before(&self, req: &mut Request) -> Result<(), Box> { // Check if the request has a session cookie with a `user_id` property inside let id = { - req.session().get("user_id").and_then(|s| s.parse().ok()) + req.session() + .get("user_id") + .and_then(|s| s.parse().ok()) }; let user = match id { @@ -61,8 +63,8 @@ pub trait RequestUser { impl<'a> RequestUser for Request + 'a { fn user(&self) -> CargoResult<&User> { - self.extensions().find::().chain_error( - || Unauthorized, - ) + self.extensions() + .find::() + .chain_error(|| Unauthorized) } } diff --git a/src/user/mod.rs b/src/user/mod.rs index d587577538f..94fee97b22b 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -94,9 +94,9 @@ impl User { /// Queries the database for a user with a certain `gh_login` value. pub fn find_by_login(conn: &GenericConnection, login: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM users + "SELECT * FROM users WHERE gh_login = $1", - )?; + )?; let rows = stmt.query(&[&login])?; let row = rows.iter().next().chain_error(|| NotFound)?; Ok(Model::from_row(&row)) @@ -105,9 +105,9 @@ impl User { /// Queries the database for a user with a certain `api_token` value. pub fn find_by_api_token(conn: &GenericConnection, token: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM users \ + "SELECT * FROM users \ WHERE api_token = $1 LIMIT 1", - )?; + )?; let rows = stmt.query(&[&token])?; rows.iter() .next() @@ -130,7 +130,7 @@ impl User { // more errors than it needs to. let stmt = conn.prepare( - "UPDATE users + "UPDATE users SET gh_access_token = $1, email = $2, name = $3, @@ -138,26 +138,26 @@ impl User { gh_login = $5 WHERE gh_id = $6 RETURNING *", - )?; - let rows = stmt.query( - &[&access_token, &email, &name, &avatar, &login, &id], - )?; + )?; + let rows = stmt.query(&[&access_token, &email, &name, &avatar, &login, &id])?; if let Some(ref row) = rows.iter().next() { return Ok(Model::from_row(row)); } let stmt = conn.prepare( - "INSERT INTO users + "INSERT INTO users (email, gh_access_token, gh_login, name, gh_avatar, gh_id) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", - )?; - let rows = stmt.query( - &[&email, &access_token, &login, &name, &avatar, &id], - )?; - Ok(Model::from_row(&rows.iter().next().chain_error(|| { - internal("no user with email we just found") - })?)) + )?; + let rows = stmt.query(&[&email, &access_token, &login, &name, &avatar, &id])?; + Ok( + Model::from_row( + &rows.iter() + .next() + .chain_error(|| internal("no user with email we just found"))?, + ), + ) } /// Converts this `User` model into an `EncodableUser` for JSON serialization. @@ -219,10 +219,8 @@ impl Model for User { pub fn github_authorize(req: &mut Request) -> CargoResult { // Generate a random 16 char ASCII string let state: String = thread_rng().gen_ascii_chars().take(16).collect(); - req.session().insert( - "github_oauth_state".to_string(), - state.clone(), - ); + req.session() + .insert("github_oauth_state".to_string(), state.clone()); let url = req.app().github.authorize_url(state.clone()); @@ -231,10 +229,14 @@ pub fn github_authorize(req: &mut Request) -> CargoResult { url: String, state: String, } - Ok(req.json(&R { - url: url.to_string(), - state: state, - })) + Ok( + req.json( + &R { + url: url.to_string(), + state: state, + }, + ), + ) } /// Handles the `GET /authorize` route. @@ -291,9 +293,10 @@ pub fn github_access_token(req: &mut Request) -> CargoResult { } // Fetch the access token from github using the code we just got - let token = req.app().github.exchange(code.clone()).map_err( - |s| human(&s), - )?; + let token = req.app() + .github + .exchange(code.clone()) + .map_err(|s| human(&s))?; let (handle, resp) = http::github(req.app(), "/user", &token)?; let ghuser: GithubUser = http::parse_github_response(handle, &resp)?; @@ -307,10 +310,8 @@ pub fn github_access_token(req: &mut Request) -> CargoResult { ghuser.avatar_url.as_ref().map(|s| &s[..]), &token.access_token, )?; - req.session().insert( - "user_id".to_string(), - user.id.to_string(), - ); + req.session() + .insert("user_id".to_string(), user.id.to_string()); req.mut_extensions().insert(user); me(req) } @@ -327,13 +328,14 @@ pub fn reset_token(req: &mut Request) -> CargoResult { let conn = req.tx()?; let rows = conn.query( - "UPDATE users SET api_token = DEFAULT \ + "UPDATE users SET api_token = DEFAULT \ WHERE id = $1 RETURNING api_token", - &[&user.id], - )?; - let token = rows.iter().next().map(|r| r.get("api_token")).chain_error( - || NotFound, - )?; + &[&user.id], + )?; + let token = rows.iter() + .next() + .map(|r| r.get("api_token")) + .chain_error(|| NotFound)?; #[derive(RustcEncodable)] struct R { @@ -352,10 +354,14 @@ pub fn me(req: &mut Request) -> CargoResult { api_token: String, } let token = user.api_token.clone(); - Ok(req.json(&R { - user: user.clone().encodable(), - api_token: token, - })) + Ok( + req.json( + &R { + user: user.clone().encodable(), + api_token: token, + }, + ), + ) } /// Handles the `GET /users/:user_id` route. @@ -390,11 +396,7 @@ pub fn updates(req: &mut Request) -> CargoResult { .order(versions::created_at.desc()) .limit(limit) .offset(offset) - .select(( - versions::all_columns, - crates::name, - sql::("COUNT(*) OVER ()"), - )) + .select((versions::all_columns, crates::name, sql::("COUNT(*) OVER ()")),) .load::<(Version, String, i64)>(&*conn)?; let more = data.get(0) @@ -414,10 +416,14 @@ pub fn updates(req: &mut Request) -> CargoResult { struct Meta { more: bool, } - Ok(req.json(&R { - versions: versions, - meta: Meta { more: more }, - })) + Ok( + req.json( + &R { + versions: versions, + meta: Meta { more: more }, + }, + ), + ) } #[cfg(test)] diff --git a/src/util/errors.rs b/src/util/errors.rs index a3737e29cf7..afbdfb3c9af 100644 --- a/src/util/errors.rs +++ b/src/util/errors.rs @@ -27,9 +27,7 @@ pub trait CargoError: Send + fmt::Display + 'static { fn response(&self) -> Option { if self.human() { - Some(json_response(&Bad { - errors: vec![StringError { detail: self.description().to_string() }], - })) + Some(json_response(&Bad { errors: vec![StringError { detail: self.description().to_string() }] },),) } else { self.cause().and_then(|cause| cause.response()) } @@ -111,12 +109,16 @@ impl ChainError for Result { E2: CargoError, C: FnOnce() -> E2, { - self.map_err(move |err| { - Box::new(ChainedError { - error: callback(), - cause: Box::new(err), - }) as Box - }) + self.map_err( + move |err| { + Box::new( + ChainedError { + error: callback(), + cause: Box::new(err), + }, + ) as Box + }, + ) } } @@ -231,9 +233,8 @@ impl CargoError for NotFound { } fn response(&self) -> Option { - let mut response = json_response(&Bad { - errors: vec![StringError { detail: "Not Found".to_string() }], - }); + let mut response = + json_response(&Bad { errors: vec![StringError { detail: "Not Found".to_string() }] },); response.status = (404, "Not Found"); Some(response) } @@ -253,13 +254,15 @@ impl CargoError for Unauthorized { } fn response(&self) -> Option { - let mut response = json_response(&Bad { - errors: vec![ + let mut response = json_response( + &Bad { + errors: vec![ StringError { detail: "must be logged in to perform that action".to_string(), }, ], - }); + }, + ); response.status = (403, "Forbidden"); Some(response) } @@ -272,30 +275,36 @@ impl fmt::Display for Unauthorized { } pub fn internal_error(error: &str, detail: &str) -> Box { - Box::new(ConcreteCargoError { - description: error.to_string(), - detail: Some(detail.to_string()), - cause: None, - human: false, - }) + Box::new( + ConcreteCargoError { + description: error.to_string(), + detail: Some(detail.to_string()), + cause: None, + human: false, + }, + ) } pub fn internal(error: &S) -> Box { - Box::new(ConcreteCargoError { - description: error.to_string(), - detail: None, - cause: None, - human: false, - }) + Box::new( + ConcreteCargoError { + description: error.to_string(), + detail: None, + cause: None, + human: false, + }, + ) } pub fn human(error: &S) -> Box { - Box::new(ConcreteCargoError { - description: error.to_string(), - detail: None, - cause: None, - human: true, - }) + Box::new( + ConcreteCargoError { + description: error.to_string(), + detail: None, + cause: None, + human: true, + }, + ) } pub fn std_error(e: Box) -> Box { diff --git a/src/util/head.rs b/src/util/head.rs index 36202d76513..55f677f28ca 100644 --- a/src/util/head.rs +++ b/src/util/head.rs @@ -25,12 +25,18 @@ impl Handler for Head { path: None, method: Some(Method::Get), }; - self.handler.as_ref().unwrap().call(&mut req).map(|r| { - Response { - body: Box::new(io::empty()), - ..r - } - }) + self.handler + .as_ref() + .unwrap() + .call(&mut req) + .map( + |r| { + Response { + body: Box::new(io::empty()), + ..r + } + }, + ) } else { self.handler.as_ref().unwrap().call(req) } diff --git a/src/util/io_util.rs b/src/util/io_util.rs index be25ddd14f0..f5ab1f920ab 100644 --- a/src/util/io_util.rs +++ b/src/util/io_util.rs @@ -15,10 +15,9 @@ impl LimitErrorReader { impl Read for LimitErrorReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self.inner.read(buf) { - Ok(0) if self.inner.limit() == 0 => Err(io::Error::new( - io::ErrorKind::Other, - "maximum limit reached when reading", - )), + Ok(0) if self.inner.limit() == 0 => { + Err(io::Error::new(io::ErrorKind::Other, "maximum limit reached when reading"),) + } e => e, } } @@ -27,9 +26,7 @@ impl Read for LimitErrorReader { pub fn read_le_u32(r: &mut R) -> io::Result { let mut b = [0; 4]; read_fill(r, &mut b)?; - Ok( - (b[0] as u32) | ((b[1] as u32) << 8) | ((b[2] as u32) << 16) | ((b[3] as u32) << 24), - ) + Ok((b[0] as u32) | ((b[1] as u32) << 8) | ((b[2] as u32) << 16) | ((b[3] as u32) << 24),) } pub fn read_fill(r: &mut R, mut slice: &mut [u8]) -> io::Result<()> { diff --git a/src/util/mod.rs b/src/util/mod.rs index 02a8d2e4696..b6b4df4ef1a 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -46,10 +46,10 @@ pub fn json_response(t: &T) -> Response { ); headers.insert("Content-Length".to_string(), vec![json.len().to_string()]); return Response { - status: (200, "OK"), - headers: headers, - body: Box::new(Cursor::new(json.into_bytes())), - }; + status: (200, "OK"), + headers: headers, + body: Box::new(Cursor::new(json.into_bytes())), + }; fn fixup(json: Json) -> Json { match json { @@ -57,10 +57,12 @@ pub fn json_response(t: &T) -> Response { Json::Object( object .into_iter() - .map(|(k, v)| { - let k = if k == "krate" { "crate".to_string() } else { k }; - (k, fixup(v)) - }) + .map( + |(k, v)| { + let k = if k == "krate" { "crate".to_string() } else { k }; + (k, fixup(v)) + }, + ) .collect(), ) } @@ -110,9 +112,7 @@ impl<'a> RequestUtils for Request + 'a { .and_then(|s| s.parse::().ok()) .unwrap_or(default); if limit > max { - return Err(human( - &format_args!("cannot request more than {} items", max), - )); + return Err(human(&format_args!("cannot request more than {} items", max)),); } if page == 0 { return Err(human("page indexing starts from 1, page 0 is invalid")); @@ -147,11 +147,13 @@ impl Handler for R { fn call(&self, req: &mut Request) -> Result> { let path = req.params()["path"].to_string(); let R(ref sub_router) = *self; - sub_router.call(&mut RequestProxy { - other: req, - path: Some(&path), - method: None, - }) + sub_router.call( + &mut RequestProxy { + other: req, + path: Some(&path), + method: None, + }, + ) } } diff --git a/src/util/request_proxy.rs b/src/util/request_proxy.rs index 5409b318b4a..d2bbf596f18 100644 --- a/src/util/request_proxy.rs +++ b/src/util/request_proxy.rs @@ -19,9 +19,9 @@ impl<'a> Request for RequestProxy<'a> { self.other.conduit_version() } fn method(&self) -> conduit::Method { - self.method.clone().unwrap_or_else( - || self.other.method().clone(), - ) + self.method + .clone() + .unwrap_or_else(|| self.other.method().clone()) } fn scheme(&self) -> conduit::Scheme { self.other.scheme() @@ -33,7 +33,9 @@ impl<'a> Request for RequestProxy<'a> { self.other.virtual_root() } fn path(&self) -> &str { - self.path.map(|s| &*s).unwrap_or_else(|| self.other.path()) + self.path + .map(|s| &*s) + .unwrap_or_else(|| self.other.path()) } fn query_string(&self) -> Option<&str> { self.other.query_string() diff --git a/src/version.rs b/src/version.rs index e566a59bbb6..18693272020 100644 --- a/src/version.rs +++ b/src/version.rs @@ -82,9 +82,9 @@ impl Version { ) -> CargoResult> { let num = num.to_string(); let stmt = conn.prepare( - "SELECT * FROM versions \ + "SELECT * FROM versions \ WHERE crate_id = $1 AND num = $2", - )?; + )?; let rows = stmt.query(&[&crate_id, &num])?; Ok(rows.iter().next().map(|r| Model::from_row(&r))) } @@ -99,15 +99,17 @@ impl Version { let num = num.to_string(); let features = json::encode(features).unwrap(); let stmt = conn.prepare( - "INSERT INTO versions \ + "INSERT INTO versions \ (crate_id, num, features) \ VALUES ($1, $2, $3) \ RETURNING *", - )?; + )?; let rows = stmt.query(&[&crate_id, &num, &features])?; - let ret: Version = Model::from_row(&rows.iter().next().chain_error( - || internal("no version returned"), - )?); + let ret: Version = Model::from_row( + &rows.iter() + .next() + .chain_error(|| internal("no version returned"))?, + ); for author in authors { ret.add_author(conn, author)?; } @@ -161,10 +163,10 @@ impl Version { pub fn authors(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT * FROM version_authors + "SELECT * FROM version_authors WHERE version_id = $1 ORDER BY name ASC", - )?; + )?; let rows = stmt.query(&[&self.id])?; Ok( rows.into_iter() @@ -175,18 +177,18 @@ impl Version { pub fn add_author(&self, conn: &GenericConnection, name: &str) -> CargoResult<()> { conn.execute( - "INSERT INTO version_authors (version_id, name) + "INSERT INTO version_authors (version_id, name) VALUES ($1, $2)", - &[&self.id, &name], - )?; + &[&self.id, &name], + )?; Ok(()) } pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> { conn.execute( - "UPDATE versions SET yanked = $1 WHERE id = $2", - &[&yanked, &self.id], - )?; + "UPDATE versions SET yanked = $1 WHERE id = $2", + &[&yanked, &self.id], + )?; Ok(()) } @@ -194,15 +196,20 @@ impl Version { where T: IntoIterator, { - versions.into_iter().max().unwrap_or_else(|| { - semver::Version { - major: 0, - minor: 0, - patch: 0, - pre: vec![], - build: vec![], - } - }) + versions + .into_iter() + .max() + .unwrap_or_else( + || { + semver::Version { + major: 0, + minor: 0, + patch: 0, + pre: vec![], + build: vec![], + } + }, + ) } } @@ -233,44 +240,58 @@ impl NewVersion { use diesel::expression::dsl::exists; use schema::versions::dsl::*; - let already_uploaded = versions.filter(crate_id.eq(self.crate_id)).filter( - num.eq(&self.num), - ); + let already_uploaded = versions + .filter(crate_id.eq(self.crate_id)) + .filter(num.eq(&self.num)); if select(exists(already_uploaded)).get_result(conn)? { - return Err(human(&format_args!( + return Err( + human( + &format_args!( "crate version `{}` is already \ uploaded", self.num - ))); + ), + ), + ); } - conn.transaction(|| { - let version = insert(self).into(versions).get_result::(conn)?; - - let new_authors = authors - .iter() - .map(|s| { - NewAuthor { - version_id: version.id, - name: &*s, - } - }) - .collect::>(); - - insert(&new_authors).into(version_authors::table).execute( - conn, - )?; - Ok(version) - }) + conn.transaction( + || { + let version = insert(self).into(versions).get_result::(conn)?; + + let new_authors = authors + .iter() + .map( + |s| { + NewAuthor { + version_id: version.id, + name: &*s, + } + }, + ) + .collect::>(); + + insert(&new_authors) + .into(version_authors::table) + .execute(conn)?; + Ok(version) + }, + ) } fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { if let Some(ref license) = self.license { for part in license.split('/') { - license_exprs::validate_license_expr(part) - .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + license_exprs::validate_license_expr(part) + .map_err( + |e| { + human( + &format_args!("{}; see http://opensource.org/licenses \ for options, and http://spdx.org/licenses/ \ - for their identifiers", e)))?; + for their identifiers", e), + ) + }, + )?; } } else if license_file.is_some() { // If no license is given, but a license file is given, flag this @@ -293,9 +314,9 @@ impl Queryable for Version { type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool, Option); fn build(row: Self::Row) -> Self { - let features = row.6.map(|s| json::decode(&s).unwrap()).unwrap_or_else( - HashMap::new, - ); + let features = row.6 + .map(|s| json::decode(&s).unwrap()) + .unwrap_or_else(HashMap::new); Version { id: row.0, crate_id: row.1, @@ -314,9 +335,9 @@ impl Model for Version { fn from_row(row: &Row) -> Version { let num: String = row.get("num"); let features: Option = row.get("features"); - let features = features.map(|s| json::decode(&s).unwrap()).unwrap_or_else( - HashMap::new, - ); + let features = features + .map(|s| json::decode(&s).unwrap()) + .unwrap_or_else(HashMap::new); Version { id: row.get("id"), crate_id: row.get("crate_id"), @@ -343,11 +364,7 @@ pub fn index(req: &mut Request) -> CargoResult { // Extract all ids requested. let query = url::form_urlencoded::parse(req.query_string().unwrap_or("").as_bytes()); let ids = query - .filter_map(|(ref a, ref b)| if *a == "ids[]" { - b.parse().ok() - } else { - None - }) + .filter_map(|(ref a, ref b)| if *a == "ids[]" { b.parse().ok() } else { None },) .collect::>(); let versions = versions::table @@ -392,19 +409,23 @@ pub fn show(req: &mut Request) -> CargoResult { fn version_and_crate_old(req: &mut Request) -> CargoResult<(Version, Crate)> { let crate_name = &req.params()["crate_id"]; let semver = &req.params()["version"]; - let semver = semver::Version::parse(semver).map_err(|_| { - human(&format_args!("invalid semver: {}", semver)) - })?; + let semver = semver::Version::parse(semver) + .map_err(|_| human(&format_args!("invalid semver: {}", semver)))?; let tx = req.tx()?; let krate = Crate::find_by_name(tx, crate_name)?; let version = Version::find_by_num(tx, krate.id, &semver)?; - let version = version.chain_error(|| { - human(&format_args!( + let version = version + .chain_error( + || { + human( + &format_args!( "crate `{}` does not have a version `{}`", crate_name, semver - )) - })?; + ), + ) + }, + )?; Ok((version, krate)) } @@ -419,13 +440,17 @@ fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> { let version = Version::belonging_to(&krate) .filter(versions::num.eq(semver)) .first(&*conn) - .map_err(|_| { - human(&format_args!( + .map_err( + |_| { + human( + &format_args!( "crate `{}` does not have a version `{}`", crate_name, semver - )) - })?; + ), + ) + }, + )?; Ok((version, krate)) } @@ -458,10 +483,7 @@ pub fn downloads(req: &mut Request) -> CargoResult { let cutoff_start_date = cutoff_end_date + Duration::days(-89); let downloads = VersionDownload::belonging_to(&version) - .filter(version_downloads::date.between( - date(cutoff_start_date).. - date(cutoff_end_date), - )) + .filter(version_downloads::date.between(date(cutoff_start_date)..date(cutoff_end_date)),) .order(version_downloads::date) .load(&*conn)? .into_iter() @@ -479,7 +501,11 @@ pub fn downloads(req: &mut Request) -> CargoResult { pub fn authors(req: &mut Request) -> CargoResult { let (version, _) = version_and_crate_old(req)?; let tx = req.tx()?; - let names = version.authors(tx)?.into_iter().map(|a| a.name).collect(); + let names = version + .authors(tx)? + .into_iter() + .map(|a| a.name) + .collect(); // It was imagined that we wold associate authors with users. // This was never implemented. This complicated return struct @@ -493,10 +519,14 @@ pub fn authors(req: &mut Request) -> CargoResult { struct Meta { names: Vec, } - Ok(req.json(&R { - users: vec![], - meta: Meta { names: names }, - })) + Ok( + req.json( + &R { + users: vec![], + meta: Meta { names: names }, + }, + ), + ) } /// Handles the `DELETE /crates/:crate_id/:version/yank` route. @@ -519,13 +549,15 @@ fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult { } if version.yanked != yanked { - conn.transaction::<_, Box, _>(|| { - diesel::update(&version) - .set(versions::yanked.eq(yanked)) - .execute(&*conn)?; - git::yank(&**req.app(), &krate.name, &version.num, yanked)?; - Ok(()) - })?; + conn.transaction::<_, Box, _>( + || { + diesel::update(&version) + .set(versions::yanked.eq(yanked)) + .execute(&*conn)?; + git::yank(&**req.app(), &krate.name, &version.num, yanked)?; + Ok(()) + }, + )?; } #[derive(RustcEncodable)] From 8d8305d78c5abba0a250f444e71b642dba9559b4 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Mon, 19 Jun 2017 19:52:51 -0400 Subject: [PATCH 27/29] Soooo I updated rustfmt to nightly and then ran it again. --- build.rs | 5 +- src/app.rs | 4 +- src/badge.rs | 26 +- src/bin/delete-crate.rs | 49 +-- src/bin/delete-version.rs | 14 +- src/bin/fill-in-user-id.rs | 22 +- src/bin/populate.rs | 10 +- src/bin/transfer-crates.rs | 15 +- src/bin/update-downloads.rs | 162 ++++---- src/bin/update-licenses.rs | 10 +- src/categories.rs | 70 ++-- src/category.rs | 213 +++++----- src/db.rs | 13 +- src/dependency.rs | 114 +++--- src/dist.rs | 13 +- src/git.rs | 115 +++--- src/http.rs | 40 +- src/keyword.rs | 58 ++- src/krate.rs | 783 ++++++++++++++++-------------------- src/lib.rs | 21 +- src/owner.rs | 87 ++-- src/tests/all.rs | 136 ++++--- src/tests/badge.rs | 12 +- src/tests/category.rs | 9 +- src/tests/git.rs | 8 +- src/tests/krate.rs | 54 +-- src/tests/record.rs | 153 +++---- src/tests/version.rs | 8 +- src/upload.rs | 34 +- src/uploaders.rs | 80 ++-- src/user/middleware.rs | 4 +- src/user/mod.rs | 84 ++-- src/util/errors.rs | 75 ++-- src/util/head.rs | 18 +- src/util/io_util.rs | 9 +- src/util/mod.rs | 34 +- src/util/request_proxy.rs | 4 +- src/version.rs | 212 +++++----- 38 files changed, 1263 insertions(+), 1515 deletions(-) diff --git a/build.rs b/build.rs index 2a819a48bb4..d72b5441d7c 100644 --- a/build.rs +++ b/build.rs @@ -11,9 +11,8 @@ fn main() { if env::var("PROFILE") == Ok("debug".into()) { let _ = dotenv(); if let Ok(database_url) = env::var("TEST_DATABASE_URL") { - let connection = PgConnection::establish(&database_url).expect( - "Could not connect to TEST_DATABASE_URL", - ); + let connection = PgConnection::establish(&database_url) + .expect("Could not connect to TEST_DATABASE_URL"); run_pending_migrations(&connection).expect("Error running migrations"); } } diff --git a/src/app.rs b/src/app.rs index ae59e6a1a09..cf99744f9e6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -127,8 +127,6 @@ pub trait RequestApp { impl RequestApp for T { fn app(&self) -> &Arc { - self.extensions() - .find::>() - .expect("Missing app") + self.extensions().find::>().expect("Missing app") } } diff --git a/src/badge.rs b/src/badge.rs index f9b7b81a79f..bdbcea7fe11 100644 --- a/src/badge.rs +++ b/src/badge.rs @@ -100,26 +100,22 @@ impl Badge { let json = json!({"badge_type": k, "attributes": attributes_json}); if serde_json::from_value::(json).is_ok() { - new_badges.push( - NewBadge { - crate_id: krate.id, - badge_type: &**k, - attributes: attributes_json, - }, - ); + new_badges.push(NewBadge { + crate_id: krate.id, + badge_type: &**k, + attributes: attributes_json, + }); } else { invalid_badges.push(&**k); } } } - conn.transaction( - || { - delete(badges::table.filter(badges::crate_id.eq(krate.id))) - .execute(conn)?; - insert(&new_badges).into(badges::table).execute(conn)?; - Ok(invalid_badges) - }, - ) + conn.transaction(|| { + delete(badges::table.filter(badges::crate_id.eq(krate.id))) + .execute(conn)?; + insert(&new_badges).into(badges::table).execute(conn)?; + Ok(invalid_badges) + }) } } diff --git a/src/bin/delete-crate.rs b/src/bin/delete-crate.rs index 00887fccc5d..3e32cec3115 100644 --- a/src/bin/delete-crate.rs +++ b/src/bin/delete-crate.rs @@ -55,16 +55,14 @@ fn delete(tx: &postgres::transaction::Transaction) { for v in versions.iter() { println!("deleting version {} ({})", v.num, v.id); let n = tx.execute( - "DELETE FROM version_downloads WHERE version_id = $1", - &[&v.id], - ) - .unwrap(); + "DELETE FROM version_downloads WHERE version_id = $1", + &[&v.id], + ).unwrap(); println!(" {} download records deleted", n); let n = tx.execute( - "DELETE FROM version_authors WHERE version_id = $1", - &[&v.id], - ) - .unwrap(); + "DELETE FROM version_authors WHERE version_id = $1", + &[&v.id], + ).unwrap(); println!(" {} author records deleted", n); let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1", &[&v.id]) .unwrap(); @@ -80,10 +78,9 @@ fn delete(tx: &postgres::transaction::Transaction) { println!("deleting crate download records"); let n = tx.execute( - "DELETE FROM crate_downloads WHERE crate_id = $1", - &[&krate.id], - ) - .unwrap(); + "DELETE FROM crate_downloads WHERE crate_id = $1", + &[&krate.id], + ).unwrap(); println!(" {} deleted", n); println!("deleting crate owners"); @@ -93,33 +90,29 @@ fn delete(tx: &postgres::transaction::Transaction) { println!("disabling reserved crate name trigger"); let _ = tx.execute( - "ALTER TABLE crates DISABLE TRIGGER trigger_ensure_crate_name_not_reserved;", - &[], - ) - .unwrap(); + "ALTER TABLE crates DISABLE TRIGGER trigger_ensure_crate_name_not_reserved;", + &[], + ).unwrap(); println!("deleting crate keyword connections"); let n = tx.execute( - "DELETE FROM crates_keywords WHERE crate_id = $1", - &[&krate.id], - ) - .unwrap(); + "DELETE FROM crates_keywords WHERE crate_id = $1", + &[&krate.id], + ).unwrap(); println!(" {} deleted", n); println!("deleting crate category connections"); let n = tx.execute( - "DELETE FROM crates_categories WHERE crate_id = $1", - &[&krate.id], - ) - .unwrap(); + "DELETE FROM crates_categories WHERE crate_id = $1", + &[&krate.id], + ).unwrap(); println!(" {} deleted", n); println!("enabling reserved crate name trigger"); let _ = tx.execute( - "ALTER TABLE crates ENABLE TRIGGER trigger_ensure_crate_name_not_reserved;", - &[], - ) - .unwrap(); + "ALTER TABLE crates ENABLE TRIGGER trigger_ensure_crate_name_not_reserved;", + &[], + ).unwrap(); println!("deleting crate badges"); let n = tx.execute("DELETE FROM badges WHERE crate_id = $1", &[&krate.id]) diff --git a/src/bin/delete-version.rs b/src/bin/delete-version.rs index 826cdc968d9..9679323d59c 100644 --- a/src/bin/delete-version.rs +++ b/src/bin/delete-version.rs @@ -65,16 +65,14 @@ fn delete(tx: &postgres::transaction::Transaction) { println!("deleting version {} ({})", v.num, v.id); let n = tx.execute( - "DELETE FROM version_downloads WHERE version_id = $1", - &[&v.id], - ) - .unwrap(); + "DELETE FROM version_downloads WHERE version_id = $1", + &[&v.id], + ).unwrap(); println!(" {} download records deleted", n); let n = tx.execute( - "DELETE FROM version_authors WHERE version_id = $1", - &[&v.id], - ) - .unwrap(); + "DELETE FROM version_authors WHERE version_id = $1", + &[&v.id], + ).unwrap(); println!(" {} author records deleted", n); let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1", &[&v.id]) .unwrap(); diff --git a/src/bin/fill-in-user-id.rs b/src/bin/fill-in-user-id.rs index e8d2d26dd81..d3a907a2ca1 100644 --- a/src/bin/fill-in-user-id.rs +++ b/src/bin/fill-in-user-id.rs @@ -56,15 +56,13 @@ fn update(app: &App, tx: &postgres::transaction::Transaction) { let rows = tx.query(query, &[]) .unwrap() .into_iter() - .map( - |row| { - let id: i32 = row.get("id"); - let login: String = row.get("gh_login"); - let token: String = row.get("gh_access_token"); - let avatar: Option = row.get("gh_avatar"); - (id, login, http::token(token), avatar) - }, - ) + .map(|row| { + let id: i32 = row.get("id"); + let login: String = row.get("gh_login"); + let token: String = row.get("gh_access_token"); + let avatar: Option = row.get("gh_avatar"); + (id, login, http::token(token), avatar) + }) .collect::>(); for (id, login, token, avatar) in rows { @@ -80,9 +78,9 @@ fn update(app: &App, tx: &postgres::transaction::Transaction) { } if ghuser.login == login { tx.execute( - "UPDATE users SET gh_id = $1 WHERE id = $2", - &[&ghuser.id, &id], - )?; + "UPDATE users SET gh_id = $1 WHERE id = $2", + &[&ghuser.id, &id], + )?; Ok(()) } else { Err(human(&format_args!("different login: {}", ghuser.login))) diff --git a/src/bin/populate.rs b/src/bin/populate.rs index 84fe9a31d4e..bde4df36633 100644 --- a/src/bin/populate.rs +++ b/src/bin/populate.rs @@ -39,11 +39,11 @@ fn update(tx: &postgres::transaction::Transaction) -> postgres::Result<()> { let moment = now + Duration::days(-day); dls += rng.gen_range(-100, 100); tx.execute( - "INSERT INTO version_downloads \ - (version_id, downloads, date) \ - VALUES ($1, $2, $3)", - &[&id, &dls, &moment], - )?; + "INSERT INTO version_downloads \ + (version_id, downloads, date) \ + VALUES ($1, $2, $3)", + &[&id, &dls, &moment], + )?; } } Ok(()) diff --git a/src/bin/transfer-crates.rs b/src/bin/transfer-crates.rs index 1e1a4df89cb..48e507757bb 100644 --- a/src/bin/transfer-crates.rs +++ b/src/bin/transfer-crates.rs @@ -69,13 +69,11 @@ fn transfer(tx: &postgres::transaction::Transaction) { let stmt = tx.prepare( - "SELECT * FROM crate_owners + "SELECT * FROM crate_owners WHERE owner_id = $1 AND owner_kind = $2", - ) - .unwrap(); - let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]) - .unwrap(); + ).unwrap(); + let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]).unwrap(); for row in rows.iter() { let id: i32 = row.get("id"); let krate = Crate::find(tx, row.get("crate_id")).unwrap(); @@ -85,11 +83,10 @@ fn transfer(tx: &postgres::transaction::Transaction) { println!("warning: not exactly one owner for {}", krate.name); } let n = tx.execute( - "UPDATE crate_owners SET owner_id = $1 + "UPDATE crate_owners SET owner_id = $1 WHERE id $2", - &[&to.id, &id], - ) - .unwrap(); + &[&to.id, &id], + ).unwrap(); assert_eq!(n, 1); } diff --git a/src/bin/update-downloads.rs b/src/bin/update-downloads.rs index da157dc3232..59aa514bff6 100644 --- a/src/bin/update-downloads.rs +++ b/src/bin/update-downloads.rs @@ -40,11 +40,11 @@ fn update(conn: &postgres::GenericConnection) -> postgres::Result<()> { tx = conn.transaction()?; { let stmt = tx.prepare( - "SELECT * FROM version_downloads \ + "SELECT * FROM version_downloads \ WHERE processed = FALSE AND id > $1 ORDER BY id ASC LIMIT $2", - )?; + )?; let mut rows = stmt.query(&[&max, &LIMIT])?; match collect(&tx, &mut rows)? { None => break, @@ -94,11 +94,11 @@ fn collect( // Flag this row as having been processed if we're passed the cutoff, // and unconditionally increment the number of counted downloads. tx.execute( - "UPDATE version_downloads + "UPDATE version_downloads SET processed = $2, counted = counted + $3 WHERE id = $1", - &[id, &(download.date < cutoff), &amt], - )?; + &[id, &(download.date < cutoff), &amt], + )?; total += amt as i64; if amt == 0 { @@ -109,41 +109,41 @@ fn collect( // Update the total number of version downloads tx.execute( - "UPDATE versions + "UPDATE versions SET downloads = downloads + $1 WHERE id = $2", - &[&amt, &download.version_id], - )?; + &[&amt, &download.version_id], + )?; // Update the total number of crate downloads tx.execute( - "UPDATE crates SET downloads = downloads + $1 + "UPDATE crates SET downloads = downloads + $1 WHERE id = $2", - &[&amt, &crate_id], - )?; + &[&amt, &crate_id], + )?; // Update the total number of crate downloads for today let cnt = tx.execute( - "UPDATE crate_downloads + "UPDATE crate_downloads SET downloads = downloads + $2 WHERE crate_id = $1 AND date = $3", - &[&crate_id, &amt, &download.date], - )?; + &[&crate_id, &amt, &download.date], + )?; if cnt == 0 { tx.execute( - "INSERT INTO crate_downloads + "INSERT INTO crate_downloads (crate_id, downloads, date) VALUES ($1, $2, $3)", - &[&crate_id, &amt, &download.date], - )?; + &[&crate_id, &amt, &download.date], + )?; } } // After everything else is done, update the global counter of total // downloads. tx.execute( - "UPDATE metadata SET total_downloads = total_downloads + $1", - &[&total], - )?; + "UPDATE metadata SET total_downloads = total_downloads + $1", + &[&total], + )?; Ok(Some(max)) } @@ -171,10 +171,9 @@ mod test { fn crate_downloads(tx: &postgres::transaction::Transaction, id: i32, expected: usize) { let stmt = tx.prepare( - "SELECT * FROM crate_downloads + "SELECT * FROM crate_downloads WHERE crate_id = $1", - ) - .unwrap(); + ).unwrap(); let dl: i32 = stmt.query(&[&id]) .unwrap() .iter() @@ -201,30 +200,26 @@ mod test { &None, &None, None, - ) - .unwrap(); + ).unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ) - .unwrap(); + ).unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id) VALUES ($1)", - &[&version.id], - ) - .unwrap(); + &[&version.id], + ).unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, date, processed) VALUES ($1, current_date - interval '1 day', true)", - &[&version.id], - ) - .unwrap(); + &[&version.id], + ).unwrap(); ::update(&tx).unwrap(); assert_eq!(Version::find(&tx, version.id).unwrap().downloads, 1); assert_eq!(Crate::find(&tx, krate.id).unwrap().downloads, 1); @@ -250,29 +245,25 @@ mod test { &None, &None, None, - ) - .unwrap(); + ).unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ) - .unwrap(); + ).unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 2, current_date - interval '2 days', false)", - &[&version.id], - ) - .unwrap(); + &[&version.id], + ).unwrap(); ::update(&tx).unwrap(); let stmt = tx.prepare( - "SELECT processed FROM version_downloads + "SELECT processed FROM version_downloads WHERE version_id = $1", - ) - .unwrap(); + ).unwrap(); let processed: bool = stmt.query(&[&version.id]) .unwrap() .iter() @@ -299,30 +290,26 @@ mod test { &None, &None, None, - ) - .unwrap(); + ).unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ) - .unwrap(); + ).unwrap(); let time = time::now_utc().to_timespec() - Duration::hours(2); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 2, date($2), false)", - &[&version.id, &time], - ) - .unwrap(); + &[&version.id, &time], + ).unwrap(); ::update(&tx).unwrap(); let stmt = tx.prepare( - "SELECT processed FROM version_downloads + "SELECT processed FROM version_downloads WHERE version_id = $1", - ) - .unwrap(); + ).unwrap(); let processed: bool = stmt.query(&[&version.id]) .unwrap() .iter() @@ -349,42 +336,36 @@ mod test { &None, &None, None, - ) - .unwrap(); + ).unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ) - .unwrap(); + ).unwrap(); tx.execute( - "UPDATE versions + "UPDATE versions SET updated_at = current_date - interval '2 hours'", - &[], - ) - .unwrap(); + &[], + ).unwrap(); tx.execute( - "UPDATE crates + "UPDATE crates SET updated_at = current_date - interval '2 hours'", - &[], - ) - .unwrap(); + &[], + ).unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 1, current_date, false)", - &[&version.id], - ) - .unwrap(); + &[&version.id], + ).unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, date) VALUES ($1, current_date - interval '1 day')", - &[&version.id], - ) - .unwrap(); + &[&version.id], + ).unwrap(); let version_before = Version::find(&tx, version.id).unwrap(); let krate_before = Crate::find(&tx, krate.id).unwrap(); @@ -417,35 +398,30 @@ mod test { &None, &None, None, - ) - .unwrap(); + ).unwrap(); let version = Version::insert( &tx, krate.id, &semver::Version::parse("1.0.0").unwrap(), &HashMap::new(), &[], - ) - .unwrap(); + ).unwrap(); tx.execute( - "UPDATE versions + "UPDATE versions SET updated_at = current_date - interval '2 days'", - &[], - ) - .unwrap(); + &[], + ).unwrap(); tx.execute( - "UPDATE crates + "UPDATE crates SET updated_at = current_date - interval '2 days'", - &[], - ) - .unwrap(); + &[], + ).unwrap(); tx.execute( - "INSERT INTO version_downloads \ + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 2, current_date - interval '2 days', false)", - &[&version.id], - ) - .unwrap(); + &[&version.id], + ).unwrap(); let version_before = Version::find(&tx, version.id).unwrap(); let krate_before = Crate::find(&tx, krate.id).unwrap(); diff --git a/src/bin/update-licenses.rs b/src/bin/update-licenses.rs index ac4c213d037..56394e1cfa4 100644 --- a/src/bin/update-licenses.rs +++ b/src/bin/update-licenses.rs @@ -21,8 +21,7 @@ fn main() { } fn transfer(tx: &postgres::transaction::Transaction) { - let stmt = tx.prepare("SELECT id, name, license FROM crates") - .unwrap(); + let stmt = tx.prepare("SELECT id, name, license FROM crates").unwrap(); let rows = stmt.query(&[]).unwrap(); for row in rows.iter() { @@ -37,10 +36,9 @@ fn transfer(tx: &postgres::transaction::Transaction) { ); let num_updated = tx.execute( - "UPDATE versions SET license = $1 WHERE crate_id = $2", - &[&license, &id], - ) - .unwrap(); + "UPDATE versions SET license = $1 WHERE crate_id = $2", + &[&license, &id], + ).unwrap(); assert!(num_updated > 0); } diff --git a/src/categories.rs b/src/categories.rs index de2c068153f..31620800f71 100644 --- a/src/categories.rs +++ b/src/categories.rs @@ -39,24 +39,16 @@ impl Category { } fn required_string_from_toml<'a>(toml: &'a toml::Table, key: &str) -> CargoResult<&'a str> { - toml.get(key) - .and_then(toml::Value::as_str) - .chain_error( - || { - internal( - &format_args!( + toml.get(key).and_then(toml::Value::as_str).chain_error(|| { + internal(&format_args!( "Expected category TOML attribute '{}' to be a String", key - ), - ) - }, - ) + )) + }) } fn optional_string_from_toml<'a>(toml: &'a toml::Table, key: &str) -> &'a str { - toml.get(key) - .and_then(toml::Value::as_str) - .unwrap_or("") + toml.get(key).and_then(toml::Value::as_str).unwrap_or("") } fn categories_from_toml( @@ -66,9 +58,11 @@ fn categories_from_toml( let mut result = vec![]; for (slug, details) in categories { - let details = details.as_table().chain_error(|| { - internal(&format_args!("category {} was not a TOML table", slug)) - })?; + let details = details + .as_table() + .chain_error(|| { + internal(&format_args!("category {} was not a TOML table", slug)) + })?; let category = Category::from_parent( slug, @@ -78,18 +72,12 @@ fn categories_from_toml( ); if let Some(categories) = details.get("categories") { - let categories = categories - .as_table() - .chain_error( - || { - internal( - &format_args!( + let categories = categories.as_table().chain_error(|| { + internal(&format_args!( "child categories of {} were not a table", slug - ), - ) - }, - )?; + )) + })?; result.extend(categories_from_toml(categories, Some(&category))?); } @@ -109,19 +97,19 @@ pub fn sync() -> CargoResult<()> { .parse() .expect("Could not parse categories.toml"); - let categories = - categories_from_toml(&toml, None).expect("Could not convert categories from TOML"); + let categories = categories_from_toml(&toml, None) + .expect("Could not convert categories from TOML"); for category in &categories { tx.execute( - "\ - INSERT INTO categories (slug, category, description) \ - VALUES (LOWER($1), $2, $3) \ - ON CONFLICT (slug) DO UPDATE \ - SET category = EXCLUDED.category, \ - description = EXCLUDED.description;", - &[&category.slug, &category.name, &category.description], - )?; + "\ + INSERT INTO categories (slug, category, description) \ + VALUES (LOWER($1), $2, $3) \ + ON CONFLICT (slug) DO UPDATE \ + SET category = EXCLUDED.category, \ + description = EXCLUDED.description;", + &[&category.slug, &category.name, &category.description], + )?; } let in_clause = categories @@ -131,14 +119,14 @@ pub fn sync() -> CargoResult<()> { .join(","); tx.execute( - &format!( + &format!( "\ - DELETE FROM categories \ - WHERE slug NOT IN ({});", + DELETE FROM categories \ + WHERE slug NOT IN ({});", in_clause ), - &[], - )?; + &[], + )?; tx.set_commit(); tx.finish().unwrap(); Ok(()) diff --git a/src/category.rs b/src/category.rs index 092de5c3a5e..28f5f332de0 100644 --- a/src/category.rs +++ b/src/category.rs @@ -59,9 +59,9 @@ pub struct EncodableCategoryWithSubcategories { impl Category { pub fn find_by_category(conn: &GenericConnection, name: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM categories \ - WHERE category = $1", - )?; + "SELECT * FROM categories \ + WHERE category = $1", + )?; let rows = stmt.query(&[&name])?; rows.iter() .next() @@ -71,9 +71,9 @@ impl Category { pub fn find_by_slug(conn: &GenericConnection, slug: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM categories \ - WHERE slug = LOWER($1)", - )?; + "SELECT * FROM categories \ + WHERE slug = LOWER($1)", + )?; let rows = stmt.query(&[&slug])?; rows.iter() .next() @@ -107,35 +107,31 @@ impl Category { ) -> QueryResult> { use diesel::expression::dsl::any; - conn.transaction( - || { - let categories = categories::table - .filter(categories::slug.eq(any(slugs))) - .load::(conn)?; - let invalid_categories = slugs - .iter() - .cloned() - .filter(|s| !categories.iter().any(|c| c.slug == *s)) - .collect(); - let crate_categories = categories - .iter() - .map( - |c| { - CrateCategory { - category_id: c.id, - crate_id: krate.id, - } - }, - ) - .collect::>(); - - delete(CrateCategory::belonging_to(krate)).execute(conn)?; - insert(&crate_categories) - .into(crates_categories::table) - .execute(conn)?; - Ok(invalid_categories) - }, - ) + conn.transaction(|| { + let categories = categories::table + .filter(categories::slug.eq(any(slugs))) + .load::(conn)?; + let invalid_categories = slugs + .iter() + .cloned() + .filter(|s| !categories.iter().any(|c| c.slug == *s)) + .collect(); + let crate_categories = categories + .iter() + .map(|c| { + CrateCategory { + category_id: c.id, + crate_id: krate.id, + } + }) + .collect::>(); + + delete(CrateCategory::belonging_to(krate)).execute(conn)?; + insert(&crate_categories) + .into(crates_categories::table) + .execute(conn)?; + Ok(invalid_categories) + }) } pub fn update_crate_old( @@ -151,15 +147,13 @@ impl Category { let mut invalid_categories = vec![]; let new_categories: Vec = categories .iter() - .flat_map( - |c| match Category::find_by_slug(conn, c) { - Ok(cat) => Some(cat), - Err(_) => { - invalid_categories.push(c.to_string()); - None - } - }, - ) + .flat_map(|c| match Category::find_by_slug(conn, c) { + Ok(cat) => Some(cat), + Err(_) => { + invalid_categories.push(c.to_string()); + None + } + }) .collect(); let new_categories_ids: HashSet<_> = new_categories.iter().map(|cat| cat.id).collect(); @@ -175,11 +169,11 @@ impl Category { if !to_rm.is_empty() { conn.execute( - "DELETE FROM crates_categories \ - WHERE category_id = ANY($1) \ - AND crate_id = $2", - &[&to_rm, &krate.id], - )?; + "DELETE FROM crates_categories \ + WHERE category_id = ANY($1) \ + AND crate_id = $2", + &[&to_rm, &krate.id], + )?; } if !to_add.is_empty() { @@ -189,13 +183,13 @@ impl Category { .collect(); let insert = insert.join(", "); conn.execute( - &format!( + &format!( "INSERT INTO crates_categories \ - (crate_id, category_id) VALUES {}", + (crate_id, category_id) VALUES {}", insert ), - &[], - )?; + &[], + )?; } Ok(invalid_categories) @@ -204,9 +198,9 @@ impl Category { pub fn count_toplevel(conn: &GenericConnection) -> CargoResult { let sql = format!( "\ - SELECT COUNT(*) \ - FROM {} \ - WHERE category NOT LIKE '%::%'", + SELECT COUNT(*) \ + FROM {} \ + WHERE category NOT LIKE '%::%'", Model::table_name(None::) ); let stmt = conn.prepare(&sql)?; @@ -230,9 +224,7 @@ impl Category { // Collect all the top-level categories and sum up the crates_cnt of // the crates in all subcategories - select( - sql::( - &format!( + select(sql::(&format!( "c.id, c.category, c.slug, c.description, sum(c2.crates_cnt)::int as crates_cnt, c.created_at FROM categories as c @@ -243,10 +235,7 @@ impl Category { sort_sql, limit, offset - ), - ), - ) - .load(conn) + ))).load(conn) } pub fn toplevel_old( @@ -263,8 +252,7 @@ impl Category { // Collect all the top-level categories and sum up the crates_cnt of // the crates in all subcategories - let stmt = conn.prepare( - &format!( + let stmt = conn.prepare(&format!( "SELECT c.id, c.category, c.slug, c.description, c.created_at, sum(c2.crates_cnt)::int as crates_cnt FROM categories as c @@ -273,8 +261,7 @@ impl Category { GROUP BY c.id {} LIMIT $1 OFFSET $2", sort_sql - ), - )?; + ))?; let categories: Vec<_> = stmt.query(&[&limit, &offset])? .iter() @@ -286,18 +273,18 @@ impl Category { pub fn subcategories(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "\ - SELECT c.id, c.category, c.slug, c.description, c.created_at, \ - COALESCE (( \ - SELECT sum(c2.crates_cnt)::int \ - FROM categories as c2 \ - WHERE c2.slug = c.slug \ - OR c2.slug LIKE c.slug || '::%' \ - ), 0) as crates_cnt \ - FROM categories as c \ - WHERE c.category ILIKE $1 || '::%' \ - AND c.category NOT ILIKE $1 || '::%::%'", - )?; + "\ + SELECT c.id, c.category, c.slug, c.description, c.created_at, \ + COALESCE (( \ + SELECT sum(c2.crates_cnt)::int \ + FROM categories as c2 \ + WHERE c2.slug = c.slug \ + OR c2.slug LIKE c.slug || '::%' \ + ), 0) as crates_cnt \ + FROM categories as c \ + WHERE c.category ILIKE $1 || '::%' \ + AND c.category NOT ILIKE $1 || '::%::%'", + )?; let rows = stmt.query(&[&self.category])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) @@ -353,10 +340,7 @@ pub fn index(req: &mut Request) -> CargoResult { let sort = query.get("sort").map_or("alpha", String::as_str); let categories = Category::toplevel_old(conn, sort, limit, offset)?; - let categories = categories - .into_iter() - .map(Category::encodable) - .collect(); + let categories = categories.into_iter().map(Category::encodable).collect(); // Query for the total count of categories let total = Category::count_toplevel(conn)?; @@ -371,14 +355,10 @@ pub fn index(req: &mut Request) -> CargoResult { total: i64, } - Ok( - req.json( - &R { - categories: categories, - meta: Meta { total: total }, - }, - ), - ) + Ok(req.json(&R { + categories: categories, + meta: Meta { total: total }, + })) } /// Handles the `GET /categories/:category_id` route. @@ -412,9 +392,9 @@ pub fn show(req: &mut Request) -> CargoResult { pub fn slugs(req: &mut Request) -> CargoResult { let conn = req.tx()?; let stmt = conn.prepare( - "SELECT slug FROM categories \ - ORDER BY slug", - )?; + "SELECT slug FROM categories \ + ORDER BY slug", + )?; let rows = stmt.query(&[])?; #[derive(RustcEncodable)] @@ -424,15 +404,13 @@ pub fn slugs(req: &mut Request) -> CargoResult { } let slugs: Vec = rows.iter() - .map( - |r| { - let slug: String = r.get("slug"); - Slug { - id: slug.clone(), - slug: slug, - } - }, - ) + .map(|r| { + let slug: String = r.get("slug"); + Slug { + id: slug.clone(), + slug: slug, + } + }) .collect(); #[derive(RustcEncodable)] @@ -451,8 +429,8 @@ mod tests { fn pg_connection() -> PgConnection { let _ = dotenv(); - let database_url = - env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests"); + let database_url = env::var("TEST_DATABASE_URL") + .expect("TEST_DATABASE_URL must be set to run tests"); let conn = PgConnection::establish(&database_url).unwrap(); // These tests deadlock if run concurrently conn.batch_execute("BEGIN; LOCK categories IN ACCESS EXCLUSIVE MODE") @@ -464,11 +442,10 @@ mod tests { fn category_toplevel_excludes_subcategories() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug) VALUES + "INSERT INTO categories (category, slug) VALUES ('Cat 2', 'cat2'), ('Cat 1', 'cat1'), ('Cat 1::sub', 'cat1::sub') ", - ) - .unwrap(); + ).unwrap(); let categories = Category::toplevel(&conn, "", 10, 0) .unwrap() @@ -483,11 +460,10 @@ mod tests { fn category_toplevel_orders_by_crates_cnt_when_sort_given() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug, crates_cnt) VALUES + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 0), ('Cat 2', 'cat2', 2), ('Cat 3', 'cat3', 1) ", - ) - .unwrap(); + ).unwrap(); let categories = Category::toplevel(&conn, "crates", 10, 0) .unwrap() @@ -506,11 +482,10 @@ mod tests { fn category_toplevel_applies_limit_and_offset() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug) VALUES + "INSERT INTO categories (category, slug) VALUES ('Cat 1', 'cat1'), ('Cat 2', 'cat2') ", - ) - .unwrap(); + ).unwrap(); let categories = Category::toplevel(&conn, "", 1, 0) .unwrap() @@ -533,13 +508,12 @@ mod tests { fn category_toplevel_includes_subcategories_in_crate_cnt() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug, crates_cnt) VALUES + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 1), ('Cat 1::sub', 'cat1::sub', 2), ('Cat 2', 'cat2', 3), ('Cat 2::Sub 1', 'cat2::sub1', 4), ('Cat 2::Sub 2', 'cat2::sub2', 5), ('Cat 3', 'cat3', 6) ", - ) - .unwrap(); + ).unwrap(); let categories = Category::toplevel(&conn, "crates", 10, 0) .unwrap() @@ -558,13 +532,12 @@ mod tests { fn category_toplevel_applies_limit_and_offset_after_grouping() { let conn = pg_connection(); conn.batch_execute( - "INSERT INTO categories (category, slug, crates_cnt) VALUES + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 1), ('Cat 1::sub', 'cat1::sub', 2), ('Cat 2', 'cat2', 3), ('Cat 2::Sub 1', 'cat2::sub1', 4), ('Cat 2::Sub 2', 'cat2::sub2', 5), ('Cat 3', 'cat3', 6) ", - ) - .unwrap(); + ).unwrap(); let categories = Category::toplevel(&conn, "crates", 2, 0) .unwrap() diff --git a/src/db.rs b/src/db.rs index 715d67b6dca..2e29d1a391b 100644 --- a/src/db.rs +++ b/src/db.rs @@ -150,12 +150,15 @@ impl Transaction { } pub fn conn( - &self,) - -> CargoResult<&r2d2::PooledConnection> { + &self, + ) -> CargoResult<&r2d2::PooledConnection> { if !self.slot.filled() { - let conn = self.app.database.get().map_err(|e| { - internal(&format_args!("failed to get a database connection: {}", e)) - })?; + let conn = self.app + .database + .get() + .map_err(|e| { + internal(&format_args!("failed to get a database connection: {}", e)) + })?; self.slot.fill(Box::new(conn)); } Ok(&**self.slot.borrow().unwrap()) diff --git a/src/dependency.rs b/src/dependency.rs index 6a2c229d4b6..2553965a926 100644 --- a/src/dependency.rs +++ b/src/dependency.rs @@ -85,24 +85,24 @@ impl Dependency { ) -> CargoResult { let req = req.to_string(); let stmt = conn.prepare( - "INSERT INTO dependencies + "INSERT INTO dependencies (version_id, crate_id, req, optional, default_features, features, target, kind) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *", - )?; + )?; let rows = stmt.query( - &[ - &version_id, - &crate_id, - &req, - &optional, - &default_features, - &features, - target, - &(kind as i32), - ], - )?; + &[ + &version_id, + &crate_id, + &req, + &optional, + &default_features, + &features, + target, + &(kind as i32), + ], + )?; Ok(Model::from_row(&rows.iter().next().unwrap())) } @@ -138,48 +138,44 @@ pub fn add_dependencies( use diesel::insert; let git_and_new_dependencies = deps.iter() - .map( - |dep| { - let krate = Crate::by_name(&dep.name).first::(&*conn).map_err( - |_| { + .map(|dep| { + let krate = Crate::by_name(&dep.name) + .first::(&*conn) + .map_err(|_| { human(&format_args!("no known crate named `{}`", &*dep.name)) - }, - )?; - if dep.version_req == semver::VersionReq::parse("*").unwrap() { - return Err( - human( - "wildcard (`*`) dependency constraints are not allowed \ - on crates.io. See http://doc.crates.io/faq.html#can-\ - libraries-use--as-a-version-for-their-dependencies for more \ - information", - ), - ); - } - let features: Vec<_> = dep.features.iter().map(|s| &**s).collect(); + })?; + if dep.version_req == semver::VersionReq::parse("*").unwrap() { + return Err(human( + "wildcard (`*`) dependency constraints are not allowed \ + on crates.io. See http://doc.crates.io/faq.html#can-\ + libraries-use--as-a-version-for-their-dependencies for more \ + information", + )); + } + let features: Vec<_> = dep.features.iter().map(|s| &**s).collect(); - Ok( - (git::Dependency { - name: dep.name.to_string(), - req: dep.version_req.to_string(), - features: features.iter().map(|s| s.to_string()).collect(), - optional: dep.optional, - default_features: dep.default_features, - target: dep.target.clone(), - kind: dep.kind.or(Some(Kind::Normal)), - }, - NewDependency { - version_id: version_id, - crate_id: krate.id, - req: dep.version_req.to_string(), - kind: dep.kind.unwrap_or(Kind::Normal) as i32, - optional: dep.optional, - default_features: dep.default_features, - features: features, - target: dep.target.as_ref().map(|s| &**s), - }), - ) - }, - ) + Ok(( + git::Dependency { + name: dep.name.to_string(), + req: dep.version_req.to_string(), + features: features.iter().map(|s| s.to_string()).collect(), + optional: dep.optional, + default_features: dep.default_features, + target: dep.target.clone(), + kind: dep.kind.or(Some(Kind::Normal)), + }, + NewDependency { + version_id: version_id, + crate_id: krate.id, + req: dep.version_req.to_string(), + kind: dep.kind.unwrap_or(Kind::Normal) as i32, + optional: dep.optional, + default_features: dep.default_features, + features: features, + target: dep.target.as_ref().map(|s| &**s), + }, + )) + }) .collect::, _>>()?; let (git_deps, new_dependencies): (Vec<_>, Vec<_>) = @@ -193,7 +189,17 @@ pub fn add_dependencies( } impl Queryable for Dependency { - type Row = (i32, i32, i32, String, bool, bool, Vec, Option, i32); + type Row = ( + i32, + i32, + i32, + String, + bool, + bool, + Vec, + Option, + i32, + ); fn build(row: Self::Row) -> Self { Dependency { diff --git a/src/dist.rs b/src/dist.rs index 1dff06dcb51..ba83b84d20f 100644 --- a/src/dist.rs +++ b/src/dist.rs @@ -42,14 +42,11 @@ impl Handler for Middleware { .map(|accept| accept.iter().any(|s| s.contains("html"))) .unwrap_or(false); if wants_html { - self.dist - .call( - &mut RequestProxy { - other: req, - path: Some("/index.html"), - method: None, - }, - ) + self.dist.call(&mut RequestProxy { + other: req, + path: Some("/index.html"), + method: None, + }) } else { self.handler.as_ref().unwrap().call(req) } diff --git a/src/git.rs b/src/git.rs index 04223c33ad1..12a6e15da64 100644 --- a/src/git.rs +++ b/src/git.rs @@ -51,24 +51,25 @@ pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> { let repo_path = repo.workdir().unwrap(); let dst = index_file(repo_path, &krate.name); - commit_and_push( - repo, || { - // Add the crate to its relevant file - fs::create_dir_all(dst.parent().unwrap())?; - let mut prev = String::new(); - if fs::metadata(&dst).is_ok() { - File::open(&dst) - .and_then(|mut f| f.read_to_string(&mut prev))?; - } - let s = json::encode(krate).unwrap(); - let new = prev + &s; - let mut f = File::create(&dst)?; - f.write_all(new.as_bytes())?; - f.write_all(b"\n")?; - - Ok((format!("Updating crate `{}#{}`", krate.name, krate.vers), dst.clone()),) + commit_and_push(repo, || { + // Add the crate to its relevant file + fs::create_dir_all(dst.parent().unwrap())?; + let mut prev = String::new(); + if fs::metadata(&dst).is_ok() { + File::open(&dst) + .and_then(|mut f| f.read_to_string(&mut prev))?; } - ) + let s = json::encode(krate).unwrap(); + let new = prev + &s; + let mut f = File::create(&dst)?; + f.write_all(new.as_bytes())?; + f.write_all(b"\n")?; + + Ok(( + format!("Updating crate `{}#{}`", krate.name, krate.vers), + dst.clone(), + )) + }) } pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> { @@ -76,41 +77,36 @@ pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> let repo_path = repo.workdir().unwrap(); let dst = index_file(repo_path, krate); - commit_and_push( - &repo, || { - let mut prev = String::new(); - File::open(&dst) - .and_then(|mut f| f.read_to_string(&mut prev))?; - let new = prev.lines() - .map( - |line| { - let mut git_crate = json::decode::(line).map_err(|_| { - internal(&format_args!("couldn't decode: `{}`", line)) - })?; - if git_crate.name != krate || git_crate.vers != version.to_string() { - return Ok(line.to_string()); - } - git_crate.yanked = Some(yanked); - Ok(json::encode(&git_crate).unwrap()) - }, - ) - .collect::>>(); - let new = new?.join("\n"); - let mut f = File::create(&dst)?; - f.write_all(new.as_bytes())?; - f.write_all(b"\n")?; - - Ok( - (format!( + commit_and_push(&repo, || { + let mut prev = String::new(); + File::open(&dst) + .and_then(|mut f| f.read_to_string(&mut prev))?; + let new = prev.lines() + .map(|line| { + let mut git_crate = json::decode::(line) + .map_err(|_| internal(&format_args!("couldn't decode: `{}`", line)))?; + if git_crate.name != krate || git_crate.vers != version.to_string() { + return Ok(line.to_string()); + } + git_crate.yanked = Some(yanked); + Ok(json::encode(&git_crate).unwrap()) + }) + .collect::>>(); + let new = new?.join("\n"); + let mut f = File::create(&dst)?; + f.write_all(new.as_bytes())?; + f.write_all(b"\n")?; + + Ok(( + format!( "{} crate `{}#{}`", if yanked { "Yanking" } else { "Unyanking" }, krate, version ), - dst.clone()), - ) - } - ) + dst.clone(), + )) + }) } fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> @@ -149,13 +145,11 @@ where let res = { let mut callbacks = git2::RemoteCallbacks::new(); callbacks.credentials(credentials); - callbacks.push_update_reference( - |refname, status| { - assert_eq!(refname, "refs/heads/master"); - ref_status = status.map(|s| s.to_string()); - Ok(()) - }, - ); + callbacks.push_update_reference(|refname, status| { + assert_eq!(refname, "refs/heads/master"); + ref_status = status.map(|s| s.to_string()); + Ok(()) + }); let mut opts = git2::PushOptions::new(); opts.remote_callbacks(callbacks); origin.push(&["refs/heads/master"], Some(&mut opts)) @@ -168,13 +162,12 @@ where let mut callbacks = git2::RemoteCallbacks::new(); callbacks.credentials(credentials); - origin - .update_tips( - Some(&mut callbacks), - true, - git2::AutotagOption::Unspecified, - None, - )?; + origin.update_tips( + Some(&mut callbacks), + true, + git2::AutotagOption::Unspecified, + None, + )?; // Ok, we need to update, so fetch and reset --hard origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?; diff --git a/src/http.rs b/src/http.rs index 4a638c0abfc..e6b26a0d0d3 100644 --- a/src/http.rs +++ b/src/http.rs @@ -32,12 +32,10 @@ pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec), cur { let mut transfer = handle.transfer(); transfer - .write_function( - |buf| { - data.extend_from_slice(buf); - Ok(buf.len()) - }, - ) + .write_function(|buf| { + data.extend_from_slice(buf); + Ok(buf.len()) + }) .unwrap(); transfer.perform()?; } @@ -49,30 +47,24 @@ pub fn parse_github_response(mut resp: Easy, data: &[u8]) -> Cargo match resp.response_code().unwrap() { 200 => {} // Ok! 403 => { - return Err( - human( - "It looks like you don't have permission \ - to query a necessary property from Github \ - to complete this request. \ - You may need to re-authenticate on \ - crates.io to grant permission to read \ - github org memberships. Just go to \ - https://crates.io/login", - ), - ); + return Err(human( + "It looks like you don't have permission \ + to query a necessary property from Github \ + to complete this request. \ + You may need to re-authenticate on \ + crates.io to grant permission to read \ + github org memberships. Just go to \ + https://crates.io/login", + )); } n => { let resp = String::from_utf8_lossy(data); - return Err( - internal( - &format_args!( + return Err(internal(&format_args!( "didn't get a 200 result from \ - github, got {} with: {}", + github, got {} with: {}", n, resp - ), - ), - ); + ))); } } diff --git a/src/keyword.rs b/src/keyword.rs index c34c207ffe2..9de46a05760 100644 --- a/src/keyword.rs +++ b/src/keyword.rs @@ -79,9 +79,9 @@ impl Keyword { return false; } name.chars().next().unwrap().is_alphanumeric() && - name.chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && - name.chars().all(|c| c.is_ascii()) + name.chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && + name.chars().all(|c| c.is_ascii()) } pub fn encodable(self) -> EncodableKeyword { @@ -100,28 +100,24 @@ impl Keyword { } pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> { - conn.transaction( - || { - let keywords = Keyword::find_or_create_all(conn, keywords)?; - diesel::delete(CrateKeyword::belonging_to(krate)) - .execute(conn)?; - let crate_keywords = keywords - .into_iter() - .map( - |kw| { - CrateKeyword { - crate_id: krate.id, - keyword_id: kw.id, - } - }, - ) - .collect::>(); - diesel::insert(&crate_keywords) - .into(crates_keywords::table) - .execute(conn)?; - Ok(()) - }, - ) + conn.transaction(|| { + let keywords = Keyword::find_or_create_all(conn, keywords)?; + diesel::delete(CrateKeyword::belonging_to(krate)) + .execute(conn)?; + let crate_keywords = keywords + .into_iter() + .map(|kw| { + CrateKeyword { + crate_id: krate.id, + keyword_id: kw.id, + } + }) + .collect::>(); + diesel::insert(&crate_keywords) + .into(crates_keywords::table) + .execute(conn)?; + Ok(()) + }) } } @@ -178,14 +174,10 @@ pub fn index(req: &mut Request) -> CargoResult { total: i64, } - Ok( - req.json( - &R { - keywords: kws, - meta: Meta { total: total }, - }, - ), - ) + Ok(req.json(&R { + keywords: kws, + meta: Meta { total: total }, + })) } /// Handles the `GET /keywords/:keyword_id` route. diff --git a/src/krate.rs b/src/krate.rs index b6b0765d1eb..0cb6ce800bf 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -56,31 +56,35 @@ pub struct Crate { /// We literally never want to select `textsearchable_index_col` /// so we provide this type and constant to pass to `.select` -type AllColumns = (crates::id, - crates::name, - crates::updated_at, - crates::created_at, - crates::downloads, - crates::description, - crates::homepage, - crates::documentation, - crates::readme, - crates::license, - crates::repository, - crates::max_upload_size); - -pub const ALL_COLUMNS: AllColumns = (crates::id, - crates::name, - crates::updated_at, - crates::created_at, - crates::downloads, - crates::description, - crates::homepage, - crates::documentation, - crates::readme, - crates::license, - crates::repository, - crates::max_upload_size); +type AllColumns = ( + crates::id, + crates::name, + crates::updated_at, + crates::created_at, + crates::downloads, + crates::description, + crates::homepage, + crates::documentation, + crates::readme, + crates::license, + crates::repository, + crates::max_upload_size, +); + +pub const ALL_COLUMNS: AllColumns = ( + crates::id, + crates::name, + crates::updated_at, + crates::created_at, + crates::downloads, + crates::description, + crates::homepage, + crates::documentation, + crates::readme, + crates::license, + crates::repository, + crates::max_upload_size, +); pub const MAX_NAME_LENGTH: usize = 64; @@ -141,24 +145,22 @@ impl<'a> NewCrate<'a> { self.validate(license_file)?; self.ensure_name_not_reserved(conn)?; - conn.transaction( - || { - // To avoid race conditions, we try to insert - // first so we know whether to add an owner - if let Some(krate) = self.save_new_crate(conn, uploader)? { - return Ok(krate); - } + conn.transaction(|| { + // To avoid race conditions, we try to insert + // first so we know whether to add an owner + if let Some(krate) = self.save_new_crate(conn, uploader)? { + return Ok(krate); + } - let target = crates::table.filter(canon_crate_name(crates::name).eq( - canon_crate_name(self.name), - )); - update(target) - .set(&self) - .returning(ALL_COLUMNS) - .get_result(conn) - .map_err(Into::into) - }, - ) + let target = crates::table.filter( + canon_crate_name(crates::name).eq(canon_crate_name(self.name)), + ); + update(target) + .set(&self) + .returning(ALL_COLUMNS) + .get_result(conn) + .map_err(Into::into) + }) } fn validate(&mut self, license_file: Option<&'a str>) -> CargoResult<()> { @@ -167,35 +169,28 @@ impl<'a> NewCrate<'a> { Some(s) => s, None => return Ok(()), }; - let url = Url::parse(url).map_err(|_| { - human(&format_args!("`{}` is not a valid url: `{}`", field, url)) - })?; + let url = Url::parse(url) + .map_err(|_| { + human(&format_args!("`{}` is not a valid url: `{}`", field, url)) + })?; match &url.scheme()[..] { "http" | "https" => {} s => { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "`{}` has an invalid url \ - scheme: `{}`", + scheme: `{}`", field, s - ), - ), - ) + ))) } } if url.cannot_be_a_base() { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "`{}` must have relative scheme \ - data: {}", + data: {}", field, url - ), - ), - ); + ))); } Ok(()) } @@ -210,16 +205,14 @@ impl<'a> NewCrate<'a> { fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { if let Some(license) = self.license { for part in license.split('/') { - license_exprs::validate_license_expr(part) - .map_err( - |e| { - human( - &format_args!("{}; see http://opensource.org/licenses \ - for options, and http://spdx.org/licenses/ \ - for their identifiers", e), - ) - }, - )?; + license_exprs::validate_license_expr(part).map_err(|e| { + human(&format_args!( + "{}; see http://opensource.org/licenses \ + for options, and http://spdx.org/licenses/ \ + for their identifiers", + e + )) + })?; } } else if license_file.is_some() { // If no license is given, but a license file is given, flag this @@ -235,15 +228,9 @@ impl<'a> NewCrate<'a> { use diesel::select; use diesel::expression::dsl::exists; - let reserved_name = select( - exists( - reserved_crate_names.filter( - canon_crate_name(name) - .eq(canon_crate_name(self.name)), - ), - ), - ) - .get_result::(conn)?; + let reserved_name = select(exists( + reserved_crate_names.filter(canon_crate_name(name).eq(canon_crate_name(self.name))), + )).get_result::(conn)?; if reserved_name { Err(human("cannot upload a crate with a reserved name")) } else { @@ -255,27 +242,25 @@ impl<'a> NewCrate<'a> { use schema::crates::dsl::*; use diesel::insert; - conn.transaction( - || { - let maybe_inserted = insert(&self.on_conflict_do_nothing()) - .into(crates) - .returning(ALL_COLUMNS) - .get_result::(conn) - .optional()?; - - if let Some(ref krate) = maybe_inserted { - let owner = CrateOwner { - crate_id: krate.id, - owner_id: user_id, - created_by: user_id, - owner_kind: OwnerKind::User as i32, - }; - insert(&owner).into(crate_owners::table).execute(conn)?; - } + conn.transaction(|| { + let maybe_inserted = insert(&self.on_conflict_do_nothing()) + .into(crates) + .returning(ALL_COLUMNS) + .get_result::(conn) + .optional()?; + + if let Some(ref krate) = maybe_inserted { + let owner = CrateOwner { + crate_id: krate.id, + owner_id: user_id, + created_by: user_id, + owner_kind: OwnerKind::User as i32, + }; + insert(&owner).into(crate_owners::table).execute(conn)?; + } - Ok(maybe_inserted) - }, - ) + Ok(maybe_inserted) + }) } } @@ -292,10 +277,10 @@ impl Crate { pub fn find_by_name(conn: &GenericConnection, name: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM crates \ + "SELECT * FROM crates \ WHERE canon_crate_name(name) = canon_crate_name($1) LIMIT 1", - )?; + )?; let rows = stmt.query(&[&name])?; let row = rows.iter().next(); let row = row.chain_error(|| NotFound)?; @@ -345,7 +330,7 @@ impl Crate { // TODO: like with users, this is sadly racy let stmt = conn.prepare( - "UPDATE crates + "UPDATE crates SET documentation = $1, homepage = $2, description = $3, @@ -355,64 +340,62 @@ impl Crate { WHERE canon_crate_name(name) = canon_crate_name($7) RETURNING *", - )?; + )?; let rows = stmt.query( - &[ - &documentation, - &homepage, - &description, - &readme, - &license, - &repository, - &name, - ], - )?; + &[ + &documentation, + &homepage, + &description, + &readme, + &license, + &repository, + &name, + ], + )?; if let Some(row) = rows.iter().next() { return Ok(Model::from_row(&row)); } let stmt = conn.prepare( - "SELECT 1 FROM reserved_crate_names + "SELECT 1 FROM reserved_crate_names WHERE canon_crate_name(name) = canon_crate_name($1)", - )?; + )?; let rows = stmt.query(&[&name])?; if !rows.is_empty() { return Err(human("cannot upload a crate with a reserved name")); } let stmt = conn.prepare( - "INSERT INTO crates + "INSERT INTO crates (name, description, homepage, documentation, readme, repository, license, max_upload_size) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *", - )?; + )?; let rows = stmt.query( - &[ - &name, - &description, - &homepage, - &documentation, - &readme, - &repository, - &license, - &max_upload_size, - ], - )?; - let ret: Crate = Model::from_row( - &rows.iter() - .next() - .chain_error(|| internal("no crate returned"))?, - ); + &[ + &name, + &description, + &homepage, + &documentation, + &readme, + &repository, + &license, + &max_upload_size, + ], + )?; + let ret: Crate = Model::from_row(&rows.iter() + .next() + .chain_error(|| internal("no crate returned"))?); conn.execute( - "INSERT INTO crate_owners + "INSERT INTO crate_owners (crate_id, owner_id, created_by, owner_kind) VALUES ($1, $2, $2, $3)", - &[&ret.id, &user_id, &(OwnerKind::User as i32)], - )?; + &[&ret.id, &user_id, &(OwnerKind::User as i32)], + )?; return Ok(ret); fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { @@ -420,35 +403,28 @@ impl Crate { Some(s) => s, None => return Ok(()), }; - let url = Url::parse(url).map_err(|_| { - human(&format_args!("`{}` is not a valid url: `{}`", field, url)) - })?; + let url = Url::parse(url) + .map_err(|_| { + human(&format_args!("`{}` is not a valid url: `{}`", field, url)) + })?; match &url.scheme()[..] { "http" | "https" => {} s => { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "`{}` has an invalid url \ - scheme: `{}`", + scheme: `{}`", field, s - ), - ), - ) + ))) } } if url.cannot_be_a_base() { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "`{}` must have relative scheme \ - data: {}", + data: {}", field, url - ), - ), - ); + ))); } Ok(()) } @@ -460,18 +436,14 @@ impl Crate { .map(license_exprs::validate_license_expr) .collect::, _>>() .map(|_| ()) - .map_err( - |e| { - human( - &format_args!( + .map_err(|e| { + human(&format_args!( "{}; see http://opensource.org/licenses \ - for options, and http://spdx.org/licenses/ \ - for their identifiers", + for options, and http://spdx.org/licenses/ \ + for their identifiers", e - ), - ) - }, - ) + )) + }) } } @@ -486,9 +458,9 @@ impl Crate { return false; } name.chars().next().unwrap().is_alphabetic() && - name.chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && - name.chars().all(|c| c.is_ascii()) + name.chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && + name.chars().all(|c| c.is_ascii()) } pub fn valid_feature_name(name: &str) -> bool { @@ -582,24 +554,22 @@ impl Crate { pub fn max_version_old(&self, conn: &GenericConnection) -> CargoResult { let stmt = conn.prepare( - "SELECT num FROM versions WHERE crate_id = $1 + "SELECT num FROM versions WHERE crate_id = $1 AND yanked = 'f'", - )?; + )?; let rows = stmt.query(&[&self.id])?; - Ok( - Version::max( - rows.iter() - .map(|r| r.get::<_, String>("num")) - .map(|s| semver::Version::parse(&s).unwrap()), - ), - ) + Ok(Version::max( + rows.iter() + .map(|r| r.get::<_, String>("num")) + .map(|s| semver::Version::parse(&s).unwrap()), + )) } pub fn versions(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT * FROM versions \ - WHERE crate_id = $1", - )?; + "SELECT * FROM versions \ + WHERE crate_id = $1", + )?; let rows = stmt.query(&[&self.id])?; let mut ret = rows.iter() .map(|r| Model::from_row(&r)) @@ -630,36 +600,28 @@ impl Crate { pub fn owners_old(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT * FROM users + "SELECT * FROM users INNER JOIN crate_owners ON crate_owners.owner_id = users.id WHERE crate_owners.crate_id = $1 AND crate_owners.deleted = FALSE AND crate_owners.owner_kind = $2", - )?; + )?; let user_rows = stmt.query(&[&self.id, &(OwnerKind::User as i32)])?; let stmt = conn.prepare( - "SELECT * FROM teams + "SELECT * FROM teams INNER JOIN crate_owners ON crate_owners.owner_id = teams.id WHERE crate_owners.crate_id = $1 AND crate_owners.deleted = FALSE AND crate_owners.owner_kind = $2", - )?; + )?; let team_rows = stmt.query(&[&self.id, &(OwnerKind::Team as i32)])?; let mut owners = vec![]; - owners.extend( - user_rows - .iter() - .map(|r| Owner::User(Model::from_row(&r))), - ); - owners.extend( - team_rows - .iter() - .map(|r| Owner::Team(Model::from_row(&r))), - ); + owners.extend(user_rows.iter().map(|r| Owner::User(Model::from_row(&r)))); + owners.extend(team_rows.iter().map(|r| Owner::Team(Model::from_row(&r)))); Ok(owners) } @@ -676,15 +638,11 @@ impl Crate { if team.contains_user(app, req_user)? { Owner::Team(team) } else { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "only members of {} can add it as \ - an owner", + an owner", login - ), - ), - ); + ))); } } Err(err) => { @@ -702,14 +660,11 @@ impl Crate { created_by: req_user.id, owner_kind: owner.kind() as i32, }; - diesel::insert( - &crate_owner.on_conflict( - crate_owners::table.primary_key(), - do_update().set(crate_owners::deleted.eq(false)), - ), - ) - .into(crate_owners::table) - .execute(conn)?; + diesel::insert(&crate_owner.on_conflict( + crate_owners::table.primary_key(), + do_update().set(crate_owners::deleted.eq(false)), + )).into(crate_owners::table) + .execute(conn)?; Ok(()) } @@ -720,9 +675,10 @@ impl Crate { _req_user: &User, login: &str, ) -> CargoResult<()> { - let owner = - Owner::find_by_login(conn, login) - .map_err(|_| human(&format_args!("could not find owner with login `{}`", login)),)?; + let owner = Owner::find_by_login(conn, login) + .map_err(|_| { + human(&format_args!("could not find owner with login `{}`", login)) + })?; let target = crate_owners::table.find((self.id(), owner.id(), owner.kind() as i32)); diesel::update(target) .set(crate_owners::deleted.eq(true)) @@ -738,30 +694,32 @@ impl Crate { authors: &[String], ) -> CargoResult { if Version::find_by_num(conn, self.id, ver)?.is_some() { - return Err(human(&format_args!("crate version `{}` is already uploaded", ver)),); + return Err(human( + &format_args!("crate version `{}` is already uploaded", ver), + )); } Version::insert(conn, self.id, ver, features, authors) } pub fn keywords(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT keywords.* FROM keywords + "SELECT keywords.* FROM keywords LEFT JOIN crates_keywords ON keywords.id = crates_keywords.keyword_id WHERE crates_keywords.crate_id = $1", - )?; + )?; let rows = stmt.query(&[&self.id])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) } pub fn categories(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT categories.* FROM categories \ - LEFT JOIN crates_categories \ - ON categories.id = \ - crates_categories.category_id \ - WHERE crates_categories.crate_id = $1", - )?; + "SELECT categories.* FROM categories \ + LEFT JOIN crates_categories \ + ON categories.id = \ + crates_categories.category_id \ + WHERE crates_categories.crate_id = $1", + )?; let rows = stmt.query(&[&self.id])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) } @@ -827,7 +785,11 @@ pub fn index(req: &mut Request) -> CargoResult { let sort = params.get("sort").map(|s| &**s).unwrap_or("alpha"); let mut query = crates::table - .select((ALL_COLUMNS, sql::("COUNT(*) OVER ()"), sql::("false")),) + .select(( + ALL_COLUMNS, + sql::("COUNT(*) OVER ()"), + sql::("false"), + )) .limit(limit) .offset(offset) .into_boxed(); @@ -868,14 +830,7 @@ pub fn index(req: &mut Request) -> CargoResult { .filter( categories::slug .eq(cat) - .or( - categories::slug.like( - format!( - "{}::%", - cat - ), - ), - ), + .or(categories::slug.like(format!("{}::%", cat))), ), ), ); @@ -903,13 +858,12 @@ pub fn index(req: &mut Request) -> CargoResult { query = query.filter(canon_crate_name(crates::name).like(pattern)); } else if let Some(user_id) = params.get("user_id").and_then(|s| s.parse::().ok()) { query = query.filter( - crates::id - .eq_any( - crate_owners::table - .select(crate_owners::crate_id) - .filter(crate_owners::owner_id.eq(user_id)) - .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)), - ), + crates::id.eq_any( + crate_owners::table + .select(crate_owners::crate_id) + .filter(crate_owners::owner_id.eq(user_id)) + .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)), + ), ); } else if params.get("following").is_some() { query = query.filter( @@ -937,16 +891,16 @@ pub fn index(req: &mut Request) -> CargoResult { let crates = versions .zip(crates) .zip(perfect_matches) - .map( - |((max_version, krate), perfect_match)| { - // FIXME: If we add crate_id to the Badge enum we can eliminate - // this N+1 - let badges = badges::table - .filter(badges::crate_id.eq(krate.id)) - .load::(&*conn)?; - Ok(krate.minimal_encodable(max_version, Some(badges), perfect_match),) - }, - ) + .map(|((max_version, krate), perfect_match)| { + // FIXME: If we add crate_id to the Badge enum we can eliminate + // this N+1 + let badges = badges::table + .filter(badges::crate_id.eq(krate.id)) + .load::(&*conn)?; + Ok( + krate.minimal_encodable(max_version, Some(badges), perfect_match), + ) + }) .collect::>()?; #[derive(RustcEncodable)] @@ -959,14 +913,10 @@ pub fn index(req: &mut Request) -> CargoResult { total: i64, } - Ok( - req.json( - &R { - crates: crates, - meta: Meta { total: total }, - }, - ), - ) + Ok(req.json(&R { + crates: crates, + meta: Meta { total: total }, + })) } /// Handles the `GET /summary` route. @@ -987,7 +937,9 @@ pub fn summary(req: &mut Request) -> CargoResult { .into_iter() .map(|versions| Version::max(versions.into_iter().map(|v| v.num))) .zip(krates) - .map(|(max_version, krate)| Ok(krate.minimal_encodable(max_version, None, false)),) + .map(|(max_version, krate)| { + Ok(krate.minimal_encodable(max_version, None, false)) + }) .collect() }; @@ -1031,19 +983,15 @@ pub fn summary(req: &mut Request) -> CargoResult { popular_keywords: Vec, popular_categories: Vec, } - Ok( - req.json( - &R { - num_downloads: num_downloads, - num_crates: num_crates, - new_crates: encode_crates(new_crates)?, - most_downloaded: encode_crates(most_downloaded)?, - just_updated: encode_crates(just_updated)?, - popular_keywords: popular_keywords, - popular_categories: popular_categories, - }, - ), - ) + Ok(req.json(&R { + num_downloads: num_downloads, + num_crates: num_crates, + new_crates: encode_crates(new_crates)?, + most_downloaded: encode_crates(most_downloaded)?, + just_updated: encode_crates(just_updated)?, + popular_keywords: popular_keywords, + popular_categories: popular_categories, + })) } /// Handles the `GET /crates/:crate_id` route. @@ -1078,11 +1026,8 @@ pub fn show(req: &mut Request) -> CargoResult { categories: Vec, } Ok( - req.json( - &R { - krate: krate - .clone() - .encodable( + req.json(&R { + krate: krate.clone().encodable( max_version, Some(ids), Some(&kws), @@ -1090,14 +1035,13 @@ pub fn show(req: &mut Request) -> CargoResult { Some(badges), false, ), - versions: versions - .into_iter() - .map(|v| v.encodable(&krate.name)) - .collect(), - keywords: kws.into_iter().map(|k| k.encodable()).collect(), - categories: cats.into_iter().map(|k| k.encodable()).collect(), - }, - ), + versions: versions + .into_iter() + .map(|v| v.encodable(&krate.name)) + .collect(), + keywords: kws.into_iter().map(|k| k.encodable()).collect(), + categories: cats.into_iter().map(|k| k.encodable()).collect(), + }), ) } @@ -1111,7 +1055,12 @@ pub fn new(req: &mut Request) -> CargoResult { let features = new_crate .features .iter() - .map(|(k, v)| (k[..].to_string(), v.iter().map(|v| v[..].to_string()).collect()),) + .map(|(k, v)| { + ( + k[..].to_string(), + v.iter().map(|v| v[..].to_string()).collect(), + ) + }) .collect::>>(); let keywords = new_crate .keywords @@ -1119,132 +1068,116 @@ pub fn new(req: &mut Request) -> CargoResult { .map(|kws| kws.iter().map(|kw| &**kw).collect()) .unwrap_or_else(Vec::new); - let categories = new_crate - .categories - .as_ref() - .map(|s| &s[..]) - .unwrap_or(&[]); + let categories = new_crate.categories.as_ref().map(|s| &s[..]).unwrap_or(&[]); let categories: Vec<_> = categories.iter().map(|k| &**k).collect(); let conn = req.db_conn()?; - conn.transaction( - || { - // Persist the new crate, if it doesn't already exist - let persist = NewCrate { - name: name, - description: new_crate.description.as_ref().map(|s| &**s), - homepage: new_crate.homepage.as_ref().map(|s| &**s), - documentation: new_crate.documentation.as_ref().map(|s| &**s), - readme: new_crate.readme.as_ref().map(|s| &**s), - repository: new_crate.repository.as_ref().map(|s| &**s), - license: new_crate.license.as_ref().map(|s| &**s), - max_upload_size: None, - }; + conn.transaction(|| { + // Persist the new crate, if it doesn't already exist + let persist = NewCrate { + name: name, + description: new_crate.description.as_ref().map(|s| &**s), + homepage: new_crate.homepage.as_ref().map(|s| &**s), + documentation: new_crate.documentation.as_ref().map(|s| &**s), + readme: new_crate.readme.as_ref().map(|s| &**s), + repository: new_crate.repository.as_ref().map(|s| &**s), + license: new_crate.license.as_ref().map(|s| &**s), + max_upload_size: None, + }; - let license_file = new_crate.license_file.as_ref().map(|s| &**s); - let krate = persist.create_or_update(&conn, license_file, user.id)?; + let license_file = new_crate.license_file.as_ref().map(|s| &**s); + let krate = persist.create_or_update(&conn, license_file, user.id)?; - let owners = krate.owners(&conn)?; - if rights(req.app(), &owners, &user)? < Rights::Publish { - return Err( - human( - "crate name has already been claimed by \ - another user", - ), - ); - } + let owners = krate.owners(&conn)?; + if rights(req.app(), &owners, &user)? < Rights::Publish { + return Err(human( + "crate name has already been claimed by \ + another user", + )); + } - if krate.name != name { - return Err(human(&format_args!("crate was previously named `{}`", krate.name)),); - } + if krate.name != name { + return Err(human( + &format_args!("crate was previously named `{}`", krate.name), + )); + } - let length = req.content_length() - .chain_error(|| human("missing header: Content-Length"))?; - let max = krate - .max_upload_size - .map(|m| m as u64) - .unwrap_or(app.config.max_upload_size); - if length > max { - return Err(human(&format_args!("max upload size is: {}", max))); - } + let length = req.content_length() + .chain_error(|| human("missing header: Content-Length"))?; + let max = krate + .max_upload_size + .map(|m| m as u64) + .unwrap_or(app.config.max_upload_size); + if length > max { + return Err(human(&format_args!("max upload size is: {}", max))); + } - // This is only redundant for now. Eventually the duplication will be removed. - let license = new_crate.license.clone(); - - // Persist the new version of this crate - let version = NewVersion::new(krate.id, vers, &features, license, license_file)? - .save(&conn, &new_crate.authors)?; - - // Link this new version to all dependencies - let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?; - - // Update all keywords for this crate - Keyword::update_crate(&conn, &krate, &keywords)?; - - // Update all categories for this crate, collecting any invalid categories - // in order to be able to warn about them - let ignored_invalid_categories = Category::update_crate(&conn, &krate, &categories)?; - - // Update all badges for this crate, collecting any invalid badges in - // order to be able to warn about them - let ignored_invalid_badges = - Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?; - let max_version = krate.max_version(&conn)?; - - // Upload the crate, return way to delete the crate from the server - // If the git commands fail below, we shouldn't keep the crate on the - // server. - let (cksum, mut bomb) = app.config.uploader.upload(req, &krate, max, vers)?; - - // Register this crate in our local git repo. - let git_crate = git::Crate { - name: name.to_string(), - vers: vers.to_string(), - cksum: cksum.to_hex(), - features: features, - deps: git_deps, - yanked: Some(false), - }; - git::add_crate(&**req.app(), &git_crate) - .chain_error( - || { - internal( - &format_args!( + // This is only redundant for now. Eventually the duplication will be removed. + let license = new_crate.license.clone(); + + // Persist the new version of this crate + let version = NewVersion::new(krate.id, vers, &features, license, license_file)? + .save(&conn, &new_crate.authors)?; + + // Link this new version to all dependencies + let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?; + + // Update all keywords for this crate + Keyword::update_crate(&conn, &krate, &keywords)?; + + // Update all categories for this crate, collecting any invalid categories + // in order to be able to warn about them + let ignored_invalid_categories = Category::update_crate(&conn, &krate, &categories)?; + + // Update all badges for this crate, collecting any invalid badges in + // order to be able to warn about them + let ignored_invalid_badges = Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?; + let max_version = krate.max_version(&conn)?; + + // Upload the crate, return way to delete the crate from the server + // If the git commands fail below, we shouldn't keep the crate on the + // server. + let (cksum, mut bomb) = app.config.uploader.upload(req, &krate, max, vers)?; + + // Register this crate in our local git repo. + let git_crate = git::Crate { + name: name.to_string(), + vers: vers.to_string(), + cksum: cksum.to_hex(), + features: features, + deps: git_deps, + yanked: Some(false), + }; + git::add_crate(&**req.app(), &git_crate).chain_error(|| { + internal(&format_args!( "could not add crate `{}` to the git repo", name - ), - ) - }, - )?; + )) + })?; - // Now that we've come this far, we're committed! - bomb.path = None; + // Now that we've come this far, we're committed! + bomb.path = None; - #[derive(RustcEncodable)] - struct Warnings<'a> { - invalid_categories: Vec<&'a str>, - invalid_badges: Vec<&'a str>, - } - let warnings = Warnings { - invalid_categories: ignored_invalid_categories, - invalid_badges: ignored_invalid_badges, - }; + #[derive(RustcEncodable)] + struct Warnings<'a> { + invalid_categories: Vec<&'a str>, + invalid_badges: Vec<&'a str>, + } + let warnings = Warnings { + invalid_categories: ignored_invalid_categories, + invalid_badges: ignored_invalid_badges, + }; - #[derive(RustcEncodable)] - struct R<'a> { - krate: EncodableCrate, - warnings: Warnings<'a>, - } - Ok( - req.json( - &R { - krate: krate.minimal_encodable(max_version, None, false), - warnings: warnings, - }, - ), - ) - }, - ) + #[derive(RustcEncodable)] + struct R<'a> { + krate: EncodableCrate, + warnings: Warnings<'a>, + } + Ok(req.json(&R { + krate: krate.minimal_encodable(max_version, None, false), + warnings: warnings, + })) + }) } fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> { @@ -1258,9 +1191,8 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> read_fill(req.body(), &mut json)?; let json = String::from_utf8(json) .map_err(|_| human("json body was not valid utf-8"))?; - let new: upload::NewCrate = - json::decode(&json) - .map_err(|e| human(&format_args!("invalid upload request: {:?}", e)))?; + let new: upload::NewCrate = json::decode(&json) + .map_err(|e| human(&format_args!("invalid upload request: {:?}", e)))?; // Make sure required fields are provided fn empty(s: Option<&String>) -> bool { @@ -1278,16 +1210,12 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> missing.push("authors"); } if !missing.is_empty() { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "missing or empty metadata fields: {}. Please \ - see http://doc.crates.io/manifest.html#package-metadata for \ - how to upload metadata", + see http://doc.crates.io/manifest.html#package-metadata for \ + how to upload metadata", missing.join(", ") - ), - ), - ); + ))); } let user = req.user()?; @@ -1332,7 +1260,9 @@ fn increment_download_counts(req: &Request, crate_name: &str, version: &str) -> let conn = req.db_conn()?; let version_id = versions .select(id) - .filter(crate_id.eq_any(Crate::by_name(crate_name).select(crates::id)),) + .filter( + crate_id.eq_any(Crate::by_name(crate_name).select(crates::id)), + ) .filter(num.eq(version)) .first(&*conn)?; @@ -1363,7 +1293,10 @@ pub fn downloads(req: &mut Request) -> CargoResult { let sum_downloads = sql::("SUM(version_downloads.downloads)"); let extra = VersionDownload::belonging_to(rest) - .select((to_char(version_downloads::date, "YYYY-MM-DD"), sum_downloads),) + .select(( + to_char(version_downloads::date, "YYYY-MM-DD"), + sum_downloads, + )) .filter(version_downloads::date.gt(date(now - 90.days()))) .group_by(version_downloads::date) .order(version_downloads::date.asc()) @@ -1384,14 +1317,10 @@ pub fn downloads(req: &mut Request) -> CargoResult { extra_downloads: Vec, } let meta = Meta { extra_downloads: extra }; - Ok( - req.json( - &R { - version_downloads: downloads, - meta: meta, - }, - ), - ) + Ok(req.json(&R { + version_downloads: downloads, + meta: meta, + })) } #[derive(Insertable, Queryable, Identifiable, Associations)] @@ -1407,15 +1336,11 @@ fn follow_target(req: &mut Request) -> CargoResult { let user = req.user()?; let conn = req.db_conn()?; let crate_name = &req.params()["crate_id"]; - let crate_id = Crate::by_name(crate_name) - .select(crates::id) - .first(&*conn)?; - Ok( - Follow { - user_id: user.id, - crate_id: crate_id, - }, - ) + let crate_id = Crate::by_name(crate_name).select(crates::id).first(&*conn)?; + Ok(Follow { + user_id: user.id, + crate_id: crate_id, + }) } /// Handles the `PUT /crates/:crate_id/follow` route. @@ -1585,14 +1510,10 @@ pub fn reverse_dependencies(req: &mut Request) -> CargoResult { struct Meta { total: i64, } - Ok( - req.json( - &R { - dependencies: rev_deps, - meta: Meta { total: total }, - }, - ), - ) + Ok(req.json(&R { + dependencies: rev_deps, + meta: Meta { total: total }, + })) } use diesel::types::{Text, Date}; diff --git a/src/lib.rs b/src/lib.rs index 013592c0c02..db1d485e6c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -183,7 +183,10 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { m.around(util::Head::default()); m.add(conduit_conditional_get::ConditionalGet); m.add(conduit_cookie::Middleware::new(app.session_key.as_bytes())); - m.add(conduit_cookie::SessionMiddleware::new("cargo_session", env == Env::Production),); + m.add(conduit_cookie::SessionMiddleware::new( + "cargo_session", + env == Env::Production, + )); m.add(app::AppMiddleware::new(app)); if env != Env::Test { m.add(db::TransactionMiddleware); @@ -216,15 +219,13 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { _req: &mut conduit::Request, res: Result>, ) -> Result> { - res.map( - |res| { - println!(" <- {:?}", res.status); - for (k, v) in &res.headers { - println!(" <- {} {:?}", k, v); - } - res - }, - ) + res.map(|res| { + println!(" <- {:?}", res.status); + for (k, v) in &res.headers { + println!(" <- {} {:?}", k, v); + } + res + }) } } } diff --git a/src/owner.rs b/src/owner.rs index 8602e374211..19fc6c59b62 100644 --- a/src/owner.rs +++ b/src/owner.rs @@ -87,25 +87,19 @@ impl Team { "github" => { // Ok to unwrap since we know one ":" is contained let org = chunks.next().unwrap(); - let team = chunks - .next() - .ok_or_else( - || { - human( - "missing github team argument; \ - format is github:org:team", - ) - }, - )?; + let team = chunks.next().ok_or_else(|| { + human( + "missing github team argument; \ + format is github:org:team", + ) + })?; Team::create_github_team(app, conn, login, org, team, req_user) } _ => { - Err( - human( - "unknown organization handler, \ - only 'github:org:team' is supported", - ), - ) + Err(human( + "unknown organization handler, \ + only 'github:org:team' is supported", + )) } } } @@ -133,15 +127,11 @@ impl Team { } if let Some(c) = org_name.chars().find(whitelist) { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "organization cannot contain special \ - characters like {}", + characters like {}", c - ), - ), - ); + ))); } #[derive(RustcDecodable)] @@ -161,17 +151,13 @@ impl Team { let team = teams .into_iter() .find(|team| team.slug == team_name) - .ok_or_else( - || { - human( - &format_args!( + .ok_or_else(|| { + human(&format_args!( "could not find the github team {}/{}", org_name, team_name - ), - ) - }, - )?; + )) + })?; if !team_with_gh_id_contains_user(app, team.id, req_user)? { return Err(human("only members of a team can add it as an owner")); @@ -213,8 +199,9 @@ impl Team { avatar: avatar, }; - diesel::insert(&new_team.on_conflict(teams::github_id, do_update().set(&new_team)),) - .into(teams::table) + diesel::insert( + &new_team.on_conflict(teams::github_id, do_update().set(&new_team)), + ).into(teams::table) .get_result(conn) .map_err(Into::into) } @@ -279,13 +266,17 @@ impl Owner { .filter(teams::login.eq(name)) .first(conn) .map(Owner::Team) - .map_err(|_| human(&format_args!("could not find team with name {}", name)),) + .map_err(|_| { + human(&format_args!("could not find team with name {}", name)) + }) } else { users::table .filter(users::gh_login.eq(name)) .first(conn) .map(Owner::User) - .map_err(|_| human(&format_args!("could not find user with login `{}`", name)),) + .map_err(|_| { + human(&format_args!("could not find user with login `{}`", name)) + }) } } @@ -313,13 +304,13 @@ impl Owner { pub fn encodable(self) -> EncodableOwner { match self { Owner::User(User { - id, - email, - name, - gh_login, - gh_avatar, - .. - }) => { + id, + email, + name, + gh_login, + gh_avatar, + .. + }) => { let url = format!("https://github.com/{}", gh_login); EncodableOwner { id: id, @@ -332,12 +323,12 @@ impl Owner { } } Owner::Team(Team { - id, - name, - login, - avatar, - .. - }) => { + id, + name, + login, + avatar, + .. + }) => { let url = { let mut parts = login.split(':'); parts.next(); // discard github diff --git a/src/tests/all.rs b/src/tests/all.rs index 66906045bd0..fca62dd3ab4 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -86,7 +86,13 @@ mod team; mod user; mod version; -fn app() -> (record::Bomb, Arc, conduit_middleware::MiddlewareBuilder) { +fn app() + -> ( + record::Bomb, + Arc, + conduit_middleware::MiddlewareBuilder, +) +{ dotenv::dotenv().ok(); git::init(); @@ -162,9 +168,9 @@ fn json(r: &mut conduit::Response) -> T { let j = fixup(j); let s = j.to_string(); return match json::decode(&s) { - Ok(t) => t, - Err(e) => panic!("failed to decode: {:?}\n{}", e, s), - }; + Ok(t) => t, + Err(e) => panic!("failed to decode: {:?}\n{}", e, s), + }; fn fixup(json: Json) -> Json { @@ -173,12 +179,10 @@ fn json(r: &mut conduit::Response) -> T { Json::Object( object .into_iter() - .map( - |(k, v)| { - let k = if k == "crate" { "krate".to_string() } else { k }; - (k, fixup(v)) - }, - ) + .map(|(k, v)| { + let k = if k == "crate" { "krate".to_string() } else { k }; + (k, fixup(v)) + }) .collect(), ) } @@ -225,11 +229,9 @@ struct VersionBuilder<'a> { impl<'a> VersionBuilder<'a> { fn new(version: &str) -> VersionBuilder { - let version = semver::Version::parse(version).unwrap_or_else( - |e| { - panic!("The version {} is not valid: {}", version, e); - }, - ); + let version = semver::Version::parse(version).unwrap_or_else(|e| { + panic!("The version {} is not valid: {}", version, e); + }); VersionBuilder { version: version, @@ -257,7 +259,7 @@ impl<'a> VersionBuilder<'a> { license, self.license_file, )? - .save(connection, &[]) + .save(connection, &[]) } } @@ -353,12 +355,9 @@ impl<'a> CrateBuilder<'a> { fn expect_build(self, connection: &PgConnection) -> Crate { let name = self.krate.name; - self.build(connection) - .unwrap_or_else( - |e| { - panic!("Unable to create crate {}: {:?}", name, e); - }, - ) + self.build(connection).unwrap_or_else(|e| { + panic!("Unable to create crate {}: {:?}", name, e); + }) } } @@ -393,8 +392,7 @@ fn mock_user(req: &mut Request, u: User) -> User { u.name.as_ref().map(|s| &s[..]), u.gh_avatar.as_ref().map(|s| &s[..]), &u.gh_access_token, - ) - .unwrap(); + ).unwrap(); sign_in_as(req, &u); return u; } @@ -427,8 +425,7 @@ fn mock_crate_vers(req: &mut Request, krate: Crate, v: &semver::Version) -> (Cra &krate.license, &None, krate.max_upload_size, - ) - .unwrap(); + ).unwrap(); let v = krate.add_version(req.tx().unwrap(), v, &HashMap::new(), &[]); (krate, v.unwrap()) } @@ -466,8 +463,7 @@ fn mock_dep( true, &[], &target.map(|s| s.to_string()), - ) - .unwrap() + ).unwrap() } fn new_category<'a>(category: &'a str, slug: &'a str) -> NewCategory<'a> { @@ -481,12 +477,11 @@ fn new_category<'a>(category: &'a str, slug: &'a str) -> NewCategory<'a> { fn mock_category(req: &mut Request, name: &str, slug: &str) -> Category { let conn = req.tx().unwrap(); let stmt = conn.prepare( - " \ - INSERT INTO categories (category, slug) \ - VALUES ($1, $2) \ - RETURNING *", - ) - .unwrap(); + " \ + INSERT INTO categories (category, slug) \ + VALUES ($1, $2) \ + RETURNING *", + ).unwrap(); let rows = stmt.query(&[&name, &slug]).unwrap(); Model::from_row(&rows.iter().next().unwrap()) } @@ -517,7 +512,14 @@ fn new_req_full( deps: Vec, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body(krate, version, deps, Vec::new(), Vec::new(), HashMap::new()),); + req.with_body(&new_req_body( + krate, + version, + deps, + Vec::new(), + Vec::new(), + HashMap::new(), + )); return req; } @@ -528,7 +530,14 @@ fn new_req_with_keywords( kws: Vec, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body(krate, version, Vec::new(), kws, Vec::new(), HashMap::new()),); + req.with_body(&new_req_body( + krate, + version, + Vec::new(), + kws, + Vec::new(), + HashMap::new(), + )); return req; } @@ -539,7 +548,14 @@ fn new_req_with_categories( cats: Vec, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body(krate, version, Vec::new(), Vec::new(), cats, HashMap::new()),); + req.with_body(&new_req_body( + krate, + version, + Vec::new(), + Vec::new(), + cats, + HashMap::new(), + )); return req; } @@ -550,7 +566,14 @@ fn new_req_with_badges( badges: HashMap>, ) -> MockRequest { let mut req = ::req(app, Method::Put, "/api/v1/crates/new"); - req.with_body(&new_req_body(krate, version, Vec::new(), Vec::new(), Vec::new(), badges),); + req.with_body(&new_req_body( + krate, + version, + Vec::new(), + Vec::new(), + Vec::new(), + badges, + )); return req; } @@ -577,22 +600,22 @@ fn new_req_body( let cats = cats.into_iter().map(u::Category).collect(); new_crate_to_body( &u::NewCrate { - name: u::CrateName(krate.name), - vers: u::CrateVersion(semver::Version::parse(version).unwrap()), - features: HashMap::new(), - deps: deps, - authors: vec!["foo".to_string()], - description: Some("description".to_string()), - homepage: krate.homepage, - documentation: krate.documentation, - readme: krate.readme, - keywords: Some(u::KeywordList(kws)), - categories: Some(u::CategoryList(cats)), - license: Some("MIT".to_string()), - license_file: None, - repository: krate.repository, - badges: Some(badges), - }, + name: u::CrateName(krate.name), + vers: u::CrateVersion(semver::Version::parse(version).unwrap()), + features: HashMap::new(), + deps: deps, + authors: vec!["foo".to_string()], + description: Some("description".to_string()), + homepage: krate.homepage, + documentation: krate.documentation, + readme: krate.readme, + keywords: Some(u::KeywordList(kws)), + categories: Some(u::CategoryList(cats)), + license: Some("MIT".to_string()), + license_file: None, + repository: krate.repository, + badges: Some(badges), + }, &[], ) } @@ -606,9 +629,8 @@ fn new_crate_to_body(new_crate: &u::NewCrate, krate: &[u8]) -> Vec { (json.len() >> 8) as u8, (json.len() >> 16) as u8, (json.len() >> 24) as u8, - ] - .iter() - .cloned(), + ].iter() + .cloned(), ); body.extend(json.as_bytes().iter().cloned()); body.extend( diff --git a/src/tests/badge.rs b/src/tests/badge.rs index 6adc341c1f2..81dd7f8d3aa 100644 --- a/src/tests/badge.rs +++ b/src/tests/badge.rs @@ -59,18 +59,14 @@ fn set_up() -> (Arc, Crate, BadgeRef) { let isitmaintained_issue_resolution = Badge::IsItMaintainedIssueResolution { repository: String::from("rust-lang/rust") }; let mut badge_attributes_isitmaintained_issue_resolution = HashMap::new(); - badge_attributes_isitmaintained_issue_resolution.insert( - String::from("repository"), - String::from("rust-lang/rust"), - ); + badge_attributes_isitmaintained_issue_resolution + .insert(String::from("repository"), String::from("rust-lang/rust")); let isitmaintained_open_issues = Badge::IsItMaintainedOpenIssues { repository: String::from("rust-lang/rust") }; let mut badge_attributes_isitmaintained_open_issues = HashMap::new(); - badge_attributes_isitmaintained_open_issues.insert( - String::from("repository"), - String::from("rust-lang/rust"), - ); + badge_attributes_isitmaintained_open_issues + .insert(String::from("repository"), String::from("rust-lang/rust")); let codecov = Badge::Codecov { service: Some(String::from("github")), diff --git a/src/tests/category.rs b/src/tests/category.rs index b251448a3eb..511b0b2c131 100644 --- a/src/tests/category.rs +++ b/src/tests/category.rs @@ -107,8 +107,7 @@ fn update_crate() { req.tx().unwrap(), &krate, &["cat1".to_string(), "category-2".to_string()], - ) - .unwrap(); + ).unwrap(); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "category-2"), 1); @@ -122,8 +121,7 @@ fn update_crate() { req.tx().unwrap(), &krate, &["cat1".to_string(), "catnope".to_string()], - ) - .unwrap(); + ).unwrap(); assert_eq!(invalid_categories, vec!["catnope".to_string()]); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "category-2"), 0); @@ -147,8 +145,7 @@ fn update_crate() { req.tx().unwrap(), &krate, &["cat1".to_string(), "cat1::bar".to_string()], - ) - .unwrap(); + ).unwrap(); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "cat1::bar"), 1); assert_eq!(cnt(&mut req, "category-2"), 0); diff --git a/src/tests/git.rs b/src/tests/git.rs index 36c893cf968..9ae8bc8cfcf 100644 --- a/src/tests/git.rs +++ b/src/tests/git.rs @@ -26,7 +26,9 @@ pub fn init() { let _ = fs::remove_dir_all(&checkout()); let _ = fs::remove_dir_all(&bare()); - INIT.call_once(|| { fs::create_dir_all(root().parent().unwrap()).unwrap(); },); + INIT.call_once(|| { + fs::create_dir_all(root().parent().unwrap()).unwrap(); + }); // Prepare a bare remote repo { @@ -42,9 +44,7 @@ pub fn init() { // Setup the `origin` remote checkout.remote_set_url("origin", &url).unwrap(); - checkout - .remote_set_pushurl("origin", Some(&url)) - .unwrap(); + checkout.remote_set_pushurl("origin", Some(&url)).unwrap(); checkout .remote_add_push("origin", "refs/heads/master") .unwrap(); diff --git a/src/tests/krate.rs b/src/tests/krate.rs index 7997234f34d..49de405d95e 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -248,7 +248,9 @@ fn exact_match_first_on_queries() { .expect_build(&conn); ::CrateBuilder::new("baz_exact", user.id) - .description("foo_exact bar_exact foo_exact bar_exact foo_exact bar_exact",) + .description( + "foo_exact bar_exact foo_exact bar_exact foo_exact bar_exact", + ) .expect_build(&conn); ::CrateBuilder::new("other_exact", user.id) @@ -299,7 +301,9 @@ fn exact_match_on_queries_with_sort() { .expect_build(&conn); ::CrateBuilder::new("baz_sort", user.id) - .description("foo_sort bar_sort foo_sort bar_sort foo_sort bar_sort const",) + .description( + "foo_sort bar_sort foo_sort bar_sort foo_sort bar_sort const", + ) .downloads(100000) .expect_build(&conn); @@ -979,12 +983,16 @@ fn download() { let yesterday = now_utc() + Duration::days(-1); req.with_path("/api/v1/crates/FOO_DOWNLOAD/1.0.0/downloads"); - req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()),); + req.with_query( + &("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()), + ); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); assert_eq!(downloads.version_downloads.len(), 0); req.with_path("/api/v1/crates/FOO_DOWNLOAD/downloads"); - req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()),); + req.with_query( + &("before_date=".to_string() + &strftime("%Y-%m-%d", &yesterday).unwrap()), + ); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); // crate/downloads always returns the last 90 days and ignores date params @@ -992,12 +1000,16 @@ fn download() { let tomorrow = now_utc() + Duration::days(1); req.with_path("/api/v1/crates/FOO_DOWNLOAD/1.0.0/downloads"); - req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()),); + req.with_query( + &("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()), + ); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); assert_eq!(downloads.version_downloads.len(), 1); req.with_path("/api/v1/crates/FOO_DOWNLOAD/downloads"); - req.with_query(&("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()),); + req.with_query( + &("before_date=".to_string() + &strftime("%Y-%m-%d", &tomorrow).unwrap()), + ); let mut resp = ok_resp!(middle.call(&mut req)); let downloads = ::json::(&mut resp); assert_eq!(downloads.version_downloads.len(), 1); @@ -1163,7 +1175,8 @@ fn owners() { assert_eq!(r.users.len(), 1); let body = r#"{"users":["foobar"]}"#; - let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); + let mut response = + ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(req.with_method(Method::Get))); @@ -1171,12 +1184,8 @@ fn owners() { assert_eq!(r.users.len(), 2); let body = r#"{"users":["foobar"]}"#; - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_body(body.as_bytes()), - ) - ); + let mut response = + ok_resp!(middle.call(req.with_method(Method::Delete).with_body(body.as_bytes()))); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(req.with_method(Method::Get))); @@ -1184,16 +1193,13 @@ fn owners() { assert_eq!(r.users.len(), 1); let body = r#"{"users":["foo"]}"#; - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_body(body.as_bytes()), - ) - ); + let mut response = + ok_resp!(middle.call(req.with_method(Method::Delete).with_body(body.as_bytes()))); ::json::<::Bad>(&mut response); let body = r#"{"users":["foobar"]}"#; - let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); + let mut response = + ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); assert!(::json::(&mut response).ok); } @@ -1777,7 +1783,7 @@ fn author_license_and_description_required() { let json = bad_resp!(middle.call(&mut req)); assert!( json.errors[0].detail.contains("author") && json.errors[0].detail.contains("description") && - json.errors[0].detail.contains("license"), + json.errors[0].detail.contains("license"), "{:?}", json.errors ); @@ -1788,7 +1794,7 @@ fn author_license_and_description_required() { let json = bad_resp!(middle.call(&mut req)); assert!( json.errors[0].detail.contains("author") && json.errors[0].detail.contains("description") && - !json.errors[0].detail.contains("license"), + !json.errors[0].detail.contains("license"), "{:?}", json.errors ); @@ -1800,8 +1806,8 @@ fn author_license_and_description_required() { let json = bad_resp!(middle.call(&mut req)); assert!( !json.errors[0].detail.contains("author") && - json.errors[0].detail.contains("description") && - !json.errors[0].detail.contains("license"), + json.errors[0].detail.contains("description") && + !json.errors[0].detail.contains("license"), "{:?}", json.errors ); diff --git a/src/tests/record.rs b/src/tests/record.rs index b26008f235c..a4bb7f588d8 100644 --- a/src/tests/record.rs +++ b/src/tests/record.rs @@ -86,50 +86,48 @@ pub fn proxy() -> (String, Bomb) { let (quittx, quitrx) = channel(); - thread::spawn( - move || { - let mut file = None; - for socket in a.incoming() { - if quitrx.try_recv().is_ok() { - break; - } - let socket = t!(socket); - - if file.is_none() { - let io = t!( - if record { - File::create(&data) - } else { - File::open(&data) - } - ); - file = Some(BufStream::new(io)); - } + thread::spawn(move || { + let mut file = None; + for socket in a.incoming() { + if quitrx.try_recv().is_ok() { + break; + } + let socket = t!(socket); - if record { - record_http(socket, file.as_mut().unwrap()); + if file.is_none() { + let io = t!(if record { + File::create(&data) } else { - replay_http(socket, file.as_mut().unwrap(), &mut sink2); - } + File::open(&data) + }); + file = Some(BufStream::new(io)); } - if !record { - if let Some(mut f) = file { - let mut s = String::new(); - t!(f.read_line(&mut s)); - assert_eq!(s, ""); - } + + if record { + record_http(socket, file.as_mut().unwrap()); + } else { + replay_http(socket, file.as_mut().unwrap(), &mut sink2); } - tx.send(()).unwrap(); + } + if !record { + if let Some(mut f) = file { + let mut s = String::new(); + t!(f.read_line(&mut s)); + assert_eq!(s, ""); + } + } + tx.send(()).unwrap(); + }); + + ( + ret, + Bomb { + accept: a2, + rx: rx, + iorx: Sink(sink), + quit: quittx, }, - ); - - (ret, - Bomb { - accept: a2, - rx: rx, - iorx: Sink(sink), - quit: quittx, - }) + ) } fn record_http(mut socket: TcpStream, data: &mut BufStream) { @@ -141,16 +139,14 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { respond(handle, headers, body, &mut response); t!(socket.write_all(&response)); - t!( - write!( - data, - "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n", - request.len(), - str::from_utf8(&request).unwrap(), - response.len(), - str::from_utf8(&response).unwrap() - ) - ); + t!(write!( + data, + "===REQUEST {}\n{}\n===RESPONSE {}\n{}\n", + request.len(), + str::from_utf8(&request).unwrap(), + response.len(), + str::from_utf8(&response).unwrap() + )); fn send(rdr: R) -> (Easy, Vec>, Vec) { let mut socket = BufReader::new(rdr); @@ -187,22 +183,14 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { let mut response = Vec::new(); { let mut transfer = handle.transfer(); - t!( - transfer.header_function( - |header| { - headers.push(header.to_owned()); - true - }, - ) - ); - t!( - transfer.write_function( - |data| { - response.extend(data); - Ok(data.len()) - }, - ) - ); + t!(transfer.header_function(|header| { + headers.push(header.to_owned()); + true + })); + t!(transfer.write_function(|data| { + response.extend(data); + Ok(data.len()) + })); t!(transfer.read_function(|buf| socket.read(buf).map_err(|_| ReadError::Abort))); t!(transfer.perform()); @@ -212,7 +200,9 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { } fn respond(mut handle: Easy, headers: Vec>, body: Vec, mut socket: W) { - t!(socket.write_all(format!("HTTP/1.1 {}\r\n", t!(handle.response_code())).as_bytes(),)); + t!(socket.write_all( + format!("HTTP/1.1 {}\r\n", t!(handle.response_code())).as_bytes(), + )); for header in headers { if header.starts_with(b"Transfer-Encoding: ") { continue; @@ -282,9 +272,7 @@ fn replay_http(socket: TcpStream, data: &mut BufStream, stdout: &mut Write assert_eq!(response.next().unwrap(), "===RESPONSE"); let response_size = response.next().unwrap().trim().parse().unwrap(); let mut response = Vec::new(); - data.take(response_size) - .read_to_end(&mut response) - .unwrap(); + data.take(response_size).read_to_end(&mut response).unwrap(); let lines = <[_]>::split(&response[..], |b| *b == b'\n').map(|s| str::from_utf8(s).unwrap()); for line in lines { if line.starts_with("Date:") { @@ -336,15 +324,12 @@ impl GhUser { self.login, password ); - let body = json::encode( - &Authorization { - scopes: vec!["read:org".to_string()], - note: "crates.io test".to_string(), - client_id: ::env("GH_CLIENT_ID"), - client_secret: ::env("GH_CLIENT_SECRET"), - }, - ) - .unwrap(); + let body = json::encode(&Authorization { + scopes: vec!["read:org".to_string()], + note: "crates.io test".to_string(), + client_id: ::env("GH_CLIENT_ID"), + client_secret: ::env("GH_CLIENT_SECRET"), + }).unwrap(); t!(handle.url(&url)); t!(handle.post(true)); @@ -358,14 +343,10 @@ impl GhUser { { let mut transfer = handle.transfer(); t!(transfer.read_function(|buf| body.read(buf).map_err(|_| ReadError::Abort))); - t!( - transfer.write_function( - |data| { - response.extend(data); - Ok(data.len()) - }, - ) - ); + t!(transfer.write_function(|data| { + response.extend(data); + Ok(data.len()) + })); t!(transfer.perform()) } diff --git a/src/tests/version.rs b/src/tests/version.rs index 455bc0e786d..d69972d9474 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -30,7 +30,9 @@ fn index() { let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) .version(::VersionBuilder::new("2.0.0").license(Some("MIT"))) - .version(::VersionBuilder::new("2.0.1").license(Some("MIT/Apache-2.0")),) + .version( + ::VersionBuilder::new("2.0.1").license(Some("MIT/Apache-2.0")), + ) .expect_build(&conn); let ids = versions::table .select(versions::id) @@ -60,9 +62,7 @@ fn show() { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); let krate = ::CrateBuilder::new("foo_vers_show", user.id).expect_build(&conn); - ::new_version(krate.id, "2.0.0") - .save(&conn, &[]) - .unwrap() + ::new_version(krate.id, "2.0.0").save(&conn, &[]).unwrap() }; req.with_path(&format!("/api/v1/versions/{}", v.id)); let mut response = ok_resp!(middle.call(&mut req)); diff --git a/src/upload.rs b/src/upload.rs index 59adef1ca53..ff987cd3252 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -52,18 +52,14 @@ impl Decodable for CrateName { fn decode(d: &mut D) -> Result { let s = d.read_str()?; if !Crate::valid_name(&s) { - return Err( - d.error( - &format!( + return Err(d.error(&format!( "invalid crate name specified: {}. \ - Valid crate names must start with a letter; contain only \ - letters, numbers, hyphens, or underscores; and have {} or \ - fewer characters.", + Valid crate names must start with a letter; contain only \ + letters, numbers, hyphens, or underscores; and have {} or \ + fewer characters.", s, MAX_NAME_LENGTH - ), - ), - ); + ))); } Ok(CrateName(s)) } @@ -141,12 +137,10 @@ impl Decodable for KeywordList { } for val in &inner { if val.len() > 20 { - return Err( - d.error( - "keywords must contain less than 20 \ - characters", - ), - ); + return Err(d.error( + "keywords must contain less than 20 \ + characters", + )); } } Ok(KeywordList(inner)) @@ -171,15 +165,11 @@ impl Decodable for DependencyKind { "build" => Ok(DependencyKind::Build), "normal" => Ok(DependencyKind::Normal), s => { - Err( - d.error( - &format!( + Err(d.error(&format!( "invalid dependency kind `{}`, must be \ - one of dev, build, or normal", + one of dev, build, or normal", s - ), - ), - ) + ))) } } } diff --git a/src/uploaders.rs b/src/uploaders.rs index 26ee6797aa7..0424da4ce8d 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -38,21 +38,17 @@ impl Uploader { pub fn crate_location(&self, crate_name: &str, version: &str) -> Option { match *self { Uploader::S3 { ref bucket, .. } => { - Some( - format!( + Some(format!( "https://{}/{}", bucket.host(), Uploader::crate_path(crate_name, version) - ), - ) + )) } Uploader::Local => { - Some( - format!( + Some(format!( "/local_uploads/{}", Uploader::crate_path(crate_name, version) - ), - ) + )) } Uploader::NoOp => None, } @@ -88,38 +84,34 @@ impl Uploader { length as u64, ); s3req - .write_function( - |data| { - response.extend(data); - Ok(data.len()) - }, - ) + .write_function(|data| { + response.extend(data); + Ok(data.len()) + }) .unwrap(); - s3req.perform().chain_error(|| { - internal(&format_args!("failed to upload to S3: `{}`", path)) - })?; + s3req + .perform() + .chain_error(|| { + internal(&format_args!("failed to upload to S3: `{}`", path)) + })?; } (response, body.finalize()) }; if handle.response_code().unwrap() != 200 { let response = String::from_utf8_lossy(&response); - return Err( - internal( - &format_args!( + return Err(internal(&format_args!( "failed to get a 200 response from S3: {}", response - ), - ), - ); + ))); } - Ok( - (cksum, - Bomb { - app: req.app().clone(), - path: Some(path), - }), - ) + Ok(( + cksum, + Bomb { + app: req.app().clone(), + path: Some(path), + }, + )) } Uploader::Local => { let path = Uploader::crate_path(&krate.name, &vers.to_string()); @@ -143,22 +135,22 @@ impl Uploader { body.finalize() }; - Ok( - (cksum, - Bomb { - app: req.app().clone(), - path: crate_filename.to_str().map(String::from), - }), - ) + Ok(( + cksum, + Bomb { + app: req.app().clone(), + path: crate_filename.to_str().map(String::from), + }, + )) } Uploader::NoOp => { - Ok( - (vec![], - Bomb { - app: req.app().clone(), - path: None, - }), - ) + Ok(( + vec![], + Bomb { + app: req.app().clone(), + path: None, + }, + )) } } } diff --git a/src/user/middleware.rs b/src/user/middleware.rs index f97ddaffa79..2b5b256b606 100644 --- a/src/user/middleware.rs +++ b/src/user/middleware.rs @@ -15,9 +15,7 @@ impl conduit_middleware::Middleware for Middleware { fn before(&self, req: &mut Request) -> Result<(), Box> { // Check if the request has a session cookie with a `user_id` property inside let id = { - req.session() - .get("user_id") - .and_then(|s| s.parse().ok()) + req.session().get("user_id").and_then(|s| s.parse().ok()) }; let user = match id { diff --git a/src/user/mod.rs b/src/user/mod.rs index 94fee97b22b..2c89cb57039 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -94,9 +94,9 @@ impl User { /// Queries the database for a user with a certain `gh_login` value. pub fn find_by_login(conn: &GenericConnection, login: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM users + "SELECT * FROM users WHERE gh_login = $1", - )?; + )?; let rows = stmt.query(&[&login])?; let row = rows.iter().next().chain_error(|| NotFound)?; Ok(Model::from_row(&row)) @@ -105,9 +105,9 @@ impl User { /// Queries the database for a user with a certain `api_token` value. pub fn find_by_api_token(conn: &GenericConnection, token: &str) -> CargoResult { let stmt = conn.prepare( - "SELECT * FROM users \ - WHERE api_token = $1 LIMIT 1", - )?; + "SELECT * FROM users \ + WHERE api_token = $1 LIMIT 1", + )?; let rows = stmt.query(&[&token])?; rows.iter() .next() @@ -130,7 +130,7 @@ impl User { // more errors than it needs to. let stmt = conn.prepare( - "UPDATE users + "UPDATE users SET gh_access_token = $1, email = $2, name = $3, @@ -138,26 +138,24 @@ impl User { gh_login = $5 WHERE gh_id = $6 RETURNING *", - )?; + )?; let rows = stmt.query(&[&access_token, &email, &name, &avatar, &login, &id])?; if let Some(ref row) = rows.iter().next() { return Ok(Model::from_row(row)); } let stmt = conn.prepare( - "INSERT INTO users + "INSERT INTO users (email, gh_access_token, gh_login, name, gh_avatar, gh_id) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", - )?; + )?; let rows = stmt.query(&[&email, &access_token, &login, &name, &avatar, &id])?; - Ok( - Model::from_row( - &rows.iter() - .next() - .chain_error(|| internal("no user with email we just found"))?, - ), - ) + Ok(Model::from_row( + &rows.iter() + .next() + .chain_error(|| internal("no user with email we just found"))?, + )) } /// Converts this `User` model into an `EncodableUser` for JSON serialization. @@ -229,14 +227,10 @@ pub fn github_authorize(req: &mut Request) -> CargoResult { url: String, state: String, } - Ok( - req.json( - &R { - url: url.to_string(), - state: state, - }, - ), - ) + Ok(req.json(&R { + url: url.to_string(), + state: state, + })) } /// Handles the `GET /authorize` route. @@ -328,10 +322,10 @@ pub fn reset_token(req: &mut Request) -> CargoResult { let conn = req.tx()?; let rows = conn.query( - "UPDATE users SET api_token = DEFAULT \ - WHERE id = $1 RETURNING api_token", - &[&user.id], - )?; + "UPDATE users SET api_token = DEFAULT \ + WHERE id = $1 RETURNING api_token", + &[&user.id], + )?; let token = rows.iter() .next() .map(|r| r.get("api_token")) @@ -354,14 +348,10 @@ pub fn me(req: &mut Request) -> CargoResult { api_token: String, } let token = user.api_token.clone(); - Ok( - req.json( - &R { - user: user.clone().encodable(), - api_token: token, - }, - ), - ) + Ok(req.json(&R { + user: user.clone().encodable(), + api_token: token, + })) } /// Handles the `GET /users/:user_id` route. @@ -396,7 +386,11 @@ pub fn updates(req: &mut Request) -> CargoResult { .order(versions::created_at.desc()) .limit(limit) .offset(offset) - .select((versions::all_columns, crates::name, sql::("COUNT(*) OVER ()")),) + .select(( + versions::all_columns, + crates::name, + sql::("COUNT(*) OVER ()"), + )) .load::<(Version, String, i64)>(&*conn)?; let more = data.get(0) @@ -416,14 +410,10 @@ pub fn updates(req: &mut Request) -> CargoResult { struct Meta { more: bool, } - Ok( - req.json( - &R { - versions: versions, - meta: Meta { more: more }, - }, - ), - ) + Ok(req.json(&R { + versions: versions, + meta: Meta { more: more }, + })) } #[cfg(test)] @@ -435,8 +425,8 @@ mod tests { fn connection() -> PgConnection { let _ = dotenv(); - let database_url = - env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests"); + let database_url = env::var("TEST_DATABASE_URL") + .expect("TEST_DATABASE_URL must be set to run tests"); let conn = PgConnection::establish(&database_url).unwrap(); conn.begin_test_transaction().unwrap(); conn diff --git a/src/util/errors.rs b/src/util/errors.rs index afbdfb3c9af..a3737e29cf7 100644 --- a/src/util/errors.rs +++ b/src/util/errors.rs @@ -27,7 +27,9 @@ pub trait CargoError: Send + fmt::Display + 'static { fn response(&self) -> Option { if self.human() { - Some(json_response(&Bad { errors: vec![StringError { detail: self.description().to_string() }] },),) + Some(json_response(&Bad { + errors: vec![StringError { detail: self.description().to_string() }], + })) } else { self.cause().and_then(|cause| cause.response()) } @@ -109,16 +111,12 @@ impl ChainError for Result { E2: CargoError, C: FnOnce() -> E2, { - self.map_err( - move |err| { - Box::new( - ChainedError { - error: callback(), - cause: Box::new(err), - }, - ) as Box - }, - ) + self.map_err(move |err| { + Box::new(ChainedError { + error: callback(), + cause: Box::new(err), + }) as Box + }) } } @@ -233,8 +231,9 @@ impl CargoError for NotFound { } fn response(&self) -> Option { - let mut response = - json_response(&Bad { errors: vec![StringError { detail: "Not Found".to_string() }] },); + let mut response = json_response(&Bad { + errors: vec![StringError { detail: "Not Found".to_string() }], + }); response.status = (404, "Not Found"); Some(response) } @@ -254,15 +253,13 @@ impl CargoError for Unauthorized { } fn response(&self) -> Option { - let mut response = json_response( - &Bad { - errors: vec![ + let mut response = json_response(&Bad { + errors: vec![ StringError { detail: "must be logged in to perform that action".to_string(), }, ], - }, - ); + }); response.status = (403, "Forbidden"); Some(response) } @@ -275,36 +272,30 @@ impl fmt::Display for Unauthorized { } pub fn internal_error(error: &str, detail: &str) -> Box { - Box::new( - ConcreteCargoError { - description: error.to_string(), - detail: Some(detail.to_string()), - cause: None, - human: false, - }, - ) + Box::new(ConcreteCargoError { + description: error.to_string(), + detail: Some(detail.to_string()), + cause: None, + human: false, + }) } pub fn internal(error: &S) -> Box { - Box::new( - ConcreteCargoError { - description: error.to_string(), - detail: None, - cause: None, - human: false, - }, - ) + Box::new(ConcreteCargoError { + description: error.to_string(), + detail: None, + cause: None, + human: false, + }) } pub fn human(error: &S) -> Box { - Box::new( - ConcreteCargoError { - description: error.to_string(), - detail: None, - cause: None, - human: true, - }, - ) + Box::new(ConcreteCargoError { + description: error.to_string(), + detail: None, + cause: None, + human: true, + }) } pub fn std_error(e: Box) -> Box { diff --git a/src/util/head.rs b/src/util/head.rs index 55f677f28ca..36202d76513 100644 --- a/src/util/head.rs +++ b/src/util/head.rs @@ -25,18 +25,12 @@ impl Handler for Head { path: None, method: Some(Method::Get), }; - self.handler - .as_ref() - .unwrap() - .call(&mut req) - .map( - |r| { - Response { - body: Box::new(io::empty()), - ..r - } - }, - ) + self.handler.as_ref().unwrap().call(&mut req).map(|r| { + Response { + body: Box::new(io::empty()), + ..r + } + }) } else { self.handler.as_ref().unwrap().call(req) } diff --git a/src/util/io_util.rs b/src/util/io_util.rs index f5ab1f920ab..9d7eb38d2be 100644 --- a/src/util/io_util.rs +++ b/src/util/io_util.rs @@ -16,7 +16,10 @@ impl Read for LimitErrorReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self.inner.read(buf) { Ok(0) if self.inner.limit() == 0 => { - Err(io::Error::new(io::ErrorKind::Other, "maximum limit reached when reading"),) + Err(io::Error::new( + io::ErrorKind::Other, + "maximum limit reached when reading", + )) } e => e, } @@ -26,7 +29,9 @@ impl Read for LimitErrorReader { pub fn read_le_u32(r: &mut R) -> io::Result { let mut b = [0; 4]; read_fill(r, &mut b)?; - Ok((b[0] as u32) | ((b[1] as u32) << 8) | ((b[2] as u32) << 16) | ((b[3] as u32) << 24),) + Ok( + (b[0] as u32) | ((b[1] as u32) << 8) | ((b[2] as u32) << 16) | ((b[3] as u32) << 24), + ) } pub fn read_fill(r: &mut R, mut slice: &mut [u8]) -> io::Result<()> { diff --git a/src/util/mod.rs b/src/util/mod.rs index b6b4df4ef1a..02a8d2e4696 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -46,10 +46,10 @@ pub fn json_response(t: &T) -> Response { ); headers.insert("Content-Length".to_string(), vec![json.len().to_string()]); return Response { - status: (200, "OK"), - headers: headers, - body: Box::new(Cursor::new(json.into_bytes())), - }; + status: (200, "OK"), + headers: headers, + body: Box::new(Cursor::new(json.into_bytes())), + }; fn fixup(json: Json) -> Json { match json { @@ -57,12 +57,10 @@ pub fn json_response(t: &T) -> Response { Json::Object( object .into_iter() - .map( - |(k, v)| { - let k = if k == "krate" { "crate".to_string() } else { k }; - (k, fixup(v)) - }, - ) + .map(|(k, v)| { + let k = if k == "krate" { "crate".to_string() } else { k }; + (k, fixup(v)) + }) .collect(), ) } @@ -112,7 +110,9 @@ impl<'a> RequestUtils for Request + 'a { .and_then(|s| s.parse::().ok()) .unwrap_or(default); if limit > max { - return Err(human(&format_args!("cannot request more than {} items", max)),); + return Err(human( + &format_args!("cannot request more than {} items", max), + )); } if page == 0 { return Err(human("page indexing starts from 1, page 0 is invalid")); @@ -147,13 +147,11 @@ impl Handler for R { fn call(&self, req: &mut Request) -> Result> { let path = req.params()["path"].to_string(); let R(ref sub_router) = *self; - sub_router.call( - &mut RequestProxy { - other: req, - path: Some(&path), - method: None, - }, - ) + sub_router.call(&mut RequestProxy { + other: req, + path: Some(&path), + method: None, + }) } } diff --git a/src/util/request_proxy.rs b/src/util/request_proxy.rs index d2bbf596f18..8c1929db133 100644 --- a/src/util/request_proxy.rs +++ b/src/util/request_proxy.rs @@ -33,9 +33,7 @@ impl<'a> Request for RequestProxy<'a> { self.other.virtual_root() } fn path(&self) -> &str { - self.path - .map(|s| &*s) - .unwrap_or_else(|| self.other.path()) + self.path.map(|s| &*s).unwrap_or_else(|| self.other.path()) } fn query_string(&self) -> Option<&str> { self.other.query_string() diff --git a/src/version.rs b/src/version.rs index 18693272020..6a49193f251 100644 --- a/src/version.rs +++ b/src/version.rs @@ -82,9 +82,9 @@ impl Version { ) -> CargoResult> { let num = num.to_string(); let stmt = conn.prepare( - "SELECT * FROM versions \ - WHERE crate_id = $1 AND num = $2", - )?; + "SELECT * FROM versions \ + WHERE crate_id = $1 AND num = $2", + )?; let rows = stmt.query(&[&crate_id, &num])?; Ok(rows.iter().next().map(|r| Model::from_row(&r))) } @@ -99,17 +99,15 @@ impl Version { let num = num.to_string(); let features = json::encode(features).unwrap(); let stmt = conn.prepare( - "INSERT INTO versions \ - (crate_id, num, features) \ - VALUES ($1, $2, $3) \ - RETURNING *", - )?; + "INSERT INTO versions \ + (crate_id, num, features) \ + VALUES ($1, $2, $3) \ + RETURNING *", + )?; let rows = stmt.query(&[&crate_id, &num, &features])?; - let ret: Version = Model::from_row( - &rows.iter() - .next() - .chain_error(|| internal("no version returned"))?, - ); + let ret: Version = Model::from_row(&rows.iter() + .next() + .chain_error(|| internal("no version returned"))?); for author in authors { ret.add_author(conn, author)?; } @@ -163,10 +161,10 @@ impl Version { pub fn authors(&self, conn: &GenericConnection) -> CargoResult> { let stmt = conn.prepare( - "SELECT * FROM version_authors + "SELECT * FROM version_authors WHERE version_id = $1 ORDER BY name ASC", - )?; + )?; let rows = stmt.query(&[&self.id])?; Ok( rows.into_iter() @@ -177,18 +175,18 @@ impl Version { pub fn add_author(&self, conn: &GenericConnection, name: &str) -> CargoResult<()> { conn.execute( - "INSERT INTO version_authors (version_id, name) + "INSERT INTO version_authors (version_id, name) VALUES ($1, $2)", - &[&self.id, &name], - )?; + &[&self.id, &name], + )?; Ok(()) } pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> { conn.execute( - "UPDATE versions SET yanked = $1 WHERE id = $2", - &[&yanked, &self.id], - )?; + "UPDATE versions SET yanked = $1 WHERE id = $2", + &[&yanked, &self.id], + )?; Ok(()) } @@ -196,20 +194,15 @@ impl Version { where T: IntoIterator, { - versions - .into_iter() - .max() - .unwrap_or_else( - || { - semver::Version { - major: 0, - minor: 0, - patch: 0, - pre: vec![], - build: vec![], - } - }, - ) + versions.into_iter().max().unwrap_or_else(|| { + semver::Version { + major: 0, + minor: 0, + patch: 0, + pre: vec![], + build: vec![], + } + }) } } @@ -244,54 +237,44 @@ impl NewVersion { .filter(crate_id.eq(self.crate_id)) .filter(num.eq(&self.num)); if select(exists(already_uploaded)).get_result(conn)? { - return Err( - human( - &format_args!( + return Err(human(&format_args!( "crate version `{}` is already \ - uploaded", + uploaded", self.num - ), - ), - ); + ))); } - conn.transaction( - || { - let version = insert(self).into(versions).get_result::(conn)?; - - let new_authors = authors - .iter() - .map( - |s| { - NewAuthor { - version_id: version.id, - name: &*s, - } - }, - ) - .collect::>(); - - insert(&new_authors) - .into(version_authors::table) - .execute(conn)?; - Ok(version) - }, - ) + conn.transaction(|| { + let version = insert(self).into(versions).get_result::(conn)?; + + let new_authors = authors + .iter() + .map(|s| { + NewAuthor { + version_id: version.id, + name: &*s, + } + }) + .collect::>(); + + insert(&new_authors) + .into(version_authors::table) + .execute(conn)?; + Ok(version) + }) } fn validate_license(&mut self, license_file: Option<&str>) -> CargoResult<()> { if let Some(ref license) = self.license { for part in license.split('/') { - license_exprs::validate_license_expr(part) - .map_err( - |e| { - human( - &format_args!("{}; see http://opensource.org/licenses \ - for options, and http://spdx.org/licenses/ \ - for their identifiers", e), - ) - }, - )?; + license_exprs::validate_license_expr(part).map_err(|e| { + human(&format_args!( + "{}; see http://opensource.org/licenses \ + for options, and http://spdx.org/licenses/ \ + for their identifiers", + e + )) + })?; } } else if license_file.is_some() { // If no license is given, but a license file is given, flag this @@ -311,7 +294,17 @@ struct NewAuthor<'a> { } impl Queryable for Version { - type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool, Option); + type Row = ( + i32, + i32, + String, + Timespec, + Timespec, + i32, + Option, + bool, + Option, + ); fn build(row: Self::Row) -> Self { let features = row.6 @@ -364,7 +357,11 @@ pub fn index(req: &mut Request) -> CargoResult { // Extract all ids requested. let query = url::form_urlencoded::parse(req.query_string().unwrap_or("").as_bytes()); let ids = query - .filter_map(|(ref a, ref b)| if *a == "ids[]" { b.parse().ok() } else { None },) + .filter_map(|(ref a, ref b)| if *a == "ids[]" { + b.parse().ok() + } else { + None + }) .collect::>(); let versions = versions::table @@ -414,18 +411,13 @@ fn version_and_crate_old(req: &mut Request) -> CargoResult<(Version, Crate)> { let tx = req.tx()?; let krate = Crate::find_by_name(tx, crate_name)?; let version = Version::find_by_num(tx, krate.id, &semver)?; - let version = version - .chain_error( - || { - human( - &format_args!( + let version = version.chain_error(|| { + human(&format_args!( "crate `{}` does not have a version `{}`", crate_name, semver - ), - ) - }, - )?; + )) + })?; Ok((version, krate)) } @@ -440,17 +432,13 @@ fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> { let version = Version::belonging_to(&krate) .filter(versions::num.eq(semver)) .first(&*conn) - .map_err( - |_| { - human( - &format_args!( + .map_err(|_| { + human(&format_args!( "crate `{}` does not have a version `{}`", crate_name, semver - ), - ) - }, - )?; + )) + })?; Ok((version, krate)) } @@ -483,7 +471,9 @@ pub fn downloads(req: &mut Request) -> CargoResult { let cutoff_start_date = cutoff_end_date + Duration::days(-89); let downloads = VersionDownload::belonging_to(&version) - .filter(version_downloads::date.between(date(cutoff_start_date)..date(cutoff_end_date)),) + .filter( + version_downloads::date.between(date(cutoff_start_date)..date(cutoff_end_date)), + ) .order(version_downloads::date) .load(&*conn)? .into_iter() @@ -501,11 +491,7 @@ pub fn downloads(req: &mut Request) -> CargoResult { pub fn authors(req: &mut Request) -> CargoResult { let (version, _) = version_and_crate_old(req)?; let tx = req.tx()?; - let names = version - .authors(tx)? - .into_iter() - .map(|a| a.name) - .collect(); + let names = version.authors(tx)?.into_iter().map(|a| a.name).collect(); // It was imagined that we wold associate authors with users. // This was never implemented. This complicated return struct @@ -519,14 +505,10 @@ pub fn authors(req: &mut Request) -> CargoResult { struct Meta { names: Vec, } - Ok( - req.json( - &R { - users: vec![], - meta: Meta { names: names }, - }, - ), - ) + Ok(req.json(&R { + users: vec![], + meta: Meta { names: names }, + })) } /// Handles the `DELETE /crates/:crate_id/:version/yank` route. @@ -549,15 +531,13 @@ fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult { } if version.yanked != yanked { - conn.transaction::<_, Box, _>( - || { - diesel::update(&version) - .set(versions::yanked.eq(yanked)) - .execute(&*conn)?; - git::yank(&**req.app(), &krate.name, &version.num, yanked)?; - Ok(()) - }, - )?; + conn.transaction::<_, Box, _>(|| { + diesel::update(&version) + .set(versions::yanked.eq(yanked)) + .execute(&*conn)?; + git::yank(&**req.app(), &krate.name, &version.num, yanked)?; + Ok(()) + })?; } #[derive(RustcEncodable)] From 41ae4c0a27d2756face3a5c151c87690fc5b64b2 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 21 Jun 2017 09:03:06 -0400 Subject: [PATCH 28/29] cargo fmt again --- build.rs | 5 +- src/bin/populate.rs | 6 +- src/bin/update-downloads.rs | 9 +- src/categories.rs | 18 ++- src/category.rs | 18 ++- src/db.rs | 21 ++- src/dependency.rs | 26 ++-- src/git.rs | 24 +++- src/http.rs | 6 +- src/keyword.rs | 11 +- src/krate.rs | 171 +++++++++++------------ src/owner.rs | 33 ++--- src/tests/all.rs | 11 +- src/tests/badge.rs | 22 ++- src/tests/git.rs | 9 +- src/tests/krate.rs | 266 +++++++++++++----------------------- src/tests/record.rs | 8 +- src/tests/team.rs | 12 +- src/tests/user.rs | 8 +- src/tests/version.rs | 6 +- src/uploaders.rs | 8 +- src/user/middleware.rs | 6 +- src/user/mod.rs | 46 ++++--- src/util/request_proxy.rs | 6 +- src/version.rs | 54 ++++---- 25 files changed, 370 insertions(+), 440 deletions(-) diff --git a/build.rs b/build.rs index d72b5441d7c..2a819a48bb4 100644 --- a/build.rs +++ b/build.rs @@ -11,8 +11,9 @@ fn main() { if env::var("PROFILE") == Ok("debug".into()) { let _ = dotenv(); if let Ok(database_url) = env::var("TEST_DATABASE_URL") { - let connection = PgConnection::establish(&database_url) - .expect("Could not connect to TEST_DATABASE_URL"); + let connection = PgConnection::establish(&database_url).expect( + "Could not connect to TEST_DATABASE_URL", + ); run_pending_migrations(&connection).expect("Error running migrations"); } } diff --git a/src/bin/populate.rs b/src/bin/populate.rs index bde4df36633..f87fed92e47 100644 --- a/src/bin/populate.rs +++ b/src/bin/populate.rs @@ -27,9 +27,9 @@ fn main() { } fn update(tx: &postgres::transaction::Transaction) -> postgres::Result<()> { - let ids = env::args() - .skip(1) - .filter_map(|arg| arg.parse::().ok()); + let ids = env::args().skip(1).filter_map( + |arg| arg.parse::().ok(), + ); for id in ids { let now = time::now_utc().to_timespec(); let mut rng = StdRng::new().unwrap(); diff --git a/src/bin/update-downloads.rs b/src/bin/update-downloads.rs index 59aa514bff6..6360c715ee1 100644 --- a/src/bin/update-downloads.rs +++ b/src/bin/update-downloads.rs @@ -174,12 +174,9 @@ mod test { "SELECT * FROM crate_downloads WHERE crate_id = $1", ).unwrap(); - let dl: i32 = stmt.query(&[&id]) - .unwrap() - .iter() - .next() - .unwrap() - .get("downloads"); + let dl: i32 = stmt.query(&[&id]).unwrap().iter().next().unwrap().get( + "downloads", + ); assert_eq!(dl, expected as i32); } diff --git a/src/categories.rs b/src/categories.rs index 31620800f71..1d6e16bdef8 100644 --- a/src/categories.rs +++ b/src/categories.rs @@ -58,11 +58,9 @@ fn categories_from_toml( let mut result = vec![]; for (slug, details) in categories { - let details = details - .as_table() - .chain_error(|| { - internal(&format_args!("category {} was not a TOML table", slug)) - })?; + let details = details.as_table().chain_error(|| { + internal(&format_args!("category {} was not a TOML table", slug)) + })?; let category = Category::from_parent( slug, @@ -93,12 +91,12 @@ pub fn sync() -> CargoResult<()> { let tx = conn.transaction().unwrap(); let categories = include_str!("./categories.toml"); - let toml = toml::Parser::new(categories) - .parse() - .expect("Could not parse categories.toml"); + let toml = toml::Parser::new(categories).parse().expect( + "Could not parse categories.toml", + ); - let categories = categories_from_toml(&toml, None) - .expect("Could not convert categories from TOML"); + let categories = + categories_from_toml(&toml, None).expect("Could not convert categories from TOML"); for category in &categories { tx.execute( diff --git a/src/category.rs b/src/category.rs index 28f5f332de0..eec05b8d7d5 100644 --- a/src/category.rs +++ b/src/category.rs @@ -63,10 +63,9 @@ impl Category { WHERE category = $1", )?; let rows = stmt.query(&[&name])?; - rows.iter() - .next() - .chain_error(|| NotFound) - .map(|row| Model::from_row(&row)) + rows.iter().next().chain_error(|| NotFound).map(|row| { + Model::from_row(&row) + }) } pub fn find_by_slug(conn: &GenericConnection, slug: &str) -> CargoResult { @@ -75,10 +74,9 @@ impl Category { WHERE slug = LOWER($1)", )?; let rows = stmt.query(&[&slug])?; - rows.iter() - .next() - .chain_error(|| NotFound) - .map(|row| Model::from_row(&row)) + rows.iter().next().chain_error(|| NotFound).map(|row| { + Model::from_row(&row) + }) } pub fn encodable(self) -> EncodableCategory { @@ -429,8 +427,8 @@ mod tests { fn pg_connection() -> PgConnection { let _ = dotenv(); - let database_url = env::var("TEST_DATABASE_URL") - .expect("TEST_DATABASE_URL must be set to run tests"); + let database_url = + env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests"); let conn = PgConnection::establish(&database_url).unwrap(); // These tests deadlock if run concurrently conn.batch_execute("BEGIN; LOCK categories IN ACCESS EXCLUSIVE MODE") diff --git a/src/db.rs b/src/db.rs index 2e29d1a391b..8ed45a18517 100644 --- a/src/db.rs +++ b/src/db.rs @@ -153,12 +153,9 @@ impl Transaction { &self, ) -> CargoResult<&r2d2::PooledConnection> { if !self.slot.filled() { - let conn = self.app - .database - .get() - .map_err(|e| { - internal(&format_args!("failed to get a database connection: {}", e)) - })?; + let conn = self.app.database.get().map_err(|e| { + internal(&format_args!("failed to get a database connection: {}", e)) + })?; self.slot.fill(Box::new(conn)); } Ok(&**self.slot.borrow().unwrap()) @@ -205,16 +202,16 @@ impl Middleware for TransactionMiddleware { req: &mut Request, res: Result>, ) -> Result> { - let tx = req.mut_extensions() - .pop::() - .expect("Transaction not present in request"); + let tx = req.mut_extensions().pop::().expect( + "Transaction not present in request", + ); if let Some(transaction) = tx.tx.into_inner() { if res.is_ok() && tx.commit.get() == Some(true) { transaction.set_commit(); } - transaction - .finish() - .map_err(|e| Box::new(e) as Box)?; + transaction.finish().map_err( + |e| Box::new(e) as Box, + )?; } res } diff --git a/src/dependency.rs b/src/dependency.rs index 2553965a926..3b33ab42b58 100644 --- a/src/dependency.rs +++ b/src/dependency.rs @@ -125,8 +125,10 @@ impl Dependency { impl ReverseDependency { pub fn encodable(self) -> EncodableDependency { - self.dependency - .encodable(&self.crate_name, Some(self.crate_downloads)) + self.dependency.encodable( + &self.crate_name, + Some(self.crate_downloads), + ) } } @@ -139,11 +141,11 @@ pub fn add_dependencies( let git_and_new_dependencies = deps.iter() .map(|dep| { - let krate = Crate::by_name(&dep.name) - .first::(&*conn) - .map_err(|_| { + let krate = Crate::by_name(&dep.name).first::(&*conn).map_err( + |_| { human(&format_args!("no known crate named `{}`", &*dep.name)) - })?; + }, + )?; if dep.version_req == semver::VersionReq::parse("*").unwrap() { return Err(human( "wildcard (`*`) dependency constraints are not allowed \ @@ -189,17 +191,7 @@ pub fn add_dependencies( } impl Queryable for Dependency { - type Row = ( - i32, - i32, - i32, - String, - bool, - bool, - Vec, - Option, - i32, - ); + type Row = (i32, i32, i32, String, bool, bool, Vec, Option, i32); fn build(row: Self::Row) -> Self { Dependency { diff --git a/src/git.rs b/src/git.rs index 12a6e15da64..751bac4c8f5 100644 --- a/src/git.rs +++ b/src/git.rs @@ -56,8 +56,9 @@ pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> { fs::create_dir_all(dst.parent().unwrap())?; let mut prev = String::new(); if fs::metadata(&dst).is_ok() { - File::open(&dst) - .and_then(|mut f| f.read_to_string(&mut prev))?; + File::open(&dst).and_then( + |mut f| f.read_to_string(&mut prev), + )?; } let s = json::encode(krate).unwrap(); let new = prev + &s; @@ -79,12 +80,14 @@ pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> commit_and_push(&repo, || { let mut prev = String::new(); - File::open(&dst) - .and_then(|mut f| f.read_to_string(&mut prev))?; + File::open(&dst).and_then( + |mut f| f.read_to_string(&mut prev), + )?; let new = prev.lines() .map(|line| { - let mut git_crate = json::decode::(line) - .map_err(|_| internal(&format_args!("couldn't decode: `{}`", line)))?; + let mut git_crate = json::decode::(line).map_err(|_| { + internal(&format_args!("couldn't decode: `{}`", line)) + })?; if git_crate.name != krate || git_crate.vers != version.to_string() { return Ok(line.to_string()); } @@ -137,7 +140,14 @@ where let head = repo.head()?; let parent = repo.find_commit(head.target().unwrap())?; let sig = repo.signature()?; - repo.commit(Some("HEAD"), &sig, &sig, &msg, &tree, &[&parent])?; + repo.commit( + Some("HEAD"), + &sig, + &sig, + &msg, + &tree, + &[&parent], + )?; // git push let mut ref_status = None; diff --git a/src/http.rs b/src/http.rs index e6b26a0d0d3..7d153a8dac3 100644 --- a/src/http.rs +++ b/src/http.rs @@ -68,9 +68,9 @@ pub fn parse_github_response(mut resp: Easy, data: &[u8]) -> Cargo } } - let json = str::from_utf8(data) - .ok() - .chain_error(|| internal("github didn't send a utf8-response"))?; + let json = str::from_utf8(data).ok().chain_error(|| { + internal("github didn't send a utf8-response") + })?; json::decode(json).chain_error(|| internal("github didn't send a valid json response")) } diff --git a/src/keyword.rs b/src/keyword.rs index 9de46a05760..0b7990eac10 100644 --- a/src/keyword.rs +++ b/src/keyword.rs @@ -79,9 +79,9 @@ impl Keyword { return false; } name.chars().next().unwrap().is_alphanumeric() && - name.chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && - name.chars().all(|c| c.is_ascii()) + name.chars().all( + |c| c.is_alphanumeric() || c == '_' || c == '-', + ) && name.chars().all(|c| c.is_ascii()) } pub fn encodable(self) -> EncodableKeyword { @@ -102,8 +102,9 @@ impl Keyword { pub fn update_crate(conn: &PgConnection, krate: &Crate, keywords: &[&str]) -> QueryResult<()> { conn.transaction(|| { let keywords = Keyword::find_or_create_all(conn, keywords)?; - diesel::delete(CrateKeyword::belonging_to(krate)) - .execute(conn)?; + diesel::delete(CrateKeyword::belonging_to(krate)).execute( + conn, + )?; let crate_keywords = keywords .into_iter() .map(|kw| { diff --git a/src/krate.rs b/src/krate.rs index 0cb6ce800bf..1c0d8f08aab 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -56,20 +56,18 @@ pub struct Crate { /// We literally never want to select `textsearchable_index_col` /// so we provide this type and constant to pass to `.select` -type AllColumns = ( - crates::id, - crates::name, - crates::updated_at, - crates::created_at, - crates::downloads, - crates::description, - crates::homepage, - crates::documentation, - crates::readme, - crates::license, - crates::repository, - crates::max_upload_size, -); +type AllColumns = (crates::id, + crates::name, + crates::updated_at, + crates::created_at, + crates::downloads, + crates::description, + crates::homepage, + crates::documentation, + crates::readme, + crates::license, + crates::repository, + crates::max_upload_size); pub const ALL_COLUMNS: AllColumns = ( crates::id, @@ -152,9 +150,9 @@ impl<'a> NewCrate<'a> { return Ok(krate); } - let target = crates::table.filter( - canon_crate_name(crates::name).eq(canon_crate_name(self.name)), - ); + let target = crates::table.filter(canon_crate_name(crates::name).eq( + canon_crate_name(self.name), + )); update(target) .set(&self) .returning(ALL_COLUMNS) @@ -169,10 +167,9 @@ impl<'a> NewCrate<'a> { Some(s) => s, None => return Ok(()), }; - let url = Url::parse(url) - .map_err(|_| { - human(&format_args!("`{}` is not a valid url: `{}`", field, url)) - })?; + let url = Url::parse(url).map_err(|_| { + human(&format_args!("`{}` is not a valid url: `{}`", field, url)) + })?; match &url.scheme()[..] { "http" | "https" => {} s => { @@ -229,7 +226,11 @@ impl<'a> NewCrate<'a> { use diesel::expression::dsl::exists; let reserved_name = select(exists( - reserved_crate_names.filter(canon_crate_name(name).eq(canon_crate_name(self.name))), + reserved_crate_names.filter(canon_crate_name(name).eq( + canon_crate_name( + self.name, + ), + )), )).get_result::(conn)?; if reserved_name { Err(human("cannot upload a crate with a reserved name")) @@ -386,9 +387,9 @@ impl Crate { &max_upload_size, ], )?; - let ret: Crate = Model::from_row(&rows.iter() - .next() - .chain_error(|| internal("no crate returned"))?); + let ret: Crate = Model::from_row(&rows.iter().next().chain_error( + || internal("no crate returned"), + )?); conn.execute( "INSERT INTO crate_owners @@ -403,10 +404,9 @@ impl Crate { Some(s) => s, None => return Ok(()), }; - let url = Url::parse(url) - .map_err(|_| { - human(&format_args!("`{}` is not a valid url: `{}`", field, url)) - })?; + let url = Url::parse(url).map_err(|_| { + human(&format_args!("`{}` is not a valid url: `{}`", field, url)) + })?; match &url.scheme()[..] { "http" | "https" => {} s => { @@ -458,9 +458,9 @@ impl Crate { return false; } name.chars().next().unwrap().is_alphabetic() && - name.chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-') && - name.chars().all(|c| c.is_ascii()) + name.chars().all( + |c| c.is_alphanumeric() || c == '_' || c == '-', + ) && name.chars().all(|c| c.is_ascii()) } pub fn valid_feature_name(name: &str) -> bool { @@ -559,9 +559,9 @@ impl Crate { )?; let rows = stmt.query(&[&self.id])?; Ok(Version::max( - rows.iter() - .map(|r| r.get::<_, String>("num")) - .map(|s| semver::Version::parse(&s).unwrap()), + rows.iter().map(|r| r.get::<_, String>("num")).map(|s| { + semver::Version::parse(&s).unwrap() + }), )) } @@ -675,10 +675,9 @@ impl Crate { _req_user: &User, login: &str, ) -> CargoResult<()> { - let owner = Owner::find_by_login(conn, login) - .map_err(|_| { - human(&format_args!("could not find owner with login `{}`", login)) - })?; + let owner = Owner::find_by_login(conn, login).map_err(|_| { + human(&format_args!("could not find owner with login `{}`", login)) + })?; let target = crate_owners::table.find((self.id(), owner.id(), owner.kind() as i32)); diesel::update(target) .set(crate_owners::deleted.eq(true)) @@ -725,9 +724,9 @@ impl Crate { } pub fn badges(&self, conn: &PgConnection) -> QueryResult> { - badges::table - .filter(badges::crate_id.eq(self.id)) - .load(conn) + badges::table.filter(badges::crate_id.eq(self.id)).load( + conn, + ) } /// Returns (dependency, dependent crate name, dependent crate downloads) @@ -802,10 +801,11 @@ pub fn index(req: &mut Request) -> CargoResult { if let Some(q_string) = params.get("q") { let q = plainto_tsquery(q_string); - query = query.filter( - q.matches(crates::textsearchable_index_col) - .or(crates::name.eq(q_string)), - ); + query = query.filter(q.matches(crates::textsearchable_index_col).or( + crates::name.eq( + q_string, + ), + )); query = query.select(( ALL_COLUMNS, @@ -827,11 +827,10 @@ pub fn index(req: &mut Request) -> CargoResult { crates_categories::table .select(crates_categories::crate_id) .inner_join(categories::table) - .filter( - categories::slug - .eq(cat) - .or(categories::slug.like(format!("{}::%", cat))), - ), + .filter(categories::slug.eq(cat).or(categories::slug.like(format!( + "{}::%", + cat + )))), ), ); } @@ -866,13 +865,11 @@ pub fn index(req: &mut Request) -> CargoResult { ), ); } else if params.get("following").is_some() { - query = query.filter( - crates::id.eq_any( - follows::table - .select(follows::crate_id) - .filter(follows::user_id.eq(req.user()?.id)), + query = query.filter(crates::id.eq_any( + follows::table.select(follows::crate_id).filter( + follows::user_id.eq(req.user()?.id), ), - ); + )); } let data = query.load::<(Crate, i64, bool)>(&*conn)?; @@ -897,9 +894,11 @@ pub fn index(req: &mut Request) -> CargoResult { let badges = badges::table .filter(badges::crate_id.eq(krate.id)) .load::(&*conn)?; - Ok( - krate.minimal_encodable(max_version, Some(badges), perfect_match), - ) + Ok(krate.minimal_encodable( + max_version, + Some(badges), + perfect_match, + )) }) .collect::>()?; @@ -1013,9 +1012,9 @@ pub fn show(req: &mut Request) -> CargoResult { .select(categories::all_columns) .load(&*conn)?; - let badges = badges::table - .filter(badges::crate_id.eq(krate.id)) - .load(&*conn)?; + let badges = badges::table.filter(badges::crate_id.eq(krate.id)).load( + &*conn, + )?; let max_version = krate.max_version(&conn)?; #[derive(RustcEncodable)] @@ -1102,12 +1101,13 @@ pub fn new(req: &mut Request) -> CargoResult { )); } - let length = req.content_length() - .chain_error(|| human("missing header: Content-Length"))?; - let max = krate - .max_upload_size - .map(|m| m as u64) - .unwrap_or(app.config.max_upload_size); + let length = req.content_length().chain_error(|| { + human("missing header: Content-Length") + })?; + let max = krate.max_upload_size.map(|m| m as u64).unwrap_or( + app.config + .max_upload_size, + ); if length > max { return Err(human(&format_args!("max upload size is: {}", max))); } @@ -1189,10 +1189,12 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> } let mut json = vec![0; amt as usize]; read_fill(req.body(), &mut json)?; - let json = String::from_utf8(json) - .map_err(|_| human("json body was not valid utf-8"))?; - let new: upload::NewCrate = json::decode(&json) - .map_err(|e| human(&format_args!("invalid upload request: {:?}", e)))?; + let json = String::from_utf8(json).map_err(|_| { + human("json body was not valid utf-8") + })?; + let new: upload::NewCrate = json::decode(&json).map_err(|e| { + human(&format_args!("invalid upload request: {:?}", e)) + })?; // Make sure required fields are provided fn empty(s: Option<&String>) -> bool { @@ -1260,9 +1262,9 @@ fn increment_download_counts(req: &Request, crate_name: &str, version: &str) -> let conn = req.db_conn()?; let version_id = versions .select(id) - .filter( - crate_id.eq_any(Crate::by_name(crate_name).select(crates::id)), - ) + .filter(crate_id.eq_any( + Crate::by_name(crate_name).select(crates::id), + )) .filter(num.eq(version)) .first(&*conn)?; @@ -1437,8 +1439,9 @@ fn modify_owners(req: &mut Request, add: bool) -> CargoResult { req.body().read_to_string(&mut body)?; let user = req.user()?; let conn = req.db_conn()?; - let krate = Crate::by_name(&req.params()["crate_id"]) - .first::(&*conn)?; + let krate = Crate::by_name(&req.params()["crate_id"]).first::( + &*conn, + )?; let owners = krate.owners(&conn)?; match rights(req.app(), &owners, user)? { @@ -1458,13 +1461,13 @@ fn modify_owners(req: &mut Request, add: bool) -> CargoResult { owners: Option>, } - let request: Request = json::decode(&body) - .map_err(|_| human("invalid json request"))?; + let request: Request = json::decode(&body).map_err( + |_| human("invalid json request"), + )?; - let logins = request - .owners - .or(request.users) - .ok_or_else(|| human("invalid json request"))?; + let logins = request.owners.or(request.users).ok_or_else(|| { + human("invalid json request") + })?; for login in &logins { if add { diff --git a/src/owner.rs b/src/owner.rs index 19fc6c59b62..a28af6ae1bf 100644 --- a/src/owner.rs +++ b/src/owner.rs @@ -199,9 +199,10 @@ impl Team { avatar: avatar, }; - diesel::insert( - &new_team.on_conflict(teams::github_id, do_update().set(&new_team)), - ).into(teams::table) + diesel::insert(&new_team.on_conflict( + teams::github_id, + do_update().set(&new_team), + )).into(teams::table) .get_result(conn) .map_err(Into::into) } @@ -304,13 +305,13 @@ impl Owner { pub fn encodable(self) -> EncodableOwner { match self { Owner::User(User { - id, - email, - name, - gh_login, - gh_avatar, - .. - }) => { + id, + email, + name, + gh_login, + gh_avatar, + .. + }) => { let url = format!("https://github.com/{}", gh_login); EncodableOwner { id: id, @@ -323,12 +324,12 @@ impl Owner { } } Owner::Team(Team { - id, - name, - login, - avatar, - .. - }) => { + id, + name, + login, + avatar, + .. + }) => { let url = { let mut parts = login.split(':'); parts.next(); // discard github diff --git a/src/tests/all.rs b/src/tests/all.rs index fca62dd3ab4..9a270fd8f92 100644 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -86,13 +86,7 @@ mod team; mod user; mod version; -fn app() - -> ( - record::Bomb, - Arc, - conduit_middleware::MiddlewareBuilder, -) -{ +fn app() -> (record::Bomb, Arc, conduit_middleware::MiddlewareBuilder) { dotenv::dotenv().ok(); git::init(); @@ -328,8 +322,7 @@ impl<'a> CrateBuilder<'a> { fn build(mut self, connection: &PgConnection) -> CargoResult { use diesel::update; - let mut krate = self.krate - .create_or_update(connection, None, self.owner_id)?; + let mut krate = self.krate.create_or_update(connection, None, self.owner_id)?; // Since we are using `NewCrate`, we can't set all the // crate properties in a single DB call. diff --git a/src/tests/badge.rs b/src/tests/badge.rs index 81dd7f8d3aa..aa1b6f66089 100644 --- a/src/tests/badge.rs +++ b/src/tests/badge.rs @@ -59,14 +59,22 @@ fn set_up() -> (Arc, Crate, BadgeRef) { let isitmaintained_issue_resolution = Badge::IsItMaintainedIssueResolution { repository: String::from("rust-lang/rust") }; let mut badge_attributes_isitmaintained_issue_resolution = HashMap::new(); - badge_attributes_isitmaintained_issue_resolution - .insert(String::from("repository"), String::from("rust-lang/rust")); + badge_attributes_isitmaintained_issue_resolution.insert( + String::from("repository"), + String::from("rust-lang/rust"), + ); let isitmaintained_open_issues = Badge::IsItMaintainedOpenIssues { repository: String::from("rust-lang/rust") }; let mut badge_attributes_isitmaintained_open_issues = HashMap::new(); - badge_attributes_isitmaintained_open_issues - .insert(String::from("repository"), String::from("rust-lang/rust")); + badge_attributes_isitmaintained_open_issues.insert( + String::from( + "repository", + ), + String::from( + "rust-lang/rust", + ), + ); let codecov = Badge::Codecov { service: Some(String::from("github")), @@ -380,9 +388,9 @@ fn isitmaintained_open_issues_required_keys() { let mut badges = HashMap::new(); // Repository is a required key - test_badges - .isitmaintained_open_issues_attributes - .remove("repository"); + test_badges.isitmaintained_open_issues_attributes.remove( + "repository", + ); badges.insert( String::from("isitmaintained_open_issues"), test_badges.isitmaintained_open_issues_attributes, diff --git a/src/tests/git.rs b/src/tests/git.rs index 9ae8bc8cfcf..3b26cd18c2e 100644 --- a/src/tests/git.rs +++ b/src/tests/git.rs @@ -8,10 +8,11 @@ use git2; use url::Url; fn root() -> PathBuf { - env::current_dir() - .unwrap() - .join("tmp") - .join(thread::current().name().unwrap()) + env::current_dir().unwrap().join("tmp").join( + thread::current() + .name() + .unwrap(), + ) } pub fn checkout() -> PathBuf { diff --git a/src/tests/krate.rs b/src/tests/krate.rs index 49de405d95e..612d87e7be5 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -473,11 +473,9 @@ fn new_krate_with_reserved_name() { let mut req = ::new_req(app, name, "1.0.0"); ::mock_user(&mut req, ::user("foo")); let json = bad_resp!(middle.call(&mut req)); - assert!( - json.errors[0] - .detail - .contains("cannot upload a crate with a reserved name") - ); + assert!(json.errors[0].detail.contains( + "cannot upload a crate with a reserved name", + )); } test_bad_name("std"); @@ -926,11 +924,9 @@ fn new_krate_dependency_missing() { ::sign_in(&mut req, &app); let mut response = ok_resp!(middle.call(&mut req)); let json = ::json::<::Bad>(&mut response); - assert!( - json.errors[0] - .detail - .contains("no known crate named `bar_missing`") - ); + assert!(json.errors[0].detail.contains( + "no known crate named `bar_missing`", + )); } #[test] @@ -1175,8 +1171,9 @@ fn owners() { assert_eq!(r.users.len(), 1); let body = r#"{"users":["foobar"]}"#; - let mut response = - ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); + let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body( + body.as_bytes(), + ))); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(req.with_method(Method::Get))); @@ -1184,8 +1181,9 @@ fn owners() { assert_eq!(r.users.len(), 2); let body = r#"{"users":["foobar"]}"#; - let mut response = - ok_resp!(middle.call(req.with_method(Method::Delete).with_body(body.as_bytes()))); + let mut response = ok_resp!(middle.call(req.with_method(Method::Delete).with_body( + body.as_bytes(), + ))); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(req.with_method(Method::Get))); @@ -1193,13 +1191,15 @@ fn owners() { assert_eq!(r.users.len(), 1); let body = r#"{"users":["foo"]}"#; - let mut response = - ok_resp!(middle.call(req.with_method(Method::Delete).with_body(body.as_bytes()))); + let mut response = ok_resp!(middle.call(req.with_method(Method::Delete).with_body( + body.as_bytes(), + ))); ::json::<::Bad>(&mut response); let body = r#"{"users":["foobar"]}"#; - let mut response = - ok_resp!(middle.call(req.with_method(Method::Put).with_body(body.as_bytes()))); + let mut response = ok_resp!(middle.call(req.with_method(Method::Put).with_body( + body.as_bytes(), + ))); assert!(::json::(&mut response).ok); } @@ -1229,21 +1229,15 @@ fn yank() { assert!(contents.contains("\"yanked\":false")); // make sure it's not yanked - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk/1.0.0"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk/1.0.0", + ))); assert!(!::json::(&mut r).version.yanked); // yank it - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_path("/api/v1/crates/fyk/1.0.0/yank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( + "/api/v1/crates/fyk/1.0.0/yank", + ))); assert!(::json::(&mut r).ok); let mut contents = String::new(); File::open(&path) @@ -1251,21 +1245,15 @@ fn yank() { .read_to_string(&mut contents) .unwrap(); assert!(contents.contains("\"yanked\":true")); - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk/1.0.0"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk/1.0.0", + ))); assert!(::json::(&mut r).version.yanked); // un-yank it - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Put) - .with_path("/api/v1/crates/fyk/1.0.0/unyank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( + "/api/v1/crates/fyk/1.0.0/unyank", + ))); assert!(::json::(&mut r).ok); let mut contents = String::new(); File::open(&path) @@ -1273,12 +1261,9 @@ fn yank() { .read_to_string(&mut contents) .unwrap(); assert!(contents.contains("\"yanked\":false")); - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk/1.0.0"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk/1.0.0", + ))); assert!(!::json::(&mut r).version.yanked); } @@ -1287,8 +1272,9 @@ fn yank_not_owner() { let (_b, app, middle) = ::app(); let mut req = ::request_with_user_and_mock_crate(&app, ::new_user("bar"), "foo_not"); ::sign_in(&mut req, &app); - req.with_method(Method::Delete) - .with_path("/api/v1/crates/foo_not/1.0.0/yank"); + req.with_method(Method::Delete).with_path( + "/api/v1/crates/foo_not/1.0.0/yank", + ); let mut response = ok_resp!(middle.call(&mut req)); ::json::<::Bad>(&mut response); } @@ -1323,104 +1309,68 @@ fn yank_max_version() { assert_eq!(json.krate.max_version, "2.0.0"); // yank version 1.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_path("/api/v1/crates/fyk_max/1.0.0/yank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( + "/api/v1/crates/fyk_max/1.0.0/yank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); // unyank version 1.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Put) - .with_path("/api/v1/crates/fyk_max/1.0.0/unyank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( + "/api/v1/crates/fyk_max/1.0.0/unyank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); // yank version 2.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_path("/api/v1/crates/fyk_max/2.0.0/yank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( + "/api/v1/crates/fyk_max/2.0.0/yank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "1.0.0"); // yank version 1.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_path("/api/v1/crates/fyk_max/1.0.0/yank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( + "/api/v1/crates/fyk_max/1.0.0/yank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "0.0.0"); // unyank version 2.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Put) - .with_path("/api/v1/crates/fyk_max/2.0.0/unyank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( + "/api/v1/crates/fyk_max/2.0.0/unyank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); // unyank version 1.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Put) - .with_path("/api/v1/crates/fyk_max/1.0.0/unyank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( + "/api/v1/crates/fyk_max/1.0.0/unyank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); } @@ -1443,19 +1393,13 @@ fn publish_after_yank_max_version() { assert_eq!(json.krate.max_version, "1.0.0"); // yank version 1.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Delete) - .with_path("/api/v1/crates/fyk_max/1.0.0/yank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Delete).with_path( + "/api/v1/crates/fyk_max/1.0.0/yank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "0.0.0"); @@ -1472,19 +1416,13 @@ fn publish_after_yank_max_version() { assert_eq!(json.krate.max_version, "2.0.0"); // unyank version 1.0.0 - let mut r = ok_resp!( - middle.call( - req.with_method(Method::Put) - .with_path("/api/v1/crates/fyk_max/1.0.0/unyank"), - ) - ); + let mut r = ok_resp!(middle.call(req.with_method(Method::Put).with_path( + "/api/v1/crates/fyk_max/1.0.0/unyank", + ))); assert!(::json::(&mut r).ok); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/fyk_max"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/fyk_max", + ))); let json: CrateResponse = ::json(&mut response); assert_eq!(json.krate.max_version, "2.0.0"); } @@ -1580,12 +1518,9 @@ fn good_badges() { assert_eq!(json.krate.name, "foobadger"); assert_eq!(json.krate.max_version, "1.0.0"); - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/foobadger"), - ) - ); + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/foobadger", + ))); let json: CrateResponse = ::json(&mut response); @@ -1623,23 +1558,16 @@ fn ignored_badges() { assert_eq!(json.krate.name, "foo_ignored_badge"); assert_eq!(json.krate.max_version, "1.0.0"); assert_eq!(json.warnings.invalid_badges.len(), 2); - assert!( - json.warnings - .invalid_badges - .contains(&"travis-ci".to_string()) - ); - assert!( - json.warnings - .invalid_badges - .contains(&"not-a-badge".to_string()) - ); - - let mut response = ok_resp!( - middle.call( - req.with_method(Method::Get) - .with_path("/api/v1/crates/foo_ignored_badge"), - ) - ); + assert!(json.warnings.invalid_badges.contains( + &"travis-ci".to_string(), + )); + assert!(json.warnings.invalid_badges.contains( + &"not-a-badge".to_string(), + )); + + let mut response = ok_resp!(middle.call(req.with_method(Method::Get).with_path( + "/api/v1/crates/foo_ignored_badge", + ))); let json: CrateResponse = ::json(&mut response); diff --git a/src/tests/record.rs b/src/tests/record.rs index a4bb7f588d8..de0d26a869f 100644 --- a/src/tests/record.rs +++ b/src/tests/record.rs @@ -191,7 +191,9 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { response.extend(data); Ok(data.len()) })); - t!(transfer.read_function(|buf| socket.read(buf).map_err(|_| ReadError::Abort))); + t!(transfer.read_function( + |buf| socket.read(buf).map_err(|_| ReadError::Abort), + )); t!(transfer.perform()); } @@ -342,7 +344,9 @@ impl GhUser { let mut response = Vec::new(); { let mut transfer = handle.transfer(); - t!(transfer.read_function(|buf| body.read(buf).map_err(|_| ReadError::Abort))); + t!(transfer.read_function( + |buf| body.read(buf).map_err(|_| ReadError::Abort), + )); t!(transfer.write_function(|data| { response.extend(data); Ok(data.len()) diff --git a/src/tests/team.rs b/src/tests/team.rs index efa3d7946e9..9df3ac6f073 100644 --- a/src/tests/team.rs +++ b/src/tests/team.rs @@ -70,9 +70,9 @@ fn weird_name() { ) ); assert!( - json.errors[0] - .detail - .contains("organization cannot contain"), + json.errors[0].detail.contains( + "organization cannot contain", + ), "{:?}", json.errors ); @@ -114,9 +114,9 @@ fn nonexistent_team() { ) ); assert!( - json.errors[0] - .detail - .contains("could not find the github team"), + json.errors[0].detail.contains( + "could not find the github team", + ), "{:?}", json.errors ); diff --git a/src/tests/user.rs b/src/tests/user.rs index e513c3469ba..c2f78b473ce 100644 --- a/src/tests/user.rs +++ b/src/tests/user.rs @@ -163,7 +163,9 @@ fn following() { .expect_build(&conn); } - let mut response = ok_resp!(middle.call(req.with_path("/me/updates").with_method(Method::Get))); + let mut response = ok_resp!(middle.call( + req.with_path("/me/updates").with_method(Method::Get), + )); let r = ::json::(&mut response); assert_eq!(r.versions.len(), 0); assert_eq!(r.meta.more, false); @@ -181,7 +183,9 @@ fn following() { ) ); - let mut response = ok_resp!(middle.call(req.with_path("/me/updates").with_method(Method::Get))); + let mut response = ok_resp!(middle.call( + req.with_path("/me/updates").with_method(Method::Get), + )); let r = ::json::(&mut response); assert_eq!(r.versions.len(), 2); assert_eq!(r.meta.more, false); diff --git a/src/tests/version.rs b/src/tests/version.rs index d69972d9474..cf1df296a6f 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -30,9 +30,9 @@ fn index() { let u = ::new_user("foo").create_or_update(&conn).unwrap(); ::CrateBuilder::new("foo_vers_index", u.id) .version(::VersionBuilder::new("2.0.0").license(Some("MIT"))) - .version( - ::VersionBuilder::new("2.0.1").license(Some("MIT/Apache-2.0")), - ) + .version(::VersionBuilder::new("2.0.1").license( + Some("MIT/Apache-2.0"), + )) .expect_build(&conn); let ids = versions::table .select(versions::id) diff --git a/src/uploaders.rs b/src/uploaders.rs index 0424da4ce8d..8ad0beab834 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -89,11 +89,9 @@ impl Uploader { Ok(data.len()) }) .unwrap(); - s3req - .perform() - .chain_error(|| { - internal(&format_args!("failed to upload to S3: `{}`", path)) - })?; + s3req.perform().chain_error(|| { + internal(&format_args!("failed to upload to S3: `{}`", path)) + })?; } (response, body.finalize()) }; diff --git a/src/user/middleware.rs b/src/user/middleware.rs index 2b5b256b606..5c84c83aaf9 100644 --- a/src/user/middleware.rs +++ b/src/user/middleware.rs @@ -61,8 +61,8 @@ pub trait RequestUser { impl<'a> RequestUser for Request + 'a { fn user(&self) -> CargoResult<&User> { - self.extensions() - .find::() - .chain_error(|| Unauthorized) + self.extensions().find::().chain_error( + || Unauthorized, + ) } } diff --git a/src/user/mod.rs b/src/user/mod.rs index 2c89cb57039..902908956e4 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -139,7 +139,9 @@ impl User { WHERE gh_id = $6 RETURNING *", )?; - let rows = stmt.query(&[&access_token, &email, &name, &avatar, &login, &id])?; + let rows = stmt.query( + &[&access_token, &email, &name, &avatar, &login, &id], + )?; if let Some(ref row) = rows.iter().next() { return Ok(Model::from_row(row)); } @@ -150,12 +152,12 @@ impl User { VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", )?; - let rows = stmt.query(&[&email, &access_token, &login, &name, &avatar, &id])?; - Ok(Model::from_row( - &rows.iter() - .next() - .chain_error(|| internal("no user with email we just found"))?, - )) + let rows = stmt.query( + &[&email, &access_token, &login, &name, &avatar, &id], + )?; + Ok(Model::from_row(&rows.iter().next().chain_error(|| { + internal("no user with email we just found") + })?)) } /// Converts this `User` model into an `EncodableUser` for JSON serialization. @@ -217,8 +219,10 @@ impl Model for User { pub fn github_authorize(req: &mut Request) -> CargoResult { // Generate a random 16 char ASCII string let state: String = thread_rng().gen_ascii_chars().take(16).collect(); - req.session() - .insert("github_oauth_state".to_string(), state.clone()); + req.session().insert( + "github_oauth_state".to_string(), + state.clone(), + ); let url = req.app().github.authorize_url(state.clone()); @@ -287,10 +291,9 @@ pub fn github_access_token(req: &mut Request) -> CargoResult { } // Fetch the access token from github using the code we just got - let token = req.app() - .github - .exchange(code.clone()) - .map_err(|s| human(&s))?; + let token = req.app().github.exchange(code.clone()).map_err( + |s| human(&s), + )?; let (handle, resp) = http::github(req.app(), "/user", &token)?; let ghuser: GithubUser = http::parse_github_response(handle, &resp)?; @@ -304,8 +307,10 @@ pub fn github_access_token(req: &mut Request) -> CargoResult { ghuser.avatar_url.as_ref().map(|s| &s[..]), &token.access_token, )?; - req.session() - .insert("user_id".to_string(), user.id.to_string()); + req.session().insert( + "user_id".to_string(), + user.id.to_string(), + ); req.mut_extensions().insert(user); me(req) } @@ -326,10 +331,9 @@ pub fn reset_token(req: &mut Request) -> CargoResult { WHERE id = $1 RETURNING api_token", &[&user.id], )?; - let token = rows.iter() - .next() - .map(|r| r.get("api_token")) - .chain_error(|| NotFound)?; + let token = rows.iter().next().map(|r| r.get("api_token")).chain_error( + || NotFound, + )?; #[derive(RustcEncodable)] struct R { @@ -425,8 +429,8 @@ mod tests { fn connection() -> PgConnection { let _ = dotenv(); - let database_url = env::var("TEST_DATABASE_URL") - .expect("TEST_DATABASE_URL must be set to run tests"); + let database_url = + env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests"); let conn = PgConnection::establish(&database_url).unwrap(); conn.begin_test_transaction().unwrap(); conn diff --git a/src/util/request_proxy.rs b/src/util/request_proxy.rs index 8c1929db133..5409b318b4a 100644 --- a/src/util/request_proxy.rs +++ b/src/util/request_proxy.rs @@ -19,9 +19,9 @@ impl<'a> Request for RequestProxy<'a> { self.other.conduit_version() } fn method(&self) -> conduit::Method { - self.method - .clone() - .unwrap_or_else(|| self.other.method().clone()) + self.method.clone().unwrap_or_else( + || self.other.method().clone(), + ) } fn scheme(&self) -> conduit::Scheme { self.other.scheme() diff --git a/src/version.rs b/src/version.rs index 6a49193f251..6097025335a 100644 --- a/src/version.rs +++ b/src/version.rs @@ -105,9 +105,9 @@ impl Version { RETURNING *", )?; let rows = stmt.query(&[&crate_id, &num, &features])?; - let ret: Version = Model::from_row(&rows.iter() - .next() - .chain_error(|| internal("no version returned"))?); + let ret: Version = Model::from_row(&rows.iter().next().chain_error( + || internal("no version returned"), + )?); for author in authors { ret.add_author(conn, author)?; } @@ -233,9 +233,9 @@ impl NewVersion { use diesel::expression::dsl::exists; use schema::versions::dsl::*; - let already_uploaded = versions - .filter(crate_id.eq(self.crate_id)) - .filter(num.eq(&self.num)); + let already_uploaded = versions.filter(crate_id.eq(self.crate_id)).filter( + num.eq(&self.num), + ); if select(exists(already_uploaded)).get_result(conn)? { return Err(human(&format_args!( "crate version `{}` is already \ @@ -257,9 +257,9 @@ impl NewVersion { }) .collect::>(); - insert(&new_authors) - .into(version_authors::table) - .execute(conn)?; + insert(&new_authors).into(version_authors::table).execute( + conn, + )?; Ok(version) }) } @@ -294,22 +294,12 @@ struct NewAuthor<'a> { } impl Queryable for Version { - type Row = ( - i32, - i32, - String, - Timespec, - Timespec, - i32, - Option, - bool, - Option, - ); + type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool, Option); fn build(row: Self::Row) -> Self { - let features = row.6 - .map(|s| json::decode(&s).unwrap()) - .unwrap_or_else(HashMap::new); + let features = row.6.map(|s| json::decode(&s).unwrap()).unwrap_or_else( + HashMap::new, + ); Version { id: row.0, crate_id: row.1, @@ -328,9 +318,9 @@ impl Model for Version { fn from_row(row: &Row) -> Version { let num: String = row.get("num"); let features: Option = row.get("features"); - let features = features - .map(|s| json::decode(&s).unwrap()) - .unwrap_or_else(HashMap::new); + let features = features.map(|s| json::decode(&s).unwrap()).unwrap_or_else( + HashMap::new, + ); Version { id: row.get("id"), crate_id: row.get("crate_id"), @@ -406,8 +396,9 @@ pub fn show(req: &mut Request) -> CargoResult { fn version_and_crate_old(req: &mut Request) -> CargoResult<(Version, Crate)> { let crate_name = &req.params()["crate_id"]; let semver = &req.params()["version"]; - let semver = semver::Version::parse(semver) - .map_err(|_| human(&format_args!("invalid semver: {}", semver)))?; + let semver = semver::Version::parse(semver).map_err(|_| { + human(&format_args!("invalid semver: {}", semver)) + })?; let tx = req.tx()?; let krate = Crate::find_by_name(tx, crate_name)?; let version = Version::find_by_num(tx, krate.id, &semver)?; @@ -471,9 +462,10 @@ pub fn downloads(req: &mut Request) -> CargoResult { let cutoff_start_date = cutoff_end_date + Duration::days(-89); let downloads = VersionDownload::belonging_to(&version) - .filter( - version_downloads::date.between(date(cutoff_start_date)..date(cutoff_end_date)), - ) + .filter(version_downloads::date.between( + date(cutoff_start_date).. + date(cutoff_end_date), + )) .order(version_downloads::date) .load(&*conn)? .into_iter() From a2c66449572735ecf5e64a86e9bfcdcdc60d5b86 Mon Sep 17 00:00:00 2001 From: Nicholas Bailey Date: Wed, 21 Jun 2017 15:23:05 -0400 Subject: [PATCH 29/29] Updated 'update-license' binary to handle if the crate doesn't currently have a license. --- src/bin/update-licenses.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/bin/update-licenses.rs b/src/bin/update-licenses.rs index 56394e1cfa4..0bcd6de7865 100644 --- a/src/bin/update-licenses.rs +++ b/src/bin/update-licenses.rs @@ -27,19 +27,26 @@ fn transfer(tx: &postgres::transaction::Transaction) { for row in rows.iter() { let id: i32 = row.get("id"); let name: String = row.get("name"); - let license: String = row.get("license"); - - println!( - "Setting the license for all versions of {} to {}.", - name, - license - ); - - let num_updated = tx.execute( - "UPDATE versions SET license = $1 WHERE crate_id = $2", - &[&license, &id], - ).unwrap(); - assert!(num_updated > 0); + let license: Option = row.get("license"); + + if let Some(license) = license { + println!( + "Setting the license for all versions of {} to {}.", + name, + license + ); + + let num_updated = tx.execute( + "UPDATE versions SET license = $1 WHERE crate_id = $2", + &[&license, &id], + ).unwrap(); + assert!(num_updated > 0); + } else { + println!( + "Ignoring crate `{}` because it doesn't have a license.", + name + ); + } } get_confirm("Finish committing?");