a148f9d0be
## Summary
This PR refactors our `RemoteDistribution` type such that it now follows
a clear hierarchy that matches the actual variants, and encodes the
differences between source and built distributions:
```rust
pub enum Distribution {
Built(BuiltDistribution),
Source(SourceDistribution),
}
pub enum BuiltDistribution {
Registry(RegistryBuiltDistribution),
DirectUrl(DirectUrlBuiltDistribution),
}
pub enum SourceDistribution {
Registry(RegistrySourceDistribution),
DirectUrl(DirectUrlSourceDistribution),
Git(GitSourceDistribution),
}
/// A built distribution (wheel) that exists in a registry, like `PyPI`.
pub struct RegistryBuiltDistribution {
pub name: PackageName,
pub version: Version,
pub file: File,
}
/// A built distribution (wheel) that exists at an arbitrary URL.
pub struct DirectUrlBuiltDistribution {
pub name: PackageName,
pub url: Url,
}
/// A source distribution that exists in a registry, like `PyPI`.
pub struct RegistrySourceDistribution {
pub name: PackageName,
pub version: Version,
pub file: File,
}
/// A source distribution that exists at an arbitrary URL.
pub struct DirectUrlSourceDistribution {
pub name: PackageName,
pub url: Url,
}
/// A source distribution that exists in a Git repository.
pub struct GitSourceDistribution {
pub name: PackageName,
pub url: Url,
}
```
Most of the PR just stems downstream from this change. There are no
behavioral changes, so I'm largely relying on lint, tests, and the
compiler for correctness.
121 lines
3.4 KiB
Rust
121 lines
3.4 KiB
Rust
use url::Url;
|
|
|
|
use crate::git::GitReference;
|
|
pub use crate::source::{GitSource, Reporter};
|
|
|
|
mod git;
|
|
mod source;
|
|
mod util;
|
|
|
|
/// A URL reference to a Git repository.
|
|
#[derive(Debug, Clone)]
|
|
pub struct GitUrl {
|
|
/// The URL of the Git repository, with any query parameters and fragments removed.
|
|
repository: Url,
|
|
/// The reference to the commit to use, which could be a branch, tag or revision.
|
|
reference: GitReference,
|
|
/// The precise commit to use, if known.
|
|
precise: Option<git2::Oid>,
|
|
}
|
|
|
|
impl GitUrl {
|
|
#[must_use]
|
|
pub(crate) fn with_precise(mut self, precise: git2::Oid) -> Self {
|
|
self.precise = Some(precise);
|
|
self
|
|
}
|
|
|
|
/// Return the [`Url`] of the Git repository.
|
|
pub fn repository(&self) -> &Url {
|
|
&self.repository
|
|
}
|
|
|
|
/// Return the reference to the commit to use, which could be a branch, tag or revision.
|
|
pub fn reference(&self) -> Option<&str> {
|
|
match &self.reference {
|
|
GitReference::Branch(rev)
|
|
| GitReference::Tag(rev)
|
|
| GitReference::BranchOrTag(rev)
|
|
| GitReference::Ref(rev)
|
|
| GitReference::FullCommit(rev)
|
|
| GitReference::ShortCommit(rev) => Some(rev),
|
|
GitReference::DefaultBranch => None,
|
|
}
|
|
}
|
|
|
|
/// Return the precise commit, if known.
|
|
pub fn precise(&self) -> Option<git2::Oid> {
|
|
self.precise
|
|
}
|
|
}
|
|
|
|
impl TryFrom<Url> for GitUrl {
|
|
type Error = anyhow::Error;
|
|
|
|
/// Initialize a [`GitUrl`] source from a URL.
|
|
fn try_from(mut url: Url) -> Result<Self, Self::Error> {
|
|
// Remove any query parameters and fragments.
|
|
url.set_fragment(None);
|
|
url.set_query(None);
|
|
|
|
// If the URL ends with a reference, like `https://git.example.com/MyProject.git@v1.0`,
|
|
// extract it.
|
|
let mut reference = GitReference::DefaultBranch;
|
|
if let Some((prefix, rev)) = url.as_str().rsplit_once('@') {
|
|
reference = GitReference::from_rev(rev);
|
|
url = Url::parse(prefix)?;
|
|
}
|
|
let precise = if let GitReference::FullCommit(rev) = &reference {
|
|
Some(git2::Oid::from_str(rev)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(Self {
|
|
repository: url,
|
|
reference,
|
|
precise,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<GitUrl> for Url {
|
|
fn from(git: GitUrl) -> Self {
|
|
let mut url = git.repository;
|
|
|
|
// If we have a precise commit, add `@` and the commit hash to the URL.
|
|
if let Some(precise) = git.precise {
|
|
url.set_path(&format!("{}@{}", url.path(), precise));
|
|
} else {
|
|
// Otherwise, add the branch or tag name.
|
|
match git.reference {
|
|
GitReference::Branch(rev)
|
|
| GitReference::Tag(rev)
|
|
| GitReference::BranchOrTag(rev)
|
|
| GitReference::Ref(rev)
|
|
| GitReference::FullCommit(rev)
|
|
| GitReference::ShortCommit(rev) => {
|
|
url.set_path(&format!("{}@{}", url.path(), rev));
|
|
}
|
|
GitReference::DefaultBranch => {}
|
|
}
|
|
}
|
|
|
|
url
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for GitUrl {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.repository)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum FetchStrategy {
|
|
/// Fetch Git repositories using libgit2.
|
|
Libgit2,
|
|
/// Fetch Git repositories using the `git` CLI.
|
|
Cli,
|
|
}
|