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