| @@ -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 | |
| 26 | pub fn show( | 27 | pub fn show( |
| @@ -34,6 +35,7 @@ pub fn show( · 7 unmodified lines |
| 34 | // TODO: implement this | 35 | // 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 | |
| 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 | } |
| 113 | | 148 | |
| 114 | impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W> | 149 | impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W> |
| 115 | where | 150 | where |
| @@ -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 | |
| 133 | impl<W: std::io::Write> Printer<W> { | 168 | 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<()> { |
| 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 | |