diff --git a/crates/uv-install-wheel/src/wheel.rs b/crates/uv-install-wheel/src/wheel.rs index bc5a0caa6..4037567e2 100644 --- a/crates/uv-install-wheel/src/wheel.rs +++ b/crates/uv-install-wheel/src/wheel.rs @@ -373,7 +373,9 @@ pub(crate) fn move_folder_recorded( src.simplified_display() )) })?; - entry.path = relative_to(&target, site_packages)?.display().to_string(); + entry.path = relative_to(&target, site_packages)? + .portable_display() + .to_string(); } } Ok(()) @@ -576,7 +578,7 @@ fn install_script( })?; // Update the entry in the `RECORD`. - entry.path = script_relative.simplified_display().to_string(); + entry.path = script_relative.portable_display().to_string(); if let Some((size, encoded_hash)) = size_and_encoded_hash { entry.size = Some(size); entry.hash = Some(encoded_hash); diff --git a/crates/uv/tests/it/pip_install.rs b/crates/uv/tests/it/pip_install.rs index 06c58f9e5..58f2f6274 100644 --- a/crates/uv/tests/it/pip_install.rs +++ b/crates/uv/tests/it/pip_install.rs @@ -13660,3 +13660,65 @@ fn build_backend_wrong_wheel_platform() -> Result<()> { Ok(()) } + +/// Test that RECORD entries use forward slashes on all platforms. +/// +/// See . +#[test] +fn record_uses_forward_slashes() -> Result<()> { + let context = TestContext::new("3.12"); + + // Create a package with scripts via uv_build data directory. + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [project] + name = "project" + version = "0.1.0" + + [build-system] + requires = ["uv_build>=0.7,<10000"] + build-backend = "uv_build" + + [tool.uv.build-backend.data] + scripts = "scripts" + headers = "headers" + "#})?; + + let module_dir = context.temp_dir.child("src").child("project"); + module_dir.child("__init__.py").touch()?; + + // Create a script that uses the install_script path. + let scripts_dir = context.temp_dir.child("scripts"); + scripts_dir.child("my_script").write_str(indoc! {r#" + #!python + print("Hello from script") + "#})?; + + let scripts_dir = context.temp_dir.child("headers"); + scripts_dir.child("project.h").write_str(indoc! {r" + #include + "})?; + + context.pip_install().arg(".").assert().success(); + + // Read the RECORD file and check that all paths use forward slashes. + let record_path = context + .site_packages() + .join("project-0.1.0.dist-info") + .join("RECORD"); + + let record = fs::read_to_string(&record_path)?; + let record_lines: Vec<_> = record + .lines() + .filter(|line| !line.trim().is_empty()) + .collect(); + assert!(record_lines.iter().any(|line| line.contains("/my_script"))); + assert!(record_lines.iter().any(|line| line.contains("/project.h"))); + for line in record_lines { + // Each RECORD line is: path,hash,size + let path = line.split(',').next().unwrap(); + assert!(!path.contains('\\'), "{path}"); + } + + Ok(()) +} diff --git a/crates/uv/tests/it/tool_run.rs b/crates/uv/tests/it/tool_run.rs index 26bd5d636..9eb71af7d 100644 --- a/crates/uv/tests/it/tool_run.rs +++ b/crates/uv/tests/it/tool_run.rs @@ -3147,9 +3147,9 @@ fn tool_run_windows_runnable_types() -> anyhow::Result<()> { ----- stderr ----- An executable named `does_not_exist` is not provided by package `foo`. The following executables are available: - - custom_pydoc.exe - custom_pydoc.bat - custom_pydoc.cmd + - custom_pydoc.exe - custom_pydoc.ps1 "###);