Skip to content

Commit cddf5e8

Browse files
committed
Merge rust-bitcoin#62: Restore lock file on failure
9749597 Restore lock file on failure (Nick Johnson) Pull request description: Follow up for the bug found by @apoelstra in rust-bitcoin#60 (comment). I thought the recommended drop guard pattern turned out pretty slick, if a little verbose. ACKs for top commit: tcharding: ACK 9749597 Tree-SHA512: 330b2cdc87030c6ca5f42235df16c94502c3c06d7ab03959f777b25e20095b8e6283099b9d7a8651488eca634527d64e13452b5701b965abf644243e11768884
2 parents 554c939 + 9749597 commit cddf5e8

File tree

1 file changed

+39
-24
lines changed

1 file changed

+39
-24
lines changed

cargo-rbmt/src/lock.rs

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! resolution we need here.
66
77
use std::fs;
8+
use std::path::PathBuf;
89

910
use clap::ValueEnum;
1011
use xshell::Shell;
@@ -18,6 +19,41 @@ const CARGO_LOCK: &str = "Cargo.lock";
1819
/// The temporary backup file for Cargo.lock.
1920
const CARGO_LOCK_BACKUP: &str = "Cargo.lock.backup";
2021

22+
/// RAII guard that backs up and restores the original Cargo.lock file.
23+
struct LockFileGuard {
24+
backup_path: PathBuf,
25+
restore_path: PathBuf,
26+
}
27+
28+
impl LockFileGuard {
29+
fn new(sh: &Shell) -> Result<Self, Box<dyn std::error::Error>> {
30+
let source = sh.current_dir().join(CARGO_LOCK);
31+
let backup = sh.current_dir().join(CARGO_LOCK_BACKUP);
32+
33+
// Backup the existing Cargo.lock file if it exists.
34+
if source.exists() {
35+
fs::copy(&source, &backup)?;
36+
}
37+
38+
Ok(Self { backup_path: backup, restore_path: source })
39+
}
40+
}
41+
42+
impl Drop for LockFileGuard {
43+
fn drop(&mut self) {
44+
// Restore the existing Cargo.lock file from backup (best effort).
45+
if self.backup_path.exists() {
46+
if let Err(e) = fs::copy(&self.backup_path, &self.restore_path) {
47+
eprintln!("Warning: Failed to restore Cargo.lock from backup: {}", e);
48+
return;
49+
}
50+
if let Err(e) = fs::remove_file(&self.backup_path) {
51+
eprintln!("Warning: Failed to remove Cargo.lock backup: {}", e);
52+
}
53+
}
54+
}
55+
}
56+
2157
/// Represents the different types of managed lock files.
2258
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
2359
pub enum LockFile {
@@ -86,13 +122,13 @@ pub fn run(sh: &Shell) -> Result<(), Box<dyn std::error::Error>> {
86122
let repo_dir = sh.current_dir();
87123
quiet_println(&format!("Updating lock files in: {}", repo_dir.display()));
88124

89-
backup_existing(sh)?;
125+
// Create guard to back up and ensure restoration, even on error.
126+
let _guard = LockFileGuard::new(sh)?;
127+
90128
LockFile::Minimal.derive(sh)?;
91129
LockFile::Recent.derive(sh)?;
92-
restore_existing(sh)?;
93130

94131
quiet_println("Lock files updated successfully");
95-
96132
Ok(())
97133
}
98134

@@ -168,24 +204,3 @@ fn copy_lock_file(sh: &Shell, target: LockFile) -> Result<(), Box<dyn std::error
168204
fs::copy(&source, &dest)?;
169205
Ok(())
170206
}
171-
172-
/// Backup the existing Cargo.lock file.
173-
fn backup_existing(sh: &Shell) -> Result<(), Box<dyn std::error::Error>> {
174-
let source = sh.current_dir().join(CARGO_LOCK);
175-
let backup = sh.current_dir().join(CARGO_LOCK_BACKUP);
176-
if source.exists() {
177-
fs::copy(&source, &backup)?;
178-
}
179-
Ok(())
180-
}
181-
182-
/// Restore the existing Cargo.lock file from backup.
183-
fn restore_existing(sh: &Shell) -> Result<(), Box<dyn std::error::Error>> {
184-
let backup = sh.current_dir().join(CARGO_LOCK_BACKUP);
185-
let dest = sh.current_dir().join(CARGO_LOCK);
186-
if backup.exists() {
187-
fs::copy(&backup, &dest)?;
188-
fs::remove_file(&backup)?;
189-
}
190-
Ok(())
191-
}

0 commit comments

Comments
 (0)