##// END OF EJS Templates
remotenames: use util.always instead of handcrafted lambda
Yuya Nishihara -
r40102:fe641781 default
parent child Browse files
Show More
@@ -1,397 +1,398 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 (EXPERIMENTAL)
9 """ showing remotebookmarks and remotebranches in UI (EXPERIMENTAL)
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 (default: True)
17 Boolean value to enable or disable showing of remotebookmarks (default: True)
18
18
19 remotenames.branches
19 remotenames.branches
20 Boolean value to enable or disable showing of remotebranches (default: True)
20 Boolean value to enable or disable showing of remotebranches (default: True)
21
21
22 remotenames.hoistedpeer
22 remotenames.hoistedpeer
23 Name of the peer whose remotebookmarks should be hoisted into the top-level
23 Name of the peer whose remotebookmarks should be hoisted into the top-level
24 namespace (default: 'default')
24 namespace (default: 'default')
25 """
25 """
26
26
27 from __future__ import absolute_import
27 from __future__ import absolute_import
28
28
29 from mercurial.i18n import _
29 from mercurial.i18n import _
30
30
31 from mercurial.node import (
31 from mercurial.node import (
32 bin,
32 bin,
33 )
33 )
34 from mercurial import (
34 from mercurial import (
35 bookmarks,
35 bookmarks,
36 extensions,
36 extensions,
37 logexchange,
37 logexchange,
38 namespaces,
38 namespaces,
39 pycompat,
39 pycompat,
40 registrar,
40 registrar,
41 revsetlang,
41 revsetlang,
42 smartset,
42 smartset,
43 templateutil,
43 templateutil,
44 util,
44 )
45 )
45
46
46 from mercurial.utils import (
47 from mercurial.utils import (
47 stringutil,
48 stringutil,
48 )
49 )
49
50
50 if pycompat.ispy3:
51 if pycompat.ispy3:
51 import collections.abc
52 import collections.abc
52 mutablemapping = collections.abc.MutableMapping
53 mutablemapping = collections.abc.MutableMapping
53 else:
54 else:
54 import collections
55 import collections
55 mutablemapping = collections.MutableMapping
56 mutablemapping = collections.MutableMapping
56
57
57 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
58 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
58 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
59 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
59 # be specifying the version(s) of Mercurial they are tested with, or
60 # be specifying the version(s) of Mercurial they are tested with, or
60 # leave the attribute unspecified.
61 # leave the attribute unspecified.
61 testedwith = 'ships-with-hg-core'
62 testedwith = 'ships-with-hg-core'
62
63
63 configtable = {}
64 configtable = {}
64 configitem = registrar.configitem(configtable)
65 configitem = registrar.configitem(configtable)
65 templatekeyword = registrar.templatekeyword()
66 templatekeyword = registrar.templatekeyword()
66 revsetpredicate = registrar.revsetpredicate()
67 revsetpredicate = registrar.revsetpredicate()
67
68
68 configitem('remotenames', 'bookmarks',
69 configitem('remotenames', 'bookmarks',
69 default=True,
70 default=True,
70 )
71 )
71 configitem('remotenames', 'branches',
72 configitem('remotenames', 'branches',
72 default=True,
73 default=True,
73 )
74 )
74 configitem('remotenames', 'hoistedpeer',
75 configitem('remotenames', 'hoistedpeer',
75 default='default',
76 default='default',
76 )
77 )
77
78
78 class lazyremotenamedict(mutablemapping):
79 class lazyremotenamedict(mutablemapping):
79 """
80 """
80 Read-only dict-like Class to lazily resolve remotename entries
81 Read-only dict-like Class to lazily resolve remotename entries
81
82
82 We are doing that because remotenames startup was slow.
83 We are doing that because remotenames startup was slow.
83 We lazily read the remotenames file once to figure out the potential entries
84 We lazily read the remotenames file once to figure out the potential entries
84 and store them in self.potentialentries. Then when asked to resolve an
85 and store them in self.potentialentries. Then when asked to resolve an
85 entry, if it is not in self.potentialentries, then it isn't there, if it
86 entry, if it is not in self.potentialentries, then it isn't there, if it
86 is in self.potentialentries we resolve it and store the result in
87 is in self.potentialentries we resolve it and store the result in
87 self.cache. We cannot be lazy is when asked all the entries (keys).
88 self.cache. We cannot be lazy is when asked all the entries (keys).
88 """
89 """
89 def __init__(self, kind, repo):
90 def __init__(self, kind, repo):
90 self.cache = {}
91 self.cache = {}
91 self.potentialentries = {}
92 self.potentialentries = {}
92 self._kind = kind # bookmarks or branches
93 self._kind = kind # bookmarks or branches
93 self._repo = repo
94 self._repo = repo
94 self.loaded = False
95 self.loaded = False
95
96
96 def _load(self):
97 def _load(self):
97 """ Read the remotenames file, store entries matching selected kind """
98 """ Read the remotenames file, store entries matching selected kind """
98 self.loaded = True
99 self.loaded = True
99 repo = self._repo
100 repo = self._repo
100 for node, rpath, rname in logexchange.readremotenamefile(repo,
101 for node, rpath, rname in logexchange.readremotenamefile(repo,
101 self._kind):
102 self._kind):
102 name = rpath + '/' + rname
103 name = rpath + '/' + rname
103 self.potentialentries[name] = (node, rpath, name)
104 self.potentialentries[name] = (node, rpath, name)
104
105
105 def _resolvedata(self, potentialentry):
106 def _resolvedata(self, potentialentry):
106 """ Check that the node for potentialentry exists and return it """
107 """ Check that the node for potentialentry exists and return it """
107 if not potentialentry in self.potentialentries:
108 if not potentialentry in self.potentialentries:
108 return None
109 return None
109 node, remote, name = self.potentialentries[potentialentry]
110 node, remote, name = self.potentialentries[potentialentry]
110 repo = self._repo
111 repo = self._repo
111 binnode = bin(node)
112 binnode = bin(node)
112 # if the node doesn't exist, skip it
113 # if the node doesn't exist, skip it
113 try:
114 try:
114 repo.changelog.rev(binnode)
115 repo.changelog.rev(binnode)
115 except LookupError:
116 except LookupError:
116 return None
117 return None
117 # Skip closed branches
118 # Skip closed branches
118 if (self._kind == 'branches' and repo[binnode].closesbranch()):
119 if (self._kind == 'branches' and repo[binnode].closesbranch()):
119 return None
120 return None
120 return [binnode]
121 return [binnode]
121
122
122 def __getitem__(self, key):
123 def __getitem__(self, key):
123 if not self.loaded:
124 if not self.loaded:
124 self._load()
125 self._load()
125 val = self._fetchandcache(key)
126 val = self._fetchandcache(key)
126 if val is not None:
127 if val is not None:
127 return val
128 return val
128 else:
129 else:
129 raise KeyError()
130 raise KeyError()
130
131
131 def __iter__(self):
132 def __iter__(self):
132 return iter(self.potentialentries)
133 return iter(self.potentialentries)
133
134
134 def __len__(self):
135 def __len__(self):
135 return len(self.potentialentries)
136 return len(self.potentialentries)
136
137
137 def __setitem__(self):
138 def __setitem__(self):
138 raise NotImplementedError
139 raise NotImplementedError
139
140
140 def __delitem__(self):
141 def __delitem__(self):
141 raise NotImplementedError
142 raise NotImplementedError
142
143
143 def _fetchandcache(self, key):
144 def _fetchandcache(self, key):
144 if key in self.cache:
145 if key in self.cache:
145 return self.cache[key]
146 return self.cache[key]
146 val = self._resolvedata(key)
147 val = self._resolvedata(key)
147 if val is not None:
148 if val is not None:
148 self.cache[key] = val
149 self.cache[key] = val
149 return val
150 return val
150 else:
151 else:
151 return None
152 return None
152
153
153 def keys(self):
154 def keys(self):
154 """ Get a list of bookmark or branch names """
155 """ Get a list of bookmark or branch names """
155 if not self.loaded:
156 if not self.loaded:
156 self._load()
157 self._load()
157 return self.potentialentries.keys()
158 return self.potentialentries.keys()
158
159
159 def iteritems(self):
160 def iteritems(self):
160 """ Iterate over (name, node) tuples """
161 """ Iterate over (name, node) tuples """
161
162
162 if not self.loaded:
163 if not self.loaded:
163 self._load()
164 self._load()
164
165
165 for k, vtup in self.potentialentries.iteritems():
166 for k, vtup in self.potentialentries.iteritems():
166 yield (k, [bin(vtup[0])])
167 yield (k, [bin(vtup[0])])
167
168
168 class remotenames(object):
169 class remotenames(object):
169 """
170 """
170 This class encapsulates all the remotenames state. It also contains
171 This class encapsulates all the remotenames state. It also contains
171 methods to access that state in convenient ways. Remotenames are lazy
172 methods to access that state in convenient ways. Remotenames are lazy
172 loaded. Whenever client code needs to ensure the freshest copy of
173 loaded. Whenever client code needs to ensure the freshest copy of
173 remotenames, use the `clearnames` method to force an eventual load.
174 remotenames, use the `clearnames` method to force an eventual load.
174 """
175 """
175
176
176 def __init__(self, repo, *args):
177 def __init__(self, repo, *args):
177 self._repo = repo
178 self._repo = repo
178 self.clearnames()
179 self.clearnames()
179
180
180 def clearnames(self):
181 def clearnames(self):
181 """ Clear all remote names state """
182 """ Clear all remote names state """
182 self.bookmarks = lazyremotenamedict("bookmarks", self._repo)
183 self.bookmarks = lazyremotenamedict("bookmarks", self._repo)
183 self.branches = lazyremotenamedict("branches", self._repo)
184 self.branches = lazyremotenamedict("branches", self._repo)
184 self._invalidatecache()
185 self._invalidatecache()
185
186
186 def _invalidatecache(self):
187 def _invalidatecache(self):
187 self._nodetobmarks = None
188 self._nodetobmarks = None
188 self._nodetobranch = None
189 self._nodetobranch = None
189 self._hoisttonodes = None
190 self._hoisttonodes = None
190 self._nodetohoists = None
191 self._nodetohoists = None
191
192
192 def bmarktonodes(self):
193 def bmarktonodes(self):
193 return self.bookmarks
194 return self.bookmarks
194
195
195 def nodetobmarks(self):
196 def nodetobmarks(self):
196 if not self._nodetobmarks:
197 if not self._nodetobmarks:
197 bmarktonodes = self.bmarktonodes()
198 bmarktonodes = self.bmarktonodes()
198 self._nodetobmarks = {}
199 self._nodetobmarks = {}
199 for name, node in bmarktonodes.iteritems():
200 for name, node in bmarktonodes.iteritems():
200 self._nodetobmarks.setdefault(node[0], []).append(name)
201 self._nodetobmarks.setdefault(node[0], []).append(name)
201 return self._nodetobmarks
202 return self._nodetobmarks
202
203
203 def branchtonodes(self):
204 def branchtonodes(self):
204 return self.branches
205 return self.branches
205
206
206 def nodetobranch(self):
207 def nodetobranch(self):
207 if not self._nodetobranch:
208 if not self._nodetobranch:
208 branchtonodes = self.branchtonodes()
209 branchtonodes = self.branchtonodes()
209 self._nodetobranch = {}
210 self._nodetobranch = {}
210 for name, nodes in branchtonodes.iteritems():
211 for name, nodes in branchtonodes.iteritems():
211 for node in nodes:
212 for node in nodes:
212 self._nodetobranch.setdefault(node, []).append(name)
213 self._nodetobranch.setdefault(node, []).append(name)
213 return self._nodetobranch
214 return self._nodetobranch
214
215
215 def hoisttonodes(self, hoist):
216 def hoisttonodes(self, hoist):
216 if not self._hoisttonodes:
217 if not self._hoisttonodes:
217 marktonodes = self.bmarktonodes()
218 marktonodes = self.bmarktonodes()
218 self._hoisttonodes = {}
219 self._hoisttonodes = {}
219 hoist += '/'
220 hoist += '/'
220 for name, node in marktonodes.iteritems():
221 for name, node in marktonodes.iteritems():
221 if name.startswith(hoist):
222 if name.startswith(hoist):
222 name = name[len(hoist):]
223 name = name[len(hoist):]
223 self._hoisttonodes[name] = node
224 self._hoisttonodes[name] = node
224 return self._hoisttonodes
225 return self._hoisttonodes
225
226
226 def nodetohoists(self, hoist):
227 def nodetohoists(self, hoist):
227 if not self._nodetohoists:
228 if not self._nodetohoists:
228 marktonodes = self.bmarktonodes()
229 marktonodes = self.bmarktonodes()
229 self._nodetohoists = {}
230 self._nodetohoists = {}
230 hoist += '/'
231 hoist += '/'
231 for name, node in marktonodes.iteritems():
232 for name, node in marktonodes.iteritems():
232 if name.startswith(hoist):
233 if name.startswith(hoist):
233 name = name[len(hoist):]
234 name = name[len(hoist):]
234 self._nodetohoists.setdefault(node[0], []).append(name)
235 self._nodetohoists.setdefault(node[0], []).append(name)
235 return self._nodetohoists
236 return self._nodetohoists
236
237
237 def wrapprintbookmarks(orig, ui, repo, fm, bmarks):
238 def wrapprintbookmarks(orig, ui, repo, fm, bmarks):
238 if 'remotebookmarks' not in repo.names:
239 if 'remotebookmarks' not in repo.names:
239 return
240 return
240 ns = repo.names['remotebookmarks']
241 ns = repo.names['remotebookmarks']
241
242
242 for name in ns.listnames(repo):
243 for name in ns.listnames(repo):
243 nodes = ns.nodes(repo, name)
244 nodes = ns.nodes(repo, name)
244 if not nodes:
245 if not nodes:
245 continue
246 continue
246 node = nodes[0]
247 node = nodes[0]
247
248
248 bmarks[name] = (node, ' ', '')
249 bmarks[name] = (node, ' ', '')
249
250
250 return orig(ui, repo, fm, bmarks)
251 return orig(ui, repo, fm, bmarks)
251
252
252 def extsetup(ui):
253 def extsetup(ui):
253 extensions.wrapfunction(bookmarks, '_printbookmarks', wrapprintbookmarks)
254 extensions.wrapfunction(bookmarks, '_printbookmarks', wrapprintbookmarks)
254
255
255 def reposetup(ui, repo):
256 def reposetup(ui, repo):
256
257
257 # set the config option to store remotenames
258 # set the config option to store remotenames
258 repo.ui.setconfig('experimental', 'remotenames', True, 'remotenames-ext')
259 repo.ui.setconfig('experimental', 'remotenames', True, 'remotenames-ext')
259
260
260 if not repo.local():
261 if not repo.local():
261 return
262 return
262
263
263 repo._remotenames = remotenames(repo)
264 repo._remotenames = remotenames(repo)
264 ns = namespaces.namespace
265 ns = namespaces.namespace
265
266
266 if ui.configbool('remotenames', 'bookmarks'):
267 if ui.configbool('remotenames', 'bookmarks'):
267 remotebookmarkns = ns(
268 remotebookmarkns = ns(
268 'remotebookmarks',
269 'remotebookmarks',
269 templatename='remotebookmarks',
270 templatename='remotebookmarks',
270 colorname='remotebookmark',
271 colorname='remotebookmark',
271 logfmt='remote bookmark: %s\n',
272 logfmt='remote bookmark: %s\n',
272 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(),
273 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(),
273 namemap=lambda repo, name:
274 namemap=lambda repo, name:
274 repo._remotenames.bmarktonodes().get(name, []),
275 repo._remotenames.bmarktonodes().get(name, []),
275 nodemap=lambda repo, node:
276 nodemap=lambda repo, node:
276 repo._remotenames.nodetobmarks().get(node, []))
277 repo._remotenames.nodetobmarks().get(node, []))
277 repo.names.addnamespace(remotebookmarkns)
278 repo.names.addnamespace(remotebookmarkns)
278
279
279 # hoisting only works if there are remote bookmarks
280 # hoisting only works if there are remote bookmarks
280 hoist = ui.config('remotenames', 'hoistedpeer')
281 hoist = ui.config('remotenames', 'hoistedpeer')
281 if hoist:
282 if hoist:
282 hoistednamens = ns(
283 hoistednamens = ns(
283 'hoistednames',
284 'hoistednames',
284 templatename='hoistednames',
285 templatename='hoistednames',
285 colorname='hoistedname',
286 colorname='hoistedname',
286 logfmt='hoisted name: %s\n',
287 logfmt='hoisted name: %s\n',
287 listnames = lambda repo:
288 listnames = lambda repo:
288 repo._remotenames.hoisttonodes(hoist).keys(),
289 repo._remotenames.hoisttonodes(hoist).keys(),
289 namemap = lambda repo, name:
290 namemap = lambda repo, name:
290 repo._remotenames.hoisttonodes(hoist).get(name, []),
291 repo._remotenames.hoisttonodes(hoist).get(name, []),
291 nodemap = lambda repo, node:
292 nodemap = lambda repo, node:
292 repo._remotenames.nodetohoists(hoist).get(node, []))
293 repo._remotenames.nodetohoists(hoist).get(node, []))
293 repo.names.addnamespace(hoistednamens)
294 repo.names.addnamespace(hoistednamens)
294
295
295 if ui.configbool('remotenames', 'branches'):
296 if ui.configbool('remotenames', 'branches'):
296 remotebranchns = ns(
297 remotebranchns = ns(
297 'remotebranches',
298 'remotebranches',
298 templatename='remotebranches',
299 templatename='remotebranches',
299 colorname='remotebranch',
300 colorname='remotebranch',
300 logfmt='remote branch: %s\n',
301 logfmt='remote branch: %s\n',
301 listnames = lambda repo: repo._remotenames.branchtonodes().keys(),
302 listnames = lambda repo: repo._remotenames.branchtonodes().keys(),
302 namemap = lambda repo, name:
303 namemap = lambda repo, name:
303 repo._remotenames.branchtonodes().get(name, []),
304 repo._remotenames.branchtonodes().get(name, []),
304 nodemap = lambda repo, node:
305 nodemap = lambda repo, node:
305 repo._remotenames.nodetobranch().get(node, []))
306 repo._remotenames.nodetobranch().get(node, []))
306 repo.names.addnamespace(remotebranchns)
307 repo.names.addnamespace(remotebranchns)
307
308
308 @templatekeyword('remotenames', requires={'repo', 'ctx'})
309 @templatekeyword('remotenames', requires={'repo', 'ctx'})
309 def remotenameskw(context, mapping):
310 def remotenameskw(context, mapping):
310 """List of strings. Remote names associated with the changeset."""
311 """List of strings. Remote names associated with the changeset."""
311 repo = context.resource(mapping, 'repo')
312 repo = context.resource(mapping, 'repo')
312 ctx = context.resource(mapping, 'ctx')
313 ctx = context.resource(mapping, 'ctx')
313
314
314 remotenames = []
315 remotenames = []
315 if 'remotebookmarks' in repo.names:
316 if 'remotebookmarks' in repo.names:
316 remotenames = repo.names['remotebookmarks'].names(repo, ctx.node())
317 remotenames = repo.names['remotebookmarks'].names(repo, ctx.node())
317
318
318 if 'remotebranches' in repo.names:
319 if 'remotebranches' in repo.names:
319 remotenames += repo.names['remotebranches'].names(repo, ctx.node())
320 remotenames += repo.names['remotebranches'].names(repo, ctx.node())
320
321
321 return templateutil.compatlist(context, mapping, 'remotename', remotenames,
322 return templateutil.compatlist(context, mapping, 'remotename', remotenames,
322 plural='remotenames')
323 plural='remotenames')
323
324
324 @templatekeyword('remotebookmarks', requires={'repo', 'ctx'})
325 @templatekeyword('remotebookmarks', requires={'repo', 'ctx'})
325 def remotebookmarkskw(context, mapping):
326 def remotebookmarkskw(context, mapping):
326 """List of strings. Remote bookmarks associated with the changeset."""
327 """List of strings. Remote bookmarks associated with the changeset."""
327 repo = context.resource(mapping, 'repo')
328 repo = context.resource(mapping, 'repo')
328 ctx = context.resource(mapping, 'ctx')
329 ctx = context.resource(mapping, 'ctx')
329
330
330 remotebmarks = []
331 remotebmarks = []
331 if 'remotebookmarks' in repo.names:
332 if 'remotebookmarks' in repo.names:
332 remotebmarks = repo.names['remotebookmarks'].names(repo, ctx.node())
333 remotebmarks = repo.names['remotebookmarks'].names(repo, ctx.node())
333
334
334 return templateutil.compatlist(context, mapping, 'remotebookmark',
335 return templateutil.compatlist(context, mapping, 'remotebookmark',
335 remotebmarks, plural='remotebookmarks')
336 remotebmarks, plural='remotebookmarks')
336
337
337 @templatekeyword('remotebranches', requires={'repo', 'ctx'})
338 @templatekeyword('remotebranches', requires={'repo', 'ctx'})
338 def remotebrancheskw(context, mapping):
339 def remotebrancheskw(context, mapping):
339 """List of strings. Remote branches associated with the changeset."""
340 """List of strings. Remote branches associated with the changeset."""
340 repo = context.resource(mapping, 'repo')
341 repo = context.resource(mapping, 'repo')
341 ctx = context.resource(mapping, 'ctx')
342 ctx = context.resource(mapping, 'ctx')
342
343
343 remotebranches = []
344 remotebranches = []
344 if 'remotebranches' in repo.names:
345 if 'remotebranches' in repo.names:
345 remotebranches = repo.names['remotebranches'].names(repo, ctx.node())
346 remotebranches = repo.names['remotebranches'].names(repo, ctx.node())
346
347
347 return templateutil.compatlist(context, mapping, 'remotebranch',
348 return templateutil.compatlist(context, mapping, 'remotebranch',
348 remotebranches, plural='remotebranches')
349 remotebranches, plural='remotebranches')
349
350
350 def _revsetutil(repo, subset, x, rtypes):
351 def _revsetutil(repo, subset, x, rtypes):
351 """utility function to return a set of revs based on the rtypes"""
352 """utility function to return a set of revs based on the rtypes"""
352 args = revsetlang.getargs(x, 0, 1, _('only one argument accepted'))
353 args = revsetlang.getargs(x, 0, 1, _('only one argument accepted'))
353 if args:
354 if args:
354 kind, pattern, matcher = stringutil.stringmatcher(
355 kind, pattern, matcher = stringutil.stringmatcher(
355 revsetlang.getstring(args[0], _('argument must be a string')))
356 revsetlang.getstring(args[0], _('argument must be a string')))
356 else:
357 else:
357 matcher = lambda a: True
358 matcher = util.always
358
359
359 revs = set()
360 revs = set()
360 cl = repo.changelog
361 cl = repo.changelog
361 for rtype in rtypes:
362 for rtype in rtypes:
362 if rtype in repo.names:
363 if rtype in repo.names:
363 ns = repo.names[rtype]
364 ns = repo.names[rtype]
364 for name in ns.listnames(repo):
365 for name in ns.listnames(repo):
365 if not matcher(name):
366 if not matcher(name):
366 continue
367 continue
367 revs.update(ns.nodes(repo, name))
368 revs.update(ns.nodes(repo, name))
368
369
369 results = (cl.rev(n) for n in revs if cl.hasnode(n))
370 results = (cl.rev(n) for n in revs if cl.hasnode(n))
370 return subset & smartset.baseset(sorted(results))
371 return subset & smartset.baseset(sorted(results))
371
372
372 @revsetpredicate('remotenames([name])')
373 @revsetpredicate('remotenames([name])')
373 def remotenamesrevset(repo, subset, x):
374 def remotenamesrevset(repo, subset, x):
374 """All changesets which have a remotename on them. If `name` is
375 """All changesets which have a remotename on them. If `name` is
375 specified, only remotenames of matching remote paths are considered.
376 specified, only remotenames of matching remote paths are considered.
376
377
377 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
378 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
378 """
379 """
379 return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'))
380 return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'))
380
381
381 @revsetpredicate('remotebranches([name])')
382 @revsetpredicate('remotebranches([name])')
382 def remotebranchesrevset(repo, subset, x):
383 def remotebranchesrevset(repo, subset, x):
383 """All changesets which are branch heads on remotes. If `name` is
384 """All changesets which are branch heads on remotes. If `name` is
384 specified, only remotenames of matching remote paths are considered.
385 specified, only remotenames of matching remote paths are considered.
385
386
386 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
387 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
387 """
388 """
388 return _revsetutil(repo, subset, x, ('remotebranches',))
389 return _revsetutil(repo, subset, x, ('remotebranches',))
389
390
390 @revsetpredicate('remotebookmarks([name])')
391 @revsetpredicate('remotebookmarks([name])')
391 def remotebmarksrevset(repo, subset, x):
392 def remotebmarksrevset(repo, subset, x):
392 """All changesets which have bookmarks on remotes. If `name` is
393 """All changesets which have bookmarks on remotes. If `name` is
393 specified, only remotenames of matching remote paths are considered.
394 specified, only remotenames of matching remote paths are considered.
394
395
395 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
396 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
396 """
397 """
397 return _revsetutil(repo, subset, x, ('remotebookmarks',))
398 return _revsetutil(repo, subset, x, ('remotebookmarks',))
General Comments 0
You need to be logged in to leave comments. Login now