mirror of https://github.com/astral-sh/uv
Mark metadata as dynamic when reading from built wheel cache (#11046)
## Summary The issue here boils down to: when we write metadata that came from building the wheel itself, we aren't setting the `dynamic` field. We now _always_ set the dynamic field when reading, even when we read cached data. Closes https://github.com/astral-sh/uv/issues/11047.
This commit is contained in:
parent
7868d5df95
commit
3878c00dbd
|
|
@ -1187,10 +1187,19 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.await?
|
.await?
|
||||||
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
||||||
{
|
{
|
||||||
debug!("Using cached metadata for: {source}");
|
// If necessary, mark the metadata as dynamic.
|
||||||
|
let metadata = if dynamic {
|
||||||
|
ResolutionMetadata {
|
||||||
|
dynamic: true,
|
||||||
|
..metadata.into()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
metadata.into()
|
||||||
|
};
|
||||||
|
|
||||||
return Ok(ArchiveMetadata::from(
|
return Ok(ArchiveMetadata::from(
|
||||||
Metadata::from_workspace(
|
Metadata::from_workspace(
|
||||||
metadata.into(),
|
metadata,
|
||||||
resource.install_path.as_ref(),
|
resource.install_path.as_ref(),
|
||||||
None,
|
None,
|
||||||
self.build_context.locations(),
|
self.build_context.locations(),
|
||||||
|
|
@ -1212,6 +1221,14 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
|
// Store the metadata.
|
||||||
|
fs::create_dir_all(metadata_entry.dir())
|
||||||
|
.await
|
||||||
|
.map_err(Error::CacheWrite)?;
|
||||||
|
write_atomic(metadata_entry.path(), rmp_serde::to_vec(&metadata)?)
|
||||||
|
.await
|
||||||
|
.map_err(Error::CacheWrite)?;
|
||||||
|
|
||||||
// If necessary, mark the metadata as dynamic.
|
// If necessary, mark the metadata as dynamic.
|
||||||
let metadata = if dynamic {
|
let metadata = if dynamic {
|
||||||
ResolutionMetadata {
|
ResolutionMetadata {
|
||||||
|
|
@ -1222,14 +1239,6 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
metadata
|
metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store the metadata.
|
|
||||||
fs::create_dir_all(metadata_entry.dir())
|
|
||||||
.await
|
|
||||||
.map_err(Error::CacheWrite)?;
|
|
||||||
write_atomic(metadata_entry.path(), rmp_serde::to_vec(&metadata)?)
|
|
||||||
.await
|
|
||||||
.map_err(Error::CacheWrite)?;
|
|
||||||
|
|
||||||
return Ok(ArchiveMetadata::from(
|
return Ok(ArchiveMetadata::from(
|
||||||
Metadata::from_workspace(
|
Metadata::from_workspace(
|
||||||
metadata,
|
metadata,
|
||||||
|
|
@ -1273,6 +1282,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the metadata.
|
||||||
|
write_atomic(metadata_entry.path(), rmp_serde::to_vec(&metadata)?)
|
||||||
|
.await
|
||||||
|
.map_err(Error::CacheWrite)?;
|
||||||
|
|
||||||
// If necessary, mark the metadata as dynamic.
|
// If necessary, mark the metadata as dynamic.
|
||||||
let metadata = if dynamic {
|
let metadata = if dynamic {
|
||||||
ResolutionMetadata {
|
ResolutionMetadata {
|
||||||
|
|
@ -1283,11 +1297,6 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
metadata
|
metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store the metadata.
|
|
||||||
write_atomic(metadata_entry.path(), rmp_serde::to_vec(&metadata)?)
|
|
||||||
.await
|
|
||||||
.map_err(Error::CacheWrite)?;
|
|
||||||
|
|
||||||
Ok(ArchiveMetadata::from(
|
Ok(ArchiveMetadata::from(
|
||||||
Metadata::from_workspace(
|
Metadata::from_workspace(
|
||||||
metadata,
|
metadata,
|
||||||
|
|
|
||||||
|
|
@ -20363,6 +20363,125 @@ fn lock_dynamic_version_self_extra_setuptools() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See: <https://github.com/astral-sh/uv/issues/11047>
|
||||||
|
#[test]
|
||||||
|
fn lock_dynamic_built_cache() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "project"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dynamic = ["version"]
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
cache-keys = [{ file = "pyproject.toml" }, { file = "src/__about__.py" }]
|
||||||
|
|
||||||
|
[tool.hatch.version]
|
||||||
|
path = "src/__about__.py"
|
||||||
|
scheme = "standard"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child("src")
|
||||||
|
.child("__about__.py")
|
||||||
|
.write_str("__version__ = '0.1.0'")?;
|
||||||
|
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child("src")
|
||||||
|
.child("project")
|
||||||
|
.child("__init__.py")
|
||||||
|
.touch()?;
|
||||||
|
|
||||||
|
// Lock the project, which should omit the dynamic version.
|
||||||
|
uv_snapshot!(context.filters(), context.lock(), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
"###);
|
||||||
|
|
||||||
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
|
|
||||||
|
insta::with_settings!({
|
||||||
|
filters => context.filters(),
|
||||||
|
}, {
|
||||||
|
assert_snapshot!(
|
||||||
|
lock, @r###"
|
||||||
|
version = 1
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[options]
|
||||||
|
exclude-newer = "2024-03-25T00:00:00Z"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "project"
|
||||||
|
source = { editable = "." }
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Install the project, to force a build.
|
||||||
|
uv_snapshot!(context.filters(), context.sync(), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
Prepared 1 package in [TIME]
|
||||||
|
Installed 1 package in [TIME]
|
||||||
|
+ project==0.1.0 (from file://[TEMP_DIR]/)
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Remove the lockfile.
|
||||||
|
fs_err::remove_file(context.temp_dir.join("uv.lock"))?;
|
||||||
|
|
||||||
|
// Lock the project, which should omit the dynamic version.
|
||||||
|
uv_snapshot!(context.filters(), context.lock(), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
"###);
|
||||||
|
|
||||||
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
|
|
||||||
|
insta::with_settings!({
|
||||||
|
filters => context.filters(),
|
||||||
|
}, {
|
||||||
|
assert_snapshot!(
|
||||||
|
lock, @r###"
|
||||||
|
version = 1
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[options]
|
||||||
|
exclude-newer = "2024-03-25T00:00:00Z"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "project"
|
||||||
|
source = { editable = "." }
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Re-lock after converting a package from dynamic to static.
|
/// Re-lock after converting a package from dynamic to static.
|
||||||
#[test]
|
#[test]
|
||||||
fn lock_dynamic_to_static() -> Result<()> {
|
fn lock_dynamic_to_static() -> Result<()> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue