Re-use `HEAD` reference if it exists
Since the `HEAD` reference is trusted (we set it locally), use that when possible, instead of re-computing it. Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
2ec320acec
commit
1906124497
|
|
@ -31,8 +31,12 @@ pub const PROTOCOL_PORT: u16 = 9418;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum RefError {
|
pub enum RefError {
|
||||||
#[error("invalid ref name '{0}'")]
|
#[error("ref name is not valid UTF-8")]
|
||||||
InvalidName(format::RefString),
|
InvalidName,
|
||||||
|
#[error("unexpected symbolic ref: {0}")]
|
||||||
|
Symbolic(RefString),
|
||||||
|
#[error("unexpected unqualified ref: {0}")]
|
||||||
|
Unqualified(RefString),
|
||||||
#[error("invalid ref format: {0}")]
|
#[error("invalid ref format: {0}")]
|
||||||
Format(#[from] format::Error),
|
Format(#[from] format::Error),
|
||||||
#[error("expected ref to begin with 'refs/namespaces' but found '{0}'")]
|
#[error("expected ref to begin with 'refs/namespaces' but found '{0}'")]
|
||||||
|
|
@ -67,8 +71,20 @@ pub mod refs {
|
||||||
/// Where project information is kept.
|
/// Where project information is kept.
|
||||||
pub static IDENTITY_BRANCH: Lazy<RefString> = Lazy::new(|| refname!("radicle/id"));
|
pub static IDENTITY_BRANCH: Lazy<RefString> = Lazy::new(|| refname!("radicle/id"));
|
||||||
|
|
||||||
pub mod storage {
|
/// Try to get a qualified reference from a generic reference.
|
||||||
|
pub fn qualified_from<'a>(r: &'a git2::Reference) -> Result<(Qualified<'a>, Oid), RefError> {
|
||||||
|
let name = r.name().ok_or(RefError::InvalidName)?;
|
||||||
|
let refstr = RefStr::try_from_str(name)?;
|
||||||
|
let target = r
|
||||||
|
.target()
|
||||||
|
.ok_or_else(|| RefError::Symbolic(refstr.to_owned()))?;
|
||||||
|
let qualified = Qualified::from_refstr(refstr)
|
||||||
|
.ok_or_else(|| RefError::Unqualified(refstr.to_owned()))?;
|
||||||
|
|
||||||
|
Ok((qualified, target.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod storage {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Create the [`Namespaced`] `branch` under the `remote` namespace, i.e.
|
/// Create the [`Namespaced`] `branch` under the `remote` namespace, i.e.
|
||||||
|
|
@ -157,7 +173,7 @@ where
|
||||||
match input.to_namespaced() {
|
match input.to_namespaced() {
|
||||||
None => {
|
None => {
|
||||||
let refname = Qualified::from_refstr(input)
|
let refname = Qualified::from_refstr(input)
|
||||||
.ok_or_else(|| RefError::InvalidName(input.to_owned()))?;
|
.ok_or_else(|| RefError::Unqualified(input.to_owned()))?;
|
||||||
|
|
||||||
Ok((None, refname))
|
Ok((None, refname))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,15 +154,13 @@ pub fn fork<G: Signer, S: storage::WriteStorage>(
|
||||||
) -> Result<(), ForkError> {
|
) -> Result<(), ForkError> {
|
||||||
let me = signer.public_key();
|
let me = signer.public_key();
|
||||||
let repository = storage.repository(proj)?;
|
let repository = storage.repository(proj)?;
|
||||||
let (canonical_id, project) = repository.project_identity()?;
|
// TODO: We should get the id branch pointer from a stored canonical reference.
|
||||||
let (canonical_head, _) = repository.head()?;
|
let (canonical_id, _) = repository.project_identity()?;
|
||||||
|
let (canonical_branch, canonical_head) = repository.head()?;
|
||||||
let raw = repository.raw();
|
let raw = repository.raw();
|
||||||
|
|
||||||
// TODO: We should only get the project HEAD once we've stored the canonical identity
|
|
||||||
// branch on disk. This way it can use what we stored, instead of recomputing it.
|
|
||||||
|
|
||||||
raw.reference(
|
raw.reference(
|
||||||
&git::refs::storage::branch(me, &project.default_branch),
|
&canonical_branch.with_namespace(me.into()),
|
||||||
*canonical_head,
|
*canonical_head,
|
||||||
false,
|
false,
|
||||||
&format!("creating default branch for {me}"),
|
&format!("creating default branch for {me}"),
|
||||||
|
|
@ -353,7 +351,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let project_repo = storage.repository(proj).unwrap();
|
let project_repo = storage.repository(proj).unwrap();
|
||||||
let (head, _) = project_repo.head().unwrap();
|
let (_, head) = project_repo.head().unwrap();
|
||||||
|
|
||||||
// Test canonical refs.
|
// Test canonical refs.
|
||||||
assert_eq!(project_repo.raw().refname_to_id("HEAD").unwrap(), *head);
|
assert_eq!(project_repo.raw().refname_to_id("HEAD").unwrap(), *head);
|
||||||
|
|
|
||||||
|
|
@ -242,10 +242,20 @@ pub trait ReadRepository {
|
||||||
|
|
||||||
fn blob_at<'a>(&'a self, oid: Oid, path: &'a Path) -> Result<git2::Blob<'a>, git_ext::Error>;
|
fn blob_at<'a>(&'a self, oid: Oid, path: &'a Path) -> Result<git2::Blob<'a>, git_ext::Error>;
|
||||||
|
|
||||||
/// Get the canonical head of this repository.
|
/// Get the head of this repository.
|
||||||
|
///
|
||||||
|
/// Returns the value of `HEAD` if it is set, otherwise computes the canonical head
|
||||||
|
/// using [`ReadRepository::canonical_head`].
|
||||||
///
|
///
|
||||||
/// Returns the [`Oid`] as well as the qualified reference name.
|
/// Returns the [`Oid`] as well as the qualified reference name.
|
||||||
fn head(&self) -> Result<(Oid, Qualified), ProjectError>;
|
fn head(&self) -> Result<(Qualified, Oid), ProjectError>;
|
||||||
|
|
||||||
|
/// Compute the canonical head of this repository.
|
||||||
|
///
|
||||||
|
/// Ignores any existing `HEAD` reference.
|
||||||
|
///
|
||||||
|
/// Returns the [`Oid`] as well as the qualified reference name.
|
||||||
|
fn canonical_head(&self) -> Result<(Qualified, Oid), ProjectError>;
|
||||||
|
|
||||||
/// Get the `reference` for the given `remote`.
|
/// Get the `reference` for the given `remote`.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -487,10 +487,18 @@ impl ReadRepository for Repository {
|
||||||
Repository::project(self)
|
Repository::project(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn head(&self) -> Result<(Oid, Qualified), ProjectError> {
|
fn head(&self) -> Result<(Qualified, Oid), ProjectError> {
|
||||||
// TODO: We shouldn't need to re-construct the history here; we should use the cached
|
// If `HEAD` is already set locally, just return that.
|
||||||
// document head of the "trusted" (local) user for this project.
|
if let Ok(head) = self.backend.head() {
|
||||||
// In the `fork` function for example, we call Repository::project_identity again,
|
if let Ok((name, oid)) = git::refs::qualified_from(&head) {
|
||||||
|
return Ok((name.to_owned(), oid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.canonical_head()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonical_head(&self) -> Result<(Qualified, Oid), ProjectError> {
|
||||||
|
// TODO: In the `fork` function for example, we call Repository::project_identity again,
|
||||||
// This should only be necessary once.
|
// This should only be necessary once.
|
||||||
let (_, project) = self.project_identity()?;
|
let (_, project) = self.project_identity()?;
|
||||||
let branch_ref = Qualified::from(lit::refs_heads(&project.default_branch));
|
let branch_ref = Qualified::from(lit::refs_heads(&project.default_branch));
|
||||||
|
|
@ -509,7 +517,7 @@ impl ReadRepository for Repository {
|
||||||
heads => raw.merge_base_many(heads),
|
heads => raw.merge_base_many(heads),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok((oid.into(), branch_ref))
|
Ok((branch_ref, oid.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -631,7 +639,7 @@ impl WriteRepository for Repository {
|
||||||
|
|
||||||
fn set_head(&self) -> Result<Oid, ProjectError> {
|
fn set_head(&self) -> Result<Oid, ProjectError> {
|
||||||
let head_ref = refname!("HEAD");
|
let head_ref = refname!("HEAD");
|
||||||
let (head, branch_ref) = self.head()?;
|
let (branch_ref, head) = self.canonical_head()?;
|
||||||
|
|
||||||
log::debug!("Setting ref {:?} -> {:?}", &branch_ref, head);
|
log::debug!("Setting ref {:?} -> {:?}", &branch_ref, head);
|
||||||
self.raw()
|
self.raw()
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,11 @@ impl ReadRepository for MockRepository {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn head(&self) -> Result<(Oid, fmt::Qualified), ProjectError> {
|
fn head(&self) -> Result<(fmt::Qualified, Oid), ProjectError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonical_head(&self) -> Result<(fmt::Qualified, Oid), ProjectError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue