diff --git a/crates/distribution-types/src/index.rs b/crates/distribution-types/src/index.rs index 4ffafebcc4de..4b7e0bcc75b5 100644 --- a/crates/distribution-types/src/index.rs +++ b/crates/distribution-types/src/index.rs @@ -94,6 +94,16 @@ impl Index { } } + /// Initialize an [`Index`] from a pip-style `--find-links`. + pub fn from_find_links(url: IndexUrl) -> Self { + Self { + url, + name: None, + explicit: false, + default: false, + } + } + /// Return the [`IndexUrl`] of the index. pub fn url(&self) -> &IndexUrl { &self.url diff --git a/crates/distribution-types/src/index_url.rs b/crates/distribution-types/src/index_url.rs index d8c4413da3c5..86a5f650fb21 100644 --- a/crates/distribution-types/src/index_url.rs +++ b/crates/distribution-types/src/index_url.rs @@ -99,15 +99,6 @@ impl Verbatim for IndexUrl { } } -impl From for IndexUrl { - fn from(location: FlatIndexLocation) -> Self { - match location { - FlatIndexLocation::Path(url) => Self::Path(url), - FlatIndexLocation::Url(url) => Self::Url(url), - } - } -} - /// An error that can occur when parsing an [`IndexUrl`]. #[derive(Error, Debug)] pub enum IndexUrlError { @@ -185,117 +176,6 @@ impl Deref for IndexUrl { } } -/// A directory with distributions or a URL to an HTML file with a flat listing of distributions. -/// -/// Also known as `--find-links`. -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub enum FlatIndexLocation { - Path(VerbatimUrl), - Url(VerbatimUrl), -} - -#[cfg(feature = "schemars")] -impl schemars::JsonSchema for FlatIndexLocation { - fn schema_name() -> String { - "FlatIndexLocation".to_string() - } - - fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { - schemars::schema::SchemaObject { - instance_type: Some(schemars::schema::InstanceType::String.into()), - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some("The path to a directory of distributions, or a URL to an HTML file with a flat listing of distributions.".to_string()), - ..schemars::schema::Metadata::default() - })), - ..schemars::schema::SchemaObject::default() - } - .into() - } -} - -impl FlatIndexLocation { - /// Return the raw URL for the `--find-links` index. - pub fn url(&self) -> &Url { - match self { - Self::Url(url) => url.raw(), - Self::Path(url) => url.raw(), - } - } - - /// Return the redacted URL for the `--find-links` index, omitting any sensitive credentials. - pub fn redacted(&self) -> Cow<'_, Url> { - let url = self.url(); - if url.username().is_empty() && url.password().is_none() { - Cow::Borrowed(url) - } else { - let mut url = url.clone(); - let _ = url.set_username(""); - let _ = url.set_password(None); - Cow::Owned(url) - } - } -} - -impl Display for FlatIndexLocation { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::Url(url) => Display::fmt(url, f), - Self::Path(url) => Display::fmt(url, f), - } - } -} - -impl Verbatim for FlatIndexLocation { - fn verbatim(&self) -> Cow<'_, str> { - match self { - Self::Url(url) => url.verbatim(), - Self::Path(url) => url.verbatim(), - } - } -} - -impl FromStr for FlatIndexLocation { - type Err = IndexUrlError; - - fn from_str(s: &str) -> Result { - let url = if Path::new(s).exists() { - VerbatimUrl::from_absolute_path(std::path::absolute(s)?)? - } else { - VerbatimUrl::parse_url(s)? - }; - Ok(Self::from(url.with_given(s))) - } -} - -impl serde::ser::Serialize for FlatIndexLocation { - fn serialize(&self, serializer: S) -> Result - where - S: serde::ser::Serializer, - { - self.to_string().serialize(serializer) - } -} - -impl<'de> serde::de::Deserialize<'de> for FlatIndexLocation { - fn deserialize(deserializer: D) -> Result - where - D: serde::de::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - FlatIndexLocation::from_str(&s).map_err(serde::de::Error::custom) - } -} - -impl From for FlatIndexLocation { - fn from(url: VerbatimUrl) -> Self { - if url.scheme() == "file" { - Self::Path(url) - } else { - Self::Url(url) - } - } -} - /// The index locations to use for fetching packages. By default, uses the PyPI index. /// /// From a pip perspective, this type merges `--index-url`, `--extra-index-url`, and `--find-links`, @@ -304,13 +184,13 @@ impl From for FlatIndexLocation { #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct IndexLocations { indexes: Vec, - flat_index: Vec, + flat_index: Vec, no_index: bool, } impl IndexLocations { /// Determine the index URLs to use for fetching packages. - pub fn new(indexes: Vec, flat_index: Vec, no_index: bool) -> Self { + pub fn new(indexes: Vec, flat_index: Vec, no_index: bool) -> Self { Self { indexes, flat_index, @@ -325,12 +205,7 @@ impl IndexLocations { /// /// If the current index location has an `index` set, it will be preserved. #[must_use] - pub fn combine( - self, - indexes: Vec, - flat_index: Vec, - no_index: bool, - ) -> Self { + pub fn combine(self, indexes: Vec, flat_index: Vec, no_index: bool) -> Self { Self { indexes: self.indexes.into_iter().chain(indexes).collect(), flat_index: self.flat_index.into_iter().chain(flat_index).collect(), @@ -407,7 +282,7 @@ impl<'a> IndexLocations { } /// Return an iterator over the [`FlatIndexLocation`] entries. - pub fn flat_indexes(&'a self) -> impl Iterator + 'a { + pub fn flat_indexes(&'a self) -> impl Iterator + 'a { self.flat_index.iter() } @@ -426,13 +301,12 @@ impl<'a> IndexLocations { /// Return an iterator over all allowed [`Index`] entries. /// - /// This includes both explicit and implicit indexes, as well as the default index (but _not_ - /// the flat indexes). + /// This includes explicit indexes, implicit indexes flat indexes, and the default index. /// - /// If `no_index` was enabled, then this always returns an empty - /// iterator. + /// If `no_index` was enabled, then this always returns an empty iterator. pub fn allowed_indexes(&'a self) -> impl Iterator + 'a { - self.explicit_indexes() + self.flat_indexes() + .chain(self.explicit_indexes()) .chain(self.implicit_indexes()) .chain(self.default_index()) } diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index e581df7aab1e..d9542e131c1f 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -7,7 +7,7 @@ use anyhow::{anyhow, Result}; use clap::builder::styling::{AnsiColor, Effects, Style}; use clap::builder::Styles; use clap::{Args, Parser, Subcommand}; -use distribution_types::{FlatIndexLocation, Index, IndexUrl}; +use distribution_types::{Index, IndexUrl}; use pep508_rs::Requirement; use pypi_types::VerbatimParsedUrl; use url::Url; @@ -3777,7 +3777,7 @@ pub struct IndexArgs { /// If a URL, the page must contain a flat list of links to package files adhering to the /// formats described above. #[arg(long, short, help_heading = "Index options")] - pub find_links: Option>, + pub find_links: Option>, /// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those /// provided via `--find-links`. diff --git a/crates/uv-client/src/flat_index.rs b/crates/uv-client/src/flat_index.rs index 04e1c5243186..2c1e49465041 100644 --- a/crates/uv-client/src/flat_index.rs +++ b/crates/uv-client/src/flat_index.rs @@ -6,7 +6,7 @@ use tracing::{debug, info_span, warn, Instrument}; use url::Url; use distribution_filename::DistFilename; -use distribution_types::{File, FileLocation, FlatIndexLocation, IndexUrl, UrlString}; +use distribution_types::{File, FileLocation, IndexUrl, UrlString}; use uv_cache::{Cache, CacheBucket}; use crate::cached_client::{CacheControl, CachedClientError}; @@ -94,19 +94,19 @@ impl<'a> FlatIndexClient<'a> { #[allow(clippy::result_large_err)] pub async fn fetch( &self, - indexes: impl Iterator, + indexes: impl Iterator, ) -> Result { let mut fetches = futures::stream::iter(indexes) .map(|index| async move { let entries = match index { - FlatIndexLocation::Path(url) => { + IndexUrl::Path(url) => { let path = url .to_file_path() .map_err(|()| FlatIndexError::NonFileUrl(url.to_url()))?; Self::read_from_directory(&path, index) .map_err(|err| FlatIndexError::FindLinksDirectory(path.clone(), err))? } - FlatIndexLocation::Url(url) => self + IndexUrl::Pypi(url) | IndexUrl::Url(url) => self .read_from_url(url, index) .await .map_err(|err| FlatIndexError::FindLinksUrl(url.to_url(), err))?, @@ -136,7 +136,7 @@ impl<'a> FlatIndexClient<'a> { async fn read_from_url( &self, url: &Url, - flat_index: &FlatIndexLocation, + flat_index: &IndexUrl, ) -> Result { let cache_entry = self.cache.entry( CacheBucket::FlatIndex, @@ -210,7 +210,7 @@ impl<'a> FlatIndexClient<'a> { Some(( DistFilename::try_from_normalized_filename(&file.filename)?, file, - IndexUrl::from(flat_index.clone()), + flat_index.clone(), )) }) .collect(); @@ -226,7 +226,7 @@ impl<'a> FlatIndexClient<'a> { /// Read a flat remote index from a `--find-links` directory. fn read_from_directory( path: &Path, - flat_index: &FlatIndexLocation, + flat_index: &IndexUrl, ) -> Result { let mut dists = Vec::new(); for entry in fs_err::read_dir(path)? { @@ -279,7 +279,7 @@ impl<'a> FlatIndexClient<'a> { ); continue; }; - dists.push((filename, file, IndexUrl::from(flat_index.clone()))); + dists.push((filename, file, flat_index.clone())); } Ok(FlatIndexEntries::from_entries(dists)) } diff --git a/crates/uv-distribution/src/index/registry_wheel_index.rs b/crates/uv-distribution/src/index/registry_wheel_index.rs index e395ab8ec4fb..9cc74bcd2e20 100644 --- a/crates/uv-distribution/src/index/registry_wheel_index.rs +++ b/crates/uv-distribution/src/index/registry_wheel_index.rs @@ -87,16 +87,7 @@ impl<'a> RegistryWheelIndex<'a> { ) -> IndexMap> { let mut map = IndexMap::new(); - // Collect into owned `IndexUrl`. - let flat_index_urls: Vec = index_locations - .flat_indexes() - .map(|flat_index| Index::from_extra_index_url(IndexUrl::from(flat_index.clone()))) - .collect(); - - for index in index_locations - .allowed_indexes() - .chain(flat_index_urls.iter()) - { + for index in index_locations.allowed_indexes() { let mut versions = BTreeMap::new(); // Index all the wheels that were downloaded directly from the registry. diff --git a/crates/uv-requirements/src/specification.rs b/crates/uv-requirements/src/specification.rs index d1943e5e1ab1..6e8cc756340a 100644 --- a/crates/uv-requirements/src/specification.rs +++ b/crates/uv-requirements/src/specification.rs @@ -35,7 +35,7 @@ use tracing::instrument; use cache_key::CanonicalUrl; use distribution_types::{ - FlatIndexLocation, IndexUrl, NameRequirementSpecification, UnresolvedRequirement, + IndexUrl, NameRequirementSpecification, UnresolvedRequirement, UnresolvedRequirementSpecification, }; use pep508_rs::{MarkerTree, UnnamedRequirement, UnnamedRequirementUrl}; @@ -71,7 +71,7 @@ pub struct RequirementsSpecification { /// Whether to disallow index usage. pub no_index: bool, /// The `--find-links` locations to use for fetching packages. - pub find_links: Vec, + pub find_links: Vec, /// The `--no-binary` flags to enforce when selecting distributions. pub no_binary: NoBinary, /// The `--no-build` flags to enforce when selecting distributions. @@ -142,7 +142,7 @@ impl RequirementsSpecification { find_links: requirements_txt .find_links .into_iter() - .map(FlatIndexLocation::from) + .map(IndexUrl::from) .collect(), no_binary: requirements_txt.no_binary, no_build: requirements_txt.only_binary, diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index ac9717cc6ef8..826bfab793c4 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -18,10 +18,9 @@ use cache_key::RepositoryUrl; use distribution_filename::{DistExtension, ExtensionError, SourceDistExtension, WheelFilename}; use distribution_types::{ BuiltDist, DependencyMetadata, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist, - Dist, DistributionMetadata, FileLocation, FlatIndexLocation, GitSourceDist, HashPolicy, - IndexLocations, IndexUrl, Name, PathBuiltDist, PathSourceDist, RegistryBuiltDist, - RegistryBuiltWheel, RegistrySourceDist, RemoteSource, Resolution, ResolvedDist, StaticMetadata, - ToUrlError, UrlString, + Dist, DistributionMetadata, FileLocation, GitSourceDist, HashPolicy, IndexLocations, IndexUrl, + Name, PathBuiltDist, PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, + RemoteSource, Resolution, ResolvedDist, StaticMetadata, ToUrlError, UrlString, }; use pep440_rs::Version; use pep508_rs::{split_scheme, MarkerEnvironment, MarkerTree, VerbatimUrl, VerbatimUrlError}; @@ -1053,16 +1052,6 @@ impl Lock { } IndexUrl::Path(_) => None, }) - .chain( - locations - .flat_indexes() - .filter_map(|index_url| match index_url { - FlatIndexLocation::Url(_) => { - Some(UrlString::from(index_url.redacted())) - } - FlatIndexLocation::Path(_) => None, - }), - ) .collect::>() }); @@ -1079,20 +1068,6 @@ impl Lock { Some(path) } }) - .chain( - locations - .flat_indexes() - .filter_map(|index_url| match index_url { - FlatIndexLocation::Url(_) => None, - FlatIndexLocation::Path(index_url) => { - let path = index_url.to_file_path().ok()?; - let path = relative_to(&path, workspace.install_path()) - .or_else(|_| std::path::absolute(path)) - .ok()?; - Some(path) - } - }), - ) .collect::>() }); diff --git a/crates/uv-settings/src/settings.rs b/crates/uv-settings/src/settings.rs index 2881b840f3ac..5e6fec30e2f7 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -1,6 +1,6 @@ use std::{fmt::Debug, num::NonZeroUsize, path::PathBuf}; -use distribution_types::{FlatIndexLocation, Index, IndexUrl, StaticMetadata}; +use distribution_types::{Index, IndexUrl, StaticMetadata}; use install_wheel_rs::linker::LinkMode; use pep508_rs::Requirement; use pypi_types::{SupportedEnvironments, VerbatimParsedUrl}; @@ -238,7 +238,7 @@ pub struct InstallerOptions { pub index_url: Option, pub extra_index_url: Option>, pub no_index: Option, - pub find_links: Option>, + pub find_links: Option>, pub index_strategy: Option, pub keyring_provider: Option, pub allow_insecure_host: Option>, @@ -266,7 +266,7 @@ pub struct ResolverOptions { pub index_url: Option, pub extra_index_url: Option>, pub no_index: Option, - pub find_links: Option>, + pub find_links: Option>, pub index_strategy: Option, pub keyring_provider: Option, pub allow_insecure_host: Option>, @@ -393,7 +393,7 @@ pub struct ResolverInstallerOptions { find-links = ["https://download.pytorch.org/whl/torch_stable.html"] "# )] - pub find_links: Option>, + pub find_links: Option>, /// The strategy to use when resolving against multiple index URLs. /// /// By default, uv will stop at the first index on which a given package is available, and @@ -832,7 +832,7 @@ pub struct PipOptions { find-links = ["https://download.pytorch.org/whl/torch_stable.html"] "# )] - pub find_links: Option>, + pub find_links: Option>, /// The strategy to use when resolving against multiple index URLs. /// /// By default, uv will stop at the first index on which a given package is available, and @@ -1448,7 +1448,7 @@ pub struct ToolOptions { pub index_url: Option, pub extra_index_url: Option>, pub no_index: Option, - pub find_links: Option>, + pub find_links: Option>, pub index_strategy: Option, pub keyring_provider: Option, pub allow_insecure_host: Option>, @@ -1554,7 +1554,7 @@ pub struct OptionsWire { index_url: Option, extra_index_url: Option>, no_index: Option, - find_links: Option>, + find_links: Option>, index_strategy: Option, keyring_provider: Option, allow_insecure_host: Option>, diff --git a/crates/uv/src/commands/build.rs b/crates/uv/src/commands/build.rs index ddb0cbc03548..c05592fa4f6f 100644 --- a/crates/uv/src/commands/build.rs +++ b/crates/uv/src/commands/build.rs @@ -4,11 +4,11 @@ use std::path::{Path, PathBuf}; use anyhow::Result; use distribution_filename::SourceDistExtension; -use distribution_types::{DependencyMetadata, IndexLocations}; +use distribution_types::{DependencyMetadata, Index, IndexLocations}; use install_wheel_rs::linker::LinkMode; use owo_colors::OwoColorize; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -396,9 +396,6 @@ async fn build_package( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Read build constraints. let build_constraints = operations::read_constraints(build_constraints, client_builder).await?; @@ -450,7 +447,9 @@ async fn build_package( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, None, &hasher, build_options) }; diff --git a/crates/uv/src/commands/pip/compile.rs b/crates/uv/src/commands/pip/compile.rs index b457d6b35b83..b458aed33fa3 100644 --- a/crates/uv/src/commands/pip/compile.rs +++ b/crates/uv/src/commands/pip/compile.rs @@ -13,7 +13,7 @@ use distribution_types::{ }; use install_wheel_rs::linker::LinkMode; use pypi_types::{Requirement, SupportedEnvironments}; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -280,7 +280,7 @@ pub(crate) async fn pip_compile( .map(Index::from_extra_index_url) .chain(index_url.map(Index::from_index_url)) .collect(), - find_links, + find_links.into_iter().map(Index::from_find_links).collect(), no_index, ); @@ -290,9 +290,6 @@ pub(crate) async fn pip_compile( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -314,7 +311,9 @@ pub(crate) async fn pip_compile( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, &cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, tags.as_deref(), &hasher, &build_options) }; @@ -465,7 +464,7 @@ pub(crate) async fn pip_compile( // If necessary, include the `--find-links` locations. if include_find_links { for flat_index in index_locations.flat_indexes() { - writeln!(writer, "--find-links {}", flat_index.verbatim())?; + writeln!(writer, "--find-links {}", flat_index.url().verbatim())?; wrote_preamble = true; } } diff --git a/crates/uv/src/commands/pip/install.rs b/crates/uv/src/commands/pip/install.rs index 81dfc09a2e2c..dbedd629880b 100644 --- a/crates/uv/src/commands/pip/install.rs +++ b/crates/uv/src/commands/pip/install.rs @@ -12,7 +12,7 @@ use distribution_types::{ use install_wheel_rs::linker::LinkMode; use pep508_rs::PackageName; use pypi_types::Requirement; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -278,7 +278,7 @@ pub(crate) async fn pip_install( .map(Index::from_extra_index_url) .chain(index_url.map(Index::from_index_url)) .collect(), - find_links, + find_links.into_iter().map(Index::from_find_links).collect(), no_index, ); @@ -288,9 +288,6 @@ pub(crate) async fn pip_install( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -307,7 +304,9 @@ pub(crate) async fn pip_install( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, &cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options) }; diff --git a/crates/uv/src/commands/pip/sync.rs b/crates/uv/src/commands/pip/sync.rs index 54a1067c9c31..33267323b2b6 100644 --- a/crates/uv/src/commands/pip/sync.rs +++ b/crates/uv/src/commands/pip/sync.rs @@ -8,7 +8,7 @@ use tracing::debug; use distribution_types::{DependencyMetadata, Index, IndexLocations, Resolution}; use install_wheel_rs::linker::LinkMode; use pep508_rs::PackageName; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -221,7 +221,7 @@ pub(crate) async fn pip_sync( .map(Index::from_extra_index_url) .chain(index_url.map(Index::from_index_url)) .collect(), - find_links, + find_links.into_iter().map(Index::from_find_links).collect(), no_index, ); @@ -231,9 +231,6 @@ pub(crate) async fn pip_sync( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -250,7 +247,9 @@ pub(crate) async fn pip_sync( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, &cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options) }; diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index 9789fa1b7fa7..b335e35fd219 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -12,7 +12,7 @@ use cache_key::RepositoryUrl; use distribution_types::{Index, UnresolvedRequirement}; use pep508_rs::{ExtraName, Requirement, UnnamedRequirement, VersionOrUrl}; use pypi_types::{redact_git_credentials, ParsedUrl, RequirementSource, VerbatimParsedUrl}; -use uv_auth::{store_credentials, store_credentials_from_url, Credentials}; +use uv_auth::{store_credentials, Credentials}; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -248,9 +248,6 @@ pub(crate) async fn add( store_credentials(index.raw_url(), credentials); } } - for index in settings.index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -279,7 +276,7 @@ pub(crate) async fn add( let flat_index = { let client = FlatIndexClient::new(&client, cache); let entries = client - .fetch(settings.index_locations.flat_indexes()) + .fetch(settings.index_locations.flat_indexes().map(Index::url)) .await?; FlatIndex::from_entries(entries, Some(&tags), &hasher, &settings.build_options) }; diff --git a/crates/uv/src/commands/project/lock.rs b/crates/uv/src/commands/project/lock.rs index 5fff6cac084c..9d2ba6344bae 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -9,12 +9,12 @@ use std::path::Path; use tracing::debug; use distribution_types::{ - DependencyMetadata, IndexLocations, NameRequirementSpecification, + DependencyMetadata, Index, IndexLocations, NameRequirementSpecification, UnresolvedRequirementSpecification, }; use pep440_rs::Version; use pypi_types::{Requirement, SupportedEnvironments}; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -359,9 +359,6 @@ async fn do_lock( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -404,7 +401,9 @@ async fn do_lock( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, None, &hasher, build_options) }; diff --git a/crates/uv/src/commands/project/mod.rs b/crates/uv/src/commands/project/mod.rs index cd2e6c97bc65..f854824f1e5a 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -11,7 +11,7 @@ use distribution_types::{ use pep440_rs::{Version, VersionSpecifiers}; use pep508_rs::MarkerTreeContents; use pypi_types::Requirement; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{Concurrency, Constraints, ExtrasSpecification, Reinstall, Upgrade}; @@ -631,9 +631,6 @@ pub(crate) async fn resolve_names( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -784,9 +781,6 @@ pub(crate) async fn resolve_environment<'a>( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -847,7 +841,9 @@ pub(crate) async fn resolve_environment<'a>( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, Some(tags), &hasher, build_options) }; @@ -948,9 +944,6 @@ pub(crate) async fn sync_environment( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -983,7 +976,9 @@ pub(crate) async fn sync_environment( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, Some(tags), &hasher, build_options) }; @@ -1142,9 +1137,6 @@ pub(crate) async fn update_environment( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -1191,7 +1183,9 @@ pub(crate) async fn update_environment( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, Some(tags), &hasher, build_options) }; @@ -1371,7 +1365,11 @@ fn warn_on_requirements_txt_setting( } } for find_link in find_links { - if !settings.index_locations.flat_indexes().contains(find_link) { + if !settings + .index_locations + .flat_indexes() + .any(|index| index.url() == find_link) + { warn_user_once!( "Ignoring `--find-links` from requirements file: `{find_link}`. Instead, use the `--find-links` command-line argument, or set `find-links` in a `uv.toml` or `pyproject.toml` file.`" ); diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index ad4c336c7de4..ce696f2091f7 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -6,7 +6,7 @@ use crate::commands::{pip, project, ExitStatus}; use crate::printer::Printer; use crate::settings::{InstallerSettingsRef, ResolverInstallerSettings}; use anyhow::{Context, Result}; -use distribution_types::{DirectorySourceDist, Dist, ResolvedDist, SourceDist}; +use distribution_types::{DirectorySourceDist, Dist, Index, ResolvedDist, SourceDist}; use itertools::Itertools; use pep508_rs::{MarkerTree, Requirement, VersionOrUrl}; use pypi_types::{ @@ -15,7 +15,7 @@ use pypi_types::{ use std::borrow::Cow; use std::path::Path; use std::str::FromStr; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -260,9 +260,6 @@ pub(super) async fn do_sync( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Populate credentials from the workspace. store_credentials_from_workspace(target.workspace()); @@ -300,7 +297,9 @@ pub(super) async fn do_sync( // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, cache); - let entries = client.fetch(index_locations.flat_indexes()).await?; + let entries = client + .fetch(index_locations.flat_indexes().map(Index::url)) + .await?; FlatIndex::from_entries(entries, Some(tags), &hasher, build_options) }; diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index 2df6f886376e..a3b8a40c5018 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -9,10 +9,10 @@ use miette::{Diagnostic, IntoDiagnostic}; use owo_colors::OwoColorize; use thiserror::Error; -use distribution_types::{DependencyMetadata, IndexLocations}; +use distribution_types::{DependencyMetadata, Index, IndexLocations}; use install_wheel_rs::linker::LinkMode; use pypi_types::Requirement; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -231,9 +231,6 @@ async fn venv_impl( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } if managed { writeln!( @@ -285,9 +282,6 @@ async fn venv_impl( store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - store_credentials_from_url(index.url()); - } // Instantiate a client. let client = RegistryClientBuilder::try_from(client_builder) @@ -306,7 +300,7 @@ async fn venv_impl( let tags = interpreter.tags().map_err(VenvError::Tags)?; let client = FlatIndexClient::new(&client, cache); let entries = client - .fetch(index_locations.flat_indexes()) + .fetch(index_locations.flat_indexes().map(Index::url)) .await .map_err(VenvError::FlatIndex)?; FlatIndex::from_entries( diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 6294b7576d14..674b682dff72 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -1959,7 +1959,12 @@ impl From for ResolverSettings { ) .chain(value.index_url.into_iter().map(Index::from_index_url)) .collect(), - value.find_links.unwrap_or_default(), + value + .find_links + .into_iter() + .flatten() + .map(Index::from_find_links) + .collect(), value.no_index.unwrap_or_default(), ), resolution: value.resolution.unwrap_or_default(), @@ -2097,7 +2102,12 @@ impl From for ResolverInstallerSettings { ) .chain(value.index_url.into_iter().map(Index::from_index_url)) .collect(), - value.find_links.unwrap_or_default(), + value + .find_links + .into_iter() + .flatten() + .map(Index::from_find_links) + .collect(), value.no_index.unwrap_or_default(), ), resolution: value.resolution.unwrap_or_default(), @@ -2331,7 +2341,12 @@ impl PipSettings { ) .chain(index_url.into_iter().map(Index::from_index_url)) .collect(), - args.find_links.combine(find_links).unwrap_or_default(), + args.find_links + .combine(find_links) + .into_iter() + .flatten() + .map(Index::from_find_links) + .collect(), args.no_index.combine(no_index).unwrap_or_default(), ), extras: ExtrasSpecification::from_args( diff --git a/crates/uv/tests/show_settings.rs b/crates/uv/tests/show_settings.rs index 0bded9244d37..a2cd7a2d251a 100644 --- a/crates/uv/tests/show_settings.rs +++ b/crates/uv/tests/show_settings.rs @@ -1414,28 +1414,33 @@ fn resolve_find_links() -> anyhow::Result<()> { index_locations: IndexLocations { indexes: [], flat_index: [ - Url( - VerbatimUrl { - url: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "download.pytorch.org", + Index { + name: None, + url: Url( + VerbatimUrl { + url: Url { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), ), + port: None, + path: "/whl/torch_stable.html", + query: None, + fragment: None, + }, + given: Some( + "https://download.pytorch.org/whl/torch_stable.html", ), - port: None, - path: "/whl/torch_stable.html", - query: None, - fragment: None, }, - given: Some( - "https://download.pytorch.org/whl/torch_stable.html", - ), - }, - ), + ), + explicit: false, + default: false, + }, ], no_index: true, }, diff --git a/uv.schema.json b/uv.schema.json index 7a1fe99242bd..ccc86de5e5bf 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -144,7 +144,7 @@ "null" ], "items": { - "$ref": "#/definitions/FlatIndexLocation" + "$ref": "#/definitions/IndexUrl" } }, "index": { @@ -551,10 +551,6 @@ "description": "The normalized name of an extra dependency.\n\nConverts the name to lowercase and collapses runs of `-`, `_`, and `.` down to a single `-`. For example, `---`, `.`, and `__` are all converted to a single `-`.\n\nSee: - - ", "type": "string" }, - "FlatIndexLocation": { - "description": "The path to a directory of distributions, or a URL to an HTML file with a flat listing of distributions.", - "type": "string" - }, "Index": { "type": "object", "required": [ @@ -831,7 +827,7 @@ "null" ], "items": { - "$ref": "#/definitions/FlatIndexLocation" + "$ref": "#/definitions/IndexUrl" } }, "generate-hashes": {