diff --git a/src/module_writer/mod.rs b/src/module_writer/mod.rs index 9cf136fe5..3a58e0a46 100644 --- a/src/module_writer/mod.rs +++ b/src/module_writer/mod.rs @@ -137,6 +137,7 @@ pub fn write_python_part( .parents(false) .git_global(false) .git_exclude(false) + .follow_links(true) .build() { let absolute = match absolute { diff --git a/src/source_distribution/pyproject.rs b/src/source_distribution/pyproject.rs index 0e0cb6fef..551a7d253 100644 --- a/src/source_distribution/pyproject.rs +++ b/src/source_distribution/pyproject.rs @@ -72,7 +72,7 @@ pub(super) fn add_python_sources( } for package in python_packages { - for entry in ignore::Walk::new(package) { + for entry in ignore::WalkBuilder::new(package).follow_links(true).build() { let source = entry?.into_path(); if is_compiled_artifact(&source) { debug!("Ignoring {}", source.display()); diff --git a/tests/run/wheel.rs b/tests/run/wheel.rs index 520b7a089..265a35353 100644 --- a/tests/run/wheel.rs +++ b/tests/run/wheel.rs @@ -1,4 +1,5 @@ use crate::common::{handle_result, other}; +use std::path::Path; #[test] #[cfg(feature = "sbom")] @@ -57,6 +58,62 @@ fn pyo3_mixed_py_subdir_include_wheel_files() { )) } +#[test] +#[cfg(unix)] +fn pyo3_mixed_py_subdir_includes_symlinked_python_files() { + use std::os::unix::fs::symlink; + + handle_result((|| { + let temp_dir = tempfile::tempdir()?; + let project_dir = temp_dir.path().join("pyo3-mixed-py-subdir"); + other::copy_dir_recursive(Path::new("test-crates/pyo3-mixed-py-subdir"), &project_dir)?; + + let external_sources = temp_dir.path().join("external-python"); + fs_err::create_dir_all(external_sources.join("linked_dir"))?; + fs_err::write(external_sources.join("linked_file.py"), "VALUE = 1\n")?; + fs_err::write( + external_sources.join("linked_dir").join("nested.py"), + "VALUE = 2\n", + )?; + + let package_dir = project_dir + .join("python") + .join("pyo3_mixed_py_subdir") + .join("python_module"); + symlink( + external_sources.join("linked_file.py"), + package_dir.join("linked_file.py"), + )?; + symlink( + external_sources.join("linked_dir"), + package_dir.join("linked_dir"), + )?; + + let mut expected = vec![ + "assets/extra_data.txt", + "pyo3_mixed_py_subdir-2.1.3.dist-info/METADATA", + "pyo3_mixed_py_subdir-2.1.3.dist-info/RECORD", + "pyo3_mixed_py_subdir-2.1.3.dist-info/WHEEL", + "pyo3_mixed_py_subdir-2.1.3.dist-info/entry_points.txt", + "pyo3_mixed_py_subdir/__init__.py", + "pyo3_mixed_py_subdir/python_module/__init__.py", + "pyo3_mixed_py_subdir/python_module/double.py", + "pyo3_mixed_py_subdir/python_module/linked_dir/nested.py", + "pyo3_mixed_py_subdir/python_module/linked_file.py", + ]; + #[cfg(feature = "sbom")] + expected + .push("pyo3_mixed_py_subdir-2.1.3.dist-info/sboms/pyo3-mixed-py-subdir.cyclonedx.json"); + + assert_eq!( + other::wheel_files(&project_dir, "wheel-files-pyo3-mixed-py-subdir-symlinks")?, + expected.into_iter().map(str::to_owned).collect() + ); + + Ok(()) + })()) +} + #[test] fn pyo3_wheel_record_has_normalized_paths() { handle_result(other::check_wheel_paths(