mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Make project and interpreter lock acquisition non-fatal (#14404)
## Summary If we fail to acquire a lock on an environment, uv shouldn't fail; we should just warn. In some cases, users run uv with read-only permissions for their projects, etc. For now, I kept any locks acquired _in the cache_ as hard failures, since we always need write-access to the cache. Closes https://github.com/astral-sh/uv/issues/14411.
This commit is contained in:
parent
2f53ea5c5c
commit
743260b1f5
10 changed files with 143 additions and 21 deletions
|
@ -25,7 +25,7 @@ use tempfile::TempDir;
|
|||
use tokio::io::AsyncBufReadExt;
|
||||
use tokio::process::Command;
|
||||
use tokio::sync::{Mutex, Semaphore};
|
||||
use tracing::{Instrument, debug, info_span, instrument};
|
||||
use tracing::{Instrument, debug, info_span, instrument, warn};
|
||||
|
||||
use uv_cache_key::cache_digest;
|
||||
use uv_configuration::PreviewMode;
|
||||
|
@ -456,8 +456,12 @@ impl SourceBuild {
|
|||
"uv-setuptools-{}.lock",
|
||||
cache_digest(&canonical_source_path)
|
||||
));
|
||||
source_tree_lock =
|
||||
Some(LockedFile::acquire(lock_path, self.source_tree.to_string_lossy()).await?);
|
||||
source_tree_lock = LockedFile::acquire(lock_path, self.source_tree.to_string_lossy())
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire build lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Ok(source_tree_lock)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::path::PathBuf;
|
|||
use anyhow::Context;
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::{Level, debug, enabled};
|
||||
use tracing::{Level, debug, enabled, warn};
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
|
@ -236,7 +236,13 @@ pub(crate) async fn pip_install(
|
|||
}
|
||||
}
|
||||
|
||||
let _lock = environment.lock().await?;
|
||||
let _lock = environment
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Determine the markers to use for the resolution.
|
||||
let interpreter = environment.interpreter();
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::Write;
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
|
@ -211,7 +211,13 @@ pub(crate) async fn pip_sync(
|
|||
}
|
||||
}
|
||||
|
||||
let _lock = environment.lock().await?;
|
||||
let _lock = environment
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
let interpreter = environment.interpreter();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::Write;
|
|||
use anyhow::Result;
|
||||
use itertools::{Either, Itertools};
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
|
@ -100,7 +100,13 @@ pub(crate) async fn pip_uninstall(
|
|||
}
|
||||
}
|
||||
|
||||
let _lock = environment.lock().await?;
|
||||
let _lock = environment
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Index the current `site-packages` directory.
|
||||
let site_packages = uv_installer::SitePackages::from_environment(&environment)?;
|
||||
|
|
|
@ -10,7 +10,7 @@ use anyhow::{Context, Result, bail};
|
|||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
use tracing::debug;
|
||||
use tracing::{debug, warn};
|
||||
use url::Url;
|
||||
|
||||
use uv_cache::Cache;
|
||||
|
@ -319,7 +319,13 @@ pub(crate) async fn add(
|
|||
}
|
||||
};
|
||||
|
||||
let _lock = target.acquire_lock().await?;
|
||||
let _lock = target
|
||||
.acquire_lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.connectivity(network_settings.connectivity)
|
||||
|
|
|
@ -1244,7 +1244,12 @@ impl ProjectEnvironment {
|
|||
preview: PreviewMode,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// Lock the project environment to avoid synchronization issues.
|
||||
let _lock = ProjectInterpreter::lock(workspace).await?;
|
||||
let _lock = ProjectInterpreter::lock(workspace)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire project environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
let upgradeable = preview.is_enabled()
|
||||
&& python
|
||||
|
@ -1462,7 +1467,13 @@ impl ScriptEnvironment {
|
|||
preview: PreviewMode,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// Lock the script environment to avoid synchronization issues.
|
||||
let _lock = ScriptInterpreter::lock(script).await?;
|
||||
let _lock = ScriptInterpreter::lock(script)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire script environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
let upgradeable = python_request
|
||||
.as_ref()
|
||||
.is_none_or(|request| !request.includes_patch());
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::str::FromStr;
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::{
|
||||
|
@ -281,7 +281,13 @@ pub(crate) async fn remove(
|
|||
}
|
||||
};
|
||||
|
||||
let _lock = target.acquire_lock().await?;
|
||||
let _lock = target
|
||||
.acquire_lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Determine the lock mode.
|
||||
let mode = if locked {
|
||||
|
|
|
@ -240,7 +240,13 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
.await?
|
||||
.into_environment()?;
|
||||
|
||||
let _lock = environment.lock().await?;
|
||||
let _lock = environment
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Determine the lock mode.
|
||||
let mode = if frozen {
|
||||
|
@ -386,7 +392,13 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
)
|
||||
});
|
||||
|
||||
let _lock = environment.lock().await?;
|
||||
let _lock = environment
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
match update_environment(
|
||||
environment,
|
||||
|
@ -699,7 +711,13 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
.map(|lock| (lock, project.workspace().install_path().to_owned()));
|
||||
}
|
||||
} else {
|
||||
let _lock = venv.lock().await?;
|
||||
let _lock = venv
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Determine the lock mode.
|
||||
let mode = if frozen {
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::sync::Arc;
|
|||
use anyhow::{Context, Result};
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::warn;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
|
@ -169,7 +170,13 @@ pub(crate) async fn sync(
|
|||
),
|
||||
};
|
||||
|
||||
let _lock = environment.lock().await?;
|
||||
let _lock = environment
|
||||
.lock()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
warn!("Failed to acquire environment lock: {err}");
|
||||
})
|
||||
.ok();
|
||||
|
||||
// Notify the user of any environment changes.
|
||||
match &environment {
|
||||
|
|
|
@ -3,13 +3,14 @@ use assert_cmd::prelude::*;
|
|||
use assert_fs::{fixture::ChildPath, prelude::*};
|
||||
use indoc::{formatdoc, indoc};
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::common::{TestContext, download_to_disk, packse_index_url, uv_snapshot, venv_bin_path};
|
||||
use predicates::prelude::predicate;
|
||||
use tempfile::tempdir_in;
|
||||
|
||||
use uv_fs::Simplified;
|
||||
use uv_static::EnvVars;
|
||||
|
||||
use crate::common::{TestContext, download_to_disk, packse_index_url, uv_snapshot, venv_bin_path};
|
||||
|
||||
#[test]
|
||||
fn sync() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
@ -9989,3 +9990,54 @@ fn sync_url_with_query_parameters() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn read_only() -> Result<()> {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ iniconfig==2.0.0
|
||||
"###);
|
||||
|
||||
assert!(context.temp_dir.child("uv.lock").exists());
|
||||
|
||||
// Remove the flock.
|
||||
fs_err::remove_file(context.venv.child(".lock"))?;
|
||||
|
||||
// Make the virtual environment read and execute (but not write).
|
||||
fs_err::set_permissions(&context.venv, std::fs::Permissions::from_mode(0o555))?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Audited 1 package in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue