Remove the flat index types (#7759)

## Summary

I think these really don't pull their weight.
This commit is contained in:
Charlie Marsh 2024-10-15 16:30:37 -07:00 committed by GitHub
parent d31b995511
commit a034a8b83b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 158 additions and 315 deletions

View file

@ -14,7 +14,7 @@ use uv_configuration::{
ConfigSettingEntry, ExportFormat, IndexStrategy, KeyringProviderType, PackageNameSpecifier, ConfigSettingEntry, ExportFormat, IndexStrategy, KeyringProviderType, PackageNameSpecifier,
TargetTriple, TrustedHost, TrustedPublishing, VersionControlSystem, TargetTriple, TrustedHost, TrustedPublishing, VersionControlSystem,
}; };
use uv_distribution_types::{FlatIndexLocation, Index, IndexUrl}; use uv_distribution_types::{Index, IndexUrl};
use uv_normalize::{ExtraName, PackageName}; use uv_normalize::{ExtraName, PackageName};
use uv_pep508::Requirement; use uv_pep508::Requirement;
use uv_pypi_types::VerbatimParsedUrl; use uv_pypi_types::VerbatimParsedUrl;
@ -786,18 +786,6 @@ fn parse_index_url(input: &str) -> Result<Maybe<IndexUrl>, String> {
} }
} }
/// Parse a string into an [`FlatIndexLocation`], mapping the empty string to `None`.
fn parse_flat_index(input: &str) -> Result<Maybe<FlatIndexLocation>, 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`. /// Parse a string into an [`Index`], mapping the empty string to `None`.
fn parse_index_source(input: &str) -> Result<Maybe<Index>, String> { fn parse_index_source(input: &str) -> Result<Maybe<Index>, String> {
if input.is_empty() { if input.is_empty() {
@ -3897,10 +3885,10 @@ pub struct IndexArgs {
long, long,
short, short,
env = EnvVars::UV_FIND_LINKS, env = EnvVars::UV_FIND_LINKS,
value_parser = parse_flat_index, value_parser = parse_index_url,
help_heading = "Index options" help_heading = "Index options"
)] )]
pub find_links: Option<Vec<Maybe<FlatIndexLocation>>>, pub find_links: Option<Vec<Maybe<IndexUrl>>>,
/// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those /// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those
/// provided via `--find-links`. /// provided via `--find-links`.

View file

@ -5,13 +5,14 @@ use reqwest::Response;
use tracing::{debug, info_span, warn, Instrument}; use tracing::{debug, info_span, warn, Instrument};
use url::Url; 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::{Cache, CacheBucket};
use uv_cache_key::cache_digest; use uv_cache_key::cache_digest;
use uv_distribution_filename::DistFilename; 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)] #[derive(Debug, thiserror::Error)]
pub enum FlatIndexError { pub enum FlatIndexError {
@ -94,19 +95,19 @@ impl<'a> FlatIndexClient<'a> {
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
pub async fn fetch( pub async fn fetch(
&self, &self,
indexes: impl Iterator<Item = &FlatIndexLocation>, indexes: impl Iterator<Item = &IndexUrl>,
) -> Result<FlatIndexEntries, FlatIndexError> { ) -> Result<FlatIndexEntries, FlatIndexError> {
let mut fetches = futures::stream::iter(indexes) let mut fetches = futures::stream::iter(indexes)
.map(|index| async move { .map(|index| async move {
let entries = match index { let entries = match index {
FlatIndexLocation::Path(url) => { IndexUrl::Path(url) => {
let path = url let path = url
.to_file_path() .to_file_path()
.map_err(|()| FlatIndexError::NonFileUrl(url.to_url()))?; .map_err(|()| FlatIndexError::NonFileUrl(url.to_url()))?;
Self::read_from_directory(&path, index) Self::read_from_directory(&path, index)
.map_err(|err| FlatIndexError::FindLinksDirectory(path.clone(), err))? .map_err(|err| FlatIndexError::FindLinksDirectory(path.clone(), err))?
} }
FlatIndexLocation::Url(url) => self IndexUrl::Pypi(url) | IndexUrl::Url(url) => self
.read_from_url(url, index) .read_from_url(url, index)
.await .await
.map_err(|err| FlatIndexError::FindLinksUrl(url.to_url(), err))?, .map_err(|err| FlatIndexError::FindLinksUrl(url.to_url(), err))?,
@ -136,7 +137,7 @@ impl<'a> FlatIndexClient<'a> {
async fn read_from_url( async fn read_from_url(
&self, &self,
url: &Url, url: &Url,
flat_index: &FlatIndexLocation, flat_index: &IndexUrl,
) -> Result<FlatIndexEntries, Error> { ) -> Result<FlatIndexEntries, Error> {
let cache_entry = self.cache.entry( let cache_entry = self.cache.entry(
CacheBucket::FlatIndex, CacheBucket::FlatIndex,
@ -210,7 +211,7 @@ impl<'a> FlatIndexClient<'a> {
Some(( Some((
DistFilename::try_from_normalized_filename(&file.filename)?, DistFilename::try_from_normalized_filename(&file.filename)?,
file, file,
IndexUrl::from(flat_index.clone()), flat_index.clone(),
)) ))
}) })
.collect(); .collect();
@ -226,7 +227,7 @@ impl<'a> FlatIndexClient<'a> {
/// Read a flat remote index from a `--find-links` directory. /// Read a flat remote index from a `--find-links` directory.
fn read_from_directory( fn read_from_directory(
path: &Path, path: &Path,
flat_index: &FlatIndexLocation, flat_index: &IndexUrl,
) -> Result<FlatIndexEntries, FindLinksDirectoryError> { ) -> Result<FlatIndexEntries, FindLinksDirectoryError> {
let mut dists = Vec::new(); let mut dists = Vec::new();
for entry in fs_err::read_dir(path)? { for entry in fs_err::read_dir(path)? {
@ -279,7 +280,7 @@ impl<'a> FlatIndexClient<'a> {
); );
continue; continue;
}; };
dists.push((filename, file, IndexUrl::from(flat_index.clone()))); dists.push((filename, file, flat_index.clone()));
} }
Ok(FlatIndexEntries::from_entries(dists)) Ok(FlatIndexEntries::from_entries(dists))
} }

View file

@ -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. /// Return the [`IndexUrl`] of the index.
pub fn url(&self) -> &IndexUrl { pub fn url(&self) -> &IndexUrl {
&self.url &self.url

View file

@ -99,15 +99,6 @@ impl Verbatim for IndexUrl {
} }
} }
impl From<FlatIndexLocation> 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`]. /// An error that can occur when parsing an [`IndexUrl`].
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum IndexUrlError { 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<Self, Self::Err> {
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
self.to_string().serialize(serializer)
}
}
impl<'de> serde::de::Deserialize<'de> for FlatIndexLocation {
fn deserialize<D>(deserializer: D) -> Result<FlatIndexLocation, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FlatIndexLocation::from_str(&s).map_err(serde::de::Error::custom)
}
}
impl From<VerbatimUrl> 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. /// 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, /// This type merges the legacy `--index-url`, `--extra-index-url`, and `--find-links` options,
@ -304,13 +184,13 @@ impl From<VerbatimUrl> for FlatIndexLocation {
#[serde(rename_all = "kebab-case", deny_unknown_fields)] #[serde(rename_all = "kebab-case", deny_unknown_fields)]
pub struct IndexLocations { pub struct IndexLocations {
indexes: Vec<Index>, indexes: Vec<Index>,
flat_index: Vec<FlatIndexLocation>, flat_index: Vec<Index>,
no_index: bool, no_index: bool,
} }
impl IndexLocations { impl IndexLocations {
/// Determine the index URLs to use for fetching packages. /// Determine the index URLs to use for fetching packages.
pub fn new(indexes: Vec<Index>, flat_index: Vec<FlatIndexLocation>, no_index: bool) -> Self { pub fn new(indexes: Vec<Index>, flat_index: Vec<Index>, no_index: bool) -> Self {
Self { Self {
indexes, indexes,
flat_index, flat_index,
@ -325,12 +205,7 @@ impl IndexLocations {
/// ///
/// If the current index location has an `index` set, it will be preserved. /// If the current index location has an `index` set, it will be preserved.
#[must_use] #[must_use]
pub fn combine( pub fn combine(self, indexes: Vec<Index>, flat_index: Vec<Index>, no_index: bool) -> Self {
self,
indexes: Vec<Index>,
flat_index: Vec<FlatIndexLocation>,
no_index: bool,
) -> Self {
Self { Self {
indexes: self.indexes.into_iter().chain(indexes).collect(), indexes: self.indexes.into_iter().chain(indexes).collect(),
flat_index: self.flat_index.into_iter().chain(flat_index).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. /// Return an iterator over the [`FlatIndexLocation`] entries.
pub fn flat_indexes(&'a self) -> impl Iterator<Item = &'a FlatIndexLocation> + 'a { pub fn flat_indexes(&'a self) -> impl Iterator<Item = &'a Index> + 'a {
self.flat_index.iter() self.flat_index.iter()
} }
@ -426,13 +301,12 @@ impl<'a> IndexLocations {
/// Return an iterator over all allowed [`Index`] entries. /// Return an iterator over all allowed [`Index`] entries.
/// ///
/// This includes both explicit and implicit indexes, as well as the default index (but _not_ /// This includes explicit indexes, implicit indexes flat indexes, and the default index.
/// the flat indexes).
/// ///
/// If `no_index` was enabled, then this always returns an empty /// If `no_index` was enabled, then this always returns an empty iterator.
/// iterator.
pub fn allowed_indexes(&'a self) -> impl Iterator<Item = &'a Index> + 'a { pub fn allowed_indexes(&'a self) -> impl Iterator<Item = &'a Index> + 'a {
self.explicit_indexes() self.flat_indexes()
.chain(self.explicit_indexes())
.chain(self.implicit_indexes()) .chain(self.implicit_indexes())
.chain(self.default_index()) .chain(self.default_index())
} }

View file

@ -14,13 +14,13 @@ use crate::source::{HttpRevisionPointer, LocalRevisionPointer, HTTP_REVISION, LO
/// An entry in the [`RegistryWheelIndex`]. /// An entry in the [`RegistryWheelIndex`].
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct IndexEntry { pub struct IndexEntry<'index> {
/// The cached distribution. /// The cached distribution.
pub dist: CachedRegistryDist, 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). /// Whether the wheel was built from source (true), or downloaded from the registry directly (false).
pub built: bool, 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`. /// A local index of distributions that originate from a registry, like `PyPI`.
@ -30,7 +30,7 @@ pub struct RegistryWheelIndex<'a> {
tags: &'a Tags, tags: &'a Tags,
index_locations: &'a IndexLocations, index_locations: &'a IndexLocations,
hasher: &'a HashStrategy, hasher: &'a HashStrategy,
index: FxHashMap<&'a PackageName, Vec<IndexEntry>>, index: FxHashMap<&'a PackageName, Vec<IndexEntry<'a>>>,
} }
impl<'a> RegistryWheelIndex<'a> { impl<'a> RegistryWheelIndex<'a> {
@ -73,21 +73,16 @@ impl<'a> RegistryWheelIndex<'a> {
} }
/// Add a package to the index by reading from the cache. /// Add a package to the index by reading from the cache.
fn index( fn index<'index>(
package: &PackageName, package: &PackageName,
cache: &Cache, cache: &Cache,
tags: &Tags, tags: &Tags,
index_locations: &IndexLocations, index_locations: &'index IndexLocations,
hasher: &HashStrategy, hasher: &HashStrategy,
) -> Vec<IndexEntry> { ) -> Vec<IndexEntry<'index>> {
let mut entries = vec![]; let mut entries = vec![];
let flat_index_urls: Vec<Index> = index_locations for index in index_locations.allowed_indexes() {
.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()) {
// Index all the wheels that were downloaded directly from the registry. // Index all the wheels that were downloaded directly from the registry.
let wheel_dir = cache.shard( let wheel_dir = cache.shard(
CacheBucket::Wheels, CacheBucket::Wheels,
@ -117,7 +112,7 @@ impl<'a> RegistryWheelIndex<'a> {
) { ) {
entries.push(IndexEntry { entries.push(IndexEntry {
dist: wheel.into_registry_dist(), dist: wheel.into_registry_dist(),
index: index.clone(), index,
built: false, built: false,
}); });
} }
@ -144,7 +139,7 @@ impl<'a> RegistryWheelIndex<'a> {
) { ) {
entries.push(IndexEntry { entries.push(IndexEntry {
dist: wheel.into_registry_dist(), dist: wheel.into_registry_dist(),
index: index.clone(), index,
built: false, built: false,
}); });
} }
@ -200,7 +195,7 @@ impl<'a> RegistryWheelIndex<'a> {
) { ) {
entries.push(IndexEntry { entries.push(IndexEntry {
dist: wheel.into_registry_dist(), dist: wheel.into_registry_dist(),
index: index.clone(), index,
built: true, built: true,
}); });
} }

View file

@ -32,12 +32,11 @@ use std::path::{Path, PathBuf};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use tracing::instrument; use tracing::instrument;
use uv_cache_key::CanonicalUrl; use uv_cache_key::CanonicalUrl;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{NoBinary, NoBuild}; use uv_configuration::{NoBinary, NoBuild};
use uv_distribution_types::{ use uv_distribution_types::{
FlatIndexLocation, IndexUrl, NameRequirementSpecification, UnresolvedRequirement, IndexUrl, NameRequirementSpecification, UnresolvedRequirement,
UnresolvedRequirementSpecification, UnresolvedRequirementSpecification,
}; };
use uv_fs::{Simplified, CWD}; use uv_fs::{Simplified, CWD};
@ -71,7 +70,7 @@ pub struct RequirementsSpecification {
/// Whether to disallow index usage. /// Whether to disallow index usage.
pub no_index: bool, pub no_index: bool,
/// The `--find-links` locations to use for fetching packages. /// The `--find-links` locations to use for fetching packages.
pub find_links: Vec<FlatIndexLocation>, pub find_links: Vec<IndexUrl>,
/// The `--no-binary` flags to enforce when selecting distributions. /// The `--no-binary` flags to enforce when selecting distributions.
pub no_binary: NoBinary, pub no_binary: NoBinary,
/// The `--no-build` flags to enforce when selecting distributions. /// The `--no-build` flags to enforce when selecting distributions.
@ -142,7 +141,7 @@ impl RequirementsSpecification {
find_links: requirements_txt find_links: requirements_txt
.find_links .find_links
.into_iter() .into_iter()
.map(FlatIndexLocation::from) .map(IndexUrl::from)
.collect(), .collect(),
no_binary: requirements_txt.no_binary, no_binary: requirements_txt.no_binary,
no_build: requirements_txt.only_binary, no_build: requirements_txt.only_binary,

View file

@ -20,10 +20,9 @@ use uv_distribution::DistributionDatabase;
use uv_distribution_filename::{DistExtension, ExtensionError, SourceDistExtension, WheelFilename}; use uv_distribution_filename::{DistExtension, ExtensionError, SourceDistExtension, WheelFilename};
use uv_distribution_types::{ use uv_distribution_types::{
BuiltDist, DependencyMetadata, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist, BuiltDist, DependencyMetadata, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist,
Dist, DistributionMetadata, FileLocation, FlatIndexLocation, GitSourceDist, IndexLocations, Dist, DistributionMetadata, FileLocation, GitSourceDist, IndexLocations, IndexUrl, Name,
IndexUrl, Name, PathBuiltDist, PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel, PathBuiltDist, PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist,
RegistrySourceDist, RemoteSource, Resolution, ResolvedDist, StaticMetadata, ToUrlError, RemoteSource, Resolution, ResolvedDist, StaticMetadata, ToUrlError, UrlString,
UrlString,
}; };
use uv_fs::{relative_to, PortablePath, PortablePathBuf}; use uv_fs::{relative_to, PortablePath, PortablePathBuf};
use uv_git::{GitReference, GitSha, RepositoryReference, ResolvedRepositoryReference}; use uv_git::{GitReference, GitSha, RepositoryReference, ResolvedRepositoryReference};
@ -1065,16 +1064,6 @@ impl Lock {
} }
IndexUrl::Path(_) => None, 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::<BTreeSet<_>>() .collect::<BTreeSet<_>>()
}); });
@ -1091,20 +1080,6 @@ impl Lock {
Some(path) 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::<BTreeSet<_>>() .collect::<BTreeSet<_>>()
}); });

View file

@ -7,7 +7,7 @@ use uv_configuration::{
ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple, ConfigSettings, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple,
TrustedHost, TrustedPublishing, 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_install_wheel::linker::LinkMode;
use uv_macros::{CombineOptions, OptionsMetadata}; use uv_macros::{CombineOptions, OptionsMetadata};
use uv_normalize::{ExtraName, PackageName}; use uv_normalize::{ExtraName, PackageName};
@ -234,7 +234,7 @@ pub struct InstallerOptions {
pub index_url: Option<IndexUrl>, pub index_url: Option<IndexUrl>,
pub extra_index_url: Option<Vec<IndexUrl>>, pub extra_index_url: Option<Vec<IndexUrl>>,
pub no_index: Option<bool>, pub no_index: Option<bool>,
pub find_links: Option<Vec<FlatIndexLocation>>, pub find_links: Option<Vec<IndexUrl>>,
pub index_strategy: Option<IndexStrategy>, pub index_strategy: Option<IndexStrategy>,
pub keyring_provider: Option<KeyringProviderType>, pub keyring_provider: Option<KeyringProviderType>,
pub allow_insecure_host: Option<Vec<TrustedHost>>, pub allow_insecure_host: Option<Vec<TrustedHost>>,
@ -259,7 +259,7 @@ pub struct ResolverOptions {
pub index_url: Option<IndexUrl>, pub index_url: Option<IndexUrl>,
pub extra_index_url: Option<Vec<IndexUrl>>, pub extra_index_url: Option<Vec<IndexUrl>>,
pub no_index: Option<bool>, pub no_index: Option<bool>,
pub find_links: Option<Vec<FlatIndexLocation>>, pub find_links: Option<Vec<IndexUrl>>,
pub index_strategy: Option<IndexStrategy>, pub index_strategy: Option<IndexStrategy>,
pub keyring_provider: Option<KeyringProviderType>, pub keyring_provider: Option<KeyringProviderType>,
pub allow_insecure_host: Option<Vec<TrustedHost>>, pub allow_insecure_host: Option<Vec<TrustedHost>>,
@ -386,7 +386,7 @@ pub struct ResolverInstallerOptions {
find-links = ["https://download.pytorch.org/whl/torch_stable.html"] find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
"# "#
)] )]
pub find_links: Option<Vec<FlatIndexLocation>>, pub find_links: Option<Vec<IndexUrl>>,
/// The strategy to use when resolving against multiple index URLs. /// 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 /// 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"] find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
"# "#
)] )]
pub find_links: Option<Vec<FlatIndexLocation>>, pub find_links: Option<Vec<IndexUrl>>,
/// The strategy to use when resolving against multiple index URLs. /// 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 /// 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<IndexUrl>, pub index_url: Option<IndexUrl>,
pub extra_index_url: Option<Vec<IndexUrl>>, pub extra_index_url: Option<Vec<IndexUrl>>,
pub no_index: Option<bool>, pub no_index: Option<bool>,
pub find_links: Option<Vec<FlatIndexLocation>>, pub find_links: Option<Vec<IndexUrl>>,
pub index_strategy: Option<IndexStrategy>, pub index_strategy: Option<IndexStrategy>,
pub keyring_provider: Option<KeyringProviderType>, pub keyring_provider: Option<KeyringProviderType>,
pub allow_insecure_host: Option<Vec<TrustedHost>>, pub allow_insecure_host: Option<Vec<TrustedHost>>,
@ -1520,7 +1520,7 @@ pub struct OptionsWire {
index_url: Option<IndexUrl>, index_url: Option<IndexUrl>,
extra_index_url: Option<Vec<IndexUrl>>, extra_index_url: Option<Vec<IndexUrl>>,
no_index: Option<bool>, no_index: Option<bool>,
find_links: Option<Vec<FlatIndexLocation>>, find_links: Option<Vec<IndexUrl>>,
index_strategy: Option<IndexStrategy>, index_strategy: Option<IndexStrategy>,
keyring_provider: Option<KeyringProviderType>, keyring_provider: Option<KeyringProviderType>,
allow_insecure_host: Option<Vec<TrustedHost>>, allow_insecure_host: Option<Vec<TrustedHost>>,

View file

@ -5,12 +5,13 @@ use std::io::Write as _;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use uv_distribution_filename::SourceDistExtension; 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_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_cache::{Cache, CacheBucket};
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
@ -405,9 +406,6 @@ async fn build_package(
store_credentials(index.raw_url(), credentials); store_credentials(index.raw_url(), credentials);
} }
} }
for index in index_locations.flat_indexes() {
store_credentials_from_url(index.url());
}
// Read build constraints. // Read build constraints.
let build_constraints = operations::read_constraints(build_constraints, client_builder).await?; 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`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); 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) FlatIndex::from_entries(entries, None, &hasher, build_options)
}; };

View file

@ -278,7 +278,7 @@ pub(crate) async fn pip_compile(
.map(Index::from_extra_index_url) .map(Index::from_extra_index_url)
.chain(index_url.map(Index::from_index_url)) .chain(index_url.map(Index::from_index_url))
.collect(), .collect(),
find_links, find_links.into_iter().map(Index::from_find_links).collect(),
no_index, no_index,
); );
@ -288,9 +288,6 @@ pub(crate) async fn pip_compile(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)? let client = RegistryClientBuilder::try_from(client_builder)?
@ -312,7 +309,9 @@ pub(crate) async fn pip_compile(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, &cache); 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) 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 necessary, include the `--find-links` locations.
if include_find_links { if include_find_links {
for flat_index in index_locations.flat_indexes() { 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; wrote_preamble = true;
} }
} }

View file

@ -280,7 +280,7 @@ pub(crate) async fn pip_install(
.map(Index::from_extra_index_url) .map(Index::from_extra_index_url)
.chain(index_url.map(Index::from_index_url)) .chain(index_url.map(Index::from_index_url))
.collect(), .collect(),
find_links, find_links.into_iter().map(Index::from_find_links).collect(),
no_index, no_index,
); );
@ -290,9 +290,6 @@ pub(crate) async fn pip_install(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)? let client = RegistryClientBuilder::try_from(client_builder)?
@ -309,7 +306,9 @@ pub(crate) async fn pip_install(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, &cache); 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) FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options)
}; };

