Show More
@@ -10,6 +10,11 b'' | |||||
10 |
|
10 | |||
11 | from __future__ import absolute_import |
|
11 | from __future__ import absolute_import | |
12 |
|
12 | |||
|
13 | import UserDict | |||
|
14 | ||||
|
15 | from mercurial.node import ( | |||
|
16 | bin, | |||
|
17 | ) | |||
13 | from mercurial import ( |
|
18 | from mercurial import ( | |
14 | logexchange, |
|
19 | logexchange, | |
15 | ) |
|
20 | ) | |
@@ -20,34 +25,102 b' from mercurial import (' | |||||
20 | # leave the attribute unspecified. |
|
25 | # leave the attribute unspecified. | |
21 | testedwith = 'ships-with-hg-core' |
|
26 | testedwith = 'ships-with-hg-core' | |
22 |
|
27 | |||
|
28 | class lazyremotenamedict(UserDict.DictMixin): | |||
|
29 | """ | |||
|
30 | Read-only dict-like Class to lazily resolve remotename entries | |||
|
31 | ||||
|
32 | We are doing that because remotenames startup was slow. | |||
|
33 | We lazily read the remotenames file once to figure out the potential entries | |||
|
34 | and store them in self.potentialentries. Then when asked to resolve an | |||
|
35 | entry, if it is not in self.potentialentries, then it isn't there, if it | |||
|
36 | is in self.potentialentries we resolve it and store the result in | |||
|
37 | self.cache. We cannot be lazy is when asked all the entries (keys). | |||
|
38 | """ | |||
|
39 | def __init__(self, kind, repo): | |||
|
40 | self.cache = {} | |||
|
41 | self.potentialentries = {} | |||
|
42 | self._kind = kind # bookmarks or branches | |||
|
43 | self._repo = repo | |||
|
44 | self.loaded = False | |||
|
45 | ||||
|
46 | def _load(self): | |||
|
47 | """ Read the remotenames file, store entries matching selected kind """ | |||
|
48 | self.loaded = True | |||
|
49 | repo = self._repo | |||
|
50 | for node, rpath, rname in logexchange.readremotenamefile(repo, | |||
|
51 | self._kind): | |||
|
52 | name = rpath + '/' + rname | |||
|
53 | self.potentialentries[name] = (node, rpath, name) | |||
|
54 | ||||
|
55 | def _resolvedata(self, potentialentry): | |||
|
56 | """ Check that the node for potentialentry exists and return it """ | |||
|
57 | if not potentialentry in self.potentialentries: | |||
|
58 | return None | |||
|
59 | node, remote, name = self.potentialentries[potentialentry] | |||
|
60 | repo = self._repo | |||
|
61 | binnode = bin(node) | |||
|
62 | # if the node doesn't exist, skip it | |||
|
63 | try: | |||
|
64 | repo.changelog.rev(binnode) | |||
|
65 | except LookupError: | |||
|
66 | return None | |||
|
67 | # Skip closed branches | |||
|
68 | if (self._kind == 'branches' and repo[binnode].closesbranch()): | |||
|
69 | return None | |||
|
70 | return [binnode] | |||
|
71 | ||||
|
72 | def __getitem__(self, key): | |||
|
73 | if not self.loaded: | |||
|
74 | self._load() | |||
|
75 | val = self._fetchandcache(key) | |||
|
76 | if val is not None: | |||
|
77 | return val | |||
|
78 | else: | |||
|
79 | raise KeyError() | |||
|
80 | ||||
|
81 | def _fetchandcache(self, key): | |||
|
82 | if key in self.cache: | |||
|
83 | return self.cache[key] | |||
|
84 | val = self._resolvedata(key) | |||
|
85 | if val is not None: | |||
|
86 | self.cache[key] = val | |||
|
87 | return val | |||
|
88 | else: | |||
|
89 | return None | |||
|
90 | ||||
|
91 | def keys(self): | |||
|
92 | """ Get a list of bookmark or branch names """ | |||
|
93 | if not self.loaded: | |||
|
94 | self._load() | |||
|
95 | return self.potentialentries.keys() | |||
|
96 | ||||
|
97 | def iteritems(self): | |||
|
98 | """ Iterate over (name, node) tuples """ | |||
|
99 | ||||
|
100 | if not self.loaded: | |||
|
101 | self._load() | |||
|
102 | ||||
|
103 | for k, vtup in self.potentialentries.iteritems(): | |||
|
104 | yield (k, [bin(vtup[0])]) | |||
|
105 | ||||
23 | class remotenames(dict): |
|
106 | class remotenames(dict): | |
24 | """ |
|
107 | """ | |
25 | This class encapsulates all the remotenames state. It also contains |
|
108 | This class encapsulates all the remotenames state. It also contains | |
26 | methods to access that state in convenient ways. |
|
109 | methods to access that state in convenient ways. Remotenames are lazy | |
|
110 | loaded. Whenever client code needs to ensure the freshest copy of | |||
|
111 | remotenames, use the `clearnames` method to force an eventual load. | |||
27 | """ |
|
112 | """ | |
28 |
|
113 | |||
29 | def __init__(self, repo, *args): |
|
114 | def __init__(self, repo, *args): | |
30 | dict.__init__(self, *args) |
|
115 | dict.__init__(self, *args) | |
31 | self._repo = repo |
|
116 | self._repo = repo | |
32 | self['bookmarks'] = {} |
|
117 | self.clearnames() | |
33 | self['branches'] = {} |
|
|||
34 | self.loadnames() |
|
|||
35 | self._loadednames = True |
|
|||
36 |
|
||||
37 | def loadnames(self): |
|
|||
38 | """ loads the remotenames information from the remotenames file """ |
|
|||
39 | for rtype in ('bookmarks', 'branches'): |
|
|||
40 | for node, rpath, name in logexchange.readremotenamefile(self._repo, |
|
|||
41 | rtype): |
|
|||
42 | rname = rpath + '/' + name |
|
|||
43 | self[rtype][rname] = [node] |
|
|||
44 |
|
118 | |||
45 | def clearnames(self): |
|
119 | def clearnames(self): | |
46 | """ Clear all remote names state """ |
|
120 | """ Clear all remote names state """ | |
47 | self['bookmarks'] = {} |
|
121 | self['bookmarks'] = lazyremotenamedict("bookmarks", self._repo) | |
48 | self['branches'] = {} |
|
122 | self['branches'] = lazyremotenamedict("branches", self._repo) | |
49 | self._invalidatecache() |
|
123 | self._invalidatecache() | |
50 | self._loadednames = False |
|
|||
51 |
|
124 | |||
52 | def _invalidatecache(self): |
|
125 | def _invalidatecache(self): | |
53 | self._nodetobmarks = None |
|
126 | self._nodetobmarks = None |
General Comments 0
You need to be logged in to leave comments.
Login now