mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-01 12:24:15 +00:00
Cache WHEEL and METADATA reads in installed distributions (#15489)
## Summary Uses interior mutability to cache the reads. This follows the pattern we use for reading the platform tags in `Interpreter::tags`.
This commit is contained in:
parent
be4d5b72aa
commit
ef9a332364
10 changed files with 240 additions and 161 deletions
|
|
@ -2,6 +2,7 @@ use std::borrow::Cow;
|
|||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use fs_err as fs;
|
||||
use thiserror::Error;
|
||||
|
|
@ -68,9 +69,42 @@ pub enum InstalledDistError {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InstalledDist {
|
||||
pub kind: InstalledDistKind,
|
||||
// Cache data that must be read from the `.dist-info` directory. These are safe to cache as
|
||||
// the `InstalledDist` is immutable after creation.
|
||||
metadata_cache: OnceLock<uv_pypi_types::ResolutionMetadata>,
|
||||
tags_cache: OnceLock<Option<ExpandedTags>>,
|
||||
}
|
||||
|
||||
impl From<InstalledDistKind> for InstalledDist {
|
||||
fn from(kind: InstalledDistKind) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
metadata_cache: OnceLock::new(),
|
||||
tags_cache: OnceLock::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for InstalledDist {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.kind.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for InstalledDist {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.kind == other.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for InstalledDist {}
|
||||
|
||||
/// A built distribution (wheel) that is installed in a virtual environment.
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub enum InstalledDist {
|
||||
pub enum InstalledDistKind {
|
||||
/// The distribution was derived from a registry, like `PyPI`.
|
||||
Registry(InstalledRegistryDist),
|
||||
/// The distribution was derived from an arbitrary URL.
|
||||
|
|
@ -152,35 +186,41 @@ impl InstalledDist {
|
|||
|
||||
return if let Some(direct_url) = Self::read_direct_url(path)? {
|
||||
match Url::try_from(&direct_url) {
|
||||
Ok(url) => Ok(Some(Self::Url(InstalledDirectUrlDist {
|
||||
name,
|
||||
version,
|
||||
editable: matches!(&direct_url, DirectUrl::LocalDirectory { dir_info, .. } if dir_info.editable == Some(true)),
|
||||
direct_url: Box::new(direct_url),
|
||||
url: DisplaySafeUrl::from(url),
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
cache_info,
|
||||
build_info,
|
||||
}))),
|
||||
Err(err) => {
|
||||
warn!("Failed to parse direct URL: {err}");
|
||||
Ok(Some(Self::Registry(InstalledRegistryDist {
|
||||
Ok(url) => Ok(Some(Self::from(InstalledDistKind::Url(
|
||||
InstalledDirectUrlDist {
|
||||
name,
|
||||
version,
|
||||
editable: matches!(&direct_url, DirectUrl::LocalDirectory { dir_info, .. } if dir_info.editable == Some(true)),
|
||||
direct_url: Box::new(direct_url),
|
||||
url: DisplaySafeUrl::from(url),
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
cache_info,
|
||||
build_info,
|
||||
})))
|
||||
},
|
||||
)))),
|
||||
Err(err) => {
|
||||
warn!("Failed to parse direct URL: {err}");
|
||||
Ok(Some(Self::from(InstalledDistKind::Registry(
|
||||
InstalledRegistryDist {
|
||||
name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
cache_info,
|
||||
build_info,
|
||||
},
|
||||
))))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(Some(Self::Registry(InstalledRegistryDist {
|
||||
name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
cache_info,
|
||||
build_info,
|
||||
})))
|
||||
Ok(Some(Self::from(InstalledDistKind::Registry(
|
||||
InstalledRegistryDist {
|
||||
name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
cache_info,
|
||||
build_info,
|
||||
},
|
||||
))))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -204,19 +244,23 @@ impl InstalledDist {
|
|||
|
||||
if let Some(version) = file_name.version {
|
||||
if metadata.is_dir() {
|
||||
return Ok(Some(Self::EggInfoDirectory(InstalledEggInfoDirectory {
|
||||
name: file_name.name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
})));
|
||||
return Ok(Some(Self::from(InstalledDistKind::EggInfoDirectory(
|
||||
InstalledEggInfoDirectory {
|
||||
name: file_name.name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
|
||||
if metadata.is_file() {
|
||||
return Ok(Some(Self::EggInfoFile(InstalledEggInfoFile {
|
||||
name: file_name.name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
})));
|
||||
return Ok(Some(Self::from(InstalledDistKind::EggInfoFile(
|
||||
InstalledEggInfoFile {
|
||||
name: file_name.name,
|
||||
version,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,22 +268,26 @@ impl InstalledDist {
|
|||
let Some(egg_metadata) = read_metadata(&path.join("PKG-INFO")) else {
|
||||
return Ok(None);
|
||||
};
|
||||
return Ok(Some(Self::EggInfoDirectory(InstalledEggInfoDirectory {
|
||||
name: file_name.name,
|
||||
version: Version::from_str(&egg_metadata.version)?,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
})));
|
||||
return Ok(Some(Self::from(InstalledDistKind::EggInfoDirectory(
|
||||
InstalledEggInfoDirectory {
|
||||
name: file_name.name,
|
||||
version: Version::from_str(&egg_metadata.version)?,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
|
||||
if metadata.is_file() {
|
||||
let Some(egg_metadata) = read_metadata(path) else {
|
||||
return Ok(None);
|
||||
};
|
||||
return Ok(Some(Self::EggInfoDirectory(InstalledEggInfoDirectory {
|
||||
name: file_name.name,
|
||||
version: Version::from_str(&egg_metadata.version)?,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
})));
|
||||
return Ok(Some(Self::from(InstalledDistKind::EggInfoDirectory(
|
||||
InstalledEggInfoDirectory {
|
||||
name: file_name.name,
|
||||
version: Version::from_str(&egg_metadata.version)?,
|
||||
path: path.to_path_buf().into_boxed_path(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -283,14 +331,16 @@ impl InstalledDist {
|
|||
return Ok(None);
|
||||
};
|
||||
|
||||
return Ok(Some(Self::LegacyEditable(InstalledLegacyEditable {
|
||||
name: egg_metadata.name,
|
||||
version: Version::from_str(&egg_metadata.version)?,
|
||||
egg_link: path.to_path_buf().into_boxed_path(),
|
||||
target: target.into_boxed_path(),
|
||||
target_url: DisplaySafeUrl::from(url),
|
||||
egg_info: egg_info.into_boxed_path(),
|
||||
})));
|
||||
return Ok(Some(Self::from(InstalledDistKind::LegacyEditable(
|
||||
InstalledLegacyEditable {
|
||||
name: egg_metadata.name,
|
||||
version: Version::from_str(&egg_metadata.version)?,
|
||||
egg_link: path.to_path_buf().into_boxed_path(),
|
||||
target: target.into_boxed_path(),
|
||||
target_url: DisplaySafeUrl::from(url),
|
||||
egg_info: egg_info.into_boxed_path(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
|
|
@ -298,45 +348,45 @@ impl InstalledDist {
|
|||
|
||||
/// Return the [`Path`] at which the distribution is stored on-disk.
|
||||
pub fn install_path(&self) -> &Path {
|
||||
match self {
|
||||
Self::Registry(dist) => &dist.path,
|
||||
Self::Url(dist) => &dist.path,
|
||||
Self::EggInfoDirectory(dist) => &dist.path,
|
||||
Self::EggInfoFile(dist) => &dist.path,
|
||||
Self::LegacyEditable(dist) => &dist.egg_info,
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => &dist.path,
|
||||
InstalledDistKind::Url(dist) => &dist.path,
|
||||
InstalledDistKind::EggInfoDirectory(dist) => &dist.path,
|
||||
InstalledDistKind::EggInfoFile(dist) => &dist.path,
|
||||
InstalledDistKind::LegacyEditable(dist) => &dist.egg_info,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the [`Version`] of the distribution.
|
||||
pub fn version(&self) -> &Version {
|
||||
match self {
|
||||
Self::Registry(dist) => &dist.version,
|
||||
Self::Url(dist) => &dist.version,
|
||||
Self::EggInfoDirectory(dist) => &dist.version,
|
||||
Self::EggInfoFile(dist) => &dist.version,
|
||||
Self::LegacyEditable(dist) => &dist.version,
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => &dist.version,
|
||||
InstalledDistKind::Url(dist) => &dist.version,
|
||||
InstalledDistKind::EggInfoDirectory(dist) => &dist.version,
|
||||
InstalledDistKind::EggInfoFile(dist) => &dist.version,
|
||||
InstalledDistKind::LegacyEditable(dist) => &dist.version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the [`CacheInfo`] of the distribution, if any.
|
||||
pub fn cache_info(&self) -> Option<&CacheInfo> {
|
||||
match self {
|
||||
Self::Registry(dist) => dist.cache_info.as_ref(),
|
||||
Self::Url(dist) => dist.cache_info.as_ref(),
|
||||
Self::EggInfoDirectory(..) => None,
|
||||
Self::EggInfoFile(..) => None,
|
||||
Self::LegacyEditable(..) => None,
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => dist.cache_info.as_ref(),
|
||||
InstalledDistKind::Url(dist) => dist.cache_info.as_ref(),
|
||||
InstalledDistKind::EggInfoDirectory(..) => None,
|
||||
InstalledDistKind::EggInfoFile(..) => None,
|
||||
InstalledDistKind::LegacyEditable(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the [`BuildInfo`] of the distribution, if any.
|
||||
pub fn build_info(&self) -> Option<&BuildInfo> {
|
||||
match self {
|
||||
Self::Registry(dist) => dist.build_info.as_ref(),
|
||||
Self::Url(dist) => dist.build_info.as_ref(),
|
||||
Self::EggInfoDirectory(..) => None,
|
||||
Self::EggInfoFile(..) => None,
|
||||
Self::LegacyEditable(..) => None,
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => dist.build_info.as_ref(),
|
||||
InstalledDistKind::Url(dist) => dist.build_info.as_ref(),
|
||||
InstalledDistKind::EggInfoDirectory(..) => None,
|
||||
InstalledDistKind::EggInfoFile(..) => None,
|
||||
InstalledDistKind::LegacyEditable(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,9 +430,13 @@ impl InstalledDist {
|
|||
}
|
||||
|
||||
/// Read the `METADATA` file from a `.dist-info` directory.
|
||||
pub fn read_metadata(&self) -> Result<uv_pypi_types::ResolutionMetadata, InstalledDistError> {
|
||||
match self {
|
||||
Self::Registry(_) | Self::Url(_) => {
|
||||
pub fn read_metadata(&self) -> Result<&uv_pypi_types::ResolutionMetadata, InstalledDistError> {
|
||||
if let Some(metadata) = self.metadata_cache.get() {
|
||||
return Ok(metadata);
|
||||
}
|
||||
|
||||
let metadata = match &self.kind {
|
||||
InstalledDistKind::Registry(_) | InstalledDistKind::Url(_) => {
|
||||
let path = self.install_path().join("METADATA");
|
||||
let contents = fs::read(&path)?;
|
||||
// TODO(zanieb): Update this to use thiserror so we can unpack parse errors downstream
|
||||
|
|
@ -391,13 +445,19 @@ impl InstalledDist {
|
|||
path: path.clone(),
|
||||
err: Box::new(err),
|
||||
}
|
||||
})
|
||||
})?
|
||||
}
|
||||
Self::EggInfoFile(_) | Self::EggInfoDirectory(_) | Self::LegacyEditable(_) => {
|
||||
let path = match self {
|
||||
Self::EggInfoFile(dist) => Cow::Borrowed(&*dist.path),
|
||||
Self::EggInfoDirectory(dist) => Cow::Owned(dist.path.join("PKG-INFO")),
|
||||
Self::LegacyEditable(dist) => Cow::Owned(dist.egg_info.join("PKG-INFO")),
|
||||
InstalledDistKind::EggInfoFile(_)
|
||||
| InstalledDistKind::EggInfoDirectory(_)
|
||||
| InstalledDistKind::LegacyEditable(_) => {
|
||||
let path = match &self.kind {
|
||||
InstalledDistKind::EggInfoFile(dist) => Cow::Borrowed(&*dist.path),
|
||||
InstalledDistKind::EggInfoDirectory(dist) => {
|
||||
Cow::Owned(dist.path.join("PKG-INFO"))
|
||||
}
|
||||
InstalledDistKind::LegacyEditable(dist) => {
|
||||
Cow::Owned(dist.egg_info.join("PKG-INFO"))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let contents = fs::read(path.as_ref())?;
|
||||
|
|
@ -406,9 +466,12 @@ impl InstalledDist {
|
|||
path: path.to_path_buf(),
|
||||
err: Box::new(err),
|
||||
}
|
||||
})
|
||||
})?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let _ = self.metadata_cache.set(metadata);
|
||||
Ok(self.metadata_cache.get().expect("metadata should be set"))
|
||||
}
|
||||
|
||||
/// Return the `INSTALLER` of the distribution.
|
||||
|
|
@ -422,56 +485,64 @@ impl InstalledDist {
|
|||
}
|
||||
|
||||
/// Return the supported wheel tags for the distribution from the `WHEEL` file, if available.
|
||||
pub fn read_tags(&self) -> Result<Option<ExpandedTags>, InstalledDistError> {
|
||||
// TODO(charlie): Cache this result.
|
||||
let path = match self {
|
||||
Self::Registry(InstalledRegistryDist { path, .. }) => path,
|
||||
Self::Url(InstalledDirectUrlDist { path, .. }) => path,
|
||||
Self::EggInfoFile(_) => return Ok(None),
|
||||
Self::EggInfoDirectory(_) => return Ok(None),
|
||||
Self::LegacyEditable(_) => return Ok(None),
|
||||
pub fn read_tags(&self) -> Result<Option<&ExpandedTags>, InstalledDistError> {
|
||||
if let Some(tags) = self.tags_cache.get() {
|
||||
return Ok(tags.as_ref());
|
||||
}
|
||||
|
||||
let path = match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => &dist.path,
|
||||
InstalledDistKind::Url(dist) => &dist.path,
|
||||
InstalledDistKind::EggInfoFile(_) => return Ok(None),
|
||||
InstalledDistKind::EggInfoDirectory(_) => return Ok(None),
|
||||
InstalledDistKind::LegacyEditable(_) => return Ok(None),
|
||||
};
|
||||
|
||||
// Read the `WHEEL` file.
|
||||
let contents = fs_err::read_to_string(path.join("WHEEL"))?;
|
||||
let wheel_file = WheelFile::parse(&contents)?;
|
||||
let Some(tags) = wheel_file.tags() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// Parse the tags.
|
||||
let tags = ExpandedTags::parse(tags.iter().map(String::as_str))?;
|
||||
let tags = if let Some(tags) = wheel_file.tags() {
|
||||
Some(ExpandedTags::parse(tags.iter().map(String::as_str))?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Some(tags))
|
||||
let _ = self.tags_cache.set(tags);
|
||||
Ok(self.tags_cache.get().expect("tags should be set").as_ref())
|
||||
}
|
||||
|
||||
/// Return true if the distribution is editable.
|
||||
pub fn is_editable(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::LegacyEditable(_) | Self::Url(InstalledDirectUrlDist { editable: true, .. })
|
||||
&self.kind,
|
||||
InstalledDistKind::LegacyEditable(_)
|
||||
| InstalledDistKind::Url(InstalledDirectUrlDist { editable: true, .. })
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the [`Url`] of the distribution, if it is editable.
|
||||
pub fn as_editable(&self) -> Option<&Url> {
|
||||
match self {
|
||||
Self::Registry(_) => None,
|
||||
Self::Url(dist) => dist.editable.then_some(&dist.url),
|
||||
Self::EggInfoFile(_) => None,
|
||||
Self::EggInfoDirectory(_) => None,
|
||||
Self::LegacyEditable(dist) => Some(&dist.target_url),
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(_) => None,
|
||||
InstalledDistKind::Url(dist) => dist.editable.then_some(&dist.url),
|
||||
InstalledDistKind::EggInfoFile(_) => None,
|
||||
InstalledDistKind::EggInfoDirectory(_) => None,
|
||||
InstalledDistKind::LegacyEditable(dist) => Some(&dist.target_url),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if the distribution refers to a local file or directory.
|
||||
pub fn is_local(&self) -> bool {
|
||||
match self {
|
||||
Self::Registry(_) => false,
|
||||
Self::Url(dist) => matches!(&*dist.direct_url, DirectUrl::LocalDirectory { .. }),
|
||||
Self::EggInfoFile(_) => false,
|
||||
Self::EggInfoDirectory(_) => false,
|
||||
Self::LegacyEditable(_) => true,
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(_) => false,
|
||||
InstalledDistKind::Url(dist) => {
|
||||
matches!(&*dist.direct_url, DirectUrl::LocalDirectory { .. })
|
||||
}
|
||||
InstalledDistKind::EggInfoFile(_) => false,
|
||||
InstalledDistKind::EggInfoDirectory(_) => false,
|
||||
InstalledDistKind::LegacyEditable(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -514,12 +585,12 @@ impl Name for InstalledLegacyEditable {
|
|||
|
||||
impl Name for InstalledDist {
|
||||
fn name(&self) -> &PackageName {
|
||||
match self {
|
||||
Self::Registry(dist) => dist.name(),
|
||||
Self::Url(dist) => dist.name(),
|
||||
Self::EggInfoDirectory(dist) => dist.name(),
|
||||
Self::EggInfoFile(dist) => dist.name(),
|
||||
Self::LegacyEditable(dist) => dist.name(),
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => dist.name(),
|
||||
InstalledDistKind::Url(dist) => dist.name(),
|
||||
InstalledDistKind::EggInfoDirectory(dist) => dist.name(),
|
||||
InstalledDistKind::EggInfoFile(dist) => dist.name(),
|
||||
InstalledDistKind::LegacyEditable(dist) => dist.name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -556,12 +627,12 @@ impl InstalledMetadata for InstalledLegacyEditable {
|
|||
|
||||
impl InstalledMetadata for InstalledDist {
|
||||
fn installed_version(&self) -> InstalledVersion<'_> {
|
||||
match self {
|
||||
Self::Registry(dist) => dist.installed_version(),
|
||||
Self::Url(dist) => dist.installed_version(),
|
||||
Self::EggInfoFile(dist) => dist.installed_version(),
|
||||
Self::EggInfoDirectory(dist) => dist.installed_version(),
|
||||
Self::LegacyEditable(dist) => dist.installed_version(),
|
||||
match &self.kind {
|
||||
InstalledDistKind::Registry(dist) => dist.installed_version(),
|
||||
InstalledDistKind::Url(dist) => dist.installed_version(),
|
||||
InstalledDistKind::EggInfoFile(dist) => dist.installed_version(),
|
||||
InstalledDistKind::EggInfoDirectory(dist) => dist.installed_version(),
|
||||
InstalledDistKind::LegacyEditable(dist) => dist.installed_version(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
|||
.read_metadata()
|
||||
.map_err(|err| Error::ReadInstalled(Box::new(dist.clone()), err))?;
|
||||
|
||||
Ok(ArchiveMetadata::from_metadata23(metadata))
|
||||
Ok(ArchiveMetadata::from_metadata23(metadata.clone()))
|
||||
}
|
||||
|
||||
/// Either fetch the only wheel metadata (directly from the index or with range requests) or
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use uv_cache_info::CacheInfo;
|
|||
use uv_cache_key::{CanonicalUrl, RepositoryUrl};
|
||||
use uv_distribution_types::{
|
||||
BuildInfo, BuildVariables, ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires,
|
||||
ExtraBuildVariables, InstalledDirectUrlDist, InstalledDist, PackageConfigSettings,
|
||||
RequirementSource,
|
||||
ExtraBuildVariables, InstalledDirectUrlDist, InstalledDist, InstalledDistKind,
|
||||
PackageConfigSettings, RequirementSource,
|
||||
};
|
||||
use uv_git_types::GitOid;
|
||||
use uv_normalize::PackageName;
|
||||
|
|
@ -78,12 +78,12 @@ impl RequirementSatisfaction {
|
|||
ext: _,
|
||||
url: _,
|
||||
} => {
|
||||
let InstalledDist::Url(InstalledDirectUrlDist {
|
||||
let InstalledDistKind::Url(InstalledDirectUrlDist {
|
||||
direct_url,
|
||||
editable,
|
||||
cache_info,
|
||||
..
|
||||
}) = &distribution
|
||||
}) = &distribution.kind
|
||||
else {
|
||||
return Self::Mismatch;
|
||||
};
|
||||
|
|
@ -137,7 +137,8 @@ impl RequirementSatisfaction {
|
|||
git: requested_git,
|
||||
subdirectory: requested_subdirectory,
|
||||
} => {
|
||||
let InstalledDist::Url(InstalledDirectUrlDist { direct_url, .. }) = &distribution
|
||||
let InstalledDistKind::Url(InstalledDirectUrlDist { direct_url, .. }) =
|
||||
&distribution.kind
|
||||
else {
|
||||
return Self::Mismatch;
|
||||
};
|
||||
|
|
@ -192,11 +193,11 @@ impl RequirementSatisfaction {
|
|||
ext: _,
|
||||
url: _,
|
||||
} => {
|
||||
let InstalledDist::Url(InstalledDirectUrlDist {
|
||||
let InstalledDistKind::Url(InstalledDirectUrlDist {
|
||||
direct_url,
|
||||
cache_info,
|
||||
..
|
||||
}) = &distribution
|
||||
}) = &distribution.kind
|
||||
else {
|
||||
return Self::Mismatch;
|
||||
};
|
||||
|
|
@ -247,11 +248,11 @@ impl RequirementSatisfaction {
|
|||
r#virtual: _,
|
||||
url: _,
|
||||
} => {
|
||||
let InstalledDist::Url(InstalledDirectUrlDist {
|
||||
let InstalledDistKind::Url(InstalledDirectUrlDist {
|
||||
direct_url,
|
||||
cache_info,
|
||||
..
|
||||
}) = &distribution
|
||||
}) = &distribution.kind
|
||||
else {
|
||||
return Self::Mismatch;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use fs_err as fs;
|
|||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use uv_distribution_types::{
|
||||
ConfigSettings, Diagnostic, ExtraBuildRequires, ExtraBuildVariables, InstalledDist, Name,
|
||||
NameRequirementSpecification, PackageConfigSettings, Requirement, UnresolvedRequirement,
|
||||
UnresolvedRequirementSpecification,
|
||||
ConfigSettings, Diagnostic, ExtraBuildRequires, ExtraBuildVariables, InstalledDist,
|
||||
InstalledDistKind, Name, NameRequirementSpecification, PackageConfigSettings, Requirement,
|
||||
UnresolvedRequirement, UnresolvedRequirementSpecification,
|
||||
};
|
||||
use uv_fs::Simplified;
|
||||
use uv_normalize::PackageName;
|
||||
|
|
@ -126,7 +126,7 @@ impl SitePackages {
|
|||
.push(idx);
|
||||
|
||||
// Index the distribution by URL.
|
||||
if let InstalledDist::Url(dist) = &dist_info {
|
||||
if let InstalledDistKind::Url(dist) = &dist_info.kind {
|
||||
by_url.entry(dist.url.clone()).or_default().push(idx);
|
||||
}
|
||||
|
||||
|
|
@ -528,8 +528,8 @@ impl SitePackages {
|
|||
.with_context(|| format!("Failed to read metadata for: {distribution}"))?;
|
||||
|
||||
// Add the dependencies to the queue.
|
||||
for dependency in metadata.requires_dist {
|
||||
let dependency = Requirement::from(dependency);
|
||||
for dependency in &metadata.requires_dist {
|
||||
let dependency = Requirement::from(dependency.clone());
|
||||
if let Some(r#overrides) = overrides.get(&dependency.name) {
|
||||
for dependency in r#overrides {
|
||||
if dependency.evaluate_markers(Some(markers), &requirement.extras) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use uv_distribution_types::{InstalledDist, InstalledEggInfoFile};
|
||||
use uv_distribution_types::{InstalledDist, InstalledDistKind, InstalledEggInfoFile};
|
||||
|
||||
/// Uninstall a package from the specified Python environment.
|
||||
pub async fn uninstall(
|
||||
|
|
@ -6,17 +6,17 @@ pub async fn uninstall(
|
|||
) -> Result<uv_install_wheel::Uninstall, UninstallError> {
|
||||
let uninstall = tokio::task::spawn_blocking({
|
||||
let dist = dist.clone();
|
||||
move || match dist {
|
||||
InstalledDist::Registry(_) | InstalledDist::Url(_) => {
|
||||
move || match dist.kind {
|
||||
InstalledDistKind::Registry(_) | InstalledDistKind::Url(_) => {
|
||||
Ok(uv_install_wheel::uninstall_wheel(dist.install_path())?)
|
||||
}
|
||||
InstalledDist::EggInfoDirectory(_) => {
|
||||
InstalledDistKind::EggInfoDirectory(_) => {
|
||||
Ok(uv_install_wheel::uninstall_egg(dist.install_path())?)
|
||||
}
|
||||
InstalledDist::LegacyEditable(dist) => {
|
||||
InstalledDistKind::LegacyEditable(dist) => {
|
||||
Ok(uv_install_wheel::uninstall_legacy_editable(&dist.egg_link)?)
|
||||
}
|
||||
InstalledDist::EggInfoFile(dist) => Err(UninstallError::Distutils(dist)),
|
||||
InstalledDistKind::EggInfoFile(dist) => Err(UninstallError::Distutils(dist)),
|
||||
}
|
||||
})
|
||||
.await??;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
|||
use rustc_hash::FxHashMap;
|
||||
use tracing::trace;
|
||||
|
||||
use uv_distribution_types::{IndexUrl, InstalledDist};
|
||||
use uv_distribution_types::{IndexUrl, InstalledDist, InstalledDistKind};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::{Operator, Version};
|
||||
use uv_pep508::{MarkerTree, VerbatimUrl, VersionOrUrl};
|
||||
|
|
@ -122,7 +122,7 @@ impl Preference {
|
|||
|
||||
/// Create a [`Preference`] from an installed distribution.
|
||||
pub fn from_installed(dist: &InstalledDist) -> Option<Self> {
|
||||
let InstalledDist::Registry(dist) = dist else {
|
||||
let InstalledDistKind::Registry(dist) = &dist.kind else {
|
||||
return None;
|
||||
};
|
||||
Some(Self {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
|||
use owo_colors::OwoColorize;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_distribution_types::{Diagnostic, InstalledDist, Name};
|
||||
use uv_distribution_types::{Diagnostic, InstalledDistKind, Name};
|
||||
use uv_installer::SitePackages;
|
||||
use uv_preview::Preview;
|
||||
use uv_python::PythonPreference;
|
||||
|
|
@ -61,24 +61,24 @@ pub(crate) fn pip_freeze(
|
|||
.flat_map(uv_installer::SitePackages::iter)
|
||||
.filter(|dist| !(exclude_editable && dist.is_editable()))
|
||||
.sorted_unstable_by(|a, b| a.name().cmp(b.name()).then(a.version().cmp(b.version())))
|
||||
.map(|dist| match dist {
|
||||
InstalledDist::Registry(dist) => {
|
||||
.map(|dist| match &dist.kind {
|
||||
InstalledDistKind::Registry(dist) => {
|
||||
format!("{}=={}", dist.name().bold(), dist.version)
|
||||
}
|
||||
InstalledDist::Url(dist) => {
|
||||
InstalledDistKind::Url(dist) => {
|
||||
if dist.editable {
|
||||
format!("-e {}", dist.url)
|
||||
} else {
|
||||
format!("{} @ {}", dist.name().bold(), dist.url)
|
||||
}
|
||||
}
|
||||
InstalledDist::EggInfoFile(dist) => {
|
||||
InstalledDistKind::EggInfoFile(dist) => {
|
||||
format!("{}=={}", dist.name().bold(), dist.version)
|
||||
}
|
||||
InstalledDist::EggInfoDirectory(dist) => {
|
||||
InstalledDistKind::EggInfoDirectory(dist) => {
|
||||
format!("{}=={}", dist.name().bold(), dist.version)
|
||||
}
|
||||
InstalledDist::LegacyEditable(dist) => {
|
||||
InstalledDistKind::LegacyEditable(dist) => {
|
||||
format!("-e {}", dist.target.display())
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -389,6 +389,9 @@ pub(crate) struct Changelog {
|
|||
impl Changelog {
|
||||
/// Create a [`Changelog`] from a list of installed and uninstalled distributions.
|
||||
pub(crate) fn new(installed: Vec<CachedDist>, uninstalled: Vec<InstalledDist>) -> Self {
|
||||
// SAFETY: This is allowed because `LocalDist` implements `Hash` and `Eq` based solely on
|
||||
// the inner `kind`, and omits the types that rely on internal mutability.
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
let mut uninstalled: HashSet<_> = uninstalled.into_iter().map(LocalDist::from).collect();
|
||||
|
||||
let (reinstalled, installed): (HashSet<_>, HashSet<_>) = installed
|
||||
|
|
|
|||
|
|
@ -102,9 +102,11 @@ pub(crate) fn pip_show(
|
|||
if let Ok(metadata) = dist.read_metadata() {
|
||||
requires_map.insert(
|
||||
dist.name(),
|
||||
Box::into_iter(metadata.requires_dist)
|
||||
metadata
|
||||
.requires_dist
|
||||
.iter()
|
||||
.filter(|req| req.evaluate_markers(&markers, &[]))
|
||||
.map(|req| req.name)
|
||||
.map(|req| &req.name)
|
||||
.sorted_unstable()
|
||||
.dedup()
|
||||
.collect_vec(),
|
||||
|
|
@ -118,9 +120,11 @@ pub(crate) fn pip_show(
|
|||
continue;
|
||||
}
|
||||
if let Ok(metadata) = installed.read_metadata() {
|
||||
let requires = Box::into_iter(metadata.requires_dist)
|
||||
let requires = metadata
|
||||
.requires_dist
|
||||
.iter()
|
||||
.filter(|req| req.evaluate_markers(&markers, &[]))
|
||||
.map(|req| req.name)
|
||||
.map(|req| &req.name)
|
||||
.collect_vec();
|
||||
if !requires.is_empty() {
|
||||
requires_map.insert(installed.name(), requires);
|
||||
|
|
@ -172,7 +176,7 @@ pub(crate) fn pip_show(
|
|||
.iter()
|
||||
.filter(|(name, pkgs)| {
|
||||
**name != distribution.name()
|
||||
&& pkgs.iter().any(|pkg| pkg == distribution.name())
|
||||
&& pkgs.iter().any(|pkg| *pkg == distribution.name())
|
||||
})
|
||||
.map(|(name, _)| name)
|
||||
.sorted_unstable()
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ impl<'env> DisplayDependencyGraph<'env> {
|
|||
invert: bool,
|
||||
show_version_specifiers: bool,
|
||||
markers: &ResolverMarkerEnvironment,
|
||||
packages: &'env FxHashMap<&PackageName, Vec<ResolutionMetadata>>,
|
||||
packages: &'env FxHashMap<&PackageName, Vec<&ResolutionMetadata>>,
|
||||
latest: &'env FxHashMap<&PackageName, Version>,
|
||||
) -> Self {
|
||||
// Create a graph.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue