mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
use $TMPDIR/uv-locks instead of putting lockfiles directly in $TMPDIR
This commit is contained in:
parent
0019a4acb7
commit
530f4205d3
4 changed files with 77 additions and 8 deletions
|
@ -739,8 +739,8 @@ impl SourceBuild {
|
|||
// lock the output dir, but setuptools always writes to `build/` in the source tree,
|
||||
// regardless of whether its output dir is set to somewhere else.
|
||||
let canonical_source_path = self.source_tree.canonicalize()?;
|
||||
let build_lock_path =
|
||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&canonical_source_path)));
|
||||
let build_lock_path = uv_fs::locks_temp_dir()?
|
||||
.join(format!("uv-{}.lock", cache_digest(&canonical_source_path)));
|
||||
let _lock =
|
||||
LockedFile::acquire(build_lock_path, self.source_tree.to_string_lossy()).await?;
|
||||
|
||||
|
|
|
@ -778,3 +778,69 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Re
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The path to a shared, world-writeable directory for creating locks, to avoid polluting `/tmp`.
|
||||
/// On Linux this is `/tmp/uv_locks`, if `$TMPDIR` is unset.
|
||||
pub fn locks_temp_dir() -> std::io::Result<PathBuf> {
|
||||
let locks_dir_path = std::env::temp_dir().join("uv-locks");
|
||||
if !locks_dir_path.is_dir() {
|
||||
create_world_writeable_dir(&locks_dir_path)?;
|
||||
}
|
||||
Ok(locks_dir_path)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn create_world_writeable_dir(path: &Path) -> std::io::Result<()> {
|
||||
// We need the new directory to have 0o777 permissions on Unix, but if we create it and then
|
||||
// set those permissions, there's a small window in between where other processes could race in
|
||||
// and get IO errors. You'd think we could use `DirBuilderExt::mode` from the standard library
|
||||
// to set the permissions during creation, but the process-wide "umask" interferes with that,
|
||||
// and we can't change our own umask without interfering other threads. Spawn a subprocess that
|
||||
// can set its own umask before creating the dir for us. This is expensive, but we only need to
|
||||
// do it the first time. The `-p` flag makes it not an error for multiple callers to do this
|
||||
// concurrently.
|
||||
let output = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
// The -p flag makes it not an error for multiple callers to do this concurrently. The 1 at
|
||||
// the top of 1777 is the "sticky bit", which prevents different users from deleting each
|
||||
// other's files. It hardly matters for us in practice, but this is exactly the sort of use
|
||||
// case it's intended for, and we might as well set it.
|
||||
.arg(r#"umask 0 && mkdir -p -m 1777 -- "$1""#)
|
||||
.arg("--")
|
||||
.arg(path)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !output.status.success() {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"`mkdir {}` failed: {}",
|
||||
path.to_string_lossy(),
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn create_world_writeable_dir(path: &Path) -> std::io::Result<()> {
|
||||
// Windows doesn't have Unix-style file permission. Just create the dir.
|
||||
fs_err::create_dir_all(path)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_world_writeable_dir() -> io::Result<()> {
|
||||
let parent_dir = tempfile::tempdir()?;
|
||||
let new_dir_path = parent_dir.path().join("foo");
|
||||
create_world_writeable_dir(&new_dir_path)?;
|
||||
assert!(new_dir_path.exists());
|
||||
assert!(new_dir_path.is_dir());
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// On Unix only, explicitly check the permissions mask of the new directory.
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let metadata = fs_err::metadata(&new_dir_path)?;
|
||||
assert_eq!(metadata.permissions().mode() & 0o777, 0o777);
|
||||
}
|
||||
// Create a file in the new directory, for good measure.
|
||||
fs_err::File::create(new_dir_path.join("bar.txt"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::env::consts::ARCH;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, ExitStatus};
|
||||
use std::sync::OnceLock;
|
||||
use std::{env, io};
|
||||
|
||||
use configparser::ini::Ini;
|
||||
use fs_err as fs;
|
||||
|
@ -625,7 +625,8 @@ impl Interpreter {
|
|||
} else {
|
||||
// Otherwise, use a global lockfile.
|
||||
LockedFile::acquire(
|
||||
env::temp_dir().join(format!("uv-{}.lock", cache_digest(&self.sys_executable))),
|
||||
uv_fs::locks_temp_dir()?
|
||||
.join(format!("uv-{}.lock", cache_digest(&self.sys_executable))),
|
||||
self.sys_prefix.user_display(),
|
||||
)
|
||||
.await
|
||||
|
|
|
@ -722,21 +722,23 @@ impl ScriptInterpreter {
|
|||
match script {
|
||||
Pep723ItemRef::Script(script) => {
|
||||
LockedFile::acquire(
|
||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&script.path))),
|
||||
uv_fs::locks_temp_dir()?
|
||||
.join(format!("uv-{}.lock", cache_digest(&script.path))),
|
||||
script.path.simplified_display(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
Pep723ItemRef::Remote(.., url) => {
|
||||
LockedFile::acquire(
|
||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(url))),
|
||||
uv_fs::locks_temp_dir()?.join(format!("uv-{}.lock", cache_digest(url))),
|
||||
url.to_string(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
Pep723ItemRef::Stdin(metadata) => {
|
||||
LockedFile::acquire(
|
||||
std::env::temp_dir().join(format!("uv-{}.lock", cache_digest(&metadata.raw))),
|
||||
uv_fs::locks_temp_dir()?
|
||||
.join(format!("uv-{}.lock", cache_digest(&metadata.raw))),
|
||||
"stdin".to_string(),
|
||||
)
|
||||
.await
|
||||
|
@ -989,7 +991,7 @@ impl ProjectInterpreter {
|
|||
/// Grab a file lock for the environment to prevent concurrent writes across processes.
|
||||
pub(crate) async fn lock(workspace: &Workspace) -> Result<LockedFile, std::io::Error> {
|
||||
LockedFile::acquire(
|
||||
std::env::temp_dir().join(format!(
|
||||
uv_fs::locks_temp_dir()?.join(format!(
|
||||
"uv-{}.lock",
|
||||
cache_digest(workspace.install_path())
|
||||
)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue