Skip to content

Commit

Permalink
feat: gix status auto-writes changed indices.
Browse files Browse the repository at this point in the history
This prevents expensive operations to re-occour.
  • Loading branch information
Byron committed Oct 5, 2023
1 parent b5b50f8 commit 46e5919
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 7 deletions.
61 changes: 54 additions & 7 deletions gitoxide-core/src/repository/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct Options {
pub submodules: Submodules,
pub thread_limit: Option<usize>,
pub statistics: bool,
pub allow_write: bool,
}

pub fn show(
Expand All @@ -34,6 +35,7 @@ pub fn show(
// TODO: implement this
submodules: _,
thread_limit,
allow_write,
statistics,
}: Options,
) -> anyhow::Result<()> {
Expand Down Expand Up @@ -67,11 +69,15 @@ pub fn show(
_ => unreachable!("state must be attributes stack only"),
},
};
let mut printer = Printer {
out,
changes: Vec::new(),
};
let outcome = gix_status::index_as_worktree(
index,
repo.work_dir()
.context("This operation cannot be run on a bare repository")?,
&mut Printer(out),
&mut printer,
FastEq,
Submodule,
{
Expand All @@ -88,6 +94,27 @@ pub fn show(
options,
)?;

if outcome.entries_to_update != 0 && allow_write {
{
let entries = index.entries_mut();
for (entry_index, change) in printer.changes {
let entry = &mut entries[entry_index];
match change {
ApplyChange::SetSizeToZero => {
entry.stat.size = 0;
}
ApplyChange::NewStat(new_stat) => {
entry.stat = new_stat;
}
}
}
}
index.write(gix::index::write::Options {
extensions: Default::default(),
skip_hash: false, // TODO: make this based on configuration
})?;
}

if statistics {
writeln!(err, "{outcome:#?}").ok();
}
Expand All @@ -109,7 +136,15 @@ impl gix_status::index_as_worktree::traits::SubmoduleStatus for Submodule {
}
}

struct Printer<W>(W);
struct Printer<W> {
out: W,
changes: Vec<(usize, ApplyChange)>,
}

enum ApplyChange {
SetSizeToZero,
NewStat(gix::index::entry::Stat),
}

impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W>
where
Expand All @@ -122,28 +157,40 @@ where
&mut self,
_entries: &'index [Entry],
_entry: &'index Entry,
_entry_index: usize,
entry_index: usize,
rela_path: &'index BStr,
status: EntryStatus<Self::ContentChange>,
) {
self.visit_inner(rela_path, status).ok();
self.visit_inner(entry_index, rela_path, status).ok();
}
}

impl<W: std::io::Write> Printer<W> {
fn visit_inner(&mut self, rela_path: &BStr, status: EntryStatus<()>) -> std::io::Result<()> {
fn visit_inner(&mut self, entry_index: usize, rela_path: &BStr, status: EntryStatus<()>) -> std::io::Result<()> {
let char_storage;
let status = match status {
EntryStatus::Conflict(conflict) => as_str(conflict),
EntryStatus::Change(change) => {
if matches!(
change,
Change::Modification {
set_entry_stat_size_zero: true,
..
}
) {
self.changes.push((entry_index, ApplyChange::SetSizeToZero))
}
char_storage = change_to_char(&change);
std::str::from_utf8(std::slice::from_ref(&char_storage)).expect("valid ASCII")
}
EntryStatus::NeedsUpdate(_) => return Ok(()),
EntryStatus::NeedsUpdate(stat) => {
self.changes.push((entry_index, ApplyChange::NewStat(stat)));
return Ok(());
}
EntryStatus::IntentToAdd => "A",
};

writeln!(&mut self.0, "{status: >3} {rela_path}")
writeln!(&mut self.out, "{status: >3} {rela_path}")
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/plumbing/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ pub fn main() -> Result<()> {
Subcommands::Status(crate::plumbing::options::status::Platform {
statistics,
submodules,
no_write,
pathspec,
}) => prepare_and_run(
"status",
Expand All @@ -156,6 +157,7 @@ pub fn main() -> Result<()> {
format,
statistics,
thread_limit: thread_limit.or(cfg!(target_os = "macos").then_some(3)), // TODO: make this a configurable when in `gix`, this seems to be optimal on MacOS, linux scales though!
allow_write: !no_write,
submodules: match submodules {
Submodules::All => core::repository::status::Submodules::All,
Submodules::RefChange => core::repository::status::Submodules::RefChange,
Expand Down
3 changes: 3 additions & 0 deletions src/plumbing/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ pub mod status {
/// Print additional statistics to help understanding performance.
#[clap(long, short = 's')]
pub statistics: bool,
/// Don't write back a changed index, which forces this operation to always be idempotent.
#[clap(long)]
pub no_write: bool,
/// The git path specifications to list attributes for, or unset to read from stdin one per line.
#[clap(value_parser = CheckPathSpec)]
pub pathspec: Vec<BString>,
Expand Down

0 comments on commit 46e5919

Please sign in to comment.