diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000000..e640536fa2a --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,9 @@ +fn_args_layout = "Block" +array_layout = "Block" +control_style = "Rfc" +where_style = "Rfc" +generics_indent = "Block" +fn_call_style = "Block" +combine_control_expr = true +fn_args_paren_newline = false +max_width = 160 diff --git a/.travis.yml b/.travis.yml index 5c2bfe1e026..01423dc5073 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ sudo: false dist: trusty cache: + cargo: true directories: - $HOME/.yarn-cache @@ -17,6 +18,8 @@ install: - yarn - yarn run bower install - cargo install diesel_cli --debug --no-default-features --features postgres && export PATH=$HOME/.cargo/bin:$PATH + - cargo install rustfmt + - rustfmt --version before_script: - diesel database setup @@ -34,6 +37,9 @@ addons: matrix: include: + - rust: stable + script: + - cargo fmt -- --write-mode=diff - rust: stable script: - cargo build diff --git a/README.md b/README.md index 1fe03282c3c..c8b3559fdfc 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,12 @@ A volunteer will get back to you as soon as possible. Welcome! We love contributions! Crates.io is an [Ember](https://emberjs.com/) frontend with a Rust backend, and there are many tasks appropriate for a -variety of skill levels. +variety of skill levels. + +The Rust backend uses rustfmt for code formatting, so ensure that you run it prior +to submitting a pull request, and that your version of rustfmt is the latst version. +More information on setting up and running rustfmt can be found +[here](https://github.com/rust-lang-nursery/rustfmt/blob/master/README.md). Please see [docs/CONTRIBUTING.md](https://github.com/rust-lang/crates.io/blob/master/docs/CONTRIBUTING.md) for ideas about what to work on and how to set up a development environment. diff --git a/build.rs b/build.rs index 70c9bb1d8e4..6f3b30a0661 100644 --- a/build.rs +++ b/build.rs @@ -11,10 +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"); - run_pending_migrations(&connection) - .expect("Error running migrations"); + 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 b38ee8412a1..a19f2b03275 100644 --- a/src/app.rs +++ b/src/app.rs @@ -34,7 +34,7 @@ pub struct App { /// The `AppMiddleware` injects an `App` instance into the `Request` extensions pub struct AppMiddleware { - app: Arc + app: Arc, } impl App { @@ -105,13 +105,12 @@ impl AppMiddleware { } impl Middleware for AppMiddleware { - fn before(&self, req: &mut Request) -> Result<(), Box> { + fn before(&self, req: &mut Request) -> Result<(), Box> { req.mut_extensions().insert(self.app.clone()); Ok(()) } - fn after(&self, req: &mut Request, res: Result>) - -> Result> { + fn after(&self, req: &mut Request, res: Result>) -> Result> { req.mut_extensions().pop::>().unwrap(); res } @@ -124,7 +123,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 bcb627b32ed..7e885800608 100644 --- a/src/badge.rs +++ b/src/badge.rs @@ -12,31 +12,35 @@ use std::collections::HashMap; pub enum Badge { #[serde(rename = "travis-ci")] TravisCi { - repository: String, branch: Option, + repository: String, + branch: Option, }, #[serde(rename = "appveyor")] Appveyor { - repository: String, branch: Option, service: Option, + repository: String, + branch: Option, + service: Option, }, #[serde(rename = "gitlab")] GitLab { - repository: String, branch: Option, - }, - #[serde(rename = "is-it-maintained-issue-resolution")] - IsItMaintainedIssueResolution { repository: String, + branch: Option, }, + #[serde(rename = "is-it-maintained-issue-resolution")] + IsItMaintainedIssueResolution { repository: String }, #[serde(rename = "is-it-maintained-open-issues")] - IsItMaintainedOpenIssues { - repository: String, - }, + IsItMaintainedOpenIssues { repository: String }, #[serde(rename = "codecov")] Codecov { - repository: String, branch: Option, service: Option, + repository: String, + branch: Option, + service: Option, }, #[serde(rename = "coveralls")] Coveralls { - repository: String, branch: Option, service: Option, + repository: String, + branch: Option, + service: Option, }, } @@ -51,8 +55,7 @@ impl Queryable for Badge { fn build((_, badge_type, attributes): Self::Row) -> Self { let json = json!({"badge_type": badge_type, "attributes": attributes}); - serde_json::from_value(json) - .expect("Invalid CI badge in the database") + serde_json::from_value(json).expect("Invalid CI badge in the database") } } @@ -63,24 +66,21 @@ impl Badge { pub fn badge_type(&self) -> &'static str { match *self { - Badge::TravisCi {..} => "travis-ci", - Badge::Appveyor {..} => "appveyor", - Badge::GitLab{..} => "gitlab", - Badge::IsItMaintainedIssueResolution{..} => "is-it-maintained-issue-resolution", - Badge::IsItMaintainedOpenIssues{..} => "is-it-maintained-open-issues", - Badge::Codecov{..} => "codecov", - Badge::Coveralls{..} => "coveralls", + Badge::TravisCi { .. } => "travis-ci", + Badge::Appveyor { .. } => "appveyor", + Badge::GitLab { .. } => "gitlab", + Badge::IsItMaintainedIssueResolution { .. } => "is-it-maintained-issue-resolution", + Badge::IsItMaintainedOpenIssues { .. } => "is-it-maintained-open-issues", + Badge::Codecov { .. } => "codecov", + Badge::Coveralls { .. } => "coveralls", } } - pub fn update_crate<'a>(conn: &PgConnection, - krate: &Crate, - badges: Option<&'a HashMap>>) - -> CargoResult> { + pub fn update_crate<'a>(conn: &PgConnection, krate: &Crate, badges: Option<&'a HashMap>>) -> CargoResult> { use diesel::{insert, delete}; #[derive(Insertable)] - #[table_name="badges"] + #[table_name = "badges"] struct NewBadge<'a> { crate_id: i32, badge_type: &'a str, @@ -108,7 +108,8 @@ impl Badge { } conn.transaction(|| { - delete(badges::table.filter(badges::crate_id.eq(krate.id))).execute(conn)?; + 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 3c15bc99204..3e32cec3115 100644 --- a/src/bin/delete-crate.rs +++ b/src/bin/delete-crate.rs @@ -30,80 +30,105 @@ fn main() { fn delete(tx: &postgres::transaction::Transaction) { let name = match env::args().nth(1) { - None => { println!("needs a crate-name argument"); return } + None => { + println!("needs a crate-name argument"); + return; + } Some(s) => s, }; let krate = Crate::find_by_name(tx, &name).unwrap(); - print!("Are you sure you want to delete {} ({}) [y/N]: ", name, krate.id); + print!( + "Are you sure you want to delete {} ({}) [y/N]: ", + name, + krate.id + ); io::stdout().flush().unwrap(); let mut line = String::new(); io::stdin().read_line(&mut line).unwrap(); - if !line.starts_with("y") { return } + if !line.starts_with("y") { + return; + } let versions = krate.versions(tx).unwrap(); 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(); + let n = tx.execute( + "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(); + let n = tx.execute( + "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(); + let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1", &[&v.id]) + .unwrap(); println!(" {} dependencies deleted", n); - tx.execute("DELETE FROM versions WHERE id = $1", - &[&v.id]).unwrap(); + tx.execute("DELETE FROM versions WHERE id = $1", &[&v.id]) + .unwrap(); } println!("deleting follows"); - let n = tx.execute("DELETE FROM follows WHERE crate_id = $1", - &[&krate.id]).unwrap(); + let n = tx.execute("DELETE FROM follows WHERE crate_id = $1", &[&krate.id]) + .unwrap(); println!(" {} deleted", n); println!("deleting crate download records"); - let n = tx.execute("DELETE FROM crate_downloads WHERE crate_id = $1", - &[&krate.id]).unwrap(); + let n = tx.execute( + "DELETE FROM crate_downloads WHERE crate_id = $1", + &[&krate.id], + ).unwrap(); println!(" {} deleted", n); println!("deleting crate owners"); - let n = tx.execute("DELETE FROM crate_owners WHERE crate_id = $1", - &[&krate.id]).unwrap(); + let n = tx.execute("DELETE FROM crate_owners WHERE crate_id = $1", &[&krate.id]) + .unwrap(); println!(" {} deleted", n); println!("disabling reserved crate name trigger"); - let _ = tx.execute("ALTER TABLE crates DISABLE TRIGGER trigger_ensure_crate_name_not_reserved;", - &[]).unwrap(); + let _ = tx.execute( + "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(); + let n = tx.execute( + "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(); + let n = tx.execute( + "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(); + let _ = tx.execute( + "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]).unwrap(); + let n = tx.execute("DELETE FROM badges WHERE crate_id = $1", &[&krate.id]) + .unwrap(); println!(" {} deleted", n); println!("deleting the crate"); - let n = tx.execute("DELETE FROM crates WHERE id = $1", - &[&krate.id]).unwrap(); + let n = tx.execute("DELETE FROM crates WHERE id = $1", &[&krate.id]) + .unwrap(); println!(" {} deleted", n); print!("commit? [y/N]: "); io::stdout().flush().unwrap(); let mut line = String::new(); io::stdin().read_line(&mut line).unwrap(); - if !line.starts_with("y") { panic!("aborting transaction"); } + if !line.starts_with("y") { + panic!("aborting transaction"); + } } diff --git a/src/bin/delete-version.rs b/src/bin/delete-version.rs index c3711175146..9679323d59c 100644 --- a/src/bin/delete-version.rs +++ b/src/bin/delete-version.rs @@ -31,40 +31,60 @@ fn main() { fn delete(tx: &postgres::transaction::Transaction) { let name = match env::args().nth(1) { - None => { println!("needs a crate-name argument"); return } + None => { + println!("needs a crate-name argument"); + return; + } Some(s) => s, }; let version = match env::args().nth(2) { - None => { println!("needs a version argument"); return } + None => { + println!("needs a version argument"); + return; + } Some(s) => s, }; let version = semver::Version::parse(&version).unwrap(); let krate = Crate::find_by_name(tx, &name).unwrap(); - let v = Version::find_by_num(tx, krate.id, &version).unwrap().unwrap(); - print!("Are you sure you want to delete {}#{} ({}) [y/N]: ", name, version, - v.id); + let v = Version::find_by_num(tx, krate.id, &version) + .unwrap() + .unwrap(); + print!( + "Are you sure you want to delete {}#{} ({}) [y/N]: ", + name, + version, + v.id + ); io::stdout().flush().unwrap(); let mut line = String::new(); io::stdin().read_line(&mut line).unwrap(); - if !line.starts_with("y") { return } + if !line.starts_with("y") { + return; + } println!("deleting version {} ({})", v.num, v.id); - let n = tx.execute("DELETE FROM version_downloads WHERE version_id = $1", - &[&v.id]).unwrap(); + let n = tx.execute( + "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(); + let n = tx.execute( + "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(); + let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1", &[&v.id]) + .unwrap(); println!(" {} dependencies deleted", n); - tx.execute("DELETE FROM versions WHERE id = $1", - &[&v.id]).unwrap(); + tx.execute("DELETE FROM versions WHERE id = $1", &[&v.id]) + .unwrap(); print!("commit? [y/N]: "); io::stdout().flush().unwrap(); let mut line = String::new(); io::stdin().read_line(&mut line).unwrap(); - if !line.starts_with("y") { panic!("aborting transaction"); } + if !line.starts_with("y") { + panic!("aborting transaction"); + } } diff --git a/src/bin/fill-in-user-id.rs b/src/bin/fill-in-user-id.rs index e1dfae7442d..d3a907a2ca1 100644 --- a/src/bin/fill-in-user-id.rs +++ b/src/bin/fill-in-user-id.rs @@ -53,13 +53,17 @@ struct GithubUser { fn update(app: &App, tx: &postgres::transaction::Transaction) { let query = "SELECT id, gh_login, gh_access_token, gh_avatar FROM users WHERE gh_id IS NULL"; - 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) - }).collect::>(); + 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) + }) + .collect::>(); for (id, login, token, avatar) in rows { println!("attempt: {}/{}", id, login); @@ -69,12 +73,14 @@ fn update(app: &App, tx: &postgres::transaction::Transaction) { let ghuser: GithubUser = http::parse_github_response(handle, &resp)?; if let Some(ref avatar) = avatar { if !avatar.contains(&ghuser.id.to_string()) { - return Err(human(&format_args!("avatar: {}", avatar))) + return Err(human(&format_args!("avatar: {}", avatar))); } } if ghuser.login == login { - tx.execute("UPDATE users SET gh_id = $1 WHERE id = $2", - &[&ghuser.id, &id])?; + tx.execute( + "UPDATE users SET gh_id = $1 WHERE id = $2", + &[&ghuser.id, &id], + )?; Ok(()) } else { Err(human(&format_args!("different login: {}", ghuser.login))) @@ -85,4 +91,3 @@ fn update(app: &App, tx: &postgres::transaction::Transaction) { } } } - diff --git a/src/bin/populate.rs b/src/bin/populate.rs index b4567d6c367..8dfa0514f6f 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(); @@ -38,10 +38,12 @@ fn update(tx: &postgres::transaction::Transaction) -> postgres::Result<()> { for day in 0..90 { let moment = now + Duration::days(-day); dls += rng.gen_range(-100, 100); - tx.execute("INSERT INTO version_downloads \ + tx.execute( + "INSERT INTO version_downloads \ (version_id, downloads, date) \ VALUES ($1, $2, $3)", - &[&id, &dls, &moment])?; + &[&id, &dls, &moment], + )?; } } Ok(()) diff --git a/src/bin/server.rs b/src/bin/server.rs index daadf46a9f7..8cf6099e56b 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -31,8 +31,9 @@ fn main() { let mut opts = git2::FetchOptions::new(); opts.remote_callbacks(cb); git2::build::RepoBuilder::new() - .fetch_options(opts) - .clone(&url, &checkout).unwrap() + .fetch_options(opts) + .clone(&url, &checkout) + .unwrap() } }; let mut cfg = repo.config().unwrap(); @@ -57,42 +58,48 @@ fn main() { (Env::Production, Replica::Primary) => { // `env` panics if these vars are not set Uploader::S3 { - bucket: s3::Bucket::new(env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env("S3_ACCESS_KEY"), - env("S3_SECRET_KEY"), - &api_protocol), + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env("S3_ACCESS_KEY"), + env("S3_SECRET_KEY"), + &api_protocol, + ), proxy: None, } - }, + } (Env::Production, Replica::ReadOnlyMirror) => { // Read-only mirrors don't need access key or secret key, // but they might have them. Definitely need bucket though. Uploader::S3 { - bucket: s3::Bucket::new(env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), - &api_protocol), + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env::var("S3_ACCESS_KEY").unwrap_or(String::new()), + env::var("S3_SECRET_KEY").unwrap_or(String::new()), + &api_protocol, + ), proxy: None, } - }, + } _ => { if env::var("S3_BUCKET").is_ok() { println!("Using S3 uploader"); Uploader::S3 { - bucket: s3::Bucket::new(env("S3_BUCKET"), - env::var("S3_REGION").ok(), - env::var("S3_ACCESS_KEY").unwrap_or(String::new()), - env::var("S3_SECRET_KEY").unwrap_or(String::new()), - &api_protocol), + bucket: s3::Bucket::new( + env("S3_BUCKET"), + env::var("S3_REGION").ok(), + env::var("S3_ACCESS_KEY").unwrap_or(String::new()), + env::var("S3_SECRET_KEY").unwrap_or(String::new()), + &api_protocol, + ), proxy: None, } } else { println!("Using local uploader, crate files will be in the dist directory"); Uploader::Local } - }, + } }; let config = cargo_registry::Config { @@ -115,9 +122,12 @@ fn main() { let port = if heroku { 8888 } else { - env::var("PORT").ok().and_then(|s| s.parse().ok()).unwrap_or(8888) + env::var("PORT") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(8888) }; - let threads = if cargo_env == Env::Development {1} else {50}; + let threads = if cargo_env == Env::Development { 1 } else { 50 }; let mut cfg = civet::Config::new(); cfg.port(port).threads(threads).keep_alive(true); let _a = Server::start(cfg, app); diff --git a/src/bin/transfer-crates.rs b/src/bin/transfer-crates.rs index 817a1943d3f..48e507757bb 100644 --- a/src/bin/transfer-crates.rs +++ b/src/bin/transfer-crates.rs @@ -31,11 +31,17 @@ fn main() { fn transfer(tx: &postgres::transaction::Transaction) { let from = match env::args().nth(1) { - None => { println!("needs a from-user argument"); return } + None => { + println!("needs a from-user argument"); + return; + } Some(s) => s, }; let to = match env::args().nth(2) { - None => { println!("needs a to-user argument"); return } + None => { + println!("needs a to-user argument"); + return; + } Some(s) => s, }; @@ -54,15 +60,19 @@ fn transfer(tx: &postgres::transaction::Transaction) { get_confirm("continue?"); } - println!("Are you sure you want to transfer crates from {} to {}", - from.gh_login, to.gh_login); + println!( + "Are you sure you want to transfer crates from {} to {}", + from.gh_login, + to.gh_login + ); get_confirm("continue"); - let stmt = tx.prepare("SELECT * FROM crate_owners + let stmt = tx.prepare( + "SELECT * FROM crate_owners WHERE owner_id = $1 - AND owner_kind = $2") - .unwrap(); + AND owner_kind = $2", + ).unwrap(); let rows = stmt.query(&[&from.id, &(OwnerKind::User as i32)]).unwrap(); for row in rows.iter() { let id: i32 = row.get("id"); @@ -72,9 +82,11 @@ fn transfer(tx: &postgres::transaction::Transaction) { if owners.len() != 1 { println!("warning: not exactly one owner for {}", krate.name); } - let n = tx.execute("UPDATE crate_owners SET owner_id = $1 + let n = tx.execute( + "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 299d97558aa..e89c1b94580 100644 --- a/src/bin/update-downloads.rs +++ b/src/bin/update-downloads.rs @@ -17,8 +17,7 @@ static LIMIT: i64 = 1000; #[allow(dead_code)] // dead in tests fn main() { - let daemon = env::args().nth(1).as_ref().map(|s| &s[..]) - == Some("daemon"); + let daemon = env::args().nth(1).as_ref().map(|s| &s[..]) == Some("daemon"); let sleep = env::args().nth(2).map(|s| s.parse().unwrap()); loop { let conn = cargo_registry::db::connect_now(); @@ -27,7 +26,7 @@ fn main() { if daemon { std::thread::sleep(Duration::new(sleep.unwrap(), 0)); } else { - break + break; } } } @@ -37,12 +36,15 @@ fn update(conn: &postgres::GenericConnection) -> postgres::Result<()> { loop { // FIXME(rust-lang/rust#27401): weird declaration to make sure this // variable gets dropped. - let tx; tx = conn.transaction()?; + let tx; + tx = conn.transaction()?; { - let stmt = tx.prepare("SELECT * FROM version_downloads \ + let stmt = tx.prepare( + "SELECT * FROM version_downloads \ WHERE processed = FALSE AND id > $1 ORDER BY id ASC - LIMIT $2")?; + LIMIT $2", + )?; let mut rows = stmt.query(&[&max, &LIMIT])?; match collect(&tx, &mut rows)? { None => break, @@ -55,8 +57,7 @@ fn update(conn: &postgres::GenericConnection) -> postgres::Result<()> { Ok(()) } -fn collect(tx: &postgres::transaction::Transaction, - rows: &mut postgres::rows::Rows) -> postgres::Result> { +fn collect(tx: &postgres::transaction::Transaction, rows: &mut postgres::rows::Rows) -> postgres::Result> { // Anything older than 24 hours ago will be frozen and will not be queried // against again. let now = chrono::UTC::now(); @@ -67,9 +68,13 @@ fn collect(tx: &postgres::transaction::Transaction, let download: VersionDownload = Model::from_row(&row); assert!(map.insert(download.id, download).is_none()); } - println!("updating {} versions (cutoff {})", map.len(), now.to_rfc2822()); + println!( + "updating {} versions (cutoff {})", + map.len(), + now.to_rfc2822() + ); if map.len() == 0 { - return Ok(None) + return Ok(None); } let mut max = 0; @@ -79,50 +84,63 @@ fn collect(tx: &postgres::transaction::Transaction, max = *id; } if download.date > cutoff && download.counted == download.downloads { - continue + continue; } let amt = download.downloads - download.counted; // 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 + tx.execute( + "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 { - continue + continue; } let crate_id = Version::find(tx, download.version_id).unwrap().crate_id; // Update the total number of version downloads - tx.execute("UPDATE versions + tx.execute( + "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 - WHERE id = $2", &[&amt, &crate_id])?; + tx.execute( + "UPDATE crates SET downloads = downloads + $1 + WHERE id = $2", + &[&amt, &crate_id], + )?; // Update the total number of crate downloads for today - let cnt = tx.execute("UPDATE crate_downloads + let cnt = tx.execute( + "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 + tx.execute( + "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])?; + tx.execute( + "UPDATE metadata SET total_downloads = total_downloads + $1", + &[&total], + )?; Ok(Some(max)) } @@ -140,20 +158,21 @@ mod test { use cargo_registry::{Version, Crate, User, Model, env}; fn conn() -> postgres::Connection { - postgres::Connection::connect(&env("TEST_DATABASE_URL")[..], - postgres::TlsMode::None).unwrap() + postgres::Connection::connect(&env("TEST_DATABASE_URL")[..], postgres::TlsMode::None).unwrap() } - fn user(conn: &postgres::transaction::Transaction) -> User{ - User::find_or_insert(conn, 2, "login", None, None, None, - "access_token").unwrap() + fn user(conn: &postgres::transaction::Transaction) -> User { + User::find_or_insert(conn, 2, "login", None, None, None, "access_token").unwrap() } fn crate_downloads(tx: &postgres::transaction::Transaction, id: i32, expected: usize) { - let stmt = tx.prepare("SELECT * FROM crate_downloads - WHERE crate_id = $1").unwrap(); - let dl: i32 = stmt.query(&[&id]).unwrap().iter() - .next().unwrap().get("downloads"); + let stmt = tx.prepare( + "SELECT * FROM crate_downloads + WHERE crate_id = $1", + ).unwrap(); + let dl: i32 = stmt.query(&[&id]).unwrap().iter().next().unwrap().get( + "downloads", + ); assert_eq!(dl, expected as i32); } @@ -162,20 +181,38 @@ mod test { let conn = conn(); let tx = conn.transaction().unwrap(); let user = user(&tx); - let krate = Crate::find_or_insert(&tx, "foo", user.id, &None, &None, - &None, &None, &None, &None, - &None, None).unwrap(); - let version = Version::insert(&tx, krate.id, - &semver::Version::parse("1.0.0").unwrap(), - &HashMap::new(), &[]).unwrap(); - tx.execute("INSERT INTO version_downloads \ + let krate = Crate::find_or_insert( + &tx, + "foo", + user.id, + &None, + &None, + &None, + &None, + &None, + &None, + &None, + None, + ).unwrap(); + let version = Version::insert( + &tx, + krate.id, + &semver::Version::parse("1.0.0").unwrap(), + &HashMap::new(), + &[], + ).unwrap(); + tx.execute( + "INSERT INTO version_downloads \ (version_id) VALUES ($1)", - &[&version.id]).unwrap(); - tx.execute("INSERT INTO version_downloads \ + &[&version.id], + ).unwrap(); + tx.execute( + "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); @@ -189,21 +226,43 @@ mod test { let conn = conn(); let tx = conn.transaction().unwrap(); let user = user(&tx); - let krate = Crate::find_or_insert(&tx, "foo", user.id, &None, - &None, &None, &None, &None, - &None, &None, None).unwrap(); - let version = Version::insert(&tx, krate.id, - &semver::Version::parse("1.0.0").unwrap(), - &HashMap::new(), &[]).unwrap(); - tx.execute("INSERT INTO version_downloads \ + let krate = Crate::find_or_insert( + &tx, + "foo", + user.id, + &None, + &None, + &None, + &None, + &None, + &None, + &None, + None, + ).unwrap(); + let version = Version::insert( + &tx, + krate.id, + &semver::Version::parse("1.0.0").unwrap(), + &HashMap::new(), + &[], + ).unwrap(); + tx.execute( + "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 - WHERE version_id = $1").unwrap(); - let processed: bool = stmt.query(&[&version.id]).unwrap().iter() - .next().unwrap().get("processed"); + let stmt = tx.prepare( + "SELECT processed FROM version_downloads + WHERE version_id = $1", + ).unwrap(); + let processed: bool = stmt.query(&[&version.id]) + .unwrap() + .iter() + .next() + .unwrap() + .get("processed"); assert!(processed); } @@ -212,22 +271,44 @@ mod test { let conn = conn(); let tx = conn.transaction().unwrap(); let user = user(&tx); - let krate = Crate::find_or_insert(&tx, "foo", user.id, &None, - &None, &None, &None, &None, - &None, &None, None).unwrap(); - let version = Version::insert(&tx, krate.id, - &semver::Version::parse("1.0.0").unwrap(), - &HashMap::new(), &[]).unwrap(); + let krate = Crate::find_or_insert( + &tx, + "foo", + user.id, + &None, + &None, + &None, + &None, + &None, + &None, + &None, + None, + ).unwrap(); + let version = Version::insert( + &tx, + krate.id, + &semver::Version::parse("1.0.0").unwrap(), + &HashMap::new(), + &[], + ).unwrap(); let time = time::now_utc().to_timespec() - Duration::hours(2); - tx.execute("INSERT INTO version_downloads \ + tx.execute( + "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 - WHERE version_id = $1").unwrap(); - let processed: bool = stmt.query(&[&version.id]).unwrap().iter() - .next().unwrap().get("processed"); + let stmt = tx.prepare( + "SELECT processed FROM version_downloads + WHERE version_id = $1", + ).unwrap(); + let processed: bool = stmt.query(&[&version.id]) + .unwrap() + .iter() + .next() + .unwrap() + .get("processed"); assert!(!processed); } @@ -236,26 +317,48 @@ mod test { let conn = conn(); let tx = conn.transaction().unwrap(); let user = user(&tx); - let krate = Crate::find_or_insert(&tx, "foo", user.id, &None, - &None, &None, &None, &None, - &None, &None, None).unwrap(); - let version = Version::insert(&tx, krate.id, - &semver::Version::parse("1.0.0").unwrap(), - &HashMap::new(), &[]).unwrap(); - tx.execute("UPDATE versions + let krate = Crate::find_or_insert( + &tx, + "foo", + user.id, + &None, + &None, + &None, + &None, + &None, + &None, + &None, + None, + ).unwrap(); + let version = Version::insert( + &tx, + krate.id, + &semver::Version::parse("1.0.0").unwrap(), + &HashMap::new(), + &[], + ).unwrap(); + tx.execute( + "UPDATE versions SET updated_at = current_date - interval '2 hours'", - &[]).unwrap(); - tx.execute("UPDATE crates + &[], + ).unwrap(); + tx.execute( + "UPDATE crates SET updated_at = current_date - interval '2 hours'", - &[]).unwrap(); - tx.execute("INSERT INTO version_downloads \ + &[], + ).unwrap(); + tx.execute( + "INSERT INTO version_downloads \ (version_id, downloads, counted, date, processed) VALUES ($1, 2, 1, current_date, false)", - &[&version.id]).unwrap(); - tx.execute("INSERT INTO version_downloads \ + &[&version.id], + ).unwrap(); + tx.execute( + "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(); @@ -276,22 +379,42 @@ mod test { let conn = conn(); let tx = conn.transaction().unwrap(); let user = user(&tx); - let krate = Crate::find_or_insert(&tx, "foo", user.id, &None, - &None, &None, &None, &None, - &None, &None, None).unwrap(); - let version = Version::insert(&tx, krate.id, - &semver::Version::parse("1.0.0").unwrap(), - &HashMap::new(), &[]).unwrap(); - tx.execute("UPDATE versions + let krate = Crate::find_or_insert( + &tx, + "foo", + user.id, + &None, + &None, + &None, + &None, + &None, + &None, + &None, + None, + ).unwrap(); + let version = Version::insert( + &tx, + krate.id, + &semver::Version::parse("1.0.0").unwrap(), + &HashMap::new(), + &[], + ).unwrap(); + tx.execute( + "UPDATE versions SET updated_at = current_date - interval '2 days'", - &[]).unwrap(); - tx.execute("UPDATE crates + &[], + ).unwrap(); + tx.execute( + "UPDATE crates SET updated_at = current_date - interval '2 days'", - &[]).unwrap(); - tx.execute("INSERT INTO version_downloads \ + &[], + ).unwrap(); + tx.execute( + "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/categories.rs b/src/categories.rs index 6cb41b05669..83ea8017fc4 100644 --- a/src/categories.rs +++ b/src/categories.rs @@ -13,8 +13,7 @@ struct Category { } impl Category { - fn from_parent(slug: &str, name: &str, description: &str, parent: Option<&Category>) - -> Category { + fn from_parent(slug: &str, name: &str, description: &str, parent: Option<&Category>) -> Category { match parent { Some(parent) => { Category { @@ -35,17 +34,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!("Expected category TOML attribute '{}' to be a String", key)) - }) + 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(categories: &toml::Table, parent: Option<&Category>) -> CargoResult> { @@ -65,12 +63,13 @@ fn categories_from_toml(categories: &toml::Table, parent: Option<&Category>) -> if let Some(categories) = details.get("categories") { let categories = categories.as_table().chain_error(|| { - internal(&format_args!("child categories of {} were not a table", slug)) + internal(&format_args!( + "child categories of {} were not a table", + slug + )) })?; - result.extend( - categories_from_toml(categories, Some(&category))? - ); + result.extend(categories_from_toml(categories, Some(&category))?); } result.push(category) @@ -85,33 +84,37 @@ pub fn sync() -> CargoResult<()> { let categories = include_str!("./categories.toml"); let toml = toml::Parser::new(categories).parse().expect( - "Could not parse categories.toml" + "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("\ + 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.iter().map(|category| { - format!("LOWER('{}')", category.slug) - }).collect::>().join(","); + let in_clause = categories + .iter() + .map(|category| format!("LOWER('{}')", category.slug)) + .collect::>() + .join(","); - tx.execute(&format!("\ + tx.execute( + &format!( + "\ DELETE FROM categories \ WHERE slug NOT IN ({});", - in_clause), - &[] + in_clause + ), + &[], )?; tx.set_commit(); tx.finish().unwrap(); diff --git a/src/category.rs b/src/category.rs index f6f45cb2188..90a649aceca 100644 --- a/src/category.rs +++ b/src/category.rs @@ -15,7 +15,7 @@ use util::{RequestUtils, CargoResult, ChainError}; use {Model, Crate}; #[derive(Clone, Identifiable, Queryable)] -#[table_name="categories"] +#[table_name = "categories"] pub struct Category { pub id: i32, pub category: String, @@ -28,7 +28,7 @@ pub struct Category { #[derive(Associations, Insertable, Identifiable)] #[belongs_to(Category)] #[belongs_to(Crate)] -#[table_name="crates_categories"] +#[table_name = "crates_categories"] #[primary_key(crate_id, category_id)] pub struct CrateCategory { crate_id: i32, @@ -57,29 +57,36 @@ 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")?; + pub fn find_by_category(conn: &GenericConnection, name: &str) -> CargoResult { + let stmt = conn.prepare( + "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 \ - WHERE slug = LOWER($1)")?; + pub fn find_by_slug(conn: &GenericConnection, slug: &str) -> CargoResult { + let stmt = conn.prepare( + "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 { let Category { - crates_cnt, category, slug, description, created_at, .. + crates_cnt, + category, + slug, + description, + created_at, + .. } = self; EncodableCategory { id: slug.clone(), @@ -91,99 +98,107 @@ impl Category { } } - pub fn update_crate<'a>(conn: &PgConnection, - krate: &Crate, - slugs: &[&'a str]) -> QueryResult> { + pub fn update_crate<'a>(conn: &PgConnection, krate: &Crate, slugs: &[&'a str]) -> 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() + 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 }) + 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)?; + insert(&crate_categories) + .into(crates_categories::table) + .execute(conn)?; Ok(invalid_categories) }) } - pub fn update_crate_old(conn: &GenericConnection, - krate: &Crate, - categories: &[String]) -> CargoResult> { + pub fn update_crate_old(conn: &GenericConnection, krate: &Crate, categories: &[String]) -> CargoResult> { let old_categories = krate.categories(conn)?; - let old_categories_ids: HashSet<_> = old_categories.iter().map(|cat| { - cat.id - }).collect(); + let old_categories_ids: HashSet<_> = old_categories.iter().map(|cat| cat.id).collect(); // If a new category specified is not in the database, filter // it out and don't add it. Return it to be able to warn about it. let mut invalid_categories = vec![]; - let new_categories: Vec = categories.iter().flat_map(|c| { - match Category::find_by_slug(conn, c) { + 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 - }, - } - }).collect(); + } + }) + .collect(); - let new_categories_ids: HashSet<_> = new_categories.iter().map(|cat| { - cat.id - }).collect(); + let new_categories_ids: HashSet<_> = new_categories.iter().map(|cat| cat.id).collect(); let to_rm: Vec<_> = old_categories_ids - .difference(&new_categories_ids) - .cloned() - .collect(); + .difference(&new_categories_ids) + .cloned() + .collect(); let to_add: Vec<_> = new_categories_ids - .difference(&old_categories_ids) - .cloned() - .collect(); + .difference(&old_categories_ids) + .cloned() + .collect(); if !to_rm.is_empty() { - conn.execute("DELETE FROM crates_categories \ + conn.execute( + "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() { - let insert: Vec<_> = to_add.into_iter().map(|id| { - format!("({}, {})", krate.id, id) - }).collect(); + let insert: Vec<_> = to_add + .into_iter() + .map(|id| format!("({}, {})", krate.id, id)) + .collect(); let insert = insert.join(", "); - conn.execute(&format!("INSERT INTO crates_categories \ + conn.execute( + &format!( + "INSERT INTO crates_categories \ (crate_id, category_id) VALUES {}", - insert), - &[])?; + insert + ), + &[], + )?; } Ok(invalid_categories) } pub fn count_toplevel(conn: &GenericConnection) -> CargoResult { - let sql = format!("\ + let sql = format!( + "\ SELECT COUNT(*) \ FROM {} \ WHERE category NOT LIKE '%::%'", - Model::table_name(None:: - )); + Model::table_name(None::) + ); let stmt = conn.prepare(&sql)?; let rows = stmt.query(&[])?; Ok(rows.iter().next().unwrap().get("count")) } - pub fn toplevel(conn: &PgConnection, - sort: &str, - limit: i64, - offset: i64) -> QueryResult> { + pub fn toplevel(conn: &PgConnection, sort: &str, limit: i64, offset: i64) -> QueryResult> { use diesel::select; use diesel::expression::dsl::*; @@ -202,14 +217,13 @@ impl Category { WHERE split_part(c.slug, '::', 1) = c.slug GROUP BY c.id {} LIMIT {} OFFSET {}", - sort_sql, limit, offset + sort_sql, + limit, + offset ))).load(conn) } - pub fn toplevel_old(conn: &GenericConnection, - sort: &str, - limit: i64, - offset: i64) -> CargoResult> { + pub fn toplevel_old(conn: &GenericConnection, sort: &str, limit: i64, offset: i64) -> CargoResult> { let sort_sql = match sort { "crates" => "ORDER BY crates_cnt DESC", @@ -237,9 +251,9 @@ impl Category { Ok(categories) } - pub fn subcategories(&self, conn: &GenericConnection) - -> CargoResult> { - let stmt = conn.prepare("\ + 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 \ @@ -249,7 +263,8 @@ impl Category { ), 0) as crates_cnt \ FROM categories as c \ WHERE c.category ILIKE $1 || '::%' \ - AND c.category NOT ILIKE $1 || '::%::%'")?; + AND c.category NOT ILIKE $1 || '::%::%'", + )?; let rows = stmt.query(&[&self.category])?; Ok(rows.iter().map(|r| Model::from_row(&r)).collect()) @@ -257,7 +272,7 @@ impl Category { } #[derive(Insertable, Default)] -#[table_name="categories"] +#[table_name = "categories"] pub struct NewCategory<'a> { pub category: &'a str, pub slug: &'a str, @@ -277,8 +292,7 @@ impl<'a> NewCategory<'a> { return Ok(c); } - categories.filter(slug.eq(self.slug)) - .first(conn) + categories.filter(slug.eq(self.slug)).first(conn) } } @@ -293,7 +307,9 @@ impl Model for Category { description: row.get("description"), } } - fn table_name(_: Option) -> &'static str { "categories" } + fn table_name(_: Option) -> &'static str { + "categories" + } } /// Handles the `GET /categories` route. @@ -310,9 +326,14 @@ pub fn index(req: &mut Request) -> CargoResult { let total = Category::count_toplevel(conn)?; #[derive(RustcEncodable)] - struct R { categories: Vec, meta: Meta } + struct R { + categories: Vec, + meta: Meta, + } #[derive(RustcEncodable)] - struct Meta { total: i64 } + struct Meta { + total: i64, + } Ok(req.json(&R { categories: categories, @@ -325,9 +346,10 @@ pub fn show(req: &mut Request) -> CargoResult { let slug = &req.params()["category_id"]; let conn = req.tx()?; let cat = Category::find_by_slug(conn, slug)?; - let subcats = cat.subcategories(conn)?.into_iter().map(|s| { - s.encodable() - }).collect(); + let subcats = cat.subcategories(conn)? + .into_iter() + .map(|s| s.encodable()) + .collect(); let cat = cat.encodable(); let cat_with_subcats = EncodableCategoryWithSubcategories { id: cat.id, @@ -340,27 +362,41 @@ pub fn show(req: &mut Request) -> CargoResult { }; #[derive(RustcEncodable)] - struct R { category: EncodableCategoryWithSubcategories} + struct R { + category: EncodableCategoryWithSubcategories, + } Ok(req.json(&R { category: cat_with_subcats })) } /// Handles the `GET /category_slugs` route. pub fn slugs(req: &mut Request) -> CargoResult { let conn = req.tx()?; - let stmt = conn.prepare("SELECT slug FROM categories \ - ORDER BY slug")?; + let stmt = conn.prepare( + "SELECT slug FROM categories \ + ORDER BY slug", + )?; let rows = stmt.query(&[])?; #[derive(RustcEncodable)] - struct Slug { id: String, slug: String } + struct Slug { + id: String, + slug: String, + } - let slugs: Vec = rows.iter().map(|r| { - let slug: String = r.get("slug"); - Slug { id: slug.clone(), slug: slug } - }).collect(); + let slugs: Vec = rows.iter() + .map(|r| { + let slug: String = r.get("slug"); + Slug { + id: slug.clone(), + slug: slug, + } + }) + .collect(); #[derive(RustcEncodable)] - struct R { category_slugs: Vec } + struct R { + category_slugs: Vec, + } Ok(req.json(&R { category_slugs: slugs })) } @@ -373,23 +409,28 @@ 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").unwrap(); + conn.batch_execute("BEGIN; LOCK categories IN ACCESS EXCLUSIVE MODE") + .unwrap(); conn } #[test] fn category_toplevel_excludes_subcategories() { let conn = pg_connection(); - conn.batch_execute("INSERT INTO categories (category, slug) VALUES + conn.batch_execute( + "INSERT INTO categories (category, slug) VALUES ('Cat 2', 'cat2'), ('Cat 1', 'cat1'), ('Cat 1::sub', 'cat1::sub') - ").unwrap(); - - let categories = Category::toplevel(&conn, "", 10, 0).unwrap() - .into_iter().map(|c| c.category).collect::>(); + ", + ).unwrap(); + + let categories = Category::toplevel(&conn, "", 10, 0) + .unwrap() + .into_iter() + .map(|c| c.category) + .collect::>(); let expected = vec!["Cat 1".to_string(), "Cat 2".to_string()]; assert_eq!(expected, categories); } @@ -397,30 +438,47 @@ mod tests { #[test] 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 + conn.batch_execute( + "INSERT INTO categories (category, slug, crates_cnt) VALUES ('Cat 1', 'cat1', 0), ('Cat 2', 'cat2', 2), ('Cat 3', 'cat3', 1) - ").unwrap(); - - let categories = Category::toplevel(&conn, "crates", 10, 0).unwrap() - .into_iter().map(|c| c.category).collect::>(); - let expected = vec!["Cat 2".to_string(), "Cat 3".to_string(), "Cat 1".to_string()]; + ", + ).unwrap(); + + let categories = Category::toplevel(&conn, "crates", 10, 0) + .unwrap() + .into_iter() + .map(|c| c.category) + .collect::>(); + let expected = vec![ + "Cat 2".to_string(), + "Cat 3".to_string(), + "Cat 1".to_string(), + ]; assert_eq!(expected, categories); } #[test] fn category_toplevel_applies_limit_and_offset() { let conn = pg_connection(); - conn.batch_execute("INSERT INTO categories (category, slug) VALUES + conn.batch_execute( + "INSERT INTO categories (category, slug) VALUES ('Cat 1', 'cat1'), ('Cat 2', 'cat2') - ").unwrap(); - - let categories = Category::toplevel(&conn, "", 1, 0).unwrap() - .into_iter().map(|c| c.category).collect::>(); + ", + ).unwrap(); + + let categories = Category::toplevel(&conn, "", 1, 0) + .unwrap() + .into_iter() + .map(|c| c.category) + .collect::>(); let expected = vec!["Cat 1".to_string()]; assert_eq!(expected, categories); - let categories = Category::toplevel(&conn, "", 1, 1).unwrap() - .into_iter().map(|c| c.category).collect::>(); + let categories = Category::toplevel(&conn, "", 1, 1) + .unwrap() + .into_iter() + .map(|c| c.category) + .collect::>(); let expected = vec!["Cat 2".to_string()]; assert_eq!(expected, categories); } @@ -428,14 +486,19 @@ mod tests { #[test] fn category_toplevel_includes_subcategories_in_crate_cnt() { let conn = pg_connection(); - conn.batch_execute("INSERT INTO categories (category, slug, crates_cnt) VALUES + conn.batch_execute( + "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(); - - let categories = Category::toplevel(&conn, "crates", 10, 0).unwrap() - .into_iter().map(|c| (c.category, c.crates_cnt)).collect::>(); + ", + ).unwrap(); + + let categories = Category::toplevel(&conn, "crates", 10, 0) + .unwrap() + .into_iter() + .map(|c| (c.category, c.crates_cnt)) + .collect::>(); let expected = vec![ ("Cat 2".to_string(), 12), ("Cat 3".to_string(), 6), @@ -447,26 +510,28 @@ mod tests { #[test] fn category_toplevel_applies_limit_and_offset_after_grouping() { let conn = pg_connection(); - conn.batch_execute("INSERT INTO categories (category, slug, crates_cnt) VALUES + conn.batch_execute( + "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(); - - let categories = Category::toplevel(&conn, "crates", 2, 0).unwrap() - .into_iter().map(|c| (c.category, c.crates_cnt)).collect::>(); - let expected = vec![ - ("Cat 2".to_string(), 12), - ("Cat 3".to_string(), 6), - ]; + ", + ).unwrap(); + + let categories = Category::toplevel(&conn, "crates", 2, 0) + .unwrap() + .into_iter() + .map(|c| (c.category, c.crates_cnt)) + .collect::>(); + let expected = vec![("Cat 2".to_string(), 12), ("Cat 3".to_string(), 6)]; assert_eq!(expected, categories); - let categories = Category::toplevel(&conn, "crates", 2, 1).unwrap() - .into_iter().map(|c| (c.category, c.crates_cnt)).collect::>(); - let expected = vec![ - ("Cat 3".to_string(), 6), - ("Cat 1".to_string(), 3), - ]; + let categories = Category::toplevel(&conn, "crates", 2, 1) + .unwrap() + .into_iter() + .map(|c| (c.category, c.crates_cnt)) + .collect::>(); + let expected = vec![("Cat 3".to_string(), 6), ("Cat 1".to_string(), 3)]; assert_eq!(expected, categories); } } diff --git a/src/db.rs b/src/db.rs index 68a39c5a9c4..e139f9b2c32 100644 --- a/src/db.rs +++ b/src/db.rs @@ -59,11 +59,9 @@ pub fn tls_handshake() -> Box { // better solution in the future for certificate verification... impl TlsHandshake for MyHandshake { - fn tls_handshake(&self, - _domain: &str, - stream: Stream) - -> Result, Box> { - let stream = self.0.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream)?; + fn tls_handshake(&self, _domain: &str, stream: Stream) -> Result, Box> { + let stream = self.0 + .danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream)?; Ok(Box::new(stream)) } } @@ -75,8 +73,7 @@ pub fn tls_handshake() -> Box { } let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - builder.builder_mut() - .set_verify(SSL_VERIFY_NONE); + builder.builder_mut().set_verify(SSL_VERIFY_NONE); Box::new(MyHandshake(builder.build())) } @@ -183,23 +180,23 @@ impl Transaction { } impl Middleware for TransactionMiddleware { - fn before(&self, req: &mut Request) -> Result<(), Box> { + fn before(&self, req: &mut Request) -> Result<(), Box> { let app = req.app().clone(); req.mut_extensions().insert(Transaction::new(app)); Ok(()) } - fn after(&self, req: &mut Request, res: Result>) - -> Result> { - let tx = req.mut_extensions().pop::() - .expect("Transaction not present in request"); + fn after(&self, req: &mut Request, res: Result>) -> Result> { + 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 } @@ -225,24 +222,26 @@ pub trait RequestTransaction { impl RequestTransaction for T { fn db_conn(&self) -> CargoResult { - self.app().diesel_database.get() - .map_err(Into::into) + self.app().diesel_database.get().map_err(Into::into) } fn tx(&self) -> CargoResult<&GenericConnection> { - self.extensions().find::() + self.extensions() + .find::() .expect("Transaction not present in request") .tx() } fn rollback(&self) { - self.extensions().find::() + self.extensions() + .find::() .expect("Transaction not present in request") .rollback() } fn commit(&self) { - self.extensions().find::() + self.extensions() + .find::() .expect("Transaction not present in request") .commit() } diff --git a/src/dependency.rs b/src/dependency.rs index 08e3f3cc06f..b482d9f40cb 100644 --- a/src/dependency.rs +++ b/src/dependency.rs @@ -14,7 +14,7 @@ use version::Version; #[derive(Identifiable, Associations)] #[belongs_to(Version)] #[belongs_to(Crate)] -#[table_name="dependencies"] +#[table_name = "dependencies"] pub struct Dependency { pub id: i32, pub version_id: i32, @@ -57,7 +57,7 @@ pub enum Kind { } #[derive(Default, Insertable)] -#[table_name="dependencies"] +#[table_name = "dependencies"] pub struct NewDependency<'a> { pub version_id: i32, pub crate_id: i32, @@ -72,20 +72,37 @@ pub struct NewDependency<'a> { impl Dependency { // FIXME: Encapsulate this in a `NewDependency` struct #[cfg_attr(feature = "clippy", allow(too_many_arguments))] - pub fn insert(conn: &GenericConnection, version_id: i32, crate_id: i32, - req: &semver::VersionReq, kind: Kind, - optional: bool, default_features: bool, - features: &[String], target: &Option) - -> CargoResult { + pub fn insert( + conn: &GenericConnection, + version_id: i32, + crate_id: i32, + req: &semver::VersionReq, + kind: Kind, + optional: bool, + default_features: bool, + features: &[String], + target: &Option, + ) -> CargoResult { let req = req.to_string(); - let stmt = conn.prepare("INSERT INTO dependencies + let stmt = conn.prepare( + "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)])?; + RETURNING *", + )?; + let rows = stmt.query( + &[ + &version_id, + &crate_id, + &req, + &optional, + &default_features, + &features, + target, + &(kind as i32), + ], + )?; Ok(Model::from_row(&rows.iter().next().unwrap())) } @@ -108,65 +125,68 @@ 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), + ) } } -pub fn add_dependencies( - conn: &PgConnection, - deps: &[::upload::CrateDependency], - version_id: i32, -) -> CargoResult> { +pub fn add_dependencies(conn: &PgConnection, deps: &[::upload::CrateDependency], version_id: i32) -> CargoResult> { use diesel::insert; - let git_and_new_dependencies = deps.iter().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 \ + let git_and_new_dependencies = deps.iter() + .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(); - - 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), + information", + )); } - )) - }).collect::, _>>()?; - - let (git_deps, new_dependencies): (Vec<_>, Vec<_>) = - git_and_new_dependencies.into_iter().unzip(); - - insert(&new_dependencies).into(dependencies::table) + 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<_>) = git_and_new_dependencies.into_iter().unzip(); + + insert(&new_dependencies) + .into(dependencies::table) .execute(conn)?; Ok(git_deps) } 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 { @@ -183,7 +203,7 @@ impl Queryable for Dependency { 1 => Kind::Build, 2 => Kind::Dev, n => panic!("unknown kind: {}", n), - } + }, } } } @@ -205,11 +225,13 @@ impl Model for Dependency { 1 => Kind::Build, 2 => Kind::Dev, n => panic!("unknown kind: {}", n), - } + }, } } - fn table_name(_: Option) -> &'static str { "dependencies" } + fn table_name(_: Option) -> &'static str { + "dependencies" + } } impl Model for ReverseDependency { @@ -221,5 +243,7 @@ impl Model for ReverseDependency { } } - fn table_name(_: Option) -> &'static str { panic!("no table") } + fn table_name(_: Option) -> &'static str { + panic!("no table") + } } diff --git a/src/dist.rs b/src/dist.rs index 3ba232629bf..ba83b84d20f 100644 --- a/src/dist.rs +++ b/src/dist.rs @@ -11,7 +11,7 @@ pub struct Middleware { dist: Static, } -impl Default for Middleware { +impl Default for Middleware { fn default() -> Middleware { Middleware { handler: None, @@ -27,7 +27,7 @@ impl AroundMiddleware for Middleware { } impl Handler for Middleware { - fn call(&self, req: &mut Request) -> Result> { + fn call(&self, req: &mut Request) -> Result> { // First, attempt to serve a static file. If we're missing a static // file, then keep going. match self.dist.call(req) { @@ -37,9 +37,10 @@ impl Handler for Middleware { // Second, if we're requesting html, then we've only got one page so // serve up that page. Otherwise proxy on to the rest of the app. - let wants_html = req.headers().find("Accept").map(|accept| { - accept.iter().any(|s| s.contains("html")) - }).unwrap_or(false); + let wants_html = req.headers() + .find("Accept") + .map(|accept| accept.iter().any(|s| s.contains("html"))) + .unwrap_or(false); if wants_html { self.dist.call(&mut RequestProxy { other: req, diff --git a/src/download.rs b/src/download.rs index 0df4d0c8cee..d83350bbbb2 100644 --- a/src/download.rs +++ b/src/download.rs @@ -20,8 +20,11 @@ pub struct VersionDownload { } #[derive(Insertable)] -#[table_name="version_downloads"] -struct NewVersionDownload(#[column_name(version_id)] i32); +#[table_name = "version_downloads"] +struct NewVersionDownload( + #[column_name(version_id)] + i32 +); #[derive(RustcEncodable, RustcDecodable)] pub struct EncodableVersionDownload { @@ -40,11 +43,13 @@ impl VersionDownload { // nothing else. We have lots of other counters, but they're // all updated later on via the update-downloads script. let new_download = NewVersionDownload(version); - let downloads_row = new_download - .on_conflict((version_id, date), do_update().set( - downloads.eq(downloads + 1) - )); - diesel::insert(&downloads_row).into(version_downloads).execute(conn)?; + let downloads_row = new_download.on_conflict( + (version_id, date), + do_update().set(downloads.eq(downloads + 1)), + ); + diesel::insert(&downloads_row) + .into(version_downloads) + .execute(conn)?; Ok(()) } @@ -70,5 +75,7 @@ impl Model for VersionDownload { } } - fn table_name(_: Option) -> &'static str { "version_downloads" } + fn table_name(_: Option) -> &'static str { + "version_downloads" + } } diff --git a/src/git.rs b/src/git.rs index ac97a3d1ab0..810e16b5855 100644 --- a/src/git.rs +++ b/src/git.rs @@ -34,14 +34,14 @@ pub struct Dependency { } fn index_file(base: &Path, name: &str) -> PathBuf { - let name = name.chars().flat_map(|c| c.to_lowercase()).collect::(); + let name = name.chars() + .flat_map(|c| c.to_lowercase()) + .collect::(); match name.len() { 1 => base.join("1").join(&name), 2 => base.join("2").join(&name), 3 => base.join("3").join(&name[..1]).join(&name), - _ => base.join(&name[0..2]) - .join(&name[2..4]) - .join(&name), + _ => base.join(&name[0..2]).join(&name[2..4]).join(&name), } } @@ -56,7 +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; @@ -64,45 +66,55 @@ pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> { f.write_all(new.as_bytes())?; f.write_all(b"\n")?; - Ok((format!("Updating crate `{}#{}`", krate.name, krate.vers), - dst.clone())) + Ok(( + format!("Updating crate `{}#{}`", krate.name, krate.vers), + dst.clone(), + )) }) } -pub fn yank(app: &App, krate: &str, version: &semver::Version, - yanked: bool) -> CargoResult<()> { +pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> { let repo = app.git_repo.lock().unwrap(); 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::>>(); + 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())) + Ok(( + format!( + "{} crate `{}#{}`", + if yanked { "Yanking" } else { "Unyanking" }, + krate, + version + ), + dst.clone(), + )) }) } fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> - where F: FnMut() -> CargoResult<(String, PathBuf)> +where + F: FnMut() -> CargoResult<(String, PathBuf)>, { let repo_path = repo.workdir().unwrap(); @@ -116,8 +128,9 @@ fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> // git add $file let mut index = repo.index()?; let mut repo_path = repo_path.iter(); - let dst = dst.iter().skip_while(|s| Some(*s) == repo_path.next()) - .collect::(); + let dst = dst.iter() + .skip_while(|s| Some(*s) == repo_path.next()) + .collect::(); index.add_path(&dst)?; index.write()?; let tree_id = index.write_tree()?; @@ -127,7 +140,14 @@ fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> 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; @@ -152,9 +172,12 @@ fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> 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)?; @@ -166,13 +189,9 @@ fn commit_and_push(repo: &git2::Repository, mut f: F) -> CargoResult<()> Err(internal("Too many rebase failures")) } -pub fn credentials(_user: &str, _user_from_url: Option<&str>, - _cred: git2::CredentialType) - -> Result { +pub fn credentials(_user: &str, _user_from_url: Option<&str>, _cred: git2::CredentialType) -> Result { match (env::var("GIT_HTTP_USER"), env::var("GIT_HTTP_PWD")) { - (Ok(u), Ok(p)) => { - git2::Cred::userpass_plaintext(&u, &p) - } - _ => Err(git2::Error::from_str("no authentication set")) + (Ok(u), Ok(p)) => git2::Cred::userpass_plaintext(&u, &p), + _ => Err(git2::Error::from_str("no authentication set")), } } diff --git a/src/http.rs b/src/http.rs index a62cd3ad1b7..4767239958a 100644 --- a/src/http.rs +++ b/src/http.rs @@ -10,15 +10,18 @@ use std::str; /// Does all the nonsense for sending a GET to Github. Doesn't handle parsing /// because custom error-code handling may be desirable. Use /// `parse_github_response` to handle the "common" processing of responses. -pub fn github(app: &App, url: &str, auth: &Token) - -> Result<(Easy, Vec), curl::Error> { +pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec), curl::Error> { let url = format!("{}://api.github.com{}", app.config.api_protocol, url); info!("GITHUB HTTP: {}", url); let mut headers = List::new(); - headers.append("Accept: application/vnd.github.v3+json").unwrap(); + headers + .append("Accept: application/vnd.github.v3+json") + .unwrap(); headers.append("User-Agent: hello!").unwrap(); - headers.append(&format!("Authorization: token {}", auth.access_token)).unwrap(); + headers + .append(&format!("Authorization: token {}", auth.access_token)) + .unwrap(); let mut handle = app.handle(); handle.url(&url).unwrap(); @@ -28,33 +31,40 @@ pub fn github(app: &App, url: &str, auth: &Token) let mut data = Vec::new(); { let mut transfer = handle.transfer(); - transfer.write_function(|buf| { - data.extend_from_slice(buf); - Ok(buf.len()) - }).unwrap(); + transfer + .write_function(|buf| { + data.extend_from_slice(buf); + Ok(buf.len()) + }) + .unwrap(); transfer.perform()?; } Ok((handle, data)) } /// Checks for normal responses -pub fn parse_github_response(mut resp: Easy, data: &[u8]) - -> CargoResult { +pub fn parse_github_response(mut resp: Easy, data: &[u8]) -> CargoResult { 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")); + https://crates.io/login", + )); } n => { let resp = String::from_utf8_lossy(data); - return Err(internal(&format_args!("didn't get a 200 result from \ - github, got {} with: {}", n, resp))); + return Err(internal(&format_args!( + "didn't get a 200 result from \ + github, got {} with: {}", + n, + resp + ))); } } @@ -62,9 +72,7 @@ pub fn parse_github_response(mut resp: Easy, data: &[u8]) internal("github didn't send a utf8-response") })?; - json::decode(json).chain_error(|| { - internal("github didn't send a valid json response") - }) + json::decode(json).chain_error(|| internal("github didn't send a valid json response")) } /// Gets a token with the given string as the access token, but all diff --git a/src/keyword.rs b/src/keyword.rs index 6c53d5877ad..0b7990eac10 100644 --- a/src/keyword.rs +++ b/src/keyword.rs @@ -24,7 +24,7 @@ pub struct Keyword { #[derive(Associations, Insertable, Identifiable)] #[belongs_to(Keyword)] #[belongs_to(Crate)] -#[table_name="crates_keywords"] +#[table_name = "crates_keywords"] #[primary_key(crate_id, keyword_id)] pub struct CrateKeyword { crate_id: i32, @@ -40,8 +40,7 @@ pub struct EncodableKeyword { } impl Keyword { - pub fn find_by_keyword(conn: &PgConnection, name: &str) - -> QueryResult { + pub fn find_by_keyword(conn: &PgConnection, name: &str) -> QueryResult { keywords::table .filter(keywords::keyword.eq(::lower(name))) .first(&*conn) @@ -52,16 +51,15 @@ impl Keyword { use diesel::expression::dsl::any; #[derive(Insertable)] - #[table_name="keywords"] + #[table_name = "keywords"] struct NewKeyword<'a> { keyword: &'a str, } - let lowercase_names: Vec<_> = names.iter() - .map(|s| s.to_lowercase()) - .collect(); + let lowercase_names: Vec<_> = names.iter().map(|s| s.to_lowercase()).collect(); - let new_keywords: Vec<_> = lowercase_names.iter() + let new_keywords: Vec<_> = lowercase_names + .iter() .map(|s| NewKeyword { keyword: s }) .collect(); @@ -77,14 +75,22 @@ impl Keyword { } pub fn valid_name(name: &str) -> bool { - if name.is_empty() { return false } + if name.is_empty() { + 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 { - let Keyword { crates_cnt, keyword, created_at, .. } = self; + let Keyword { + crates_cnt, + keyword, + created_at, + .. + } = self; EncodableKeyword { id: keyword.clone(), created_at: ::encode_time(created_at), @@ -93,17 +99,23 @@ impl Keyword { } } - pub fn update_crate(conn: &PgConnection, - krate: &Crate, - keywords: &[&str]) -> QueryResult<()> { + 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) + 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(()) }) @@ -119,7 +131,9 @@ impl Model for Keyword { keyword: row.get("keyword"), } } - fn table_name(_: Option) -> &'static str { "keywords" } + fn table_name(_: Option) -> &'static str { + "keywords" + } } /// Handles the `GET /keywords` route. @@ -148,12 +162,18 @@ pub fn index(req: &mut Request) -> CargoResult { let data = query.load::<(Keyword, i64)>(&*conn)?; let total = data.get(0).map(|&(_, t)| t).unwrap_or(0); let kws = data.into_iter() - .map(|(k, _)| k.encodable()).collect::>(); + .map(|(k, _)| k.encodable()) + .collect::>(); #[derive(RustcEncodable)] - struct R { keywords: Vec, meta: Meta } + struct R { + keywords: Vec, + meta: Meta, + } #[derive(RustcEncodable)] - struct Meta { total: i64 } + struct Meta { + total: i64, + } Ok(req.json(&R { keywords: kws, @@ -169,6 +189,8 @@ pub fn show(req: &mut Request) -> CargoResult { let kw = Keyword::find_by_keyword(&conn, name)?; #[derive(RustcEncodable)] - struct R { keyword: EncodableKeyword } + struct R { + keyword: EncodableKeyword, + } Ok(req.json(&R { keyword: kw.encodable() })) } diff --git a/src/krate.rs b/src/krate.rs index 9323825567c..cb77d4b3be9 100644 --- a/src/krate.rs +++ b/src/krate.rs @@ -56,16 +56,33 @@ 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; @@ -101,7 +118,7 @@ pub struct CrateLinks { } #[derive(Insertable, AsChangeset, Default)] -#[table_name="crates"] +#[table_name = "crates"] #[primary_key(name, max_upload_size)] // This is actually just to skip updating them pub struct NewCrate<'a> { pub name: &'a str, @@ -115,12 +132,7 @@ pub struct NewCrate<'a> { } impl<'a> NewCrate<'a> { - pub fn create_or_update( - mut self, - conn: &PgConnection, - license_file: Option<&str>, - uploader: i32, - ) -> CargoResult { + pub fn create_or_update(mut self, conn: &PgConnection, license_file: Option<&str>, uploader: i32) -> CargoResult { use diesel::update; self.validate(license_file)?; @@ -130,13 +142,14 @@ impl<'a> NewCrate<'a> { // 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) + return Ok(krate); } - let target = crates::table.filter( - canon_crate_name(crates::name) - .eq(canon_crate_name(self.name))); - update(target).set(&self) + 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) @@ -147,19 +160,29 @@ impl<'a> NewCrate<'a> { fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> { let url = match url { Some(s) => s, - None => return Ok(()) + None => return Ok(()), }; 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!("`{}` has an invalid url \ - scheme: `{}`", field, s))) + s => { + return Err(human(&format_args!( + "`{}` has an invalid url \ + scheme: `{}`", + field, + s + ))) + } } if url.cannot_be_a_base() { - return Err(human(&format_args!("`{}` must have relative scheme \ - data: {}", field, url))) + return Err(human(&format_args!( + "`{}` must have relative scheme \ + data: {}", + field, + url + ))); } Ok(()) } @@ -174,10 +197,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 \ + 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 @@ -193,9 +220,13 @@ 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 { @@ -208,7 +239,8 @@ impl<'a> NewCrate<'a> { use diesel::insert; conn.transaction(|| { - let maybe_inserted = insert(&self.on_conflict_do_nothing()).into(crates) + let maybe_inserted = insert(&self.on_conflict_do_nothing()) + .into(crates) .returning(ALL_COLUMNS) .get_result::(conn) .optional()?; @@ -220,8 +252,7 @@ impl<'a> NewCrate<'a> { created_by: user_id, owner_kind: OwnerKind::User as i32, }; - insert(&owner).into(crate_owners::table) - .execute(conn)?; + insert(&owner).into(crate_owners::table).execute(conn)?; } Ok(maybe_inserted) @@ -232,21 +263,20 @@ impl<'a> NewCrate<'a> { impl Crate { pub fn by_name(name: &str) -> CrateQuery { Crate::all() - .filter( - canon_crate_name(crates::name).eq( - canon_crate_name(name)) - ).into_boxed() + .filter(canon_crate_name(crates::name).eq(canon_crate_name(name))) + .into_boxed() } pub fn all() -> Select { crates::table.select(ALL_COLUMNS) } - pub fn find_by_name(conn: &GenericConnection, - name: &str) -> CargoResult { - let stmt = conn.prepare("SELECT * FROM crates \ + pub fn find_by_name(conn: &GenericConnection, name: &str) -> CargoResult { + let stmt = conn.prepare( + "SELECT * FROM crates \ WHERE canon_crate_name(name) = - canon_crate_name($1) LIMIT 1")?; + canon_crate_name($1) LIMIT 1", + )?; let rows = stmt.query(&[&name])?; let row = rows.iter().next(); let row = row.chain_error(|| NotFound)?; @@ -255,18 +285,19 @@ impl Crate { // This is cleaned up by the diesel port #[cfg_attr(feature = "lint", allow(too_many_arguments))] - pub fn find_or_insert(conn: &GenericConnection, - name: &str, - user_id: i32, - description: &Option, - homepage: &Option, - documentation: &Option, - readme: &Option, - repository: &Option, - license: &Option, - license_file: &Option, - max_upload_size: Option) - -> CargoResult { + pub fn find_or_insert( + conn: &GenericConnection, + name: &str, + user_id: i32, + description: &Option, + homepage: &Option, + documentation: &Option, + readme: &Option, + repository: &Option, + license: &Option, + license_file: &Option, + max_upload_size: Option, + ) -> CargoResult { let description = description.as_ref().map(|s| &s[..]); let homepage = homepage.as_ref().map(|s| &s[..]); let documentation = documentation.as_ref().map(|s| &s[..]); @@ -294,7 +325,8 @@ impl Crate { } // TODO: like with users, this is sadly racy - let stmt = conn.prepare("UPDATE crates + let stmt = conn.prepare( + "UPDATE crates SET documentation = $1, homepage = $2, description = $3, @@ -303,86 +335,127 @@ impl Crate { repository = $6 WHERE canon_crate_name(name) = canon_crate_name($7) - RETURNING *")?; - let rows = stmt.query(&[&documentation, &homepage, - &description, &readme, - &license, &repository, - &name])?; + RETURNING *", + )?; + let rows = stmt.query( + &[ + &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 + let stmt = conn.prepare( + "SELECT 1 FROM reserved_crate_names WHERE canon_crate_name(name) = - canon_crate_name($1)")?; + canon_crate_name($1)", + )?; let rows = stmt.query(&[&name])?; if !rows.is_empty() { - return Err(human("cannot upload a crate with a reserved name")) + return Err(human("cannot upload a crate with a reserved name")); } - let stmt = conn.prepare("INSERT INTO crates + let stmt = conn.prepare( + "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") - })?); - - conn.execute("INSERT INTO crate_owners + 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"), + )?); + + conn.execute( + "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<()> { let url = match url { Some(s) => s, - None => return Ok(()) + None => return Ok(()), }; 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!("`{}` has an invalid url \ - scheme: `{}`", field, s))) + s => { + return Err(human(&format_args!( + "`{}` has an invalid url \ + scheme: `{}`", + field, + s + ))) + } } if url.cannot_be_a_base() { - return Err(human(&format_args!("`{}` must have relative scheme \ - data: {}", field, url))) + return Err(human(&format_args!( + "`{}` must have relative scheme \ + data: {}", + field, + url + ))); } Ok(()) } fn validate_license(license: Option<&str>) -> CargoResult<()> { - license.iter().flat_map(|s| s.split('/')) - .map(license_exprs::validate_license_expr) - .collect::, _>>() - .map(|_| ()) - .map_err(|e| human(&format_args!("{}; see http://opensource.org/licenses \ + license + .iter() + .flat_map(|s| s.split('/')) + .map(license_exprs::validate_license_expr) + .collect::, _>>() + .map(|_| ()) + .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 + )) + }) } } pub fn valid_name(name: &str) -> bool { - let under_max_length = name.chars() - .take(MAX_NAME_LENGTH + 1) - .count() <= MAX_NAME_LENGTH; + let under_max_length = name.chars().take(MAX_NAME_LENGTH + 1).count() <= MAX_NAME_LENGTH; Crate::valid_ident(name) && under_max_length } fn valid_ident(name: &str) -> bool { - if name.is_empty() { return false } + if name.is_empty() { + 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 { @@ -399,23 +472,30 @@ impl Crate { parts.next().is_none() } - pub fn minimal_encodable(self, - max_version: semver::Version, - badges: Option>, exact_match: bool) -> EncodableCrate { + pub fn minimal_encodable(self, max_version: semver::Version, badges: Option>, exact_match: bool) -> EncodableCrate { self.encodable(max_version, None, None, None, badges, exact_match) } - pub fn encodable(self, - max_version: semver::Version, - versions: Option>, - keywords: Option<&[Keyword]>, - categories: Option<&[Category]>, - badges: Option>, - exact_match: bool) - -> EncodableCrate { + pub fn encodable( + self, + max_version: semver::Version, + versions: Option>, + keywords: Option<&[Keyword]>, + categories: Option<&[Category]>, + badges: Option>, + exact_match: bool, + ) -> EncodableCrate { let Crate { - name, created_at, updated_at, downloads, description, - homepage, documentation, license, repository, .. + name, + created_at, + updated_at, + downloads, + description, + homepage, + documentation, + license, + repository, + .. } = self; let versions_link = match versions { Some(..) => None, @@ -423,9 +503,7 @@ impl Crate { }; let keyword_ids = keywords.map(|kws| kws.iter().map(|kw| kw.keyword.clone()).collect()); let category_ids = categories.map(|cats| cats.iter().map(|cat| cat.slug.clone()).collect()); - let badges = badges.map(|bs| { - bs.into_iter().map(|b| b.encodable()).collect() - }); + let badges = badges.map(|bs| bs.into_iter().map(|b| b.encodable()).collect()); EncodableCrate { id: name.clone(), name: name.clone(), @@ -447,7 +525,7 @@ impl Crate { version_downloads: format!("/api/v1/crates/{}/downloads", name), versions: versions_link, owners: Some(format!("/api/v1/crates/{}/owners", name)), - reverse_dependencies: format!("/api/v1/crates/{}/reverse_dependencies", name) + reverse_dependencies: format!("/api/v1/crates/{}/reverse_dependencies", name), }, } } @@ -455,7 +533,8 @@ impl Crate { pub fn max_version(&self, conn: &PgConnection) -> CargoResult { use schema::versions::dsl::*; - let vs = Version::belonging_to(self).select(num) + let vs = Version::belonging_to(self) + .select(num) .filter(yanked.eq(false)) .load::(conn)? .into_iter() @@ -464,34 +543,42 @@ impl Crate { } pub fn max_version_old(&self, conn: &GenericConnection) -> CargoResult { - let stmt = conn.prepare("SELECT num FROM versions WHERE crate_id = $1 - AND yanked = 'f'")?; + let stmt = conn.prepare( + "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")?; + let stmt = conn.prepare( + "SELECT * FROM versions \ + WHERE crate_id = $1", + )?; let rows = stmt.query(&[&self.id])?; - let mut ret = rows.iter().map(|r| { - Model::from_row(&r) - }).collect::>(); + let mut ret = rows.iter() + .map(|r| Model::from_row(&r)) + .collect::>(); ret.sort_by(|a, b| b.num.cmp(&a.num)); Ok(ret) } pub fn owners(&self, conn: &PgConnection) -> CargoResult> { - let base_query = CrateOwner::belonging_to(self) - .filter(crate_owners::deleted.eq(false)); - let users = base_query.inner_join(users::table) + let base_query = CrateOwner::belonging_to(self).filter(crate_owners::deleted.eq(false)); + let users = base_query + .inner_join(users::table) .select(users::all_columns) .filter(crate_owners::owner_kind.eq(OwnerKind::User as i32)) .load(conn)? .into_iter() .map(Owner::User); - let teams = base_query.inner_join(teams::table) + let teams = base_query + .inner_join(teams::table) .select(teams::all_columns) .filter(crate_owners::owner_kind.eq(OwnerKind::Team as i32)) .load(conn)? @@ -502,20 +589,24 @@ impl Crate { } pub fn owners_old(&self, conn: &GenericConnection) -> CargoResult> { - let stmt = conn.prepare("SELECT * FROM users + let stmt = conn.prepare( + "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")?; + AND crate_owners.owner_kind = $2", + )?; let user_rows = stmt.query(&[&self.id, &(OwnerKind::User as i32)])?; - let stmt = conn.prepare("SELECT * FROM teams + let stmt = conn.prepare( + "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")?; + AND crate_owners.owner_kind = $2", + )?; let team_rows = stmt.query(&[&self.id, &(OwnerKind::Team as i32)])?; let mut owners = vec![]; @@ -524,26 +615,27 @@ impl Crate { Ok(owners) } - pub fn owner_add( - &self, - app: &App, - conn: &PgConnection, - req_user: &User, - login: &str, - ) -> CargoResult<()> { + pub fn owner_add(&self, app: &App, conn: &PgConnection, req_user: &User, login: &str) -> CargoResult<()> { let owner = match Owner::find_by_login(conn, login) { - Ok(owner @ Owner::User(_)) => { owner } - Ok(Owner::Team(team)) => if team.contains_user(app, req_user)? { - Owner::Team(team) - } else { - return Err(human(&format_args!("only members of {} can add it as \ - an owner", login))); - }, - Err(err) => if login.contains(':') { - Owner::Team(Team::create(app, conn, login, req_user)?) - } else { - return Err(err); - }, + Ok(owner @ Owner::User(_)) => owner, + Ok(Owner::Team(team)) => { + if team.contains_user(app, req_user)? { + Owner::Team(team) + } else { + return Err(human(&format_args!( + "only members of {} can add it as \ + an owner", + login + ))); + } + } + Err(err) => { + if login.contains(':') { + Owner::Team(Team::create(app, conn, login, req_user)?) + } else { + return Err(err); + } + } }; let crate_owner = CrateOwner { @@ -553,72 +645,71 @@ impl Crate { 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) + crate_owners::table.primary_key(), + do_update().set(crate_owners::deleted.eq(false)), + )).into(crate_owners::table) .execute(conn)?; Ok(()) } - pub fn owner_remove(&self, - conn: &PgConnection, - _req_user: &User, - login: &str) -> CargoResult<()> { + pub fn owner_remove(&self, conn: &PgConnection, _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 target = crate_owners::table.find(( - self.id(), - owner.id(), - owner.kind() as i32, - )); - diesel::update(target).set(crate_owners::deleted.eq(true)) + let target = crate_owners::table.find((self.id(), owner.id(), owner.kind() as i32)); + diesel::update(target) + .set(crate_owners::deleted.eq(true)) .execute(conn)?; Ok(()) } - pub fn add_version(&mut self, - conn: &GenericConnection, - ver: &semver::Version, - features: &HashMap>, - authors: &[String]) - -> CargoResult { + pub fn add_version( + &mut self, + conn: &GenericConnection, + ver: &semver::Version, + features: &HashMap>, + 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 + let stmt = conn.prepare( + "SELECT keywords.* FROM keywords LEFT JOIN crates_keywords ON keywords.id = crates_keywords.keyword_id - WHERE crates_keywords.crate_id = $1")?; + 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 \ + 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")?; + 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) - pub fn reverse_dependencies(&self, - conn: &GenericConnection, - offset: i64, - limit: i64) - -> CargoResult<(Vec, i64)> { + pub fn reverse_dependencies(&self, conn: &GenericConnection, offset: i64, limit: i64) -> CargoResult<(Vec, i64)> { let stmt = conn.prepare(include_str!("krate_reverse_dependencies.sql"))?; let rows = stmt.query(&[&self.id, &offset, &limit])?; @@ -627,10 +718,7 @@ impl Crate { } else { rows.get(0).get("total") }; - let vec: Vec<_> = rows - .iter() - .map(|r| Model::from_row(&r)) - .collect(); + let vec: Vec<_> = rows.iter().map(|r| Model::from_row(&r)).collect(); Ok((vec, cnt)) } @@ -653,7 +741,9 @@ impl Model for Crate { max_upload_size: row.get("max_upload_size"), } } - fn table_name(_: Option) -> &'static str { "crates" } + fn table_name(_: Option) -> &'static str { + "crates" + } } /// Handles the `GET /crates` route. @@ -668,7 +758,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(); @@ -683,7 +777,11 @@ pub fn index(req: &mut Request) -> CargoResult { let q = plainto_tsquery(q_string); query = query.filter(q.matches(crates::textsearchable_index_col)); - query = query.select((ALL_COLUMNS, sql::("COUNT(*) OVER()"), crates::name.eq(q_string))); + query = query.select(( + ALL_COLUMNS, + sql::("COUNT(*) OVER()"), + crates::name.eq(q_string), + )); let perfect_match = crates::name.eq(q_string).desc(); if sort == "downloads" { query = query.order((perfect_match, crates::downloads.desc())); @@ -694,41 +792,61 @@ pub fn index(req: &mut Request) -> CargoResult { } if let Some(cat) = params.get("category") { - query = query.filter(crates::id.eq_any( - crates_categories::table.select(crates_categories::crate_id) - .inner_join(categories::table) - .filter(categories::slug.eq(cat).or( - categories::slug.like(format!("{}::%", cat)))) - )); + query = query.filter( + crates::id.eq_any( + crates_categories::table + .select(crates_categories::crate_id) + .inner_join(categories::table) + .filter(categories::slug.eq(cat).or(categories::slug.like(format!( + "{}::%", + cat + )))), + ), + ); } if let Some(kw) = params.get("keyword") { - query = query.filter(crates::id.eq_any( - crates_keywords::table.select(crates_keywords::crate_id) - .inner_join(keywords::table) - .filter(::lower(keywords::keyword).eq(::lower(kw))) - )); + query = query.filter( + crates::id.eq_any( + crates_keywords::table + .select(crates_keywords::crate_id) + .inner_join(keywords::table) + .filter(::lower(keywords::keyword).eq(::lower(kw))), + ), + ); } else if let Some(letter) = params.get("letter") { - let pattern = format!("{}%", letter.chars().next().unwrap() - .to_lowercase().collect::()); + let pattern = format!( + "{}%", + letter + .chars() + .next() + .unwrap() + .to_lowercase() + .collect::() + ); 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)) - )); + } 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)), + ), + ); } 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)) + follows::table.select(follows::crate_id).filter( + follows::user_id.eq(req.user()?.id), + ), )); } let data = query.load::<(Crate, i64, bool)>(&*conn)?; let total = data.get(0).map(|&(_, t, _)| t).unwrap_or(0); - let crates = data.iter().map(|&(ref c, _, _)| c.clone()).collect::>(); + let crates = data.iter() + .map(|&(ref c, _, _)| c.clone()) + .collect::>(); let perfect_matches = data.into_iter().map(|(_, _, b)| b).collect::>(); let versions = Version::belonging_to(&crates) @@ -737,18 +855,32 @@ pub fn index(req: &mut Request) -> CargoResult { .into_iter() .map(|versions| Version::max(versions.into_iter().map(|v| v.num))); - 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)) - }).collect::>()?; + 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, + )) + }) + .collect::>()?; #[derive(RustcEncodable)] - struct R { crates: Vec, meta: Meta } + struct R { + crates: Vec, + meta: Meta, + } #[derive(RustcEncodable)] - struct Meta { total: i64 } + struct Meta { + total: i64, + } Ok(req.json(&R { crates: crates, @@ -762,7 +894,8 @@ pub fn summary(req: &mut Request) -> CargoResult { let conn = req.db_conn()?; let num_crates = crates.count().get_result(&*conn)?; - let num_downloads = metadata::table.select(metadata::total_downloads) + let num_downloads = metadata::table + .select(metadata::total_downloads) .get_result(&*conn)?; let encode_crates = |krates: Vec| -> CargoResult> { @@ -774,25 +907,30 @@ pub fn summary(req: &mut Request) -> CargoResult { .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)) - }).collect() + Ok(krate.minimal_encodable(max_version, None, false)) + }) + .collect() }; - let new_crates = crates.order(created_at.desc()) + let new_crates = crates + .order(created_at.desc()) .select(ALL_COLUMNS) .limit(10) .load(&*conn)?; - let just_updated = crates.filter(updated_at.ne(created_at)) + let just_updated = crates + .filter(updated_at.ne(created_at)) .order(updated_at.desc()) .select(ALL_COLUMNS) .limit(10) .load(&*conn)?; - let most_downloaded = crates.order(downloads.desc()) + let most_downloaded = crates + .order(downloads.desc()) .select(ALL_COLUMNS) .limit(10) .load(&*conn)?; - let popular_keywords = keywords::table.order(keywords::crates_cnt.desc()) + let popular_keywords = keywords::table + .order(keywords::crates_cnt.desc()) .limit(10) .load(&*conn)? .into_iter() @@ -844,8 +982,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)] @@ -855,16 +994,24 @@ pub fn show(req: &mut Request) -> CargoResult { keywords: Vec, categories: Vec, } - Ok(req.json(&R { - krate: krate.clone().encodable( - max_version, Some(ids), Some(&kws), Some(&cats), 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(), - })) + Ok( + req.json(&R { + krate: krate.clone().encodable( + max_version, + Some(ids), + Some(&kws), + Some(&cats), + 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(), + }), + ) } /// Handles the `PUT /crates/new` route. @@ -874,15 +1021,23 @@ pub fn new(req: &mut Request) -> CargoResult { let name = &*new_crate.name; let vers = &*new_crate.vers; - let features = new_crate.features.iter().map(|(k, v)| { - (k[..].to_string(), v.iter().map(|v| v[..].to_string()).collect()) - }).collect::>>(); - let keywords = new_crate.keywords.as_ref().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 features = new_crate + .features + .iter() + .map(|(k, v)| { + ( + k[..].to_string(), + v.iter().map(|v| v[..].to_string()).collect(), + ) + }) + .collect::>>(); + let keywords = new_crate + .keywords + .as_ref() + .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: Vec<_> = categories.iter().map(|k| &**k).collect(); let conn = req.db_conn()?; @@ -903,26 +1058,35 @@ pub fn new(req: &mut Request) -> CargoResult { 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")) + 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))) + 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); + 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))) + return Err(human(&format_args!("max upload size is: {}", max))); } // Persist the new version of this crate - let version = NewVersion::new(krate.id, vers, &features)? - .save(&conn, &new_crate.authors)?; + let version = NewVersion::new(krate.id, vers, &features)?.save( + &conn, + &new_crate + .authors, + )?; // Link this new version to all dependencies let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?; @@ -936,11 +1100,7 @@ pub fn new(req: &mut Request) -> CargoResult { // 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 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 @@ -958,7 +1118,10 @@ pub fn new(req: &mut Request) -> CargoResult { yanked: Some(false), }; git::add_crate(&**req.app(), &git_crate).chain_error(|| { - internal(&format_args!("could not add crate `{}` to the git repo", name)) + internal(&format_args!( + "could not add crate `{}` to the git repo", + name + )) })?; // Now that we've come this far, we're committed! @@ -975,10 +1138,13 @@ pub fn new(req: &mut Request) -> CargoResult { }; #[derive(RustcEncodable)] - struct R<'a> { krate: EncodableCrate, warnings: Warnings<'a> } + struct R<'a> { + krate: EncodableCrate, + warnings: Warnings<'a>, + } Ok(req.json(&R { krate: krate.minimal_encodable(max_version, None, false), - warnings: warnings + warnings: warnings, })) }) } @@ -988,7 +1154,7 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> let amt = read_le_u32(req.body())? as u64; let max = req.app().config.max_upload_size; if amt > max { - return Err(human(&format_args!("max upload size is: {}", max))) + return Err(human(&format_args!("max upload size is: {}", max))); } let mut json = vec![0; amt as usize]; read_fill(req.body(), &mut json)?; @@ -1000,7 +1166,9 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> })?; // Make sure required fields are provided - fn empty(s: Option<&String>) -> bool { s.map_or(true, |s| s.is_empty()) } + fn empty(s: Option<&String>) -> bool { + s.map_or(true, |s| s.is_empty()) + } let mut missing = Vec::new(); if empty(new.description.as_ref()) { @@ -1013,9 +1181,12 @@ fn parse_new_headers(req: &mut Request) -> CargoResult<(upload::NewCrate, User)> missing.push("authors"); } if !missing.is_empty() { - return Err(human(&format_args!("missing or empty metadata fields: {}. Please \ + 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(", ")))); + how to upload metadata", + missing.join(", ") + ))); } let user = req.user()?; @@ -1037,15 +1208,18 @@ pub fn download(req: &mut Request) -> CargoResult { increment_download_counts(req, crate_name, version)?; } - let redirect_url = req.app().config.uploader - .crate_location(crate_name, version).ok_or_else(|| - human("crate files not found") - )?; + let redirect_url = req.app() + .config + .uploader + .crate_location(crate_name, version) + .ok_or_else(|| human("crate files not found"))?; if req.wants_json() { #[derive(RustcEncodable)] - struct R { url: String } - Ok(req.json(&R{ url: redirect_url })) + struct R { + url: String, + } + Ok(req.json(&R { url: redirect_url })) } else { Ok(req.redirect(redirect_url)) } @@ -1055,8 +1229,11 @@ fn increment_download_counts(req: &Request, crate_name: &str, version: &str) -> use self::versions::dsl::*; let conn = req.db_conn()?; - let version_id = versions.select(id) - .filter(crate_id.eq_any(Crate::by_name(crate_name).select(crates::id))) + let version_id = versions + .select(id) + .filter(crate_id.eq_any( + Crate::by_name(crate_name).select(crates::id), + )) .filter(num.eq(version)) .first(&*conn)?; @@ -1087,26 +1264,40 @@ 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()) .load::(&*conn)?; #[derive(RustcEncodable, Queryable)] - struct ExtraDownload { date: String, downloads: i64 } + struct ExtraDownload { + date: String, + downloads: i64, + } #[derive(RustcEncodable)] - struct R { version_downloads: Vec, meta: Meta } + struct R { + version_downloads: Vec, + meta: Meta, + } #[derive(RustcEncodable)] - struct Meta { extra_downloads: Vec } + struct Meta { + 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)] #[belongs_to(User)] #[primary_key(user_id, crate_id)] -#[table_name="follows"] +#[table_name = "follows"] pub struct Follow { user_id: i32, crate_id: i32, @@ -1116,9 +1307,7 @@ 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)?; + let crate_id = Crate::by_name(crate_name).select(crates::id).first(&*conn)?; Ok(Follow { user_id: user.id, crate_id: crate_id, @@ -1133,7 +1322,9 @@ pub fn follow(req: &mut Request) -> CargoResult { .into(follows::table) .execute(&*conn)?; #[derive(RustcEncodable)] - struct R { ok: bool } + struct R { + ok: bool, + } Ok(req.json(&R { ok: true })) } @@ -1143,7 +1334,9 @@ pub fn unfollow(req: &mut Request) -> CargoResult { let conn = req.db_conn()?; diesel::delete(&follow).execute(&*conn)?; #[derive(RustcEncodable)] - struct R { ok: bool } + struct R { + ok: bool, + } Ok(req.json(&R { ok: true })) } @@ -1156,7 +1349,9 @@ pub fn following(req: &mut Request) -> CargoResult { let following = diesel::select(exists(follows::table.find(follow.id()))) .get_result(&*conn)?; #[derive(RustcEncodable)] - struct R { following: bool } + struct R { + following: bool, + } Ok(req.json(&R { following: following })) } @@ -1168,12 +1363,16 @@ pub fn versions(req: &mut Request) -> CargoResult { let tx = req.tx()?; let krate = Crate::find_by_name(tx, crate_name)?; let versions = krate.versions(tx)?; - let versions = versions.into_iter().map(|v| v.encodable(crate_name)) - .collect(); + let versions = versions + .into_iter() + .map(|v| v.encodable(crate_name)) + .collect(); #[derive(RustcEncodable)] - struct R { versions: Vec } - Ok(req.json(&R{ versions: versions })) + struct R { + versions: Vec, + } + Ok(req.json(&R { versions: versions })) } /// Handles the `GET /crates/:crate_id/owners` route. @@ -1181,14 +1380,17 @@ pub fn owners(req: &mut Request) -> CargoResult { let crate_name = &req.params()["crate_id"]; let conn = req.db_conn()?; let krate = Crate::by_name(crate_name).first::(&*conn)?; - let owners = krate.owners(&conn)? + let owners = krate + .owners(&conn)? .into_iter() .map(Owner::encodable) .collect(); #[derive(RustcEncodable)] - struct R { users: Vec } - Ok(req.json(&R{ users: owners })) + struct R { + users: Vec, + } + Ok(req.json(&R { users: owners })) } /// Handles the `PUT /crates/:crate_id/owners` route. @@ -1206,8 +1408,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)? { @@ -1227,9 +1430,9 @@ 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") @@ -1238,22 +1441,24 @@ fn modify_owners(req: &mut Request, add: bool) -> CargoResult { for login in &logins { if add { if owners.iter().any(|owner| owner.login() == *login) { - return Err(human(&format_args!("`{}` is already an owner", login))) + return Err(human(&format_args!("`{}` is already an owner", login))); } krate.owner_add(req.app(), &conn, user, login)?; } else { // Removing the team that gives you rights is prevented because // team members only have Rights::Publish if *login == user.gh_login { - return Err(human("cannot remove yourself as an owner")) + return Err(human("cannot remove yourself as an owner")); } krate.owner_remove(&conn, user, login)?; } } #[derive(RustcEncodable)] - struct R { ok: bool } - Ok(req.json(&R{ ok: true })) + struct R { + ok: bool, + } + Ok(req.json(&R { ok: true })) } /// Handles the `GET /crates/:crate_id/reverse_dependencies` route. @@ -1263,15 +1468,24 @@ pub fn reverse_dependencies(req: &mut Request) -> CargoResult { let krate = Crate::find_by_name(conn, name)?; let (offset, limit) = req.pagination(10, 100)?; let (rev_deps, total) = krate.reverse_dependencies(conn, offset, limit)?; - let rev_deps = rev_deps.into_iter() + let rev_deps = rev_deps + .into_iter() .map(ReverseDependency::encodable) .collect(); #[derive(RustcEncodable)] - struct R { dependencies: Vec, meta: Meta } + struct R { + dependencies: Vec, + meta: Meta, + } #[derive(RustcEncodable)] - struct Meta { total: i64 } - Ok(req.json(&R{ dependencies: rev_deps, meta: Meta { total: total } })) + struct Meta { + total: i64, + } + 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 25cf755e746..71cc750fb3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,16 @@ #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", plugin(clippy))] -#[macro_use] extern crate diesel; -#[macro_use] extern crate diesel_codegen; -#[macro_use] extern crate log; -#[macro_use] extern crate serde_json; -#[macro_use] extern crate serde_derive; +#[macro_use] +extern crate diesel; +#[macro_use] +extern crate diesel_codegen; +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde_json; +#[macro_use] +extern crate serde_derive; extern crate chrono; extern crate curl; extern crate diesel_full_text_search; @@ -109,8 +114,14 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { api_router.put("/crates/new", C(krate::new)); api_router.get("/crates/:crate_id/:version", C(version::show)); api_router.get("/crates/:crate_id/:version/download", C(krate::download)); - api_router.get("/crates/:crate_id/:version/dependencies", C(version::dependencies)); - api_router.get("/crates/:crate_id/:version/downloads", C(version::downloads)); + api_router.get( + "/crates/:crate_id/:version/dependencies", + C(version::dependencies), + ); + api_router.get( + "/crates/:crate_id/:version/downloads", + C(version::downloads), + ); api_router.get("/crates/:crate_id/:version/authors", C(version::authors)); api_router.get("/crates/:crate_id/downloads", C(krate::downloads)); api_router.get("/crates/:crate_id/versions", C(krate::versions)); @@ -122,7 +133,10 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { api_router.delete("/crates/:crate_id/owners", C(krate::remove_owners)); api_router.delete("/crates/:crate_id/:version/yank", C(version::yank)); api_router.put("/crates/:crate_id/:version/unyank", C(version::unyank)); - api_router.get("/crates/:crate_id/reverse_dependencies", C(krate::reverse_dependencies)); + api_router.get( + "/crates/:crate_id/reverse_dependencies", + C(krate::reverse_dependencies), + ); api_router.get("/versions", C(version::index)); api_router.get("/versions/:version_id", C(version::show)); api_router.get("/keywords", C(keyword::index)); @@ -169,8 +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); @@ -185,8 +201,7 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { struct DebugMiddleware; impl conduit_middleware::Middleware for DebugMiddleware { - fn before(&self, req: &mut conduit::Request) - -> Result<(), Box> { + fn before(&self, req: &mut conduit::Request) -> Result<(), Box> { println!(" version: {}", req.http_version()); println!(" method: {:?}", req.method()); println!(" scheme: {:?}", req.scheme()); @@ -199,9 +214,7 @@ pub fn middleware(app: Arc) -> MiddlewareBuilder { } Ok(()) } - fn after(&self, _req: &mut conduit::Request, - res: Result>) - -> Result> { + fn after(&self, _req: &mut conduit::Request, res: Result>) -> Result> { res.map(|res| { println!(" <- {:?}", res.status); for (k, v) in &res.headers { @@ -223,9 +236,7 @@ pub fn encode_time(ts: time::Timespec) -> String { pub fn env(s: &str) -> String { dotenv::dotenv().ok(); - ::std::env::var(s).unwrap_or_else(|_| { - panic!("must have `{}` defined", s) - }) + ::std::env::var(s).unwrap_or_else(|_| panic!("must have `{}` defined", s)) } sql_function!(lower, lower_t, (x: ::diesel::types::Text) -> ::diesel::types::Text); diff --git a/src/model.rs b/src/model.rs index 07381044776..fc0ed056f92 100644 --- a/src/model.rs +++ b/src/model.rs @@ -9,8 +9,10 @@ pub trait Model: Sized { fn table_name(_: Option) -> &'static str; fn find(conn: &GenericConnection, id: i32) -> CargoResult { - let sql = format!("SELECT * FROM {} WHERE id = $1", - Model::table_name(None::)); + let sql = format!( + "SELECT * FROM {} WHERE id = $1", + Model::table_name(None::) + ); let stmt = conn.prepare(&sql)?; let rows = stmt.query(&[&id])?; let row = rows.into_iter().next().chain_error(|| NotFound)?; diff --git a/src/owner.rs b/src/owner.rs index 70faa2d0987..8a389aa8af3 100644 --- a/src/owner.rs +++ b/src/owner.rs @@ -11,9 +11,9 @@ use {Model, User, Crate}; #[derive(Insertable, Associations, Identifiable)] #[belongs_to(Crate)] -#[belongs_to(User, foreign_key="owner_id")] -#[belongs_to(Team, foreign_key="owner_id")] -#[table_name="crate_owners"] +#[belongs_to(User, foreign_key = "owner_id")] +#[belongs_to(Team, foreign_key = "owner_id")] +#[table_name = "crate_owners"] #[primary_key(crate_id, owner_id, owner_kind)] pub struct CrateOwner { pub crate_id: i32, @@ -50,7 +50,6 @@ pub struct Team { /// Sugary goodness pub name: Option, pub avatar: Option, - } #[derive(RustcEncodable)] @@ -75,11 +74,7 @@ pub enum Rights { impl Team { /// Tries to create the Team in the DB (assumes a `:` has already been found). - pub fn create(app: &App, - conn: &PgConnection, - login: &str, - req_user: &User) - -> CargoResult { + pub fn create(app: &App, conn: &PgConnection, login: &str, req_user: &User) -> CargoResult { // must look like system:xxxxxxx let mut chunks = login.split(':'); match chunks.next().unwrap() { @@ -87,15 +82,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", + )) } } } @@ -103,9 +102,7 @@ impl Team { /// Tries to create a Github Team from scratch. Assumes `org` and `team` are /// correctly parsed out of the full `name`. `name` is passed as a /// convenience to avoid rebuilding it. - pub fn create_github_team(app: &App, conn: &PgConnection, login: &str, - org_name: &str, team_name: &str, req_user: &User) - -> CargoResult { + pub fn create_github_team(app: &App, conn: &PgConnection, login: &str, org_name: &str, team_name: &str, req_user: &User) -> CargoResult { // GET orgs/:org/teams // check that `team` is the `slug` in results, and grab its data @@ -113,20 +110,23 @@ impl Team { fn whitelist(c: &char) -> bool { match *c { 'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => false, - _ => true + _ => true, } } if let Some(c) = org_name.chars().find(whitelist) { - return Err(human(&format_args!("organization cannot contain special \ - characters like {}", c))); + return Err(human(&format_args!( + "organization cannot contain special \ + characters like {}", + c + ))); } #[derive(RustcDecodable)] struct GithubTeam { - slug: String, // the name we want to find - id: i32, // unique GH id (needed for membership queries) - name: Option, // Pretty name + slug: String, // the name we want to find + id: i32, // unique GH id (needed for membership queries) + name: Option, // Pretty name } // FIXME: we just set per_page=100 and don't bother chasing pagination @@ -136,10 +136,15 @@ impl Team { let (handle, data) = http::github(app, &url, &token)?; let teams: Vec = http::parse_github_response(handle, &data)?; - let team = teams.into_iter().find(|team| team.slug == team_name) + let team = teams + .into_iter() + .find(|team| team.slug == team_name) .ok_or_else(|| { - human(&format_args!("could not find the github team {}/{}", - org_name, team_name)) + 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)? { @@ -158,16 +163,11 @@ impl Team { Team::insert(conn, login, team.id, team.name, org.avatar_url) } - pub fn insert(conn: &PgConnection, - login: &str, - github_id: i32, - name: Option, - avatar: Option) - -> CargoResult { + pub fn insert(conn: &PgConnection, login: &str, github_id: i32, name: Option, avatar: Option) -> CargoResult { use diesel::pg::upsert::*; #[derive(Insertable, AsChangeset)] - #[table_name="teams"] + #[table_name = "teams"] struct NewTeam<'a> { login: &'a str, github_id: i32, @@ -181,9 +181,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) } @@ -197,8 +198,7 @@ impl Team { } } -fn team_with_gh_id_contains_user(app: &App, github_id: i32, user: &User) - -> CargoResult { +fn team_with_gh_id_contains_user(app: &App, github_id: i32, user: &User) -> CargoResult { // GET teams/:team_id/memberships/:user_name // check that "state": "active" @@ -207,14 +207,13 @@ fn team_with_gh_id_contains_user(app: &App, github_id: i32, user: &User) state: String, } - let url = format!("/teams/{}/memberships/{}", - &github_id, &user.gh_login); + let url = format!("/teams/{}/memberships/{}", &github_id, &user.gh_login); let token = http::token(user.gh_access_token.clone()); let (mut handle, resp) = http::github(app, &url, &token)?; // Officially how `false` is returned if handle.response_code().unwrap() == 404 { - return Ok(false) + return Ok(false); } let membership: Membership = http::parse_github_response(handle, &resp)?; @@ -235,29 +234,32 @@ impl Model for Team { } } - fn table_name(_: Option) -> &'static str { "teams" } + fn table_name(_: Option) -> &'static str { + "teams" + } } impl Owner { /// Finds the owner by name, failing out if it doesn't exist. /// May be a user's GH login, or a full team name. This is case /// sensitive. - pub fn find_by_login(conn: &PgConnection, - name: &str) -> CargoResult { + pub fn find_by_login(conn: &PgConnection, name: &str) -> CargoResult { if name.contains(':') { - teams::table.filter(teams::login.eq(name)) + teams::table + .filter(teams::login.eq(name)) .first(conn) .map(Owner::Team) - .map_err(|_| + .map_err(|_| { human(&format_args!("could not find team with name {}", name)) - ) + }) } else { - users::table.filter(users::gh_login.eq(name)) + users::table + .filter(users::gh_login.eq(name)) .first(conn) .map(Owner::User) - .map_err(|_| + .map_err(|_| { human(&format_args!("could not find user with login `{}`", name)) - ) + }) } } @@ -284,7 +286,14 @@ impl Owner { pub fn encodable(self) -> EncodableOwner { match self { - Owner::User(User { id, email, name, gh_login, gh_avatar, .. }) => { + Owner::User(User { + id, + email, + name, + gh_login, + gh_avatar, + .. + }) => { let url = format!("https://github.com/{}", gh_login); EncodableOwner { id: id, @@ -296,12 +305,21 @@ impl Owner { kind: String::from("user"), } } - Owner::Team(Team { id, name, login, avatar, .. }) => { + Owner::Team(Team { + id, + name, + login, + avatar, + .. + }) => { let url = { let mut parts = login.split(':'); parts.next(); // discard github - format!("https://github.com/orgs/{}/teams/{}", - parts.next().unwrap(), parts.next().unwrap()) + format!( + "https://github.com/orgs/{}/teams/{}", + parts.next().unwrap(), + parts.next().unwrap() + ) }; EncodableOwner { id: id, @@ -329,14 +347,17 @@ pub fn rights(app: &App, owners: &[Owner], user: &User) -> CargoResult { let mut best = Rights::None; for owner in owners { match *owner { - Owner::User(ref other_user) => if other_user.id == user.id { - return Ok(Rights::Full); - }, - Owner::Team(ref team) => if team.contains_user(app, user)? { - best = Rights::Publish; - }, + Owner::User(ref other_user) => { + if other_user.id == user.id { + return Ok(Rights::Full); + } + } + Owner::Team(ref team) => { + if team.contains_user(app, user)? { + best = Rights::Publish; + } + } } } Ok(best) } - diff --git a/src/tests/all.rs b/src/tests/all.rs index ce5fe12452e..6a3a4c3b8b5 100755 --- a/src/tests/all.rs +++ b/src/tests/all.rs @@ -68,9 +68,13 @@ macro_rules! bad_resp { } #[derive(RustcDecodable, Debug)] -struct Error { detail: String } +struct Error { + detail: String, +} #[derive(RustcDecodable)] -struct Bad { errors: Vec } +struct Bad { + errors: Vec, +} mod badge; mod category; @@ -93,11 +97,13 @@ fn app() -> (record::Bomb, Arc, conduit_middleware::MiddlewareBuilder) { let api_protocol = String::from("http"); let uploader = cargo_registry::Uploader::S3 { - bucket: s3::Bucket::new(String::from("alexcrichton-test"), - None, - String::new(), - String::new(), - &api_protocol), + bucket: s3::Bucket::new( + String::from("alexcrichton-test"), + None, + String::new(), + String::new(), + &api_protocol, + ), proxy: Some(proxy), }; @@ -139,7 +145,9 @@ fn ok_resp(r: &conduit::Response) -> bool { fn bad_resp(r: &mut conduit::Response) -> Option { let bad = json::(r); - if bad.errors.len() == 0 { return None } + if bad.errors.len() == 0 { + return None; + } Some(bad) } @@ -162,18 +170,17 @@ fn json(r: &mut conduit::Response) -> T { fn fixup(json: Json) -> Json { match json { Json::Object(object) => { - Json::Object(object.into_iter().map(|(k, v)| { - let k = if k == "crate" { - "krate".to_string() - } else { - k - }; - (k, fixup(v)) - }).collect()) - } - Json::Array(list) => { - Json::Array(list.into_iter().map(fixup).collect()) + Json::Object( + object + .into_iter() + .map(|(k, v)| { + let k = if k == "crate" { "krate".to_string() } else { k }; + (k, fixup(v)) + }) + .collect(), + ) } + Json::Array(list) => Json::Array(list.into_iter().map(fixup).collect()), j => j, } } @@ -277,8 +284,11 @@ impl<'a> CrateBuilder<'a> { fn build(mut self, connection: &PgConnection) -> CargoResult { use diesel::update; - let mut krate = self.krate - .create_or_update(connection, self.license_file, self.owner_id)?; + let mut krate = self.krate.create_or_update( + connection, + self.license_file, + self.owner_id, + )?; // Since we are using `NewCrate`, we can't set all the // crate properties in a single DB call. @@ -288,12 +298,14 @@ impl<'a> CrateBuilder<'a> { } if self.versions.is_empty() { - self.versions.push("0.99.0".parse().expect("invalid version number")); + self.versions.push("0.99.0".parse().expect( + "invalid version number", + )); } for version_num in &self.versions { NewVersion::new(krate.id, version_num, &HashMap::new())? - .save(connection, &[])?; + .save(connection, &[])?; } if !self.keywords.is_empty() { @@ -305,10 +317,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); + }) } } @@ -335,13 +346,15 @@ fn krate(name: &str) -> Crate { } fn mock_user(req: &mut Request, u: User) -> User { - let u = User::find_or_insert(req.tx().unwrap(), - u.gh_id, - &u.gh_login, - u.email.as_ref().map(|s| &s[..]), - u.name.as_ref().map(|s| &s[..]), - u.gh_avatar.as_ref().map(|s| &s[..]), - &u.gh_access_token).unwrap(); + let u = User::find_or_insert( + req.tx().unwrap(), + u.gh_id, + &u.gh_login, + u.email.as_ref().map(|s| &s[..]), + u.name.as_ref().map(|s| &s[..]), + u.gh_avatar.as_ref().map(|s| &s[..]), + &u.gh_access_token, + ).unwrap(); sign_in_as(req, &u); return u; } @@ -360,18 +373,21 @@ fn mock_crate(req: &mut Request, krate: Crate) -> (Crate, Version) { mock_crate_vers(req, krate, &semver::Version::parse("1.0.0").unwrap()) } -fn mock_crate_vers(req: &mut Request, krate: Crate, v: &semver::Version) - -> (Crate, Version) { +fn mock_crate_vers(req: &mut Request, krate: Crate, v: &semver::Version) -> (Crate, Version) { let user = req.extensions().find::().unwrap(); - let mut krate = Crate::find_or_insert(req.tx().unwrap(), &krate.name, - user.id, &krate.description, - &krate.homepage, - &krate.documentation, - &krate.readme, - &krate.repository, - &krate.license, - &None, - krate.max_upload_size).unwrap(); + let mut krate = Crate::find_or_insert( + req.tx().unwrap(), + &krate.name, + user.id, + &krate.description, + &krate.homepage, + &krate.documentation, + &krate.readme, + &krate.repository, + &krate.license, + &None, + krate.max_upload_size, + ).unwrap(); let v = krate.add_version(req.tx().unwrap(), v, &HashMap::new(), &[]); (krate, v.unwrap()) } @@ -387,30 +403,42 @@ fn new_dependency(conn: &PgConnection, version: &Version, krate: &Crate) -> Depe optional: false, ..Default::default() }; - insert(&dep).into(dependencies::table).get_result(conn).unwrap() -} - -fn mock_dep(req: &mut Request, version: &Version, krate: &Crate, - target: Option<&str>) -> Dependency { - Dependency::insert(req.tx().unwrap(), - version.id, - krate.id, - &semver::VersionReq::parse(">= 0").unwrap(), - Kind::Normal, - false, true, &[], - &target.map(|s| s.to_string())).unwrap() + insert(&dep) + .into(dependencies::table) + .get_result(conn) + .unwrap() +} + +fn mock_dep(req: &mut Request, version: &Version, krate: &Crate, target: Option<&str>) -> Dependency { + Dependency::insert( + req.tx().unwrap(), + version.id, + krate.id, + &semver::VersionReq::parse(">= 0").unwrap(), + Kind::Normal, + false, + true, + &[], + &target.map(|s| s.to_string()), + ).unwrap() } fn new_category<'a>(category: &'a str, slug: &'a str) -> NewCategory<'a> { - NewCategory { category: category, slug: slug, ..NewCategory::default() } + NewCategory { + category: category, + slug: slug, + ..NewCategory::default() + } } fn mock_category(req: &mut Request, name: &str, slug: &str) -> Category { let conn = req.tx().unwrap(); - let stmt = conn.prepare(" \ + let stmt = conn.prepare( + " \ INSERT INTO categories (category, slug) \ VALUES ($1, $2) \ - RETURNING *").unwrap(); + RETURNING *", + ).unwrap(); let rows = stmt.query(&[&name, &slug]).unwrap(); Model::from_row(&rows.iter().next().unwrap()) } @@ -419,11 +447,7 @@ fn logout(req: &mut Request) { req.mut_extensions().pop::(); } -fn request_with_user_and_mock_crate( - app: &Arc, - user: NewUser, - krate: &str, -) -> MockRequest { +fn request_with_user_and_mock_crate(app: &Arc, user: NewUser, krate: &str) -> MockRequest { let mut req = new_req(app.clone(), krate, "1.0.0"); { let conn = app.diesel_database.get().unwrap(); @@ -438,89 +462,122 @@ fn new_req(app: Arc, krate: &str, version: &str) -> MockRequest { new_req_full(app, ::krate(krate), version, Vec::new()) } -fn new_req_full(app: Arc, krate: Crate, version: &str, - deps: Vec) -> MockRequest { +fn new_req_full(app: Arc, krate: Crate, version: &str, 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() + krate, + version, + deps, + Vec::new(), + Vec::new(), + HashMap::new(), )); return req; } -fn new_req_with_keywords(app: Arc, krate: Crate, version: &str, - kws: Vec) -> MockRequest { +fn new_req_with_keywords(app: Arc, krate: Crate, version: &str, 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() + krate, + version, + Vec::new(), + kws, + Vec::new(), + HashMap::new(), )); return req; } -fn new_req_with_categories(app: Arc, krate: Crate, version: &str, - cats: Vec) -> MockRequest { +fn new_req_with_categories(app: Arc, krate: Crate, version: &str, 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() + krate, + version, + Vec::new(), + Vec::new(), + cats, + HashMap::new(), )); return req; } -fn new_req_with_badges(app: Arc, krate: Crate, version: &str, - badges: HashMap>) - -> MockRequest { +fn new_req_with_badges(app: Arc, krate: Crate, version: &str, 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 + krate, + version, + Vec::new(), + Vec::new(), + Vec::new(), + badges, )); return req; } fn new_req_body_version_2(krate: Crate) -> Vec { new_req_body( - krate, "2.0.0", Vec::new(), Vec::new(), Vec::new(), HashMap::new() + krate, + "2.0.0", + Vec::new(), + Vec::new(), + Vec::new(), + HashMap::new(), ) } -fn new_req_body(krate: Crate, version: &str, deps: Vec, - kws: Vec, cats: Vec, - badges: HashMap>) -> Vec { +fn new_req_body( + krate: Crate, + version: &str, + deps: Vec, + kws: Vec, + cats: Vec, + badges: HashMap>, +) -> Vec { let kws = kws.into_iter().map(u::Keyword).collect(); 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), - }, &[]) + 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), + }, + &[], + ) } fn new_crate_to_body(new_crate: &u::NewCrate, krate: &[u8]) -> Vec { let json = json::encode(&new_crate).unwrap(); let mut body = Vec::new(); - body.extend([ - (json.len() >> 0) as u8, - (json.len() >> 8) as u8, - (json.len() >> 16) as u8, - (json.len() >> 24) as u8, - ].iter().cloned()); + body.extend( + [ + (json.len() >> 0) as u8, + (json.len() >> 8) as u8, + (json.len() >> 16) as u8, + (json.len() >> 24) as u8, + ].iter() + .cloned(), + ); body.extend(json.as_bytes().iter().cloned()); - body.extend(&[ - (krate.len() >> 0) as u8, - (krate.len() >> 8) as u8, - (krate.len() >> 16) as u8, - (krate.len() >> 24) as u8, - ]); + body.extend( + &[ + (krate.len() >> 0) as u8, + (krate.len() >> 8) as u8, + (krate.len() >> 16) as u8, + (krate.len() >> 24) as u8, + ], + ); body.extend(krate); body } diff --git a/src/tests/badge.rs b/src/tests/badge.rs index df997918390..86a06ee8f31 100644 --- a/src/tests/badge.rs +++ b/src/tests/badge.rs @@ -27,11 +27,8 @@ fn set_up() -> (Arc, Crate, BadgeRef) { let krate = { let conn = app.diesel_database.get().unwrap(); - let u = ::new_user("foo") - .create_or_update(&conn) - .unwrap(); - ::CrateBuilder::new("badged_crate", u.id) - .expect_build(&conn) + let u = ::new_user("foo").create_or_update(&conn).unwrap(); + ::CrateBuilder::new("badged_crate", u.id).expect_build(&conn) }; let appveyor = Badge::Appveyor { @@ -40,60 +37,32 @@ fn set_up() -> (Arc, Crate, BadgeRef) { repository: String::from("rust-lang/cargo"), }; let mut badge_attributes_appveyor = HashMap::new(); - badge_attributes_appveyor.insert( - String::from("service"), - String::from("github") - ); - badge_attributes_appveyor.insert( - String::from("repository"), - String::from("rust-lang/cargo") - ); + badge_attributes_appveyor.insert(String::from("service"), String::from("github")); + badge_attributes_appveyor.insert(String::from("repository"), String::from("rust-lang/cargo")); let travis_ci = Badge::TravisCi { branch: Some(String::from("beta")), repository: String::from("rust-lang/rust"), }; let mut badge_attributes_travis_ci = HashMap::new(); - badge_attributes_travis_ci.insert( - String::from("branch"), - String::from("beta") - ); - badge_attributes_travis_ci.insert( - String::from("repository"), - String::from("rust-lang/rust") - ); + badge_attributes_travis_ci.insert(String::from("branch"), String::from("beta")); + badge_attributes_travis_ci.insert(String::from("repository"), String::from("rust-lang/rust")); let gitlab = Badge::GitLab { branch: Some(String::from("beta")), repository: String::from("rust-lang/rust"), }; let mut badge_attributes_gitlab = HashMap::new(); - badge_attributes_gitlab.insert( - String::from("branch"), - String::from("beta") - ); - badge_attributes_gitlab.insert( - String::from("repository"), - String::from("rust-lang/rust") - ); + badge_attributes_gitlab.insert(String::from("branch"), String::from("beta")); + badge_attributes_gitlab.insert(String::from("repository"), String::from("rust-lang/rust")); - let isitmaintained_issue_resolution = Badge::IsItMaintainedIssueResolution { - repository: String::from("rust-lang/rust"), - }; + 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 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")), @@ -101,18 +70,9 @@ fn set_up() -> (Arc, Crate, BadgeRef) { repository: String::from("rust-lang/rust"), }; let mut badge_attributes_codecov = HashMap::new(); - badge_attributes_codecov.insert( - String::from("branch"), - String::from("beta") - ); - badge_attributes_codecov.insert( - String::from("repository"), - String::from("rust-lang/rust") - ); - badge_attributes_codecov.insert( - String::from("service"), - String::from("github") - ); + badge_attributes_codecov.insert(String::from("branch"), String::from("beta")); + badge_attributes_codecov.insert(String::from("repository"), String::from("rust-lang/rust")); + badge_attributes_codecov.insert(String::from("service"), String::from("github")); let coveralls = Badge::Coveralls { service: Some(String::from("github")), @@ -120,18 +80,9 @@ fn set_up() -> (Arc, Crate, BadgeRef) { repository: String::from("rust-lang/rust"), }; let mut badge_attributes_coveralls = HashMap::new(); - badge_attributes_coveralls.insert( - String::from("branch"), - String::from("beta") - ); - badge_attributes_coveralls.insert( - String::from("repository"), - String::from("rust-lang/rust") - ); - badge_attributes_coveralls.insert( - String::from("service"), - String::from("github") - ); + badge_attributes_coveralls.insert(String::from("branch"), String::from("beta")); + badge_attributes_coveralls.insert(String::from("repository"), String::from("rust-lang/rust")); + badge_attributes_coveralls.insert(String::from("service"), String::from("github")); let badges = BadgeRef { appveyor: appveyor, @@ -170,10 +121,7 @@ fn update_add_appveyor() { let conn = app.diesel_database.get().unwrap(); let mut badges = HashMap::new(); - badges.insert( - String::from("appveyor"), - test_badges.appveyor_attributes - ); + badges.insert(String::from("appveyor"), test_badges.appveyor_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.appveyor]); } @@ -185,10 +133,7 @@ fn update_add_travis_ci() { let conn = app.diesel_database.get().unwrap(); let mut badges = HashMap::new(); - badges.insert( - String::from("travis-ci"), - test_badges.travis_ci_attributes - ); + badges.insert(String::from("travis-ci"), test_badges.travis_ci_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.travis_ci]); } @@ -200,10 +145,7 @@ fn update_add_gitlab() { let conn = app.diesel_database.get().unwrap(); let mut badges = HashMap::new(); - badges.insert( - String::from("gitlab"), - test_badges.gitlab_attributes - ); + badges.insert(String::from("gitlab"), test_badges.gitlab_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.gitlab]); } @@ -217,10 +159,13 @@ fn update_add_isitmaintained_issue_resolution() { let mut badges = HashMap::new(); badges.insert( String::from("is-it-maintained-issue-resolution"), - test_badges.isitmaintained_issue_resolution_attributes + test_badges.isitmaintained_issue_resolution_attributes, ); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); - assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.isitmaintained_issue_resolution]); + assert_eq!( + krate.badges(&conn).unwrap(), + vec![test_badges.isitmaintained_issue_resolution] + ); } #[test] @@ -232,10 +177,13 @@ fn update_add_isitmaintained_open_issues() { let mut badges = HashMap::new(); badges.insert( String::from("is-it-maintained-open-issues"), - test_badges.isitmaintained_open_issues_attributes + test_badges.isitmaintained_open_issues_attributes, ); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); - assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.isitmaintained_open_issues]); + assert_eq!( + krate.badges(&conn).unwrap(), + vec![test_badges.isitmaintained_open_issues] + ); } #[test] @@ -245,10 +193,7 @@ fn update_add_codecov() { let conn = app.diesel_database.get().unwrap(); let mut badges = HashMap::new(); - badges.insert( - String::from("codecov"), - test_badges.codecov_attributes - ); + badges.insert(String::from("codecov"), test_badges.codecov_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.codecov]); } @@ -260,10 +205,7 @@ fn update_add_coveralls() { let conn = app.diesel_database.get().unwrap(); let mut badges = HashMap::new(); - badges.insert( - String::from("coveralls"), - test_badges.coveralls_attributes - ); + badges.insert(String::from("coveralls"), test_badges.coveralls_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.coveralls]); } @@ -276,10 +218,7 @@ fn replace_badge() { // Add a badge let mut badges = HashMap::new(); - badges.insert( - String::from("gitlab"), - test_badges.gitlab_attributes - ); + badges.insert(String::from("gitlab"), test_badges.gitlab_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.gitlab]); @@ -287,7 +226,7 @@ fn replace_badge() { badges.clear(); badges.insert( String::from("travis-ci"), - test_badges.travis_ci_attributes.clone() + test_badges.travis_ci_attributes.clone(), ); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.travis_ci]); @@ -301,10 +240,7 @@ fn update_attributes() { // Add a travis-ci badge let mut badges = HashMap::new(); - badges.insert( - String::from("travis-ci"), - test_badges.travis_ci_attributes - ); + badges.insert(String::from("travis-ci"), test_badges.travis_ci_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); let current_badges = krate.badges(&conn).unwrap(); assert_eq!(current_badges.len(), 1); @@ -317,13 +253,10 @@ fn update_attributes() { repository: String::from("rust-lang/rust"), }; let mut badge_attributes_travis_ci2 = HashMap::new(); - badge_attributes_travis_ci2.insert( - String::from("repository"), - String::from("rust-lang/rust") - ); + badge_attributes_travis_ci2.insert(String::from("repository"), String::from("rust-lang/rust")); badges.insert( String::from("travis-ci"), - badge_attributes_travis_ci2.clone() + badge_attributes_travis_ci2.clone(), ); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); let current_badges = krate.badges(&conn).unwrap(); @@ -340,18 +273,9 @@ fn clear_badges() { let mut badges = HashMap::new(); // Adding 3 badges - badges.insert( - String::from("appveyor"), - test_badges.appveyor_attributes - ); - badges.insert( - String::from("travis-ci"), - test_badges.travis_ci_attributes - ); - badges.insert( - String::from("gitlab"), - test_badges.gitlab_attributes - ); + badges.insert(String::from("appveyor"), test_badges.appveyor_attributes); + badges.insert(String::from("travis-ci"), test_badges.travis_ci_attributes); + badges.insert(String::from("gitlab"), test_badges.gitlab_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); let current_badges = krate.badges(&conn).unwrap(); @@ -376,14 +300,8 @@ fn appveyor_extra_keys() { // Extra invalid keys are fine, they just get ignored let mut appveyor_attributes = test_badges.appveyor_attributes.clone(); - appveyor_attributes.insert( - String::from("extra"), - String::from("info") - ); - badges.insert( - String::from("appveyor"), - test_badges.appveyor_attributes - ); + appveyor_attributes.insert(String::from("extra"), String::from("info")); + badges.insert(String::from("appveyor"), test_badges.appveyor_attributes); Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(krate.badges(&conn).unwrap(), vec![test_badges.appveyor]); @@ -399,10 +317,7 @@ fn travis_ci_required_keys() { // Repository is a required key test_badges.travis_ci_attributes.remove("repository"); - badges.insert( - String::from("travis-ci"), - test_badges.travis_ci_attributes - ); + badges.insert(String::from("travis-ci"), test_badges.travis_ci_attributes); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(invalid_badges.len(), 1); @@ -420,10 +335,7 @@ fn gitlab_required_keys() { // Repository is a required key test_badges.gitlab_attributes.remove("repository"); - badges.insert( - String::from("gitlab"), - test_badges.gitlab_attributes - ); + badges.insert(String::from("gitlab"), test_badges.gitlab_attributes); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(invalid_badges.len(), 1); @@ -440,10 +352,12 @@ fn isitmaintained_issue_resolution_required_keys() { let mut badges = HashMap::new(); // Repository is a required key - test_badges.isitmaintained_issue_resolution_attributes.remove("repository"); + test_badges + .isitmaintained_issue_resolution_attributes + .remove("repository"); badges.insert( String::from("isitmaintained_issue_resolution"), - test_badges.isitmaintained_issue_resolution_attributes + test_badges.isitmaintained_issue_resolution_attributes, ); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); @@ -461,10 +375,12 @@ 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 + test_badges.isitmaintained_open_issues_attributes, ); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); @@ -483,10 +399,7 @@ fn codecov_required_keys() { // Repository is a required key test_badges.codecov_attributes.remove("repository"); - badges.insert( - String::from("codecov"), - test_badges.codecov_attributes - ); + badges.insert(String::from("codecov"), test_badges.codecov_attributes); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(invalid_badges.len(), 1); @@ -504,10 +417,7 @@ fn coveralls_required_keys() { // Repository is a required key test_badges.coveralls_attributes.remove("repository"); - badges.insert( - String::from("coveralls"), - test_badges.coveralls_attributes - ); + badges.insert(String::from("coveralls"), test_badges.coveralls_attributes); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(invalid_badges.len(), 1); @@ -527,12 +437,9 @@ fn unknown_badge() { let mut invalid_attributes = HashMap::new(); invalid_attributes.insert( String::from("not-a-badge-attribute"), - String::from("not-a-badge-value") - ); - badges.insert( - String::from("not-a-badge"), - invalid_attributes + String::from("not-a-badge-value"), ); + badges.insert(String::from("not-a-badge"), invalid_attributes); let invalid_badges = Badge::update_crate(&conn, &krate, Some(&badges)).unwrap(); assert_eq!(invalid_badges.len(), 1); diff --git a/src/tests/category.rs b/src/tests/category.rs index b1beb4a1f3b..511b0b2c131 100644 --- a/src/tests/category.rs +++ b/src/tests/category.rs @@ -5,14 +5,21 @@ use cargo_registry::db::RequestTransaction; use cargo_registry::category::{Category, EncodableCategory, EncodableCategoryWithSubcategories}; #[derive(RustcDecodable)] -struct CategoryList { categories: Vec, meta: CategoryMeta } +struct CategoryList { + categories: Vec, + meta: CategoryMeta, +} #[derive(RustcDecodable)] -struct CategoryMeta { total: i32 } +struct CategoryMeta { + total: i32, +} #[derive(RustcDecodable)] -struct GoodCategory { category: EncodableCategory } +struct GoodCategory { + category: EncodableCategory, +} #[derive(RustcDecodable)] struct CategoryWithSubcategories { - category: EncodableCategoryWithSubcategories + category: EncodableCategoryWithSubcategories, } #[test] @@ -86,9 +93,7 @@ fn update_crate() { assert_eq!(cnt(&mut req, "category-2"), 0); // Replacing one category with another - Category::update_crate_old( - req.tx().unwrap(), &krate, &["category-2".to_string()] - ).unwrap(); + Category::update_crate_old(req.tx().unwrap(), &krate, &["category-2".to_string()]).unwrap(); assert_eq!(cnt(&mut req, "cat1"), 0); assert_eq!(cnt(&mut req, "category-2"), 1); @@ -99,8 +104,10 @@ fn update_crate() { // Adding 2 categories Category::update_crate_old( - req.tx().unwrap(), &krate, &["cat1".to_string(), - "category-2".to_string()]).unwrap(); + req.tx().unwrap(), + &krate, + &["cat1".to_string(), "category-2".to_string()], + ).unwrap(); assert_eq!(cnt(&mut req, "cat1"), 1); assert_eq!(cnt(&mut req, "category-2"), 1); @@ -111,8 +118,9 @@ fn update_crate() { // Attempting to add one valid category and one invalid category let invalid_categories = Category::update_crate_old( - req.tx().unwrap(), &krate, &["cat1".to_string(), - "catnope".to_string()] + req.tx().unwrap(), + &krate, + &["cat1".to_string(), "catnope".to_string()], ).unwrap(); assert_eq!(invalid_categories, vec!["catnope".to_string()]); assert_eq!(cnt(&mut req, "cat1"), 1); @@ -127,17 +135,17 @@ fn update_crate() { assert_eq!(json.meta.total, 2); // Attempting to add a category by display text; must use slug - Category::update_crate_old( - req.tx().unwrap(), &krate, &["Category 2".to_string()] - ).unwrap(); + Category::update_crate_old(req.tx().unwrap(), &krate, &["Category 2".to_string()]).unwrap(); assert_eq!(cnt(&mut req, "cat1"), 0); assert_eq!(cnt(&mut req, "category-2"), 0); // Add a category and its subcategory ::mock_category(&mut req, "cat1::bar", "cat1::bar"); Category::update_crate_old( - req.tx().unwrap(), &krate, &["cat1".to_string(), - "cat1::bar".to_string()]).unwrap(); + req.tx().unwrap(), + &krate, + &["cat1".to_string(), "cat1::bar".to_string()], + ).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 feac51e3177..3b26cd18c2e 100644 --- a/src/tests/git.rs +++ b/src/tests/git.rs @@ -8,11 +8,19 @@ 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 { root().join("checkout") } -pub fn bare() -> PathBuf { root().join("bare") } +pub fn checkout() -> PathBuf { + root().join("checkout") +} +pub fn bare() -> PathBuf { + root().join("bare") +} pub fn init() { static INIT: Once = ONCE_INIT; @@ -38,7 +46,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_add_push("origin", "refs/heads/master").unwrap(); + checkout + .remote_add_push("origin", "refs/heads/master") + .unwrap(); // Create an empty initial commit let mut config = checkout.config().unwrap(); @@ -48,9 +58,9 @@ pub fn init() { let id = index.write_tree().unwrap(); let tree = checkout.find_tree(id).unwrap(); let sig = checkout.signature().unwrap(); - checkout.commit(Some("HEAD"), &sig, &sig, - "Initial Commit", - &tree, &[]).unwrap(); + checkout + .commit(Some("HEAD"), &sig, &sig, "Initial Commit", &tree, &[]) + .unwrap(); // Push the commit to the remote repo let mut origin = checkout.find_remote("origin").unwrap(); diff --git a/src/tests/keyword.rs b/src/tests/keyword.rs index 8d78f89f049..980615800d9 100644 --- a/src/tests/keyword.rs +++ b/src/tests/keyword.rs @@ -4,11 +4,18 @@ use conduit_test::MockRequest; use cargo_registry::keyword::{Keyword, EncodableKeyword}; #[derive(RustcDecodable)] -struct KeywordList { keywords: Vec, meta: KeywordMeta } +struct KeywordList { + keywords: Vec, + meta: KeywordMeta, +} #[derive(RustcDecodable)] -struct KeywordMeta { total: i32 } +struct KeywordMeta { + total: i32, +} #[derive(RustcDecodable)] -struct GoodKeyword { keyword: EncodableKeyword } +struct GoodKeyword { + keyword: EncodableKeyword, +} #[test] fn index() { @@ -72,12 +79,9 @@ fn update_crate() { let krate = { let conn = app.diesel_database.get().unwrap(); - let u = ::new_user("foo") - .create_or_update(&conn) - .unwrap(); + let u = ::new_user("foo").create_or_update(&conn).unwrap(); Keyword::find_or_create_all(&conn, &["kw1", "kw2"]).unwrap(); - ::CrateBuilder::new("fookey", u.id) - .expect_build(&conn) + ::CrateBuilder::new("fookey", u.id).expect_build(&conn) }; { diff --git a/src/tests/krate.rs b/src/tests/krate.rs index 98f2838bd2f..7c8e94233ca 100644 --- a/src/tests/krate.rs +++ b/src/tests/krate.rs @@ -20,23 +20,47 @@ use cargo_registry::version::EncodableVersion; use cargo_registry::category::Category; #[derive(RustcDecodable)] -struct CrateList { crates: Vec, meta: CrateMeta } +struct CrateList { + crates: Vec, + meta: CrateMeta, +} #[derive(RustcDecodable)] -struct VersionsList { versions: Vec } +struct VersionsList { + versions: Vec, +} #[derive(RustcDecodable)] -struct CrateMeta { total: i32 } +struct CrateMeta { + total: i32, +} #[derive(RustcDecodable)] -struct Warnings { invalid_categories: Vec, invalid_badges: Vec } +struct Warnings { + invalid_categories: Vec, + invalid_badges: Vec, +} #[derive(RustcDecodable)] -struct GoodCrate { krate: EncodableCrate, warnings: Warnings } +struct GoodCrate { + krate: EncodableCrate, + warnings: Warnings, +} #[derive(RustcDecodable)] -struct CrateResponse { krate: EncodableCrate, versions: Vec, keywords: Vec } +struct CrateResponse { + krate: EncodableCrate, + versions: Vec, + keywords: Vec, +} #[derive(RustcDecodable)] -struct Deps { dependencies: Vec } +struct Deps { + dependencies: Vec, +} #[derive(RustcDecodable)] -struct RevDeps { dependencies: Vec, meta: CrateMeta } +struct RevDeps { + dependencies: Vec, + meta: CrateMeta, +} #[derive(RustcDecodable)] -struct Downloads { version_downloads: Vec } +struct Downloads { + version_downloads: Vec, +} fn new_crate(name: &str) -> u::NewCrate { u::NewCrate { @@ -69,11 +93,8 @@ fn index() { let krate = { let conn = app.diesel_database.get().unwrap(); - let u = ::new_user("foo") - .create_or_update(&conn) - .unwrap(); - ::CrateBuilder::new("fooindex", u.id) - .expect_build(&conn) + let u = ::new_user("foo").create_or_update(&conn).unwrap(); + ::CrateBuilder::new("fooindex", u.id).expect_build(&conn) }; let mut response = ok_resp!(middle.call(&mut req)); @@ -93,9 +114,7 @@ fn index_queries() { let krate2; { let conn = app.diesel_database.get().unwrap(); - u = ::new_user("foo") - .create_or_update(&conn) - .unwrap(); + u = ::new_user("foo").create_or_update(&conn).unwrap(); krate = ::CrateBuilder::new("foo_index_queries", u.id) .readme("readme") @@ -155,8 +174,12 @@ fn index_queries() { { let conn = app.diesel_database.get().unwrap(); - ::new_category("Category 1", "cat1").find_or_create(&conn).unwrap(); - ::new_category("Category 1::Ba'r", "cat1::bar").find_or_create(&conn).unwrap(); + ::new_category("Category 1", "cat1") + .find_or_create(&conn) + .unwrap(); + ::new_category("Category 1::Ba'r", "cat1::bar") + .find_or_create(&conn) + .unwrap(); Category::update_crate(&conn, &krate, &["cat1"]).unwrap(); Category::update_crate(&conn, &krate2, &["cat1::bar"]).unwrap(); } @@ -206,7 +229,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) @@ -257,7 +282,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); @@ -334,8 +361,11 @@ fn show() { assert_eq!(json.versions[0].krate, json.krate.id); assert_eq!(json.versions[0].num, "1.0.0"); let suffix = "/api/v1/crates/foo_show/1.0.0/download"; - assert!(json.versions[0].dl_path.ends_with(suffix), - "bad suffix {}", json.versions[0].dl_path); + assert!( + json.versions[0].dl_path.ends_with(suffix), + "bad suffix {}", + json.versions[0].dl_path + ); assert_eq!(1, json.keywords.len()); assert_eq!("kw1", json.keywords[0].id); @@ -394,8 +424,11 @@ fn new_bad_names() { 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("invalid crate name"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("invalid crate name"), + "{:?}", + json.errors + ); } bad_name(""); @@ -421,7 +454,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"); @@ -468,7 +503,10 @@ fn new_krate_with_dependency() { let path = ::git::checkout().join("ne/w_/new_dep"); assert!(path.exists()); let mut contents = String::new(); - File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + File::open(&path) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); let p: git::Crate = json::decode(&contents).unwrap(); assert_eq!(p.name, "new_dep"); assert_eq!(p.vers, "1.0.0"); @@ -523,7 +561,11 @@ fn new_krate_with_wildcard_dependency() { ::CrateBuilder::new("foo_wild", user.id).expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("dependency constraints"), "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("dependency constraints"), + "{:?}", + json.errors + ); } #[test] @@ -562,8 +604,11 @@ fn new_krate_wrong_user() { } let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("another user"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("another user"), + "{:?}", + json.errors + ); } #[test] @@ -574,21 +619,30 @@ fn new_krate_bad_name() { let mut req = ::new_req(app.clone(), "snow☃", "2.0.0"); ::sign_in(&mut req, &app); let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("invalid crate name"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("invalid crate name"), + "{:?}", + json.errors + ); } { let mut req = ::new_req(app.clone(), "áccênts", "2.0.0"); ::sign_in(&mut req, &app); let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("invalid crate name"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("invalid crate name"), + "{:?}", + json.errors + ); } } #[test] fn new_crate_owner() { - #[derive(RustcDecodable)] struct O { ok: bool } + #[derive(RustcDecodable)] + struct O { + ok: bool, + } let (_b, app, middle) = ::app(); @@ -605,27 +659,43 @@ fn new_crate_owner() { // Flag the second user as an owner let body = r#"{"users":["bar"]}"#; - let mut response = ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_owner/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + let mut response = ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_owner/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); assert!(::json::(&mut response).ok); - bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_owner/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_owner/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); // Make sure this shows up as one of their crates. let query = format!("user_id={}", u2.id); - let mut response = ok_resp!(middle.call(req.with_path("/api/v1/crates") - .with_method(Method::Get) - .with_query(&query))); + let mut response = ok_resp!( + middle.call( + req.with_path("/api/v1/crates") + .with_method(Method::Get) + .with_query(&query), + ) + ); assert_eq!(::json::(&mut response).crates.len(), 1); // And upload a new crate as the first user let body = ::new_req_body_version_2(::krate("foo_owner")); ::sign_in_as(&mut req, &u2); - let mut response = ok_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_method(Method::Put) - .with_body(&body))); + let mut response = ok_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_method(Method::Put) + .with_body(&body), + ) + ); ::json::(&mut response); } @@ -678,8 +748,11 @@ fn new_krate_duplicate_version() { .expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("already uploaded"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("already uploaded"), + "{:?}", + json.errors + ); } #[test] @@ -693,8 +766,11 @@ fn new_crate_similar_name() { ::CrateBuilder::new("Foo_similar", u.id).expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("previously named"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("previously named"), + "{:?}", + json.errors + ); } #[test] @@ -708,8 +784,11 @@ fn new_crate_similar_name_hyphen() { ::CrateBuilder::new("foo_bar_hyphen", u.id).expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("previously named"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("previously named"), + "{:?}", + json.errors + ); } #[test] @@ -723,8 +802,11 @@ fn new_crate_similar_name_underscore() { ::CrateBuilder::new("foo-bar-underscore", u.id).expect_build(&conn); } let json = bad_resp!(middle.call(&mut req)); - assert!(json.errors[0].detail.contains("previously named"), - "{:?}", json.errors); + assert!( + json.errors[0].detail.contains("previously named"), + "{:?}", + json.errors + ); } #[test] @@ -738,13 +820,18 @@ fn new_krate_git_upload() { let path = ::git::checkout().join("3/f/fgt"); assert!(path.exists()); let mut contents = String::new(); - File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + File::open(&path) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); let p: git::Crate = json::decode(&contents).unwrap(); assert_eq!(p.name, "fgt"); assert_eq!(p.vers, "1.0.0"); assert!(p.deps.is_empty()); - assert_eq!(p.cksum, - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + assert_eq!( + p.cksum, + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ); } #[test] @@ -752,9 +839,13 @@ fn new_krate_git_upload_appends() { let (_b, app, middle) = ::app(); let path = ::git::checkout().join("3/f/fpp"); fs::create_dir_all(path.parent().unwrap()).unwrap(); - File::create(&path).unwrap().write_all( - br#"{"name":"FPP","vers":"0.0.1","deps":[],"features":{},"cksum":"3j3"} -"#).unwrap(); + File::create(&path) + .unwrap() + .write_all( + br#"{"name":"FPP","vers":"0.0.1","deps":[],"features":{},"cksum":"3j3"} +"#, + ) + .unwrap(); let mut req = ::new_req(app.clone(), "FPP", "1.0.0"); ::sign_in(&mut req, &app); @@ -762,7 +853,10 @@ fn new_krate_git_upload_appends() { ::json::(&mut response); let mut contents = String::new(); - File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + File::open(&path) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); let mut lines = contents.lines(); let p1: git::Crate = json::decode(lines.next().unwrap().trim()).unwrap(); let p2: git::Crate = json::decode(lines.next().unwrap().trim()).unwrap(); @@ -785,8 +879,8 @@ fn new_krate_git_upload_with_conflicts() { let sig = repo.signature().unwrap(); let parent = repo.find_commit(target).unwrap(); let tree = repo.find_tree(parent.tree_id()).unwrap(); - repo.commit(Some("HEAD"), &sig, &sig, "empty commit", &tree, - &[&parent]).unwrap(); + repo.commit(Some("HEAD"), &sig, &sig, "empty commit", &tree, &[&parent]) + .unwrap(); } let mut req = ::new_req(app.clone(), "foo_conflicts", "1.0.0"); @@ -811,8 +905,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] @@ -824,9 +919,13 @@ fn summary_doesnt_die() { #[test] fn download() { - use ::time::{Duration, now_utc, strftime}; + use time::{Duration, now_utc, strftime}; let (_b, app, middle) = ::app(); - let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates/foo_download/1.0.0/download"); + let mut req = ::req( + app.clone(), + Method::Get, + "/api/v1/crates/foo_download/1.0.0/download", + ); { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); @@ -861,12 +960,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 @@ -874,12 +977,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); @@ -888,12 +995,15 @@ fn download() { #[test] fn download_bad() { let (_b, app, middle) = ::app(); - let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates/foo_bad/0.1.0/download"); + let mut req = ::req( + app.clone(), + Method::Get, + "/api/v1/crates/foo_bad/0.1.0/download", + ); { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); - ::CrateBuilder::new("foo_bad", user.id) - .expect_build(&conn); + ::CrateBuilder::new("foo_bad", user.id).expect_build(&conn); } let response = t_resp!(middle.call(&mut req)); assert_eq!(404, response.status.0) @@ -903,15 +1013,17 @@ fn download_bad() { fn dependencies() { let (_b, app, middle) = ::app(); - let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates/foo_deps/1.0.0/dependencies"); + let mut req = ::req( + app.clone(), + Method::Get, + "/api/v1/crates/foo_deps/1.0.0/dependencies", + ); { let conn = app.diesel_database.get().unwrap(); let user = ::new_user("foo").create_or_update(&conn).unwrap(); - let c1 = ::CrateBuilder::new("foo_deps", user.id) - .expect_build(&conn); + let c1 = ::CrateBuilder::new("foo_deps", user.id).expect_build(&conn); let v = ::new_version(c1.id, "1.0.0").save(&conn, &[]).unwrap(); - let c2 = ::CrateBuilder::new("bar_deps", user.id) - .expect_build(&conn); + let c2 = ::CrateBuilder::new("bar_deps", user.id).expect_build(&conn); ::new_dependency(&conn, &v, &c2); } @@ -927,7 +1039,11 @@ fn dependencies() { #[test] fn diesel_not_found_results_in_404() { let (_b, app, middle) = ::app(); - let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates/foo_following/following"); + let mut req = ::req( + app.clone(), + Method::Get, + "/api/v1/crates/foo_following/following", + ); { let conn = app.diesel_database.get().unwrap(); @@ -941,11 +1057,21 @@ fn diesel_not_found_results_in_404() { #[test] fn following() { - #[derive(RustcDecodable)] struct F { following: bool } - #[derive(RustcDecodable)] struct O { ok: bool } + #[derive(RustcDecodable)] + struct F { + following: bool, + } + #[derive(RustcDecodable)] + struct O { + ok: bool, + } let (_b, app, middle) = ::app(); - let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates/foo_following/following"); + let mut req = ::req( + app.clone(), + Method::Get, + "/api/v1/crates/foo_following/following", + ); let user; { @@ -959,14 +1085,14 @@ fn following() { assert!(!::json::(&mut response).following); req.with_path("/api/v1/crates/foo_following/follow") - .with_method(Method::Put); + .with_method(Method::Put); let mut response = ok_resp!(middle.call(&mut req)); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(&mut req)); assert!(::json::(&mut response).ok); req.with_path("/api/v1/crates/foo_following/following") - .with_method(Method::Get); + .with_method(Method::Get); let mut response = ok_resp!(middle.call(&mut req)); assert!(::json::(&mut response).following); @@ -978,28 +1104,34 @@ fn following() { assert_eq!(l.crates.len(), 1); req.with_path("/api/v1/crates/foo_following/follow") - .with_method(Method::Delete); + .with_method(Method::Delete); let mut response = ok_resp!(middle.call(&mut req)); assert!(::json::(&mut response).ok); let mut response = ok_resp!(middle.call(&mut req)); assert!(::json::(&mut response).ok); req.with_path("/api/v1/crates/foo_following/following") - .with_method(Method::Get); + .with_method(Method::Get); let mut response = ok_resp!(middle.call(&mut req)); assert!(!::json::(&mut response).following); req.with_path("/api/v1/crates") - .with_query("following=1") - .with_method(Method::Get); + .with_query("following=1") + .with_method(Method::Get); let mut response = ok_resp!(middle.call(&mut req)); assert_eq!(::json::(&mut response).crates.len(), 0); } #[test] fn owners() { - #[derive(RustcDecodable)] struct R { users: Vec } - #[derive(RustcDecodable)] struct O { ok: bool } + #[derive(RustcDecodable)] + struct R { + users: Vec, + } + #[derive(RustcDecodable)] + struct O { + ok: bool, + } let (_b, app, middle) = ::app(); let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates/foo_owners/owners"); @@ -1020,8 +1152,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))); @@ -1029,8 +1162,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))); @@ -1038,20 +1172,28 @@ 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); } #[test] fn yank() { - #[derive(RustcDecodable)] struct O { ok: bool } - #[derive(RustcDecodable)] struct V { version: EncodableVersion } + #[derive(RustcDecodable)] + struct O { + ok: bool, + } + #[derive(RustcDecodable)] + struct V { + version: EncodableVersion, + } let (_b, app, middle) = ::app(); let path = ::git::checkout().join("3/f/fyk"); @@ -1061,44 +1203,59 @@ fn yank() { let mut response = ok_resp!(middle.call(&mut req)); ::json::(&mut response); let mut contents = String::new(); - File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + File::open(&path) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); 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).unwrap().read_to_string(&mut contents).unwrap(); + File::open(&path) + .unwrap() + .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).unwrap().read_to_string(&mut contents).unwrap(); + File::open(&path) + .unwrap() + .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); } #[test] fn yank_not_owner() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, ::new_user("bar"), "foo_not"); + 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); } @@ -1122,63 +1279,79 @@ fn yank_max_version() { // add version 2.0.0 let body = ::new_req_body_version_2(::krate("fyk_max")); - let mut response = ok_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_method(Method::Put) - .with_body(&body))); + let mut response = ok_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_method(Method::Put) + .with_body(&body), + ) + ); let json: GoodCrate = ::json(&mut response); 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"); } @@ -1201,28 +1374,36 @@ 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"); // add version 2.0.0 let body = ::new_req_body_version_2(::krate("fyk_max")); - let mut response = ok_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_method(Method::Put) - .with_body(&body))); + let mut response = ok_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_method(Method::Put) + .with_body(&body), + ) + ); let json: GoodCrate = ::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"); } @@ -1273,7 +1454,9 @@ fn good_categories() { ::sign_in(&mut req, &app); { let conn = app.diesel_database.get().unwrap(); - ::new_category("Category 1", "cat1").find_or_create(&conn).unwrap(); + ::new_category("Category 1", "cat1") + .find_or_create(&conn) + .unwrap(); } let mut response = ok_resp!(middle.call(&mut req)); let json: GoodCrate = ::json(&mut response); @@ -1303,7 +1486,7 @@ fn good_badges() { let mut badge_attributes = HashMap::new(); badge_attributes.insert( String::from("repository"), - String::from("rust-lang/crates.io") + String::from("rust-lang/crates.io"), ); badges.insert(String::from("travis-ci"), badge_attributes); @@ -1316,9 +1499,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); @@ -1338,18 +1521,12 @@ fn ignored_badges() { // Known badge type, missing required repository attribute let mut badge_attributes = HashMap::new(); - badge_attributes.insert( - String::from("branch"), - String::from("master") - ); + badge_attributes.insert(String::from("branch"), String::from("master")); badges.insert(String::from("travis-ci"), badge_attributes); // Unknown badge type let mut unknown_badge_attributes = HashMap::new(); - unknown_badge_attributes.insert( - String::from("repository"), - String::from("rust-lang/rust") - ); + unknown_badge_attributes.insert(String::from("repository"), String::from("rust-lang/rust")); badges.insert(String::from("not-a-badge"), unknown_badge_attributes); let (_b, app, middle) = ::app(); @@ -1362,12 +1539,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())); + 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); @@ -1381,8 +1562,7 @@ fn reverse_dependencies() { let v100 = semver::Version::parse("1.0.0").unwrap(); let v110 = semver::Version::parse("1.1.0").unwrap(); - let mut req = ::req(app, Method::Get, - "/api/v1/crates/c1/reverse_dependencies"); + let mut req = ::req(app, Method::Get, "/api/v1/crates/c1/reverse_dependencies"); ::mock_user(&mut req, ::user("foo")); let (c1, _) = ::mock_crate_vers(&mut req, ::krate("c1"), &v100); let (_, c2v1) = ::mock_crate_vers(&mut req, ::krate("c2"), &v100); @@ -1413,8 +1593,7 @@ fn reverse_dependencies_when_old_version_doesnt_depend_but_new_does() { let v100 = semver::Version::parse("1.0.0").unwrap(); let v110 = semver::Version::parse("1.1.0").unwrap(); let v200 = semver::Version::parse("2.0.0").unwrap(); - let mut req = ::req(app, Method::Get, - "/api/v1/crates/c1/reverse_dependencies"); + let mut req = ::req(app, Method::Get, "/api/v1/crates/c1/reverse_dependencies"); ::mock_user(&mut req, ::user("foo")); let (c1, _) = ::mock_crate_vers(&mut req, ::krate("c1"), &v110); let _ = ::mock_crate_vers(&mut req, ::krate("c2"), &v100); @@ -1435,8 +1614,7 @@ fn reverse_dependencies_when_old_version_depended_but_new_doesnt() { let v100 = semver::Version::parse("1.0.0").unwrap(); let v200 = semver::Version::parse("2.0.0").unwrap(); - let mut req = ::req(app, Method::Get, - "/api/v1/crates/c1/reverse_dependencies"); + let mut req = ::req(app, Method::Get, "/api/v1/crates/c1/reverse_dependencies"); ::mock_user(&mut req, ::user("foo")); let (c1, _) = ::mock_crate_vers(&mut req, ::krate("c1"), &v100); let (_, c2v1) = ::mock_crate_vers(&mut req, ::krate("c2"), &v100); @@ -1456,8 +1634,7 @@ fn prerelease_versions_not_included_in_reverse_dependencies() { let v100 = semver::Version::parse("1.0.0").unwrap(); let v110_pre = semver::Version::parse("1.1.0-pre").unwrap(); - let mut req = ::req(app, Method::Get, - "/api/v1/crates/c1/reverse_dependencies"); + let mut req = ::req(app, Method::Get, "/api/v1/crates/c1/reverse_dependencies"); ::mock_user(&mut req, ::user("foo")); let (c1, _) = ::mock_crate_vers(&mut req, ::krate("c1"), &v100); let _ = ::mock_crate_vers(&mut req, ::krate("c2"), &v110_pre); @@ -1479,8 +1656,7 @@ fn yanked_versions_not_included_in_reverse_dependencies() { let v100 = semver::Version::parse("1.0.0").unwrap(); let v200 = semver::Version::parse("2.0.0").unwrap(); - let mut req = ::req(app, Method::Get, - "/api/v1/crates/c1/reverse_dependencies"); + let mut req = ::req(app, Method::Get, "/api/v1/crates/c1/reverse_dependencies"); ::mock_user(&mut req, ::user("foo")); let (c1, _) = ::mock_crate_vers(&mut req, ::krate("c1"), &v100); let _ = ::mock_crate_vers(&mut req, ::krate("c2"), &v100); @@ -1514,28 +1690,30 @@ fn author_license_and_description_required() { new_crate.authors = Vec::new(); req.with_body(&::new_crate_to_body(&new_crate, &[])); 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); + assert!( + json.errors[0].detail.contains("author") && json.errors[0].detail.contains("description") && json.errors[0].detail.contains("license"), + "{:?}", + json.errors + ); new_crate.license = Some("MIT".to_string()); new_crate.authors.push("".to_string()); req.with_body(&::new_crate_to_body(&new_crate, &[])); 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); + assert!( + json.errors[0].detail.contains("author") && json.errors[0].detail.contains("description") && !json.errors[0].detail.contains("license"), + "{:?}", + json.errors + ); new_crate.license = None; new_crate.license_file = Some("foo".to_string()); new_crate.authors.push("foo".to_string()); req.with_body(&::new_crate_to_body(&new_crate, &[])); 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); + assert!( + !json.errors[0].detail.contains("author") && 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 2a29ee01614..de0d26a869f 100644 --- a/src/tests/record.rs +++ b/src/tests/record.rs @@ -37,7 +37,9 @@ impl Write for Sink { fn write(&mut self, data: &[u8]) -> io::Result { Write::write(&mut *self.0.lock().unwrap(), data) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } } impl Drop for Bomb { @@ -45,12 +47,11 @@ impl Drop for Bomb { t!(self.quit.send(())); drop(TcpStream::connect(&t!(self.accept.local_addr()))); let res = self.rx.recv(); - let stderr = str::from_utf8(&self.iorx.0.lock().unwrap()).unwrap() - .to_string(); + let stderr = str::from_utf8(&self.iorx.0.lock().unwrap()) + .unwrap() + .to_string(); match res { - Err(..) if !thread::panicking() => { - panic!("server subtask failed: {}", stderr) - } + Err(..) if !thread::panicking() => panic!("server subtask failed: {}", stderr), _ => { if stderr.len() > 0 { println!("server subtask failed: {}", stderr) @@ -61,7 +62,11 @@ impl Drop for Bomb { } fn cache_file(name: &str) -> PathBuf { - PathBuf::from(file!()).parent().unwrap().join("http-data").join(name) + PathBuf::from(file!()) + .parent() + .unwrap() + .join("http-data") + .join(name) } pub fn proxy() -> (String, Bomb) { @@ -81,10 +86,12 @@ pub fn proxy() -> (String, Bomb) { let (quittx, quitrx) = channel(); - thread::spawn(move|| { + thread::spawn(move || { let mut file = None; for socket in a.incoming() { - if quitrx.try_recv().is_ok() { break } + if quitrx.try_recv().is_ok() { + break; + } let socket = t!(socket); if file.is_none() { @@ -112,7 +119,15 @@ pub fn proxy() -> (String, Bomb) { 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) { @@ -124,11 +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); @@ -145,7 +163,7 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { for line in lines { let line = t!(line); if line.len() < 3 { - break + break; } t!(headers.append(&line)); } @@ -173,9 +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()); } @@ -183,15 +201,13 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { (handle, headers, response) } - 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())); + 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(), + )); for header in headers { if header.starts_with(b"Transfer-Encoding: ") { - continue + continue; } t!(socket.write_all(&header)); t!(socket.write_all(b"\r\n")); @@ -201,8 +217,7 @@ fn record_http(mut socket: TcpStream, data: &mut BufStream) { } } -fn replay_http(socket: TcpStream, data: &mut BufStream, - stdout: &mut Write) { +fn replay_http(socket: TcpStream, data: &mut BufStream, stdout: &mut Write) { let mut writer = socket.try_clone().unwrap(); let socket = BufReader::new(socket); @@ -218,22 +233,35 @@ fn replay_http(socket: TcpStream, data: &mut BufStream, let mut actual_lines = socket.lines().map(|s| s.unwrap()); // validate the headers - let mut expected: HashSet = expected_lines.by_ref() - .take_while(|l| l.len() > 2) - .collect(); + let mut expected: HashSet = expected_lines + .by_ref() + .take_while(|l| l.len() > 2) + .collect(); let mut found = HashSet::new(); t!(writeln!(stdout, "expecting: {:?}", expected)); for line in actual_lines.by_ref().take_while(|l| l.len() > 2) { t!(writeln!(stdout, "received: {}", line.trim())); - if !found.insert(line.clone()) { continue } - if expected.remove(&line) { continue } - if line.starts_with("Date:") { continue } - if line.starts_with("Authorization:") { continue } + if !found.insert(line.clone()) { + continue; + } + if expected.remove(&line) { + continue; + } + if line.starts_with("Date:") { + continue; + } + if line.starts_with("Authorization:") { + continue; + } panic!("unexpected header: {}", line); } for line in expected.iter() { - if line.starts_with("Date:") { continue } - if line.starts_with("Authorization:") { continue } + if line.starts_with("Date:") { + continue; + } + if line.starts_with("Authorization:") { + continue; + } panic!("didn't receive header: {}", line); } @@ -247,10 +275,11 @@ fn replay_http(socket: TcpStream, data: &mut BufStream, let response_size = response.next().unwrap().trim().parse().unwrap(); let mut response = Vec::new(); 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()); + let lines = <[_]>::split(&response[..], |b| *b == b'\n').map(|s| str::from_utf8(s).unwrap()); for line in lines { - if line.starts_with("Date:") { continue } + if line.starts_with("Date:") { + continue; + } writer.write_all(line.as_bytes()).unwrap(); writer.write_all(b"\r\n").unwrap(); } @@ -262,22 +291,28 @@ impl GhUser { self.init.call_once(|| self.init()); let mut u = ::new_user(self.login); u.gh_access_token = Cow::Owned(self.token()); - return u + return u; } - fn filename(&self) -> PathBuf { cache_file(&format!("gh-{}", self.login)) } + fn filename(&self) -> PathBuf { + cache_file(&format!("gh-{}", self.login)) + } fn token(&self) -> String { let mut token = String::new(); - File::open(&self.filename()).unwrap().read_to_string(&mut token).unwrap(); - return token + File::open(&self.filename()) + .unwrap() + .read_to_string(&mut token) + .unwrap(); + return token; } fn init(&self) { - if fs::metadata(&self.filename()).is_ok() { return } + if fs::metadata(&self.filename()).is_ok() { + return; + } - let password = ::env(&format!("GH_PASS_{}", - self.login.replace("-", "_"))); + let password = ::env(&format!("GH_PASS_{}", self.login.replace("-", "_"))); #[derive(RustcEncodable)] struct Authorization { scopes: Vec, @@ -286,8 +321,11 @@ impl GhUser { client_secret: String, } let mut handle = Easy::new(); - let url = format!("https://{}:{}@api.github.com/authorizations", - self.login, password); + let url = format!( + "https://{}:{}@api.github.com/authorizations", + self.login, + password + ); let body = json::encode(&Authorization { scopes: vec!["read:org".to_string()], note: "crates.io test".to_string(), @@ -306,9 +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()) @@ -317,15 +355,17 @@ impl GhUser { } if t!(handle.response_code()) < 200 || t!(handle.response_code()) >= 300 { - panic!("failed to get a 200 {}", - String::from_utf8_lossy(&response)); + panic!("failed to get a 200 {}", String::from_utf8_lossy(&response)); } #[derive(RustcDecodable)] - struct Response { token: String } - let resp: Response = json::decode(str::from_utf8(&response) - .unwrap()).unwrap(); - File::create(&self.filename()).unwrap() - .write_all(&resp.token.as_bytes()).unwrap(); + struct Response { + token: String, + } + let resp: Response = json::decode(str::from_utf8(&response).unwrap()).unwrap(); + File::create(&self.filename()) + .unwrap() + .write_all(&resp.token.as_bytes()) + .unwrap(); } } diff --git a/src/tests/team.rs b/src/tests/team.rs index 52ff6f5d135..b9658a563c1 100644 --- a/src/tests/team.rs +++ b/src/tests/team.rs @@ -9,11 +9,21 @@ use record::GhUser; // Teams: `crates-test-org:owners`, `crates-test-org:just-for-crates-2` // tester-1 is on owners only, tester-2 is on both -static GH_USER_1: GhUser = GhUser { login: "crates-tester-1", init: ONCE_INIT }; -static GH_USER_2: GhUser = GhUser { login: "crates-tester-2", init: ONCE_INIT }; - -fn mock_user_on_only_x() -> NewUser<'static> { GH_USER_1.user() } -fn mock_user_on_x_and_y() -> NewUser<'static> { GH_USER_2.user() } +static GH_USER_1: GhUser = GhUser { + login: "crates-tester-1", + init: ONCE_INIT, +}; +static GH_USER_2: GhUser = GhUser { + login: "crates-tester-2", + init: ONCE_INIT, +}; + +fn mock_user_on_only_x() -> NewUser<'static> { + GH_USER_1.user() +} +fn mock_user_on_x_and_y() -> NewUser<'static> { + GH_USER_2.user() +} fn body_for_team_y() -> &'static str { r#"{"users":["github:crates-test-org:just-for-crates-2"]}"# @@ -27,103 +37,147 @@ fn body_for_team_x() -> &'static str { #[test] fn not_github() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_not_github"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_not_github"); let body = r#"{"users":["dropbox:foo:foo"]}"#; - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_not_github/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); - assert!(json.errors[0].detail.contains("unknown organization"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_not_github/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); + assert!( + json.errors[0].detail.contains("unknown organization"), + "{:?}", + json.errors + ); } #[test] fn weird_name() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_weird_name"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_weird_name"); let body = r#"{"users":["github:foo/../bar:wut"]}"#; - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_weird_name/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); - assert!(json.errors[0].detail.contains("organization cannot contain"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_weird_name/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); + assert!( + json.errors[0].detail.contains( + "organization cannot contain", + ), + "{:?}", + json.errors + ); } // Test adding team without second `:` #[test] fn one_colon() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_one_colon"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_one_colon"); let body = r#"{"users":["github:foo"]}"#; - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_one_colon/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); - assert!(json.errors[0].detail.contains("missing github team"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_one_colon/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); + assert!( + json.errors[0].detail.contains("missing github team"), + "{:?}", + json.errors + ); } #[test] fn nonexistent_team() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_nonexistent"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_nonexistent"); let body = r#"{"users":["github:crates-test-org:this-does-not-exist"]}"#; - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_nonexistent/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); - assert!(json.errors[0].detail.contains("could not find the github team"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_nonexistent/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); + assert!( + json.errors[0].detail.contains( + "could not find the github team", + ), + "{:?}", + json.errors + ); } // Test adding team as owner when on it #[test] fn add_team_as_member() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_team_member"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_team_member"); let body = body_for_team_x(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_team_member/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_team_member/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); } // Test adding team as owner when not on in #[test] fn add_team_as_non_member() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_only_x(), "foo_team_non_member"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_only_x(), "foo_team_non_member"); let body = body_for_team_y(); - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_team_non_member/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); - assert!(json.errors[0].detail.contains("only members"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_team_non_member/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); + assert!( + json.errors[0].detail.contains("only members"), + "{:?}", + json.errors + ); } #[test] fn remove_team_as_named_owner() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_remove_team"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_remove_team"); let body = body_for_team_x(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_remove_team/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_remove_team/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); let body = body_for_team_x(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_remove_team/owners") - .with_method(Method::Delete) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_remove_team/owners") + .with_method(Method::Delete) + .with_body(body.as_bytes()), + ) + ); { let conn = app.diesel_database.get().unwrap(); @@ -131,23 +185,33 @@ fn remove_team_as_named_owner() { ::sign_in_as(&mut req, &user); } let body = ::new_req_body_version_2(::krate("foo_remove_team")); - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_body(&body) - .with_method(Method::Put))); - assert!(json.errors[0].detail.contains("another user"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_body(&body) + .with_method(Method::Put), + ) + ); + assert!( + json.errors[0].detail.contains("another user"), + "{:?}", + json.errors + ); } #[test] fn remove_team_as_team_owner() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_remove_team_owner"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_remove_team_owner"); let body = body_for_team_x(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_remove_team_owner/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_remove_team_owner/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); { let conn = app.diesel_database.get().unwrap(); @@ -155,17 +219,28 @@ fn remove_team_as_team_owner() { ::sign_in_as(&mut req, &user); } let body = body_for_team_x(); - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_remove_team_owner/owners") - .with_method(Method::Delete) - .with_body(body.as_bytes()))); - - assert!(json.errors[0].detail.contains("don't have permission"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_remove_team_owner/owners") + .with_method(Method::Delete) + .with_body(body.as_bytes()), + ) + ); + + assert!( + json.errors[0].detail.contains("don't have permission"), + "{:?}", + json.errors + ); let body = ::new_req_body_version_2(::krate("foo_remove_team_owner")); - ok_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_body(&body) - .with_method(Method::Put))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_body(&body) + .with_method(Method::Put), + ) + ); } // Test trying to publish a krate we don't own @@ -173,13 +248,16 @@ fn remove_team_as_team_owner() { fn publish_not_owned() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_not_owned"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_not_owned"); let body = body_for_team_y(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_not_owned/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_not_owned/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); { let conn = app.diesel_database.get().unwrap(); @@ -187,24 +265,34 @@ fn publish_not_owned() { ::sign_in_as(&mut req, &user); } let body = ::new_req_body_version_2(::krate("foo_not_owned")); - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_body(&body) - .with_method(Method::Put))); - assert!(json.errors[0].detail.contains("another user"), - "{:?}", json.errors); + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_body(&body) + .with_method(Method::Put), + ) + ); + assert!( + json.errors[0].detail.contains("another user"), + "{:?}", + json.errors + ); } // Test trying to publish a krate we do own (but only because of teams) #[test] fn publish_owned() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_team_owned"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_team_owned"); let body = body_for_team_x(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_team_owned/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_team_owned/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); { let conn = app.diesel_database.get().unwrap(); @@ -212,32 +300,46 @@ fn publish_owned() { ::sign_in_as(&mut req, &user); } let body = ::new_req_body_version_2(::krate("foo_team_owned")); - ok_resp!(middle.call(req.with_path("/api/v1/crates/new") - .with_body(&body) - .with_method(Method::Put))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/new") + .with_body(&body) + .with_method(Method::Put), + ) + ); } // Test trying to change owners (when only on an owning team) #[test] fn add_owners_as_team_owner() { let (_b, app, middle) = ::app(); - let mut req = ::request_with_user_and_mock_crate( - &app, mock_user_on_x_and_y(), "foo_add_owner"); + let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_add_owner"); let body = body_for_team_x(); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_add_owner/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_add_owner/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); { let conn = app.diesel_database.get().unwrap(); let user = mock_user_on_only_x().create_or_update(&conn).unwrap(); ::sign_in_as(&mut req, &user); } - let body = r#"{"users":["FlashCat"]}"#; // User doesn't matter - let json = bad_resp!(middle.call(req.with_path("/api/v1/crates/foo_add_owner/owners") - .with_method(Method::Put) - .with_body(body.as_bytes()))); - assert!(json.errors[0].detail.contains("don't have permission"), - "{:?}", json.errors); + let body = r#"{"users":["FlashCat"]}"#; // User doesn't matter + let json = bad_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_add_owner/owners") + .with_method(Method::Put) + .with_body(body.as_bytes()), + ) + ); + assert!( + json.errors[0].detail.contains("don't have permission"), + "{:?}", + json.errors + ); } diff --git a/src/tests/user.rs b/src/tests/user.rs index 2372eec8c34..0e99b3d1246 100644 --- a/src/tests/user.rs +++ b/src/tests/user.rs @@ -7,11 +7,19 @@ use cargo_registry::user::{User, NewUser, EncodableUser}; use cargo_registry::version::EncodableVersion; #[derive(RustcDecodable)] -struct AuthResponse { url: String, state: String } +struct AuthResponse { + url: String, + state: String, +} #[derive(RustcDecodable)] -struct MeResponse { user: EncodableUser, api_token: String } +struct MeResponse { + user: EncodableUser, + api_token: String, +} #[derive(RustcDecodable)] -struct UserShowResponse { user: EncodableUser } +struct UserShowResponse { + user: EncodableUser, +} #[test] fn auth_gives_a_token() { @@ -41,16 +49,16 @@ fn user_insert() { assert_eq!(t!(User::find_by_api_token(&tx, &user.api_token)), user); assert_eq!(t!(User::find(&tx, user.id)), user); - assert_eq!(t!(User::find_or_insert(&tx, 1, "foo", None, None, None, - "bar")), user); - let user2 = t!(User::find_or_insert(&tx, 1, "foo", None, None, None, - "baz")); + assert_eq!( + t!(User::find_or_insert(&tx, 1, "foo", None, None, None, "bar")), + user + ); + let user2 = t!(User::find_or_insert(&tx, 1, "foo", None, None, None, "baz")); assert!(user != user2); assert_eq!(user.id, user2.id); assert_eq!(user2.gh_access_token, "baz"); - let user3 = t!(User::find_or_insert(&tx, 1, "bar", None, None, None, - "baz")); + let user3 = t!(User::find_or_insert(&tx, 1, "bar", None, None, None, "baz")); assert!(user != user3); assert_eq!(user.id, user3.id); assert_eq!(user3.gh_login, "bar"); @@ -97,8 +105,7 @@ fn show() { fn reset_token() { let (_b, app, middle) = ::app(); let mut req = ::req(app, Method::Put, "/me/reset_token"); - let user = User::find_or_insert(req.tx().unwrap(), 1, "foo", None, - None, None, "bar").unwrap(); + let user = User::find_or_insert(req.tx().unwrap(), 1, "foo", None, None, None, "bar").unwrap(); ::sign_in_as(&mut req, &user); ok_resp!(middle.call(&mut req)); @@ -112,11 +119,8 @@ fn crates_by_user_id() { let u; { let conn = app.diesel_database.get().unwrap(); - u = ::new_user("foo") - .create_or_update(&conn) - .unwrap(); - ::CrateBuilder::new("foo_my_packages", u.id) - .expect_build(&conn); + u = ::new_user("foo").create_or_update(&conn).unwrap(); + ::CrateBuilder::new("foo_my_packages", u.id).expect_build(&conn); } let mut req = ::req(app, Method::Get, "/api/v1/crates"); @@ -124,7 +128,9 @@ fn crates_by_user_id() { let mut response = ok_resp!(middle.call(&mut req)); #[derive(RustcDecodable)] - struct Response { crates: Vec } + struct Response { + crates: Vec, + } let response: Response = ::json(&mut response); assert_eq!(response.crates.len(), 1); } @@ -136,7 +142,10 @@ fn following() { versions: Vec, meta: Meta, } - #[derive(RustcDecodable)] struct Meta { more: bool } + #[derive(RustcDecodable)] + struct Meta { + more: bool, + } let (_b, app, middle) = ::app(); let mut req = ::req(app.clone(), Method::Get, "/"); @@ -154,35 +163,57 @@ 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); - ok_resp!(middle.call(req.with_path("/api/v1/crates/foo_fighters/follow") - .with_method(Method::Put))); - ok_resp!(middle.call(req.with_path("/api/v1/crates/bar_fighters/follow") - .with_method(Method::Put))); - - let mut response = ok_resp!(middle.call(req.with_path("/me/updates") - .with_method(Method::Get))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/foo_fighters/follow") + .with_method(Method::Put), + ) + ); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/bar_fighters/follow") + .with_method(Method::Put), + ) + ); + + 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); - let mut response = ok_resp!(middle.call(req.with_path("/me/updates") - .with_method(Method::Get) - .with_query("per_page=1"))); + let mut response = ok_resp!( + middle.call( + req.with_path("/me/updates") + .with_method(Method::Get) + .with_query("per_page=1"), + ) + ); let r = ::json::(&mut response); assert_eq!(r.versions.len(), 1); assert_eq!(r.meta.more, true); - ok_resp!(middle.call(req.with_path("/api/v1/crates/bar_fighters/follow") - .with_method(Method::Delete))); - let mut response = ok_resp!(middle.call(req.with_path("/me/updates") - .with_method(Method::Get) - .with_query("page=2&per_page=1"))); + ok_resp!( + middle.call( + req.with_path("/api/v1/crates/bar_fighters/follow") + .with_method(Method::Delete), + ) + ); + let mut response = ok_resp!( + middle.call( + req.with_path("/me/updates") + .with_method(Method::Get) + .with_query("page=2&per_page=1"), + ) + ); let r = ::json::(&mut response); assert_eq!(r.versions.len(), 0); assert_eq!(r.meta.more, false); diff --git a/src/tests/version.rs b/src/tests/version.rs index 00501ed7449..db8851d1447 100644 --- a/src/tests/version.rs +++ b/src/tests/version.rs @@ -8,9 +8,13 @@ use cargo_registry::db::RequestTransaction; use cargo_registry::version::{EncodableVersion, Version}; #[derive(RustcDecodable)] -struct VersionList { versions: Vec } +struct VersionList { + versions: Vec, +} #[derive(RustcDecodable)] -struct VersionResponse { version: EncodableVersion } +struct VersionResponse { + version: EncodableVersion, +} fn sv(s: &str) -> semver::Version { semver::Version::parse(s).unwrap() @@ -46,8 +50,7 @@ fn show() { let v = { 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); + let krate = ::CrateBuilder::new("foo_vers_show", user.id).expect_build(&conn); ::new_version(krate.id, "2.0.0").save(&conn, &[]).unwrap() }; req.with_path(&format!("/api/v1/versions/{}", v.id)); diff --git a/src/upload.rs b/src/upload.rs index 7c64b456bf2..b450b1d600c 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -52,16 +52,21 @@ 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!("invalid crate name specified: {}. \ + 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))) + fewer characters.", + s, + MAX_NAME_LENGTH + ))); } Ok(CrateName(s)) } } -impl PartialEq for CrateName where +impl PartialEq for CrateName +where String: PartialEq, { fn eq(&self, rhs: &T) -> bool { @@ -73,7 +78,7 @@ impl Decodable for Keyword { fn decode(d: &mut D) -> Result { let s = d.read_str()?; if !CrateKeyword::valid_name(&s) { - return Err(d.error(&format!("invalid keyword specified: {}", s))) + return Err(d.error(&format!("invalid keyword specified: {}", s))); } Ok(Keyword(s)) } @@ -89,7 +94,7 @@ impl Decodable for Feature { fn decode(d: &mut D) -> Result { let s = d.read_str()?; if !Crate::valid_feature_name(&s) { - return Err(d.error(&format!("invalid feature name specified: {}", s))) + return Err(d.error(&format!("invalid feature name specified: {}", s))); } Ok(Feature(s)) } @@ -115,7 +120,8 @@ impl Decodable for CrateVersionReq { } } -impl PartialEq for CrateVersionReq where +impl PartialEq for CrateVersionReq +where semver::VersionReq: PartialEq, { fn eq(&self, rhs: &T) -> bool { @@ -127,12 +133,14 @@ impl Decodable for KeywordList { fn decode(d: &mut D) -> Result { let inner: Vec = Decodable::decode(d)?; if inner.len() > 5 { - return Err(d.error("a maximum of 5 keywords per crate are allowed")) + return Err(d.error("a maximum of 5 keywords per crate are allowed")); } 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)) @@ -143,7 +151,7 @@ impl Decodable for CategoryList { fn decode(d: &mut D) -> Result { let inner: Vec = Decodable::decode(d)?; if inner.len() > 5 { - return Err(d.error("a maximum of 5 categories per crate are allowed")) + return Err(d.error("a maximum of 5 categories per crate are allowed")); } Ok(CategoryList(inner)) } @@ -156,8 +164,13 @@ impl Decodable for DependencyKind { "dev" => Ok(DependencyKind::Dev), "build" => Ok(DependencyKind::Build), "normal" => Ok(DependencyKind::Normal), - s => Err(d.error(&format!("invalid dependency kind `{}`, must be \ - one of dev, build, or normal", s))), + s => { + Err(d.error(&format!( + "invalid dependency kind `{}`, must be \ + one of dev, build, or normal", + s + ))) + } } } } @@ -224,40 +237,56 @@ impl Encodable for DependencyKind { impl Deref for CrateName { type Target = str; - fn deref(&self) -> &str { &self.0 } + fn deref(&self) -> &str { + &self.0 + } } impl Deref for Keyword { type Target = str; - fn deref(&self) -> &str { &self.0 } + fn deref(&self) -> &str { + &self.0 + } } impl Deref for Category { type Target = str; - fn deref(&self) -> &str { &self.0 } + fn deref(&self) -> &str { + &self.0 + } } impl Deref for Feature { type Target = str; - fn deref(&self) -> &str { &self.0 } + fn deref(&self) -> &str { + &self.0 + } } impl Deref for CrateVersion { type Target = semver::Version; - fn deref(&self) -> &semver::Version { &self.0 } + fn deref(&self) -> &semver::Version { + &self.0 + } } impl Deref for CrateVersionReq { type Target = semver::VersionReq; - fn deref(&self) -> &semver::VersionReq { &self.0 } + fn deref(&self) -> &semver::VersionReq { + &self.0 + } } impl Deref for KeywordList { type Target = [Keyword]; - fn deref(&self) -> &[Keyword] { &self.0 } + fn deref(&self) -> &[Keyword] { + &self.0 + } } impl Deref for CategoryList { type Target = [Category]; - fn deref(&self) -> &[Category] { &self.0 } + fn deref(&self) -> &[Category] { + &self.0 + } } diff --git a/src/uploaders.rs b/src/uploaders.rs index f31e045bb20..d9cfb107a84 100644 --- a/src/uploaders.rs +++ b/src/uploaders.rs @@ -14,7 +14,10 @@ use std::io; pub enum Uploader { /// For production usage, uploads and redirects to s3. /// For test usage with a proxy. - S3 { bucket: s3::Bucket, proxy: Option }, + S3 { + bucket: s3::Bucket, + proxy: Option, + }, /// For development usage only: "uploads" crate files to `dist` and serves them /// from there as well to enable local publishing and download @@ -32,17 +35,20 @@ impl Uploader { } } - pub fn crate_location(&self, crate_name: &str, version: &str) - -> Option { + pub fn crate_location(&self, crate_name: &str, version: &str) -> Option { match *self { Uploader::S3 { ref bucket, .. } => { - Some(format!("https://{}/{}", - bucket.host(), - Uploader::crate_path(crate_name, version))) - }, + Some(format!( + "https://{}/{}", + bucket.host(), + Uploader::crate_path(crate_name, version) + )) + } Uploader::Local => { - Some(format!("/local_uploads/{}", - Uploader::crate_path(crate_name, version))) + Some(format!( + "/local_uploads/{}", + Uploader::crate_path(crate_name, version) + )) } Uploader::NoOp => None, } @@ -64,13 +70,19 @@ impl Uploader { let mut body = HashingReader::new(body); let mut response = Vec::new(); { - let mut s3req = bucket.put(&mut handle, &path, &mut body, - "application/x-tar", - length as u64); - s3req.write_function(|data| { - response.extend(data); - Ok(data.len()) - }).unwrap(); + let mut s3req = bucket.put( + &mut handle, + &path, + &mut body, + "application/x-tar", + length as u64, + ); + s3req + .write_function(|data| { + response.extend(data); + Ok(data.len()) + }) + .unwrap(); s3req.perform().chain_error(|| { internal(&format_args!("failed to upload to S3: `{}`", path)) })?; @@ -79,21 +91,27 @@ impl Uploader { }; if handle.response_code().unwrap() != 200 { let response = String::from_utf8_lossy(&response); - return Err(internal(&format_args!("failed to get a 200 response from S3: {}", - response))) + 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()); - let crate_filename = env::current_dir().unwrap() - .join("dist") - .join("local_uploads") - .join(path); + let crate_filename = env::current_dir() + .unwrap() + .join("dist") + .join("local_uploads") + .join(path); let crate_dir = crate_filename.parent().unwrap(); fs::create_dir_all(crate_dir)?; @@ -109,12 +127,23 @@ impl Uploader { body.finalize() }; - 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(( + 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, + }, + )) + } } } @@ -124,7 +153,7 @@ impl Uploader { let mut handle = app.handle(); bucket.delete(&mut handle, path).perform()?; Ok(()) - }, + } Uploader::Local => { fs::remove_file(path)?; Ok(()) diff --git a/src/user/middleware.rs b/src/user/middleware.rs index 43959aea975..5c84c83aaf9 100644 --- a/src/user/middleware.rs +++ b/src/user/middleware.rs @@ -12,9 +12,11 @@ use util::errors::{CargoResult, Unauthorized, ChainError, std_error}; pub struct Middleware; impl conduit_middleware::Middleware for Middleware { - fn before(&self, req: &mut Request) -> Result<(), Box> { + 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()) }; + let id = { + req.session().get("user_id").and_then(|s| s.parse().ok()) + }; let user = match id { @@ -39,10 +41,10 @@ impl conduit_middleware::Middleware for Middleware { let tx = req.tx().map_err(std_error)?; match User::find_by_api_token(tx, headers[0]) { Ok(user) => user, - Err(..) => return Ok(()) + Err(..) => return Ok(()), } } - None => return Ok(()) + None => return Ok(()), } } }; @@ -59,6 +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 d6359cc7c37..6abe86a8724 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -1,5 +1,5 @@ use conduit::{Request, Response}; -use conduit_cookie::{RequestSession}; +use conduit_cookie::RequestSession; use conduit_router::RequestParams; use diesel::prelude::*; use diesel::pg::PgConnection; @@ -35,7 +35,7 @@ pub struct User { } #[derive(Insertable, AsChangeset)] -#[table_name="users"] +#[table_name = "users"] pub struct NewUser<'a> { pub gh_id: i32, pub gh_login: &'a str, @@ -46,12 +46,7 @@ pub struct NewUser<'a> { } impl<'a> NewUser<'a> { - pub fn new(gh_id: i32, - gh_login: &'a str, - email: Option<&'a str>, - name: Option<&'a str>, - gh_avatar: Option<&'a str>, - gh_access_token: &'a str) -> Self { + pub fn new(gh_id: i32, gh_login: &'a str, email: Option<&'a str>, name: Option<&'a str>, gh_avatar: Option<&'a str>, gh_access_token: &'a str) -> Self { NewUser { gh_id: gh_id, gh_login: gh_login, @@ -90,68 +85,69 @@ pub struct EncodableUser { 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 - WHERE gh_login = $1")?; + pub fn find_by_login(conn: &GenericConnection, login: &str) -> CargoResult { + let stmt = conn.prepare( + "SELECT * FROM users + WHERE gh_login = $1", + )?; let rows = stmt.query(&[&login])?; - let row = rows.iter().next().chain_error(|| { - NotFound - })?; + let row = rows.iter().next().chain_error(|| NotFound)?; Ok(Model::from_row(&row)) } /// 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")?; + pub fn find_by_api_token(conn: &GenericConnection, token: &str) -> CargoResult { + let stmt = conn.prepare( + "SELECT * FROM users \ + WHERE api_token = $1 LIMIT 1", + )?; let rows = stmt.query(&[&token])?; - rows.iter().next().map(|r| Model::from_row(&r)).chain_error(|| { - NotFound - }) + rows.iter() + .next() + .map(|r| Model::from_row(&r)) + .chain_error(|| NotFound) } /// Updates a user or inserts a new user into the database. - pub fn find_or_insert(conn: &GenericConnection, - id: i32, - login: &str, - email: Option<&str>, - name: Option<&str>, - avatar: Option<&str>, - access_token: &str) -> CargoResult { + pub fn find_or_insert( + conn: &GenericConnection, + id: i32, + login: &str, + email: Option<&str>, + name: Option<&str>, + avatar: Option<&str>, + access_token: &str, + ) -> CargoResult { // TODO: this is racy, but it looks like any other solution is... // interesting! For now just do the racy thing which will report // more errors than it needs to. - let stmt = conn.prepare("UPDATE users + let stmt = conn.prepare( + "UPDATE users SET gh_access_token = $1, email = $2, name = $3, gh_avatar = $4, gh_login = $5 WHERE gh_id = $6 - RETURNING *")?; - let rows = stmt.query(&[&access_token, - &email, - &name, - &avatar, - &login, - &id])?; + 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 + let stmt = conn.prepare( + "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])?; + 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") })?)) @@ -159,7 +155,14 @@ impl User { /// Converts this `User` model into an `EncodableUser` for JSON serialization. pub fn encodable(self) -> EncodableUser { - let User { id, email, name, gh_login, gh_avatar, .. } = self; + let User { + id, + email, + name, + gh_login, + gh_avatar, + .. + } = self; let url = format!("https://github.com/{}", gh_login); EncodableUser { id: id, @@ -186,7 +189,9 @@ impl Model for User { } } - fn table_name(_: Option) -> &'static str { "users" } + fn table_name(_: Option) -> &'static str { + "users" + } } /// Handles the `GET /authorize_url` route. @@ -207,13 +212,22 @@ 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()); #[derive(RustcEncodable)] - struct R { url: String, state: String } - Ok(req.json(&R { url: url.to_string(), state: state })) + struct R { + url: String, + state: String, + } + Ok(req.json(&R { + url: url.to_string(), + state: state, + })) } /// Handles the `GET /authorize` route. @@ -256,7 +270,7 @@ pub fn github_access_token(req: &mut Request) -> CargoResult { let session_state = req.session().remove(&"github_oauth_state".to_string()); let session_state = session_state.as_ref().map(|a| &a[..]); if Some(&state[..]) != session_state { - return Err(human("invalid state parameter")) + return Err(human("invalid state parameter")); } } @@ -270,23 +284,26 @@ 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)?; - let user = User::find_or_insert(req.tx()?, - ghuser.id, - &ghuser.login, - ghuser.email.as_ref() - .map(|s| &s[..]), - ghuser.name.as_ref() - .map(|s| &s[..]), - ghuser.avatar_url.as_ref() - .map(|s| &s[..]), - &token.access_token)?; - req.session().insert("user_id".to_string(), user.id.to_string()); + let user = User::find_or_insert( + req.tx()?, + ghuser.id, + &ghuser.login, + ghuser.email.as_ref().map(|s| &s[..]), + ghuser.name.as_ref().map(|s| &s[..]), + ghuser.avatar_url.as_ref().map(|s| &s[..]), + &token.access_token, + )?; + req.session().insert( + "user_id".to_string(), + user.id.to_string(), + ); req.mut_extensions().insert(user); me(req) } @@ -302,14 +319,19 @@ pub fn reset_token(req: &mut Request) -> CargoResult { let user = req.user()?; let conn = req.tx()?; - let rows = conn.query("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)?; + let rows = conn.query( + "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, + )?; #[derive(RustcEncodable)] - struct R { api_token: String } + struct R { + api_token: String, + } Ok(req.json(&R { api_token: token })) } @@ -318,9 +340,15 @@ pub fn me(req: &mut Request) -> CargoResult { let user = req.user()?; #[derive(RustcEncodable)] - struct R { user: EncodableUser, api_token: String } + struct R { + user: EncodableUser, + 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. @@ -329,14 +357,13 @@ pub fn show(req: &mut Request) -> CargoResult { let name = &req.params()["user_id"]; let conn = req.db_conn()?; - let user = users.filter(gh_login.eq(name)) - .first::(&*conn)?; + let user = users.filter(gh_login.eq(name)).first::(&*conn)?; #[derive(RustcEncodable)] struct R { user: EncodableUser, } - Ok(req.json(&R{ user: user.encodable() })) + Ok(req.json(&R { user: user.encodable() })) } @@ -349,9 +376,9 @@ pub fn updates(req: &mut Request) -> CargoResult { let (offset, limit) = req.pagination(10, 100)?; let conn = req.db_conn()?; - let followed_crates = Follow::belonging_to(user) - .select(follows::crate_id); - let data = versions::table.inner_join(crates::table) + let followed_crates = Follow::belonging_to(user).select(follows::crate_id); + let data = versions::table + .inner_join(crates::table) .filter(crates::id.eq(any(followed_crates))) .order(versions::created_at.desc()) .limit(limit) @@ -367,9 +394,9 @@ pub fn updates(req: &mut Request) -> CargoResult { .map(|&(_, _, count)| count > offset + limit) .unwrap_or(false); - let versions = data.into_iter().map(|(version, crate_name, _)| { - version.encodable(&crate_name) - }).collect(); + let versions = data.into_iter() + .map(|(version, crate_name, _)| version.encodable(&crate_name)) + .collect(); #[derive(RustcEncodable)] struct R { @@ -377,8 +404,13 @@ pub fn updates(req: &mut Request) -> CargoResult { meta: Meta, } #[derive(RustcEncodable)] - struct Meta { more: bool } - Ok(req.json(&R{ versions: versions, meta: Meta { more: more } })) + struct Meta { + more: bool, + } + Ok(req.json(&R { + versions: versions, + meta: Meta { more: more }, + })) } #[cfg(test)] @@ -390,8 +422,7 @@ 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 @@ -401,9 +432,11 @@ mod tests { fn new_users_have_different_api_tokens() { let conn = connection(); let user1 = NewUser::new(1, "foo", None, None, None, "foo") - .create_or_update(&conn).unwrap(); + .create_or_update(&conn) + .unwrap(); let user2 = NewUser::new(2, "bar", None, None, None, "bar") - .create_or_update(&conn).unwrap(); + .create_or_update(&conn) + .unwrap(); assert_ne!(user1.id, user2.id); assert_ne!(user1.api_token, user2.api_token); @@ -414,10 +447,12 @@ mod tests { fn updating_existing_user_doesnt_change_api_token() { let conn = connection(); let user_after_insert = NewUser::new(1, "foo", None, None, None, "foo") - .create_or_update(&conn).unwrap(); + .create_or_update(&conn) + .unwrap(); let original_token = user_after_insert.api_token; NewUser::new(1, "bar", None, None, None, "bar_token") - .create_or_update(&conn).unwrap(); + .create_or_update(&conn) + .unwrap(); let mut users = users::table.load::(&conn).unwrap(); assert_eq!(1, users.len()); let user = users.pop().unwrap(); diff --git a/src/util/errors.rs b/src/util/errors.rs index 6fa45c96d83..f89d9d6d43f 100644 --- a/src/util/errors.rs +++ b/src/util/errors.rs @@ -3,30 +3,40 @@ use std::error::Error; use std::fmt; use conduit::Response; -use diesel::result::{Error as DieselError}; +use diesel::result::Error as DieselError; use util::json_response; -#[derive(RustcEncodable)] struct StringError { detail: String } -#[derive(RustcEncodable)] struct Bad { errors: Vec } +#[derive(RustcEncodable)] +struct StringError { + detail: String, +} +#[derive(RustcEncodable)] +struct Bad { + errors: Vec, +} // ============================================================================= // CargoError trait pub trait CargoError: Send + fmt::Display + 'static { fn description(&self) -> &str; - fn cause(&self) -> Option<&(CargoError)> { None } + fn cause(&self) -> Option<&(CargoError)> { + None + } fn response(&self) -> Option { if self.human() { Some(json_response(&Bad { - errors: vec![StringError { detail: self.description().to_string() }] + errors: vec![StringError { detail: self.description().to_string() }], })) } else { self.cause().and_then(|cause| cause.response()) } } - fn human(&self) -> bool { false } + fn human(&self) -> bool { + false + } } impl fmt::Debug for Box { @@ -36,16 +46,32 @@ impl fmt::Debug for Box { } impl CargoError for Box { - fn description(&self) -> &str { (**self).description() } - fn cause(&self) -> Option<&CargoError> { (**self).cause() } - fn human(&self) -> bool { (**self).human() } - fn response(&self) -> Option { (**self).response() } + fn description(&self) -> &str { + (**self).description() + } + fn cause(&self) -> Option<&CargoError> { + (**self).cause() + } + fn human(&self) -> bool { + (**self).human() + } + fn response(&self) -> Option { + (**self).response() + } } impl CargoError for Box { - fn description(&self) -> &str { (**self).description() } - fn cause(&self) -> Option<&CargoError> { (**self).cause() } - fn human(&self) -> bool { (**self).human() } - fn response(&self) -> Option { (**self).response() } + fn description(&self) -> &str { + (**self).description() + } + fn cause(&self) -> Option<&CargoError> { + (**self).cause() + } + fn human(&self) -> bool { + (**self).human() + } + fn response(&self) -> Option { + (**self).response() + } } pub type CargoResult = Result>; @@ -55,7 +81,9 @@ pub type CargoResult = Result>; pub trait ChainError { fn chain_error(self, callback: F) -> CargoResult - where E: CargoError, F: FnOnce() -> E; + where + E: CargoError, + F: FnOnce() -> E; } struct ChainedError { @@ -63,9 +91,15 @@ struct ChainedError { cause: Box, } -impl ChainError for F where F: FnOnce() -> CargoResult { +impl ChainError for F +where + F: FnOnce() -> CargoResult, +{ fn chain_error(self, callback: C) -> CargoResult - where E: CargoError, C: FnOnce() -> E { + where + E: CargoError, + C: FnOnce() -> E, + { self().chain_error(callback) } } @@ -73,7 +107,10 @@ impl ChainError for F where F: FnOnce() -> CargoResult { impl ChainError for Result { #[allow(trivial_casts)] fn chain_error(self, callback: C) -> CargoResult - where E2: CargoError, C: FnOnce() -> E2 { + where + E2: CargoError, + C: FnOnce() -> E2, + { self.map_err(move |err| { Box::new(ChainedError { error: callback(), @@ -85,7 +122,10 @@ impl ChainError for Result { impl ChainError for Option { fn chain_error(self, callback: C) -> CargoResult - where E: CargoError, C: FnOnce() -> E { + where + E: CargoError, + C: FnOnce() -> E, + { match self { Some(t) => Ok(t), None => Err(Box::new(callback())), @@ -94,10 +134,18 @@ impl ChainError for Option { } impl CargoError for ChainedError { - fn description(&self) -> &str { self.error.description() } - fn cause(&self) -> Option<&CargoError> { Some(&*self.cause) } - fn response(&self) -> Option { self.error.response() } - fn human(&self) -> bool { self.error.human() } + fn description(&self) -> &str { + self.error.description() + } + fn cause(&self) -> Option<&CargoError> { + Some(&*self.cause) + } + fn response(&self) -> Option { + self.error.response() + } + fn human(&self) -> bool { + self.error.human() + } } impl fmt::Display for ChainedError { @@ -119,7 +167,9 @@ impl From for Box { struct Shim(E); impl CargoError for Shim { - fn description(&self) -> &str { Error::description(&self.0) } + fn description(&self) -> &str { + Error::description(&self.0) + } } impl fmt::Display for Shim { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -131,10 +181,14 @@ impl From for Box { } impl CargoError for ::curl::Error { - fn description(&self) -> &str { Error::description(self) } + fn description(&self) -> &str { + Error::description(self) + } } impl CargoError for ::rustc_serialize::json::DecoderError { - fn description(&self) -> &str { Error::description(self) } + fn description(&self) -> &str { + Error::description(self) + } } // ============================================================================= @@ -158,15 +212,23 @@ impl fmt::Display for ConcreteCargoError { } impl CargoError for ConcreteCargoError { - fn description(&self) -> &str { &self.description } - fn cause(&self) -> Option<&CargoError> { self.cause.as_ref().map(|c| &**c) } - fn human(&self) -> bool { self.human } + fn description(&self) -> &str { + &self.description + } + fn cause(&self) -> Option<&CargoError> { + self.cause.as_ref().map(|c| &**c) + } + fn human(&self) -> bool { + self.human + } } pub struct NotFound; impl CargoError for NotFound { - fn description(&self) -> &str { "not found" } + fn description(&self) -> &str { + "not found" + } fn response(&self) -> Option { let mut response = json_response(&Bad { @@ -186,13 +248,15 @@ impl fmt::Display for NotFound { pub struct Unauthorized; impl CargoError for Unauthorized { - fn description(&self) -> &str { "unauthorized" } + fn description(&self) -> &str { + "unauthorized" + } fn response(&self) -> Option { let mut response = json_response(&Bad { - errors: vec![StringError { - detail: "must be logged in to perform that action".to_string(), - }], + errors: vec![ + StringError { detail: "must be logged in to perform that action".to_string() }, + ], }); response.status = (403, "Forbidden"); Some(response) @@ -232,11 +296,13 @@ pub fn human(error: &S) -> Box { }) } -pub fn std_error(e: Box) -> Box { +pub fn std_error(e: Box) -> Box { #[derive(Debug)] struct E(Box); impl Error for E { - fn description(&self) -> &str { self.0.description() } + fn description(&self) -> &str { + self.0.description() + } } impl fmt::Display for E { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/util/hasher.rs b/src/util/hasher.rs index 468c18c0a1d..a81e19f8044 100644 --- a/src/util/hasher.rs +++ b/src/util/hasher.rs @@ -16,6 +16,11 @@ impl HashingReader { } pub fn finalize(mut self) -> Vec { + /* + rustfmt wanted to merge the lines together so had to use this + to stop this from occurring + */ + #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(deprecated)] self.hasher.finish().unwrap() } diff --git a/src/util/head.rs b/src/util/head.rs index 5f931ab0ee1..36202d76513 100644 --- a/src/util/head.rs +++ b/src/util/head.rs @@ -18,7 +18,7 @@ impl AroundMiddleware for Head { } impl Handler for Head { - fn call(&self, req: &mut Request) -> Result> { + fn call(&self, req: &mut Request) -> Result> { if req.method() == Method::Head { let mut req = RequestProxy { other: req, diff --git a/src/util/io_util.rs b/src/util/io_util.rs index 9ebc2308043..be25ddd14f0 100644 --- a/src/util/io_util.rs +++ b/src/util/io_util.rs @@ -15,10 +15,10 @@ 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,19 +27,16 @@ 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<()> { +pub fn read_fill(r: &mut R, mut slice: &mut [u8]) -> io::Result<()> { while !slice.is_empty() { let n = r.read(slice)?; if n == 0 { - return Err(io::Error::new(io::ErrorKind::Other, - "end of file reached")) + return Err(io::Error::new(io::ErrorKind::Other, "end of file reached")); } slice = &mut mem::replace(&mut slice, &mut [])[n..]; } diff --git a/src/util/lazy_cell.rs b/src/util/lazy_cell.rs index 9ab36f7430f..e530473d597 100644 --- a/src/util/lazy_cell.rs +++ b/src/util/lazy_cell.rs @@ -33,7 +33,9 @@ impl LazyCell { } /// Test whether this cell has been previously filled. - pub fn filled(&self) -> bool { self.inner.borrow().is_some() } + pub fn filled(&self) -> bool { + self.inner.borrow().is_some() + } /// Borrows the contents of this lazy cell for the duration of the cell /// itself. @@ -43,7 +45,7 @@ impl LazyCell { pub fn borrow(&self) -> Option<&T> { match *self.inner.borrow() { Some(ref inner) => unsafe { Some(mem::transmute(inner)) }, - None => None + None => None, } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 866d1256111..02a8d2e4696 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -14,7 +14,7 @@ use self::errors::NotFound; pub use self::errors::{CargoError, CargoResult, internal, human, internal_error}; pub use self::errors::{ChainError, std_error}; -pub use self::hasher::{HashingReader}; +pub use self::hasher::HashingReader; pub use self::head::Head; pub use self::io_util::{LimitErrorReader, read_le_u32, read_fill}; pub use self::lazy_cell::LazyCell; @@ -40,8 +40,10 @@ pub fn json_response(t: &T) -> Response { let s = json::encode(t).unwrap(); let json = fixup(s.parse().unwrap()).to_string(); let mut headers = HashMap::new(); - headers.insert("Content-Type".to_string(), - vec!["application/json; charset=utf-8".to_string()]); + headers.insert( + "Content-Type".to_string(), + vec!["application/json; charset=utf-8".to_string()], + ); headers.insert("Content-Length".to_string(), vec![json.len().to_string()]); return Response { status: (200, "OK"), @@ -52,18 +54,17 @@ pub fn json_response(t: &T) -> Response { fn fixup(json: Json) -> Json { match json { Json::Object(object) => { - Json::Object(object.into_iter().map(|(k, v)| { - let k = if k == "krate" { - "crate".to_string() - } else { - k - }; - (k, fixup(v)) - }).collect()) - } - Json::Array(list) => { - Json::Array(list.into_iter().map(fixup).collect()) + Json::Object( + object + .into_iter() + .map(|(k, v)| { + let k = if k == "krate" { "crate".to_string() } else { k }; + (k, fixup(v)) + }) + .collect(), + ) } + Json::Array(list) => Json::Array(list.into_iter().map(fixup).collect()), j => j, } } @@ -76,8 +77,7 @@ impl<'a> RequestUtils for Request + 'a { } fn query(&self) -> HashMap { - url::form_urlencoded::parse(self.query_string().unwrap_or("") - .as_bytes()) + url::form_urlencoded::parse(self.query_string().unwrap_or("").as_bytes()) .map(|(a, b)| (a.into_owned(), b.into_owned())) .collect() } @@ -93,22 +93,29 @@ impl<'a> RequestUtils for Request + 'a { } fn wants_json(&self) -> bool { - self.headers().find("Accept").map(|accept| { - accept.iter().any(|s| s.contains("json")) - }).unwrap_or(false) + self.headers() + .find("Accept") + .map(|accept| accept.iter().any(|s| s.contains("json"))) + .unwrap_or(false) } fn pagination(&self, default: usize, max: usize) -> CargoResult<(i64, i64)> { let query = self.query(); - let page = query.get("page").and_then(|s| s.parse::().ok()) - .unwrap_or(1); - let limit = query.get("per_page").and_then(|s| s.parse::().ok()) - .unwrap_or(default); + let page = query + .get("page") + .and_then(|s| s.parse::().ok()) + .unwrap_or(1); + let limit = query + .get("per_page") + .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")) + return Err(human("page indexing starts from 1, page 0 is invalid")); } Ok((((page - 1) * limit) as i64, limit as i64)) } @@ -117,7 +124,7 @@ impl<'a> RequestUtils for Request + 'a { pub struct C(pub fn(&mut Request) -> CargoResult); impl Handler for C { - fn call(&self, req: &mut Request) -> Result> { + fn call(&self, req: &mut Request) -> Result> { let C(f) = *self; match f(req) { Ok(resp) => { @@ -127,7 +134,7 @@ impl Handler for C { Err(e) => { match e.response() { Some(response) => Ok(response), - None => Err(std_error(e)) + None => Err(std_error(e)), } } } @@ -137,7 +144,7 @@ impl Handler for C { pub struct R(pub Arc); impl Handler for R { - fn call(&self, req: &mut Request) -> Result> { + 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 { @@ -151,7 +158,7 @@ impl Handler for R { pub struct R404(pub RouteBuilder); impl Handler for R404 { - fn call(&self, req: &mut Request) -> Result> { + fn call(&self, req: &mut Request) -> Result> { let R404(ref router) = *self; match router.recognize(&req.method(), req.path()) { Ok(m) => { diff --git a/src/util/request_proxy.rs b/src/util/request_proxy.rs index e29063abdd0..5409b318b4a 100644 --- a/src/util/request_proxy.rs +++ b/src/util/request_proxy.rs @@ -19,10 +19,16 @@ 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() + } + fn host(&self) -> conduit::Host { + self.other.host() } - fn scheme(&self) -> conduit::Scheme { self.other.scheme() } - fn host(&self) -> conduit::Host { self.other.host() } fn virtual_root(&self) -> Option<&str> { self.other.virtual_root() } @@ -32,14 +38,18 @@ impl<'a> Request for RequestProxy<'a> { fn query_string(&self) -> Option<&str> { self.other.query_string() } - fn remote_addr(&self) -> SocketAddr { self.other.remote_addr() } + fn remote_addr(&self) -> SocketAddr { + self.other.remote_addr() + } fn content_length(&self) -> Option { self.other.content_length() } fn headers(&self) -> &conduit::Headers { self.other.headers() } - fn body(&mut self) -> &mut Read { self.other.body() } + fn body(&mut self) -> &mut Read { + self.other.body() + } fn extensions(&self) -> &conduit::Extensions { self.other.extensions() } diff --git a/src/version.rs b/src/version.rs index 218d9b36b4b..8bdb9acbb27 100644 --- a/src/version.rs +++ b/src/version.rs @@ -38,7 +38,7 @@ pub struct Version { } #[derive(Insertable)] -#[table_name="versions"] +#[table_name = "versions"] pub struct NewVersion { crate_id: i32, num: String, @@ -46,7 +46,7 @@ pub struct NewVersion { } pub struct Author { - pub name: String + pub name: String, } #[derive(RustcEncodable, RustcDecodable)] @@ -71,33 +71,35 @@ pub struct VersionLinks { } impl Version { - pub fn find_by_num(conn: &GenericConnection, - crate_id: i32, - num: &semver::Version) - -> CargoResult> { + pub fn find_by_num(conn: &GenericConnection, crate_id: i32, num: &semver::Version) -> CargoResult> { let num = num.to_string(); - let stmt = conn.prepare("SELECT * FROM versions \ - WHERE crate_id = $1 AND num = $2")?; + let stmt = conn.prepare( + "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))) } - pub fn insert(conn: &GenericConnection, - crate_id: i32, - num: &semver::Version, - features: &HashMap>, - authors: &[String]) - -> CargoResult { + pub fn insert( + conn: &GenericConnection, + crate_id: i32, + num: &semver::Version, + features: &HashMap>, + authors: &[String], + ) -> CargoResult { let num = num.to_string(); let features = json::encode(features).unwrap(); - let stmt = conn.prepare("INSERT INTO versions \ + let stmt = conn.prepare( + "INSERT INTO versions \ (crate_id, num, features) \ VALUES ($1, $2, $3) \ - RETURNING *")?; + 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)?; } @@ -109,8 +111,16 @@ impl Version { } pub fn encodable(self, crate_name: &str) -> EncodableVersion { - let Version { id, num, updated_at, created_at, - downloads, features, yanked, .. } = self; + let Version { + id, + num, + updated_at, + created_at, + downloads, + features, + yanked, + .. + } = self; let num = num.to_string(); EncodableVersion { dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num), @@ -123,18 +133,15 @@ impl Version { features: features, yanked: yanked, links: VersionLinks { - dependencies: format!("/api/v1/crates/{}/{}/dependencies", - crate_name, num), - version_downloads: format!("/api/v1/crates/{}/{}/downloads", - crate_name, num), + dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num), + version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num), authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num), }, } } /// Returns (dependency, crate dependency name) - pub fn dependencies(&self, conn: &PgConnection) - -> QueryResult> { + pub fn dependencies(&self, conn: &PgConnection) -> QueryResult> { Dependency::belonging_to(self) .inner_join(crates::table) .select((dependencies::all_columns, crates::name)) @@ -143,50 +150,54 @@ impl Version { } pub fn authors(&self, conn: &GenericConnection) -> CargoResult> { - let stmt = conn.prepare("SELECT * FROM version_authors + let stmt = conn.prepare( + "SELECT * FROM version_authors WHERE version_id = $1 - ORDER BY name ASC")?; + ORDER BY name ASC", + )?; let rows = stmt.query(&[&self.id])?; - Ok(rows.into_iter().map(|row| { - Author { name: row.get("name") } - }).collect()) + Ok( + rows.into_iter() + .map(|row| Author { name: row.get("name") }) + .collect(), + ) } - pub fn add_author(&self, - conn: &GenericConnection, - name: &str) -> CargoResult<()> { - conn.execute("INSERT INTO version_authors (version_id, name) - VALUES ($1, $2)", &[&self.id, &name])?; + pub fn add_author(&self, conn: &GenericConnection, name: &str) -> CargoResult<()> { + conn.execute( + "INSERT INTO version_authors (version_id, name) + VALUES ($1, $2)", + &[&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])?; + conn.execute( + "UPDATE versions SET yanked = $1 WHERE id = $2", + &[&yanked, &self.id], + )?; Ok(()) } - pub fn max(versions: T) -> semver::Version where - T: IntoIterator, + pub fn max(versions: T) -> semver::Version + where + T: IntoIterator, { - versions.into_iter() - .max() - .unwrap_or_else(|| semver::Version { + versions.into_iter().max().unwrap_or_else(|| { + semver::Version { major: 0, minor: 0, patch: 0, pre: vec![], build: vec![], - }) + } + }) } } impl NewVersion { - pub fn new( - crate_id: i32, - num: &semver::Version, - features: &HashMap>, - ) -> CargoResult { + pub fn new(crate_id: i32, num: &semver::Version, features: &HashMap>) -> CargoResult { let features = json::encode(features)?; Ok(NewVersion { crate_id: crate_id, @@ -200,31 +211,40 @@ 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 \ - uploaded", self.num))); + 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)?; + 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) }) } } #[derive(Insertable)] -#[table_name="version_authors"] +#[table_name = "version_authors"] struct NewAuthor<'a> { version_id: i32, name: &'a str, @@ -234,9 +254,9 @@ impl Queryable for Version { type Row = (i32, i32, String, Timespec, Timespec, i32, Option, bool); 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, @@ -254,9 +274,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"), @@ -268,7 +288,9 @@ impl Model for Version { yanked: row.get("yanked"), } } - fn table_name(_: Option) -> &'static str { "versions" } + fn table_name(_: Option) -> &'static str { + "versions" + } } /// Handles the `GET /versions` route. @@ -277,27 +299,28 @@ pub fn index(req: &mut Request) -> CargoResult { let conn = req.tx()?; // 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[]" { + 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 - } - }).collect::>(); + }) + .collect::>(); // Load all versions // // TODO: can rust-postgres do this for us? let mut versions = Vec::new(); if !ids.is_empty() { - let stmt = conn.prepare("\ + let stmt = conn.prepare( + "\ SELECT versions.*, crates.name AS crate_name FROM versions LEFT JOIN crates ON crates.id = versions.crate_id WHERE versions.id = ANY($1) - ")?; + ", + )?; for row in stmt.query(&[&ids])?.iter() { let v: Version = Model::from_row(&row); let crate_name: String = row.get("crate_name"); @@ -306,7 +329,9 @@ pub fn index(req: &mut Request) -> CargoResult { } #[derive(RustcEncodable)] - struct R { versions: Vec } + struct R { + versions: Vec, + } Ok(req.json(&R { versions: versions })) } @@ -318,7 +343,8 @@ pub fn show(req: &mut Request) -> CargoResult { let id = &req.params()["version_id"]; let id = id.parse().unwrap_or(0); let conn = req.db_conn()?; - versions::table.find(id) + versions::table + .find(id) .inner_join(crates::table) .select((versions::all_columns, ::krate::ALL_COLUMNS)) .first(&*conn)? @@ -326,7 +352,9 @@ pub fn show(req: &mut Request) -> CargoResult { }; #[derive(RustcEncodable)] - struct R { version: EncodableVersion } + struct R { + version: EncodableVersion, + } Ok(req.json(&R { version: version.encodable(&krate.name) })) } @@ -340,8 +368,11 @@ fn version_and_crate_old(req: &mut Request) -> CargoResult<(Version, Crate)> { 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!("crate `{}` does not have a version `{}`", - crate_name, semver)) + human(&format_args!( + "crate `{}` does not have a version `{}`", + crate_name, + semver + )) })?; Ok((version, krate)) } @@ -358,8 +389,11 @@ fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> { .filter(versions::num.eq(semver)) .first(&*conn) .map_err(|_| { - human(&format_args!("crate `{}` does not have a version `{}`", - crate_name, semver)) + human(&format_args!( + "crate `{}` does not have a version `{}`", + crate_name, + semver + )) })?; Ok((version, krate)) } @@ -369,13 +403,15 @@ pub fn dependencies(req: &mut Request) -> CargoResult { let (version, _) = version_and_crate(req)?; let conn = req.db_conn()?; let deps = version.dependencies(&*conn)?; - let deps = deps.into_iter().map(|(dep, crate_name)| { - dep.encodable(&crate_name, None) - }).collect(); + let deps = deps.into_iter() + .map(|(dep, crate_name)| dep.encodable(&crate_name, None)) + .collect(); #[derive(RustcEncodable)] - struct R { dependencies: Vec } - Ok(req.json(&R{ dependencies: deps })) + struct R { + dependencies: Vec, + } + Ok(req.json(&R { dependencies: deps })) } /// Handles the `GET /crates/:crate_id/:version/downloads` route. @@ -383,13 +419,18 @@ pub fn downloads(req: &mut Request) -> CargoResult { use diesel::expression::dsl::date; let (version, _) = version_and_crate(req)?; let conn = req.db_conn()?; - let cutoff_end_date = req.query().get("before_date") + let cutoff_end_date = req.query() + .get("before_date") .and_then(|d| strptime(d, "%Y-%m-%d").ok()) - .unwrap_or_else(now_utc).to_timespec(); + .unwrap_or_else(now_utc) + .to_timespec(); 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() @@ -397,8 +438,10 @@ pub fn downloads(req: &mut Request) -> CargoResult { .collect(); #[derive(RustcEncodable)] - struct R { version_downloads: Vec } - Ok(req.json(&R{ version_downloads: downloads })) + struct R { + version_downloads: Vec, + } + Ok(req.json(&R { version_downloads: downloads })) } /// Handles the `GET /crates/:crate_id/:version/authors` route. @@ -411,10 +454,18 @@ pub fn authors(req: &mut Request) -> CargoResult { // This was never implemented. This complicated return struct // is all that is left, hear for backwards compatibility. #[derive(RustcEncodable)] - struct R { users: Vec<::user::EncodableUser>, meta: Meta } + struct R { + users: Vec<::user::EncodableUser>, + meta: Meta, + } #[derive(RustcEncodable)] - struct Meta { names: Vec } - Ok(req.json(&R{ users: vec![], meta: Meta { names: names } })) + struct Meta { + names: Vec, + } + Ok(req.json(&R { + users: vec![], + meta: Meta { names: names }, + })) } /// Handles the `DELETE /crates/:crate_id/:version/yank` route. @@ -433,12 +484,13 @@ fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult { let conn = req.db_conn()?; let owners = krate.owners(&conn)?; if rights(req.app(), &owners, user)? < Rights::Publish { - return Err(human("must already be an owner to yank or unyank")) + return Err(human("must already be an owner to yank or unyank")); } if version.yanked != yanked { conn.transaction::<_, Box, _>(|| { - diesel::update(&version).set(versions::yanked.eq(yanked)) + diesel::update(&version) + .set(versions::yanked.eq(yanked)) .execute(&*conn)?; git::yank(&**req.app(), &krate.name, &version.num, yanked)?; Ok(()) @@ -446,6 +498,8 @@ fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult { } #[derive(RustcEncodable)] - struct R { ok: bool } - Ok(req.json(&R{ ok: true })) + struct R { + ok: bool, + } + Ok(req.json(&R { ok: true })) }