Skip to content

Commit ee1685e

Browse files
committed
Check if a crate is already yanked/unyanked in the job
Right now we check if a crate is already yanked/unyanked before enqueing the job at all. This means that if you try to undo a yank before the yank finishes running, we won't enqueue the unyank at all. This isn't an expected scenario, and we still might not do the unyank if the jobs are run out of order, but this means that we should always end up in the expected state under normal operation.
1 parent 8f9dccb commit ee1685e

File tree

2 files changed

+49
-36
lines changed

2 files changed

+49
-36
lines changed

src/controllers/version/yank.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ fn modify_yank(req: &mut dyn Request, yanked: bool) -> CargoResult<Response> {
3636
return Err(human("must already be an owner to yank or unyank"));
3737
}
3838

39-
if version.yanked != yanked {
40-
git::yank(&conn, krate.name, version, yanked)?;
41-
}
39+
git::yank(&conn, krate.name, version, yanked)?;
4240

4341
#[derive(Serialize)]
4442
struct R {

src/git.rs

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -168,39 +168,54 @@ impl Job for Yank {
168168
let repo = Repository::open(&env.index_location)?;
169169
let dst = repo.index_file(&self.krate);
170170

171-
let prev = fs::read_to_string(&dst)?;
172-
let version = self.version.num.to_string();
173-
let new = prev
174-
.lines()
175-
.map(|line| {
176-
let mut git_crate = serde_json::from_str::<Crate>(line)
177-
.map_err(|_| internal(&format_args!("couldn't decode: `{}`", line)))?;
178-
if git_crate.name != self.krate || git_crate.vers != version {
179-
return Ok(line.to_string());
180-
}
181-
git_crate.yanked = Some(self.yanked);
182-
Ok(serde_json::to_string(&git_crate)?)
183-
})
184-
.collect::<CargoResult<Vec<String>>>();
185-
let new = new?.join("\n") + "\n";
186-
fs::write(&dst, new.as_bytes())?;
187-
188-
repo.commit_and_push(
189-
&format!(
190-
"{} crate `{}#{}`",
191-
if self.yanked { "Yanking" } else { "Unyanking" },
192-
self.krate,
193-
self.version.num
194-
),
195-
&repo.relative_index_file(&self.krate),
196-
env.credentials(),
197-
)?;
198-
199-
diesel::update(&self.version)
200-
.set(versions::yanked.eq(self.yanked))
201-
.execute(&*env.connection()?)?;
202-
203-
Ok(())
171+
let conn = env.connection()?;
172+
173+
conn.transaction(|| {
174+
let yanked_in_db = versions::table
175+
.find(self.version.id)
176+
.select(versions::yanked)
177+
.for_update()
178+
.first::<bool>(&*conn)?;
179+
180+
if yanked_in_db == self.yanked {
181+
// The crate is alread in the state requested, nothing to do
182+
return Ok(());
183+
}
184+
185+
let prev = fs::read_to_string(&dst)?;
186+
let version = self.version.num.to_string();
187+
let new = prev
188+
.lines()
189+
.map(|line| {
190+
let mut git_crate = serde_json::from_str::<Crate>(line)
191+
.map_err(|_| internal(&format_args!("couldn't decode: `{}`", line)))?;
192+
if git_crate.name != self.krate || git_crate.vers != version {
193+
return Ok(line.to_string());
194+
}
195+
git_crate.yanked = Some(self.yanked);
196+
Ok(serde_json::to_string(&git_crate)?)
197+
})
198+
.collect::<CargoResult<Vec<String>>>();
199+
let new = new?.join("\n") + "\n";
200+
fs::write(&dst, new.as_bytes())?;
201+
202+
repo.commit_and_push(
203+
&format!(
204+
"{} crate `{}#{}`",
205+
if self.yanked { "Yanking" } else { "Unyanking" },
206+
self.krate,
207+
self.version.num
208+
),
209+
&repo.relative_index_file(&self.krate),
210+
env.credentials(),
211+
)?;
212+
213+
diesel::update(&self.version)
214+
.set(versions::yanked.eq(self.yanked))
215+
.execute(&*conn)?;
216+
217+
Ok(())
218+
})
204219
}
205220
}
206221

0 commit comments

Comments
 (0)