mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-17 02:52:45 +00:00
Load credentials for explicit members when lowering (#15844)
## Summary If the target for `uv pip compile` is a `pyproject.toml` in a subdirectory, we won't have loaded the credentials when we go to lower (since it won't be loaded as part of "configuration discovery"). We now add those indexes just-in-time. Closes https://github.com/astral-sh/uv/issues/15362.
This commit is contained in:
parent
43c187dd93
commit
ef17e7d0f4
4 changed files with 85 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -5624,6 +5624,7 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uv-auth",
|
||||||
"uv-cache",
|
"uv-cache",
|
||||||
"uv-cache-info",
|
"uv-cache-info",
|
||||||
"uv-client",
|
"uv-client",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
uv-auth = { workspace = true }
|
||||||
uv-cache = { workspace = true }
|
uv-cache = { workspace = true }
|
||||||
uv-cache-info = { workspace = true }
|
uv-cache-info = { workspace = true }
|
||||||
uv-client = { workspace = true }
|
uv-client = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -222,20 +223,20 @@ impl LoweredRequirement {
|
||||||
.find(|Index { name, .. }| {
|
.find(|Index { name, .. }| {
|
||||||
name.as_ref().is_some_and(|name| *name == index)
|
name.as_ref().is_some_and(|name| *name == index)
|
||||||
})
|
})
|
||||||
.map(
|
|
||||||
|Index {
|
|
||||||
url, format: kind, ..
|
|
||||||
}| IndexMetadata {
|
|
||||||
url: url.clone(),
|
|
||||||
format: *kind,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
else {
|
else {
|
||||||
return Err(LoweringError::MissingIndex(
|
return Err(LoweringError::MissingIndex(
|
||||||
requirement.name.clone(),
|
requirement.name.clone(),
|
||||||
index,
|
index,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
if let Some(credentials) = index.credentials() {
|
||||||
|
let credentials = Arc::new(credentials);
|
||||||
|
uv_auth::store_credentials(index.raw_url(), credentials);
|
||||||
|
}
|
||||||
|
let index = IndexMetadata {
|
||||||
|
url: index.url.clone(),
|
||||||
|
format: index.format,
|
||||||
|
};
|
||||||
let conflict = project_name.and_then(|project_name| {
|
let conflict = project_name.and_then(|project_name| {
|
||||||
if let Some(extra) = extra {
|
if let Some(extra) = extra {
|
||||||
Some(ConflictItem::from((project_name.clone(), extra)))
|
Some(ConflictItem::from((project_name.clone(), extra)))
|
||||||
|
|
@ -456,20 +457,20 @@ impl LoweredRequirement {
|
||||||
.find(|Index { name, .. }| {
|
.find(|Index { name, .. }| {
|
||||||
name.as_ref().is_some_and(|name| *name == index)
|
name.as_ref().is_some_and(|name| *name == index)
|
||||||
})
|
})
|
||||||
.map(
|
|
||||||
|Index {
|
|
||||||
url, format: kind, ..
|
|
||||||
}| IndexMetadata {
|
|
||||||
url: url.clone(),
|
|
||||||
format: *kind,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
else {
|
else {
|
||||||
return Err(LoweringError::MissingIndex(
|
return Err(LoweringError::MissingIndex(
|
||||||
requirement.name.clone(),
|
requirement.name.clone(),
|
||||||
index,
|
index,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
if let Some(credentials) = index.credentials() {
|
||||||
|
let credentials = Arc::new(credentials);
|
||||||
|
uv_auth::store_credentials(index.raw_url(), credentials);
|
||||||
|
}
|
||||||
|
let index = IndexMetadata {
|
||||||
|
url: index.url.clone(),
|
||||||
|
format: index.format,
|
||||||
|
};
|
||||||
let conflict = None;
|
let conflict = None;
|
||||||
let source = registry_source(&requirement, index, conflict);
|
let source = registry_source(&requirement, index, conflict);
|
||||||
(source, marker)
|
(source, marker)
|
||||||
|
|
|
||||||
|
|
@ -17784,3 +17784,69 @@ fn omit_python_patch_universal() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn credentials_from_subdirectory() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
// Create a local dependency in a subdirectory.
|
||||||
|
let pyproject_toml = context.temp_dir.child("foo").child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0.0"
|
||||||
|
dependencies = ["iniconfig"]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[tool.uv.sources]
|
||||||
|
iniconfig = { index = "internal" }
|
||||||
|
|
||||||
|
[[tool.uv.index]]
|
||||||
|
name = "internal"
|
||||||
|
url = "https://pypi-proxy.fly.dev/basic-auth/simple/"
|
||||||
|
explicit = true
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child("foo")
|
||||||
|
.child("src")
|
||||||
|
.child("foo")
|
||||||
|
.child("__init__.py")
|
||||||
|
.touch()?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context
|
||||||
|
.pip_compile()
|
||||||
|
.arg("foo/pyproject.toml"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because iniconfig was not found in the package registry and foo depends on iniconfig, we can conclude that your requirements are unsatisfiable.
|
||||||
|
");
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context
|
||||||
|
.pip_compile()
|
||||||
|
.arg("foo/pyproject.toml")
|
||||||
|
.env("UV_INDEX_INTERNAL_USERNAME", "public")
|
||||||
|
.env("UV_INDEX_INTERNAL_PASSWORD", "heron"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
# This file was autogenerated by uv via the following command:
|
||||||
|
# uv pip compile --cache-dir [CACHE_DIR] foo/pyproject.toml
|
||||||
|
iniconfig==2.0.0
|
||||||
|
# via foo (foo/pyproject.toml)
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue