##// END OF EJS Templates
commit: use `dirstate.change_files` to scope the associated `addremove`...
marmoute -
r50924:28dfb2df default
parent child Browse files
Show More
@@ -1545,11 +1545,19 b' def overridesummary(orig, ui, repo, *pat'
1545
1545
1546
1546
1547 @eh.wrapfunction(scmutil, b'addremove')
1547 @eh.wrapfunction(scmutil, b'addremove')
1548 def scmutiladdremove(orig, repo, matcher, prefix, uipathfn, opts=None):
1548 def scmutiladdremove(
1549 orig,
1550 repo,
1551 matcher,
1552 prefix,
1553 uipathfn,
1554 opts=None,
1555 open_tr=None,
1556 ):
1549 if opts is None:
1557 if opts is None:
1550 opts = {}
1558 opts = {}
1551 if not lfutil.islfilesrepo(repo):
1559 if not lfutil.islfilesrepo(repo):
1552 return orig(repo, matcher, prefix, uipathfn, opts)
1560 return orig(repo, matcher, prefix, uipathfn, opts, open_tr=open_tr)
1553 # Get the list of missing largefiles so we can remove them
1561 # Get the list of missing largefiles so we can remove them
1554 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1562 lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
1555 unsure, s, mtime_boundary = lfdirstate.status(
1563 unsure, s, mtime_boundary = lfdirstate.status(
@@ -1560,6 +1568,10 b' def scmutiladdremove(orig, repo, matcher'
1560 unknown=False,
1568 unknown=False,
1561 )
1569 )
1562
1570
1571 # open the transaction and changing_files context
1572 if open_tr is not None:
1573 open_tr()
1574
1563 # Call into the normal remove code, but the removing of the standin, we want
1575 # Call into the normal remove code, but the removing of the standin, we want
1564 # to have handled by original addremove. Monkey patching here makes sure
1576 # to have handled by original addremove. Monkey patching here makes sure
1565 # we don't remove the standin in the largefiles code, preventing a very
1577 # we don't remove the standin in the largefiles code, preventing a very
@@ -1592,7 +1604,8 b' def scmutiladdremove(orig, repo, matcher'
1592 # function to take care of the rest. Make sure it doesn't do anything with
1604 # function to take care of the rest. Make sure it doesn't do anything with
1593 # largefiles by passing a matcher that will ignore them.
1605 # largefiles by passing a matcher that will ignore them.
1594 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1606 matcher = composenormalfilematcher(matcher, repo[None].manifest(), added)
1595 return orig(repo, matcher, prefix, uipathfn, opts)
1607
1608 return orig(repo, matcher, prefix, uipathfn, opts, open_tr=open_tr)
1596
1609
1597
1610
1598 # Calling purge with --all will cause the largefiles to be deleted.
1611 # Calling purge with --all will cause the largefiles to be deleted.
@@ -29,7 +29,6 b' from . import ('
29 changelog,
29 changelog,
30 copies,
30 copies,
31 crecord as crecordmod,
31 crecord as crecordmod,
32 dirstateguard,
33 encoding,
32 encoding,
34 error,
33 error,
35 formatter,
34 formatter,
@@ -2789,21 +2788,114 b' def cat(ui, repo, ctx, matcher, basefm, '
2789 return err
2788 return err
2790
2789
2791
2790
2791 class _AddRemoveContext:
2792 """a small (hacky) context to deal with lazy opening of context
2793
2794 This is to be used in the `commit` function right below. This deals with
2795 lazily open a `changing_files` context inside a `transaction` that span the
2796 full commit operation.
2797
2798 We need :
2799 - a `changing_files` context to wrap the dirstate change within the
2800 "addremove" operation,
2801 - a transaction to make sure these change are not written right after the
2802 addremove, but when the commit operation succeed.
2803
2804 However it get complicated because:
2805 - opening a transaction "this early" shuffle hooks order, especially the
2806 `precommit` one happening after the `pretxtopen` one which I am not too
2807 enthusiastic about.
2808 - the `mq` extensions + the `record` extension stacks many layers of call
2809 to implement `qrefresh --interactive` and this result with `mq` calling a
2810 `strip` in the middle of this function. Which prevent the existence of
2811 transaction wrapping all of its function code. (however, `qrefresh` never
2812 call the `addremove` bits.
2813 - the largefile extensions (and maybe other extensions?) wraps `addremove`
2814 so slicing `addremove` in smaller bits is a complex endeavour.
2815
2816 So I eventually took a this shortcut that open the transaction if we
2817 actually needs it, not disturbing much of the rest of the code.
2818
2819 It will result in some hooks order change for `hg commit --addremove`,
2820 however it seems a corner case enough to ignore that for now (hopefully).
2821
2822 Notes that None of the above problems seems insurmountable, however I have
2823 been fighting with this specific piece of code for a couple of day already
2824 and I need a solution to keep moving forward on the bigger work around
2825 `changing_files` context that is being introduced at the same time as this
2826 hack.
2827
2828 Each problem seems to have a solution:
2829 - the hook order issue could be solved by refactoring the many-layer stack
2830 that currently composes a commit and calling them earlier,
2831 - the mq issue could be solved by refactoring `mq` so that the final strip
2832 is done after transaction closure. Be warned that the mq code is quite
2833 antic however.
2834 - large-file could be reworked in parallel of the `addremove` to be
2835 friendlier to this.
2836
2837 However each of these tasks are too much a diversion right now. In addition
2838 they will be much easier to undertake when the `changing_files` dust has
2839 settled."""
2840
2841 def __init__(self, repo):
2842 self._repo = repo
2843 self._transaction = None
2844 self._dirstate_context = None
2845 self._state = None
2846
2847 def __enter__(self):
2848 assert self._state is None
2849 self._state = True
2850 return self
2851
2852 def open_transaction(self):
2853 """open a `transaction` and `changing_files` context
2854
2855 Call this when you know that change to the dirstate will be needed and
2856 we need to open the transaction early
2857
2858 This will also open the dirstate `changing_files` context, so you should
2859 call `close_dirstate_context` when the distate changes are done.
2860 """
2861 assert self._state is not None
2862 if self._transaction is None:
2863 self._transaction = self._repo.transaction(b'commit')
2864 self._transaction.__enter__()
2865 if self._dirstate_context is None:
2866 self._dirstate_context = self._repo.dirstate.changing_files(
2867 self._repo
2868 )
2869 self._dirstate_context.__enter__()
2870
2871 def close_dirstate_context(self):
2872 """close the change_files if any
2873
2874 Call this after the (potential) `open_transaction` call to close the
2875 (potential) changing_files context.
2876 """
2877 if self._dirstate_context is not None:
2878 self._dirstate_context.__exit__(None, None, None)
2879 self._dirstate_context = None
2880
2881 def __exit__(self, *args):
2882 if self._dirstate_context is not None:
2883 self._dirstate_context.__exit__(*args)
2884 if self._transaction is not None:
2885 self._transaction.__exit__(*args)
2886
2887
2792 def commit(ui, repo, commitfunc, pats, opts):
2888 def commit(ui, repo, commitfunc, pats, opts):
2793 '''commit the specified files or all outstanding changes'''
2889 '''commit the specified files or all outstanding changes'''
2794 date = opts.get(b'date')
2890 date = opts.get(b'date')
2795 if date:
2891 if date:
2796 opts[b'date'] = dateutil.parsedate(date)
2892 opts[b'date'] = dateutil.parsedate(date)
2797
2893
2798 dsguard = None
2894 with repo.wlock(), repo.lock():
2799 # extract addremove carefully -- this function can be called from a command
2800 # that doesn't support addremove
2801 if opts.get(b'addremove'):
2802 dsguard = dirstateguard.dirstateguard(repo, b'commit')
2803 with dsguard or util.nullcontextmanager():
2804 message = logmessage(ui, opts)
2895 message = logmessage(ui, opts)
2805 matcher = scmutil.match(repo[None], pats, opts)
2896 matcher = scmutil.match(repo[None], pats, opts)
2806 if True:
2897
2898 with _AddRemoveContext(repo) as c:
2807 # extract addremove carefully -- this function can be called from a
2899 # extract addremove carefully -- this function can be called from a
2808 # command that doesn't support addremove
2900 # command that doesn't support addremove
2809 if opts.get(b'addremove'):
2901 if opts.get(b'addremove'):
@@ -2818,11 +2910,12 b' def commit(ui, repo, commitfunc, pats, o'
2818 b"",
2910 b"",
2819 uipathfn,
2911 uipathfn,
2820 opts,
2912 opts,
2913 open_tr=c.open_transaction,
2821 )
2914 )
2822 m = _(b"failed to mark all new/missing files as added/removed")
2915 m = _(b"failed to mark all new/missing files as added/removed")
2823 if r != 0:
2916 if r != 0:
2824 raise error.Abort(m)
2917 raise error.Abort(m)
2825
2918 c.close_dirstate_context()
2826 return commitfunc(ui, repo, message, matcher, opts)
2919 return commitfunc(ui, repo, message, matcher, opts)
2827
2920
2828
2921
@@ -1219,7 +1219,7 b' def cleanupnodes('
1219 )
1219 )
1220
1220
1221
1221
1222 def addremove(repo, matcher, prefix, uipathfn, opts=None):
1222 def addremove(repo, matcher, prefix, uipathfn, opts=None, open_tr=None):
1223 if opts is None:
1223 if opts is None:
1224 opts = {}
1224 opts = {}
1225 m = matcher
1225 m = matcher
@@ -1279,7 +1279,9 b' def addremove(repo, matcher, prefix, uip'
1279 repo, m, added + unknown, removed + deleted, similarity, uipathfn
1279 repo, m, added + unknown, removed + deleted, similarity, uipathfn
1280 )
1280 )
1281
1281
1282 if not dry_run:
1282 if not dry_run and (unknown or forgotten or deleted or renames):
1283 if open_tr is not None:
1284 open_tr()
1283 _markchanges(repo, unknown + forgotten, deleted, renames)
1285 _markchanges(repo, unknown + forgotten, deleted, renames)
1284
1286
1285 for f in rejected:
1287 for f in rejected:
@@ -103,12 +103,10 b' Non store repo:'
103 .hg/phaseroots
103 .hg/phaseroots
104 .hg/requires
104 .hg/requires
105 .hg/undo
105 .hg/undo
106 .hg/undo.backup.dirstate
107 .hg/undo.backupfiles
106 .hg/undo.backupfiles
108 .hg/undo.bookmarks
107 .hg/undo.bookmarks
109 .hg/undo.branch
108 .hg/undo.branch
110 .hg/undo.desc
109 .hg/undo.desc
111 .hg/undo.dirstate
112 .hg/undo.phaseroots
110 .hg/undo.phaseroots
113 .hg/wcache
111 .hg/wcache
114 .hg/wcache/checkisexec (execbit !)
112 .hg/wcache/checkisexec (execbit !)
@@ -147,11 +145,9 b' Non fncache repo:'
147 .hg/store/undo
145 .hg/store/undo
148 .hg/store/undo.backupfiles
146 .hg/store/undo.backupfiles
149 .hg/store/undo.phaseroots
147 .hg/store/undo.phaseroots
150 .hg/undo.backup.dirstate
151 .hg/undo.bookmarks
148 .hg/undo.bookmarks
152 .hg/undo.branch
149 .hg/undo.branch
153 .hg/undo.desc
150 .hg/undo.desc
154 .hg/undo.dirstate
155 .hg/wcache
151 .hg/wcache
156 .hg/wcache/checkisexec (execbit !)
152 .hg/wcache/checkisexec (execbit !)
157 .hg/wcache/checklink (symlink !)
153 .hg/wcache/checklink (symlink !)
@@ -95,11 +95,9 b' new directories are setgid'
95 00660 ./.hg/store/undo
95 00660 ./.hg/store/undo
96 00660 ./.hg/store/undo.backupfiles
96 00660 ./.hg/store/undo.backupfiles
97 00660 ./.hg/store/undo.phaseroots
97 00660 ./.hg/store/undo.phaseroots
98 00660 ./.hg/undo.backup.dirstate
99 00660 ./.hg/undo.bookmarks
98 00660 ./.hg/undo.bookmarks
100 00660 ./.hg/undo.branch
99 00660 ./.hg/undo.branch
101 00660 ./.hg/undo.desc
100 00660 ./.hg/undo.desc
102 00660 ./.hg/undo.dirstate
103 00770 ./.hg/wcache/
101 00770 ./.hg/wcache/
104 00711 ./.hg/wcache/checkisexec
102 00711 ./.hg/wcache/checkisexec
105 007.. ./.hg/wcache/checklink (re)
103 007.. ./.hg/wcache/checklink (re)
@@ -106,10 +106,10 b' happen for the changelog (the linkrev sh'
106
106
107 #if fail-if-detected
107 #if fail-if-detected
108 $ cat .foo_commit_out
108 $ cat .foo_commit_out
109 note: commit message saved in .hg/last-message.txt
110 note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it
109 transaction abort!
111 transaction abort!
110 rollback completed
112 rollback completed
111 note: commit message saved in .hg/last-message.txt
112 note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it
113 abort: 00changelog.i: file cursor at position 249, expected 121
113 abort: 00changelog.i: file cursor at position 249, expected 121
114 And no corruption in the changelog.
114 And no corruption in the changelog.
115 $ hg debugrevlogindex -c
115 $ hg debugrevlogindex -c
General Comments 0
You need to be logged in to leave comments. Login now