Skip to content

Commit

Permalink
Respect reinstalls in cached environments (#5499)
Browse files Browse the repository at this point in the history
## Summary

Closes #5493.
  • Loading branch information
charliermarsh authored Jul 27, 2024
1 parent 8f16f1b commit 3ea5e16
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 15 deletions.
45 changes: 30 additions & 15 deletions crates/uv/src/commands/project/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ impl CachedEnvironment {
// Hash the resolution by hashing the generated lockfile.
// TODO(charlie): If the resolution contains any mutable metadata (like a path or URL
// dependency), skip this step.
let distributions = resolution.distributions().collect::<Vec<_>>();
let resolution_hash = hash_digest(&distributions);
let resolution_hash = {
let distributions = resolution.distributions().collect::<Vec<_>>();
hash_digest(&distributions)
};

// Hash the interpreter based on its path.
// TODO(charlie): Come up with a robust hash for the interpreter.
Expand All @@ -84,24 +86,39 @@ impl CachedEnvironment {
// Search in the content-addressed cache.
let cache_entry = cache.entry(CacheBucket::Environments, interpreter_hash, resolution_hash);

// Lock the interpreter, to avoid concurrent modification across processes.
// Lock at the interpreter level, to avoid concurrent modification across processes.
fs_err::tokio::create_dir_all(cache_entry.dir()).await?;
let _lock = LockedFile::acquire(
cache_entry.dir().join(".lock"),
cache_entry.dir().user_display(),
)?;

// If the receipt exists, return the environment.
let ok = cache_entry.path().join(".ok");
if ok.is_file() {
debug!(
"Found existing cached environment at: `{}`",
cache_entry.path().display()
);
return Ok(Self(PythonEnvironment::from_root(
cache_entry.path(),
cache,
)?));

if settings.reinstall.is_none() {
// If the receipt exists, return the environment.
if ok.is_file() {
debug!(
"Reusing cached environment at: `{}`",
cache_entry.path().display()
);
return Ok(Self(PythonEnvironment::from_root(
cache_entry.path(),
cache,
)?));
}
} else {
// If the receipt exists, remove it.
match fs_err::tokio::remove_file(&ok).await {
Ok(()) => {
debug!(
"Removed receipt for environment at: `{}`",
cache_entry.path().display()
);
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {}
Err(err) => return Err(err.into()),
}
}

debug!(
Expand All @@ -117,8 +134,6 @@ impl CachedEnvironment {
false,
)?;

// TODO(charlie): Rather than passing all the arguments to `sync_environment`, return a
// struct that lets us "continue" from `resolve_environment`.
let venv = sync_environment(
venv,
&resolution,
Expand Down
57 changes: 57 additions & 0 deletions crates/uv/tests/tool_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,63 @@ fn tool_run_cache() {
Resolved [N] packages in [TIME]
"###);

// Verify that `--reinstall` reinstalls everything.
uv_snapshot!(context.filters(), context.tool_run()
.arg("-p")
.arg("3.12")
.arg("--reinstall")
.arg("black")
.arg("--version")
.env("UV_TOOL_DIR", tool_dir.as_os_str())
.env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###"
success: true
exit_code: 0
----- stdout -----
black, 24.3.0 (compiled: yes)
Python (CPython) 3.12.[X]
----- stderr -----
warning: `uv tool run` is experimental and may change without warning
Resolved [N] packages in [TIME]
Prepared [N] packages in [TIME]
Installed [N] packages in [TIME]
+ black==24.3.0
+ click==8.1.7
+ mypy-extensions==1.0.0
+ packaging==24.0
+ pathspec==0.12.1
+ platformdirs==4.2.0
"###);

// Verify that `--reinstall-package` reinstalls everything. We may want to change this.
uv_snapshot!(context.filters(), context.tool_run()
.arg("-p")
.arg("3.12")
.arg("--reinstall-package")
.arg("packaging")
.arg("black")
.arg("--version")
.env("UV_TOOL_DIR", tool_dir.as_os_str())
.env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###"
success: true
exit_code: 0
----- stdout -----
black, 24.3.0 (compiled: yes)
Python (CPython) 3.12.[X]
----- stderr -----
warning: `uv tool run` is experimental and may change without warning
Resolved [N] packages in [TIME]
Prepared [N] packages in [TIME]
Installed [N] packages in [TIME]
+ black==24.3.0
+ click==8.1.7
+ mypy-extensions==1.0.0
+ packaging==24.0
+ pathspec==0.12.1
+ platformdirs==4.2.0
"###);

// Verify that varying the interpreter leads to a fresh environment.
uv_snapshot!(context.filters(), context.tool_run()
.arg("-p")
Expand Down

0 comments on commit 3ea5e16

Please sign in to comment.