View file

@ -216,7 +216,7 @@ pub(crate) async fn pip_sync(
.map(Index::from_extra_index_url) .map(Index::from_extra_index_url)
.chain(index_url.map(Index::from_index_url)) .chain(index_url.map(Index::from_index_url))
.collect(), .collect(),
find_links, find_links.into_iter().map(Index::from_find_links).collect(),
no_index, no_index,
); );
@ -226,9 +226,6 @@ pub(crate) async fn pip_sync(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)? let client = RegistryClientBuilder::try_from(client_builder)?
@ -245,7 +242,9 @@ pub(crate) async fn pip_sync(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, &cache); 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) FlatIndex::from_entries(entries, Some(&tags), &hasher, &build_options)
}; };

View file

@ -251,9 +251,6 @@ pub(crate) async fn add(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)? let client = RegistryClientBuilder::try_from(client_builder)?
@ -282,7 +279,7 @@ pub(crate) async fn add(
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); let client = FlatIndexClient::new(&client, cache);
let entries = client let entries = client
.fetch(settings.index_locations.flat_indexes()) .fetch(settings.index_locations.flat_indexes().map(Index::url))
.await?; .await?;
FlatIndex::from_entries(entries, Some(&tags), &hasher, &settings.build_options) FlatIndex::from_entries(entries, Some(&tags), &hasher, &settings.build_options)
}; };

