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