comparison hgext/remotenames.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 3018749a71bb
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
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 bin
32 bin,
33 )
34 from mercurial import ( 32 from mercurial import (
35 bookmarks, 33 bookmarks,
36 error, 34 error,
37 extensions, 35 extensions,
38 logexchange, 36 logexchange,
43 smartset, 41 smartset,
44 templateutil, 42 templateutil,
45 util, 43 util,
46 ) 44 )
47 45
48 from mercurial.utils import ( 46 from mercurial.utils import stringutil
49 stringutil,
50 )
51 47
52 if pycompat.ispy3: 48 if pycompat.ispy3:
53 import collections.abc 49 import collections.abc
50
54 mutablemapping = collections.abc.MutableMapping 51 mutablemapping = collections.abc.MutableMapping
55 else: 52 else:
56 import collections 53 import collections
54
57 mutablemapping = collections.MutableMapping 55 mutablemapping = collections.MutableMapping
58 56
59 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for 57 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
60 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should 58 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
61 # be specifying the version(s) of Mercurial they are tested with, or 59 # be specifying the version(s) of Mercurial they are tested with, or
65 configtable = {} 63 configtable = {}
66 configitem = registrar.configitem(configtable) 64 configitem = registrar.configitem(configtable)
67 templatekeyword = registrar.templatekeyword() 65 templatekeyword = registrar.templatekeyword()
68 revsetpredicate = registrar.revsetpredicate() 66 revsetpredicate = registrar.revsetpredicate()
69 67
70 configitem('remotenames', 'bookmarks', 68 configitem(
71 default=True, 69 'remotenames', 'bookmarks', default=True,
72 ) 70 )
73 configitem('remotenames', 'branches', 71 configitem(
74 default=True, 72 'remotenames', 'branches', default=True,
75 ) 73 )
76 configitem('remotenames', 'hoistedpeer', 74 configitem(
77 default='default', 75 'remotenames', 'hoistedpeer', default='default',
78 ) 76 )
77
79 78
80 class lazyremotenamedict(mutablemapping): 79 class lazyremotenamedict(mutablemapping):
81 """ 80 """
82 Read-only dict-like Class to lazily resolve remotename entries 81 Read-only dict-like Class to lazily resolve remotename entries
83 82
86 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
87 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
88 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
89 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).
90 """ 89 """
90
91 def __init__(self, kind, repo): 91 def __init__(self, kind, repo):
92 self.cache = {} 92 self.cache = {}
93 self.potentialentries = {} 93 self.potentialentries = {}
94 self._kind = kind # bookmarks or branches 94 self._kind = kind # bookmarks or branches
95 self._repo = repo 95 self._repo = repo
96 self.loaded = False 96 self.loaded = False
97 97
98 def _load(self): 98 def _load(self):
99 """ Read the remotenames file, store entries matching selected kind """ 99 """ Read the remotenames file, store entries matching selected kind """
100 self.loaded = True 100 self.loaded = True
101 repo = self._repo 101 repo = self._repo
102 for node, rpath, rname in logexchange.readremotenamefile(repo, 102 for node, rpath, rname in logexchange.readremotenamefile(
103 self._kind): 103 repo, self._kind
104 ):
104 name = rpath + '/' + rname 105 name = rpath + '/' + rname
105 self.potentialentries[name] = (node, rpath, name) 106 self.potentialentries[name] = (node, rpath, name)
106 107
107 def _resolvedata(self, potentialentry): 108 def _resolvedata(self, potentialentry):
108 """ Check that the node for potentialentry exists and return it """ 109 """ Check that the node for potentialentry exists and return it """
115 try: 116 try:
116 repo.changelog.rev(binnode) 117 repo.changelog.rev(binnode)
117 except LookupError: 118 except LookupError:
118 return None 119 return None
119 # Skip closed branches 120 # Skip closed branches
120 if (self._kind == 'branches' and repo[binnode].closesbranch()): 121 if self._kind == 'branches' and repo[binnode].closesbranch():
121 return None 122 return None
122 return [binnode] 123 return [binnode]
123 124
124 def __getitem__(self, key): 125 def __getitem__(self, key):
125 if not self.loaded: 126 if not self.loaded:
167 for k, vtup in self.potentialentries.iteritems(): 168 for k, vtup in self.potentialentries.iteritems():
168 yield (k, [bin(vtup[0])]) 169 yield (k, [bin(vtup[0])])
169 170
170 items = iteritems 171 items = iteritems
171 172
173
172 class remotenames(object): 174 class remotenames(object):
173 """ 175 """
174 This class encapsulates all the remotenames state. It also contains 176 This class encapsulates all the remotenames state. It also contains
175 methods to access that state in convenient ways. Remotenames are lazy 177 methods to access that state in convenient ways. Remotenames are lazy
176 loaded. Whenever client code needs to ensure the freshest copy of 178 loaded. Whenever client code needs to ensure the freshest copy of
221 marktonodes = self.bmarktonodes() 223 marktonodes = self.bmarktonodes()
222 self._hoisttonodes = {} 224 self._hoisttonodes = {}
223 hoist += '/' 225 hoist += '/'
224 for name, node in marktonodes.iteritems(): 226 for name, node in marktonodes.iteritems():
225 if name.startswith(hoist): 227 if name.startswith(hoist):
226 name = name[len(hoist):] 228 name = name[len(hoist) :]
227 self._hoisttonodes[name] = node 229 self._hoisttonodes[name] = node
228 return self._hoisttonodes 230 return self._hoisttonodes
229 231
230 def nodetohoists(self, hoist): 232 def nodetohoists(self, hoist):
231 if not self._nodetohoists: 233 if not self._nodetohoists:
232 marktonodes = self.bmarktonodes() 234 marktonodes = self.bmarktonodes()
233 self._nodetohoists = {} 235 self._nodetohoists = {}
234 hoist += '/' 236 hoist += '/'
235 for name, node in marktonodes.iteritems(): 237 for name, node in marktonodes.iteritems():
236 if name.startswith(hoist): 238 if name.startswith(hoist):
237 name = name[len(hoist):] 239 name = name[len(hoist) :]
238 self._nodetohoists.setdefault(node[0], []).append(name) 240 self._nodetohoists.setdefault(node[0], []).append(name)
239 return self._nodetohoists 241 return self._nodetohoists
242
240 243
241 def wrapprintbookmarks(orig, ui, repo, fm, bmarks): 244 def wrapprintbookmarks(orig, ui, repo, fm, bmarks):
242 if 'remotebookmarks' not in repo.names: 245 if 'remotebookmarks' not in repo.names:
243 return 246 return
244 ns = repo.names['remotebookmarks'] 247 ns = repo.names['remotebookmarks']
251 254
252 bmarks[name] = (node, ' ', '') 255 bmarks[name] = (node, ' ', '')
253 256
254 return orig(ui, repo, fm, bmarks) 257 return orig(ui, repo, fm, bmarks)
255 258
259
256 def extsetup(ui): 260 def extsetup(ui):
257 extensions.wrapfunction(bookmarks, '_printbookmarks', wrapprintbookmarks) 261 extensions.wrapfunction(bookmarks, '_printbookmarks', wrapprintbookmarks)
262
258 263
259 def reposetup(ui, repo): 264 def reposetup(ui, repo):
260 265
261 # set the config option to store remotenames 266 # set the config option to store remotenames
262 repo.ui.setconfig('experimental', 'remotenames', True, 'remotenames-ext') 267 repo.ui.setconfig('experimental', 'remotenames', True, 'remotenames-ext')
272 'remotebookmarks', 277 'remotebookmarks',
273 templatename='remotebookmarks', 278 templatename='remotebookmarks',
274 colorname='remotebookmark', 279 colorname='remotebookmark',
275 logfmt='remote bookmark: %s\n', 280 logfmt='remote bookmark: %s\n',
276 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(), 281 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(),
277 namemap=lambda repo, name: 282 namemap=lambda repo, name: repo._remotenames.bmarktonodes().get(
278 repo._remotenames.bmarktonodes().get(name, []), 283 name, []
279 nodemap=lambda repo, node: 284 ),
280 repo._remotenames.nodetobmarks().get(node, [])) 285 nodemap=lambda repo, node: repo._remotenames.nodetobmarks().get(
286 node, []
287 ),
288 )
281 repo.names.addnamespace(remotebookmarkns) 289 repo.names.addnamespace(remotebookmarkns)
282 290
283 # hoisting only works if there are remote bookmarks 291 # hoisting only works if there are remote bookmarks
284 hoist = ui.config('remotenames', 'hoistedpeer') 292 hoist = ui.config('remotenames', 'hoistedpeer')
285 if hoist: 293 if hoist:
286 hoistednamens = ns( 294 hoistednamens = ns(
287 'hoistednames', 295 'hoistednames',
288 templatename='hoistednames', 296 templatename='hoistednames',
289 colorname='hoistedname', 297 colorname='hoistedname',
290 logfmt='hoisted name: %s\n', 298 logfmt='hoisted name: %s\n',
291 listnames = lambda repo: 299 listnames=lambda repo: repo._remotenames.hoisttonodes(
292 repo._remotenames.hoisttonodes(hoist).keys(), 300 hoist
293 namemap = lambda repo, name: 301 ).keys(),
294 repo._remotenames.hoisttonodes(hoist).get(name, []), 302 namemap=lambda repo, name: repo._remotenames.hoisttonodes(
295 nodemap = lambda repo, node: 303 hoist
296 repo._remotenames.nodetohoists(hoist).get(node, [])) 304 ).get(name, []),
305 nodemap=lambda repo, node: repo._remotenames.nodetohoists(
306 hoist
307 ).get(node, []),
308 )
297 repo.names.addnamespace(hoistednamens) 309 repo.names.addnamespace(hoistednamens)
298 310
299 if ui.configbool('remotenames', 'branches'): 311 if ui.configbool('remotenames', 'branches'):
300 remotebranchns = ns( 312 remotebranchns = ns(
301 'remotebranches', 313 'remotebranches',
302 templatename='remotebranches', 314 templatename='remotebranches',
303 colorname='remotebranch', 315 colorname='remotebranch',
304 logfmt='remote branch: %s\n', 316 logfmt='remote branch: %s\n',
305 listnames = lambda repo: repo._remotenames.branchtonodes().keys(), 317 listnames=lambda repo: repo._remotenames.branchtonodes().keys(),
306 namemap = lambda repo, name: 318 namemap=lambda repo, name: repo._remotenames.branchtonodes().get(
307 repo._remotenames.branchtonodes().get(name, []), 319 name, []
308 nodemap = lambda repo, node: 320 ),
309 repo._remotenames.nodetobranch().get(node, [])) 321 nodemap=lambda repo, node: repo._remotenames.nodetobranch().get(
322 node, []
323 ),
324 )
310 repo.names.addnamespace(remotebranchns) 325 repo.names.addnamespace(remotebranchns)
326
311 327
312 @templatekeyword('remotenames', requires={'repo', 'ctx'}) 328 @templatekeyword('remotenames', requires={'repo', 'ctx'})
313 def remotenameskw(context, mapping): 329 def remotenameskw(context, mapping):
314 """List of strings. Remote names associated with the changeset.""" 330 """List of strings. Remote names associated with the changeset."""
315 repo = context.resource(mapping, 'repo') 331 repo = context.resource(mapping, 'repo')
320 remotenames = repo.names['remotebookmarks'].names(repo, ctx.node()) 336 remotenames = repo.names['remotebookmarks'].names(repo, ctx.node())
321 337
322 if 'remotebranches' in repo.names: 338 if 'remotebranches' in repo.names:
323 remotenames += repo.names['remotebranches'].names(repo, ctx.node()) 339 remotenames += repo.names['remotebranches'].names(repo, ctx.node())
324 340
325 return templateutil.compatlist(context, mapping, 'remotename', remotenames, 341 return templateutil.compatlist(
326 plural='remotenames') 342 context, mapping, 'remotename', remotenames, plural='remotenames'
343 )
344
327 345
328 @templatekeyword('remotebookmarks', requires={'repo', 'ctx'}) 346 @templatekeyword('remotebookmarks', requires={'repo', 'ctx'})
329 def remotebookmarkskw(context, mapping): 347 def remotebookmarkskw(context, mapping):
330 """List of strings. Remote bookmarks associated with the changeset.""" 348 """List of strings. Remote bookmarks associated with the changeset."""
331 repo = context.resource(mapping, 'repo') 349 repo = context.resource(mapping, 'repo')
333 351
334 remotebmarks = [] 352 remotebmarks = []
335 if 'remotebookmarks' in repo.names: 353 if 'remotebookmarks' in repo.names:
336 remotebmarks = repo.names['remotebookmarks'].names(repo, ctx.node()) 354 remotebmarks = repo.names['remotebookmarks'].names(repo, ctx.node())
337 355
338 return templateutil.compatlist(context, mapping, 'remotebookmark', 356 return templateutil.compatlist(
339 remotebmarks, plural='remotebookmarks') 357 context,
358 mapping,
359 'remotebookmark',
360 remotebmarks,
361 plural='remotebookmarks',
362 )
363
340 364
341 @templatekeyword('remotebranches', requires={'repo', 'ctx'}) 365 @templatekeyword('remotebranches', requires={'repo', 'ctx'})
342 def remotebrancheskw(context, mapping): 366 def remotebrancheskw(context, mapping):
343 """List of strings. Remote branches associated with the changeset.""" 367 """List of strings. Remote branches associated with the changeset."""
344 repo = context.resource(mapping, 'repo') 368 repo = context.resource(mapping, 'repo')
346 370
347 remotebranches = [] 371 remotebranches = []
348 if 'remotebranches' in repo.names: 372 if 'remotebranches' in repo.names:
349 remotebranches = repo.names['remotebranches'].names(repo, ctx.node()) 373 remotebranches = repo.names['remotebranches'].names(repo, ctx.node())
350 374
351 return templateutil.compatlist(context, mapping, 'remotebranch', 375 return templateutil.compatlist(
352 remotebranches, plural='remotebranches') 376 context,
377 mapping,
378 'remotebranch',
379 remotebranches,
380 plural='remotebranches',
381 )
382
353 383
354 def _revsetutil(repo, subset, x, rtypes): 384 def _revsetutil(repo, subset, x, rtypes):
355 """utility function to return a set of revs based on the rtypes""" 385 """utility function to return a set of revs based on the rtypes"""
356 args = revsetlang.getargs(x, 0, 1, _('only one argument accepted')) 386 args = revsetlang.getargs(x, 0, 1, _('only one argument accepted'))
357 if args: 387 if args:
358 kind, pattern, matcher = stringutil.stringmatcher( 388 kind, pattern, matcher = stringutil.stringmatcher(
359 revsetlang.getstring(args[0], _('argument must be a string'))) 389 revsetlang.getstring(args[0], _('argument must be a string'))
390 )
360 else: 391 else:
361 kind = pattern = None 392 kind = pattern = None
362 matcher = util.always 393 matcher = util.always
363 394
364 nodes = set() 395 nodes = set()
369 for name in ns.listnames(repo): 400 for name in ns.listnames(repo):
370 if not matcher(name): 401 if not matcher(name):
371 continue 402 continue
372 nodes.update(ns.nodes(repo, name)) 403 nodes.update(ns.nodes(repo, name))
373 if kind == 'literal' and not nodes: 404 if kind == 'literal' and not nodes:
374 raise error.RepoLookupError(_("remote name '%s' does not exist") 405 raise error.RepoLookupError(
375 % pattern) 406 _("remote name '%s' does not exist") % pattern
407 )
376 408
377 revs = (cl.rev(n) for n in nodes if cl.hasnode(n)) 409 revs = (cl.rev(n) for n in nodes if cl.hasnode(n))
378 return subset & smartset.baseset(revs) 410 return subset & smartset.baseset(revs)
411
379 412
380 @revsetpredicate('remotenames([name])') 413 @revsetpredicate('remotenames([name])')
381 def remotenamesrevset(repo, subset, x): 414 def remotenamesrevset(repo, subset, x):
382 """All changesets which have a remotename on them. If `name` is 415 """All changesets which have a remotename on them. If `name` is
383 specified, only remotenames of matching remote paths are considered. 416 specified, only remotenames of matching remote paths are considered.
384 417
385 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`. 418 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
386 """ 419 """
387 return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches')) 420 return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'))
388 421
422
389 @revsetpredicate('remotebranches([name])') 423 @revsetpredicate('remotebranches([name])')
390 def remotebranchesrevset(repo, subset, x): 424 def remotebranchesrevset(repo, subset, x):
391 """All changesets which are branch heads on remotes. If `name` is 425 """All changesets which are branch heads on remotes. If `name` is
392 specified, only remotenames of matching remote paths are considered. 426 specified, only remotenames of matching remote paths are considered.
393 427
394 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`. 428 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
395 """ 429 """
396 return _revsetutil(repo, subset, x, ('remotebranches',)) 430 return _revsetutil(repo, subset, x, ('remotebranches',))
397 431
432
398 @revsetpredicate('remotebookmarks([name])') 433 @revsetpredicate('remotebookmarks([name])')
399 def remotebmarksrevset(repo, subset, x): 434 def remotebmarksrevset(repo, subset, x):
400 """All changesets which have bookmarks on remotes. If `name` is 435 """All changesets which have bookmarks on remotes. If `name` is
401 specified, only remotenames of matching remote paths are considered. 436 specified, only remotenames of matching remote paths are considered.
402 437