View file

@ -17,7 +17,7 @@ use uv_configuration::{
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
use uv_distribution_types::{ use uv_distribution_types::{
DependencyMetadata, IndexLocations, NameRequirementSpecification, DependencyMetadata, Index, IndexLocations, NameRequirementSpecification,
UnresolvedRequirementSpecification, UnresolvedRequirementSpecification,
}; };
use uv_git::ResolvedRepositoryReference; use uv_git::ResolvedRepositoryReference;
@ -369,9 +369,6 @@ async fn do_lock(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Initialize the registry client.
let client = RegistryClientBuilder::new(cache.clone()) let client = RegistryClientBuilder::new(cache.clone())
@ -414,7 +411,9 @@ async fn do_lock(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); 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) FlatIndex::from_entries(entries, None, &hasher, build_options)
}; };

View file

@ -651,9 +651,6 @@ pub(crate) async fn resolve_names(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Initialize the registry client.
let client = RegistryClientBuilder::new(cache.clone()) 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); 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. // Initialize the registry client.
let client = RegistryClientBuilder::new(cache.clone()) let client = RegistryClientBuilder::new(cache.clone())
@ -866,7 +860,9 @@ pub(crate) async fn resolve_environment<'a>(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); 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) 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); 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. // Initialize the registry client.
let client = RegistryClientBuilder::new(cache.clone()) let client = RegistryClientBuilder::new(cache.clone())
@ -1001,7 +994,9 @@ pub(crate) async fn sync_environment(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); 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) 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); 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. // Initialize the registry client.
let client = RegistryClientBuilder::new(cache.clone()) let client = RegistryClientBuilder::new(cache.clone())
@ -1208,7 +1200,9 @@ pub(crate) async fn update_environment(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); 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) 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 { 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!( 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.`" "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.`"
); );

