Skip to main content

cargo_msrv/
lockfile.rs

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
7/// Must be called once to set up the lockfile restoration handler
8pub fn init_lockfile_cleanup_handler() -> Result<(), LockfileHandlerError> {
9    match ctrlc::set_handler(|| {
10        restore();
11    }) {
12        Ok(()) => Ok(()),
13        // only init once, if there are multiple processes playing with the lockfile we could have a problem
14        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}