use std::path::{Path, PathBuf};
use eyre::Context;
use tracing::instrument;
use crate::core::eventlog::EventTransactionId;
use super::{FileMode, GitRunInfo, GitRunOpts, GitRunResult, MaybeZeroOid, NonZeroOid, Repo};
#[derive(Copy, Clone, Debug)]
pub enum Stage {
Stage0,
Stage1,
Stage2,
Stage3,
}
impl Stage {
pub(super) fn get_trailer(&self) -> &'static str {
match self {
Stage::Stage0 => "Branchless-stage-0",
Stage::Stage1 => "Branchless-stage-1",
Stage::Stage2 => "Branchless-stage-2",
Stage::Stage3 => "Branchless-stage-3",
}
}
}
impl From<Stage> for i32 {
fn from(stage: Stage) -> Self {
match stage {
Stage::Stage0 => 0,
Stage::Stage1 => 1,
Stage::Stage2 => 2,
Stage::Stage3 => 3,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct IndexEntry {
pub(super) oid: MaybeZeroOid,
pub(super) file_mode: FileMode,
}
pub struct Index {
pub(super) inner: git2::Index,
}
impl std::fmt::Debug for Index {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Index>")
}
}
impl Index {
pub fn has_conflicts(&self) -> bool {
self.inner.has_conflicts()
}
pub fn get_entry(&self, path: &Path) -> Option<IndexEntry> {
self.get_entry_in_stage(path, Stage::Stage0)
}
pub fn get_entry_in_stage(&self, path: &Path, stage: Stage) -> Option<IndexEntry> {
self.inner
.get_path(path, i32::from(stage))
.map(|entry| IndexEntry {
oid: entry.id.into(),
file_mode: {
let mode = i32::try_from(entry.mode).unwrap();
FileMode::try_from(mode).unwrap()
},
})
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum UpdateIndexCommand {
Delete {
path: PathBuf,
},
Update {
path: PathBuf,
stage: Stage,
mode: FileMode,
oid: NonZeroOid,
},
}
#[instrument]
pub fn update_index(
git_run_info: &GitRunInfo,
repo: &Repo,
index: &Index,
event_tx_id: EventTransactionId,
commands: &[UpdateIndexCommand],
) -> eyre::Result<()> {
let stdin = {
let mut buf = Vec::new();
for command in commands {
use std::io::Write;
match command {
UpdateIndexCommand::Delete { path } => {
write!(
&mut buf,
"0 {zero} 0\t{path}\0",
zero = MaybeZeroOid::Zero,
path = path.display(),
)?;
}
UpdateIndexCommand::Update {
path,
stage,
mode,
oid,
} => {
write!(
&mut buf,
"{mode} {sha1} {stage}\t{path}\0",
mode = mode.to_string(),
sha1 = oid,
stage = i32::from(*stage),
path = path.display(),
)?;
}
}
}
buf
};
let GitRunResult { .. } = git_run_info
.run_silent(
repo,
Some(event_tx_id),
&["update-index", "-z", "--index-info"],
GitRunOpts {
treat_git_failure_as_error: true,
stdin: Some(stdin),
},
)
.wrap_err("Updating index")?;
Ok(())
}