##// END OF EJS Templates
remotenames: drop redundant templatekw names from help text...
Yuya Nishihara -
r36458:bb852a52 default
parent child Browse files
Show More
@@ -1,307 +1,301 b''
1 # remotenames.py - extension to display remotenames
1 # remotenames.py - extension to display remotenames
2 #
2 #
3 # Copyright 2017 Augie Fackler <raf@durin42.com>
3 # Copyright 2017 Augie Fackler <raf@durin42.com>
4 # Copyright 2017 Sean Farley <sean@farley.io>
4 # Copyright 2017 Sean Farley <sean@farley.io>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """ showing remotebookmarks and remotebranches in UI
9 """ showing remotebookmarks and remotebranches in UI
10
10
11 By default both remotebookmarks and remotebranches are turned on. Config knob to
11 By default both remotebookmarks and remotebranches are turned on. Config knob to
12 control the individually are as follows.
12 control the individually are as follows.
13
13
14 Config options to tweak the default behaviour:
14 Config options to tweak the default behaviour:
15
15
16 remotenames.bookmarks
16 remotenames.bookmarks
17 Boolean value to enable or disable showing of remotebookmarks
17 Boolean value to enable or disable showing of remotebookmarks
18
18
19 remotenames.branches
19 remotenames.branches
20 Boolean value to enable or disable showing of remotebranches
20 Boolean value to enable or disable showing of remotebranches
21 """
21 """
22
22
23 from __future__ import absolute_import
23 from __future__ import absolute_import
24
24
25 import collections
25 import collections
26
26
27 from mercurial.i18n import _
27 from mercurial.i18n import _
28
28
29 from mercurial.node import (
29 from mercurial.node import (
30 bin,
30 bin,
31 )
31 )
32 from mercurial import (
32 from mercurial import (
33 logexchange,
33 logexchange,
34 namespaces,
34 namespaces,
35 pycompat,
35 pycompat,
36 registrar,
36 registrar,
37 revsetlang,
37 revsetlang,
38 smartset,
38 smartset,
39 templatekw,
39 templatekw,
40 )
40 )
41
41
42 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
42 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
43 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
43 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
44 # be specifying the version(s) of Mercurial they are tested with, or
44 # be specifying the version(s) of Mercurial they are tested with, or
45 # leave the attribute unspecified.
45 # leave the attribute unspecified.
46 testedwith = 'ships-with-hg-core'
46 testedwith = 'ships-with-hg-core'
47
47
48 configtable = {}
48 configtable = {}
49 configitem = registrar.configitem(configtable)
49 configitem = registrar.configitem(configtable)
50 templatekeyword = registrar.templatekeyword()
50 templatekeyword = registrar.templatekeyword()
51 revsetpredicate = registrar.revsetpredicate()
51 revsetpredicate = registrar.revsetpredicate()
52
52
53 configitem('remotenames', 'bookmarks',
53 configitem('remotenames', 'bookmarks',
54 default=True,
54 default=True,
55 )
55 )
56 configitem('remotenames', 'branches',
56 configitem('remotenames', 'branches',
57 default=True,
57 default=True,
58 )
58 )
59
59
60 class lazyremotenamedict(collections.MutableMapping):
60 class lazyremotenamedict(collections.MutableMapping):
61 """
61 """
62 Read-only dict-like Class to lazily resolve remotename entries
62 Read-only dict-like Class to lazily resolve remotename entries
63
63
64 We are doing that because remotenames startup was slow.
64 We are doing that because remotenames startup was slow.
65 We lazily read the remotenames file once to figure out the potential entries
65 We lazily read the remotenames file once to figure out the potential entries
66 and store them in self.potentialentries. Then when asked to resolve an
66 and store them in self.potentialentries. Then when asked to resolve an
67 entry, if it is not in self.potentialentries, then it isn't there, if it
67 entry, if it is not in self.potentialentries, then it isn't there, if it
68 is in self.potentialentries we resolve it and store the result in
68 is in self.potentialentries we resolve it and store the result in
69 self.cache. We cannot be lazy is when asked all the entries (keys).
69 self.cache. We cannot be lazy is when asked all the entries (keys).
70 """
70 """
71 def __init__(self, kind, repo):
71 def __init__(self, kind, repo):
72 self.cache = {}
72 self.cache = {}
73 self.potentialentries = {}
73 self.potentialentries = {}
74 self._kind = kind # bookmarks or branches
74 self._kind = kind # bookmarks or branches
75 self._repo = repo
75 self._repo = repo
76 self.loaded = False
76 self.loaded = False
77
77
78 def _load(self):
78 def _load(self):
79 """ Read the remotenames file, store entries matching selected kind """
79 """ Read the remotenames file, store entries matching selected kind """
80 self.loaded = True
80 self.loaded = True
81 repo = self._repo
81 repo = self._repo
82 for node, rpath, rname in logexchange.readremotenamefile(repo,
82 for node, rpath, rname in logexchange.readremotenamefile(repo,
83 self._kind):
83 self._kind):
84 name = rpath + '/' + rname
84 name = rpath + '/' + rname
85 self.potentialentries[name] = (node, rpath, name)
85 self.potentialentries[name] = (node, rpath, name)
86
86
87 def _resolvedata(self, potentialentry):
87 def _resolvedata(self, potentialentry):
88 """ Check that the node for potentialentry exists and return it """
88 """ Check that the node for potentialentry exists and return it """
89 if not potentialentry in self.potentialentries:
89 if not potentialentry in self.potentialentries:
90 return None
90 return None
91 node, remote, name = self.potentialentries[potentialentry]
91 node, remote, name = self.potentialentries[potentialentry]
92 repo = self._repo
92 repo = self._repo
93 binnode = bin(node)
93 binnode = bin(node)
94 # if the node doesn't exist, skip it
94 # if the node doesn't exist, skip it
95 try:
95 try:
96 repo.changelog.rev(binnode)
96 repo.changelog.rev(binnode)
97 except LookupError:
97 except LookupError:
98 return None
98 return None
99 # Skip closed branches
99 # Skip closed branches
100 if (self._kind == 'branches' and repo[binnode].closesbranch()):
100 if (self._kind == 'branches' and repo[binnode].closesbranch()):
101 return None
101 return None
102 return [binnode]
102 return [binnode]
103
103
104 def __getitem__(self, key):
104 def __getitem__(self, key):
105 if not self.loaded:
105 if not self.loaded:
106 self._load()
106 self._load()
107 val = self._fetchandcache(key)
107 val = self._fetchandcache(key)
108 if val is not None:
108 if val is not None:
109 return val
109 return val
110 else:
110 else:
111 raise KeyError()
111 raise KeyError()
112
112
113 def __iter__(self):
113 def __iter__(self):
114 return iter(self.potentialentries)
114 return iter(self.potentialentries)
115
115
116 def __len__(self):
116 def __len__(self):
117 return len(self.potentialentries)
117 return len(self.potentialentries)
118
118
119 def __setitem__(self):
119 def __setitem__(self):
120 raise NotImplementedError
120 raise NotImplementedError
121
121
122 def __delitem__(self):
122 def __delitem__(self):
123 raise NotImplementedError
123 raise NotImplementedError
124
124
125 def _fetchandcache(self, key):
125 def _fetchandcache(self, key):
126 if key in self.cache:
126 if key in self.cache:
127 return self.cache[key]
127 return self.cache[key]
128 val = self._resolvedata(key)
128 val = self._resolvedata(key)
129 if val is not None:
129 if val is not None:
130 self.cache[key] = val
130 self.cache[key] = val
131 return val
131 return val
132 else:
132 else:
133 return None
133 return None
134
134
135 def keys(self):
135 def keys(self):
136 """ Get a list of bookmark or branch names """
136 """ Get a list of bookmark or branch names """
137 if not self.loaded:
137 if not self.loaded:
138 self._load()
138 self._load()
139 return self.potentialentries.keys()
139 return self.potentialentries.keys()
140
140
141 def iteritems(self):
141 def iteritems(self):
142 """ Iterate over (name, node) tuples """
142 """ Iterate over (name, node) tuples """
143
143
144 if not self.loaded:
144 if not self.loaded:
145 self._load()
145 self._load()
146
146
147 for k, vtup in self.potentialentries.iteritems():
147 for k, vtup in self.potentialentries.iteritems():
148 yield (k, [bin(vtup[0])])
148 yield (k, [bin(vtup[0])])
149
149
150 class remotenames(dict):
150 class remotenames(dict):
151 """
151 """
152 This class encapsulates all the remotenames state. It also contains
152 This class encapsulates all the remotenames state. It also contains
153 methods to access that state in convenient ways. Remotenames are lazy
153 methods to access that state in convenient ways. Remotenames are lazy
154 loaded. Whenever client code needs to ensure the freshest copy of
154 loaded. Whenever client code needs to ensure the freshest copy of
155 remotenames, use the `clearnames` method to force an eventual load.
155 remotenames, use the `clearnames` method to force an eventual load.
156 """
156 """
157
157
158 def __init__(self, repo, *args):
158 def __init__(self, repo, *args):
159 dict.__init__(self, *args)
159 dict.__init__(self, *args)
160 self._repo = repo
160 self._repo = repo
161 self.clearnames()
161 self.clearnames()
162
162
163 def clearnames(self):
163 def clearnames(self):
164 """ Clear all remote names state """
164 """ Clear all remote names state """
165 self['bookmarks'] = lazyremotenamedict("bookmarks", self._repo)
165 self['bookmarks'] = lazyremotenamedict("bookmarks", self._repo)
166 self['branches'] = lazyremotenamedict("branches", self._repo)
166 self['branches'] = lazyremotenamedict("branches", self._repo)
167 self._invalidatecache()
167 self._invalidatecache()
168
168
169 def _invalidatecache(self):
169 def _invalidatecache(self):
170 self._nodetobmarks = None
170 self._nodetobmarks = None
171 self._nodetobranch = None
171 self._nodetobranch = None
172
172
173 def bmarktonodes(self):
173 def bmarktonodes(self):
174 return self['bookmarks']
174 return self['bookmarks']
175
175
176 def nodetobmarks(self):
176 def nodetobmarks(self):
177 if not self._nodetobmarks:
177 if not self._nodetobmarks:
178 bmarktonodes = self.bmarktonodes()
178 bmarktonodes = self.bmarktonodes()
179 self._nodetobmarks = {}
179 self._nodetobmarks = {}
180 for name, node in bmarktonodes.iteritems():
180 for name, node in bmarktonodes.iteritems():
181 self._nodetobmarks.setdefault(node[0], []).append(name)
181 self._nodetobmarks.setdefault(node[0], []).append(name)
182 return self._nodetobmarks
182 return self._nodetobmarks
183
183
184 def branchtonodes(self):
184 def branchtonodes(self):
185 return self['branches']
185 return self['branches']
186
186
187 def nodetobranch(self):
187 def nodetobranch(self):
188 if not self._nodetobranch:
188 if not self._nodetobranch:
189 branchtonodes = self.branchtonodes()
189 branchtonodes = self.branchtonodes()
190 self._nodetobranch = {}
190 self._nodetobranch = {}
191 for name, nodes in branchtonodes.iteritems():
191 for name, nodes in branchtonodes.iteritems():
192 for node in nodes:
192 for node in nodes:
193 self._nodetobranch.setdefault(node, []).append(name)
193 self._nodetobranch.setdefault(node, []).append(name)
194 return self._nodetobranch
194 return self._nodetobranch
195
195
196 def reposetup(ui, repo):
196 def reposetup(ui, repo):
197 if not repo.local():
197 if not repo.local():
198 return
198 return
199
199
200 repo._remotenames = remotenames(repo)
200 repo._remotenames = remotenames(repo)
201 ns = namespaces.namespace
201 ns = namespaces.namespace
202
202
203 if ui.configbool('remotenames', 'bookmarks'):
203 if ui.configbool('remotenames', 'bookmarks'):
204 remotebookmarkns = ns(
204 remotebookmarkns = ns(
205 'remotebookmarks',
205 'remotebookmarks',
206 templatename='remotebookmarks',
206 templatename='remotebookmarks',
207 colorname='remotebookmark',
207 colorname='remotebookmark',
208 logfmt='remote bookmark: %s\n',
208 logfmt='remote bookmark: %s\n',
209 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(),
209 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(),
210 namemap=lambda repo, name:
210 namemap=lambda repo, name:
211 repo._remotenames.bmarktonodes().get(name, []),
211 repo._remotenames.bmarktonodes().get(name, []),
212 nodemap=lambda repo, node:
212 nodemap=lambda repo, node:
213 repo._remotenames.nodetobmarks().get(node, []))
213 repo._remotenames.nodetobmarks().get(node, []))
214 repo.names.addnamespace(remotebookmarkns)
214 repo.names.addnamespace(remotebookmarkns)
215
215
216 if ui.configbool('remotenames', 'branches'):
216 if ui.configbool('remotenames', 'branches'):
217 remotebranchns = ns(
217 remotebranchns = ns(
218 'remotebranches',
218 'remotebranches',
219 templatename='remotebranches',
219 templatename='remotebranches',
220 colorname='remotebranch',
220 colorname='remotebranch',
221 logfmt='remote branch: %s\n',
221 logfmt='remote branch: %s\n',
222 listnames = lambda repo: repo._remotenames.branchtonodes().keys(),
222 listnames = lambda repo: repo._remotenames.branchtonodes().keys(),
223 namemap = lambda repo, name:
223 namemap = lambda repo, name:
224 repo._remotenames.branchtonodes().get(name, []),
224 repo._remotenames.branchtonodes().get(name, []),
225 nodemap = lambda repo, node:
225 nodemap = lambda repo, node:
226 repo._remotenames.nodetobranch().get(node, []))
226 repo._remotenames.nodetobranch().get(node, []))
227 repo.names.addnamespace(remotebranchns)
227 repo.names.addnamespace(remotebranchns)
228
228
229 @templatekeyword('remotenames')
229 @templatekeyword('remotenames')
230 def remotenameskw(**args):
230 def remotenameskw(**args):
231 """:remotenames: List of strings. List of remote names associated with the
231 """List of strings. Remote names associated with the changeset."""
232 changeset.
233 """
234 args = pycompat.byteskwargs(args)
232 args = pycompat.byteskwargs(args)
235 repo, ctx = args['repo'], args['ctx']
233 repo, ctx = args['repo'], args['ctx']
236
234
237 remotenames = []
235 remotenames = []
238 if 'remotebookmarks' in repo.names:
236 if 'remotebookmarks' in repo.names:
239 remotenames = repo.names['remotebookmarks'].names(repo, ctx.node())
237 remotenames = repo.names['remotebookmarks'].names(repo, ctx.node())
240
238
241 if 'remotebranches' in repo.names:
239 if 'remotebranches' in repo.names:
242 remotenames += repo.names['remotebranches'].names(repo, ctx.node())
240 remotenames += repo.names['remotebranches'].names(repo, ctx.node())
243
241
244 return templatekw.showlist('remotename', remotenames, args,
242 return templatekw.showlist('remotename', remotenames, args,
245 plural='remotenames')
243 plural='remotenames')
246
244
247 @templatekeyword('remotebookmarks')
245 @templatekeyword('remotebookmarks')
248 def remotebookmarkskw(**args):
246 def remotebookmarkskw(**args):
249 """:remotebookmarks: List of strings. List of remote bookmarks associated
247 """List of strings. Remote bookmarks associated with the changeset."""
250 with the changeset.
251 """
252 args = pycompat.byteskwargs(args)
248 args = pycompat.byteskwargs(args)
253 repo, ctx = args['repo'], args['ctx']
249 repo, ctx = args['repo'], args['ctx']
254
250
255 remotebmarks = []
251 remotebmarks = []
256 if 'remotebookmarks' in repo.names:
252 if 'remotebookmarks' in repo.names:
257 remotebmarks = repo.names['remotebookmarks'].names(repo, ctx.node())
253 remotebmarks = repo.names['remotebookmarks'].names(repo, ctx.node())
258
254
259 return templatekw.showlist('remotebookmark', remotebmarks, args,
255 return templatekw.showlist('remotebookmark', remotebmarks, args,
260 plural='remotebookmarks')
256 plural='remotebookmarks')
261
257
262 @templatekeyword('remotebranches')
258 @templatekeyword('remotebranches')
263 def remotebrancheskw(**args):
259 def remotebrancheskw(**args):
264 """:remotebranches: List of strings. List of remote branches associated
260 """List of strings. Remote branches associated with the changeset."""
265 with the changeset.
266 """
267 args = pycompat.byteskwargs(args)
261 args = pycompat.byteskwargs(args)
268 repo, ctx = args['repo'], args['ctx']
262 repo, ctx = args['repo'], args['ctx']
269
263
270 remotebranches = []
264 remotebranches = []
271 if 'remotebranches' in repo.names:
265 if 'remotebranches' in repo.names:
272 remotebranches = repo.names['remotebranches'].names(repo, ctx.node())
266 remotebranches = repo.names['remotebranches'].names(repo, ctx.node())
273
267
274 return templatekw.showlist('remotebranch', remotebranches, args,
268 return templatekw.showlist('remotebranch', remotebranches, args,
275 plural='remotebranches')
269 plural='remotebranches')
276
270
277 def _revsetutil(repo, subset, x, rtypes):
271 def _revsetutil(repo, subset, x, rtypes):
278 """utility function to return a set of revs based on the rtypes"""
272 """utility function to return a set of revs based on the rtypes"""
279
273
280 revs = set()
274 revs = set()
281 cl = repo.changelog
275 cl = repo.changelog
282 for rtype in rtypes:
276 for rtype in rtypes:
283 if rtype in repo.names:
277 if rtype in repo.names:
284 ns = repo.names[rtype]
278 ns = repo.names[rtype]
285 for name in ns.listnames(repo):
279 for name in ns.listnames(repo):
286 revs.update(ns.nodes(repo, name))
280 revs.update(ns.nodes(repo, name))
287
281
288 results = (cl.rev(n) for n in revs if cl.hasnode(n))
282 results = (cl.rev(n) for n in revs if cl.hasnode(n))
289 return subset & smartset.baseset(sorted(results))
283 return subset & smartset.baseset(sorted(results))
290
284
291 @revsetpredicate('remotenames()')
285 @revsetpredicate('remotenames()')
292 def remotenamesrevset(repo, subset, x):
286 def remotenamesrevset(repo, subset, x):
293 """All changesets which have a remotename on them."""
287 """All changesets which have a remotename on them."""
294 revsetlang.getargs(x, 0, 0, _("remotenames takes no arguments"))
288 revsetlang.getargs(x, 0, 0, _("remotenames takes no arguments"))
295 return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'))
289 return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'))
296
290
297 @revsetpredicate('remotebranches()')
291 @revsetpredicate('remotebranches()')
298 def remotebranchesrevset(repo, subset, x):
292 def remotebranchesrevset(repo, subset, x):
299 """All changesets which are branch heads on remotes."""
293 """All changesets which are branch heads on remotes."""
300 revsetlang.getargs(x, 0, 0, _("remotebranches takes no arguments"))
294 revsetlang.getargs(x, 0, 0, _("remotebranches takes no arguments"))
301 return _revsetutil(repo, subset, x, ('remotebranches',))
295 return _revsetutil(repo, subset, x, ('remotebranches',))
302
296
303 @revsetpredicate('remotebookmarks()')
297 @revsetpredicate('remotebookmarks()')
304 def remotebmarksrevset(repo, subset, x):
298 def remotebmarksrevset(repo, subset, x):
305 """All changesets which have bookmarks on remotes."""
299 """All changesets which have bookmarks on remotes."""
306 revsetlang.getargs(x, 0, 0, _("remotebookmarks takes no arguments"))
300 revsetlang.getargs(x, 0, 0, _("remotebookmarks takes no arguments"))
307 return _revsetutil(repo, subset, x, ('remotebookmarks',))
301 return _revsetutil(repo, subset, x, ('remotebookmarks',))
General Comments 0
You need to be logged in to leave comments. Login now