diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index ee472c529..e66e07291 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -14,7 +14,7 @@ use uv_configuration::{ ConfigSettingEntry, ExportFormat, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple, TrustedHost, TrustedPublishing, VersionControlSystem, }; -use uv_distribution_types::{FlatIndexLocation, Index, IndexUrl}; +use uv_distribution_types::{Index, IndexUrl}; use uv_normalize::{ExtraName, PackageName}; use uv_pep508::Requirement; use uv_pypi_types::VerbatimParsedUrl; @@ -786,18 +786,6 @@ fn parse_index_url(input: &str) -> Result, String> { } } -/// Parse a string into an [`FlatIndexLocation`], mapping the empty string to `None`. -fn parse_flat_index(input: &str) -> Result, String> { - if input.is_empty() { - Ok(Maybe::None) - } else { - match FlatIndexLocation::from_str(input) { - Ok(url) => Ok(Maybe::Some(url)), - Err(err) => Err(err.to_string()), - } - } -} - /// Parse a string into an [`Index`], mapping the empty string to `None`. fn parse_index_source(input: &str) -> Result, String> { if input.is_empty() { @@ -3897,10 +3885,10 @@ pub struct IndexArgs { long, short, env = EnvVars::UV_FIND_LINKS, - value_parser = parse_flat_index, + value_parser = parse_index_url, 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 23d72d2f0..9b9d6fe61 100644 --- a/crates/uv-client/src/flat_index.rs +++ b/crates/uv-client/src/flat_index.rs @@ -5,13 +5,14 @@ use reqwest::Response; use tracing::{debug, info_span, warn, Instrument}; use url::Url; -use crate::cached_client::{CacheControl, CachedClientError}; -use crate::html::SimpleHtml; -use crate::{Connectivity, Error, ErrorKind, OwnedArchive, RegistryClient}; use uv_cache::{Cache, CacheBucket}; use uv_cache_key::cache_digest; use uv_distribution_filename::DistFilename; -use uv_distribution_types::{File, FileLocation, FlatIndexLocation, IndexUrl, UrlString}; +use uv_distribution_types::{File, FileLocation, IndexUrl, UrlString}; + +use crate::cached_client::{CacheControl, CachedClientError}; +use crate::html::SimpleHtml; +use crate::{Connectivity, Error, ErrorKind, OwnedArchive, RegistryClient}; #[derive(Debug, thiserror::Error)] pub enum FlatIndexError { @@ -94,19 +95,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 +137,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 +211,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 +227,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 +280,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-types/src/index.rs b/crates/uv-distribution-types/src/index.rs index 9be7ba663..737b8cac9 100644 --- a/crates/uv-distribution-types/src/index.rs +++ b/crates/uv-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/uv-distribution-types/src/index_url.rs b/crates/uv-distribution-types/src/index_url.rs index 7e6650b92..43eba4587 100644 --- a/crates/uv-distribution-types/src/index_url.rs +++ b/crates/uv-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. /// /// This type merges the legacy `--index-url`, `--extra-index-url`, and `--find-links` options, @@ -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-distribution/src/index/registry_wheel_index.rs b/crates/uv-distribution/src/index/registry_wheel_index.rs index 2bc9291eb..2475ae43c 100644 --- a/crates/uv-distribution/src/index/registry_wheel_index.rs +++ b/crates/uv-distribution/src/index/registry_wheel_index.rs @@ -14,13 +14,13 @@ use crate::source::{HttpRevisionPointer, LocalRevisionPointer, HTTP_REVISION, LO /// An entry in the [`RegistryWheelIndex`]. #[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct IndexEntry { +pub struct IndexEntry<'index> { /// The cached distribution. pub dist: CachedRegistryDist, - /// The index from which the wheel was downloaded. - pub index: Index, /// Whether the wheel was built from source (true), or downloaded from the registry directly (false). pub built: bool, + /// The index from which the wheel was downloaded. + pub index: &'index Index, } /// A local index of distributions that originate from a registry, like `PyPI`. @@ -30,7 +30,7 @@ pub struct RegistryWheelIndex<'a> { tags: &'a Tags, index_locations: &'a IndexLocations, hasher: &'a HashStrategy, - index: FxHashMap<&'a PackageName, Vec>, + index: FxHashMap<&'a PackageName, Vec>>, } impl<'a> RegistryWheelIndex<'a> { @@ -73,21 +73,16 @@ impl<'a> RegistryWheelIndex<'a> { } /// Add a package to the index by reading from the cache. - fn index( + fn index<'index>( package: &PackageName, cache: &Cache, tags: &Tags, - index_locations: &IndexLocations, + index_locations: &'index IndexLocations, hasher: &HashStrategy, - ) -> Vec { + ) -> Vec> { let mut entries = vec![]; - 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.indexes().chain(flat_index_urls.iter()) { + for index in index_locations.allowed_indexes() { // Index all the wheels that were downloaded directly from the registry. let wheel_dir = cache.shard( CacheBucket::Wheels, @@ -117,7 +112,7 @@ impl<'a> RegistryWheelIndex<'a> { ) { entries.push(IndexEntry { dist: wheel.into_registry_dist(), - index: index.clone(), + index, built: false, }); } @@ -144,7 +139,7 @@ impl<'a> RegistryWheelIndex<'a> { ) { entries.push(IndexEntry { dist: wheel.into_registry_dist(), - index: index.clone(), + index, built: false, }); } @@ -200,7 +195,7 @@ impl<'a> RegistryWheelIndex<'a> { ) { entries.push(IndexEntry { dist: wheel.into_registry_dist(), - index: index.clone(), + index, built: true, }); } diff --git a/crates/uv-requirements/src/specification.rs b/crates/uv-requirements/src/specification.rs index e456acaaa..bb491cb19 100644 --- a/crates/uv-requirements/src/specification.rs +++ b/crates/uv-requirements/src/specification.rs @@ -32,12 +32,11 @@ use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; use rustc_hash::FxHashSet; use tracing::instrument; - use uv_cache_key::CanonicalUrl; use uv_client::BaseClientBuilder; use uv_configuration::{NoBinary, NoBuild}; use uv_distribution_types::{ - FlatIndexLocation, IndexUrl, NameRequirementSpecification, UnresolvedRequirement, + IndexUrl, NameRequirementSpecification, UnresolvedRequirement, UnresolvedRequirementSpecification, }; use uv_fs::{Simplified, CWD}; @@ -71,7 +70,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 +141,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 66053a1d5..626b9ac8d 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -20,10 +20,9 @@ use uv_distribution::DistributionDatabase; use uv_distribution_filename::{DistExtension, ExtensionError, SourceDistExtension, WheelFilename}; use uv_distribution_types::{ BuiltDist, DependencyMetadata, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist, - Dist, DistributionMetadata, FileLocation, FlatIndexLocation, GitSourceDist, IndexLocations, - IndexUrl, Name, PathBuiltDist, PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel, - RegistrySourceDist, RemoteSource, Resolution, ResolvedDist, StaticMetadata, ToUrlError, - UrlString, + Dist, DistributionMetadata, FileLocation, GitSourceDist, IndexLocations, IndexUrl, Name, + PathBuiltDist, PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, + RemoteSource, Resolution, ResolvedDist, StaticMetadata, ToUrlError, UrlString, }; use uv_fs::{relative_to, PortablePath, PortablePathBuf}; use uv_git::{GitReference, GitSha, RepositoryReference, ResolvedRepositoryReference}; @@ -1065,16 +1064,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::>() }); @@ -1091,20 +1080,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 f2c31fc4d..4ae01f992 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -7,7 +7,7 @@ use uv_configuration::{ ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple, TrustedHost, TrustedPublishing, }; -use uv_distribution_types::{FlatIndexLocation, Index, IndexUrl, StaticMetadata}; +use uv_distribution_types::{Index, IndexUrl, StaticMetadata}; use uv_install_wheel::linker::LinkMode; use uv_macros::{CombineOptions, OptionsMetadata}; use uv_normalize::{ExtraName, PackageName}; @@ -234,7 +234,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>, @@ -259,7 +259,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>, @@ -386,7 +386,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 @@ -798,7 +798,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 @@ -1414,7 +1414,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>, @@ -1520,7 +1520,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_frontend.rs b/crates/uv/src/commands/build_frontend.rs index 5d81cfcd8..2b8af6a9e 100644 --- a/crates/uv/src/commands/build_frontend.rs +++ b/crates/uv/src/commands/build_frontend.rs @@ -5,12 +5,13 @@ use std::io::Write as _; use std::path::{Path, PathBuf}; use anyhow::Result; + use owo_colors::OwoColorize; use uv_distribution_filename::SourceDistExtension; -use uv_distribution_types::{DependencyMetadata, IndexLocations}; +use uv_distribution_types::{DependencyMetadata, Index, IndexLocations}; use uv_install_wheel::linker::LinkMode; -use uv_auth::{store_credentials, store_credentials_from_url}; +use uv_auth::store_credentials; use uv_cache::{Cache, CacheBucket}; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -405,9 +406,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?; @@ -459,7 +457,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 d19c1b08d..36711aa33 100644 --- a/crates/uv/src/commands/pip/compile.rs +++ b/crates/uv/src/commands/pip/compile.rs @@ -278,7 +278,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, ); @@ -288,9 +288,6 @@ pub(crate) async fn pip_compile( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -312,7 +309,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) }; @@ -470,7 +469,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 8020c757b..e05dedbc4 100644 --- a/crates/uv/src/commands/pip/install.rs +++ b/crates/uv/src/commands/pip/install.rs @@ -280,7 +280,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, ); @@ -290,9 +290,6 @@ pub(crate) async fn pip_install( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -309,7 +306,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 60313068c..744679979 100644 --- a/crates/uv/src/commands/pip/sync.rs +++ b/crates/uv/src/commands/pip/sync.rs @@ -216,7 +216,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, ); @@ -226,9 +226,6 @@ pub(crate) async fn pip_sync( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -245,7 +242,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 84a0d5cd0..8da60a4aa 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -251,9 +251,6 @@ pub(crate) async fn add( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in settings.index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::try_from(client_builder)? @@ -282,7 +279,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 d42ae6e7d..ce9c51912 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -17,7 +17,7 @@ use uv_configuration::{ use uv_dispatch::BuildDispatch; use uv_distribution::DistributionDatabase; use uv_distribution_types::{ - DependencyMetadata, IndexLocations, NameRequirementSpecification, + DependencyMetadata, Index, IndexLocations, NameRequirementSpecification, UnresolvedRequirementSpecification, }; use uv_git::ResolvedRepositoryReference; @@ -369,9 +369,6 @@ async fn do_lock( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -414,7 +411,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 b7350ddc4..8ac9a7419 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -651,9 +651,6 @@ pub(crate) async fn resolve_names( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -803,9 +800,6 @@ pub(crate) async fn resolve_environment<'a>( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -866,7 +860,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) }; @@ -966,9 +962,6 @@ pub(crate) async fn sync_environment( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -1001,7 +994,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) }; @@ -1159,9 +1154,6 @@ pub(crate) async fn update_environment( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Initialize the registry client. let client = RegistryClientBuilder::new(cache.clone()) @@ -1208,7 +1200,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) }; @@ -1387,7 +1381,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 3957ca9ff..80ffd7ef2 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -1,17 +1,10 @@ -use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger}; -use crate::commands::pip::operations; -use crate::commands::pip::operations::Modifications; -use crate::commands::project::lock::do_safe_lock; -use crate::commands::project::{ProjectError, SharedState}; -use crate::commands::{diagnostics, pip, project, ExitStatus}; -use crate::printer::Printer; -use crate::settings::{InstallerSettingsRef, ResolverInstallerSettings}; -use anyhow::{Context, Result}; -use itertools::Itertools; use std::borrow::Cow; use std::path::Path; use std::str::FromStr; -use uv_auth::{store_credentials, store_credentials_from_url}; + +use anyhow::{Context, Result}; +use itertools::Itertools; +use uv_auth::store_credentials; use uv_cache::Cache; use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -19,7 +12,7 @@ use uv_configuration::{ HashCheckingMode, InstallOptions, }; use uv_dispatch::BuildDispatch; -use uv_distribution_types::{DirectorySourceDist, Dist, ResolvedDist, SourceDist}; +use uv_distribution_types::{DirectorySourceDist, Dist, Index, ResolvedDist, SourceDist}; use uv_installer::SitePackages; use uv_normalize::{PackageName, DEV_DEPENDENCIES}; use uv_pep508::{MarkerTree, Requirement, VersionOrUrl}; @@ -33,6 +26,15 @@ use uv_warnings::warn_user; use uv_workspace::pyproject::{Source, Sources, ToolUvSources}; use uv_workspace::{DiscoveryOptions, InstallTarget, MemberDiscovery, VirtualProject, Workspace}; +use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger}; +use crate::commands::pip::operations; +use crate::commands::pip::operations::Modifications; +use crate::commands::project::lock::do_safe_lock; +use crate::commands::project::{ProjectError, SharedState}; +use crate::commands::{diagnostics, pip, project, ExitStatus}; +use crate::printer::Printer; +use crate::settings::{InstallerSettingsRef, ResolverInstallerSettings}; + /// Sync the project environment. #[allow(clippy::fn_params_excessive_bools)] pub(crate) async fn sync( @@ -282,9 +284,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()); @@ -322,7 +321,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 3184f28dc..03da64bf0 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -16,7 +16,7 @@ use uv_configuration::{ NoBinary, NoBuild, SourceStrategy, TrustedHost, }; use uv_dispatch::BuildDispatch; -use uv_distribution_types::{DependencyMetadata, IndexLocations}; +use uv_distribution_types::{DependencyMetadata, Index, IndexLocations}; use uv_fs::Simplified; use uv_install_wheel::linker::LinkMode; use uv_pypi_types::Requirement; @@ -233,9 +233,6 @@ async fn venv_impl( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } if managed { writeln!( @@ -287,9 +284,6 @@ async fn venv_impl( uv_auth::store_credentials(index.raw_url(), credentials); } } - for index in index_locations.flat_indexes() { - uv_auth::store_credentials_from_url(index.url()); - } // Instantiate a client. let client = RegistryClientBuilder::try_from(client_builder) @@ -308,7 +302,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 8d7428018..6938a006a 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -1981,7 +1981,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(), @@ -2119,7 +2124,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(), @@ -2353,7 +2363,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/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 295c25fde..b9565ffd9 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -1410,28 +1410,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/crates/uv/tests/it/sync.rs b/crates/uv/tests/it/sync.rs index ef264d3aa..5bbb5a393 100644 --- a/crates/uv/tests/it/sync.rs +++ b/crates/uv/tests/it/sync.rs @@ -3126,7 +3126,6 @@ fn sync_explicit() -> Result<()> { Using CPython 3.12.[X] interpreter at: [PYTHON-3.12] Creating virtual environment at: .venv Resolved 2 packages in [TIME] - Prepared 1 package in [TIME] Installed 1 package in [TIME] + idna==2.7 "###); diff --git a/uv.schema.json b/uv.schema.json index f6ab2f8c5..370904803 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": [ @@ -835,7 +831,7 @@ "null" ], "items": { - "$ref": "#/definitions/FlatIndexLocation" + "$ref": "#/definitions/IndexUrl" } }, "generate-hashes": {