24 from mercurial import obsolete |
24 from mercurial import obsolete |
25 from mercurial import extensions |
25 from mercurial import extensions |
26 from mercurial import cmdutil |
26 from mercurial import cmdutil |
27 from mercurial import scmutil |
27 from mercurial import scmutil |
28 from mercurial import repoview |
28 from mercurial import repoview |
|
29 from mercurial import branchmap |
29 from mercurial import revset |
30 from mercurial import revset |
30 from mercurial import error |
31 from mercurial import error |
31 from mercurial import commands |
32 from mercurial import commands |
32 from mercurial import lock as lockmod |
33 from mercurial import lock as lockmod |
33 from mercurial import bookmarks |
34 from mercurial import bookmarks |
34 from mercurial import lock as lockmod |
35 from mercurial import lock as lockmod |
35 from mercurial.i18n import _ |
36 from mercurial.i18n import _ |
36 |
37 |
37 cmdtable = {} |
38 cmdtable = {} |
38 command = cmdutil.command(cmdtable) |
39 command = cmdutil.command(cmdtable) |
|
40 |
|
41 # List of commands where no warning is shown for direct access |
|
42 directaccesslevel = [ |
|
43 # warning or not, extension (None if core), command name |
|
44 (False, None, 'update'), |
|
45 (False, None, 'export'), |
|
46 (True, 'rebase', 'rebase'), |
|
47 (False, 'evolve', 'prune'), |
|
48 ] |
39 |
49 |
40 def reposetup(ui, repo): |
50 def reposetup(ui, repo): |
41 |
51 |
42 class obsinhibitedrepo(repo.__class__): |
52 class obsinhibitedrepo(repo.__class__): |
43 |
53 |
60 if not ui.configbool('inhibit', 'onlydirectaccess', False): |
70 if not ui.configbool('inhibit', 'onlydirectaccess', False): |
61 # Wrapping this to inhibit obsolete revs resulting from a transaction |
71 # Wrapping this to inhibit obsolete revs resulting from a transaction |
62 extensions.wrapfunction(localrepo.localrepository, |
72 extensions.wrapfunction(localrepo.localrepository, |
63 'transaction', transactioncallback) |
73 'transaction', transactioncallback) |
64 |
74 |
65 |
75 def _computehidden(repo): |
|
76 hidden = repoview.computehidden(repo) |
|
77 cl = repo.changelog |
|
78 dynamic = hidden & repo._explicitaccess |
|
79 if dynamic: |
|
80 blocked = cl.ancestors(dynamic, inclusive=True) |
|
81 hidden = frozenset(r for r in hidden if r not in blocked) |
|
82 return hidden |
|
83 |
|
84 def setupdirectaccess(): |
|
85 """ Add two new filtername that behave like visible to provide direct access |
|
86 and direct access with warning. Wraps the commands to setup direct access """ |
|
87 repoview.filtertable.update({'visible-directaccess-nowarn': _computehidden}) |
|
88 repoview.filtertable.update({'visible-directaccess-warn': _computehidden}) |
|
89 branchmap.subsettable['visible-directaccess-nowarn'] = 'visible' |
|
90 branchmap.subsettable['visible-directaccess-warn'] = 'visible' |
|
91 |
|
92 for warn, ext, cmd in directaccesslevel: |
|
93 cmdtable = extensions.find(ext).cmdtable if ext else commands.table |
|
94 wrapper = wrapwithwarning if warn else wrapwithoutwarning |
|
95 try: |
|
96 extensions.wrapcommand(cmdtable, cmd, wrapper) |
|
97 except error.UnknownCommand: |
|
98 pass |
66 def _update(orig, ui, repo, *args, **kwargs): |
99 def _update(orig, ui, repo, *args, **kwargs): |
67 """ |
100 """ |
68 When moving to a commit we want to inhibit any obsolete commit affecting |
101 When moving to a commit we want to inhibit any obsolete commit affecting |
69 the changeset we are updating to. In other words we don't want any visible |
102 the changeset we are updating to. In other words we don't want any visible |
70 commit to be obsolete. |
103 commit to be obsolete. |
190 _inhibitmarkers(repo, [repo[r].node() for r in visibleobsolete]) |
223 _inhibitmarkers(repo, [repo[r].node() for r in visibleobsolete]) |
191 transaction = orig(repo, *args, **kwargs) |
224 transaction = orig(repo, *args, **kwargs) |
192 transaction.addpostclose('inhibitposttransaction', inhibitposttransaction) |
225 transaction.addpostclose('inhibitposttransaction', inhibitposttransaction) |
193 return transaction |
226 return transaction |
194 |
227 |
|
228 def wrapwithoutwarning(orig, ui, repo, *args, **kwargs): |
|
229 if repo and repo.filtername == 'visible': |
|
230 repo = repo.filtered("visible-directaccess-nowarn") |
|
231 return orig(ui, repo, *args, **kwargs) |
|
232 |
|
233 def wrapwithwarning(orig, ui, repo, *args, **kwargs): |
|
234 if repo and repo.filtername == 'visible': |
|
235 repo = repo.filtered("visible-directaccess-warn") |
|
236 return orig(ui, repo, *args, **kwargs) |
|
237 |
195 def extsetup(ui): |
238 def extsetup(ui): |
196 # lets wrap the computation of the obsolete set |
239 # lets wrap the computation of the obsolete set |
197 # We apply inhibition there |
240 # We apply inhibition there |
198 obsfunc = obsolete.cachefuncs['obsolete'] |
241 obsfunc = obsolete.cachefuncs['obsolete'] |
199 def _computeobsoleteset(repo): |
242 def _computeobsoleteset(repo): |
206 obs.discard(getrev(n)) |
249 obs.discard(getrev(n)) |
207 return obs |
250 return obs |
208 obsolete.cachefuncs['obsolete'] = _computeobsoleteset |
251 obsolete.cachefuncs['obsolete'] = _computeobsoleteset |
209 # wrap create marker to make it able to lift the inhibition |
252 # wrap create marker to make it able to lift the inhibition |
210 extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers) |
253 extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers) |
211 extensions.wrapfunction(repoview, '_getdynamicblockers', _accessvisible) |
|
212 extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook) |
254 extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook) |
|
255 setupdirectaccess() |
213 if not ui.configbool('inhibit', 'onlydirectaccess', False): |
256 if not ui.configbool('inhibit', 'onlydirectaccess', False): |
214 # drop divergence computation since it is incompatible with "light revive" |
257 # drop divergence computation since it is incompatible with "light revive" |
215 obsolete.cachefuncs['divergent'] = lambda repo: set() |
258 obsolete.cachefuncs['divergent'] = lambda repo: set() |
216 # drop bumped computation since it is incompatible with "light revive" |
259 # drop bumped computation since it is incompatible with "light revive" |
217 obsolete.cachefuncs['bumped'] = lambda repo: set() |
260 obsolete.cachefuncs['bumped'] = lambda repo: set() |
249 def _posttreebuilthook(orig, tree, repo): |
292 def _posttreebuilthook(orig, tree, repo): |
250 # This is use to enabled direct hash access |
293 # This is use to enabled direct hash access |
251 # We extract the symbols that look like hashes and add them to the |
294 # We extract the symbols that look like hashes and add them to the |
252 # explicitaccess set |
295 # explicitaccess set |
253 orig(tree, repo) |
296 orig(tree, repo) |
254 if repo is not None and repo.filtername == 'visible': |
297 filternm = "" |
|
298 if repo is not None: |
|
299 filternm = repo.filtername |
|
300 if filternm is not None and filternm.startswith('visible-directaccess'): |
255 prelength = len(repo._explicitaccess) |
301 prelength = len(repo._explicitaccess) |
|
302 accessbefore = set(repo._explicitaccess) |
256 repo.symbols = gethashsymbols(tree) |
303 repo.symbols = gethashsymbols(tree) |
257 cl = repo.unfiltered().changelog |
304 cl = repo.unfiltered().changelog |
258 for node in repo.symbols: |
305 for node in repo.symbols: |
259 try: |
306 try: |
260 node = cl._partialmatch(node) |
307 node = cl._partialmatch(node) |
263 if node is not None: |
310 if node is not None: |
264 rev = cl.rev(node) |
311 rev = cl.rev(node) |
265 if rev not in repo.changelog: |
312 if rev not in repo.changelog: |
266 repo._explicitaccess.add(rev) |
313 repo._explicitaccess.add(rev) |
267 if prelength != len(repo._explicitaccess): |
314 if prelength != len(repo._explicitaccess): |
|
315 if repo.filtername != 'visible-directaccess-nowarn': |
|
316 unhiddencommits = repo._explicitaccess - accessbefore |
|
317 repo.ui.warn( _("Warning: accessing hidden changesets %s " |
|
318 "for write operation\n") % |
|
319 (",".join([str(repo.unfiltered()[l]) |
|
320 for l in unhiddencommits]))) |
268 repo.invalidatevolatilesets() |
321 repo.invalidatevolatilesets() |
269 |
322 |
270 @command('debugobsinhibit', [], '') |
323 @command('debugobsinhibit', [], '') |
271 def cmddebugobsinhibit(ui, repo, *revs): |
324 def cmddebugobsinhibit(ui, repo, *revs): |
272 """inhibit obsolescence markers effect on a set of revs""" |
325 """inhibit obsolescence markers effect on a set of revs""" |
273 nodes = (repo[r].node() for r in scmutil.revrange(repo, revs)) |
326 nodes = (repo[r].node() for r in scmutil.revrange(repo, revs)) |
274 _inhibitmarkers(repo, nodes) |
327 _inhibitmarkers(repo, nodes) |
275 |
|
276 # ensure revision accessed by hash are visible |
|
277 ############################################### |
|
278 |
|
279 def _accessvisible(orig, repo): |
|
280 """ensure accessed revs stay visible""" |
|
281 blockers = orig(repo) |
|
282 blockers.update(getattr(repo, '_explicitaccess', ())) |
|
283 return blockers |
|