1use crate::error::{IoError, IoErrorSource, LockfileHandlerError, TResult};
2use camino::{Utf8Path, Utf8PathBuf};
3use std::sync::Mutex;
4
5static RESTORE: Mutex<Option<(Utf8PathBuf, Utf8PathBuf)>> = Mutex::new(None);
6
7pub fn init_lockfile_cleanup_handler() -> Result<(), LockfileHandlerError> {
9 match ctrlc::set_handler(|| {
10 restore();
11 }) {
12 Ok(()) => Ok(()),
13 Err(ctrlc::Error::MultipleHandlers) => Ok(()),
15 Err(_) => Err(LockfileHandlerError),
16 }
17}
18
19fn with_lock<F, R>(f: F) -> R
20where
21 F: FnOnce(&mut Option<(Utf8PathBuf, Utf8PathBuf)>) -> R,
22{
23 let mut guard = RESTORE
24 .lock()
25 .unwrap_or_else(|poisoned| poisoned.into_inner());
26
27 f(&mut guard)
28}
29
30fn restore() {
31 with_lock(|opt| {
32 if let Some((temp, original)) = opt.take() {
33 let _ = std::fs::rename(temp, original);
34 }
35 });
36}
37
38fn register(temp: Utf8PathBuf, original: Utf8PathBuf) {
39 with_lock(|opt| *opt = Some((temp, original)));
40}
41
42fn deregister() {
43 with_lock(|opt| *opt = None);
44}
45
46const CARGO_LOCK_REPLACEMENT: &str = "Cargo.lock-ignored-for-cargo-msrv";
47
48pub struct LockfileHandler {
49 original: Utf8PathBuf,
50 temp: Utf8PathBuf,
51}
52
53impl LockfileHandler {
54 pub fn try_new<P: AsRef<Utf8Path>>(lock_file: P) -> Result<Self, LockfileHandlerError> {
55 let original = lock_file.as_ref().to_path_buf();
56 let temp = original.parent().unwrap().join(CARGO_LOCK_REPLACEMENT);
57
58 init_lockfile_cleanup_handler()?;
59
60 Ok(Self { original, temp })
61 }
62
63 pub fn move_lockfile(self) -> TResult<MovedLockfile> {
64 std::fs::rename(&self.original, &self.temp).map_err(|error| IoError {
65 error,
66 source: IoErrorSource::RenameFile(self.original.clone()),
67 })?;
68
69 register(self.temp.clone(), self.original.clone());
70
71 Ok(MovedLockfile {
72 original: self.original,
73 temp: self.temp,
74 })
75 }
76}
77
78pub struct MovedLockfile {
79 original: Utf8PathBuf,
80 temp: Utf8PathBuf,
81}
82
83impl Drop for MovedLockfile {
84 fn drop(&mut self) {
85 let _ = std::fs::rename(&self.temp, &self.original);
86 deregister();
87 }
88}