##// END OF EJS Templates
unionrepo: use normal inheritance scheme to call revdiff
marmoute -
r43095:a61a8f78 default
parent child Browse files
Show More
@@ -1,271 +1,271 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 return self.baserevdiff(rev1, rev2)
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 115 def baserevdiff(self, rev1, rev2):
116 116 # Revlog subclasses may override 'revdiff' method to modify format of
117 117 # content retrieved from revlog. To use unionrevlog with such class one
118 118 # needs to override 'baserevdiff' and make more specific call here.
119 119 return revlog.revlog.revdiff(self, rev1, rev2)
120 120
121 121 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
122 122 raise NotImplementedError
123 123 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None,
124 124 maybemissingparents=False):
125 125 raise NotImplementedError
126 126 def strip(self, minlink, transaction):
127 127 raise NotImplementedError
128 128 def checksize(self):
129 129 raise NotImplementedError
130 130
131 131 class unionchangelog(unionrevlog, changelog.changelog):
132 132 def __init__(self, opener, opener2):
133 133 changelog.changelog.__init__(self, opener)
134 134 linkmapper = None
135 135 changelog2 = changelog.changelog(opener2)
136 136 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
137 137 linkmapper)
138 138
139 139 def baserevdiff(self, rev1, rev2):
140 140 # Although changelog doesn't override 'revdiff' method, some extensions
141 141 # may replace this class with another that does. Same story with
142 142 # manifest and filelog classes.
143 143 return changelog.changelog.revdiff(self, rev1, rev2)
144 144
145 145 class unionmanifest(unionrevlog, manifest.manifestrevlog):
146 146 def __init__(self, opener, opener2, linkmapper):
147 147 manifest.manifestrevlog.__init__(self, opener)
148 148 manifest2 = manifest.manifestrevlog(opener2)
149 149 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
150 150 linkmapper)
151 151
152 152 def baserevdiff(self, rev1, rev2):
153 153 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
154 154
155 155 class unionfilelog(filelog.filelog):
156 156 def __init__(self, opener, path, opener2, linkmapper, repo):
157 157 filelog.filelog.__init__(self, opener, path)
158 158 filelog2 = filelog.filelog(opener2, path)
159 159 self._revlog = unionrevlog(opener, self.indexfile,
160 160 filelog2._revlog, linkmapper)
161 161 self._repo = repo
162 162 self.repotiprev = self._revlog.repotiprev
163 163 self.revlog2 = self._revlog.revlog2
164 164
165 165 def baserevdiff(self, rev1, rev2):
166 166 return filelog.filelog.revdiff(self, rev1, rev2)
167 167
168 168 def iscensored(self, rev):
169 169 """Check if a revision is censored."""
170 170 if rev <= self.repotiprev:
171 171 return filelog.filelog.iscensored(self, rev)
172 172 node = self.node(rev)
173 173 return self.revlog2.iscensored(self.revlog2.rev(node))
174 174
175 175 class unionpeer(localrepo.localpeer):
176 176 def canpush(self):
177 177 return False
178 178
179 179 class unionrepository(object):
180 180 """Represents the union of data in 2 repositories.
181 181
182 182 Instances are not usable if constructed directly. Use ``instance()``
183 183 or ``makeunionrepository()`` to create a usable instance.
184 184 """
185 185 def __init__(self, repo2, url):
186 186 self.repo2 = repo2
187 187 self._url = url
188 188
189 189 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
190 190
191 191 @localrepo.unfilteredpropertycache
192 192 def changelog(self):
193 193 return unionchangelog(self.svfs, self.repo2.svfs)
194 194
195 195 @localrepo.unfilteredpropertycache
196 196 def manifestlog(self):
197 197 rootstore = unionmanifest(self.svfs, self.repo2.svfs,
198 198 self.unfiltered()._clrev)
199 199 return manifest.manifestlog(self.svfs, self, rootstore,
200 200 self.narrowmatch())
201 201
202 202 def _clrev(self, rev2):
203 203 """map from repo2 changelog rev to temporary rev in self.changelog"""
204 204 node = self.repo2.changelog.node(rev2)
205 205 return self.changelog.rev(node)
206 206
207 207 def url(self):
208 208 return self._url
209 209
210 210 def file(self, f):
211 211 return unionfilelog(self.svfs, f, self.repo2.svfs,
212 212 self.unfiltered()._clrev, self)
213 213
214 214 def close(self):
215 215 self.repo2.close()
216 216
217 217 def cancopy(self):
218 218 return False
219 219
220 220 def peer(self):
221 221 return unionpeer(self)
222 222
223 223 def getcwd(self):
224 224 return encoding.getcwd() # always outside the repo
225 225
226 226 def instance(ui, path, create, intents=None, createopts=None):
227 227 if create:
228 228 raise error.Abort(_('cannot create new union repository'))
229 229 parentpath = ui.config("bundle", "mainreporoot")
230 230 if not parentpath:
231 231 # try to find the correct path to the working directory repo
232 232 parentpath = cmdutil.findrepo(encoding.getcwd())
233 233 if parentpath is None:
234 234 parentpath = ''
235 235 if parentpath:
236 236 # Try to make the full path relative so we get a nice, short URL.
237 237 # In particular, we don't want temp dir names in test outputs.
238 238 cwd = encoding.getcwd()
239 239 if parentpath == cwd:
240 240 parentpath = ''
241 241 else:
242 242 cwd = pathutil.normasprefix(cwd)
243 243 if parentpath.startswith(cwd):
244 244 parentpath = parentpath[len(cwd):]
245 245 if path.startswith('union:'):
246 246 s = path.split(":", 1)[1].split("+", 1)
247 247 if len(s) == 1:
248 248 repopath, repopath2 = parentpath, s[0]
249 249 else:
250 250 repopath, repopath2 = s
251 251 else:
252 252 repopath, repopath2 = parentpath, path
253 253
254 254 return makeunionrepository(ui, repopath, repopath2)
255 255
256 256 def makeunionrepository(ui, repopath1, repopath2):
257 257 """Make a union repository object from 2 local repo paths."""
258 258 repo1 = localrepo.instance(ui, repopath1, create=False)
259 259 repo2 = localrepo.instance(ui, repopath2, create=False)
260 260
261 261 url = 'union:%s+%s' % (util.expandpath(repopath1),
262 262 util.expandpath(repopath2))
263 263
264 264 class derivedunionrepository(unionrepository, repo1.__class__):
265 265 pass
266 266
267 267 repo = repo1
268 268 repo.__class__ = derivedunionrepository
269 269 unionrepository.__init__(repo1, repo2, url)
270 270
271 271 return repo
General Comments 0
You need to be logged in to leave comments. Login now