comparison hgext/directaccess.py @ 1339:0e2eb196923a

inhibit: create direct access extension Since we want to use direct access without necessarily using inhibit, this patch separates both extensions. Inhibit depends on direct access and we add a test to check that it complains if that is not the case.
author Laurent Charignon <lcharignon@fb.com>
date Thu, 14 May 2015 11:23:40 -0700
parents
children b00c2fe51ac8
comparison
equal deleted inserted replaced
1338:77cbf9121e8a 1339:0e2eb196923a
1 """ This extension provides direct access
2 It is the ability to refer and access hidden sha in commands provided that you
3 know their value.
4 For example hg log -r xxx where xxx is a commit has should work whether xxx is
5 hidden or not as we assume that the user knows what he is doing when referring
6 to xxx.
7 """
8 from mercurial import extensions
9 from mercurial import cmdutil
10 from mercurial import repoview
11 from mercurial import branchmap
12 from mercurial import revset
13 from mercurial import error
14 from mercurial import commands
15 from mercurial.i18n import _
16
17 cmdtable = {}
18 command = cmdutil.command(cmdtable)
19
20 # List of commands where no warning is shown for direct access
21 directaccesslevel = [
22 # warning or not, extension (None if core), command name
23 (False, None, 'update'),
24 (False, None, 'export'),
25 (True, 'rebase', 'rebase'),
26 (False, 'evolve', 'prune'),
27 ]
28
29 def reposetup(ui, repo):
30 repo._explicitaccess = set()
31
32 def _computehidden(repo):
33 hidden = repoview.computehidden(repo)
34 cl = repo.changelog
35 dynamic = hidden & repo._explicitaccess
36 if dynamic:
37 blocked = cl.ancestors(dynamic, inclusive=True)
38 hidden = frozenset(r for r in hidden if r not in blocked)
39 return hidden
40
41 def setupdirectaccess():
42 """ Add two new filtername that behave like visible to provide direct access
43 and direct access with warning. Wraps the commands to setup direct access """
44 repoview.filtertable.update({'visible-directaccess-nowarn': _computehidden})
45 repoview.filtertable.update({'visible-directaccess-warn': _computehidden})
46 branchmap.subsettable['visible-directaccess-nowarn'] = 'visible'
47 branchmap.subsettable['visible-directaccess-warn'] = 'visible'
48
49 for warn, ext, cmd in directaccesslevel:
50 cmdtable = extensions.find(ext).cmdtable if ext else commands.table
51 wrapper = wrapwithwarning if warn else wrapwithoutwarning
52 try:
53 extensions.wrapcommand(cmdtable, cmd, wrapper)
54 except error.UnknownCommand:
55 pass
56
57 def wrapwithoutwarning(orig, ui, repo, *args, **kwargs):
58 if repo and repo.filtername == 'visible':
59 repo = repo.filtered("visible-directaccess-nowarn")
60 return orig(ui, repo, *args, **kwargs)
61
62 def wrapwithwarning(orig, ui, repo, *args, **kwargs):
63 if repo and repo.filtername == 'visible':
64 repo = repo.filtered("visible-directaccess-warn")
65 return orig(ui, repo, *args, **kwargs)
66
67 def extsetup(ui):
68 extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook)
69 setupdirectaccess()
70
71 def gethashsymbols(tree):
72 # Returns the list of symbols of the tree that look like hashes
73 # for example for the revset 3::abe3ff it will return ('abe3ff')
74 if not tree:
75 return []
76
77 if len(tree) == 2 and tree[0] == "symbol":
78 try:
79 int(tree[1])
80 return []
81 except ValueError as e:
82 return [tree[1]]
83 elif len(tree) == 3:
84 return gethashsymbols(tree[1]) + gethashsymbols(tree[2])
85 else:
86 return []
87
88 def _posttreebuilthook(orig, tree, repo):
89 # This is use to enabled direct hash access
90 # We extract the symbols that look like hashes and add them to the
91 # explicitaccess set
92 orig(tree, repo)
93 filternm = ""
94 if repo is not None:
95 filternm = repo.filtername
96 if filternm is not None and filternm.startswith('visible-directaccess'):
97 prelength = len(repo._explicitaccess)
98 accessbefore = set(repo._explicitaccess)
99 repo.symbols = gethashsymbols(tree)
100 cl = repo.unfiltered().changelog
101 for node in repo.symbols:
102 try:
103 node = cl._partialmatch(node)
104 except error.LookupError:
105 node = None
106 if node is not None:
107 rev = cl.rev(node)
108 if rev not in repo.changelog:
109 repo._explicitaccess.add(rev)
110 if prelength != len(repo._explicitaccess):
111 if repo.filtername != 'visible-directaccess-nowarn':
112 unhiddencommits = repo._explicitaccess - accessbefore
113 repo.ui.warn( _("Warning: accessing hidden changesets %s "
114 "for write operation\n") %
115 (",".join([str(repo.unfiltered()[l])
116 for l in unhiddencommits])))
117 repo.invalidatevolatilesets()