mirror of https://github.com/astral-sh/uv
Add `METADATA.json` and `WHEEL.json` to build backend
Add an experimental JSON format for METADATA and WHEEL files in the uv build backend to have a reference what it would look like and to demonstrate that the actual change is just a few lines, how much easier it is than the existing email-ish format.
This commit is contained in:
parent
d649f9ca0f
commit
4c2fc5490d
|
|
@ -5186,6 +5186,8 @@ version = "0.8.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"uv-build-backend",
|
"uv-build-backend",
|
||||||
|
"uv-preview",
|
||||||
|
"uv-static",
|
||||||
"uv-version",
|
"uv-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -5205,6 +5207,7 @@ dependencies = [
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"spdx",
|
"spdx",
|
||||||
"tar",
|
"tar",
|
||||||
|
|
@ -5221,6 +5224,7 @@ dependencies = [
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
"uv-pep508",
|
"uv-pep508",
|
||||||
"uv-platform-tags",
|
"uv-platform-tags",
|
||||||
|
"uv-preview",
|
||||||
"uv-pypi-types",
|
"uv-pypi-types",
|
||||||
"uv-version",
|
"uv-version",
|
||||||
"uv-warnings",
|
"uv-warnings",
|
||||||
|
|
@ -6346,6 +6350,7 @@ dependencies = [
|
||||||
name = "uv-static"
|
name = "uv-static"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"thiserror 2.0.12",
|
||||||
"uv-macros",
|
"uv-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ uv-options-metadata = { workspace = true }
|
||||||
uv-pep440 = { workspace = true }
|
uv-pep440 = { workspace = true }
|
||||||
uv-pep508 = { workspace = true }
|
uv-pep508 = { workspace = true }
|
||||||
uv-platform-tags = { workspace = true }
|
uv-platform-tags = { workspace = true }
|
||||||
|
uv-preview = { workspace = true }
|
||||||
uv-pypi-types = { workspace = true }
|
uv-pypi-types = { workspace = true }
|
||||||
uv-version = { workspace = true }
|
uv-version = { workspace = true }
|
||||||
uv-warnings = { workspace = true }
|
uv-warnings = { workspace = true }
|
||||||
|
|
@ -35,6 +36,7 @@ itertools = { workspace = true }
|
||||||
rustc-hash = { workspace = true }
|
rustc-hash = { workspace = true }
|
||||||
schemars = { workspace = true, optional = true }
|
schemars = { workspace = true, optional = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
spdx = { workspace = true }
|
spdx = { workspace = true }
|
||||||
tar = { workspace = true }
|
tar = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ pub enum Error {
|
||||||
Zip(#[from] zip::result::ZipError),
|
Zip(#[from] zip::result::ZipError),
|
||||||
#[error("Failed to write RECORD file")]
|
#[error("Failed to write RECORD file")]
|
||||||
Csv(#[from] csv::Error),
|
Csv(#[from] csv::Error),
|
||||||
|
#[error("Failed to write JSON metadata file")]
|
||||||
|
Json(#[source] serde_json::Error),
|
||||||
#[error("Expected a Python module at: `{}`", _0.user_display())]
|
#[error("Expected a Python module at: `{}`", _0.user_display())]
|
||||||
MissingInitPy(PathBuf),
|
MissingInitPy(PathBuf),
|
||||||
#[error("For namespace packages, `__init__.py[i]` is not allowed in parent directory: `{}`", _0.user_display())]
|
#[error("For namespace packages, `__init__.py[i]` is not allowed in parent directory: `{}`", _0.user_display())]
|
||||||
|
|
@ -362,6 +364,7 @@ mod tests {
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use uv_distribution_filename::{SourceDistFilename, WheelFilename};
|
use uv_distribution_filename::{SourceDistFilename, WheelFilename};
|
||||||
use uv_fs::{copy_dir_all, relative_to};
|
use uv_fs::{copy_dir_all, relative_to};
|
||||||
|
use uv_preview::{Preview, PreviewFeatures};
|
||||||
|
|
||||||
const MOCK_UV_VERSION: &str = "1.0.0+test";
|
const MOCK_UV_VERSION: &str = "1.0.0+test";
|
||||||
|
|
||||||
|
|
@ -388,11 +391,11 @@ mod tests {
|
||||||
|
|
||||||
/// Run both a direct wheel build and an indirect wheel build through a source distribution,
|
/// Run both a direct wheel build and an indirect wheel build through a source distribution,
|
||||||
/// while checking that directly built wheel and indirectly built wheel are the same.
|
/// while checking that directly built wheel and indirectly built wheel are the same.
|
||||||
fn build(source_root: &Path, dist: &Path) -> Result<BuildResults, Error> {
|
fn build(source_root: &Path, dist: &Path, preview: Preview) -> Result<BuildResults, Error> {
|
||||||
// Build a direct wheel, capture all its properties to compare it with the indirect wheel
|
// Build a direct wheel, capture all its properties to compare it with the indirect wheel
|
||||||
// latest and remove it since it has the same filename as the indirect wheel.
|
// latest and remove it since it has the same filename as the indirect wheel.
|
||||||
let (_name, direct_wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION)?;
|
let (_name, direct_wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION, preview)?;
|
||||||
let direct_wheel_filename = build_wheel(source_root, dist, None, MOCK_UV_VERSION)?;
|
let direct_wheel_filename = build_wheel(source_root, dist, None, MOCK_UV_VERSION, preview)?;
|
||||||
let direct_wheel_path = dist.join(direct_wheel_filename.to_string());
|
let direct_wheel_path = dist.join(direct_wheel_filename.to_string());
|
||||||
let direct_wheel_contents = wheel_contents(&direct_wheel_path);
|
let direct_wheel_contents = wheel_contents(&direct_wheel_path);
|
||||||
let direct_wheel_hash = sha2::Sha256::digest(fs_err::read(&direct_wheel_path)?);
|
let direct_wheel_hash = sha2::Sha256::digest(fs_err::read(&direct_wheel_path)?);
|
||||||
|
|
@ -402,7 +405,7 @@ mod tests {
|
||||||
let (_name, source_dist_list_files) = list_source_dist(source_root, MOCK_UV_VERSION)?;
|
let (_name, source_dist_list_files) = list_source_dist(source_root, MOCK_UV_VERSION)?;
|
||||||
// TODO(konsti): This should run in the unpacked source dist tempdir, but we need to
|
// TODO(konsti): This should run in the unpacked source dist tempdir, but we need to
|
||||||
// normalize the path.
|
// normalize the path.
|
||||||
let (_name, wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION)?;
|
let (_name, wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION, preview)?;
|
||||||
let source_dist_filename = build_source_dist(source_root, dist, MOCK_UV_VERSION)?;
|
let source_dist_filename = build_source_dist(source_root, dist, MOCK_UV_VERSION)?;
|
||||||
let source_dist_path = dist.join(source_dist_filename.to_string());
|
let source_dist_path = dist.join(source_dist_filename.to_string());
|
||||||
let source_dist_contents = sdist_contents(&source_dist_path);
|
let source_dist_contents = sdist_contents(&source_dist_path);
|
||||||
|
|
@ -417,7 +420,13 @@ mod tests {
|
||||||
source_dist_filename.name.as_dist_info_name(),
|
source_dist_filename.name.as_dist_info_name(),
|
||||||
source_dist_filename.version
|
source_dist_filename.version
|
||||||
));
|
));
|
||||||
let wheel_filename = build_wheel(&sdist_top_level_directory, dist, None, MOCK_UV_VERSION)?;
|
let wheel_filename = build_wheel(
|
||||||
|
&sdist_top_level_directory,
|
||||||
|
dist,
|
||||||
|
None,
|
||||||
|
MOCK_UV_VERSION,
|
||||||
|
preview,
|
||||||
|
)?;
|
||||||
let wheel_contents = wheel_contents(&dist.join(wheel_filename.to_string()));
|
let wheel_contents = wheel_contents(&dist.join(wheel_filename.to_string()));
|
||||||
|
|
||||||
// Check that direct and indirect wheels are identical.
|
// Check that direct and indirect wheels are identical.
|
||||||
|
|
@ -441,7 +450,7 @@ mod tests {
|
||||||
|
|
||||||
fn build_err(source_root: &Path) -> String {
|
fn build_err(source_root: &Path) -> String {
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build_err = build(source_root, dist.path()).unwrap_err();
|
let build_err = build(source_root, dist.path(), Preview::default()).unwrap_err();
|
||||||
let err_message: String = format_err(&build_err)
|
let err_message: String = format_err(&build_err)
|
||||||
.replace(&source_root.user_display().to_string(), "[TEMP_PATH]")
|
.replace(&source_root.user_display().to_string(), "[TEMP_PATH]")
|
||||||
.replace('\\', "/");
|
.replace('\\', "/");
|
||||||
|
|
@ -558,7 +567,7 @@ mod tests {
|
||||||
|
|
||||||
// Perform both the direct and the indirect build.
|
// Perform both the direct and the indirect build.
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build = build(src.path(), dist.path()).unwrap();
|
let build = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
|
|
||||||
let source_dist_path = dist.path().join(build.source_dist_filename.to_string());
|
let source_dist_path = dist.path().join(build.source_dist_filename.to_string());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -622,7 +631,7 @@ mod tests {
|
||||||
// Check that the wheel is reproducible across platforms.
|
// Check that the wheel is reproducible across platforms.
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
format!("{:x}", sha2::Sha256::digest(fs_err::read(&wheel_path).unwrap())),
|
format!("{:x}", sha2::Sha256::digest(fs_err::read(&wheel_path).unwrap())),
|
||||||
@"319afb04e87caf894b1362b508ec745253c6d241423ea59021694d2015e821da"
|
@"dbe56fd8bd52184095b2e0ea3e83c95d1bc8b4aa53cf469cec5af62251b24abb"
|
||||||
);
|
);
|
||||||
assert_snapshot!(build.wheel_contents.join("\n"), @r"
|
assert_snapshot!(build.wheel_contents.join("\n"), @r"
|
||||||
built_by_uv-0.1.0.data/data/
|
built_by_uv-0.1.0.data/data/
|
||||||
|
|
@ -673,7 +682,7 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read_to_string(&mut record)
|
.read_to_string(&mut record)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_snapshot!(record, @r###"
|
assert_snapshot!(record, @r"
|
||||||
built_by_uv/__init__.py,sha256=AJ7XpTNWxYktP97ydb81UpnNqoebH7K4sHRakAMQKG4,44
|
built_by_uv/__init__.py,sha256=AJ7XpTNWxYktP97ydb81UpnNqoebH7K4sHRakAMQKG4,44
|
||||||
built_by_uv/arithmetic/__init__.py,sha256=x2agwFbJAafc9Z6TdJ0K6b6bLMApQdvRSQjP4iy7IEI,67
|
built_by_uv/arithmetic/__init__.py,sha256=x2agwFbJAafc9Z6TdJ0K6b6bLMApQdvRSQjP4iy7IEI,67
|
||||||
built_by_uv/arithmetic/circle.py,sha256=FYZkv6KwrF9nJcwGOKigjke1dm1Fkie7qW1lWJoh3AE,287
|
built_by_uv/arithmetic/circle.py,sha256=FYZkv6KwrF9nJcwGOKigjke1dm1Fkie7qW1lWJoh3AE,287
|
||||||
|
|
@ -685,11 +694,11 @@ mod tests {
|
||||||
built_by_uv-0.1.0.data/headers/built_by_uv.h,sha256=p5-HBunJ1dY-xd4dMn03PnRClmGyRosScIp8rT46kg4,144
|
built_by_uv-0.1.0.data/headers/built_by_uv.h,sha256=p5-HBunJ1dY-xd4dMn03PnRClmGyRosScIp8rT46kg4,144
|
||||||
built_by_uv-0.1.0.data/scripts/whoami.sh,sha256=T2cmhuDFuX-dTkiSkuAmNyIzvv8AKopjnuTCcr9o-eE,20
|
built_by_uv-0.1.0.data/scripts/whoami.sh,sha256=T2cmhuDFuX-dTkiSkuAmNyIzvv8AKopjnuTCcr9o-eE,20
|
||||||
built_by_uv-0.1.0.data/data/data.csv,sha256=7z7u-wXu7Qr2eBZFVpBILlNUiGSngv_1vYqZHVWOU94,265
|
built_by_uv-0.1.0.data/data/data.csv,sha256=7z7u-wXu7Qr2eBZFVpBILlNUiGSngv_1vYqZHVWOU94,265
|
||||||
built_by_uv-0.1.0.dist-info/WHEEL,sha256=PaG_oOj9G2zCRqoLK0SjWBVZbGAMtIXDmm-MEGw9Wo0,83
|
built_by_uv-0.1.0.dist-info/WHEEL,sha256=JBpLtoa_WBz5WPGpRsAUTD4Dz6H0KkkdiKWCkfMSS1U,84
|
||||||
built_by_uv-0.1.0.dist-info/entry_points.txt,sha256=-IO6yaq6x6HSl-zWH96rZmgYvfyHlH00L5WQoCpz-YI,50
|
built_by_uv-0.1.0.dist-info/entry_points.txt,sha256=-IO6yaq6x6HSl-zWH96rZmgYvfyHlH00L5WQoCpz-YI,50
|
||||||
built_by_uv-0.1.0.dist-info/METADATA,sha256=m6EkVvKrGmqx43b_VR45LHD37IZxPYC0NI6Qx9_UXLE,474
|
built_by_uv-0.1.0.dist-info/METADATA,sha256=m6EkVvKrGmqx43b_VR45LHD37IZxPYC0NI6Qx9_UXLE,474
|
||||||
built_by_uv-0.1.0.dist-info/RECORD,,
|
built_by_uv-0.1.0.dist-info/RECORD,,
|
||||||
"###);
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that `license = { file = "LICENSE" }` is supported.
|
/// Test that `license = { file = "LICENSE" }` is supported.
|
||||||
|
|
@ -738,6 +747,7 @@ mod tests {
|
||||||
output_dir.path(),
|
output_dir.path(),
|
||||||
None,
|
None,
|
||||||
"0.5.15",
|
"0.5.15",
|
||||||
|
Preview::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let wheel = output_dir
|
let wheel = output_dir
|
||||||
|
|
@ -790,7 +800,13 @@ mod tests {
|
||||||
|
|
||||||
// Prepare the metadata.
|
// Prepare the metadata.
|
||||||
let metadata_dir = TempDir::new().unwrap();
|
let metadata_dir = TempDir::new().unwrap();
|
||||||
let dist_info_dir = metadata(src.path(), metadata_dir.path(), "0.5.15").unwrap();
|
let dist_info_dir = metadata(
|
||||||
|
src.path(),
|
||||||
|
metadata_dir.path(),
|
||||||
|
"0.5.15",
|
||||||
|
Preview::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let metadata_prepared =
|
let metadata_prepared =
|
||||||
fs_err::read_to_string(metadata_dir.path().join(&dist_info_dir).join("METADATA"))
|
fs_err::read_to_string(metadata_dir.path().join(&dist_info_dir).join("METADATA"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -802,6 +818,7 @@ mod tests {
|
||||||
output_dir.path(),
|
output_dir.path(),
|
||||||
Some(&metadata_dir.path().join(&dist_info_dir)),
|
Some(&metadata_dir.path().join(&dist_info_dir)),
|
||||||
"0.5.15",
|
"0.5.15",
|
||||||
|
Preview::default(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let wheel = output_dir
|
let wheel = output_dir
|
||||||
|
|
@ -851,7 +868,7 @@ mod tests {
|
||||||
File::create(src.path().join("two_step_build").join("__init__.py")).unwrap();
|
File::create(src.path().join("two_step_build").join("__init__.py")).unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build1 = build(src.path(), dist.path()).unwrap();
|
let build1 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
|
|
||||||
assert_snapshot!(build1.source_dist_contents.join("\n"), @r"
|
assert_snapshot!(build1.source_dist_contents.join("\n"), @r"
|
||||||
two_step_build-1.0.0/
|
two_step_build-1.0.0/
|
||||||
|
|
@ -890,7 +907,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build2 = build(src.path(), dist.path()).unwrap();
|
let build2 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_eq!(build1, build2);
|
assert_eq!(build1, build2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -917,7 +934,7 @@ mod tests {
|
||||||
File::create(src.path().join("src").join("camelCase").join("__init__.py")).unwrap();
|
File::create(src.path().join("src").join("camelCase").join("__init__.py")).unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build1 = build(src.path(), dist.path()).unwrap();
|
let build1 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
|
|
||||||
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
|
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
|
||||||
camelCase/
|
camelCase/
|
||||||
|
|
@ -934,7 +951,7 @@ mod tests {
|
||||||
pyproject_toml.replace("camelCase", "camel_case"),
|
pyproject_toml.replace("camelCase", "camel_case"),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let build_err = build(src.path(), dist.path()).unwrap_err();
|
let build_err = build(src.path(), dist.path(), Preview::default()).unwrap_err();
|
||||||
let err_message = format_err(&build_err)
|
let err_message = format_err(&build_err)
|
||||||
.replace(&src.path().user_display().to_string(), "[TEMP_PATH]")
|
.replace(&src.path().user_display().to_string(), "[TEMP_PATH]")
|
||||||
.replace('\\', "/");
|
.replace('\\', "/");
|
||||||
|
|
@ -963,7 +980,7 @@ mod tests {
|
||||||
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build_err = build(src.path(), dist.path()).unwrap_err();
|
let build_err = build(src.path(), dist.path(), Preview::default()).unwrap_err();
|
||||||
let err_message = format_err(&build_err);
|
let err_message = format_err(&build_err);
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
err_message,
|
err_message,
|
||||||
|
|
@ -999,7 +1016,7 @@ mod tests {
|
||||||
File::create(®ular_init_py).unwrap();
|
File::create(®ular_init_py).unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build_err = build(src.path(), dist.path()).unwrap_err();
|
let build_err = build(src.path(), dist.path(), Preview::default()).unwrap_err();
|
||||||
let err_message = format_err(&build_err)
|
let err_message = format_err(&build_err)
|
||||||
.replace(&src.path().user_display().to_string(), "[TEMP_PATH]")
|
.replace(&src.path().user_display().to_string(), "[TEMP_PATH]")
|
||||||
.replace('\\', "/");
|
.replace('\\', "/");
|
||||||
|
|
@ -1018,7 +1035,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let build1 = build(src.path(), dist.path()).unwrap();
|
let build1 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
|
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
|
||||||
stuffed_bird-stubs/
|
stuffed_bird-stubs/
|
||||||
stuffed_bird-stubs/__init__.pyi
|
stuffed_bird-stubs/__init__.pyi
|
||||||
|
|
@ -1044,7 +1061,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
||||||
|
|
||||||
let build2 = build(src.path(), dist.path()).unwrap();
|
let build2 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_eq!(build1.wheel_contents, build2.wheel_contents);
|
assert_eq!(build1.wheel_contents, build2.wheel_contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1098,7 +1115,7 @@ mod tests {
|
||||||
fs_err::remove_file(bogus_init_py).unwrap();
|
fs_err::remove_file(bogus_init_py).unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build1 = build(src.path(), dist.path()).unwrap();
|
let build1 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_snapshot!(build1.source_dist_contents.join("\n"), @r"
|
assert_snapshot!(build1.source_dist_contents.join("\n"), @r"
|
||||||
simple_namespace_part-1.0.0/
|
simple_namespace_part-1.0.0/
|
||||||
simple_namespace_part-1.0.0/PKG-INFO
|
simple_namespace_part-1.0.0/PKG-INFO
|
||||||
|
|
@ -1135,7 +1152,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
||||||
|
|
||||||
let build2 = build(src.path(), dist.path()).unwrap();
|
let build2 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_eq!(build1, build2);
|
assert_eq!(build1, build2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1189,7 +1206,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build1 = build(src.path(), dist.path()).unwrap();
|
let build1 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
|
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
|
||||||
complex_namespace-1.0.0.dist-info/
|
complex_namespace-1.0.0.dist-info/
|
||||||
complex_namespace-1.0.0.dist-info/METADATA
|
complex_namespace-1.0.0.dist-info/METADATA
|
||||||
|
|
@ -1219,7 +1236,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
|
||||||
|
|
||||||
let build2 = build(src.path(), dist.path()).unwrap();
|
let build2 = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_eq!(build1, build2);
|
assert_eq!(build1, build2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1260,7 +1277,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build = build(src.path(), dist.path()).unwrap();
|
let build = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_snapshot!(build.wheel_contents.join("\n"), @r"
|
assert_snapshot!(build.wheel_contents.join("\n"), @r"
|
||||||
cloud-stubs/
|
cloud-stubs/
|
||||||
cloud-stubs/db/
|
cloud-stubs/db/
|
||||||
|
|
@ -1357,7 +1374,7 @@ mod tests {
|
||||||
fs_err::remove_file(bogus_init_py).unwrap();
|
fs_err::remove_file(bogus_init_py).unwrap();
|
||||||
|
|
||||||
let dist = TempDir::new().unwrap();
|
let dist = TempDir::new().unwrap();
|
||||||
let build = build(src.path(), dist.path()).unwrap();
|
let build = build(src.path(), dist.path(), Preview::default()).unwrap();
|
||||||
assert_snapshot!(build.source_dist_contents.join("\n"), @r"
|
assert_snapshot!(build.source_dist_contents.join("\n"), @r"
|
||||||
simple_namespace_part-1.0.0/
|
simple_namespace_part-1.0.0/
|
||||||
simple_namespace_part-1.0.0/PKG-INFO
|
simple_namespace_part-1.0.0/PKG-INFO
|
||||||
|
|
@ -1385,4 +1402,51 @@ mod tests {
|
||||||
simple_namespace_part-1.0.0.dist-info/WHEEL
|
simple_namespace_part-1.0.0.dist-info/WHEEL
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that JSON metadata files are present.
|
||||||
|
#[test]
|
||||||
|
fn metadata_json_preview() {
|
||||||
|
let src = TempDir::new().unwrap();
|
||||||
|
fs_err::write(
|
||||||
|
src.path().join("pyproject.toml"),
|
||||||
|
indoc! {r#"
|
||||||
|
[project]
|
||||||
|
name = "metadata-json-preview"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["uv_build>=0.5.15,<0.6.0"]
|
||||||
|
build-backend = "uv_build"
|
||||||
|
"#
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
fs_err::create_dir_all(src.path().join("src").join("metadata_json_preview")).unwrap();
|
||||||
|
File::create(
|
||||||
|
src.path()
|
||||||
|
.join("src")
|
||||||
|
.join("metadata_json_preview")
|
||||||
|
.join("__init__.py"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let dist = TempDir::new().unwrap();
|
||||||
|
let build = build(
|
||||||
|
src.path(),
|
||||||
|
dist.path(),
|
||||||
|
Preview::new(PreviewFeatures::METADATA_JSON),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_snapshot!(build.wheel_contents.join("\n"), @r"
|
||||||
|
metadata_json_preview-1.0.0.dist-info/
|
||||||
|
metadata_json_preview-1.0.0.dist-info/METADATA
|
||||||
|
metadata_json_preview-1.0.0.dist-info/METADATA.json
|
||||||
|
metadata_json_preview-1.0.0.dist-info/RECORD
|
||||||
|
metadata_json_preview-1.0.0.dist-info/WHEEL
|
||||||
|
metadata_json_preview-1.0.0.dist-info/WHEEL.json
|
||||||
|
metadata_json_preview/
|
||||||
|
metadata_json_preview/__init__.py
|
||||||
|
");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use base64::{Engine, prelude::BASE64_URL_SAFE_NO_PAD as base64};
|
use base64::{Engine, prelude::BASE64_URL_SAFE_NO_PAD as base64};
|
||||||
use fs_err::File;
|
use fs_err::File;
|
||||||
use globset::{GlobSet, GlobSetBuilder};
|
use globset::{GlobSet, GlobSetBuilder};
|
||||||
use itertools::Itertools;
|
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
use std::io::{BufReader, Read, Write};
|
use std::io::{BufReader, Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{io, mem};
|
use std::{io, mem};
|
||||||
|
|
@ -15,6 +15,7 @@ use uv_distribution_filename::WheelFilename;
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_globfilter::{GlobDirFilter, PortableGlobParser};
|
use uv_globfilter::{GlobDirFilter, PortableGlobParser};
|
||||||
use uv_platform_tags::{AbiTag, LanguageTag, PlatformTag};
|
use uv_platform_tags::{AbiTag, LanguageTag, PlatformTag};
|
||||||
|
use uv_preview::{Preview, PreviewFeatures};
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
|
|
||||||
use crate::metadata::DEFAULT_EXCLUDES;
|
use crate::metadata::DEFAULT_EXCLUDES;
|
||||||
|
|
@ -28,6 +29,7 @@ pub fn build_wheel(
|
||||||
wheel_dir: &Path,
|
wheel_dir: &Path,
|
||||||
metadata_directory: Option<&Path>,
|
metadata_directory: Option<&Path>,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<WheelFilename, Error> {
|
) -> Result<WheelFilename, Error> {
|
||||||
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
|
|
@ -57,6 +59,7 @@ pub fn build_wheel(
|
||||||
&filename,
|
&filename,
|
||||||
uv_version,
|
uv_version,
|
||||||
wheel_writer,
|
wheel_writer,
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(filename)
|
Ok(filename)
|
||||||
|
|
@ -66,6 +69,7 @@ pub fn build_wheel(
|
||||||
pub fn list_wheel(
|
pub fn list_wheel(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<(WheelFilename, FileList), Error> {
|
) -> Result<(WheelFilename, FileList), Error> {
|
||||||
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
|
|
@ -86,7 +90,14 @@ pub fn list_wheel(
|
||||||
|
|
||||||
let mut files = FileList::new();
|
let mut files = FileList::new();
|
||||||
let writer = ListWriter::new(&mut files);
|
let writer = ListWriter::new(&mut files);
|
||||||
write_wheel(source_tree, &pyproject_toml, &filename, uv_version, writer)?;
|
write_wheel(
|
||||||
|
source_tree,
|
||||||
|
&pyproject_toml,
|
||||||
|
&filename,
|
||||||
|
uv_version,
|
||||||
|
writer,
|
||||||
|
preview,
|
||||||
|
)?;
|
||||||
Ok((filename, files))
|
Ok((filename, files))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,6 +107,7 @@ fn write_wheel(
|
||||||
filename: &WheelFilename,
|
filename: &WheelFilename,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
mut wheel_writer: impl DirectoryWriter,
|
mut wheel_writer: impl DirectoryWriter,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let settings = pyproject_toml
|
let settings = pyproject_toml
|
||||||
.settings()
|
.settings()
|
||||||
|
|
@ -231,6 +243,7 @@ fn write_wheel(
|
||||||
filename,
|
filename,
|
||||||
source_tree,
|
source_tree,
|
||||||
uv_version,
|
uv_version,
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
wheel_writer.close(&dist_info_dir)?;
|
wheel_writer.close(&dist_info_dir)?;
|
||||||
|
|
||||||
|
|
@ -243,6 +256,7 @@ pub fn build_editable(
|
||||||
wheel_dir: &Path,
|
wheel_dir: &Path,
|
||||||
metadata_directory: Option<&Path>,
|
metadata_directory: Option<&Path>,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<WheelFilename, Error> {
|
) -> Result<WheelFilename, Error> {
|
||||||
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
|
|
@ -293,6 +307,7 @@ pub fn build_editable(
|
||||||
&filename,
|
&filename,
|
||||||
source_tree,
|
source_tree,
|
||||||
uv_version,
|
uv_version,
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
wheel_writer.close(&dist_info_dir)?;
|
wheel_writer.close(&dist_info_dir)?;
|
||||||
|
|
||||||
|
|
@ -304,6 +319,7 @@ pub fn metadata(
|
||||||
source_tree: &Path,
|
source_tree: &Path,
|
||||||
metadata_directory: &Path,
|
metadata_directory: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<String, Error> {
|
) -> Result<String, Error> {
|
||||||
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
let contents = fs_err::read_to_string(source_tree.join("pyproject.toml"))?;
|
||||||
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
let pyproject_toml = PyProjectToml::parse(&contents)?;
|
||||||
|
|
@ -333,6 +349,7 @@ pub fn metadata(
|
||||||
&filename,
|
&filename,
|
||||||
source_tree,
|
source_tree,
|
||||||
uv_version,
|
uv_version,
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
wheel_writer.close(&dist_info_dir)?;
|
wheel_writer.close(&dist_info_dir)?;
|
||||||
|
|
||||||
|
|
@ -535,6 +552,7 @@ fn write_dist_info(
|
||||||
filename: &WheelFilename,
|
filename: &WheelFilename,
|
||||||
root: &Path,
|
root: &Path,
|
||||||
uv_version: &str,
|
uv_version: &str,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<String, Error> {
|
) -> Result<String, Error> {
|
||||||
let dist_info_dir = format!(
|
let dist_info_dir = format!(
|
||||||
"{}-{}.dist-info",
|
"{}-{}.dist-info",
|
||||||
|
|
@ -544,9 +562,18 @@ fn write_dist_info(
|
||||||
|
|
||||||
writer.write_directory(&dist_info_dir)?;
|
writer.write_directory(&dist_info_dir)?;
|
||||||
|
|
||||||
// Add `WHEEL`.
|
// Add `WHEEL` and `WHEEL.json`.
|
||||||
let wheel_info = wheel_info(filename, uv_version);
|
let wheel_info = WheelInfo::new(filename, uv_version);
|
||||||
writer.write_bytes(&format!("{dist_info_dir}/WHEEL"), wheel_info.as_bytes())?;
|
writer.write_bytes(
|
||||||
|
&format!("{dist_info_dir}/WHEEL"),
|
||||||
|
wheel_info.to_string().as_bytes(),
|
||||||
|
)?;
|
||||||
|
if preview.is_enabled(PreviewFeatures::METADATA_JSON) {
|
||||||
|
writer.write_bytes(
|
||||||
|
&format!("{dist_info_dir}/WHEEL.json"),
|
||||||
|
&serde_json::to_vec(&wheel_info).map_err(Error::Json)?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Add `entry_points.txt`.
|
// Add `entry_points.txt`.
|
||||||
if let Some(entrypoint) = pyproject_toml.to_entry_points()? {
|
if let Some(entrypoint) = pyproject_toml.to_entry_points()? {
|
||||||
|
|
@ -556,34 +583,64 @@ fn write_dist_info(
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add `METADATA`.
|
// Add `METADATA` and `METADATA.json`.
|
||||||
let metadata = pyproject_toml.to_metadata(root)?.core_metadata_format();
|
let metadata = pyproject_toml.to_metadata(root)?;
|
||||||
writer.write_bytes(&format!("{dist_info_dir}/METADATA"), metadata.as_bytes())?;
|
writer.write_bytes(
|
||||||
|
&format!("{dist_info_dir}/METADATA"),
|
||||||
|
metadata.core_metadata_format().as_bytes(),
|
||||||
|
)?;
|
||||||
|
if preview.is_enabled(PreviewFeatures::METADATA_JSON) {
|
||||||
|
writer.write_bytes(
|
||||||
|
&format!("{dist_info_dir}/METADATA.json"),
|
||||||
|
&serde_json::to_vec(&metadata).map_err(Error::Json)?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// `RECORD` is added on closing.
|
// `RECORD` is added on closing.
|
||||||
|
|
||||||
Ok(dist_info_dir)
|
Ok(dist_info_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `WHEEL` file contents.
|
/// The contents of the `WHEEL` and `WHEEL.json` files.
|
||||||
fn wheel_info(filename: &WheelFilename, uv_version: &str) -> String {
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
// https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-contents
|
#[serde(rename_all = "kebab-case")]
|
||||||
let mut wheel_info = vec![
|
struct WheelInfo {
|
||||||
("Wheel-Version", "1.0".to_string()),
|
wheel_version: String,
|
||||||
("Generator", format!("uv {uv_version}")),
|
generator: String,
|
||||||
("Root-Is-Purelib", "true".to_string()),
|
root_is_purelib: bool,
|
||||||
];
|
tags: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WheelInfo {
|
||||||
|
fn new(filename: &WheelFilename, uv_version: &str) -> Self {
|
||||||
|
let mut tags = Vec::new();
|
||||||
for python_tag in filename.python_tags() {
|
for python_tag in filename.python_tags() {
|
||||||
for abi_tag in filename.abi_tags() {
|
for abi_tag in filename.abi_tags() {
|
||||||
for platform_tag in filename.platform_tags() {
|
for platform_tag in filename.platform_tags() {
|
||||||
wheel_info.push(("Tag", format!("{python_tag}-{abi_tag}-{platform_tag}")));
|
tags.push(format!("{python_tag}-{abi_tag}-{platform_tag}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wheel_info
|
Self {
|
||||||
.into_iter()
|
wheel_version: "1.0".to_string(),
|
||||||
.map(|(key, value)| format!("{key}: {value}"))
|
generator: format!("uv {uv_version}"),
|
||||||
.join("\n")
|
root_is_purelib: true,
|
||||||
|
tags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for WheelInfo {
|
||||||
|
/// Returns the `WHEEL` file contents in its key-value format.
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "Wheel-Version: {}", self.wheel_version)?;
|
||||||
|
writeln!(f, "Generator: {}", self.generator)?;
|
||||||
|
writeln!(f, "Root-Is-Purelib: {}", self.root_is_purelib)?;
|
||||||
|
for tag in &self.tags {
|
||||||
|
writeln!(f, "Tag: {tag}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zip archive (wheel) writer.
|
/// Zip archive (wheel) writer.
|
||||||
|
|
@ -784,7 +841,7 @@ mod test {
|
||||||
PlatformTag::Any,
|
PlatformTag::Any,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_snapshot!(wheel_info(&filename, "1.0.0+test"), @r"
|
assert_snapshot!(WheelInfo::new(&filename, "1.0.0+test").to_string(), @r"
|
||||||
Wheel-Version: 1.0
|
Wheel-Version: 1.0
|
||||||
Generator: uv 1.0.0+test
|
Generator: uv 1.0.0+test
|
||||||
Root-Is-Purelib: true
|
Root-Is-Purelib: true
|
||||||
|
|
@ -813,7 +870,13 @@ mod test {
|
||||||
fn test_prepare_metadata() {
|
fn test_prepare_metadata() {
|
||||||
let metadata_dir = TempDir::new().unwrap();
|
let metadata_dir = TempDir::new().unwrap();
|
||||||
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");
|
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");
|
||||||
metadata(built_by_uv, metadata_dir.path(), "1.0.0+test").unwrap();
|
metadata(
|
||||||
|
built_by_uv,
|
||||||
|
metadata_dir.path(),
|
||||||
|
"1.0.0+test",
|
||||||
|
Preview::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
|
let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
|
||||||
.sort_by_file_name()
|
.sort_by_file_name()
|
||||||
|
|
@ -861,12 +924,12 @@ mod test {
|
||||||
let record_file = metadata_dir
|
let record_file = metadata_dir
|
||||||
.path()
|
.path()
|
||||||
.join("built_by_uv-0.1.0.dist-info/RECORD");
|
.join("built_by_uv-0.1.0.dist-info/RECORD");
|
||||||
assert_snapshot!(fs_err::read_to_string(record_file).unwrap(), @r###"
|
assert_snapshot!(fs_err::read_to_string(record_file).unwrap(), @r"
|
||||||
built_by_uv-0.1.0.dist-info/WHEEL,sha256=PaG_oOj9G2zCRqoLK0SjWBVZbGAMtIXDmm-MEGw9Wo0,83
|
built_by_uv-0.1.0.dist-info/WHEEL,sha256=JBpLtoa_WBz5WPGpRsAUTD4Dz6H0KkkdiKWCkfMSS1U,84
|
||||||
built_by_uv-0.1.0.dist-info/entry_points.txt,sha256=-IO6yaq6x6HSl-zWH96rZmgYvfyHlH00L5WQoCpz-YI,50
|
built_by_uv-0.1.0.dist-info/entry_points.txt,sha256=-IO6yaq6x6HSl-zWH96rZmgYvfyHlH00L5WQoCpz-YI,50
|
||||||
built_by_uv-0.1.0.dist-info/METADATA,sha256=m6EkVvKrGmqx43b_VR45LHD37IZxPYC0NI6Qx9_UXLE,474
|
built_by_uv-0.1.0.dist-info/METADATA,sha256=m6EkVvKrGmqx43b_VR45LHD37IZxPYC0NI6Qx9_UXLE,474
|
||||||
built_by_uv-0.1.0.dist-info/RECORD,,
|
built_by_uv-0.1.0.dist-info/RECORD,,
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let wheel_file = metadata_dir
|
let wheel_file = metadata_dir
|
||||||
.path()
|
.path()
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ license = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uv-build-backend = { workspace = true }
|
uv-build-backend = { workspace = true }
|
||||||
|
uv-preview = { workspace = true }
|
||||||
uv-version = { workspace = true }
|
uv-version = { workspace = true }
|
||||||
|
uv-static = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ use anyhow::{Context, Result, bail};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use uv_preview::{Preview, PreviewFeatures};
|
||||||
|
use uv_static::{EnvVars, parse_boolish_environment_variable};
|
||||||
|
|
||||||
/// Entrypoint for the `uv-build` Python package.
|
/// Entrypoint for the `uv-build` Python package.
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
|
@ -15,6 +18,25 @@ fn main() -> Result<()> {
|
||||||
.to_str()
|
.to_str()
|
||||||
.context("Invalid non-UTF8 command")?
|
.context("Invalid non-UTF8 command")?
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
|
// Ad-hoc preview features parsing due to a lack of clap CLI in uv-build.
|
||||||
|
let preview_features =
|
||||||
|
if parse_boolish_environment_variable(EnvVars::UV_PREVIEW)?.unwrap_or(false) {
|
||||||
|
PreviewFeatures::all()
|
||||||
|
} else if let Some(preview_features) = env::var_os(EnvVars::UV_PREVIEW_FEATURES) {
|
||||||
|
let preview_features = preview_features.to_str().with_context(|| {
|
||||||
|
format!("`{}` is not valid UTF-8", EnvVars::UV_PREVIEW_FEATURES)
|
||||||
|
})?;
|
||||||
|
PreviewFeatures::from_str(preview_features).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Invalid preview features list in `{}`",
|
||||||
|
EnvVars::UV_PREVIEW_FEATURES
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
} else {
|
||||||
|
PreviewFeatures::default()
|
||||||
|
};
|
||||||
|
let preview = Preview::new(preview_features);
|
||||||
match command.as_str() {
|
match command.as_str() {
|
||||||
"build-sdist" => {
|
"build-sdist" => {
|
||||||
let sdist_directory = PathBuf::from(args.next().context("Missing sdist directory")?);
|
let sdist_directory = PathBuf::from(args.next().context("Missing sdist directory")?);
|
||||||
|
|
@ -34,6 +56,7 @@ fn main() -> Result<()> {
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
metadata_directory.as_deref(),
|
metadata_directory.as_deref(),
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -46,6 +69,7 @@ fn main() -> Result<()> {
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
metadata_directory.as_deref(),
|
metadata_directory.as_deref(),
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -56,6 +80,7 @@ fn main() -> Result<()> {
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -66,6 +91,7 @@ fn main() -> Result<()> {
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
|
||||||
|
|
@ -523,6 +523,7 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
debug!("Performing direct build for {identifier}");
|
debug!("Performing direct build for {identifier}");
|
||||||
|
|
||||||
let output_dir = output_dir.to_path_buf();
|
let output_dir = output_dir.to_path_buf();
|
||||||
|
let preview = self.preview;
|
||||||
let filename = tokio::task::spawn_blocking(move || -> Result<_> {
|
let filename = tokio::task::spawn_blocking(move || -> Result<_> {
|
||||||
let filename = match build_kind {
|
let filename = match build_kind {
|
||||||
BuildKind::Wheel => {
|
BuildKind::Wheel => {
|
||||||
|
|
@ -531,6 +532,7 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
&output_dir,
|
&output_dir,
|
||||||
None,
|
None,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
DistFilename::WheelFilename(wheel)
|
DistFilename::WheelFilename(wheel)
|
||||||
}
|
}
|
||||||
|
|
@ -548,6 +550,7 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
&output_dir,
|
&output_dir,
|
||||||
None,
|
None,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
DistFilename::WheelFilename(wheel)
|
DistFilename::WheelFilename(wheel)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ bitflags::bitflags! {
|
||||||
const EXTRA_BUILD_DEPENDENCIES = 1 << 6;
|
const EXTRA_BUILD_DEPENDENCIES = 1 << 6;
|
||||||
const DETECT_MODULE_CONFLICTS = 1 << 7;
|
const DETECT_MODULE_CONFLICTS = 1 << 7;
|
||||||
const FORMAT = 1 << 8;
|
const FORMAT = 1 << 8;
|
||||||
|
const METADATA_JSON = 1 << 9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +37,7 @@ impl PreviewFeatures {
|
||||||
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
||||||
Self::DETECT_MODULE_CONFLICTS => "detect-module-conflicts",
|
Self::DETECT_MODULE_CONFLICTS => "detect-module-conflicts",
|
||||||
Self::FORMAT => "format",
|
Self::FORMAT => "format",
|
||||||
|
Self::METADATA_JSON => "metadata-json",
|
||||||
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +84,7 @@ impl FromStr for PreviewFeatures {
|
||||||
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
||||||
"detect-module-conflicts" => Self::DETECT_MODULE_CONFLICTS,
|
"detect-module-conflicts" => Self::DETECT_MODULE_CONFLICTS,
|
||||||
"format" => Self::FORMAT,
|
"format" => Self::FORMAT,
|
||||||
|
"metadata-json" => Self::METADATA_JSON,
|
||||||
_ => {
|
_ => {
|
||||||
warn_user_once!("Unknown preview feature: `{part}`");
|
warn_user_once!("Unknown preview feature: `{part}`");
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -257,6 +260,10 @@ mod tests {
|
||||||
"detect-module-conflicts"
|
"detect-module-conflicts"
|
||||||
);
|
);
|
||||||
assert_eq!(PreviewFeatures::FORMAT.flag_as_str(), "format");
|
assert_eq!(PreviewFeatures::FORMAT.flag_as_str(), "format");
|
||||||
|
assert_eq!(
|
||||||
|
PreviewFeatures::METADATA_JSON.flag_as_str(),
|
||||||
|
"metadata-json"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ use crate::metadata::Headers;
|
||||||
|
|
||||||
/// Code Metadata 2.3 as specified in
|
/// Code Metadata 2.3 as specified in
|
||||||
/// <https://packaging.python.org/specifications/core-metadata/>.
|
/// <https://packaging.python.org/specifications/core-metadata/>.
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct Metadata23 {
|
pub struct Metadata23 {
|
||||||
/// Version of the file format; legal values are `1.0`, `1.1`, `1.2`, `2.1`, `2.2`, `2.3` and
|
/// Version of the file format; legal values are `1.0`, `1.1`, `1.2`, `2.1`, `2.2`, `2.3` and
|
||||||
/// `2.4`.
|
/// `2.4`.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use uv_dirs::{system_config_file, user_config_dir};
|
use uv_dirs::{system_config_file, user_config_dir};
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_static::EnvVars;
|
use uv_static::{EnvVars, InvalidEnvironmentVariable, parse_boolish_environment_variable};
|
||||||
use uv_warnings::warn_user;
|
use uv_warnings::warn_user;
|
||||||
|
|
||||||
pub use crate::combine::*;
|
pub use crate::combine::*;
|
||||||
|
|
@ -554,12 +554,8 @@ pub enum Error {
|
||||||
#[error("Failed to parse: `{}`. The `{}` field is not allowed in a `uv.toml` file. `{}` is only applicable in the context of a project, and should be placed in a `pyproject.toml` file instead.", _0.user_display(), _1, _1)]
|
#[error("Failed to parse: `{}`. The `{}` field is not allowed in a `uv.toml` file. `{}` is only applicable in the context of a project, and should be placed in a `pyproject.toml` file instead.", _0.user_display(), _1, _1)]
|
||||||
PyprojectOnlyField(PathBuf, &'static str),
|
PyprojectOnlyField(PathBuf, &'static str),
|
||||||
|
|
||||||
#[error("Failed to parse environment variable `{name}` with invalid value `{value}`: {err}")]
|
#[error(transparent)]
|
||||||
InvalidEnvironmentVariable {
|
InvalidEnvironmentVariable(#[from] InvalidEnvironmentVariable),
|
||||||
name: String,
|
|
||||||
value: String,
|
|
||||||
err: String,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options loaded from environment variables.
|
/// Options loaded from environment variables.
|
||||||
|
|
@ -583,55 +579,3 @@ impl EnvironmentOptions {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a boolean environment variable.
|
|
||||||
///
|
|
||||||
/// Adapted from Clap's `BoolishValueParser` which is dual licensed under the MIT and Apache-2.0.
|
|
||||||
fn parse_boolish_environment_variable(name: &'static str) -> Result<Option<bool>, Error> {
|
|
||||||
// See `clap_builder/src/util/str_to_bool.rs`
|
|
||||||
// We want to match Clap's accepted values
|
|
||||||
|
|
||||||
// True values are `y`, `yes`, `t`, `true`, `on`, and `1`.
|
|
||||||
const TRUE_LITERALS: [&str; 6] = ["y", "yes", "t", "true", "on", "1"];
|
|
||||||
|
|
||||||
// False values are `n`, `no`, `f`, `false`, `off`, and `0`.
|
|
||||||
const FALSE_LITERALS: [&str; 6] = ["n", "no", "f", "false", "off", "0"];
|
|
||||||
|
|
||||||
// Converts a string literal representation of truth to true or false.
|
|
||||||
//
|
|
||||||
// `false` values are `n`, `no`, `f`, `false`, `off`, and `0` (case insensitive).
|
|
||||||
//
|
|
||||||
// Any other value will be considered as `true`.
|
|
||||||
fn str_to_bool(val: impl AsRef<str>) -> Option<bool> {
|
|
||||||
let pat: &str = &val.as_ref().to_lowercase();
|
|
||||||
if TRUE_LITERALS.contains(&pat) {
|
|
||||||
Some(true)
|
|
||||||
} else if FALSE_LITERALS.contains(&pat) {
|
|
||||||
Some(false)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(value) = std::env::var_os(name) else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(value) = value.to_str() else {
|
|
||||||
return Err(Error::InvalidEnvironmentVariable {
|
|
||||||
name: name.to_string(),
|
|
||||||
value: value.to_string_lossy().to_string(),
|
|
||||||
err: "expected a valid UTF-8 string".to_string(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(value) = str_to_bool(value) else {
|
|
||||||
return Err(Error::InvalidEnvironmentVariable {
|
|
||||||
name: name.to_string(),
|
|
||||||
value: value.to_string(),
|
|
||||||
err: "expected a boolish value".to_string(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(value))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -17,3 +17,5 @@ workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uv-macros = { workspace = true }
|
uv-macros = { workspace = true }
|
||||||
|
|
||||||
|
thiserror = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,67 @@
|
||||||
pub use env_vars::*;
|
pub use env_vars::*;
|
||||||
|
|
||||||
mod env_vars;
|
mod env_vars;
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("Failed to parse environment variable `{name}` with invalid value `{value}`: {err}")]
|
||||||
|
pub struct InvalidEnvironmentVariable {
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
err: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a boolean environment variable.
|
||||||
|
///
|
||||||
|
/// Adapted from Clap's `BoolishValueParser` which is dual licensed under the MIT and Apache-2.0.
|
||||||
|
pub fn parse_boolish_environment_variable(
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<Option<bool>, InvalidEnvironmentVariable> {
|
||||||
|
// See `clap_builder/src/util/str_to_bool.rs`
|
||||||
|
// We want to match Clap's accepted values
|
||||||
|
|
||||||
|
// True values are `y`, `yes`, `t`, `true`, `on`, and `1`.
|
||||||
|
const TRUE_LITERALS: [&str; 6] = ["y", "yes", "t", "true", "on", "1"];
|
||||||
|
|
||||||
|
// False values are `n`, `no`, `f`, `false`, `off`, and `0`.
|
||||||
|
const FALSE_LITERALS: [&str; 6] = ["n", "no", "f", "false", "off", "0"];
|
||||||
|
|
||||||
|
// Converts a string literal representation of truth to true or false.
|
||||||
|
//
|
||||||
|
// `false` values are `n`, `no`, `f`, `false`, `off`, and `0` (case insensitive).
|
||||||
|
//
|
||||||
|
// Any other value will be considered as `true`.
|
||||||
|
fn str_to_bool(val: impl AsRef<str>) -> Option<bool> {
|
||||||
|
let pat: &str = &val.as_ref().to_lowercase();
|
||||||
|
if TRUE_LITERALS.contains(&pat) {
|
||||||
|
Some(true)
|
||||||
|
} else if FALSE_LITERALS.contains(&pat) {
|
||||||
|
Some(false)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(value) = std::env::var_os(name) else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(value) = value.to_str() else {
|
||||||
|
return Err(InvalidEnvironmentVariable {
|
||||||
|
name: name.to_string(),
|
||||||
|
value: value.to_string_lossy().to_string(),
|
||||||
|
err: "expected a valid UTF-8 string".to_string(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(value) = str_to_bool(value) else {
|
||||||
|
return Err(InvalidEnvironmentVariable {
|
||||||
|
name: name.to_string(),
|
||||||
|
value: value.to_string(),
|
||||||
|
err: "expected a boolish value".to_string(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(value))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use anyhow::{Context, Result};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use uv_preview::Preview;
|
||||||
|
|
||||||
/// PEP 517 hook to build a source distribution.
|
/// PEP 517 hook to build a source distribution.
|
||||||
pub(crate) fn build_sdist(sdist_directory: &Path) -> Result<ExitStatus> {
|
pub(crate) fn build_sdist(sdist_directory: &Path) -> Result<ExitStatus> {
|
||||||
|
|
@ -20,12 +21,14 @@ pub(crate) fn build_sdist(sdist_directory: &Path) -> Result<ExitStatus> {
|
||||||
pub(crate) fn build_wheel(
|
pub(crate) fn build_wheel(
|
||||||
wheel_directory: &Path,
|
wheel_directory: &Path,
|
||||||
metadata_directory: Option<&Path>,
|
metadata_directory: Option<&Path>,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<ExitStatus> {
|
) -> Result<ExitStatus> {
|
||||||
let filename = uv_build_backend::build_wheel(
|
let filename = uv_build_backend::build_wheel(
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
wheel_directory,
|
wheel_directory,
|
||||||
metadata_directory,
|
metadata_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -36,12 +39,14 @@ pub(crate) fn build_wheel(
|
||||||
pub(crate) fn build_editable(
|
pub(crate) fn build_editable(
|
||||||
wheel_directory: &Path,
|
wheel_directory: &Path,
|
||||||
metadata_directory: Option<&Path>,
|
metadata_directory: Option<&Path>,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<ExitStatus> {
|
) -> Result<ExitStatus> {
|
||||||
let filename = uv_build_backend::build_editable(
|
let filename = uv_build_backend::build_editable(
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
wheel_directory,
|
wheel_directory,
|
||||||
metadata_directory,
|
metadata_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -59,11 +64,15 @@ pub(crate) fn get_requires_for_build_wheel() -> Result<ExitStatus> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PEP 517 hook to just emit metadata through `.dist-info`.
|
/// PEP 517 hook to just emit metadata through `.dist-info`.
|
||||||
pub(crate) fn prepare_metadata_for_build_wheel(metadata_directory: &Path) -> Result<ExitStatus> {
|
pub(crate) fn prepare_metadata_for_build_wheel(
|
||||||
|
metadata_directory: &Path,
|
||||||
|
preview: Preview,
|
||||||
|
) -> Result<ExitStatus> {
|
||||||
let filename = uv_build_backend::metadata(
|
let filename = uv_build_backend::metadata(
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
metadata_directory,
|
metadata_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
@ -76,11 +85,15 @@ pub(crate) fn get_requires_for_build_editable() -> Result<ExitStatus> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PEP 660 hook to just emit metadata through `.dist-info`.
|
/// PEP 660 hook to just emit metadata through `.dist-info`.
|
||||||
pub(crate) fn prepare_metadata_for_build_editable(metadata_directory: &Path) -> Result<ExitStatus> {
|
pub(crate) fn prepare_metadata_for_build_editable(
|
||||||
|
metadata_directory: &Path,
|
||||||
|
preview: Preview,
|
||||||
|
) -> Result<ExitStatus> {
|
||||||
let filename = uv_build_backend::metadata(
|
let filename = uv_build_backend::metadata(
|
||||||
&env::current_dir()?,
|
&env::current_dir()?,
|
||||||
metadata_directory,
|
metadata_directory,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)?;
|
)?;
|
||||||
// Tell the build frontend about the name of the artifact we built
|
// Tell the build frontend about the name of the artifact we built
|
||||||
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
writeln!(&mut std::io::stdout(), "{filename}").context("stdout is closed")?;
|
||||||
|
|
|
||||||
|
|
@ -729,6 +729,7 @@ async fn build_package(
|
||||||
version_id,
|
version_id,
|
||||||
build_output,
|
build_output,
|
||||||
Some(sdist_build.normalized_filename().version()),
|
Some(sdist_build.normalized_filename().version()),
|
||||||
|
preview,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
build_results.push(wheel_build);
|
build_results.push(wheel_build);
|
||||||
|
|
@ -766,6 +767,7 @@ async fn build_package(
|
||||||
version_id,
|
version_id,
|
||||||
build_output,
|
build_output,
|
||||||
None,
|
None,
|
||||||
|
preview,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
build_results.push(wheel_build);
|
build_results.push(wheel_build);
|
||||||
|
|
@ -801,6 +803,7 @@ async fn build_package(
|
||||||
version_id,
|
version_id,
|
||||||
build_output,
|
build_output,
|
||||||
Some(sdist_build.normalized_filename().version()),
|
Some(sdist_build.normalized_filename().version()),
|
||||||
|
preview,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
build_results.push(sdist_build);
|
build_results.push(sdist_build);
|
||||||
|
|
@ -844,6 +847,7 @@ async fn build_package(
|
||||||
version_id,
|
version_id,
|
||||||
build_output,
|
build_output,
|
||||||
version.as_ref(),
|
version.as_ref(),
|
||||||
|
preview,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
build_results.push(wheel_build);
|
build_results.push(wheel_build);
|
||||||
|
|
@ -996,12 +1000,13 @@ async fn build_wheel(
|
||||||
build_output: BuildOutput,
|
build_output: BuildOutput,
|
||||||
// Used for checking version consistency
|
// Used for checking version consistency
|
||||||
version: Option<&Version>,
|
version: Option<&Version>,
|
||||||
|
preview: Preview,
|
||||||
) -> Result<BuildMessage, Error> {
|
) -> Result<BuildMessage, Error> {
|
||||||
let build_message = match action {
|
let build_message = match action {
|
||||||
BuildAction::List => {
|
BuildAction::List => {
|
||||||
let source_tree_ = source_tree.to_path_buf();
|
let source_tree_ = source_tree.to_path_buf();
|
||||||
let (filename, file_list) = tokio::task::spawn_blocking(move || {
|
let (filename, file_list) = tokio::task::spawn_blocking(move || {
|
||||||
uv_build_backend::list_wheel(&source_tree_, uv_version::version())
|
uv_build_backend::list_wheel(&source_tree_, uv_version::version(), preview)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
let raw_filename = filename.to_string();
|
let raw_filename = filename.to_string();
|
||||||
|
|
@ -1031,6 +1036,7 @@ async fn build_wheel(
|
||||||
&output_dir_,
|
&output_dir_,
|
||||||
None,
|
None,
|
||||||
uv_version::version(),
|
uv_version::version(),
|
||||||
|
preview,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
|
||||||
|
|
@ -1641,6 +1641,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
} => commands::build_backend::build_wheel(
|
} => commands::build_backend::build_wheel(
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
metadata_directory.as_deref(),
|
metadata_directory.as_deref(),
|
||||||
|
globals.preview,
|
||||||
),
|
),
|
||||||
BuildBackendCommand::BuildEditable {
|
BuildBackendCommand::BuildEditable {
|
||||||
wheel_directory,
|
wheel_directory,
|
||||||
|
|
@ -1648,6 +1649,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
} => commands::build_backend::build_editable(
|
} => commands::build_backend::build_editable(
|
||||||
&wheel_directory,
|
&wheel_directory,
|
||||||
metadata_directory.as_deref(),
|
metadata_directory.as_deref(),
|
||||||
|
globals.preview,
|
||||||
),
|
),
|
||||||
BuildBackendCommand::GetRequiresForBuildSdist => {
|
BuildBackendCommand::GetRequiresForBuildSdist => {
|
||||||
commands::build_backend::get_requires_for_build_sdist()
|
commands::build_backend::get_requires_for_build_sdist()
|
||||||
|
|
@ -1656,13 +1658,19 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
commands::build_backend::get_requires_for_build_wheel()
|
commands::build_backend::get_requires_for_build_wheel()
|
||||||
}
|
}
|
||||||
BuildBackendCommand::PrepareMetadataForBuildWheel { wheel_directory } => {
|
BuildBackendCommand::PrepareMetadataForBuildWheel { wheel_directory } => {
|
||||||
commands::build_backend::prepare_metadata_for_build_wheel(&wheel_directory)
|
commands::build_backend::prepare_metadata_for_build_wheel(
|
||||||
|
&wheel_directory,
|
||||||
|
globals.preview,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
BuildBackendCommand::GetRequiresForBuildEditable => {
|
BuildBackendCommand::GetRequiresForBuildEditable => {
|
||||||
commands::build_backend::get_requires_for_build_editable()
|
commands::build_backend::get_requires_for_build_editable()
|
||||||
}
|
}
|
||||||
BuildBackendCommand::PrepareMetadataForBuildEditable { wheel_directory } => {
|
BuildBackendCommand::PrepareMetadataForBuildEditable { wheel_directory } => {
|
||||||
commands::build_backend::prepare_metadata_for_build_editable(&wheel_directory)
|
commands::build_backend::prepare_metadata_for_build_editable(
|
||||||
|
&wheel_directory,
|
||||||
|
globals.preview,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue