mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Deduplicate GitSha
and GitOid
types (#10802)
## Summary I think this split is leftover from using `libgit2`. I kept `Oid` since that seems to be the official terminology.
This commit is contained in:
parent
54bb5a38a4
commit
5c7fba86e1
9 changed files with 66 additions and 104 deletions
|
@ -18,8 +18,7 @@ use uv_fs::Simplified;
|
|||
use uv_static::EnvVars;
|
||||
use uv_version::version;
|
||||
|
||||
use crate::sha::GitOid;
|
||||
use crate::{GitHubRepository, GitSha};
|
||||
use crate::{GitHubRepository, GitOid};
|
||||
|
||||
/// A file indicates that if present, `git reset` has been done and a repo
|
||||
/// checkout is ready to go. See [`GitCheckout::reset`] for why we need this.
|
||||
|
@ -32,6 +31,7 @@ pub enum GitError {
|
|||
#[error(transparent)]
|
||||
Other(#[from] which::Error),
|
||||
}
|
||||
|
||||
/// A global cache of the result of `which git`.
|
||||
pub static GIT: LazyLock<Result<PathBuf, GitError>> = LazyLock::new(|| {
|
||||
which::which("git").map_err(|e| match e {
|
||||
|
@ -123,10 +123,10 @@ impl GitReference {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the precise [`GitSha`] of this reference, if it's a full commit.
|
||||
pub(crate) fn as_sha(&self) -> Option<GitSha> {
|
||||
/// Returns the precise [`GitOid`] of this reference, if it's a full commit.
|
||||
pub(crate) fn as_sha(&self) -> Option<GitOid> {
|
||||
if let Self::FullCommit(rev) = self {
|
||||
Some(GitSha::from_str(rev).expect("Full commit should be exactly 40 characters"))
|
||||
Some(GitOid::from_str(rev).expect("Full commit should be exactly 40 characters"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -3,17 +3,17 @@ use url::Url;
|
|||
pub use crate::credentials::{store_credentials_from_url, GIT_STORE};
|
||||
pub use crate::git::{GitReference, GIT};
|
||||
pub use crate::github::GitHubRepository;
|
||||
pub use crate::oid::{GitOid, OidParseError};
|
||||
pub use crate::resolver::{
|
||||
GitResolver, GitResolverError, RepositoryReference, ResolvedRepositoryReference,
|
||||
};
|
||||
pub use crate::sha::{GitSha, OidParseError};
|
||||
pub use crate::source::{Fetch, GitSource, Reporter};
|
||||
|
||||
mod credentials;
|
||||
mod git;
|
||||
mod github;
|
||||
mod oid;
|
||||
mod resolver;
|
||||
mod sha;
|
||||
mod source;
|
||||
|
||||
/// A URL reference to a Git repository.
|
||||
|
@ -25,7 +25,7 @@ pub struct GitUrl {
|
|||
/// 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<GitSha>,
|
||||
precise: Option<GitOid>,
|
||||
}
|
||||
|
||||
impl GitUrl {
|
||||
|
@ -40,7 +40,7 @@ impl GitUrl {
|
|||
}
|
||||
|
||||
/// Create a new [`GitUrl`] from a repository URL and a precise commit.
|
||||
pub fn from_commit(repository: Url, reference: GitReference, precise: GitSha) -> Self {
|
||||
pub fn from_commit(repository: Url, reference: GitReference, precise: GitOid) -> Self {
|
||||
Self {
|
||||
repository,
|
||||
reference,
|
||||
|
@ -48,9 +48,9 @@ impl GitUrl {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set the precise [`GitSha`] to use for this Git URL.
|
||||
/// Set the precise [`GitOid`] to use for this Git URL.
|
||||
#[must_use]
|
||||
pub fn with_precise(mut self, precise: GitSha) -> Self {
|
||||
pub fn with_precise(mut self, precise: GitOid) -> Self {
|
||||
self.precise = Some(precise);
|
||||
self
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ impl GitUrl {
|
|||
}
|
||||
|
||||
/// Return the precise commit, if known.
|
||||
pub fn precise(&self) -> Option<GitSha> {
|
||||
pub fn precise(&self) -> Option<GitOid> {
|
||||
self.precise
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,81 +3,25 @@ use std::str::{self, FromStr};
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
/// A complete Git SHA, i.e., a 40-character hexadecimal representation of a Git commit.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct GitSha(GitOid);
|
||||
|
||||
impl GitSha {
|
||||
/// Return the Git SHA as a string.
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
/// Return a truncated representation, i.e., the first 16 characters of the SHA.
|
||||
pub fn as_short_str(&self) -> &str {
|
||||
&self.0.as_str()[..16]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitSha> for GitOid {
|
||||
fn from(value: GitSha) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitOid> for GitSha {
|
||||
fn from(value: GitOid) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for GitSha {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GitSha {
|
||||
type Err = OidParseError;
|
||||
|
||||
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(GitOid::from_str(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for GitSha {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.0.as_str().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for GitSha {
|
||||
fn deserialize<D>(deserializer: D) -> Result<GitSha, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let value = String::deserialize(deserializer)?;
|
||||
GitSha::from_str(&value).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unique identity of any Git object (commit, tree, blob, tag).
|
||||
///
|
||||
/// Note this type does not validate whether the input is a valid hash.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct GitOid {
|
||||
pub struct GitOid {
|
||||
len: usize,
|
||||
bytes: [u8; 40],
|
||||
}
|
||||
|
||||
impl GitOid {
|
||||
/// Return the string representation of an object ID.
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
pub fn as_str(&self) -> &str {
|
||||
str::from_utf8(&self.bytes[..self.len]).unwrap()
|
||||
}
|
||||
|
||||
/// Return a truncated representation, i.e., the first 16 characters of the SHA.
|
||||
pub fn as_short_str(&self) -> &str {
|
||||
&self.as_str()[..16]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
|
@ -116,6 +60,25 @@ impl Display for GitOid {
|
|||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for GitOid {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.as_str().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for GitOid {
|
||||
fn deserialize<D>(deserializer: D) -> Result<GitOid, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let value = String::deserialize(deserializer)?;
|
||||
GitOid::from_str(&value).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
|
@ -5,7 +5,7 @@ use std::sync::Arc;
|
|||
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{Fetch, GitHubRepository, GitReference, GitSha, GitSource, GitUrl, Reporter};
|
||||
use crate::{Fetch, GitHubRepository, GitOid, GitReference, GitSource, GitUrl, Reporter};
|
||||
use dashmap::mapref::one::Ref;
|
||||
use dashmap::DashMap;
|
||||
use fs_err::tokio as fs;
|
||||
|
@ -30,28 +30,28 @@ pub enum GitResolverError {
|
|||
|
||||
/// A resolver for Git repositories.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct GitResolver(Arc<DashMap<RepositoryReference, GitSha>>);
|
||||
pub struct GitResolver(Arc<DashMap<RepositoryReference, GitOid>>);
|
||||
|
||||
impl GitResolver {
|
||||
/// Inserts a new [`GitSha`] for the given [`RepositoryReference`].
|
||||
pub fn insert(&self, reference: RepositoryReference, sha: GitSha) {
|
||||
/// Inserts a new [`GitOid`] for the given [`RepositoryReference`].
|
||||
pub fn insert(&self, reference: RepositoryReference, sha: GitOid) {
|
||||
self.0.insert(reference, sha);
|
||||
}
|
||||
|
||||
/// Returns the [`GitSha`] for the given [`RepositoryReference`], if it exists.
|
||||
fn get(&self, reference: &RepositoryReference) -> Option<Ref<RepositoryReference, GitSha>> {
|
||||
/// Returns the [`GitOid`] for the given [`RepositoryReference`], if it exists.
|
||||
fn get(&self, reference: &RepositoryReference) -> Option<Ref<RepositoryReference, GitOid>> {
|
||||
self.0.get(reference)
|
||||
}
|
||||
|
||||
/// Resolve a Git URL to a specific commit without performing any Git operations.
|
||||
///
|
||||
/// Returns a [`GitSha`] if the URL has already been resolved (i.e., is available in the cache),
|
||||
/// Returns a [`GitOid`] if the URL has already been resolved (i.e., is available in the cache),
|
||||
/// or if it can be fetched via the GitHub API. Otherwise, returns `None`.
|
||||
pub async fn github_fast_path(
|
||||
&self,
|
||||
url: &GitUrl,
|
||||
client: ClientWithMiddleware,
|
||||
) -> Result<Option<GitSha>, GitResolverError> {
|
||||
) -> Result<Option<GitOid>, GitResolverError> {
|
||||
let reference = RepositoryReference::from(url);
|
||||
|
||||
// If we know the precise commit already, return it.
|
||||
|
@ -92,7 +92,7 @@ impl GitResolver {
|
|||
// Parse the response as a Git SHA.
|
||||
let precise = response.text().await?;
|
||||
let precise =
|
||||
GitSha::from_str(&precise).map_err(|err| GitResolverError::Git(err.into()))?;
|
||||
GitOid::from_str(&precise).map_err(|err| GitResolverError::Git(err.into()))?;
|
||||
|
||||
// Insert the resolved URL into the in-memory cache. This ensures that subsequent fetches
|
||||
// resolve to the same precise commit.
|
||||
|
@ -207,7 +207,7 @@ pub struct ResolvedRepositoryReference {
|
|||
/// tag, or revision).
|
||||
pub reference: RepositoryReference,
|
||||
/// The precise commit SHA of the reference.
|
||||
pub sha: GitSha,
|
||||
pub sha: GitOid,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -14,8 +14,7 @@ use url::Url;
|
|||
use uv_cache_key::{cache_digest, RepositoryUrl};
|
||||
|
||||
use crate::git::GitRemote;
|
||||
use crate::sha::GitOid;
|
||||
use crate::{GitSha, GitUrl, GIT_STORE};
|
||||
use crate::{GitOid, GitUrl, GIT_STORE};
|
||||
|
||||
/// A remote Git source that can be checked out locally.
|
||||
pub struct GitSource {
|
||||
|
@ -74,7 +73,7 @@ impl GitSource {
|
|||
let (db, actual_rev, task) = match (self.git.precise, remote.db_at(&db_path).ok()) {
|
||||
// If we have a locked revision, and we have a preexisting database
|
||||
// which has that revision, then no update needs to happen.
|
||||
(Some(rev), Some(db)) if db.contains(rev.into()) => {
|
||||
(Some(rev), Some(db)) if db.contains(rev) => {
|
||||
debug!("Using existing Git source `{}`", self.git.repository);
|
||||
(db, rev, None)
|
||||
}
|
||||
|
@ -99,13 +98,13 @@ impl GitSource {
|
|||
&self.client,
|
||||
)?;
|
||||
|
||||
(db, GitSha::from(actual_rev), task)
|
||||
(db, actual_rev, task)
|
||||
}
|
||||
};
|
||||
|
||||
// Don’t use the full hash, in order to contribute less to reaching the
|
||||
// path length limit on Windows.
|
||||
let short_id = db.to_short_id(actual_rev.into())?;
|
||||
let short_id = db.to_short_id(actual_rev)?;
|
||||
|
||||
// Check out `actual_rev` from the database to a scoped location on the
|
||||
// filesystem. This will use hard links and such to ideally make the
|
||||
|
@ -116,7 +115,7 @@ impl GitSource {
|
|||
.join(&ident)
|
||||
.join(short_id.as_str());
|
||||
|
||||
db.copy_to(actual_rev.into(), &checkout_path)?;
|
||||
db.copy_to(actual_rev, &checkout_path)?;
|
||||
|
||||
// Report the checkout operation to the reporter.
|
||||
if let Some(task) = task {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue