##// END OF EJS Templates
unionrepo: drop `baserevdiff`...
marmoute -
r43096:f8b5da99 default
parent child Browse files
Show More
@@ -1,271 +1,253 b''
1 1 # unionrepo.py - repository class for viewing union of repository changesets
2 2 #
3 3 # Derived from bundlerepo.py
4 4 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
5 5 # Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 """Repository class for "in-memory pull" of one local repository to another,
11 11 allowing operations like diff and log with revsets.
12 12 """
13 13
14 14 from __future__ import absolute_import
15 15
16 16 from .i18n import _
17 17
18 18 from . import (
19 19 changelog,
20 20 cmdutil,
21 21 encoding,
22 22 error,
23 23 filelog,
24 24 localrepo,
25 25 manifest,
26 26 mdiff,
27 27 pathutil,
28 28 revlog,
29 29 util,
30 30 vfs as vfsmod,
31 31 )
32 32
33 33 class unionrevlog(revlog.revlog):
34 34 def __init__(self, opener, indexfile, revlog2, linkmapper):
35 35 # How it works:
36 36 # To retrieve a revision, we just need to know the node id so we can
37 37 # look it up in revlog2.
38 38 #
39 39 # To differentiate a rev in the second revlog from a rev in the revlog,
40 40 # we check revision against repotiprev.
41 41 opener = vfsmod.readonlyvfs(opener)
42 42 revlog.revlog.__init__(self, opener, indexfile)
43 43 self.revlog2 = revlog2
44 44
45 45 n = len(self)
46 46 self.repotiprev = n - 1
47 47 self.bundlerevs = set() # used by 'bundle()' revset expression
48 48 for rev2 in self.revlog2:
49 49 rev = self.revlog2.index[rev2]
50 50 # rev numbers - in revlog2, very different from self.rev
51 51 _start, _csize, rsize, base, linkrev, p1rev, p2rev, node = rev
52 52 flags = _start & 0xFFFF
53 53
54 54 if linkmapper is None: # link is to same revlog
55 55 assert linkrev == rev2 # we never link back
56 56 link = n
57 57 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
58 58 link = linkmapper(linkrev)
59 59
60 60 if linkmapper is not None: # link is to same revlog
61 61 base = linkmapper(base)
62 62
63 63 if node in self.nodemap:
64 64 # this happens for the common revlog revisions
65 65 self.bundlerevs.add(self.nodemap[node])
66 66 continue
67 67
68 68 p1node = self.revlog2.node(p1rev)
69 69 p2node = self.revlog2.node(p2rev)
70 70
71 71 # TODO: it's probably wrong to set compressed length to None, but
72 72 # I have no idea if csize is valid in the base revlog context.
73 73 e = (flags, None, rsize, base,
74 74 link, self.rev(p1node), self.rev(p2node), node)
75 75 self.index.append(e)
76 76 self.nodemap[node] = n
77 77 self.bundlerevs.add(n)
78 78 n += 1
79 79
80 80 def _chunk(self, rev):
81 81 if rev <= self.repotiprev:
82 82 return revlog.revlog._chunk(self, rev)
83 83 return self.revlog2._chunk(self.node(rev))
84 84
85 85 def revdiff(self, rev1, rev2):
86 86 """return or calculate a delta between two revisions"""
87 87 if rev1 > self.repotiprev and rev2 > self.repotiprev:
88 88 return self.revlog2.revdiff(
89 89 self.revlog2.rev(self.node(rev1)),
90 90 self.revlog2.rev(self.node(rev2)))
91 91 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
92 92 return super(unionrevlog, self).revdiff(rev1, rev2)
93 93
94 94 return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
95 95
96 96 def _revisiondata(self, nodeorrev, _df=None, raw=False):
97 97 if isinstance(nodeorrev, int):
98 98 rev = nodeorrev
99 99 node = self.node(rev)
100 100 else:
101 101 node = nodeorrev
102 102 rev = self.rev(node)
103 103
104 104 if rev > self.repotiprev:
105 105 # work around manifestrevlog NOT being a revlog
106 106 revlog2 = getattr(self.revlog2, '_revlog', self.revlog2)
107 107 func = revlog2._revisiondata
108 108 else:
109 109 func = super(unionrevlog, self)._revisiondata
110 110 return func(node, _df=_df, raw=raw)
111 111
112 112 def rawdata(self, nodeorrev, _df=None):
113 113 return self.revision(nodeorrev, _df=_df, raw=True)
114 114
115 def baserevdiff(self, rev1, rev2):
116 # Revlog subclasses may override 'revdiff' method to modify format of
117 # content retrieved from revlog. To use unionrevlog with such class one
118 # needs to override 'baserevdiff' and make more specific call here.
119 return revlog.revlog.revdiff(self, rev1, rev2)
120
121 115 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
122 116 raise NotImplementedError
123 117 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None,
124 118 maybemissingparents=False):
125 119 raise NotImplementedError
126 120 def strip(self, minlink, transaction):
127 121 raise NotImplementedError
128 122 def checksize(self):
129 123 raise NotImplementedError
130 124
131 125 class unionchangelog(unionrevlog, changelog.changelog):
132 126 def __init__(self, opener, opener2):
133 127 changelog.changelog.__init__(self, opener)
134 128 linkmapper = None
135 129 changelog2 = changelog.changelog(opener2)
136 130 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
137 131 linkmapper)
138 132
139 def baserevdiff(self, rev1, rev2):
140 # Although changelog doesn't override 'revdiff' method, some extensions
141 # may replace this class with another that does. Same story with
142 # manifest and filelog classes.
143 return changelog.changelog.revdiff(self, rev1, rev2)
144
145 133 class unionmanifest(unionrevlog, manifest.manifestrevlog):
146 134 def __init__(self, opener, opener2, linkmapper):
147 135 manifest.manifestrevlog.__init__(self, opener)
148 136 manifest2 = manifest.manifestrevlog(opener2)
149 137 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
150 138 linkmapper)
151 139
152 def baserevdiff(self, rev1, rev2):
153 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
154
155 140 class unionfilelog(filelog.filelog):
156 141 def __init__(self, opener, path, opener2, linkmapper, repo):
157 142 filelog.filelog.__init__(self, opener, path)
158 143 filelog2 = filelog.filelog(opener2, path)
159 144 self._revlog = unionrevlog(opener, self.indexfile,
160 145 filelog2._revlog, linkmapper)
161 146 self._repo = repo
162 147 self.repotiprev = self._revlog.repotiprev
163 148 self.revlog2 = self._revlog.revlog2
164 149
165 def baserevdiff(self, rev1, rev2):
166 return filelog.filelog.revdiff(self, rev1, rev2)
167
168 150 def iscensored(self, rev):
169 151 """Check if a revision is censored."""
170 152 if rev <= self.repotiprev:
171 153 return filelog.filelog.iscensored(self, rev)
172 154 node = self.node(rev)
173 155 return self.revlog2.iscensored(self.revlog2.rev(node))
174 156
175 157 class unionpeer(localrepo.localpeer):
176 158 def canpush(self):
177 159 return False
178 160
179 161 class unionrepository(object):
180 162 """Represents the union of data in 2 repositories.
181 163
182 164 Instances are not usable if constructed directly. Use ``instance()``
183 165 or ``makeunionrepository()`` to create a usable instance.
184 166 """
185 167 def __init__(self, repo2, url):
186 168 self.repo2 = repo2
187 169 self._url = url
188 170
189 171 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
190 172
191 173 @localrepo.unfilteredpropertycache
192 174 def changelog(self):
193 175 return unionchangelog(self.svfs, self.repo2.svfs)
194 176
195 177 @localrepo.unfilteredpropertycache
196 178 def manifestlog(self):
197 179 rootstore = unionmanifest(self.svfs, self.repo2.svfs,
198 180 self.unfiltered()._clrev)
199 181 return manifest.manifestlog(self.svfs, self, rootstore,
200 182 self.narrowmatch())
201 183
202 184 def _clrev(self, rev2):
203 185 """map from repo2 changelog rev to temporary rev in self.changelog"""
204 186 node = self.repo2.changelog.node(rev2)
205 187 return self.changelog.rev(node)
206 188
207 189 def url(self):
208 190 return self._url
209 191
210 192 def file(self, f):
211 193 return unionfilelog(self.svfs, f, self.repo2.svfs,
212 194 self.unfiltered()._clrev, self)
213 195
214 196 def close(self):
215 197 self.repo2.close()
216 198
217 199 def cancopy(self):
218 200 return False
219 201
220 202 def peer(self):
221 203 return unionpeer(self)
222 204
223 205 def getcwd(self):
224 206 return encoding.getcwd() # always outside the repo
225 207
226 208 def instance(ui, path, create, intents=None, createopts=None):
227 209 if create:
228 210 raise error.Abort(_('cannot create new union repository'))
229 211 parentpath = ui.config("bundle", "mainreporoot")
230 212 if not parentpath:
231 213 # try to find the correct path to the working directory repo
232 214 parentpath = cmdutil.findrepo(encoding.getcwd())
233 215 if parentpath is None:
234 216 parentpath = ''
235 217 if parentpath:
236 218 # Try to make the full path relative so we get a nice, short URL.
237 219 # In particular, we don't want temp dir names in test outputs.
238 220 cwd = encoding.getcwd()
239 221 if parentpath == cwd:
240 222 parentpath = ''
241 223 else:
242 224 cwd = pathutil.normasprefix(cwd)
243 225 if parentpath.startswith(cwd):
244 226 parentpath = parentpath[len(cwd):]
245 227 if path.startswith('union:'):
246 228 s = path.split(":", 1)[1].split("+", 1)
247 229 if len(s) == 1:
248 230 repopath, repopath2 = parentpath, s[0]
249 231 else:
250 232 repopath, repopath2 = s
251 233 else:
252 234 repopath, repopath2 = parentpath, path
253 235
254 236 return makeunionrepository(ui, repopath, repopath2)
255 237
256 238 def makeunionrepository(ui, repopath1, repopath2):
257 239 """Make a union repository object from 2 local repo paths."""
258 240 repo1 = localrepo.instance(ui, repopath1, create=False)
259 241 repo2 = localrepo.instance(ui, repopath2, create=False)
260 242
261 243 url = 'union:%s+%s' % (util.expandpath(repopath1),
262 244 util.expandpath(repopath2))
263 245
264 246 class derivedunionrepository(unionrepository, repo1.__class__):
265 247 pass
266 248
267 249 repo = repo1
268 250 repo.__class__ = derivedunionrepository
269 251 unionrepository.__init__(repo1, repo2, url)
270 252
271 253 return repo
General Comments 0
You need to be logged in to leave comments. Login now