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