use std::fmt::Write;
use eyre::Context;
use tracing::instrument;
use crate::core::effects::Effects;
use crate::core::eventlog::{
is_gc_ref, CommitActivityStatus, EventCursor, EventLogDb, EventReplayer,
};
use crate::core::formatting::Pluralize;
use crate::git::{NonZeroOid, Reference, Repo};
pub fn find_dangling_references<'repo>(
repo: &'repo Repo,
event_replayer: &EventReplayer,
event_cursor: EventCursor,
) -> eyre::Result<Vec<Reference<'repo>>> {
let mut result = Vec::new();
for reference in repo.get_all_references()? {
let reference_name = reference.get_name()?;
if !is_gc_ref(&reference_name) {
continue;
}
let commit = match reference.peel_to_commit()? {
Some(commit) => commit,
None => continue,
};
match event_replayer.get_cursor_commit_activity_status(event_cursor, commit.get_oid()) {
CommitActivityStatus::Active => {
}
CommitActivityStatus::Inactive => {
}
CommitActivityStatus::Obsolete => {
result.push(reference)
}
}
}
Ok(result)
}
#[instrument]
pub fn mark_commit_reachable(repo: &Repo, commit_oid: NonZeroOid) -> eyre::Result<()> {
let ref_name = format!("refs/branchless/{commit_oid}");
eyre::ensure!(
Reference::is_valid_name(&ref_name),
format!("Invalid ref name to mark commit as reachable: {ref_name}")
);
if repo.find_commit(commit_oid)?.is_some() {
repo.create_reference(
&ref_name.into(),
commit_oid,
true,
"branchless: marking commit as reachable",
)
.wrap_err("Creating reference")?;
}
Ok(())
}
#[instrument]
pub fn gc(effects: &Effects) -> eyre::Result<()> {
let repo = Repo::from_current_dir()?;
let conn = repo.get_db_conn()?;
let event_log_db = EventLogDb::new(&conn)?;
let event_replayer = EventReplayer::from_event_log_db(effects, &repo, &event_log_db)?;
let event_cursor = event_replayer.make_default_cursor();
writeln!(
effects.get_output_stream(),
"branchless: collecting garbage"
)?;
let dangling_references = find_dangling_references(&repo, &event_replayer, event_cursor)?;
let num_dangling_references = Pluralize {
determiner: None,
amount: dangling_references.len(),
unit: ("dangling reference", "dangling references"),
}
.to_string();
for mut reference in dangling_references.into_iter() {
reference.delete()?;
}
writeln!(
effects.get_output_stream(),
"branchless: {num_dangling_references} deleted",
)?;
Ok(())
}