Skip to content

Commit 663488f

Browse files
committed
Implement yanking
1 parent 73c2e12 commit 663488f

File tree

13 files changed

+367
-201
lines changed

13 files changed

+367
-201
lines changed

Cargo.lock

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bin/migrate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ fn migrations() -> Vec<Migration> {
325325
Migration::add_column(20141007171517, "crates", "documentation",
326326
"VARCHAR"),
327327
Migration::add_column(20141010150327, "crates", "readme", "VARCHAR"),
328+
Migration::add_column(20141013115510, "versions", "yanked",
329+
"BOOLEAN DEFAULT FALSE"),
328330
];
329331
// NOTE: Generate a new id via `date +"%Y%m%d%H%M%S"`
330332

src/db.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub struct Transaction {
3737
// right order.
3838
tx: LazyCell<pg::PostgresTransaction<'static>>,
3939
slot: LazyCell<PooledConnnection<'static>>,
40-
rollback: Cell<bool>,
40+
commit: Cell<bool>,
4141

4242
// Keep a handle to the app which keeps a handle to the database to ensure
4343
// that this `'static` is indeed at least a little more accurate (in that
@@ -51,7 +51,7 @@ impl Transaction {
5151
app: app,
5252
slot: LazyCell::new(),
5353
tx: LazyCell::new(),
54-
rollback: Cell::new(false),
54+
commit: Cell::new(false),
5555
}
5656
}
5757

@@ -99,8 +99,8 @@ impl Transaction {
9999
Ok(tx as &Connection)
100100
}
101101

102-
pub fn rollback(&self) { self.rollback.set(true); }
103-
pub fn commit(&self) { self.rollback.set(false); }
102+
pub fn rollback(&self) { self.commit.set(false); }
103+
pub fn commit(&self) { self.commit.set(true); }
104104
}
105105

