History

feat: `gix status` auto-writes changed indices.

This prevents expensive operations to re-occour.

Sebastian Thiel committed 3 years ago

Commit 46e59191 parent b5b50f83 files · +59 −7Browse files

Unified · Split

3 files
  1. gitoxide-core/src/repository/status.rs +54 −7
  2. src/plumbing/main.rs +2 −0
  3. src/plumbing/options/mod.rs +3 −0
gitoxide-core/src/repository/status.rs+54−7
@@ -21,6 +21,7 @@ pub struct Options { · 20 unmodified lines
2121 pub submodules: Submodules,
2222 pub thread_limit: Option<usize>,
2323 pub statistics: bool,
24+ pub allow_write: bool,
2425 }
2526
2627 pub fn show(
@@ -34,6 +35,7 @@ pub fn show( · 7 unmodified lines
3435 // TODO: implement this
3536 submodules: _,
3637 thread_limit,
38+ allow_write,
3739 statistics,
3840 }: Options,
3941 ) -> anyhow::Result<()> {
@@ -67,11 +69,15 @@ pub fn show( · 27 unmodified lines
6769 _ => unreachable!("state must be attributes stack only"),
6870 },
6971 };
72+ let mut printer = Printer {
73+ out,
74+ changes: Vec::new(),
75+ };
7076 let outcome = gix_status::index_as_worktree(
7177 index,
7278 repo.work_dir()
7379 .context("This operation cannot be run on a bare repository")?,
74− &mut Printer(out),
80+ &mut printer,
7581 FastEq,
7682 Submodule,
7783 {
@@ -88,6 +94,27 @@ pub fn show( · 10 unmodified lines
8894 options,
8995 )?;
9096
97+ if outcome.entries_to_update != 0 && allow_write {
98+ {
99+ let entries = index.entries_mut();
100+ for (entry_index, change) in printer.changes {
101+ let entry = &mut entries[entry_index];
102+ match change {
103+ ApplyChange::SetSizeToZero => {
104+ entry.stat.size = 0;
105+ }
106+ ApplyChange::NewStat(new_stat) => {
107+ entry.stat = new_stat;
108+ }
109+ }
110+ }
111+ }
112+ index.write(gix::index::write::Options {
113+ extensions: Default::default(),
114+ skip_hash: false, // TODO: make this based on configuration
115+ })?;
116+ }
117+
91118 if statistics {
92119 writeln!(err, "{outcome:#?}").ok();
93120 }
@@ -109,7 +136,15 @@ impl gix_status::index_as_worktree::traits::SubmoduleStatus for Submodule { · 15 unmodified lines
109136 }
110137 }
111138
112−struct Printer<W>(W);
139+struct Printer<W> {
140+ out: W,
141+ changes: Vec<(usize, ApplyChange)>,
142+}
143+
144+enum ApplyChange {
145+ SetSizeToZero,
146+ NewStat(gix::index::entry::Stat),
147+}
113148
114149 impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W>
115150 where
@@ -122,28 +157,40 @@ where · 6 unmodified lines
122157 &mut self,
123158 _entries: &'index [Entry],
124159 _entry: &'index Entry,
125− _entry_index: usize,
160+ entry_index: usize,
126161 rela_path: &'index BStr,
127162 status: EntryStatus<Self::ContentChange>,
128163 ) {
129− self.visit_inner(rela_path, status).ok();
164+ self.visit_inner(entry_index, rela_path, status).ok();
130165 }
131166 }
132167
133168 impl<W: std::io::Write> Printer<W> {
134− fn visit_inner(&mut self, rela_path: &BStr, status: EntryStatus<()>) -> std::io::Result<()> {
169+ fn visit_inner(&mut self, entry_index: usize, rela_path: &BStr, status: EntryStatus<()>) -> std::io::Result<()> {
135170 let char_storage;
136171 let status = match status {
137172 EntryStatus::Conflict(conflict) => as_str(conflict),
138173 EntryStatus::Change(change) => {
174+ if matches!(
175+ change,
176+ Change::Modification {
177+ set_entry_stat_size_zero: true,
178+ ..
179+ }
180+ ) {
181+ self.changes.push((entry_index, ApplyChange::SetSizeToZero))
182+ }
139183 char_storage = change_to_char(&change);
140184 std::str::from_utf8(std::slice::from_ref(&char_storage)).expect("valid ASCII")
141185 }
142− EntryStatus::NeedsUpdate(_) => return Ok(()),
186+ EntryStatus::NeedsUpdate(stat) => {
187+ self.changes.push((entry_index, ApplyChange::NewStat(stat)));
188+ return Ok(());
189+ }
143190 EntryStatus::IntentToAdd => "A",
144191 };
145192
146− writeln!(&mut self.0, "{status: >3} {rela_path}")
193+ writeln!(&mut self.out, "{status: >3} {rela_path}")
147194 }
148195 }
149196
src/plumbing/main.rs+2−0
@@ -136,6 +136,7 @@ pub fn main() -> Result<()> { · 135 unmodified lines
136136 Subcommands::Status(crate::plumbing::options::status::Platform {
137137 statistics,
138138 submodules,
139+ no_write,
139140 pathspec,
140141 }) => prepare_and_run(
141142 "status",
@@ -156,6 +157,7 @@ pub fn main() -> Result<()> { · 14 unmodified lines
156157 format,
157158 statistics,
158159 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!
160+ allow_write: !no_write,
159161 submodules: match submodules {
160162 Submodules::All => core::repository::status::Submodules::All,
161163 Submodules::RefChange => core::repository::status::Submodules::RefChange,
src/plumbing/options/mod.rs+3−0
@@ -208,6 +208,9 @@ pub mod status { · 207 unmodified lines
208208 /// Print additional statistics to help understanding performance.
209209 #[clap(long, short = 's')]
210210 pub statistics: bool,
211+ /// Don't write back a changed index, which forces this operation to always be idempotent.
212+ #[clap(long)]
213+ pub no_write: bool,
211214 /// The git path specifications to list attributes for, or unset to read from stdin one per line.
212215 #[clap(value_parser = CheckPathSpec)]
213216 pub pathspec: Vec<BString>,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t