Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions crates/uv-distribution-types/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,19 @@ impl Index {
/// For indexes with a `/simple` endpoint, this is simply the URL with the final segment
/// removed. This is useful, e.g., for credential propagation to other endpoints on the index.
pub fn root_url(&self) -> Option<Url> {
let segments = self.raw_url().path_segments()?;
let last = segments.last()?;
let mut segments = self.raw_url().path_segments()?;
let last = match segments.next_back()? {
// If the last segment is empty due to a trailing `/`, skip it (as in `pop_if_empty`)
"" => segments.next_back()?,
segment => segment,
};

if !last.eq_ignore_ascii_case("simple") {
return None;
}

let mut url = self.raw_url().clone();
url.path_segments_mut().ok()?.pop();
url.path_segments_mut().ok()?.pop_if_empty().pop();
Some(url)
}

Expand Down
46 changes: 46 additions & 0 deletions crates/uv/tests/it/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8358,6 +8358,52 @@ fn lock_multiple_indexes_same_realm_different_credentials() -> Result<()> {
Ok(())
}

// Same as [`lock_multiple_indexes_same_realm_different_credentials`], but with trailing slashes
// on the index URL
#[test]
fn lock_multiple_indexes_same_realm_different_credentials_trailing_slash() -> Result<()> {
let context = TestContext::new("3.12");

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

[tool.uv.sources]
iniconfig = { index = "internal-proxy-heron" }
anyio = { index = "internal-proxy-eagle" }

[[tool.uv.index]]
name = "internal-proxy-heron"
url = "https://pypi-proxy.fly.dev/basic-auth-heron/simple/"

[[tool.uv.index]]
name = "internal-proxy-eagle"
url = "https://pypi-proxy.fly.dev/basic-auth-eagle/simple/"
"#,
)?;

// Provide credentials via environment variables.
uv_snapshot!(context.filters(), context.lock()
.env(EnvVars::index_username("INTERNAL_PROXY_HERON"), "public")
.env(EnvVars::index_password("INTERNAL_PROXY_HERON"), "heron")
.env(EnvVars::index_username("INTERNAL_PROXY_EAGLE"), "public")
.env(EnvVars::index_password("INTERNAL_PROXY_EAGLE"), "eagle"), @r###"
success: true
exit_code: 0
----- stdout -----

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

Ok(())
}

/// Resolve against an index that uses relative links.
#[test]
fn lock_relative_index() -> Result<()> {
Expand Down
Loading