mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-02 12:59:45 +00:00
Make Directory its own distribution kind (#3519)
## Summary I think this is overall good change because it explicitly encodes (in the type system) something that was previously implicit. I'm not a huge fan of the names here, open to input. It covers some of https://github.com/astral-sh/uv/issues/3506 but I don't think it _closes_ it.
This commit is contained in:
parent
6bbfe555be
commit
42c3bfa351
16 changed files with 434 additions and 163 deletions
|
|
@ -6,7 +6,7 @@ use url::Url;
|
|||
|
||||
use uv_normalize::PackageName;
|
||||
|
||||
use crate::{GitSourceDist, Name, PathSourceDist, SourceDist};
|
||||
use crate::{DirectorySourceDist, GitSourceDist, Name, PathSourceDist, SourceDist};
|
||||
|
||||
/// A reference to a source that can be built into a built distribution.
|
||||
///
|
||||
|
|
@ -62,6 +62,7 @@ pub enum SourceUrl<'a> {
|
|||
Direct(DirectSourceUrl<'a>),
|
||||
Git(GitSourceUrl<'a>),
|
||||
Path(PathSourceUrl<'a>),
|
||||
Directory(DirectorySourceUrl<'a>),
|
||||
}
|
||||
|
||||
impl<'a> SourceUrl<'a> {
|
||||
|
|
@ -71,6 +72,7 @@ impl<'a> SourceUrl<'a> {
|
|||
Self::Direct(dist) => dist.url,
|
||||
Self::Git(dist) => dist.url,
|
||||
Self::Path(dist) => dist.url,
|
||||
Self::Directory(dist) => dist.url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -81,6 +83,7 @@ impl std::fmt::Display for SourceUrl<'_> {
|
|||
Self::Direct(url) => write!(f, "{url}"),
|
||||
Self::Git(url) => write!(f, "{url}"),
|
||||
Self::Path(url) => write!(f, "{url}"),
|
||||
Self::Directory(url) => write!(f, "{url}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -133,3 +136,24 @@ impl<'a> From<&'a PathSourceDist> for PathSourceUrl<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DirectorySourceUrl<'a> {
|
||||
pub url: &'a Url,
|
||||
pub path: Cow<'a, Path>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DirectorySourceUrl<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{url}", url = self.url)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a DirectorySourceDist> for DirectorySourceUrl<'a> {
|
||||
fn from(dist: &'a DirectorySourceDist) -> Self {
|
||||
Self {
|
||||
url: &dist.url,
|
||||
path: Cow::Borrowed(&dist.path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,13 @@ impl CachedDist {
|
|||
editable: false,
|
||||
}),
|
||||
Dist::Source(SourceDist::Path(dist)) => Self::Url(CachedDirectUrlDist {
|
||||
filename,
|
||||
url: dist.url,
|
||||
hashes,
|
||||
path,
|
||||
editable: false,
|
||||
}),
|
||||
Dist::Source(SourceDist::Directory(dist)) => Self::Url(CachedDirectUrlDist {
|
||||
filename,
|
||||
url: dist.url,
|
||||
hashes,
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ pub enum SourceDist {
|
|||
DirectUrl(DirectUrlSourceDist),
|
||||
Git(GitSourceDist),
|
||||
Path(PathSourceDist),
|
||||
Directory(DirectorySourceDist),
|
||||
}
|
||||
|
||||
/// A built distribution (wheel) that exists in a registry, like `PyPI`.
|
||||
|
|
@ -203,12 +204,20 @@ pub struct GitSourceDist {
|
|||
pub url: VerbatimUrl,
|
||||
}
|
||||
|
||||
/// A source distribution that exists in a local directory.
|
||||
/// A source distribution that exists in a local archive (e.g., a `.tar.gz` file).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PathSourceDist {
|
||||
pub name: PackageName,
|
||||
pub url: VerbatimUrl,
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
/// A source distribution that exists in a local directory.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DirectorySourceDist {
|
||||
pub name: PackageName,
|
||||
pub url: VerbatimUrl,
|
||||
pub path: PathBuf,
|
||||
pub editable: bool,
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +290,15 @@ impl Dist {
|
|||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
|
||||
if path
|
||||
// Determine whether the path represents an archive or a directory.
|
||||
if path.is_dir() {
|
||||
Ok(Self::Source(SourceDist::Directory(DirectorySourceDist {
|
||||
name,
|
||||
url,
|
||||
path,
|
||||
editable,
|
||||
})))
|
||||
} else if path
|
||||
.extension()
|
||||
.is_some_and(|ext| ext.eq_ignore_ascii_case("whl"))
|
||||
{
|
||||
|
|
@ -305,11 +322,14 @@ impl Dist {
|
|||
path,
|
||||
})))
|
||||
} else {
|
||||
if editable {
|
||||
return Err(Error::EditableFile(url));
|
||||
}
|
||||
|
||||
Ok(Self::Source(SourceDist::Path(PathSourceDist {
|
||||
name,
|
||||
url,
|
||||
path,
|
||||
editable,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
|
@ -382,7 +402,7 @@ impl Dist {
|
|||
/// Create a [`Dist`] for a local editable distribution.
|
||||
pub fn from_editable(name: PackageName, editable: LocalEditable) -> Result<Self, Error> {
|
||||
let LocalEditable { url, path, .. } = editable;
|
||||
Ok(Self::Source(SourceDist::Path(PathSourceDist {
|
||||
Ok(Self::Source(SourceDist::Directory(DirectorySourceDist {
|
||||
name,
|
||||
url,
|
||||
path,
|
||||
|
|
@ -454,7 +474,7 @@ impl SourceDist {
|
|||
pub fn index(&self) -> Option<&IndexUrl> {
|
||||
match self {
|
||||
Self::Registry(registry) => Some(®istry.index),
|
||||
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) => None,
|
||||
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) | Self::Directory(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -462,14 +482,14 @@ impl SourceDist {
|
|||
pub fn file(&self) -> Option<&File> {
|
||||
match self {
|
||||
Self::Registry(registry) => Some(®istry.file),
|
||||
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) => None,
|
||||
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) | Self::Directory(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(&self) -> Option<&Version> {
|
||||
match self {
|
||||
Self::Registry(source_dist) => Some(&source_dist.filename.version),
|
||||
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) => None,
|
||||
Self::DirectUrl(_) | Self::Git(_) | Self::Path(_) | Self::Directory(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +507,7 @@ impl SourceDist {
|
|||
/// Return true if the distribution is editable.
|
||||
pub fn is_editable(&self) -> bool {
|
||||
match self {
|
||||
Self::Path(PathSourceDist { editable, .. }) => *editable,
|
||||
Self::Directory(DirectorySourceDist { editable, .. }) => *editable,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -496,6 +516,7 @@ impl SourceDist {
|
|||
pub fn as_path(&self) -> Option<&Path> {
|
||||
match self {
|
||||
Self::Path(dist) => Some(&dist.path),
|
||||
Self::Directory(dist) => Some(&dist.path),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -543,6 +564,12 @@ impl Name for PathSourceDist {
|
|||
}
|
||||
}
|
||||
|
||||
impl Name for DirectorySourceDist {
|
||||
fn name(&self) -> &PackageName {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Name for SourceDist {
|
||||
fn name(&self) -> &PackageName {
|
||||
match self {
|
||||
|
|
@ -550,6 +577,7 @@ impl Name for SourceDist {
|
|||
Self::DirectUrl(dist) => dist.name(),
|
||||
Self::Git(dist) => dist.name(),
|
||||
Self::Path(dist) => dist.name(),
|
||||
Self::Directory(dist) => dist.name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -615,6 +643,12 @@ impl DistributionMetadata for PathSourceDist {
|
|||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -622,6 +656,7 @@ impl DistributionMetadata for SourceDist {
|
|||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -760,6 +795,16 @@ impl RemoteSource for PathSourceDist {
|
|||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -767,6 +812,7 @@ impl RemoteSource for SourceDist {
|
|||
Self::DirectUrl(dist) => dist.filename(),
|
||||
Self::Git(dist) => dist.filename(),
|
||||
Self::Path(dist) => dist.filename(),
|
||||
Self::Directory(dist) => dist.filename(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -776,6 +822,7 @@ impl RemoteSource for SourceDist {
|
|||
Self::DirectUrl(dist) => dist.size(),
|
||||
Self::Git(dist) => dist.size(),
|
||||
Self::Path(dist) => dist.size(),
|
||||
Self::Directory(dist) => dist.size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -934,6 +981,16 @@ impl Identifier for PathSourceDist {
|
|||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
@ -951,6 +1008,7 @@ impl Identifier for SourceDist {
|
|||
Self::DirectUrl(dist) => dist.distribution_id(),
|
||||
Self::Git(dist) => dist.distribution_id(),
|
||||
Self::Path(dist) => dist.distribution_id(),
|
||||
Self::Directory(dist) => dist.distribution_id(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -960,6 +1018,7 @@ impl Identifier for SourceDist {
|
|||
Self::DirectUrl(dist) => dist.resource_id(),
|
||||
Self::Git(dist) => dist.resource_id(),
|
||||
Self::Path(dist) => dist.resource_id(),
|
||||
Self::Directory(dist) => dist.resource_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1038,12 +1097,23 @@ impl Identifier for PathSourceUrl<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1052,6 +1122,7 @@ impl Identifier for SourceUrl<'_> {
|
|||
Self::Direct(url) => url.resource_id(),
|
||||
Self::Git(url) => url.resource_id(),
|
||||
Self::Path(url) => url.resource_id(),
|
||||
Self::Directory(url) => url.resource_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,11 @@ impl From<&ResolvedDist> for Requirement {
|
|||
url: sdist.url.clone(),
|
||||
editable: None,
|
||||
},
|
||||
Dist::Source(SourceDist::Directory(sdist)) => RequirementSource::Path {
|
||||
path: sdist.path.clone(),
|
||||
url: sdist.url.clone(),
|
||||
editable: None,
|
||||
},
|
||||
},
|
||||
ResolvedDist::Installed(dist) => RequirementSource::Registry {
|
||||
specifier: pep440_rs::VersionSpecifiers::from(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue