namespaces.py
136 lines
| 4.9 KiB
| text/x-python
|
PythonLexer
/ mercurial / namespaces.py
|
r23559 | from i18n import _ | ||
|
r23553 | from mercurial import util | ||
|
r23610 | import templatekw | ||
|
r23553 | |||
|
r23555 | def tolist(val): | ||
""" | ||||
a convenience method to return an empty list instead of None | ||||
""" | ||||
if val is None: | ||||
return [] | ||||
else: | ||||
return [val] | ||||
|
r23553 | class namespaces(object): | ||
|
r23718 | """provides an interface to register and operate on multiple namespaces. See | ||
the namespace class below for details on the namespace object. | ||||
|
r23553 | |||
""" | ||||
_names_version = 0 | ||||
|
r23561 | def __init__(self): | ||
|
r23553 | self._names = util.sortdict() | ||
|
r23554 | |||
|
r23717 | # shorten the class name for less indentation | ||
ns = namespace | ||||
|
r23562 | |||
|
r23558 | # we need current mercurial named objects (bookmarks, tags, and | ||
# branches) to be initialized somewhere, so that place is here | ||||
|
r23717 | n = ns("bookmarks", "bookmark", | ||
|
r23760 | lambda repo: repo._bookmarks.keys(), | ||
|
r23718 | lambda repo, name: tolist(repo._bookmarks.get(name)), | ||
lambda repo, name: repo.nodebookmarks(name)) | ||||
|
r23717 | self.addnamespace(n) | ||
|
r23562 | |||
|
r23717 | n = ns("tags", "tag", | ||
|
r23760 | lambda repo: [t for t, n in repo.tagslist()], | ||
|
r23718 | lambda repo, name: tolist(repo._tagscache.tags.get(name)), | ||
lambda repo, name: repo.nodetags(name)) | ||||
|
r23717 | self.addnamespace(n) | ||
|
r23558 | |||
|
r23717 | n = ns("branches", "branch", | ||
|
r23760 | lambda repo: repo.branchmap().keys(), | ||
|
r23718 | lambda repo, name: tolist(repo.branchtip(name)), | ||
lambda repo, node: [repo[node].branch()]) | ||||
|
r23717 | self.addnamespace(n) | ||
|
r23563 | |||
|
r23736 | def __getitem__(self, namespace): | ||
"""returns the namespace object""" | ||||
return self._names[namespace] | ||||
|
r23717 | def addnamespace(self, namespace, order=None): | ||
|
r23718 | """register a namespace | ||
|
r23554 | |||
namespace: the name to be registered (in plural form) | ||||
order: optional argument to specify the order of namespaces | ||||
(e.g. 'branches' should be listed before 'bookmarks') | ||||
|
r23718 | |||
|
r23554 | """ | ||
if order is not None: | ||||
|
r23717 | self._names.insert(order, namespace.name, namespace) | ||
|
r23554 | else: | ||
|
r23717 | self._names[namespace.name] = namespace | ||
|
r23559 | |||
|
r23610 | # we only generate a template keyword if one does not already exist | ||
|
r23717 | if namespace.name not in templatekw.keywords: | ||
|
r23610 | def generatekw(**args): | ||
|
r23717 | return templatekw.shownames(namespace.name, **args) | ||
|
r23610 | |||
|
r23717 | templatekw.keywords[namespace.name] = generatekw | ||
|
r23610 | |||
|
r23561 | def singlenode(self, repo, name): | ||
|
r23559 | """ | ||
Return the 'best' node for the given name. Best means the first node | ||||
in the first nonempty list returned by a name-to-nodes mapping function | ||||
in the defined precedence order. | ||||
Raises a KeyError if there is no such node. | ||||
""" | ||||
for ns, v in self._names.iteritems(): | ||||
|
r23717 | n = v.namemap(repo, name) | ||
|
r23559 | if n: | ||
# return max revision number | ||||
if len(n) > 1: | ||||
|
r23561 | cl = repo.changelog | ||
|
r23559 | maxrev = max(cl.rev(node) for node in n) | ||
return cl.node(maxrev) | ||||
return n[0] | ||||
raise KeyError(_('no such name: %s') % name) | ||||
|
r23606 | |||
|
r23715 | class namespace(object): | ||
"""provides an interface to a namespace | ||||
Namespaces are basically generic many-to-many mapping between some | ||||
(namespaced) names and nodes. The goal here is to control the pollution of | ||||
jamming things into tags or bookmarks (in extension-land) and to simplify | ||||
internal bits of mercurial: log output, tab completion, etc. | ||||
More precisely, we define a mapping of names to nodes, and a mapping from | ||||
nodes to names. Each mapping returns a list. | ||||
Furthermore, each name mapping will be passed a name to lookup which might | ||||
not be in its domain. In this case, each method should return an empty list | ||||
and not raise an error. | ||||
This namespace object will define the properties we need: | ||||
'name': the namespace (plural form) | ||||
'templatename': name to use for templating (usually the singular form | ||||
of the plural namespace name) | ||||
|
r23760 | 'listnames': list of all names in the namespace (usually the keys of a | ||
dictionary) | ||||
|
r23715 | 'namemap': function that takes a name and returns a list of nodes | ||
'nodemap': function that takes a node and returns a list of names | ||||
""" | ||||
|
r23760 | def __init__(self, name, templatename, listnames, namemap, nodemap): | ||
|
r23715 | """create a namespace | ||
name: the namespace to be registered (in plural form) | ||||
|
r23760 | listnames: function to list all names | ||
|
r23715 | templatename: the name to use for templating | ||
namemap: function that inputs a node, output name(s) | ||||
nodemap: function that inputs a name, output node(s) | ||||
""" | ||||
self.name = name | ||||
self.templatename = templatename | ||||
|
r23760 | self.listnames = listnames | ||
|
r23715 | self.namemap = namemap | ||
self.nodemap = nodemap | ||||
|
r23716 | |||
def names(self, repo, node): | ||||
"""method that returns a (sorted) list of names in a namespace that | ||||
match a given node""" | ||||
return sorted(self.nodemap(repo, node)) | ||||