##// END OF EJS Templates
repoview: remove incorrect documentation of the function...
Pulkit Goyal -
r34650:586645e0 default
parent child Browse files
Show More
@@ -1,245 +1,242
1 1 # repoview.py - Filtered view of a localrepo object
2 2 #
3 3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 4 # Logilab SA <contact@logilab.fr>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 import copy
12 12
13 13 from .node import nullrev
14 14 from . import (
15 15 obsolete,
16 16 phases,
17 17 tags as tagsmod,
18 18 )
19 19
20 20 def hideablerevs(repo):
21 21 """Revision candidates to be hidden
22 22
23 23 This is a standalone function to allow extensions to wrap it.
24 24
25 25 Because we use the set of immutable changesets as a fallback subset in
26 26 branchmap (see mercurial.branchmap.subsettable), you cannot set "public"
27 27 changesets as "hideable". Doing so would break multiple code assertions and
28 28 lead to crashes."""
29 29 return obsolete.getrevs(repo, 'obsolete')
30 30
31 31 def pinnedrevs(repo):
32 32 """revisions blocking hidden changesets from being filtered
33 33 """
34 34
35 35 cl = repo.changelog
36 36 pinned = set()
37 37 pinned.update([par.rev() for par in repo[None].parents()])
38 38 pinned.update([cl.rev(bm) for bm in repo._bookmarks.values()])
39 39
40 40 tags = {}
41 41 tagsmod.readlocaltags(repo.ui, repo, tags, {})
42 42 if tags:
43 43 rev, nodemap = cl.rev, cl.nodemap
44 44 pinned.update(rev(t[0]) for t in tags.values() if t[0] in nodemap)
45 45 return pinned
46 46
47 47
48 48 def _revealancestors(pfunc, hidden, revs):
49 49 """reveals contiguous chains of hidden ancestors of 'revs' by removing them
50 50 from 'hidden'
51 51
52 52 - pfunc(r): a funtion returning parent of 'r',
53 53 - hidden: the (preliminary) hidden revisions, to be updated
54 54 - revs: iterable of revnum,
55 55
56 56 (Ancestors are revealed exclusively, i.e. the elements in 'revs' are
57 57 *not* revealed)
58 58 """
59 59 stack = list(revs)
60 60 while stack:
61 61 for p in pfunc(stack.pop()):
62 62 if p != nullrev and p in hidden:
63 63 hidden.remove(p)
64 64 stack.append(p)
65 65
66 66 def computehidden(repo):
67 67 """compute the set of hidden revision to filter
68 68
69 69 During most operation hidden should be filtered."""
70 70 assert not repo.changelog.filteredrevs
71 71
72 72 hidden = hideablerevs(repo)
73 73 if hidden:
74 74 hidden = set(hidden - pinnedrevs(repo))
75 75 pfunc = repo.changelog.parentrevs
76 76 mutablephases = (phases.draft, phases.secret)
77 77 mutable = repo._phasecache.getrevset(repo, mutablephases)
78 78
79 79 visible = mutable - hidden
80 80 _revealancestors(pfunc, hidden, visible)
81 81 return frozenset(hidden)
82 82
83 83 def computeunserved(repo):
84 84 """compute the set of revision that should be filtered when used a server
85 85
86 86 Secret and hidden changeset should not pretend to be here."""
87 87 assert not repo.changelog.filteredrevs
88 88 # fast path in simple case to avoid impact of non optimised code
89 89 hiddens = filterrevs(repo, 'visible')
90 90 if phases.hassecret(repo):
91 91 cl = repo.changelog
92 92 secret = phases.secret
93 93 getphase = repo._phasecache.phase
94 94 first = min(cl.rev(n) for n in repo._phasecache.phaseroots[secret])
95 95 revs = cl.revs(start=first)
96 96 secrets = set(r for r in revs if getphase(repo, r) >= secret)
97 97 return frozenset(hiddens | secrets)
98 98 else:
99 99 return hiddens
100 100
101 101 def computemutable(repo):
102 """compute the set of revision that should be filtered when used a server
103
104 Secret and hidden changeset should not pretend to be here."""
105 102 assert not repo.changelog.filteredrevs
106 103 # fast check to avoid revset call on huge repo
107 104 if any(repo._phasecache.phaseroots[1:]):
108 105 getphase = repo._phasecache.phase
109 106 maymutable = filterrevs(repo, 'base')
110 107 return frozenset(r for r in maymutable if getphase(repo, r))
111 108 return frozenset()
112 109
113 110 def computeimpactable(repo):
114 111 """Everything impactable by mutable revision
115 112
116 113 The immutable filter still have some chance to get invalidated. This will
117 114 happen when:
118 115
119 116 - you garbage collect hidden changeset,
120 117 - public phase is moved backward,
121 118 - something is changed in the filtering (this could be fixed)
122 119
123 120 This filter out any mutable changeset and any public changeset that may be
124 121 impacted by something happening to a mutable revision.
125 122
126 123 This is achieved by filtered everything with a revision number egal or
127 124 higher than the first mutable changeset is filtered."""
128 125 assert not repo.changelog.filteredrevs
129 126 cl = repo.changelog
130 127 firstmutable = len(cl)
131 128 for roots in repo._phasecache.phaseroots[1:]:
132 129 if roots:
133 130 firstmutable = min(firstmutable, min(cl.rev(r) for r in roots))
134 131 # protect from nullrev root
135 132 firstmutable = max(0, firstmutable)
136 133 return frozenset(xrange(firstmutable, len(cl)))
137 134
138 135 # function to compute filtered set
139 136 #
140 137 # When adding a new filter you MUST update the table at:
141 138 # mercurial.branchmap.subsettable
142 139 # Otherwise your filter will have to recompute all its branches cache
143 140 # from scratch (very slow).
144 141 filtertable = {'visible': computehidden,
145 142 'served': computeunserved,
146 143 'immutable': computemutable,
147 144 'base': computeimpactable}
148 145
149 146 def filterrevs(repo, filtername):
150 147 """returns set of filtered revision for this filter name"""
151 148 if filtername not in repo.filteredrevcache:
152 149 func = filtertable[filtername]
153 150 repo.filteredrevcache[filtername] = func(repo.unfiltered())
154 151 return repo.filteredrevcache[filtername]
155 152
156 153 class repoview(object):
157 154 """Provide a read/write view of a repo through a filtered changelog
158 155
159 156 This object is used to access a filtered version of a repository without
160 157 altering the original repository object itself. We can not alter the
161 158 original object for two main reasons:
162 159 - It prevents the use of a repo with multiple filters at the same time. In
163 160 particular when multiple threads are involved.
164 161 - It makes scope of the filtering harder to control.
165 162
166 163 This object behaves very closely to the original repository. All attribute
167 164 operations are done on the original repository:
168 165 - An access to `repoview.someattr` actually returns `repo.someattr`,
169 166 - A write to `repoview.someattr` actually sets value of `repo.someattr`,
170 167 - A deletion of `repoview.someattr` actually drops `someattr`
171 168 from `repo.__dict__`.
172 169
173 170 The only exception is the `changelog` property. It is overridden to return
174 171 a (surface) copy of `repo.changelog` with some revisions filtered. The
175 172 `filtername` attribute of the view control the revisions that need to be
176 173 filtered. (the fact the changelog is copied is an implementation detail).
177 174
178 175 Unlike attributes, this object intercepts all method calls. This means that
179 176 all methods are run on the `repoview` object with the filtered `changelog`
180 177 property. For this purpose the simple `repoview` class must be mixed with
181 178 the actual class of the repository. This ensures that the resulting
182 179 `repoview` object have the very same methods than the repo object. This
183 180 leads to the property below.
184 181
185 182 repoview.method() --> repo.__class__.method(repoview)
186 183
187 184 The inheritance has to be done dynamically because `repo` can be of any
188 185 subclasses of `localrepo`. Eg: `bundlerepo` or `statichttprepo`.
189 186 """
190 187
191 188 def __init__(self, repo, filtername):
192 189 object.__setattr__(self, r'_unfilteredrepo', repo)
193 190 object.__setattr__(self, r'filtername', filtername)
194 191 object.__setattr__(self, r'_clcachekey', None)
195 192 object.__setattr__(self, r'_clcache', None)
196 193
197 194 # not a propertycache on purpose we shall implement a proper cache later
198 195 @property
199 196 def changelog(self):
200 197 """return a filtered version of the changeset
201 198
202 199 this changelog must not be used for writing"""
203 200 # some cache may be implemented later
204 201 unfi = self._unfilteredrepo
205 202 unfichangelog = unfi.changelog
206 203 # bypass call to changelog.method
207 204 unfiindex = unfichangelog.index
208 205 unfilen = len(unfiindex) - 1
209 206 unfinode = unfiindex[unfilen - 1][7]
210 207
211 208 revs = filterrevs(unfi, self.filtername)
212 209 cl = self._clcache
213 210 newkey = (unfilen, unfinode, hash(revs), unfichangelog._delayed)
214 211 # if cl.index is not unfiindex, unfi.changelog would be
215 212 # recreated, and our clcache refers to garbage object
216 213 if (cl is not None and
217 214 (cl.index is not unfiindex or newkey != self._clcachekey)):
218 215 cl = None
219 216 # could have been made None by the previous if
220 217 if cl is None:
221 218 cl = copy.copy(unfichangelog)
222 219 cl.filteredrevs = revs
223 220 object.__setattr__(self, r'_clcache', cl)
224 221 object.__setattr__(self, r'_clcachekey', newkey)
225 222 return cl
226 223
227 224 def unfiltered(self):
228 225 """Return an unfiltered version of a repo"""
229 226 return self._unfilteredrepo
230 227
231 228 def filtered(self, name):
232 229 """Return a filtered version of a repository"""
233 230 if name == self.filtername:
234 231 return self
235 232 return self.unfiltered().filtered(name)
236 233
237 234 # everything access are forwarded to the proxied repo
238 235 def __getattr__(self, attr):
239 236 return getattr(self._unfilteredrepo, attr)
240 237
241 238 def __setattr__(self, attr, value):
242 239 return setattr(self._unfilteredrepo, attr, value)
243 240
244 241 def __delattr__(self, attr):
245 242 return delattr(self._unfilteredrepo, attr)
General Comments 0
You need to be logged in to leave comments. Login now