diff --git a/crates/rattler_installs_packages/src/sdist.rs b/crates/rattler_installs_packages/src/sdist.rs index 2ca5c8c5..b1f7cee1 100644 --- a/crates/rattler_installs_packages/src/sdist.rs +++ b/crates/rattler_installs_packages/src/sdist.rs @@ -239,11 +239,11 @@ mod tests { } #[tokio::test(flavor = "multi_thread")] - pub async fn build_rich() { + pub async fn sdist_metadata() { let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../test-data/sdists/rich-13.6.0.tar.gz"); - let sdist = super::SDist::from_path(&path, &"rich".parse().unwrap()).unwrap(); + let sdist = SDist::from_path(&path, &"rich".parse().unwrap()).unwrap(); let package_db = get_package_db(); let env_markers = Pep508EnvMakers::from_env().await.unwrap(); @@ -254,4 +254,48 @@ mod tests { assert_debug_snapshot!(result.1); } + + #[tokio::test(flavor = "multi_thread")] + pub async fn build_rich_with_metadata() { + let path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../test-data/sdists/rich-13.6.0.tar.gz"); + + let sdist = SDist::from_path(&path, &"rich".parse().unwrap()).unwrap(); + + let package_db = get_package_db(); + let env_markers = Pep508EnvMakers::from_env().await.unwrap(); + let resolve_options = ResolveOptions::default(); + let wheel_builder = WheelBuilder::new(&package_db.0, &env_markers, None, &resolve_options); + + // Build the wheel + wheel_builder.get_sdist_metadata(&sdist).await.unwrap(); + let result = wheel_builder.build_wheel(&sdist).await.unwrap(); + + // Try to re-open the wheel + let wheel = crate::wheel::Wheel::from_path(&result, &"rich".parse().unwrap()).unwrap(); + + let (_, metadata) = wheel.metadata().unwrap(); + assert_debug_snapshot!(metadata); + } + #[tokio::test(flavor = "multi_thread")] + pub async fn build_rich_no_metadata() { + let path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../test-data/sdists/rich-13.6.0.tar.gz"); + + let sdist = SDist::from_path(&path, &"rich".parse().unwrap()).unwrap(); + + let package_db = get_package_db(); + let env_markers = Pep508EnvMakers::from_env().await.unwrap(); + let resolve_options = ResolveOptions::default(); + let wheel_builder = WheelBuilder::new(&package_db.0, &env_markers, None, &resolve_options); + + // Build the wheel + let result = wheel_builder.build_wheel(&sdist).await.unwrap(); + + // Try to re-open the wheel + let wheel = crate::wheel::Wheel::from_path(&result, &"rich".parse().unwrap()).unwrap(); + + let (_, metadata) = wheel.metadata().unwrap(); + assert_debug_snapshot!(metadata); + } } diff --git a/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__build_rich_no_metadata.snap b/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__build_rich_no_metadata.snap new file mode 100644 index 00000000..f11c0b03 --- /dev/null +++ b/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__build_rich_no_metadata.snap @@ -0,0 +1,240 @@ +--- +source: crates/rattler_installs_packages/src/sdist.rs +expression: metadata +--- +WheelCoreMetadata { + name: PackageName { + source: "rich", + normalized: "rich", + }, + version: Version { + epoch: 0, + release: [ + 13, + 6, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + metadata_version: MetadataVersion( + Version { + epoch: 0, + release: [ + 2, + 1, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + ), + requires_dist: [ + Requirement { + name: "ipywidgets", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 7, + 5, + 1, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 9, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: Some( + Expression( + MarkerExpression { + l_value: Extra, + operator: Equal, + r_value: QuotedString( + "jupyter", + ), + }, + ), + ), + }, + Requirement { + name: "markdown-it-py", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 2, + 2, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: None, + }, + Requirement { + name: "pygments", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 2, + 13, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 3, + 0, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: None, + }, + Requirement { + name: "typing-extensions", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 4, + 0, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 5, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: Some( + Expression( + MarkerExpression { + l_value: MarkerEnvVersion( + PythonVersion, + ), + operator: LessThan, + r_value: QuotedString( + "3.9", + ), + }, + ), + ), + }, + ], + requires_python: Some( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 3, + 7, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + extras: { + Extra { + source: "jupyter", + normalized: "jupyter", + }, + }, +} diff --git a/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__build_rich_with_metadata.snap b/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__build_rich_with_metadata.snap new file mode 100644 index 00000000..f11c0b03 --- /dev/null +++ b/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__build_rich_with_metadata.snap @@ -0,0 +1,240 @@ +--- +source: crates/rattler_installs_packages/src/sdist.rs +expression: metadata +--- +WheelCoreMetadata { + name: PackageName { + source: "rich", + normalized: "rich", + }, + version: Version { + epoch: 0, + release: [ + 13, + 6, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + metadata_version: MetadataVersion( + Version { + epoch: 0, + release: [ + 2, + 1, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + ), + requires_dist: [ + Requirement { + name: "ipywidgets", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 7, + 5, + 1, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 9, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: Some( + Expression( + MarkerExpression { + l_value: Extra, + operator: Equal, + r_value: QuotedString( + "jupyter", + ), + }, + ), + ), + }, + Requirement { + name: "markdown-it-py", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 2, + 2, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: None, + }, + Requirement { + name: "pygments", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 2, + 13, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 3, + 0, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: None, + }, + Requirement { + name: "typing-extensions", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 4, + 0, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 5, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: Some( + Expression( + MarkerExpression { + l_value: MarkerEnvVersion( + PythonVersion, + ), + operator: LessThan, + r_value: QuotedString( + "3.9", + ), + }, + ), + ), + }, + ], + requires_python: Some( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 3, + 7, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + extras: { + Extra { + source: "jupyter", + normalized: "jupyter", + }, + }, +} diff --git a/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__sdist_metadata.snap b/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__sdist_metadata.snap new file mode 100644 index 00000000..bf414fc1 --- /dev/null +++ b/crates/rattler_installs_packages/src/snapshots/rattler_installs_packages__sdist__tests__sdist_metadata.snap @@ -0,0 +1,240 @@ +--- +source: crates/rattler_installs_packages/src/sdist.rs +expression: result.1 +--- +WheelCoreMetadata { + name: PackageName { + source: "rich", + normalized: "rich", + }, + version: Version { + epoch: 0, + release: [ + 13, + 6, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + metadata_version: MetadataVersion( + Version { + epoch: 0, + release: [ + 2, + 1, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + ), + requires_dist: [ + Requirement { + name: "ipywidgets", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 7, + 5, + 1, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 9, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: Some( + Expression( + MarkerExpression { + l_value: Extra, + operator: Equal, + r_value: QuotedString( + "jupyter", + ), + }, + ), + ), + }, + Requirement { + name: "markdown-it-py", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 2, + 2, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: None, + }, + Requirement { + name: "pygments", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 2, + 13, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 3, + 0, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: None, + }, + Requirement { + name: "typing-extensions", + extras: None, + version_or_url: Some( + VersionSpecifier( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 4, + 0, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + VersionSpecifier { + operator: LessThan, + version: Version { + epoch: 0, + release: [ + 5, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + ), + marker: Some( + Expression( + MarkerExpression { + l_value: MarkerEnvVersion( + PythonVersion, + ), + operator: LessThan, + r_value: QuotedString( + "3.9", + ), + }, + ), + ), + }, + ], + requires_python: Some( + VersionSpecifiers( + [ + VersionSpecifier { + operator: GreaterThanEqual, + version: Version { + epoch: 0, + release: [ + 3, + 7, + 0, + ], + pre: None, + post: None, + dev: None, + local: None, + }, + }, + ], + ), + ), + extras: { + Extra { + source: "jupyter", + normalized: "jupyter", + }, + }, +} diff --git a/crates/rattler_installs_packages/src/wheel.rs b/crates/rattler_installs_packages/src/wheel.rs index 69ae59e3..5ff13669 100644 --- a/crates/rattler_installs_packages/src/wheel.rs +++ b/crates/rattler_installs_packages/src/wheel.rs @@ -360,6 +360,15 @@ impl WheelVitalsError { pub fn from_zip(file: String, err: ZipError) -> Self { match err { ZipError::Io(err) => WheelVitalsError::IoError(err), + ZipError::FileNotFound => { + if file.ends_with("WHEEL") { + WheelVitalsError::WheelMissing + } else if file.ends_with("METADATA") { + WheelVitalsError::MetadataMissing + } else { + WheelVitalsError::ZipError(file, err) + } + } _ => WheelVitalsError::ZipError(file, err), } } diff --git a/crates/rattler_installs_packages/src/wheel_builder_frontend.py b/crates/rattler_installs_packages/src/wheel_builder_frontend.py index 006a05b1..e6445ff8 100644 --- a/crates/rattler_installs_packages/src/wheel_builder_frontend.py +++ b/crates/rattler_installs_packages/src/wheel_builder_frontend.py @@ -46,7 +46,7 @@ def get_backend_from_entry_point(entrypoint: str) -> ModuleType: def get_requires_for_build_wheel(backend: ModuleType, work_dir: Path) -> [str]: """ - Returs a list of requirements. This is only necessary if we do not + Returns a list of requirements. This is only necessary if we do not have a pyproject.toml file. """ f = getattr(backend, "get_requires_for_build_wheel") @@ -60,7 +60,7 @@ def get_requires_for_build_wheel(backend: ModuleType, work_dir: Path) -> [str]: out_json_file.write_text(j) print(j) -def metadata_dir(work_dir: Path): +def metadata_dirs(work_dir: Path): return work_dir / "metadata" def prepare_metadata_for_build_wheel(backend: ModuleType, work_dir: Path): @@ -68,28 +68,35 @@ def prepare_metadata_for_build_wheel(backend: ModuleType, work_dir: Path): Prepare any files that need to be generated before building the wheel. """ if hasattr(backend, "prepare_metadata_for_build_wheel"): + # Create an output file for the metadata result_file = work_dir / "metadata_result" - d = metadata_dir(work_dir) + + # Create the metadata output directory + d = metadata_dirs(work_dir) d.mkdir() dist_info = backend.prepare_metadata_for_build_wheel(str(d)) + # Path to the dist-info directory result = str(d / dist_info) + # Write the path to the dist-info directory to a file result_file.write_text(result) else: exit(123) -def wheel_dir(work_dir: Path): +def wheel_dirs(work_dir: Path): return work_dir / "wheel" def build_wheel(backend: ModuleType, work_dir: Path): """Take a folder with an SDist and build a wheel from it.""" + wheel_dir = wheel_dirs(work_dir) - wheel_dir = wheel_dir(work_dir) - metadata_dir = metadata_dir(work_dir) + # TODO: maybe start reading this from the file again if it fails + metadata_dir = metadata_dirs(work_dir) / ".dist-info" + # Use the metadata directory if it exists, otherwise set this to None wheel_dir.mkdir() wheel_basename = backend.build_wheel( str(wheel_dir), - metadata_directory=str(metadata_dir), + metadata_directory=metadata_dir if metadata_dir.exists() else None, ) print(str(wheel_dir / wheel_basename))