mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-17 02:52:45 +00:00
Ensure mtime of site packages is updated during wheel installation (#2545)
Closes https://github.com/astral-sh/uv/issues/2530
This commit is contained in:
parent
136e744a9f
commit
baa30697a4
2 changed files with 72 additions and 2 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use fs_err::{DirEntry, File};
|
use fs_err::{DirEntry, File};
|
||||||
|
|
@ -263,6 +264,31 @@ fn clone_wheel_files(
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The directory mtime is not updated when cloning and the mtime is used by CPython's
|
||||||
|
// import mechanisms to determine if it should look for new packages in a directory.
|
||||||
|
// Here, we force the mtime to be updated to ensure that packages are importable without
|
||||||
|
// manual cache invalidation.
|
||||||
|
//
|
||||||
|
// <https://github.com/python/cpython/blob/8336cb2b6f428246803b02a4e97fce49d0bb1e09/Lib/importlib/_bootstrap_external.py#L1601>
|
||||||
|
let now = SystemTime::now();
|
||||||
|
|
||||||
|
// `File.set_modified` is not available in `fs_err` yet
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
match std::fs::File::open(site_packages.as_ref()) {
|
||||||
|
Ok(dir) => {
|
||||||
|
if let Err(err) = dir.set_modified(now) {
|
||||||
|
debug!(
|
||||||
|
"Failed to update mtime for {}: {err}",
|
||||||
|
site_packages.as_ref().display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => debug!(
|
||||||
|
"Failed to open {} to update mtime: {err}",
|
||||||
|
site_packages.as_ref().display()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
#![cfg(all(feature = "python", feature = "pypi"))]
|
#![cfg(all(feature = "python", feature = "pypi"))]
|
||||||
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use assert_cmd::prelude::*;
|
use assert_cmd::prelude::*;
|
||||||
use assert_fs::prelude::*;
|
use assert_fs::prelude::*;
|
||||||
use base64::{prelude::BASE64_STANDARD as base64, Engine};
|
use base64::{prelude::BASE64_STANDARD as base64, Engine};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use std::process::Command;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use common::{uv_snapshot, TestContext, EXCLUDE_NEWER, INSTA_FILTERS};
|
use common::{uv_snapshot, TestContext, EXCLUDE_NEWER, INSTA_FILTERS};
|
||||||
|
|
@ -2843,3 +2842,48 @@ fn install_index_with_relative_links_authenticated() {
|
||||||
|
|
||||||
context.assert_command("import anyio").success();
|
context.assert_command("import anyio").success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The modified time of `site-packages` should change on package installation.
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn install_site_packages_mtime_updated() -> Result<()> {
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let site_packages = context.site_packages();
|
||||||
|
|
||||||
|
// `mtime` is only second-resolution so we include the nanoseconds as well
|
||||||
|
let metadata = site_packages.metadata()?;
|
||||||
|
let pre_mtime = metadata.mtime();
|
||||||
|
let pre_mtime_ns = metadata.mtime_nsec();
|
||||||
|
|
||||||
|
// Install a package.
|
||||||
|
uv_snapshot!(command(&context)
|
||||||
|
.arg("anyio")
|
||||||
|
.arg("--strict"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 3 packages in [TIME]
|
||||||
|
Downloaded 3 packages in [TIME]
|
||||||
|
Installed 3 packages in [TIME]
|
||||||
|
+ anyio==4.0.0
|
||||||
|
+ idna==3.4
|
||||||
|
+ sniffio==1.3.0
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
let metadata = site_packages.metadata()?;
|
||||||
|
let post_mtime = metadata.mtime();
|
||||||
|
let post_mtime_ns = metadata.mtime_nsec();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
(post_mtime, post_mtime_ns) > (pre_mtime, pre_mtime_ns),
|
||||||
|
"Expected newer mtime than {pre_mtime}.{pre_mtime_ns} but got {post_mtime}.{post_mtime_ns}"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue