Skip to content

Commit

Permalink
fix: per-toolchain installation lock (#144)
Browse files Browse the repository at this point in the history
```
$ elan install nightly
info: waiting for previous installation request to finish (/home/sebastian/.elan/toolchains/leanprover--lean4-nightly---nightly-2024-11-23.lock, held by PID 2508083
)

leanprover/lean4-nightly:nightly-2024-11-23 installed
```
  • Loading branch information
Kha authored Nov 25, 2024
1 parent 1c9262c commit d7920ac
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 8 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/elan-dist/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ json = "0.12.4"
zip = "0.6"
filetime = "0.2.14"
time = "0.3"
fslock = "0.2.1"

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

[lib]
name = "elan_dist"

1 change: 1 addition & 0 deletions src/elan-dist/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![recursion_limit = "1024"]

extern crate fslock;
extern crate elan_utils;
extern crate flate2;
extern crate itertools;
Expand Down
29 changes: 22 additions & 7 deletions src/elan-dist/src/manifestation.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! Manifest a particular Lean version by installing it from a distribution server.
use std::{thread::sleep, time::Duration};

use component::{TarGzPackage, TarZstdPackage, ZipPackage};
use download::DownloadCfg;
use elan_utils::utils;
use elan_utils::{raw::read_file, utils};
use errors::*;
use fslock::LockFile;
use notifications::*;
use prefix::InstallPrefix;
use temp;
Expand All @@ -25,11 +28,28 @@ impl Manifestation {
temp_cfg: &temp::Cfg,
notify_handler: &dyn Fn(Notification),
) -> Result<()> {
let prefix = self.prefix.path();
utils::ensure_dir_exists("toolchains", prefix.parent().unwrap(), &|n| {
(notify_handler)(n.into())
})?;

let lockfile_path = prefix.with_extension("lock");
let mut lockfile = LockFile::open(&lockfile_path)?;
if !lockfile.try_lock_with_pid()? {
notify_handler(Notification::WaitingForFileLock(&lockfile_path, read_file(&lockfile_path)?.trim()));
while !lockfile.try_lock_with_pid()? {
sleep(Duration::from_secs(1));
}
}
let dlcfg = DownloadCfg {
temp_cfg: temp_cfg,
notify_handler: notify_handler,
};

if utils::is_directory(prefix) {
return Ok(())
}

// find correct download on HTML page (AAAAH)
use regex::Regex;
use std::fs;
Expand Down Expand Up @@ -70,17 +90,11 @@ impl Manifestation {

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

let prefix = self.prefix.path();

notify_handler(Notification::InstallingComponent(&prefix.to_string_lossy()));

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

if utils::is_directory(prefix) {
return Err(format!("'{}' is already installed", prefix.display()).into());
}

if utils::is_directory(&unpack_dir) {
utils::remove_dir("temp toolchain directory", &unpack_dir, &|n| {
(notify_handler)(n.into())
Expand All @@ -103,6 +117,7 @@ impl Manifestation {
}

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

Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions src/elan-dist/src/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub enum Notification<'a> {
DownloadingLegacyManifest,
ManifestChecksumFailedHack,
NewVersionAvailable(String),
WaitingForFileLock(&'a Path, &'a str),
}

impl<'a> From<elan_utils::Notification<'a>> for Notification<'a> {
Expand Down Expand Up @@ -65,6 +66,7 @@ impl<'a> Notification<'a> {
| RollingBack
| DownloadingManifest(_)
| NewVersionAvailable(_)
| WaitingForFileLock(_, _)
| DownloadedManifest(_, _) => NotificationLevel::Info,
CantReadUpdateHash(_)
| ExtensionNotInstalled(_)
Expand Down Expand Up @@ -125,6 +127,9 @@ impl<'a> Display for Notification<'a> {
"Version {version} of elan is available! Use `elan self update` to update."
)
}
WaitingForFileLock(path, pid) => {
write!(f, "waiting for previous installation request to finish ({}, held by PID {})", path.display(), pid)
}
}
}
}

0 comments on commit d7920ac

Please sign in to comment.