|
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() |