aboutsummaryrefslogtreecommitdiff
path: root/src/repo/mod.rs
diff options
context:
space:
mode:
authorMax Audron <audron@cocaine.farm>2024-03-27 13:40:42 +0100
committerMax Audron <audron@cocaine.farm>2024-03-27 13:40:42 +0100
commitf7aca5859b3a40ec00c8789383e8ab84d7821ae6 (patch)
tree9a242aef7f0b0547949f4fefcff97eeaef1af356 /src/repo/mod.rs
parentimplement basic cloning and updating with gix (diff)
reorganize repo git impls
Diffstat (limited to '')
-rw-r--r--src/repo/mod.rs212
1 files changed, 3 insertions, 209 deletions
diff --git a/src/repo/mod.rs b/src/repo/mod.rs
index 4eb9043..60fb34d 100644
--- a/src/repo/mod.rs
+++ b/src/repo/mod.rs
@@ -1,22 +1,14 @@
use std::{collections::HashMap, fmt::Debug, path::PathBuf, sync::RwLock};
-use anyhow::Context;
use thiserror::Error;
-use gix::{
- bstr::BString,
- clone::checkout::main_worktree::ProgressId,
- refs::{
- transaction::{LogChange, PreviousValue, RefEdit},
- FullName,
- },
- remote, Id, ObjectId, Progress, Remote, Repository,
-};
-use tracing::{debug, error};
+use gix::Repository;
+use tracing::error;
use crate::forge::Project;
mod aggregate;
+mod git;
mod repostate;
pub use aggregate::*;
@@ -47,204 +39,6 @@ impl Repo {
None => Err(RepoError::NoLocalRepo),
}
}
-
- #[tracing::instrument(level = "debug")]
- pub fn is_clean(&self) -> Result<LocalRepoState, RepoError> {
- let repo = self.repo()?;
-
- if let Some(state) = repo.state() {
- Ok(LocalRepoState::InProgress(state))
- } else {
- let head = repo.head().unwrap();
-
- if head.is_detached() {
- return Ok(LocalRepoState::DetachedHead);
- }
-
- if head.is_unborn() {
- return Ok(LocalRepoState::UnbornHead);
- }
-
- Ok(LocalRepoState::Clean)
- }
- }
-
- pub fn default_remote(&self) -> Result<Remote, RepoError> {
- Ok(self
- .repo()?
- .find_default_remote(gix::remote::Direction::Fetch)
- .ok_or(RepoError::NoRemoteFound)?
- .context("fetch: failed to find default remote")?)
- }
-
- pub fn default_branch(&self) -> Result<BString, RepoError> {
- let repo = self.repo()?;
- let remote = self.default_remote()?;
- let remote_name = remote.name().context("remote does not have name")?;
-
- let origin_ref = repo
- .find_reference(&format!("remotes/{}/HEAD", remote_name.as_bstr()))
- .context("the remotes HEAD references does not exist")?;
-
- if let Some(origin_ref) = origin_ref.target().try_name() {
- Ok(origin_ref.shorten().to_owned())
- } else {
- Err(RepoError::NoDefaultBranch)
- }
- }
-
- #[tracing::instrument(level = "trace")]
- pub fn clone(&self, url: &str) -> Result<(), RepoError> {
- std::fs::create_dir_all(&self.path).unwrap();
-
- let mut prepare_clone = gix::prepare_clone(url, &self.path).unwrap();
-
- let (mut prepare_checkout, _) = prepare_clone
- .fetch_then_checkout(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)
- .unwrap();
-
- let (_repo, _) = prepare_checkout
- .main_worktree(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)
- .unwrap();
-
- Ok(())
- }
-
- #[tracing::instrument(level = "trace")]
- pub fn fetch<'a>(&mut self) -> Result<bool, RepoError> {
- let remote = self.default_remote()?;
- let conn = remote.connect(gix::remote::Direction::Fetch).unwrap();
- let outcome = conn
- .prepare_fetch(
- gix::progress::Discard,
- gix::remote::ref_map::Options::default(),
- )
- .context("fetch: failed to prepare patch")?
- .receive(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)
- .context("fetch: failed to receive")?;
-
- match outcome.status {
- gix::remote::fetch::Status::NoPackReceived {
- dry_run: _,
- negotiate: _,
- update_refs: _,
- } => Ok(false),
- gix::remote::fetch::Status::Change {
- negotiate: _,
- write_pack_bundle: _,
- update_refs: _,
- } => Ok(true),
- }
- }
-
- pub fn refedit(target: ObjectId, name: &str, message: &str) -> RefEdit {
- RefEdit {
- change: gix::refs::transaction::Change::Update {
- log: LogChange {
- mode: gix::refs::transaction::RefLog::AndReference,
- force_create_reflog: false,
- message: message.into(),
- },
- expected: PreviousValue::Any,
- new: gix::refs::Target::Peeled(target),
- },
- name: FullName::try_from(name).unwrap(),
- deref: true,
- }
- }
-
- pub fn update_default_branch_ref(
- &self,
- remote: remote::Name,
- head: Id,
- ) -> Result<(), RepoError> {
- let default_branch = self.default_branch()?;
- let repo = self.repo()?;
-
- repo.edit_reference(Repo::refedit(
- head.into(),
- &format!("heads/{}", default_branch),
- &format!("checkout: {}/HEAD with gtree", remote.as_bstr()),
- ))
- .context("checkout: failed to edit ref")?;
-
- Ok(())
- }
-
- pub fn default_remote_head(&self) -> Result<(remote::Name, Id), RepoError> {
- let repo = self.repo()?;
-
- let remote = repo
- .find_fetch_remote(None)
- .context("could not find remote to fetch")?;
- let remote = remote.name().context("remote does not have name")?;
-
- let head_ref = repo
- .find_reference(&format!("remotes/{}/HEAD", remote.as_bstr()))
- .context("the remotes HEAD references does not exist")?;
- let head = head_ref
- .into_fully_peeled_id()
- .context("failed to peel ref")?;
-
- Ok((remote.to_owned(), head.to_owned()))
- }
-
- #[tracing::instrument(level = "trace", skip(progress))]
- pub fn checkout(
- &self,
- remote: remote::Name,
- head: Id,
- progress: &mut dyn gix::progress::DynNestedProgress,
- ) -> Result<(), RepoError> {
- let repo = self.repo()?;
-
- let workdir = repo.work_dir().ok_or(RepoError::NoWorktree)?;
- let head_tree = head
- .object()
- .context("could not find object HEAD points to")?
- .peel_to_tree()
- .context("failed to peel HEAD object")?
- .id();
-
- let index =
- gix_index::State::from_tree(&head_tree, &repo.objects).context("index from tree")?;
- let mut index = gix_index::File::from_state(index, repo.index_path());
-
- let mut files =
- progress.add_child_with_id("checkout".to_string(), ProgressId::CheckoutFiles.into());
- let mut bytes =
- progress.add_child_with_id("writing".to_string(), ProgressId::BytesWritten.into());
-
- files.init(Some(index.entries().len()), gix::progress::count("files"));
- bytes.init(None, gix::progress::bytes());
-
- let start = std::time::Instant::now();
-
- debug!("workdir: {:?}", workdir);
- let opts = gix_worktree_state::checkout::Options::default();
- let outcome = gix_worktree_state::checkout(
- &mut index,
- workdir,
- repo.objects.clone().into_arc().unwrap(),
- &files,
- &bytes,
- &gix::interrupt::IS_INTERRUPTED,
- opts,
- )
- .context("checkout: failed");
-
- files.show_throughput(start);
- bytes.show_throughput(start);
-
- debug!("outcome: {:?}", outcome);
- debug!("is interrupted: {:?}", &gix::interrupt::IS_INTERRUPTED);
-
- index
- .write(Default::default())
- .context("checkout: write index")?;
-
- Ok(())
- }
}
#[derive(Error, Debug)]