View file

@ -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::borrow::Cow;
use std::path::Path; use std::path::Path;
use std::str::FromStr; 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_cache::Cache;
use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
@ -19,7 +12,7 @@ use uv_configuration::{
HashCheckingMode, InstallOptions, HashCheckingMode, InstallOptions,
}; };
use uv_dispatch::BuildDispatch; 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_installer::SitePackages;
use uv_normalize::{PackageName, DEV_DEPENDENCIES}; use uv_normalize::{PackageName, DEV_DEPENDENCIES};
use uv_pep508::{MarkerTree, Requirement, VersionOrUrl}; 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::pyproject::{Source, Sources, ToolUvSources};
use uv_workspace::{DiscoveryOptions, InstallTarget, MemberDiscovery, VirtualProject, Workspace}; 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. /// Sync the project environment.
#[allow(clippy::fn_params_excessive_bools)] #[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn sync( pub(crate) async fn sync(
@ -282,9 +284,6 @@ pub(super) async fn do_sync(
store_credentials(index.raw_url(), credentials); store_credentials(index.raw_url(), credentials);
} }
} }
for index in index_locations.flat_indexes() {
store_credentials_from_url(index.url());
}
// Populate credentials from the workspace. // Populate credentials from the workspace.
store_credentials_from_workspace(target.workspace()); store_credentials_from_workspace(target.workspace());
@ -322,7 +321,9 @@ pub(super) async fn do_sync(
// Resolve the flat indexes from `--find-links`. // Resolve the flat indexes from `--find-links`.
let flat_index = { let flat_index = {
let client = FlatIndexClient::new(&client, cache); 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) FlatIndex::from_entries(entries, Some(tags), &hasher, build_options)
}; };

