mirror of
https://seed.radicle.dev/rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt.git
synced 2026-10-25 22:30:35 +08:00
125 lines
3.6 KiB
Rust
125 lines
3.6 KiB
Rust
// Copyright © 2022 The Radicle Link Contributors
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
//! The `refdb` is separated into two traits: [`Read`] and [`Write`], providing
|
|
//! access to [git references][refs].
|
|
//!
|
|
//! The [`Read`] trait provides functions for read-only access to the refdb.
|
|
//! The [`Write`] trait provides functions for read and write access to the
|
|
//! refdb, thus it implies the [`Read`] trait.
|
|
//!
|
|
//! The reason for separating these types of actions out is that one can infer
|
|
//! what kind of access a function has to the refdb by looking at which trait it
|
|
//! is using.
|
|
//!
|
|
//! For implementations of these traits, this crate provides [`crate::Read`] and
|
|
//! [`crate::Write`] structs.
|
|
//!
|
|
//! [refs]: https://git-scm.com/book/en/v2/Git-Internals-Git-References
|
|
|
|
use std::fmt::Debug;
|
|
|
|
use git_ext::{ref_format::RefString, Oid};
|
|
|
|
pub mod iter;
|
|
pub use iter::{References, ReferencesGlob};
|
|
|
|
pub mod read;
|
|
pub use read::Read;
|
|
|
|
pub mod write;
|
|
pub use write::{previous, Applied, Policy, SymrefTarget, Update, Updated, Write};
|
|
|
|
/// A read-only structure representing a git reference.
|
|
///
|
|
/// References can be constructed by using the [`Read`] functions:
|
|
/// * [`Read::find_reference`]
|
|
/// * [`Read::find_references`]
|
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct Reference {
|
|
/// The name of the reference.
|
|
pub name: RefString,
|
|
/// The target of the reference.
|
|
pub target: Target,
|
|
}
|
|
|
|
impl<'a> TryFrom<git2::Reference<'a>> for Reference {
|
|
type Error = error::ParseReference;
|
|
|
|
fn try_from(value: git2::Reference) -> Result<Self, Self::Error> {
|
|
use error::ParseReference;
|
|
|
|
let name = value
|
|
.name()
|
|
.ok_or(ParseReference::InvalidUtf8)
|
|
.and_then(|name| RefString::try_from(name).map_err(ParseReference::from))?;
|
|
let target = match value.target() {
|
|
None => {
|
|
let name = value
|
|
.symbolic_target()
|
|
.ok_or(ParseReference::InvalidUtf8)
|
|
.and_then(|name| RefString::try_from(name).map_err(ParseReference::from))?;
|
|
name.into()
|
|
},
|
|
Some(oid) => oid.into(),
|
|
};
|
|
|
|
Ok(Reference { name, target })
|
|
}
|
|
}
|
|
|
|
/// The target a reference points to.
|
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub enum Target {
|
|
/// The reference points directly at an `oid`.
|
|
Direct { oid: Oid },
|
|
/// The reference is symbolic and points to another reference.
|
|
Symbolic { name: RefString },
|
|
}
|
|
|
|
impl From<Oid> for Target {
|
|
fn from(oid: Oid) -> Self {
|
|
Self::Direct { oid }
|
|
}
|
|
}
|
|
|
|
impl From<git2::Oid> for Target {
|
|
fn from(oid: git2::Oid) -> Self {
|
|
Oid::from(oid).into()
|
|
}
|
|
}
|
|
|
|
impl From<RefString> for Target {
|
|
fn from(name: RefString) -> Self {
|
|
Self::Symbolic { name }
|
|
}
|
|
}
|
|
|
|
pub mod error {
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum ParseReference {
|
|
#[error("reference name did contain valid UTF-8 bytes")]
|
|
InvalidUtf8,
|
|
#[error(transparent)]
|
|
RefString(#[from] radicle_git_ext::ref_format::Error),
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Iter {
|
|
#[error(transparent)]
|
|
Git(#[from] git2::Error),
|
|
#[error(transparent)]
|
|
Parse(#[from] ParseReference),
|
|
}
|
|
}
|
|
|
|
/// Utility function for resolving a [`Reference`] to its [`Oid`]
|
|
pub(crate) fn resolve(repo: &git2::Repository, r: &Reference) -> Result<Oid, git2::Error> {
|
|
match &r.target {
|
|
Target::Direct { oid } => Ok(*oid),
|
|
Target::Symbolic { name } => repo.refname_to_id(name.as_str()).map(Oid::from),
|
|
}
|
|
}
|