Skip to content

Commit 6023257

Browse files
committed
fix: per-toolchain installation lock
1 parent 1c9262c commit 6023257

File tree

5 files changed

+40
-8
lines changed

5 files changed

+40
-8
lines changed

Cargo.lock

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

src/elan-dist/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ json = "0.12.4"
2626
zip = "0.6"
2727
filetime = "0.2.14"
2828
time = "0.3"
29+
fslock = "0.2.1"
2930

3031
[target."cfg(windows)".dependencies]
3132
winapi = { version = "0.3.9", features = ["handleapi", "sysinfoapi", "tlhelp32", "winnt"] }
@@ -36,4 +37,3 @@ libc = "0.2.88"
3637

3738
[lib]
3839
name = "elan_dist"
39-

src/elan-dist/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![recursion_limit = "1024"]
22

3+
extern crate fslock;
34
extern crate elan_utils;
45
extern crate flate2;
56
extern crate itertools;

src/elan-dist/src/manifestation.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//! Manifest a particular Lean version by installing it from a distribution server.
22
3+
use std::{thread::sleep, time::Duration};
4+
35
use component::{TarGzPackage, TarZstdPackage, ZipPackage};
46
use download::DownloadCfg;
5-
use elan_utils::utils;
7+
use elan_utils::{raw::read_file, utils};
68
use errors::*;
9+
use fslock::LockFile;
710
use notifications::*;
811
use prefix::InstallPrefix;
912
use temp;
@@ -25,11 +28,28 @@ impl Manifestation {
2528
temp_cfg: &temp::Cfg,
2629
notify_handler: &dyn Fn(Notification),
2730
) -> Result<()> {
31+
let prefix = self.prefix.path();
32+
utils::ensure_dir_exists("toolchsin", &prefix, &|n| {
33+
(notify_handler)(n.into())
34+
})?;
35+
36+
let lockfile_path = prefix.with_extension("lock");
37+
let mut lockfile = LockFile::open(&lockfile_path)?;
38+
if !lockfile.try_lock_with_pid()? {
39+
notify_handler(Notification::WaitingForFileLock(&lockfile_path, read_file(&lockfile_path)?.trim()));
40+
while !lockfile.try_lock_with_pid()? {
41+
sleep(Duration::from_secs(1));
42+
}
43+
}
2844
let dlcfg = DownloadCfg {
2945
temp_cfg: temp_cfg,
3046
notify_handler: notify_handler,
3147
};
3248

49+
if utils::is_directory(prefix) {
50+
return Ok(())
51+
}
52+
3353
// find correct download on HTML page (AAAAH)
3454
use regex::Regex;
3555
use std::fs;
@@ -70,17 +90,11 @@ impl Manifestation {
7090

7191
let installer_file = dlcfg.download_and_check(&url)?;
7292

73-
let prefix = self.prefix.path();
74-
7593
notify_handler(Notification::InstallingComponent(&prefix.to_string_lossy()));
7694

7795
// unpack into temporary place, then move atomically to guard against aborts during unpacking
7896
let unpack_dir = prefix.with_extension("tmp");
7997

80-
if utils::is_directory(prefix) {
81-
return Err(format!("'{}' is already installed", prefix.display()).into());
82-
}
83-
8498
if utils::is_directory(&unpack_dir) {
8599
utils::remove_dir("temp toolchain directory", &unpack_dir, &|n| {
86100
(notify_handler)(n.into())
@@ -103,6 +117,7 @@ impl Manifestation {
103117
}
104118

105119
utils::rename_dir("temp toolchain directory", &unpack_dir, prefix)?;
120+
let _ = std::fs::remove_file(&lockfile_path);
106121

107122
Ok(())
108123
}

src/elan-dist/src/notifications.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub enum Notification<'a> {
3131
DownloadingLegacyManifest,
3232
ManifestChecksumFailedHack,
3333
NewVersionAvailable(String),
34+
WaitingForFileLock(&'a Path, &'a str),
3435
}
3536

3637
impl<'a> From<elan_utils::Notification<'a>> for Notification<'a> {
@@ -65,6 +66,7 @@ impl<'a> Notification<'a> {
6566
| RollingBack
6667
| DownloadingManifest(_)
6768
| NewVersionAvailable(_)
69+
| WaitingForFileLock(_, _)
6870
| DownloadedManifest(_, _) => NotificationLevel::Info,
6971
CantReadUpdateHash(_)
7072
| ExtensionNotInstalled(_)
@@ -125,6 +127,9 @@ impl<'a> Display for Notification<'a> {
125127
"Version {version} of elan is available! Use `elan self update` to update."
126128
)
127129
}
130+
WaitingForFileLock(path, pid) => {
131+
write!(f, "waiting for previous installation request to finish ({}, held by PID {})", path.display(), pid)
132+
}
128133
}
129134
}
130135
}

0 commit comments

Comments
 (0)