View file

@ -16,7 +16,7 @@ use uv_configuration::{
NoBinary, NoBuild, SourceStrategy, TrustedHost, NoBinary, NoBuild, SourceStrategy, TrustedHost,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution_types::{DependencyMetadata, IndexLocations}; use uv_distribution_types::{DependencyMetadata, Index, IndexLocations};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_install_wheel::linker::LinkMode; use uv_install_wheel::linker::LinkMode;
use uv_pypi_types::Requirement; use uv_pypi_types::Requirement;
@ -233,9 +233,6 @@ async fn venv_impl(
uv_auth::store_credentials(index.raw_url(), credentials); 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 { if managed {
writeln!( writeln!(
@ -287,9 +284,6 @@ async fn venv_impl(
uv_auth::store_credentials(index.raw_url(), credentials); 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. // Instantiate a client.
let client = RegistryClientBuilder::try_from(client_builder) let client = RegistryClientBuilder::try_from(client_builder)
@ -308,7 +302,7 @@ async fn venv_impl(
let tags = interpreter.tags().map_err(VenvError::Tags)?; let tags = interpreter.tags().map_err(VenvError::Tags)?;
let client = FlatIndexClient::new(&client, cache); let client = FlatIndexClient::new(&client, cache);
let entries = client let entries = client
.fetch(index_locations.flat_indexes()) .fetch(index_locations.flat_indexes().map(Index::url))
.await .await
.map_err(VenvError::FlatIndex)?; .map_err(VenvError::FlatIndex)?;
FlatIndex::from_entries( FlatIndex::from_entries(

View file

@ -1981,7 +1981,12 @@ impl From<ResolverOptions> for ResolverSettings {
) )
.chain(value.index_url.into_iter().map(Index::from_index_url)) .chain(value.index_url.into_iter().map(Index::from_index_url))
.collect(), .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(), value.no_index.unwrap_or_default(),
), ),
resolution: value.resolution.unwrap_or_default(), resolution: value.resolution.unwrap_or_default(),
@ -2119,7 +2124,12 @@ impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
) )
.chain(value.index_url.into_iter().map(Index::from_index_url)) .chain(value.index_url.into_iter().map(Index::from_index_url))
.collect(), .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(), value.no_index.unwrap_or_default(),
), ),
resolution: value.resolution.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)) .chain(index_url.into_iter().map(Index::from_index_url))
.collect(), .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(), args.no_index.combine(no_index).unwrap_or_default(),
), ),
extras: ExtrasSpecification::from_args( extras: ExtrasSpecification::from_args(

View file

@ -1410,28 +1410,33 @@ fn resolve_find_links() -> anyhow::Result<()> {
index_locations: IndexLocations { index_locations: IndexLocations {
indexes: [], indexes: [],
flat_index: [ flat_index: [
Url( Index {
VerbatimUrl { name: None,
url: Url { url: Url(
scheme: "https", VerbatimUrl {
cannot_be_a_base: false, url: Url {
username: "", scheme: "https",
password: None, cannot_be_a_base: false,
host: Some( username: "",
Domain( password: None,
"download.pytorch.org", 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, no_index: true,
}, },

View file

@ -3126,7 +3126,6 @@ fn sync_explicit() -> Result<()> {
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12] Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: .venv Creating virtual environment at: .venv
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME] Installed 1 package in [TIME]
+ idna==2.7 + idna==2.7
"###); "###);

8
uv.schema.json generated
View file

@ -144,7 +144,7 @@
"null" "null"
], ],
"items": { "items": {
"$ref": "#/definitions/FlatIndexLocation" "$ref": "#/definitions/IndexUrl"
} }
}, },
"index": { "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: - <https://peps.python.org/pep-0685/#specification/> - <https://packaging.python.org/en/latest/specifications/name-normalization/>", "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: - <https://peps.python.org/pep-0685/#specification/> - <https://packaging.python.org/en/latest/specifications/name-normalization/>",
"type": "string" "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": { "Index": {
"type": "object", "type": "object",
"required": [ "required": [
@ -835,7 +831,7 @@
"null" "null"
], ],
"items": { "items": {
"$ref": "#/definitions/FlatIndexLocation" "$ref": "#/definitions/IndexUrl"
} }
}, },
"generate-hashes": { "generate-hashes": {