211 """Wrap a status operation |
211 """Wrap a status operation |
212 |
212 |
213 This context is not mutally exclusive with the `changing_*` context. It |
213 This context is not mutally exclusive with the `changing_*` context. It |
214 also do not warrant for the `wlock` to be taken. |
214 also do not warrant for the `wlock` to be taken. |
215 |
215 |
216 If the wlock is taken, this context will (in the future) behave in a |
216 If the wlock is taken, this context will behave in a simple way, and |
217 simple way, and ensure the data are scheduled for write when leaving |
217 ensure the data are scheduled for write when leaving the top level |
218 the top level context. |
218 context. |
219 |
219 |
220 If the lock is not taken, it will only warrant that the data are either |
220 If the lock is not taken, it will only warrant that the data are either |
221 committed (written) and rolled back (invalidated) when exiting the top |
221 committed (written) and rolled back (invalidated) when exiting the top |
222 level context. The write/invalidate action must be performed by the |
222 level context. The write/invalidate action must be performed by the |
223 wrapped code. |
223 wrapped code. |
233 D: try to take the w-lock (this will invalidate the changes if they were raced) |
233 D: try to take the w-lock (this will invalidate the changes if they were raced) |
234 E0: if dirstate changed on disk → discard change (done by dirstate internal) |
234 E0: if dirstate changed on disk → discard change (done by dirstate internal) |
235 E1: elif lock was acquired → write the changes |
235 E1: elif lock was acquired → write the changes |
236 E2: else → discard the changes |
236 E2: else → discard the changes |
237 """ |
237 """ |
|
238 has_lock = repo.currentwlock() is not None |
238 is_changing = self.is_changing_any |
239 is_changing = self.is_changing_any |
239 has_tr = repo.currenttransaction is not None |
240 tr = repo.currenttransaction() |
|
241 has_tr = tr is not None |
240 nested = bool(self._running_status) |
242 nested = bool(self._running_status) |
241 |
243 |
242 first_and_alone = not (is_changing or has_tr or nested) |
244 first_and_alone = not (is_changing or has_tr or nested) |
243 |
245 |
244 # enforce no change happened outside of a proper context. |
246 # enforce no change happened outside of a proper context. |
245 if first_and_alone and self._dirty: |
247 if first_and_alone and self._dirty: |
246 has_tr = repo.currenttransaction() is not None |
248 has_tr = repo.currenttransaction() is not None |
247 if not has_tr and self._changing_level == 0 and self._dirty: |
249 if not has_tr and self._changing_level == 0 and self._dirty: |
248 msg = "entering a status context, but dirstate is already dirty" |
250 msg = "entering a status context, but dirstate is already dirty" |
249 raise error.ProgrammingError(msg) |
251 raise error.ProgrammingError(msg) |
|
252 |
|
253 should_write = has_lock and not (nested or is_changing) |
250 |
254 |
251 self._running_status += 1 |
255 self._running_status += 1 |
252 try: |
256 try: |
253 yield |
257 yield |
254 except Exception: |
258 except Exception: |
255 self.invalidate() |
259 self.invalidate() |
256 raise |
260 raise |
257 finally: |
261 finally: |
258 self._running_status -= 1 |
262 self._running_status -= 1 |
259 if self._invalidated_context: |
263 if self._invalidated_context: |
|
264 should_write = False |
260 self.invalidate() |
265 self.invalidate() |
|
266 |
|
267 if should_write: |
|
268 assert repo.currenttransaction() is tr |
|
269 self.write(tr) |
261 |
270 |
262 @contextlib.contextmanager |
271 @contextlib.contextmanager |
263 @check_invalidated |
272 @check_invalidated |
264 def _changing(self, repo, change_type): |
273 def _changing(self, repo, change_type): |
265 if repo.currentwlock() is None: |
274 if repo.currentwlock() is None: |