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