Show More
@@ -883,7 +883,7 b' class queue(object):' | |||||
883 | def finish(self, repo, revs): |
|
883 | def finish(self, repo, revs): | |
884 | # Manually trigger phase computation to ensure phasedefaults is |
|
884 | # Manually trigger phase computation to ensure phasedefaults is | |
885 | # executed before we remove the patches. |
|
885 | # executed before we remove the patches. | |
886 |
repo._phase |
|
886 | repo._phasecache | |
887 | patches = self._revpatches(repo, sorted(revs)) |
|
887 | patches = self._revpatches(repo, sorted(revs)) | |
888 | qfinished = self._cleanup(patches, len(patches)) |
|
888 | qfinished = self._cleanup(patches, len(patches)) | |
889 | if qfinished and repo.ui.configbool('mq', 'secret', False): |
|
889 | if qfinished and repo.ui.configbool('mq', 'secret', False): |
@@ -4378,7 +4378,7 b' def phase(ui, repo, *revs, **opts):' | |||||
4378 | nodes = [ctx.node() for ctx in repo.set('%ld', revs)] |
|
4378 | nodes = [ctx.node() for ctx in repo.set('%ld', revs)] | |
4379 | if not nodes: |
|
4379 | if not nodes: | |
4380 | raise util.Abort(_('empty revision set')) |
|
4380 | raise util.Abort(_('empty revision set')) | |
4381 | olddata = repo._phaserev[:] |
|
4381 | olddata = repo._phasecache.getphaserevs(repo)[:] | |
4382 | phases.advanceboundary(repo, targetphase, nodes) |
|
4382 | phases.advanceboundary(repo, targetphase, nodes) | |
4383 | if opts['force']: |
|
4383 | if opts['force']: | |
4384 | phases.retractboundary(repo, targetphase, nodes) |
|
4384 | phases.retractboundary(repo, targetphase, nodes) | |
@@ -4386,7 +4386,7 b' def phase(ui, repo, *revs, **opts):' | |||||
4386 | lock.release() |
|
4386 | lock.release() | |
4387 | if olddata is not None: |
|
4387 | if olddata is not None: | |
4388 | changes = 0 |
|
4388 | changes = 0 | |
4389 | newdata = repo._phaserev |
|
4389 | newdata = repo._phasecache.getphaserevs(repo) | |
4390 | changes = sum(o != newdata[i] for i, o in enumerate(olddata)) |
|
4390 | changes = sum(o != newdata[i] for i, o in enumerate(olddata)) | |
4391 | rejected = [n for n in nodes |
|
4391 | rejected = [n for n in nodes | |
4392 | if newdata[repo[n].rev()] < targetphase] |
|
4392 | if newdata[repo[n].rev()] < targetphase] |
@@ -191,12 +191,7 b' class changectx(object):' | |||||
191 | def bookmarks(self): |
|
191 | def bookmarks(self): | |
192 | return self._repo.nodebookmarks(self._node) |
|
192 | return self._repo.nodebookmarks(self._node) | |
193 | def phase(self): |
|
193 | def phase(self): | |
194 | if self._rev == -1: |
|
194 | return self._repo._phasecache.phase(self._repo, self._rev) | |
195 | return phases.public |
|
|||
196 | if self._rev >= len(self._repo._phaserev): |
|
|||
197 | # outdated cache |
|
|||
198 | del self._repo._phaserev |
|
|||
199 | return self._repo._phaserev[self._rev] |
|
|||
200 | def phasestr(self): |
|
195 | def phasestr(self): | |
201 | return phases.phasenames[self.phase()] |
|
196 | return phases.phasenames[self.phase()] | |
202 | def mutable(self): |
|
197 | def mutable(self): |
@@ -105,7 +105,7 b' def findcommonoutgoing(repo, other, only' | |||||
105 | og.commonheads, _any, _hds = commoninc |
|
105 | og.commonheads, _any, _hds = commoninc | |
106 |
|
106 | |||
107 | # compute outgoing |
|
107 | # compute outgoing | |
108 | if not repo._phaseroots[phases.secret]: |
|
108 | if not repo._phasecache.phaseroots[phases.secret]: | |
109 | og.missingheads = onlyheads or repo.heads() |
|
109 | og.missingheads = onlyheads or repo.heads() | |
110 | elif onlyheads is None: |
|
110 | elif onlyheads is None: | |
111 | # use visible heads as it should be cached |
|
111 | # use visible heads as it should be cached |
@@ -41,7 +41,6 b' class localrepository(repo.repository):' | |||||
41 | self.wopener = scmutil.opener(self.root) |
|
41 | self.wopener = scmutil.opener(self.root) | |
42 | self.baseui = baseui |
|
42 | self.baseui = baseui | |
43 | self.ui = baseui.copy() |
|
43 | self.ui = baseui.copy() | |
44 | self._dirtyphases = False |
|
|||
45 | # A list of callback to shape the phase if no data were found. |
|
44 | # A list of callback to shape the phase if no data were found. | |
46 | # Callback are in the form: func(repo, roots) --> processed root. |
|
45 | # Callback are in the form: func(repo, roots) --> processed root. | |
47 | # This list it to be filled by extension during repo setup |
|
46 | # This list it to be filled by extension during repo setup | |
@@ -182,22 +181,8 b' class localrepository(repo.repository):' | |||||
182 | bookmarks.write(self) |
|
181 | bookmarks.write(self) | |
183 |
|
182 | |||
184 | @storecache('phaseroots') |
|
183 | @storecache('phaseroots') | |
185 |
def _phase |
|
184 | def _phasecache(self): | |
186 | phaseroots, self._dirtyphases = phases.readroots( |
|
185 | return phases.phasecache(self, self._phasedefaults) | |
187 | self, self._phasedefaults) |
|
|||
188 | return phaseroots |
|
|||
189 |
|
||||
190 | @propertycache |
|
|||
191 | def _phaserev(self): |
|
|||
192 | cache = [phases.public] * len(self) |
|
|||
193 | for phase in phases.trackedphases: |
|
|||
194 | roots = map(self.changelog.rev, self._phaseroots[phase]) |
|
|||
195 | if roots: |
|
|||
196 | for rev in roots: |
|
|||
197 | cache[rev] = phase |
|
|||
198 | for rev in self.changelog.descendants(*roots): |
|
|||
199 | cache[rev] = phase |
|
|||
200 | return cache |
|
|||
201 |
|
186 | |||
202 | @storecache('00changelog.i') |
|
187 | @storecache('00changelog.i') | |
203 | def changelog(self): |
|
188 | def changelog(self): | |
@@ -604,10 +589,11 b' class localrepository(repo.repository):' | |||||
604 |
|
589 | |||
605 | def known(self, nodes): |
|
590 | def known(self, nodes): | |
606 | nm = self.changelog.nodemap |
|
591 | nm = self.changelog.nodemap | |
|
592 | pc = self._phasecache | |||
607 | result = [] |
|
593 | result = [] | |
608 | for n in nodes: |
|
594 | for n in nodes: | |
609 | r = nm.get(n) |
|
595 | r = nm.get(n) | |
610 |
resp = not (r is None or self |
|
596 | resp = not (r is None or pc.phase(self, r) >= phases.secret) | |
611 | result.append(resp) |
|
597 | result.append(resp) | |
612 | return result |
|
598 | return result | |
613 |
|
599 | |||
@@ -863,7 +849,6 b' class localrepository(repo.repository):' | |||||
863 | pass |
|
849 | pass | |
864 |
|
850 | |||
865 | delcache('_tagscache') |
|
851 | delcache('_tagscache') | |
866 | delcache('_phaserev') |
|
|||
867 |
|
852 | |||
868 | self._branchcache = None # in UTF-8 |
|
853 | self._branchcache = None # in UTF-8 | |
869 | self._branchcachetip = None |
|
854 | self._branchcachetip = None | |
@@ -931,9 +916,8 b' class localrepository(repo.repository):' | |||||
931 |
|
916 | |||
932 | def unlock(): |
|
917 | def unlock(): | |
933 | self.store.write() |
|
918 | self.store.write() | |
934 |
if self |
|
919 | if '_phasecache' in vars(self): | |
935 |
|
|
920 | self._phasecache.write() | |
936 | self._dirtyphases = False |
|
|||
937 | for k, ce in self._filecache.items(): |
|
921 | for k, ce in self._filecache.items(): | |
938 | if k == 'dirstate': |
|
922 | if k == 'dirstate': | |
939 | continue |
|
923 | continue |
@@ -99,7 +99,7 b' Note: old client behave as publish serve' | |||||
99 | """ |
|
99 | """ | |
100 |
|
100 | |||
101 | import errno |
|
101 | import errno | |
102 | from node import nullid, bin, hex, short |
|
102 | from node import nullid, nullrev, bin, hex, short | |
103 | from i18n import _ |
|
103 | from i18n import _ | |
104 |
|
104 | |||
105 | allphases = public, draft, secret = range(3) |
|
105 | allphases = public, draft, secret = range(3) | |
@@ -124,7 +124,7 b' def _filterunknown(ui, changelog, phaser' | |||||
124 | updated = True |
|
124 | updated = True | |
125 | return updated |
|
125 | return updated | |
126 |
|
126 | |||
127 | def readroots(repo, phasedefaults=None): |
|
127 | def _readroots(repo, phasedefaults=None): | |
128 | """Read phase roots from disk |
|
128 | """Read phase roots from disk | |
129 |
|
129 | |||
130 | phasedefaults is a list of fn(repo, roots) callable, which are |
|
130 | phasedefaults is a list of fn(repo, roots) callable, which are | |
@@ -156,15 +156,51 b' def readroots(repo, phasedefaults=None):' | |||||
156 | dirty = True |
|
156 | dirty = True | |
157 | return roots, dirty |
|
157 | return roots, dirty | |
158 |
|
158 | |||
159 | def writeroots(repo, phaseroots): |
|
159 | class phasecache(object): | |
160 | """Write phase roots from disk""" |
|
160 | def __init__(self, repo, phasedefaults): | |
161 | f = repo.sopener('phaseroots', 'w', atomictemp=True) |
|
161 | self.phaseroots, self.dirty = _readroots(repo, phasedefaults) | |
162 | try: |
|
162 | self.opener = repo.sopener | |
163 | for phase, roots in enumerate(phaseroots): |
|
163 | self._phaserevs = None | |
164 | for h in roots: |
|
164 | ||
165 | f.write('%i %s\n' % (phase, hex(h))) |
|
165 | def getphaserevs(self, repo, rebuild=False): | |
166 | finally: |
|
166 | if rebuild or self._phaserevs is None: | |
167 | f.close() |
|
167 | revs = [public] * len(repo.changelog) | |
|
168 | for phase in trackedphases: | |||
|
169 | roots = map(repo.changelog.rev, self.phaseroots[phase]) | |||
|
170 | if roots: | |||
|
171 | for rev in roots: | |||
|
172 | revs[rev] = phase | |||
|
173 | for rev in repo.changelog.descendants(*roots): | |||
|
174 | revs[rev] = phase | |||
|
175 | self._phaserevs = revs | |||
|
176 | return self._phaserevs | |||
|
177 | ||||
|
178 | def invalidatephaserevs(self): | |||
|
179 | self._phaserevs = None | |||
|
180 | ||||
|
181 | def phase(self, repo, rev): | |||
|
182 | # We need a repo argument here to be able to build _phaserev | |||
|
183 | # if necessary. The repository instance is not stored in | |||
|
184 | # phasecache to avoid reference cycles. The changelog instance | |||
|
185 | # is not stored because it is a filecache() property and can | |||
|
186 | # be replaced without us being notified. | |||
|
187 | if rev == nullrev: | |||
|
188 | return public | |||
|
189 | if self._phaserevs is None or rev >= len(self._phaserevs): | |||
|
190 | self._phaserevs = self.getphaserevs(repo, rebuild=True) | |||
|
191 | return self._phaserevs[rev] | |||
|
192 | ||||
|
193 | def write(self): | |||
|
194 | if not self.dirty: | |||
|
195 | return | |||
|
196 | f = self.opener('phaseroots', 'w', atomictemp=True) | |||
|
197 | try: | |||
|
198 | for phase, roots in enumerate(self.phaseroots): | |||
|
199 | for h in roots: | |||
|
200 | f.write('%i %s\n' % (phase, hex(h))) | |||
|
201 | finally: | |||
|
202 | f.close() | |||
|
203 | self.dirty = False | |||
168 |
|
204 | |||
169 | def advanceboundary(repo, targetphase, nodes): |
|
205 | def advanceboundary(repo, targetphase, nodes): | |
170 | """Add nodes to a phase changing other nodes phases if necessary. |
|
206 | """Add nodes to a phase changing other nodes phases if necessary. | |
@@ -173,6 +209,8 b' def advanceboundary(repo, targetphase, n' | |||||
173 | in the target phase or kept in a *lower* phase. |
|
209 | in the target phase or kept in a *lower* phase. | |
174 |
|
210 | |||
175 | Simplify boundary to contains phase roots only.""" |
|
211 | Simplify boundary to contains phase roots only.""" | |
|
212 | phcache = repo._phasecache | |||
|
213 | ||||
176 | delroots = [] # set of root deleted by this path |
|
214 | delroots = [] # set of root deleted by this path | |
177 | for phase in xrange(targetphase + 1, len(allphases)): |
|
215 | for phase in xrange(targetphase + 1, len(allphases)): | |
178 | # filter nodes that are not in a compatible phase already |
|
216 | # filter nodes that are not in a compatible phase already | |
@@ -181,16 +219,15 b' def advanceboundary(repo, targetphase, n' | |||||
181 | nodes = [n for n in nodes if repo[n].phase() >= phase] |
|
219 | nodes = [n for n in nodes if repo[n].phase() >= phase] | |
182 | if not nodes: |
|
220 | if not nodes: | |
183 | break # no roots to move anymore |
|
221 | break # no roots to move anymore | |
184 |
roots = |
|
222 | roots = phcache.phaseroots[phase] | |
185 | olds = roots.copy() |
|
223 | olds = roots.copy() | |
186 | ctxs = list(repo.set('roots((%ln::) - (%ln::%ln))', olds, olds, nodes)) |
|
224 | ctxs = list(repo.set('roots((%ln::) - (%ln::%ln))', olds, olds, nodes)) | |
187 | roots.clear() |
|
225 | roots.clear() | |
188 | roots.update(ctx.node() for ctx in ctxs) |
|
226 | roots.update(ctx.node() for ctx in ctxs) | |
189 | if olds != roots: |
|
227 | if olds != roots: | |
190 | # invalidate cache (we probably could be smarter here |
|
228 | # invalidate cache (we probably could be smarter here | |
191 | if '_phaserev' in vars(repo): |
|
229 | phcache.invalidatephaserevs() | |
192 | del repo._phaserev |
|
230 | phcache.dirty = True | |
193 | repo._dirtyphases = True |
|
|||
194 | # some roots may need to be declared for lower phases |
|
231 | # some roots may need to be declared for lower phases | |
195 | delroots.extend(olds - roots) |
|
232 | delroots.extend(olds - roots) | |
196 | # declare deleted root in the target phase |
|
233 | # declare deleted root in the target phase | |
@@ -205,22 +242,23 b' def retractboundary(repo, targetphase, n' | |||||
205 | in the target phase or kept in a *higher* phase. |
|
242 | in the target phase or kept in a *higher* phase. | |
206 |
|
243 | |||
207 | Simplify boundary to contains phase roots only.""" |
|
244 | Simplify boundary to contains phase roots only.""" | |
208 | currentroots = repo._phaseroots[targetphase] |
|
245 | phcache = repo._phasecache | |
|
246 | ||||
|
247 | currentroots = phcache.phaseroots[targetphase] | |||
209 | newroots = [n for n in nodes if repo[n].phase() < targetphase] |
|
248 | newroots = [n for n in nodes if repo[n].phase() < targetphase] | |
210 | if newroots: |
|
249 | if newroots: | |
211 | currentroots.update(newroots) |
|
250 | currentroots.update(newroots) | |
212 | ctxs = repo.set('roots(%ln::)', currentroots) |
|
251 | ctxs = repo.set('roots(%ln::)', currentroots) | |
213 | currentroots.intersection_update(ctx.node() for ctx in ctxs) |
|
252 | currentroots.intersection_update(ctx.node() for ctx in ctxs) | |
214 | if '_phaserev' in vars(repo): |
|
253 | phcache.invalidatephaserevs() | |
215 | del repo._phaserev |
|
254 | phcache.dirty = True | |
216 | repo._dirtyphases = True |
|
|||
217 |
|
255 | |||
218 |
|
256 | |||
219 | def listphases(repo): |
|
257 | def listphases(repo): | |
220 | """List phases root for serialisation over pushkey""" |
|
258 | """List phases root for serialisation over pushkey""" | |
221 | keys = {} |
|
259 | keys = {} | |
222 | value = '%i' % draft |
|
260 | value = '%i' % draft | |
223 | for root in repo._phaseroots[draft]: |
|
261 | for root in repo._phasecache.phaseroots[draft]: | |
224 | keys[hex(root)] = value |
|
262 | keys[hex(root)] = value | |
225 |
|
263 | |||
226 | if repo.ui.configbool('phases', 'publish', True): |
|
264 | if repo.ui.configbool('phases', 'publish', True): | |
@@ -263,7 +301,7 b' def pushphase(repo, nhex, oldphasestr, n' | |||||
263 | def visibleheads(repo): |
|
301 | def visibleheads(repo): | |
264 | """return the set of visible head of this repo""" |
|
302 | """return the set of visible head of this repo""" | |
265 | # XXX we want a cache on this |
|
303 | # XXX we want a cache on this | |
266 | sroots = repo._phaseroots[secret] |
|
304 | sroots = repo._phasecache.phaseroots[secret] | |
267 | if sroots: |
|
305 | if sroots: | |
268 | # XXX very slow revset. storing heads or secret "boundary" would help. |
|
306 | # XXX very slow revset. storing heads or secret "boundary" would help. | |
269 | revset = repo.set('heads(not (%ln::))', sroots) |
|
307 | revset = repo.set('heads(not (%ln::))', sroots) | |
@@ -279,7 +317,7 b' def visiblebranchmap(repo):' | |||||
279 | """return a branchmap for the visible set""" |
|
317 | """return a branchmap for the visible set""" | |
280 | # XXX Recomputing this data on the fly is very slow. We should build a |
|
318 | # XXX Recomputing this data on the fly is very slow. We should build a | |
281 | # XXX cached version while computin the standard branchmap version. |
|
319 | # XXX cached version while computin the standard branchmap version. | |
282 | sroots = repo._phaseroots[secret] |
|
320 | sroots = repo._phasecache.phaseroots[secret] | |
283 | if sroots: |
|
321 | if sroots: | |
284 | vbranchmap = {} |
|
322 | vbranchmap = {} | |
285 | for branch, nodes in repo.branchmap().iteritems(): |
|
323 | for branch, nodes in repo.branchmap().iteritems(): |
@@ -463,7 +463,8 b' def draft(repo, subset, x):' | |||||
463 | """``draft()`` |
|
463 | """``draft()`` | |
464 | Changeset in draft phase.""" |
|
464 | Changeset in draft phase.""" | |
465 | getargs(x, 0, 0, _("draft takes no arguments")) |
|
465 | getargs(x, 0, 0, _("draft takes no arguments")) | |
466 | return [r for r in subset if repo._phaserev[r] == phases.draft] |
|
466 | pc = repo._phasecache | |
|
467 | return [r for r in subset if pc.phase(repo, r) == phases.draft] | |||
467 |
|
468 | |||
468 | def filelog(repo, subset, x): |
|
469 | def filelog(repo, subset, x): | |
469 | """``filelog(pattern)`` |
|
470 | """``filelog(pattern)`` | |
@@ -852,7 +853,8 b' def public(repo, subset, x):' | |||||
852 | """``public()`` |
|
853 | """``public()`` | |
853 | Changeset in public phase.""" |
|
854 | Changeset in public phase.""" | |
854 | getargs(x, 0, 0, _("public takes no arguments")) |
|
855 | getargs(x, 0, 0, _("public takes no arguments")) | |
855 | return [r for r in subset if repo._phaserev[r] == phases.public] |
|
856 | pc = repo._phasecache | |
|
857 | return [r for r in subset if pc.phase(repo, r) == phases.public] | |||
856 |
|
858 | |||
857 | def remote(repo, subset, x): |
|
859 | def remote(repo, subset, x): | |
858 | """``remote([id [,path]])`` |
|
860 | """``remote([id [,path]])`` | |
@@ -1031,7 +1033,8 b' def secret(repo, subset, x):' | |||||
1031 | """``secret()`` |
|
1033 | """``secret()`` | |
1032 | Changeset in secret phase.""" |
|
1034 | Changeset in secret phase.""" | |
1033 | getargs(x, 0, 0, _("secret takes no arguments")) |
|
1035 | getargs(x, 0, 0, _("secret takes no arguments")) | |
1034 | return [r for r in subset if repo._phaserev[r] == phases.secret] |
|
1036 | pc = repo._phasecache | |
|
1037 | return [r for r in subset if pc.phase(repo, r) == phases.secret] | |||
1035 |
|
1038 | |||
1036 | def sort(repo, subset, x): |
|
1039 | def sort(repo, subset, x): | |
1037 | """``sort(set[, [-]key...])`` |
|
1040 | """``sort(set[, [-]key...])`` |
General Comments 0
You need to be logged in to leave comments.
Login now