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
21 pub submodules: Submodules,21 pub submodules: Submodules,
22 pub thread_limit: Option<usize>,22 pub thread_limit: Option<usize>,
23 pub statistics: bool,23 pub statistics: bool,
24 pub allow_write: bool,
24}25}
25 26
26pub fn show(27pub fn show(
@@ -34,6 +35,7 @@ pub fn show( · 7 unmodified lines
34 // TODO: implement this35 // TODO: implement this
35 submodules: _,36 submodules: _,
36 thread_limit,37 thread_limit,
38 allow_write,
37 statistics,39 statistics,
38 }: Options,40 }: Options,
39) -> anyhow::Result<()> {41) -> anyhow::Result<()> {
@@ -67,11 +69,15 @@ pub fn show( · 27 unmodified lines
67 _ => unreachable!("state must be attributes stack only"),69 _ => unreachable!("state must be attributes stack only"),
68 },70 },
69 };71 };
72 let mut printer = Printer {
73 out,
74 changes: Vec::new(),
75 };
70 let outcome = gix_status::index_as_worktree(76 let outcome = gix_status::index_as_worktree(
71 index,77 index,
72 repo.work_dir()78 repo.work_dir()
73 .context("This operation cannot be run on a bare repository")?,79 .context("This operation cannot be run on a bare repository")?,
74 &mut Printer(out),80 &mut printer,
75 FastEq,81 FastEq,
76 Submodule,82 Submodule,
77 {83 {
@@ -88,6 +94,27 @@ pub fn show( · 10 unmodified lines
88 options,94 options,
89 )?;95 )?;
90 96
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
91 if statistics {118 if statistics {
92 writeln!(err, "{outcome:#?}").ok();119 writeln!(err, "{outcome:#?}").ok();
93 }120 }
@@ -109,7 +136,15 @@ impl gix_status::index_as_worktree::traits::SubmoduleStatus for Submodule { · 15 unmodified lines
109 }136 }
110}137}
111 138
112struct Printer<W>(W);139struct Printer<W> {
140 out: W,
141 changes: Vec<(usize, ApplyChange)>,
142}
143
144enum ApplyChange {
145 SetSizeToZero,
146 NewStat(gix::index::entry::Stat),
147}
113 148
114impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W>149impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W>
115where150where
@@ -122,28 +157,40 @@ where · 6 unmodified lines
122 &mut self,157 &mut self,
123 _entries: &'index [Entry],158 _entries: &'index [Entry],
124 _entry: &'index Entry,159 _entry: &'index Entry,
125 _entry_index: usize,160 entry_index: usize,
126 rela_path: &'index BStr,161 rela_path: &'index BStr,
127 status: EntryStatus<Self::ContentChange>,162 status: EntryStatus<Self::ContentChange>,
128 ) {163 ) {
129 self.visit_inner(rela_path, status).ok();164 self.visit_inner(entry_index, rela_path, status).ok();
130 }165 }
131}166}
132 167
133impl<W: std::io::Write> Printer<W> {168impl<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<()> {
135 let char_storage;170 let char_storage;
136 let status = match status {171 let status = match status {
137 EntryStatus::Conflict(conflict) => as_str(conflict),172 EntryStatus::Conflict(conflict) => as_str(conflict),
138 EntryStatus::Change(change) => {173 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 }
139 char_storage = change_to_char(&change);183 char_storage = change_to_char(&change);
140 std::str::from_utf8(std::slice::from_ref(&char_storage)).expect("valid ASCII")184 std::str::from_utf8(std::slice::from_ref(&char_storage)).expect("valid ASCII")
141 }185 }
142 EntryStatus::NeedsUpdate(_) => return Ok(()),186 EntryStatus::NeedsUpdate(stat) => {
187 self.changes.push((entry_index, ApplyChange::NewStat(stat)));
188 return Ok(());
189 }
143 EntryStatus::IntentToAdd => "A",190 EntryStatus::IntentToAdd => "A",
144 };191 };
145 192
146 writeln!(&mut self.0, "{status: >3} {rela_path}")193 writeln!(&mut self.out, "{status: >3} {rela_path}")
147 }194 }
148}195}
149 196
src/plumbing/main.rs+2−0
@@ -136,6 +136,7 @@ pub fn main() -> Result<()> { · 135 unmodified lines
136 Subcommands::Status(crate::plumbing::options::status::Platform {136 Subcommands::Status(crate::plumbing::options::status::Platform {
137 statistics,137 statistics,
138 submodules,138 submodules,
139 no_write,
139 pathspec,140 pathspec,
140 }) => prepare_and_run(141 }) => prepare_and_run(
141 "status",142 "status",
@@ -156,6 +157,7 @@ pub fn main() -> Result<()> { · 14 unmodified lines
156 format,157 format,
157 statistics,158 statistics,
158 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!159 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,
159 submodules: match submodules {161 submodules: match submodules {
160 Submodules::All => core::repository::status::Submodules::All,162 Submodules::All => core::repository::status::Submodules::All,
161 Submodules::RefChange => core::repository::status::Submodules::RefChange,163 Submodules::RefChange => core::repository::status::Submodules::RefChange,
src/plumbing/options/mod.rs+3−0
@@ -208,6 +208,9 @@ pub mod status { · 207 unmodified lines
208 /// Print additional statistics to help understanding performance.208 /// Print additional statistics to help understanding performance.
209 #[clap(long, short = 's')]209 #[clap(long, short = 's')]
210 pub statistics: bool,210 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,
211 /// The git path specifications to list attributes for, or unset to read from stdin one per line.214 /// The git path specifications to list attributes for, or unset to read from stdin one per line.
212 #[clap(value_parser = CheckPathSpec)]215 #[clap(value_parser = CheckPathSpec)]
213 pub pathspec: Vec<BString>,216 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