Skip to content

Commit

Permalink
Use portable paths for subdirectories in lock URLs (#8707)
Browse files Browse the repository at this point in the history
## Summary

We're writing different URLs on Windows vs. Linux because the
subdirectory path is being serialized with a back vs. forward slash.
  • Loading branch information
charliermarsh authored Oct 30, 2024
1 parent 4a5a79e commit bed47d5
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 4 deletions.
10 changes: 8 additions & 2 deletions crates/uv-resolver/src/lock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3152,9 +3152,15 @@ fn locked_git_url(git_dist: &GitSourceDist) -> Url {
url.set_query(None);

// Put the subdirectory in the query.
if let Some(subdirectory) = git_dist.subdirectory.as_deref().and_then(Path::to_str) {
if let Some(subdirectory) = git_dist
.subdirectory
.as_deref()
.map(PortablePath::from)
.as_ref()
.map(PortablePath::to_string)
{
url.query_pairs_mut()
.append_pair("subdirectory", subdirectory);
.append_pair("subdirectory", &subdirectory);
}

// Put the requested reference in the query.
Expand Down
141 changes: 141 additions & 0 deletions crates/uv/tests/it/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17389,3 +17389,144 @@ fn lock_group_empty_entry_table() -> Result<()> {

Ok(())
}

#[test]
fn lock_transitive_git() -> Result<()> {
let context = TestContext::new("3.12");

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "a"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["c"]

[tool.uv.sources]
c = { git = "https://github.com/astral-sh/workspace-virtual-root-test", subdirectory = "packages/c", rev = "fac39c8d4c5d0ef32744e2bb309bbe34a759fd46" }
"#,
)?;

uv_snapshot!(context.filters(), context.lock(), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Resolved 6 packages in [TIME]
"###);

let lock = context.read("uv.lock");

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 = "a"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "c" },
]

[package.metadata]
requires-dist = [{ name = "c", git = "https://github.com/astral-sh/workspace-virtual-root-test?subdirectory=packages%2Fc&rev=fac39c8d4c5d0ef32744e2bb309bbe34a759fd46" }]

[[package]]
name = "anyio"
version = "4.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6", size = 159642 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", size = 85584 },
]

[[package]]
name = "c"
version = "1.0.0"
source = { git = "https://github.com/astral-sh/workspace-virtual-root-test?subdirectory=packages%2Fc&rev=fac39c8d4c5d0ef32744e2bb309bbe34a759fd46#fac39c8d4c5d0ef32744e2bb309bbe34a759fd46" }
dependencies = [
{ name = "d" },
]

[[package]]
name = "d"
version = "1.0.0"
source = { git = "https://github.com/astral-sh/workspace-virtual-root-test?subdirectory=packages%2Fd&rev=fac39c8d4c5d0ef32744e2bb309bbe34a759fd46#fac39c8d4c5d0ef32744e2bb309bbe34a759fd46" }
dependencies = [
{ name = "anyio" },
]

[[package]]
name = "idna"
version = "3.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", size = 175426 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567 },
]

[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
]
"###
);
});

// Re-run with `--locked`.
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Resolved 6 packages in [TIME]
"###);

// Re-run with `--offline`. We shouldn't need a network connection to validate an
// already-correct lockfile with immutable metadata.
uv_snapshot!(context.filters(), context.lock().arg("--locked").arg("--offline").arg("--no-cache"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Resolved 6 packages in [TIME]
"###);

// Install from the lockfile.
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Prepared 5 packages in [TIME]
Installed 5 packages in [TIME]
+ anyio==4.3.0
+ c==1.0.0 (from git+https://github.com/astral-sh/workspace-virtual-root-test@fac39c8d4c5d0ef32744e2bb309bbe34a759fd46#subdirectory=packages/c)
+ d==1.0.0 (from git+https://github.com/astral-sh/workspace-virtual-root-test@fac39c8d4c5d0ef32744e2bb309bbe34a759fd46#subdirectory=packages/d)
+ idna==3.6
+ sniffio==1.3.1
"###);

Ok(())
}
2 changes: 0 additions & 2 deletions crates/uv/tests/it/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,6 @@ fn test_path_hopping() -> Result<()> {
/// are correctly resolving `d` to a git dependency with a subdirectory and not relative to the
/// checkout directory.
#[test]
#[cfg(not(windows))]
fn transitive_dep_in_git_workspace_no_root() -> Result<()> {
let context = TestContext::new("3.12");

Expand All @@ -1789,7 +1788,6 @@ fn transitive_dep_in_git_workspace_no_root() -> Result<()> {
let lock1: SourceLock =
toml::from_str(&fs_err::read_to_string(context.temp_dir.child("uv.lock"))?)?;

// TODO(charlie): Fails on Windows due to non-portable subdirectory path in URL.
assert_json_snapshot!(lock1.sources(), @r###"
{
"a": {
Expand Down

0 comments on commit bed47d5

Please sign in to comment.