Skip to content

Update max_version on yank #582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
2 changes: 1 addition & 1 deletion app/routes/crate/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default Ember.Route.extend({
return crate.get('versions')
.then(versions => {
const version = versions.find(version => version.get('num') === params.version_num);
if (!version) {
if (params.version_num && !version) {
this.controllerFor('application').set('nextFlashError',
`Version '${params.version_num}' of crate '${crate.get('name')}' does not exist`);
}
Expand Down
105 changes: 105 additions & 0 deletions src/bin/update-max-versions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Update the max_version for all crates.
//
// Usage:
// cargo run --bin update-max-versions

#![deny(warnings)]

extern crate cargo_registry;
extern crate postgres;
extern crate semver;

fn main() {
let conn = cargo_registry::db::connect_now();
{
let tx = conn.transaction().unwrap();
update(&tx);
tx.set_commit();
tx.finish().unwrap();
}
}

fn update(tx: &postgres::transaction::Transaction) {
let crate_ids = tx.query("SELECT id FROM crates", &[]).unwrap();
for crate_id in crate_ids.iter() {
let crate_id: i32 = crate_id.get("id");
let new_max = tx.query("SELECT num FROM versions WHERE crate_id = $1 AND yanked = FALSE",
&[&crate_id]).unwrap()
.iter()
.map(|r| r.get::<&str, String>("num"))
.filter_map(|v| semver::Version::parse(&v).ok())
.max();
tx.execute("UPDATE crates SET max_version = $1 WHERE id = $2",
&[&new_max.map(|v| v.to_string()), &crate_id]).unwrap();
}
}

#[cfg(test)]
mod test {
use std::collections::HashMap;

use postgres;
use semver;

use cargo_registry::{Version, Crate, User, Model, env};

fn conn() -> postgres::Connection {
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", "api_token").unwrap()
}

#[test]
fn max_to_null() {
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 v1 = semver::Version::parse("1.0.0").unwrap();
let version = Version::insert(&tx, krate.id, &v1, &HashMap::new(), &[]).unwrap();
version.yank(&conn, true).unwrap();
::update(&tx);
assert_eq!(Crate::find(&tx, krate.id).unwrap().max_version, None);
}

#[test]
fn max_to_same() {
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 v1 = semver::Version::parse("1.0.0").unwrap();
Version::insert(&tx, krate.id, &v1, &HashMap::new(), &[]).unwrap();
::update(&tx);
assert_eq!(Crate::find(&tx, krate.id).unwrap().max_version, Some(v1));
}

#[test]
fn multiple_crates() {
let conn = conn();
let tx = conn.transaction().unwrap();
let user = user(&tx);
let krate1 = Crate::find_or_insert(&tx, "foo1", user.id, &None, &None,
&None, &None, &None, &None,
&None, None).unwrap();
let krate2 = Crate::find_or_insert(&tx, "foo2", user.id, &None, &None,
&None, &None, &None, &None,
&None, None).unwrap();
let v1 = semver::Version::parse("1.0.0").unwrap();
let krate1_ver = Version::insert(&tx, krate1.id, &v1, &HashMap::new(),
&[]).unwrap();
Version::insert(&tx, krate2.id, &v1, &HashMap::new(), &[]).unwrap();
krate1_ver.yank(&conn, true).unwrap();
::update(&tx);
assert_eq!(Crate::find(&tx, krate1.id).unwrap().max_version, None);
assert_eq!(Crate::find(&tx, krate2.id).unwrap().max_version, Some(v1));
}
}
22 changes: 14 additions & 8 deletions src/krate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub struct Crate {
pub updated_at: Timespec,
pub created_at: Timespec,
pub downloads: i32,
pub max_version: semver::Version,
pub max_version: Option<semver::Version>,
pub description: Option<String>,
pub homepage: Option<String>,
pub documentation: Option<String>,
Expand All @@ -65,7 +65,7 @@ pub struct EncodableCrate {
pub badges: Option<Vec<EncodableBadge>>,
pub created_at: String,
pub downloads: i32,
pub max_version: String,
pub max_version: Option<String>,
pub description: Option<String>,
pub homepage: Option<String>,
pub documentation: Option<String>,
Expand Down Expand Up @@ -266,7 +266,7 @@ impl Crate {
keywords: keyword_ids,
categories: category_ids,
badges: badges,
max_version: max_version.to_string(),
max_version: max_version.map(|v| v.to_string()),
documentation: documentation,
homepage: homepage,
description: description,
Expand Down Expand Up @@ -384,12 +384,18 @@ impl Crate {
None => {}
}
let zero = semver::Version::parse("0.0.0").unwrap();
if *ver > self.max_version || self.max_version == zero {
self.max_version = ver.clone();
let new_max = match self.max_version {
None => true,
Some(ref max_version) if *ver > *max_version || *max_version == zero => true,
_ => false,
};
if new_max {
self.max_version = Some(ver.clone());
}
let stmt = conn.prepare("UPDATE crates SET max_version = $1
WHERE id = $2 RETURNING updated_at")?;
let rows = stmt.query(&[&self.max_version.to_string(), &self.id])?;
let max_version = self.max_version.clone().map(|v| v.to_string());
let rows = stmt.query(&[&max_version, &self.id])?;
self.updated_at = rows.get(0).get("updated_at");
Version::insert(conn, self.id, ver, features, authors)
}
Expand Down Expand Up @@ -460,7 +466,7 @@ impl Crate {

impl Model for Crate {
fn from_row(row: &Row) -> Crate {
let max: String = row.get("max_version");
let max: Option<String> = row.get("max_version");
Crate {
id: row.get("id"),
name: row.get("name"),
Expand All @@ -471,7 +477,7 @@ impl Model for Crate {
documentation: row.get("documentation"),
homepage: row.get("homepage"),
readme: row.get("readme"),
max_version: semver::Version::parse(&max).unwrap(),
max_version: max.map(|m| semver::Version::parse(&m).unwrap()),
license: row.get("license"),
repository: row.get("repository"),
max_upload_size: row.get("max_upload_size"),
Expand Down
2 changes: 1 addition & 1 deletion src/tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ fn krate(name: &str) -> Crate {
updated_at: time::now().to_timespec(),
created_at: time::now().to_timespec(),
downloads: 10,
max_version: semver::Version::parse("0.0.0").unwrap(),
max_version: Some(semver::Version::parse("0.0.0").unwrap()),
documentation: None,
homepage: None,
description: None,
Expand Down
41 changes: 41 additions & 0 deletions src/tests/http-data/krate_publish_after_yank_max_version
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
===REQUEST 339
PUT http://alexcrichton-test.s3.amazonaws.com/crates/fyk_max/fyk_max-1.0.0.crate HTTP/1.1
Accept: */*
Proxy-Connection: Keep-Alive
Authorization: AWS AKIAJF3GEK7N44BACDZA:GDxGb6r3SIqo9wXuzHrgMNWekwk=
Content-Length: 0
Host: alexcrichton-test.s3.amazonaws.com
Content-Type: application/x-tar
Date: Sun, 28 Jun 2015 14:07:17 -0700


===RESPONSE 258
HTTP/1.1 200
x-amz-request-id: CB0E925D8E3AB3E8
x-amz-id-2: SiaMwszM1p2TzXlLauvZ6kRKcUCg7HoyBW29vts42w9ArrLwkJWl8vuvPuGFkpM6XGH+YXN852g=
date: Sun, 28 Jun 2015 21:07:51 GMT
etag: "d41d8cd98f00b204e9800998ecf8427e"
content-length: 0
server: AmazonS3


===REQUEST 339
PUT http://alexcrichton-test.s3.amazonaws.com/crates/fyk_max/fyk_max-2.0.0.crate HTTP/1.1
Accept: */*
Proxy-Connection: Keep-Alive
Authorization: AWS AKIAJF3GEK7N44BACDZA:GDxGb6r3SIqo9wXuzHrgMNWekwk=
Content-Length: 0
Host: alexcrichton-test.s3.amazonaws.com
Content-Type: application/x-tar
Date: Sun, 28 Jun 2015 14:07:17 -0700


===RESPONSE 258
HTTP/1.1 200
x-amz-request-id: CB0E925D8E3AB3E8
x-amz-id-2: SiaMwszM1p2TzXlLauvZ6kRKcUCg7HoyBW29vts42w9ArrLwkJWl8vuvPuGFkpM6XGH+YXN852g=
date: Sun, 28 Jun 2015 21:07:51 GMT
etag: "d41d8cd98f00b204e9800998ecf8427e"
content-length: 0
server: AmazonS3

41 changes: 41 additions & 0 deletions src/tests/http-data/krate_yank_max_version
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
===REQUEST 339
PUT http://alexcrichton-test.s3.amazonaws.com/crates/fyk_max/fyk_max-1.0.0.crate HTTP/1.1
Accept: */*
Proxy-Connection: Keep-Alive
Authorization: AWS AKIAJF3GEK7N44BACDZA:GDxGb6r3SIqo9wXuzHrgMNWekwk=
Content-Length: 0
Host: alexcrichton-test.s3.amazonaws.com
Content-Type: application/x-tar
Date: Sun, 28 Jun 2015 14:07:17 -0700


===RESPONSE 258
HTTP/1.1 200
x-amz-request-id: CB0E925D8E3AB3E8
x-amz-id-2: SiaMwszM1p2TzXlLauvZ6kRKcUCg7HoyBW29vts42w9ArrLwkJWl8vuvPuGFkpM6XGH+YXN852g=
date: Sun, 28 Jun 2015 21:07:51 GMT
etag: "d41d8cd98f00b204e9800998ecf8427e"
content-length: 0
server: AmazonS3


===REQUEST 339
PUT http://alexcrichton-test.s3.amazonaws.com/crates/fyk_max/fyk_max-2.0.0.crate HTTP/1.1
Accept: */*
Proxy-Connection: Keep-Alive
Authorization: AWS AKIAJF3GEK7N44BACDZA:GDxGb6r3SIqo9wXuzHrgMNWekwk=
Content-Length: 0
Host: alexcrichton-test.s3.amazonaws.com
Content-Type: application/x-tar
Date: Sun, 28 Jun 2015 14:07:17 -0700


===RESPONSE 258
HTTP/1.1 200
x-amz-request-id: CB0E925D8E3AB3E8
x-amz-id-2: SiaMwszM1p2TzXlLauvZ6kRKcUCg7HoyBW29vts42w9ArrLwkJWl8vuvPuGFkpM6XGH+YXN852g=
date: Sun, 28 Jun 2015 21:07:51 GMT
etag: "d41d8cd98f00b204e9800998ecf8427e"
content-length: 0
server: AmazonS3

Loading