annotate mercurial/repoview.py @ 18988:5bae936764bb

parsers: a C implementation of the new ancestors algorithm The performance of both the old and new Python ancestor algorithms depends on the number of revs they need to traverse. Although the new algorithm performs far better than the old when revs are numerically and topologically close, both algorithms become slow under other circumstances, taking up to 1.8 seconds to give answers in a Linux kernel repo. This C implementation of the new algorithm is a fairly straightforward transliteration. The only corner case of interest is that it raises an OverflowError if the number of GCA candidates found during the first pass is greater than 24, to avoid the dual perils of fixnum overflow and trying to allocate too much memory. (If this exception is raised, the Python implementation is used instead.) Performance numbers are good: in a Linux kernel repo, time for "hg debugancestors" on two distant revs (24bf01de7537 and c2a8808f5943) is as follows: Old Python: 0.36 sec New Python: 0.42 sec New C: 0.02 sec For a case where the new algorithm should perform well: Old Python: 1.84 sec New Python: 0.07 sec New C: measures as zero when using --time (This commit includes a paranoid cross-check to ensure that the Python and C implementations give identical answers. The above performance numbers were measured with that check disabled.)
author Bryan O'Sullivan <bryano@fb.com>
date Tue, 16 Apr 2013 10:08:20 -0700
parents 45348b4df46e
children 175c6fd8cacc
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
1 # repoview.py - Filtered view of a localrepo object
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
2 #
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
4 # Logilab SA <contact@logilab.fr>
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
5 #
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
6 # This software may be used and distributed according to the terms of the
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
7 # GNU General Public License version 2 or any later version.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
8
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
9 import copy
18102
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
10 import phases
18245
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
11 import util
18495
8260fa9f30b9 bookmarks: don't use bookmarks.listbookmarks in local computations
Kevin Bullock <kbullock@ringworld.org>
parents: 18462
diff changeset
12 import obsolete, revset
18102
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
13
18242
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
14
18293
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
15 def hideablerevs(repo):
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
16 """Revisions candidates to be hidden
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
17
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
18 This is a standalone function to help extensions to wrap it."""
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
19 return obsolete.getrevs(repo, 'obsolete')
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
20
18242
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
21 def computehidden(repo):
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
22 """compute the set of hidden revision to filter
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
23
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
24 During most operation hidden should be filtered."""
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
25 assert not repo.changelog.filteredrevs
18293
1f35d6737ed8 repoview: extract hideable revision computation in a dedicated function
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18274
diff changeset
26 hideable = hideablerevs(repo)
18272
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
27 if hideable:
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
28 cl = repo.changelog
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
29 firsthideable = min(hideable)
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
30 revs = cl.revs(start=firsthideable)
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
31 blockers = [r for r in revset._children(repo, revs, hideable)
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
32 if r not in hideable]
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
33 for par in repo[None].parents():
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
34 blockers.append(par.rev())
18495
8260fa9f30b9 bookmarks: don't use bookmarks.listbookmarks in local computations
Kevin Bullock <kbullock@ringworld.org>
parents: 18462
diff changeset
35 for bm in repo._bookmarks.values():
18272
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
36 blockers.append(repo[bm].rev())
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
37 blocked = cl.ancestors(blockers, inclusive=True)
95ef7a87c053 performance: speedup computation of hidden revisions
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18250
diff changeset
38 return frozenset(r for r in hideable if r not in blocked)
18242
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
39 return frozenset()
e4687edec014 clfilter: introduces a hidden filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18233
diff changeset
40
18102
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
41 def computeunserved(repo):
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
42 """compute the set of revision that should be filtered when used a server
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
43
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
44 Secret and hidden changeset should not pretend to be here."""
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
45 assert not repo.changelog.filteredrevs
3c7b67b76190 clfilter: introduce a "unserver" filtering mode
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18101
diff changeset
46 # fast path in simple case to avoid impact of non optimised code
18382
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
47 hiddens = filterrevs(repo, 'visible')
18273
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
48 if phases.hassecret(repo):
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
49 cl = repo.changelog
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
50 secret = phases.secret
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
51 getphase = repo._phasecache.phase
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
52 first = min(cl.rev(n) for n in repo._phasecache.phaseroots[secret])
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
53 revs = cl.revs(start=first)
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
54 secrets = set(r for r in revs if getphase(repo, r) >= secret)
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
55 return frozenset(hiddens | secrets)
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
56 else:
a2d54f68e13c performance: speedup computation of unserved revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18272
diff changeset
57 return hiddens
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
58
18245
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
59 def computemutable(repo):
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
60 """compute the set of revision that should be filtered when used a server
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
61
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
62 Secret and hidden changeset should not pretend to be here."""
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
63 assert not repo.changelog.filteredrevs
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
64 # fast check to avoid revset call on huge repo
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
65 if util.any(repo._phasecache.phaseroots[1:]):
18274
254b708fd37d performance: speedup computation of mutable revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18273
diff changeset
66 getphase = repo._phasecache.phase
18382
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
67 maymutable = filterrevs(repo, 'base')
18274
254b708fd37d performance: speedup computation of mutable revisions
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18273
diff changeset
68 return frozenset(r for r in maymutable if getphase(repo, r))
18245
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
69 return frozenset()
aff706b3a21c clfilter: add mutable filtering
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18242
diff changeset
70
18246
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
71 def computeimpactable(repo):
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
72 """Everything impactable by mutable revision
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
73
18462
593eb3786165 documentation: update to new filter names
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18445
diff changeset
74 The immutable filter still have some chance to get invalidated. This will
18246
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
75 happen when:
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
76
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
77 - you garbage collect hidden changeset,
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
78 - public phase is moved backward,
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
79 - something is changed in the filtering (this could be fixed)
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
80
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
81 This filter out any mutable changeset and any public changeset that may be
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
82 impacted by something happening to a mutable revision.
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
83
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
84 This is achieved by filtered everything with a revision number egal or
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
85 higher than the first mutable changeset is filtered."""
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
86 assert not repo.changelog.filteredrevs
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
87 cl = repo.changelog
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
88 firstmutable = len(cl)
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
89 for roots in repo._phasecache.phaseroots[1:]:
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
90 if roots:
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
91 firstmutable = min(firstmutable, min(cl.rev(r) for r in roots))
18443
64848f7fb764 repoview: protect `base` computation from weird phase root
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18382
diff changeset
92 # protect from nullrev root
64848f7fb764 repoview: protect `base` computation from weird phase root
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18382
diff changeset
93 firstmutable = max(0, firstmutable)
18246
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
94 return frozenset(xrange(firstmutable, len(cl)))
58ca19edc043 clfilter: add impactable filter
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18245
diff changeset
95
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
96 # function to compute filtered set
18382
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
97 filtertable = {'visible': computehidden,
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
98 'served': computeunserved,
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
99 'immutable': computemutable,
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
100 'base': computeimpactable}
18233
59a9f18d4587 repoview: add a subset table
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18231
diff changeset
101 ### Nearest subset relation
59a9f18d4587 repoview: add a subset table
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18231
diff changeset
102 # Nearest subset of filter X is a filter Y so that:
59a9f18d4587 repoview: add a subset table
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18231
diff changeset
103 # * Y is included in X,
59a9f18d4587 repoview: add a subset table
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18231
diff changeset
104 # * X - Y is as small as possible.
59a9f18d4587 repoview: add a subset table
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18231
diff changeset
105 # This create and ordering used for branchmap purpose.
59a9f18d4587 repoview: add a subset table
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18231
diff changeset
106 # the ordering may be partial
18382
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
107 subsettable = {None: 'visible',
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
108 'visible': 'served',
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
109 'served': 'immutable',
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
110 'immutable': 'base'}
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
111
18382
f3b21beb9802 filtering: rename filters to their antonyms
Kevin Bullock <kbullock@ringworld.org>
parents: 18293
diff changeset
112 def filterrevs(repo, filtername):
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
113 """returns set of filtered revision for this filter name"""
18101
a464deecc9dd clfilter: add a cache on repo for set of revision to filter for a given set.
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18100
diff changeset
114 if filtername not in repo.filteredrevcache:
a464deecc9dd clfilter: add a cache on repo for set of revision to filter for a given set.
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18100
diff changeset
115 func = filtertable[filtername]
a464deecc9dd clfilter: add a cache on repo for set of revision to filter for a given set.
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18100
diff changeset
116 repo.filteredrevcache[filtername] = func(repo.unfiltered())
a464deecc9dd clfilter: add a cache on repo for set of revision to filter for a given set.
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 18100
diff changeset
117 return repo.filteredrevcache[filtername]
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
118
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
119 class repoview(object):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
120 """Provide a read/write view of a repo through a filtered changelog
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
121
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
122 This object is used to access a filtered version of a repository without
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
123 altering the original repository object itself. We can not alter the
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
124 original object for two main reasons:
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
125 - It prevents the use of a repo with multiple filters at the same time. In
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
126 particular when multiple threads are involved.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
127 - It makes scope of the filtering harder to control.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
128
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
129 This object behaves very closely to the original repository. All attribute
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
130 operations are done on the original repository:
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
131 - An access to `repoview.someattr` actually returns `repo.someattr`,
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
132 - A write to `repoview.someattr` actually sets value of `repo.someattr`,
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
133 - A deletion of `repoview.someattr` actually drops `someattr`
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
134 from `repo.__dict__`.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
135
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
136 The only exception is the `changelog` property. It is overridden to return
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
137 a (surface) copy of `repo.changelog` with some revisions filtered. The
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
138 `filtername` attribute of the view control the revisions that need to be
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
139 filtered. (the fact the changelog is copied is an implementation detail).
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
140
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
141 Unlike attributes, this object intercepts all method calls. This means that
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
142 all methods are run on the `repoview` object with the filtered `changelog`
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
143 property. For this purpose the simple `repoview` class must be mixed with
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
144 the actual class of the repository. This ensures that the resulting
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
145 `repoview` object have the very same methods than the repo object. This
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
146 leads to the property below.
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
147
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
148 repoview.method() --> repo.__class__.method(repoview)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
149
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
150 The inheritance has to be done dynamically because `repo` can be of any
18644
3e92772d5383 spelling: fix some minor issues found by spell checker
Mads Kiilerich <mads@kiilerich.com>
parents: 18495
diff changeset
151 subclasses of `localrepo`. Eg: `bundlerepo` or `statichttprepo`.
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
152 """
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
153
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
154 def __init__(self, repo, filtername):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
155 object.__setattr__(self, '_unfilteredrepo', repo)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
156 object.__setattr__(self, 'filtername', filtername)
18445
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
157 object.__setattr__(self, '_clcachekey', None)
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
158 object.__setattr__(self, '_clcache', None)
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
159
18644
3e92772d5383 spelling: fix some minor issues found by spell checker
Mads Kiilerich <mads@kiilerich.com>
parents: 18495
diff changeset
160 # not a propertycache on purpose we shall implement a proper cache later
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
161 @property
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
162 def changelog(self):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
163 """return a filtered version of the changeset
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
164
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
165 this changelog must not be used for writing"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
166 # some cache may be implemented later
18445
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
167 unfi = self._unfilteredrepo
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
168 unfichangelog = unfi.changelog
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
169 revs = filterrevs(unfi, self.filtername)
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
170 cl = self._clcache
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
171 newkey = (len(unfichangelog), unfichangelog.tip(), hash(revs))
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
172 if cl is not None:
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
173 # we need to check curkey too for some obscure reason.
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
174 # MQ test show a corruption of the underlying repo (in _clcache)
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
175 # without change in the cachekey.
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
176 oldfilter = cl.filteredrevs
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
177 try:
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
178 cl.filterrevs = () # disable filtering for tip
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
179 curkey = (len(cl), cl.tip(), hash(oldfilter))
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
180 finally:
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
181 cl.filteredrevs = oldfilter
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
182 if newkey != self._clcachekey or newkey != curkey:
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
183 cl = None
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
184 # could have been made None by the previous if
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
185 if cl is None:
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
186 cl = copy.copy(unfichangelog)
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
187 cl.filteredrevs = revs
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
188 object.__setattr__(self, '_clcache', cl)
4d92e2d75cff repoview: cache filtered changelog
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 18443
diff changeset
189 object.__setattr__(self, '_clcachekey', newkey)
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
190 return cl
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
191
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
192 def unfiltered(self):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
193 """Return an unfiltered version of a repo"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
194 return self._unfilteredrepo
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
195
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
196 def filtered(self, name):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
197 """Return a filtered version of a repository"""
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
198 if name == self.filtername:
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
199 return self
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
200 return self.unfiltered().filtered(name)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
201
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
202 # everything access are forwarded to the proxied repo
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
203 def __getattr__(self, attr):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
204 return getattr(self._unfilteredrepo, attr)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
205
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
206 def __setattr__(self, attr, value):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
207 return setattr(self._unfilteredrepo, attr, value)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
208
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
209 def __delattr__(self, attr):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
210 return delattr(self._unfilteredrepo, attr)
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
211
18644
3e92772d5383 spelling: fix some minor issues found by spell checker
Mads Kiilerich <mads@kiilerich.com>
parents: 18495
diff changeset
212 # The `requirements` attribute is initialized during __init__. But
18100
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
213 # __getattr__ won't be called as it also exists on the class. We need
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
214 # explicit forwarding to main repo here
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
215 @property
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
216 def requirements(self):
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
217 return self._unfilteredrepo.requirements
3a6ddacb7198 clfilter: add actual repo filtering mechanism
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents:
diff changeset
218