use std::borrow::Cow;
use std::path;
use std::path::Path;
use std::str::FromStr;
use url::Url;
use uv_distribution_filename::{
DistExtension, SourceDistExtension, SourceDistFilename, WheelFilename,
};
use uv_fs::normalize_absolute_path;
use uv_git_types::GitUrl;
use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_pep508::{Pep508Url, VerbatimUrl};
use uv_pypi_types::{
ParsedArchiveUrl, ParsedDirectoryUrl, ParsedGitUrl, ParsedPathUrl, ParsedUrl, VerbatimParsedUrl,
};
use uv_redacted::DisplaySafeUrl;
pub use crate::annotation::*;
pub use crate::any::*;
pub use crate::build_info::*;
pub use crate::build_requires::*;
pub use crate::buildable::*;
pub use crate::cached::*;
pub use crate::config_settings::*;
pub use crate::dependency_metadata::*;
pub use crate::diagnostic::*;
pub use crate::dist_error::*;
pub use crate::error::*;
pub use crate::file::*;
pub use crate::hash::*;
pub use crate::id::*;
pub use crate::index::*;
pub use crate::index_name::*;
pub use crate::index_url::*;
pub use crate::installed::*;
pub use crate::known_platform::*;
pub use crate::origin::*;
pub use crate::pip_index::*;
pub use crate::prioritized_distribution::*;
pub use crate::requested::*;
pub use crate::requirement::*;
pub use crate::requires_python::*;
pub use crate::resolution::*;
pub use crate::resolved::*;
pub use crate::specified_requirement::*;
pub use crate::status_code_strategy::*;
pub use crate::traits::*;
mod annotation;
mod any;
mod build_info;
mod build_requires;
mod buildable;
mod cached;
mod config_settings;
mod dependency_metadata;
mod diagnostic;
mod dist_error;
mod error;
mod file;
mod hash;
mod id;
mod index;
mod index_name;
mod index_url;
mod installed;
mod known_platform;
mod origin;
mod pip_index;
mod prioritized_distribution;
mod requested;
mod requirement;
mod requires_python;
mod resolution;
mod resolved;
mod specified_requirement;
mod status_code_strategy;
mod traits;
#[derive(Debug, Clone)]
pub enum VersionOrUrlRef<'a, T: Pep508Url = VerbatimUrl> {
Version(&'a Version),
Url(&'a T),
}
impl<T: Pep508Url> VersionOrUrlRef<'_, T> {
pub fn url(&self) -> Option<&T> {
match self {
Self::Version(_) => None,
Self::Url(url) => Some(url),
}
}
}
impl Verbatim for VersionOrUrlRef<'_> {
fn verbatim(&self) -> Cow<'_, str> {
match self {
Self::Version(version) => Cow::Owned(format!("=={version}")),
Self::Url(url) => Cow::Owned(format!(" @ {}", url.verbatim())),
}
}
}
impl std::fmt::Display for VersionOrUrlRef<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Version(version) => write!(f, "=={version}"),
Self::Url(url) => write!(f, " @ {url}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum InstalledVersion<'a> {
Version(&'a Version),
Url(&'a DisplaySafeUrl, &'a Version),
}
impl InstalledVersion<'_> {
pub fn url(&self) -> Option<&DisplaySafeUrl> {
match self {
Self::Version(_) => None,
Self::Url(url, _) => Some(url),
}
}
pub fn version(&self) -> &Version {
match self {
Self::Version(version) => version,
Self::Url(_, version) => version,
}
}
}
impl std::fmt::Display for InstalledVersion<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Version(version) => write!(f, "=={version}"),
Self::Url(url, version) => write!(f, "=={version} (from {url})"),
}
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Dist {
Built(BuiltDist),
Source(SourceDist),
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum DistRef<'a> {
Built(&'a BuiltDist),
Source(&'a SourceDist),
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum BuiltDist {
Registry(RegistryBuiltDist),
DirectUrl(DirectUrlBuiltDist),
Path(PathBuiltDist),
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum SourceDist {
Registry(RegistrySourceDist),
DirectUrl(DirectUrlSourceDist),
Git(GitSourceDist),
Path(PathSourceDist),
Directory(DirectorySourceDist),
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct RegistryBuiltWheel {
pub filename: WheelFilename,
pub file: Box<File>,
pub index: IndexUrl,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct RegistryBuiltDist {
pub wheels: Vec<RegistryBuiltWheel>,
pub best_wheel_index: usize,
pub sdist: Option<RegistrySourceDist>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DirectUrlBuiltDist {
pub filename: WheelFilename,
pub location: Box<DisplaySafeUrl>,
pub url: VerbatimUrl,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct PathBuiltDist {
pub filename: WheelFilename,
pub install_path: Box<Path>,
pub url: VerbatimUrl,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct RegistrySourceDist {
pub name: PackageName,
pub version: Version,
pub file: Box<File>,
pub ext: SourceDistExtension,
pub index: IndexUrl,
pub wheels: Vec<RegistryBuiltWheel>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DirectUrlSourceDist {
pub name: PackageName,
pub location: Box<DisplaySafeUrl>,
pub subdirectory: Option<Box<Path>>,
pub ext: SourceDistExtension,
pub url: VerbatimUrl,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct GitSourceDist {
pub name: PackageName,
pub git: Box<GitUrl>,
pub subdirectory: Option<Box<Path>>,
pub url: VerbatimUrl,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct PathSourceDist {
pub name: PackageName,
pub version: Option<Version>,
pub install_path: Box<Path>,
pub ext: SourceDistExtension,
pub url: VerbatimUrl,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DirectorySourceDist {
pub name: PackageName,
pub install_path: Box<Path>,
pub editable: Option<bool>,
pub r#virtual: Option<bool>,
pub url: VerbatimUrl,
}
impl Dist {
pub fn from_http_url(
name: PackageName,
url: VerbatimUrl,
location: DisplaySafeUrl,
subdirectory: Option<Box<Path>>,
ext: DistExtension,
) -> Result<Self, Error> {
match ext {
DistExtension::Wheel => {
let filename = WheelFilename::from_str(&url.filename()?)?;
if filename.name != name {
return Err(Error::PackageNameMismatch(
name,
filename.name,
url.verbatim().to_string(),
));
}
Ok(Self::Built(BuiltDist::DirectUrl(DirectUrlBuiltDist {
filename,
location: Box::new(location),
url,
})))
}
DistExtension::Source(ext) => {
Ok(Self::Source(SourceDist::DirectUrl(DirectUrlSourceDist {
name,
location: Box::new(location),
subdirectory,
ext,
url,
})))
}
}
}
pub fn from_file_url(
name: PackageName,
url: VerbatimUrl,
install_path: &Path,
ext: DistExtension,
) -> Result<Self, Error> {
let install_path = path::absolute(install_path)?;
let install_path = normalize_absolute_path(&install_path)?;
if !install_path.exists() {
return Err(Error::NotFound(url.to_url()));
}
match ext {
DistExtension::Wheel => {
let filename = WheelFilename::from_str(&url.filename()?)?;
if filename.name != name {
return Err(Error::PackageNameMismatch(
name,
filename.name,
url.verbatim().to_string(),
));
}
Ok(Self::Built(BuiltDist::Path(PathBuiltDist {
filename,
install_path: install_path.into_boxed_path(),
url,
})))
}
DistExtension::Source(ext) => {
let version = url
.filename()
.ok()
.and_then(|filename| {
SourceDistFilename::parse(filename.as_ref(), ext, &name).ok()
})
.map(|filename| filename.version);
Ok(Self::Source(SourceDist::Path(PathSourceDist {
name,
version,
install_path: install_path.into_boxed_path(),
ext,
url,
})))
}
}
}
pub fn from_directory_url(
name: PackageName,
url: VerbatimUrl,
install_path: &Path,
editable: Option<bool>,
r#virtual: Option<bool>,
) -> Result<Self, Error> {
let install_path = path::absolute(install_path)?;
let install_path = normalize_absolute_path(&install_path)?;
if !install_path.exists() {
return Err(Error::NotFound(url.to_url()));
}
Ok(Self::Source(SourceDist::Directory(DirectorySourceDist {
name,
install_path: install_path.into_boxed_path(),
editable,
r#virtual,
url,
})))
}
pub fn from_git_url(
name: PackageName,
url: VerbatimUrl,
git: GitUrl,
subdirectory: Option<Box<Path>>,
) -> Result<Self, Error> {
Ok(Self::Source(SourceDist::Git(GitSourceDist {
name,
git: Box::new(git),
subdirectory,
url,
})))
}
pub fn from_url(name: PackageName, url: VerbatimParsedUrl) -> Result<Self, Error> {
match url.parsed_url {
ParsedUrl::Archive(archive) => Self::from_http_url(
name,
url.verbatim,
archive.url,
archive.subdirectory,
archive.ext,
),
ParsedUrl::Path(file) => {
Self::from_file_url(name, url.verbatim, &file.install_path, file.ext)
}
ParsedUrl::Directory(directory) => Self::from_directory_url(
name,
url.verbatim,
&directory.install_path,
directory.editable,
directory.r#virtual,
),
ParsedUrl::Git(git) => {
Self::from_git_url(name, url.verbatim, git.url, git.subdirectory)
}
}
}
pub fn is_editable(&self) -> bool {
match self {
Self::Source(dist) => dist.is_editable(),
Self::Built(_) => false,
}
}
pub fn is_local(&self) -> bool {
match self {
Self::Source(dist) => dist.is_local(),
Self::Built(dist) => dist.is_local(),
}
}
pub fn index(&self) -> Option<&IndexUrl> {
match self {
Self::Built(dist) => dist.index(),
Self::Source(dist) => dist.index(),
}
}
pub fn file(&self) -> Option<&File> {
match self {
Self::Built(built) => built.file(),
Self::Source(source) => source.file(),
}
}
pub fn source_tree(&self) -> Option<&Path> {
match self {
Self::Built { .. } => None,
Self::Source(source) => source.source_tree(),
}
}
pub fn version(&self) -> Option<&Version> {
match self {
Self::Built(wheel) => Some(wheel.version()),
Self::Source(source_dist) => source_dist.version(),
}
}
pub fn as_ref(&self) -> DistRef<'_> {
match self {
Self::Built(dist) => DistRef::Built(dist),
Self::Source(dist) => DistRef::Source(dist),
}
}
}
impl<'a> From<&'a Dist> for DistRef<'a> {
fn from(dist: &'a Dist) -> Self {
match dist {
Dist::Built(built) => DistRef::Built(built),
Dist::Source(source) => DistRef::Source(source),
}
}
}
impl<'a> From<&'a SourceDist> for DistRef<'a> {
fn from(dist: &'a SourceDist) -> Self {
DistRef::Source(dist)
}
}
impl<'a> From<&'a BuiltDist> for DistRef<'a> {
fn from(dist: &'a BuiltDist) -> Self {
DistRef::Built(dist)
}
}
impl BuiltDist {
pub fn is_local(&self) -> bool {
matches!(self, Self::Path(_))
}
pub fn index(&self) -> Option<&IndexUrl> {
match self {
Self::Registry(registry) => Some(®istry.best_wheel().index),
Self::DirectUrl(_) => None,
Self::Path(_) => None,
}
}
pub fn file(&self) -> Option<&File> {
match self {
Self::Registry(registry) => Some(®istry.best_wheel().file),
Self::DirectUrl(_) | Self::Path(_) => None,
}
}
pub fn version(&self) -> &Version {
match self {
Self::Registry(wheels) => &wheels.best_wheel().filename.version,
Self::DirectUrl(wheel) => &wheel.filename.version,
Self::Path(wheel) => &wheel.filename.version,
}
}
}
impl SourceDist {
pub fn index(&self) -> Option<&IndexUrl> {
match self {
Self::Registry(registry) => Some(®istry.index),
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) | Self::Directory(_) => None,
}
}
pub fn file(&self) -> Option<&File> {
match self {
Self::Registry(registry) => Some(®istry.file),
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) | Self::Directory(_) => None,
}
}
pub fn version(&self) -> Option<&Version> {
match self {
Self::Registry(source_dist) => Some(&source_dist.version),
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) | Self::Directory(_) => None,
}
}
pub fn is_editable(&self) -> bool {
match self {
Self::Directory(DirectorySourceDist { editable, .. }) => editable.unwrap_or(false),
_ => false,
}
}
pub fn is_virtual(&self) -> bool {
match self {
Self::Directory(DirectorySourceDist { r#virtual, .. }) => r#virtual.unwrap_or(false),
_ => false,
}
}
pub fn is_local(&self) -> bool {
matches!(self, Self::Directory(_) | Self::Path(_))
}
pub fn as_path(&self) -> Option<&Path> {
match self {
Self::Path(dist) => Some(&dist.install_path),
Self::Directory(dist) => Some(&dist.install_path),
_ => None,
}
}
pub fn source_tree(&self) -> Option<&Path> {
match self {
Self::Directory(dist) => Some(&dist.install_path),
_ => None,
}
}
}
impl RegistryBuiltDist {
pub fn best_wheel(&self) -> &RegistryBuiltWheel {
&self.wheels[self.best_wheel_index]
}
}
impl DirectUrlBuiltDist {
pub fn parsed_url(&self) -> ParsedUrl {
ParsedUrl::Archive(ParsedArchiveUrl::from_source(
(*self.location).clone(),
None,
DistExtension::Wheel,
))
}
}
impl PathBuiltDist {
pub fn parsed_url(&self) -> ParsedUrl {
ParsedUrl::Path(ParsedPathUrl::from_source(
self.install_path.clone(),
DistExtension::Wheel,
self.url.to_url(),
))
}
}
impl PathSourceDist {
pub fn parsed_url(&self) -> ParsedUrl {
ParsedUrl::Path(ParsedPathUrl::from_source(
self.install_path.clone(),
DistExtension::Source(self.ext),
self.url.to_url(),
))
}
}
impl DirectUrlSourceDist {
pub fn parsed_url(&self) -> ParsedUrl {
ParsedUrl::Archive(ParsedArchiveUrl::from_source(
(*self.location).clone(),
self.subdirectory.clone(),
DistExtension::Source(self.ext),
))
}
}
impl GitSourceDist {
pub fn parsed_url(&self) -> ParsedUrl {
ParsedUrl::Git(ParsedGitUrl::from_source(
(*self.git).clone(),
self.subdirectory.clone(),
))
}
}
impl DirectorySourceDist {
pub fn parsed_url(&self) -> ParsedUrl {
ParsedUrl::Directory(ParsedDirectoryUrl::from_source(
self.install_path.clone(),
self.editable,
self.r#virtual,
self.url.to_url(),
))
}
}
impl Name for RegistryBuiltWheel {
fn name(&self) -> &PackageName {
&self.filename.name
}
}
impl Name for RegistryBuiltDist {
fn name(&self) -> &PackageName {
self.best_wheel().name()
}
}
impl Name for DirectUrlBuiltDist {
fn name(&self) -> &PackageName {
&self.filename.name
}
}
impl Name for PathBuiltDist {
fn name(&self) -> &PackageName {
&self.filename.name
}
}
impl Name for RegistrySourceDist {
fn name(&self) -> &PackageName {
&self.name
}
}
impl Name for DirectUrlSourceDist {
fn name(&self) -> &PackageName {
&self.name
}
}
impl Name for GitSourceDist {
fn name(&self) -> &PackageName {
&self.name
}
}
impl Name for PathSourceDist {
fn name(&self) -> &PackageName {
&self.name
}
}
impl Name for DirectorySourceDist {
fn name(&self) -> &PackageName {
&self.name
}
}
impl Name for SourceDist {
fn name(&self) -> &PackageName {
match self {
Self::Registry(dist) => dist.name(),
Self::DirectUrl(dist) => dist.name(),
Self::Git(dist) => dist.name(),
Self::Path(dist) => dist.name(),
Self::Directory(dist) => dist.name(),
}
}
}
impl Name for BuiltDist {
fn name(&self) -> &PackageName {
match self {
Self::Registry(dist) => dist.name(),
Self::DirectUrl(dist) => dist.name(),
Self::Path(dist) => dist.name(),
}
}
}
impl Name for Dist {
fn name(&self) -> &PackageName {
match self {
Self::Built(dist) => dist.name(),
Self::Source(dist) => dist.name(),
}
}
}
impl Name for CompatibleDist<'_> {
fn name(&self) -> &PackageName {
match self {
Self::InstalledDist(dist) => dist.name(),
Self::SourceDist {
sdist,
prioritized: _,
} => sdist.name(),
Self::CompatibleWheel {
wheel,
priority: _,
prioritized: _,
} => wheel.name(),
Self::IncompatibleWheel {
sdist,
wheel: _,
prioritized: _,
} => sdist.name(),
}
}
}
impl DistributionMetadata for RegistryBuiltWheel {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Version(&self.filename.version)
}
}
impl DistributionMetadata for RegistryBuiltDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
self.best_wheel().version_or_url()
}
}
impl DistributionMetadata for DirectUrlBuiltDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Url(&self.url)
}
}
impl DistributionMetadata for PathBuiltDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Url(&self.url)
}
}
impl DistributionMetadata for RegistrySourceDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Version(&self.version)
}
}
impl DistributionMetadata for DirectUrlSourceDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Url(&self.url)
}
}
impl DistributionMetadata for GitSourceDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Url(&self.url)
}
}
impl DistributionMetadata for PathSourceDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Url(&self.url)
}
}
impl DistributionMetadata for DirectorySourceDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
VersionOrUrlRef::Url(&self.url)
}
}
impl DistributionMetadata for SourceDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
match self {
Self::Registry(dist) => dist.version_or_url(),
Self::DirectUrl(dist) => dist.version_or_url(),
Self::Git(dist) => dist.version_or_url(),
Self::Path(dist) => dist.version_or_url(),
Self::Directory(dist) => dist.version_or_url(),
}
}
}
impl DistributionMetadata for BuiltDist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
match self {
Self::Registry(dist) => dist.version_or_url(),
Self::DirectUrl(dist) => dist.version_or_url(),
Self::Path(dist) => dist.version_or_url(),
}
}
}
impl DistributionMetadata for Dist {
fn version_or_url(&self) -> VersionOrUrlRef<'_> {
match self {
Self::Built(dist) => dist.version_or_url(),
Self::Source(dist) => dist.version_or_url(),
}
}
}
impl RemoteSource for File {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
Ok(Cow::Borrowed(&self.filename))
}
fn size(&self) -> Option<u64> {
self.size
}
}
impl RemoteSource for Url {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
let mut path_segments = self
.path_segments()
.ok_or_else(|| Error::MissingPathSegments(self.to_string()))?;
let last = path_segments
.next_back()
.expect("path segments is non-empty");
let filename = percent_encoding::percent_decode_str(last).decode_utf8()?;
Ok(filename)
}
fn size(&self) -> Option<u64> {
None
}
}
impl RemoteSource for UrlString {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
let last = self
.base_str()
.split('/')
.next_back()
.ok_or_else(|| Error::MissingPathSegments(self.to_string()))?;
let filename = percent_encoding::percent_decode_str(last).decode_utf8()?;
Ok(filename)
}
fn size(&self) -> Option<u64> {
None
}
}
impl RemoteSource for RegistryBuiltWheel {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.file.filename()
}
fn size(&self) -> Option<u64> {
self.file.size()
}
}
impl RemoteSource for RegistryBuiltDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.best_wheel().filename()
}
fn size(&self) -> Option<u64> {
self.best_wheel().size()
}
}
impl RemoteSource for RegistrySourceDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.file.filename()
}
fn size(&self) -> Option<u64> {
self.file.size()
}
}
impl RemoteSource for DirectUrlBuiltDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.url.filename()
}
fn size(&self) -> Option<u64> {
self.url.size()
}
}
impl RemoteSource for DirectUrlSourceDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.url.filename()
}
fn size(&self) -> Option<u64> {
self.url.size()
}
}
impl RemoteSource for GitSourceDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
match self.url.filename()? {
Cow::Borrowed(filename) => {
if let Some((_, filename)) = filename.rsplit_once('@') {
Ok(Cow::Borrowed(filename))
} else {
Ok(Cow::Borrowed(filename))
}
}
Cow::Owned(filename) => {
if let Some((_, filename)) = filename.rsplit_once('@') {
Ok(Cow::Owned(filename.to_owned()))
} else {
Ok(Cow::Owned(filename))
}
}
}
}
fn size(&self) -> Option<u64> {
self.url.size()
}
}
impl RemoteSource for PathBuiltDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.url.filename()
}
fn size(&self) -> Option<u64> {
self.url.size()
}
}
impl RemoteSource for PathSourceDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.url.filename()
}
fn size(&self) -> Option<u64> {
self.url.size()
}
}
impl RemoteSource for DirectorySourceDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
self.url.filename()
}
fn size(&self) -> Option<u64> {
self.url.size()
}
}
impl RemoteSource for SourceDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
match self {
Self::Registry(dist) => dist.filename(),
Self::DirectUrl(dist) => dist.filename(),
Self::Git(dist) => dist.filename(),
Self::Path(dist) => dist.filename(),
Self::Directory(dist) => dist.filename(),
}
}
fn size(&self) -> Option<u64> {
match self {
Self::Registry(dist) => dist.size(),
Self::DirectUrl(dist) => dist.size(),
Self::Git(dist) => dist.size(),
Self::Path(dist) => dist.size(),
Self::Directory(dist) => dist.size(),
}
}
}
impl RemoteSource for BuiltDist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
match self {
Self::Registry(dist) => dist.filename(),
Self::DirectUrl(dist) => dist.filename(),
Self::Path(dist) => dist.filename(),
}
}
fn size(&self) -> Option<u64> {
match self {
Self::Registry(dist) => dist.size(),
Self::DirectUrl(dist) => dist.size(),
Self::Path(dist) => dist.size(),
}
}
}
impl RemoteSource for Dist {
fn filename(&self) -> Result<Cow<'_, str>, Error> {
match self {
Self::Built(dist) => dist.filename(),
Self::Source(dist) => dist.filename(),
}
}
fn size(&self) -> Option<u64> {
match self {
Self::Built(dist) => dist.size(),
Self::Source(dist) => dist.size(),
}
}
}
impl Identifier for DisplaySafeUrl {
fn distribution_id(&self) -> DistributionId {
DistributionId::Url(uv_cache_key::CanonicalUrl::new(self))
}
fn resource_id(&self) -> ResourceId {
ResourceId::Url(uv_cache_key::RepositoryUrl::new(self))
}
}
impl Identifier for File {
fn distribution_id(&self) -> DistributionId {
self.hashes
.first()
.cloned()
.map(DistributionId::Digest)
.unwrap_or_else(|| self.url.distribution_id())
}
fn resource_id(&self) -> ResourceId {
self.hashes
.first()
.cloned()
.map(ResourceId::Digest)
.unwrap_or_else(|| self.url.resource_id())
}
}
impl Identifier for Path {
fn distribution_id(&self) -> DistributionId {
DistributionId::PathBuf(self.to_path_buf())
}
fn resource_id(&self) -> ResourceId {
ResourceId::PathBuf(self.to_path_buf())
}
}
impl Identifier for FileLocation {
fn distribution_id(&self) -> DistributionId {
match self {
Self::RelativeUrl(base, url) => {
DistributionId::RelativeUrl(base.to_string(), url.to_string())
}
Self::AbsoluteUrl(url) => DistributionId::AbsoluteUrl(url.to_string()),
}
}
fn resource_id(&self) -> ResourceId {
match self {
Self::RelativeUrl(base, url) => {
ResourceId::RelativeUrl(base.to_string(), url.to_string())
}
Self::AbsoluteUrl(url) => ResourceId::AbsoluteUrl(url.to_string()),
}
}
}
impl Identifier for RegistryBuiltWheel {
fn distribution_id(&self) -> DistributionId {
self.file.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.file.resource_id()
}
}
impl Identifier for RegistryBuiltDist {
fn distribution_id(&self) -> DistributionId {
self.best_wheel().distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.best_wheel().resource_id()
}
}
impl Identifier for RegistrySourceDist {
fn distribution_id(&self) -> DistributionId {
self.file.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.file.resource_id()
}
}
impl Identifier for DirectUrlBuiltDist {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for DirectUrlSourceDist {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for PathBuiltDist {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for PathSourceDist {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for DirectorySourceDist {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for GitSourceDist {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for SourceDist {
fn distribution_id(&self) -> DistributionId {
match self {
Self::Registry(dist) => dist.distribution_id(),
Self::DirectUrl(dist) => dist.distribution_id(),
Self::Git(dist) => dist.distribution_id(),
Self::Path(dist) => dist.distribution_id(),
Self::Directory(dist) => dist.distribution_id(),
}
}
fn resource_id(&self) -> ResourceId {
match self {
Self::Registry(dist) => dist.resource_id(),
Self::DirectUrl(dist) => dist.resource_id(),
Self::Git(dist) => dist.resource_id(),
Self::Path(dist) => dist.resource_id(),
Self::Directory(dist) => dist.resource_id(),
}
}
}
impl Identifier for BuiltDist {
fn distribution_id(&self) -> DistributionId {
match self {
Self::Registry(dist) => dist.distribution_id(),
Self::DirectUrl(dist) => dist.distribution_id(),
Self::Path(dist) => dist.distribution_id(),
}
}
fn resource_id(&self) -> ResourceId {
match self {
Self::Registry(dist) => dist.resource_id(),
Self::DirectUrl(dist) => dist.resource_id(),
Self::Path(dist) => dist.resource_id(),
}
}
}
impl Identifier for InstalledDist {
fn distribution_id(&self) -> DistributionId {
self.install_path().distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.install_path().resource_id()
}
}
impl Identifier for Dist {
fn distribution_id(&self) -> DistributionId {
match self {
Self::Built(dist) => dist.distribution_id(),
Self::Source(dist) => dist.distribution_id(),
}
}
fn resource_id(&self) -> ResourceId {
match self {
Self::Built(dist) => dist.resource_id(),
Self::Source(dist) => dist.resource_id(),
}
}
}
impl Identifier for DirectSourceUrl<'_> {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for GitSourceUrl<'_> {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for PathSourceUrl<'_> {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for DirectorySourceUrl<'_> {
fn distribution_id(&self) -> DistributionId {
self.url.distribution_id()
}
fn resource_id(&self) -> ResourceId {
self.url.resource_id()
}
}
impl Identifier for SourceUrl<'_> {
fn distribution_id(&self) -> DistributionId {
match self {
Self::Direct(url) => url.distribution_id(),
Self::Git(url) => url.distribution_id(),
Self::Path(url) => url.distribution_id(),
Self::Directory(url) => url.distribution_id(),
}
}
fn resource_id(&self) -> ResourceId {
match self {
Self::Direct(url) => url.resource_id(),
Self::Git(url) => url.resource_id(),
Self::Path(url) => url.resource_id(),
Self::Directory(url) => url.resource_id(),
}
}
}
impl Identifier for BuildableSource<'_> {
fn distribution_id(&self) -> DistributionId {
match self {
Self::Dist(source) => source.distribution_id(),
Self::Url(source) => source.distribution_id(),
}
}
fn resource_id(&self) -> ResourceId {
match self {
Self::Dist(source) => source.resource_id(),
Self::Url(source) => source.resource_id(),
}
}
}
#[cfg(test)]
mod test {
use crate::{BuiltDist, Dist, RemoteSource, SourceDist, UrlString};
use uv_redacted::DisplaySafeUrl;
#[test]
fn dist_size() {
assert!(size_of::<Dist>() <= 200, "{}", size_of::<Dist>());
assert!(size_of::<BuiltDist>() <= 200, "{}", size_of::<BuiltDist>());
assert!(
size_of::<SourceDist>() <= 176,
"{}",
size_of::<SourceDist>()
);
}
#[test]
fn remote_source() {
for url in [
"https://example.com/foo-0.1.0.tar.gz",
"https://example.com/foo-0.1.0.tar.gz#fragment",
"https://example.com/foo-0.1.0.tar.gz?query",
"https://example.com/foo-0.1.0.tar.gz?query#fragment",
"https://example.com/foo-0.1.0.tar.gz?query=1/2#fragment",
"https://example.com/foo-0.1.0.tar.gz?query=1/2#fragment/3",
] {
let url = DisplaySafeUrl::parse(url).unwrap();
assert_eq!(url.filename().unwrap(), "foo-0.1.0.tar.gz", "{url}");
let url = UrlString::from(url.clone());
assert_eq!(url.filename().unwrap(), "foo-0.1.0.tar.gz", "{url}");
}
}
}