Don't error on multiple matching index URLs (#2627)

## Summary

Closes Issue:
- https://github.com/astral-sh/uv/issues/2626

## Test Plan

```
cargo run -- pip install -r dev-requirements.txt -r requirements.txt
```
where both requirements files have same `--index-url`
This commit is contained in:
Hans Baker 2024-03-22 16:37:02 -07:00 committed by GitHub
parent d0cb301d59
commit a632d2485b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 57 additions and 19 deletions

1
Cargo.lock generated
View file

@ -4733,6 +4733,7 @@ name = "uv-requirements"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cache-key",
"configparser", "configparser",
"console", "console",
"ctrlc", "ctrlc",

View file

@ -28,7 +28,7 @@ pub enum IndexUrl {
impl IndexUrl { impl IndexUrl {
/// Return the raw URL for the index. /// Return the raw URL for the index.
pub(crate) fn url(&self) -> &Url { pub fn url(&self) -> &Url {
match self { match self {
Self::Pypi(url) => url.raw(), Self::Pypi(url) => url.raw(),
Self::Url(url) => url.raw(), Self::Url(url) => url.raw(),

View file

@ -10,6 +10,7 @@ authors.workspace = true
license.workspace = true license.workspace = true
[dependencies] [dependencies]
cache-key = { workspace = true }
distribution-filename = { workspace = true } distribution-filename = { workspace = true }
distribution-types = { workspace = true } distribution-types = { workspace = true }
pep508_rs = { workspace = true } pep508_rs = { workspace = true }

View file

@ -5,7 +5,7 @@ use indexmap::IndexMap;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use tracing::{instrument, Level}; use tracing::{instrument, Level};
use crate::{ExtrasSpecification, RequirementsSource}; use cache_key::CanonicalUrl;
use distribution_types::{FlatIndexLocation, IndexUrl}; use distribution_types::{FlatIndexLocation, IndexUrl};
use pep508_rs::{Requirement, RequirementsTxtRequirement}; use pep508_rs::{Requirement, RequirementsTxtRequirement};
use requirements_txt::{EditableRequirement, FindLink, RequirementsTxt}; use requirements_txt::{EditableRequirement, FindLink, RequirementsTxt};
@ -14,6 +14,8 @@ use uv_fs::Simplified;
use uv_normalize::{ExtraName, PackageName}; use uv_normalize::{ExtraName, PackageName};
use uv_warnings::warn_user; use uv_warnings::warn_user;
use crate::{ExtrasSpecification, RequirementsSource};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct RequirementsSpecification { pub struct RequirementsSpecification {
/// The name of the project specifying requirements. /// The name of the project specifying requirements.
@ -205,13 +207,15 @@ impl RequirementsSpecification {
spec.project = source.project; spec.project = source.project;
} }
if let Some(url) = source.index_url { if let Some(index_url) = source.index_url {
if let Some(existing) = spec.index_url { if let Some(existing) = spec.index_url {
if CanonicalUrl::new(index_url.url()) != CanonicalUrl::new(existing.url()) {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(
"Multiple index URLs specified: `{existing}` vs.` {url}", "Multiple index URLs specified: `{existing}` vs. `{index_url}`",
)); ));
} }
spec.index_url = Some(url); }
spec.index_url = Some(index_url);
} }
spec.no_index |= source.no_index; spec.no_index |= source.no_index;
spec.extra_index_urls.extend(source.extra_index_urls); spec.extra_index_urls.extend(source.extra_index_urls);
@ -236,13 +240,15 @@ impl RequirementsSpecification {
spec.constraints.extend(source.constraints); spec.constraints.extend(source.constraints);
spec.constraints.extend(source.overrides); spec.constraints.extend(source.overrides);
if let Some(url) = source.index_url { if let Some(index_url) = source.index_url {
if let Some(existing) = spec.index_url { if let Some(existing) = spec.index_url {
if CanonicalUrl::new(index_url.url()) != CanonicalUrl::new(existing.url()) {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(
"Multiple index URLs specified: `{existing}` vs.` {url}", "Multiple index URLs specified: `{existing}` vs. `{index_url}`",
)); ));
} }
spec.index_url = Some(url); }
spec.index_url = Some(index_url);
} }
spec.no_index |= source.no_index; spec.no_index |= source.no_index;
spec.extra_index_urls.extend(source.extra_index_urls); spec.extra_index_urls.extend(source.extra_index_urls);
@ -267,13 +273,15 @@ impl RequirementsSpecification {
spec.overrides.extend(source.constraints); spec.overrides.extend(source.constraints);
spec.overrides.extend(source.overrides); spec.overrides.extend(source.overrides);
if let Some(url) = source.index_url { if let Some(index_url) = source.index_url {
if let Some(existing) = spec.index_url { if let Some(existing) = spec.index_url {
if CanonicalUrl::new(index_url.url()) != CanonicalUrl::new(existing.url()) {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(
"Multiple index URLs specified: `{existing}` vs.` {url}", "Multiple index URLs specified: `{existing}` vs. `{index_url}`",
)); ));
} }
spec.index_url = Some(url); }
spec.index_url = Some(index_url);
} }
spec.no_index |= source.no_index; spec.no_index |= source.no_index;
spec.extra_index_urls.extend(source.extra_index_urls); spec.extra_index_urls.extend(source.extra_index_urls);

View file

@ -3812,7 +3812,7 @@ fn index_url_requirements_txt() -> Result<()> {
Ok(()) Ok(())
} }
/// Raise an error when multiple `requirements.txt` files include `--index-url` flags. /// Raise an error when multiple `requirements.txt` files include different `--index-url` flags.
#[test] #[test]
fn conflicting_index_urls_requirements_txt() -> Result<()> { fn conflicting_index_urls_requirements_txt() -> Result<()> {
let context = TestContext::new("3.12"); let context = TestContext::new("3.12");
@ -3831,7 +3831,35 @@ fn conflicting_index_urls_requirements_txt() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
error: Multiple index URLs specified: `https://google.com/` vs.` https://wikipedia.org/ error: Multiple index URLs specified: `https://google.com/` vs. `https://wikipedia.org/`
"###
);
Ok(())
}
/// Doesn't raise an error when multiple `requirements.txt` files include matching `--index-url` flags.
#[test]
fn matching_index_urls_requirements_txt() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_in = context.temp_dir.child("requirements.in");
requirements_in.write_str("--index-url https://pypi.org/simple")?;
let constraints_in = context.temp_dir.child("constraints.in");
constraints_in.write_str("--index-url https://pypi.org/simple")?;
uv_snapshot!(context.compile()
.arg("requirements.in")
.arg("--constraint")
.arg("constraints.in"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2023-11-18T12:00:00Z requirements.in --constraint constraints.in
----- stderr -----
Resolved 0 packages in [TIME]
"### "###
); );