106106
impl Middleware for TransactionMiddleware {
@@ -118,7 +118,7 @@ impl Middleware for TransactionMiddleware {
118118
let tx = req.extensions().find::<Transaction>()
119119
.expect("Transaction not present in request");
120120
match tx.tx.borrow() {
121-
Some(transaction) if !tx.rollback.get() => {
121+
Some(transaction) if tx.commit.get() => {
122122
transaction.set_commit();
123123
}
124124
_ => {}
@@ -140,9 +140,9 @@ pub trait RequestTransaction<'a> {
140140
/// only be set to commit() if a successful response code of 200 is seen.
141141
fn tx(self) -> CargoResult<&'a Connection + 'a>;
142142

143-
/// Do not commit this request's transaction, even if it finishes ok.
143+
/// Flag the transaction to not be committed
144144
fn rollback(self);
145-
/// Flag this transaction to be committed (this is the default)
145+
/// Flag this transaction to be committed
146146
fn commit(self);
147147
}
148148

src/git.rs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::io::{Command, BufferedReader, Process, IoResult, File, fs};
66
use std::io;
77
use std::os;
88

9+
use semver;
910
use flate2::reader::GzDecoder;
1011
use git2;
1112
use serialize::json;
@@ -15,13 +16,14 @@ use conduit::{Request, Response};
1516
use app::{App, RequestApp};
1617
use util::{CargoResult, internal};
1718

18-
#[deriving(Encodable)]
19+
#[deriving(Encodable, Decodable)]
1920
pub struct GitCrate {
2021
pub name: String,
2122
pub vers: String,
2223
pub deps: Vec<String>,
2324
pub cksum: String,
2425
pub features: HashMap<String, Vec<String>>,
26+
pub yanked: Option<bool>,
2527
}
2628

2729
pub fn serve_index(req: &mut Request) -> CargoResult<Response> {
@@ -101,25 +103,24 @@ pub fn serve_index(req: &mut Request) -> CargoResult<Response> {
101103
}
102104
}
103105

106+
fn index_file(base: &Path, name: &str) -> Path {
107+
match name.len() {
108+
1 => base.join("1").join(name),
109+
2 => base.join("2").join(name),
110+
3 => base.join("3").join(name.slice_to(1)).join(name),
111+
_ => base.join(name.slice(0, 2))
112+
.join(name.slice(2, 4))
113+
.join(name),
114+
}
115+
}
116+
104117
pub fn add_crate(app: &App, krate: &GitCrate) -> CargoResult<()> {
105118
let repo = app.git_repo.lock();
106119
let repo = &*repo;
107-
let name = krate.name.as_slice();
108120
let repo_path = repo.path().dir_path();
109-
let dst = match name.len() {
110-
1 => repo_path.join("1").join(name),
111-
2 => repo_path.join("2").join(name),
112-
3 => repo_path.join("3").join(name.slice_to(1)).join(name),
113-
_ => repo_path.join(name.slice(0, 2))
114-
.join(name.slice(2, 4))
115-
.join(name),
116-
};
121+
let dst = index_file(&repo_path, krate.name.as_slice());
117122

118-
// Attempt to commit the crate in a loop. It's possible that we're going
119-
// to need to rebase our repository, and after that it's possible that we're
120-
// going to race to commit the changes. For now we just cap out the maximum
121-
// number of retries at a fixed number.
122-
for _ in range(0i, 20) {
123+
commit_and_push(repo, || {
123124
// Add the crate to its relevant file
124125
try!(fs::mkdir_recursive(&dst.dir_path(), io::USER_RWX));
125126
let prev = if dst.exists() {
@@ -131,6 +132,53 @@ pub fn add_crate(app: &App, krate: &GitCrate) -> CargoResult<()> {
131132
let new = if prev.len() == 0 {s} else {prev + "\n" + s};
132133
try!(File::create(&dst).write(new.as_bytes()));
133134

135+
Ok((format!("Updating crate `{}#{}`", krate.name, krate.vers),
136+
dst.clone()))
137+
})
138+
}
139+
140+
pub fn yank(app: &App, krate: &str, version: &semver::Version,
141+
yanked: bool) -> CargoResult<()> {
142+
let repo = app.git_repo.lock();
143+
let repo = &*repo;
144+
let repo_path = repo.path().dir_path();
145+
let dst = index_file(&repo_path, krate);
146+
147+
commit_and_push(repo, || {
148+
let prev = try!(File::open(&dst).read_to_string());
149+
let new = prev.as_slice().lines().map(|line| {
150+
let mut git_crate = try!(json::decode::<GitCrate>(line).map_err(|_| {
151+
internal(format!("couldn't decode: `{}`", line))
152+
}));
153+
if git_crate.name.as_slice() != krate ||
154+
git_crate.vers.to_string() != version.to_string() {
155+
return Ok(line.to_string())
156+
}
157+
git_crate.yanked = Some(yanked);
158+
Ok(json::encode(&git_crate))
159+
}).collect::<CargoResult<Vec<String>>>();
160+
let new = try!(new).as_slice().connect("\n");
161+
try!(File::create(&dst).write(new.as_bytes()));
162+
163+
Ok((format!("{} crate `{}#{}`",
164+
if yanked {"Yanking"} else {"Unyanking"},
165+
krate, version),
166+
dst.clone()))
167+
})
168+
}
169+
170+
fn commit_and_push(repo: &git2::Repository,
171+
f: || -> CargoResult<(String, Path)>)
172+
-> CargoResult<()> {
173+
let repo_path = repo.path().dir_path();
174+
175+
// Attempt to commit in a loop. It's possible that we're going to need to
176+
// rebase our repository, and after that it's possible that we're going to
177+
// race to commit the changes. For now we just cap out the maximum number of
178+
// retries at a fixed number.
179+
for _ in range(0i, 20) {
180+
let (msg, dst) = try!(f());
181+
134182
// git add $file
135183
let mut index = try!(repo.index());
136184
try!(index.add_path(&dst.path_relative_from(&repo_path).unwrap()));
@@ -142,7 +190,6 @@ pub fn add_crate(app: &App, krate: &GitCrate) -> CargoResult<()> {
142190
let head = try!(repo.head());
143191
let parent = try!(repo.find_commit(head.target().unwrap()));
144192
let sig = try!(repo.signature());
145-
let msg = format!("Updating crate `{}#{}`", krate.name, krate.vers);
146193
try!(repo.commit(Some("HEAD"), &sig, &sig, msg.as_slice(),
147194
&tree, &[&parent]));
148195

0 commit comments

Comments
 (0)