##// END OF EJS Templates
unionrepo: fill in uncompressed length of revlog entry...
Yuya Nishihara -
r38194:df5f6881 default
parent child Browse files
Show More
@@ -1,261 +1,263 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 error,
22 error,
23 filelog,
23 filelog,
24 localrepo,
24 localrepo,
25 manifest,
25 manifest,
26 mdiff,
26 mdiff,
27 pathutil,
27 pathutil,
28 pycompat,
28 pycompat,
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 e = (flags, None, None, base,
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.
74 e = (flags, None, rsize, base,
73 link, self.rev(p1node), self.rev(p2node), node)
75 link, self.rev(p1node), self.rev(p2node), node)
74 self.index.insert(-1, e)
76 self.index.insert(-1, e)
75 self.nodemap[node] = n
77 self.nodemap[node] = n
76 self.bundlerevs.add(n)
78 self.bundlerevs.add(n)
77 n += 1
79 n += 1
78
80
79 def _chunk(self, rev):
81 def _chunk(self, rev):
80 if rev <= self.repotiprev:
82 if rev <= self.repotiprev:
81 return revlog.revlog._chunk(self, rev)
83 return revlog.revlog._chunk(self, rev)
82 return self.revlog2._chunk(self.node(rev))
84 return self.revlog2._chunk(self.node(rev))
83
85
84 def revdiff(self, rev1, rev2):
86 def revdiff(self, rev1, rev2):
85 """return or calculate a delta between two revisions"""
87 """return or calculate a delta between two revisions"""
86 if rev1 > self.repotiprev and rev2 > self.repotiprev:
88 if rev1 > self.repotiprev and rev2 > self.repotiprev:
87 return self.revlog2.revdiff(
89 return self.revlog2.revdiff(
88 self.revlog2.rev(self.node(rev1)),
90 self.revlog2.rev(self.node(rev1)),
89 self.revlog2.rev(self.node(rev2)))
91 self.revlog2.rev(self.node(rev2)))
90 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
92 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
91 return self.baserevdiff(rev1, rev2)
93 return self.baserevdiff(rev1, rev2)
92
94
93 return mdiff.textdiff(self.revision(rev1), self.revision(rev2))
95 return mdiff.textdiff(self.revision(rev1), self.revision(rev2))
94
96
95 def revision(self, nodeorrev, _df=None, raw=False):
97 def revision(self, nodeorrev, _df=None, raw=False):
96 """return an uncompressed revision of a given node or revision
98 """return an uncompressed revision of a given node or revision
97 number.
99 number.
98 """
100 """
99 if isinstance(nodeorrev, int):
101 if isinstance(nodeorrev, int):
100 rev = nodeorrev
102 rev = nodeorrev
101 node = self.node(rev)
103 node = self.node(rev)
102 else:
104 else:
103 node = nodeorrev
105 node = nodeorrev
104 rev = self.rev(node)
106 rev = self.rev(node)
105
107
106 if node == nullid:
108 if node == nullid:
107 return ""
109 return ""
108
110
109 if rev > self.repotiprev:
111 if rev > self.repotiprev:
110 text = self.revlog2.revision(node)
112 text = self.revlog2.revision(node)
111 self._cache = (node, rev, text)
113 self._cache = (node, rev, text)
112 else:
114 else:
113 text = self.baserevision(rev)
115 text = self.baserevision(rev)
114 # already cached
116 # already cached
115 return text
117 return text
116
118
117 def baserevision(self, nodeorrev):
119 def baserevision(self, nodeorrev):
118 # Revlog subclasses may override 'revision' method to modify format of
120 # Revlog subclasses may override 'revision' method to modify format of
119 # content retrieved from revlog. To use unionrevlog with such class one
121 # content retrieved from revlog. To use unionrevlog with such class one
120 # needs to override 'baserevision' and make more specific call here.
122 # needs to override 'baserevision' and make more specific call here.
121 return revlog.revlog.revision(self, nodeorrev)
123 return revlog.revlog.revision(self, nodeorrev)
122
124
123 def baserevdiff(self, rev1, rev2):
125 def baserevdiff(self, rev1, rev2):
124 # Exists for the same purpose as baserevision.
126 # Exists for the same purpose as baserevision.
125 return revlog.revlog.revdiff(self, rev1, rev2)
127 return revlog.revlog.revdiff(self, rev1, rev2)
126
128
127 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
129 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
128 raise NotImplementedError
130 raise NotImplementedError
129 def addgroup(self, deltas, transaction, addrevisioncb=None):
131 def addgroup(self, deltas, transaction, addrevisioncb=None):
130 raise NotImplementedError
132 raise NotImplementedError
131 def strip(self, rev, minlink):
133 def strip(self, rev, minlink):
132 raise NotImplementedError
134 raise NotImplementedError
133 def checksize(self):
135 def checksize(self):
134 raise NotImplementedError
136 raise NotImplementedError
135
137
136 class unionchangelog(unionrevlog, changelog.changelog):
138 class unionchangelog(unionrevlog, changelog.changelog):
137 def __init__(self, opener, opener2):
139 def __init__(self, opener, opener2):
138 changelog.changelog.__init__(self, opener)
140 changelog.changelog.__init__(self, opener)
139 linkmapper = None
141 linkmapper = None
140 changelog2 = changelog.changelog(opener2)
142 changelog2 = changelog.changelog(opener2)
141 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
143 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
142 linkmapper)
144 linkmapper)
143
145
144 def baserevision(self, nodeorrev):
146 def baserevision(self, nodeorrev):
145 # Although changelog doesn't override 'revision' method, some extensions
147 # Although changelog doesn't override 'revision' method, some extensions
146 # may replace this class with another that does. Same story with
148 # may replace this class with another that does. Same story with
147 # manifest and filelog classes.
149 # manifest and filelog classes.
148 return changelog.changelog.revision(self, nodeorrev)
150 return changelog.changelog.revision(self, nodeorrev)
149
151
150 def baserevdiff(self, rev1, rev2):
152 def baserevdiff(self, rev1, rev2):
151 return changelog.changelog.revdiff(self, rev1, rev2)
153 return changelog.changelog.revdiff(self, rev1, rev2)
152
154
153 class unionmanifest(unionrevlog, manifest.manifestrevlog):
155 class unionmanifest(unionrevlog, manifest.manifestrevlog):
154 def __init__(self, opener, opener2, linkmapper):
156 def __init__(self, opener, opener2, linkmapper):
155 manifest.manifestrevlog.__init__(self, opener)
157 manifest.manifestrevlog.__init__(self, opener)
156 manifest2 = manifest.manifestrevlog(opener2)
158 manifest2 = manifest.manifestrevlog(opener2)
157 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
159 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
158 linkmapper)
160 linkmapper)
159
161
160 def baserevision(self, nodeorrev):
162 def baserevision(self, nodeorrev):
161 return manifest.manifestrevlog.revision(self, nodeorrev)
163 return manifest.manifestrevlog.revision(self, nodeorrev)
162
164
163 def baserevdiff(self, rev1, rev2):
165 def baserevdiff(self, rev1, rev2):
164 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
166 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
165
167
166 class unionfilelog(filelog.filelog):
168 class unionfilelog(filelog.filelog):
167 def __init__(self, opener, path, opener2, linkmapper, repo):
169 def __init__(self, opener, path, opener2, linkmapper, repo):
168 filelog.filelog.__init__(self, opener, path)
170 filelog.filelog.__init__(self, opener, path)
169 filelog2 = filelog.filelog(opener2, path)
171 filelog2 = filelog.filelog(opener2, path)
170 self._revlog = unionrevlog(opener, self.indexfile,
172 self._revlog = unionrevlog(opener, self.indexfile,
171 filelog2._revlog, linkmapper)
173 filelog2._revlog, linkmapper)
172 self._repo = repo
174 self._repo = repo
173 self.repotiprev = self._revlog.repotiprev
175 self.repotiprev = self._revlog.repotiprev
174 self.revlog2 = self._revlog.revlog2
176 self.revlog2 = self._revlog.revlog2
175
177
176 def baserevision(self, nodeorrev):
178 def baserevision(self, nodeorrev):
177 return filelog.filelog.revision(self, nodeorrev)
179 return filelog.filelog.revision(self, nodeorrev)
178
180
179 def baserevdiff(self, rev1, rev2):
181 def baserevdiff(self, rev1, rev2):
180 return filelog.filelog.revdiff(self, rev1, rev2)
182 return filelog.filelog.revdiff(self, rev1, rev2)
181
183
182 def iscensored(self, rev):
184 def iscensored(self, rev):
183 """Check if a revision is censored."""
185 """Check if a revision is censored."""
184 if rev <= self.repotiprev:
186 if rev <= self.repotiprev:
185 return filelog.filelog.iscensored(self, rev)
187 return filelog.filelog.iscensored(self, rev)
186 node = self.node(rev)
188 node = self.node(rev)
187 return self.revlog2.iscensored(self.revlog2.rev(node))
189 return self.revlog2.iscensored(self.revlog2.rev(node))
188
190
189 class unionpeer(localrepo.localpeer):
191 class unionpeer(localrepo.localpeer):
190 def canpush(self):
192 def canpush(self):
191 return False
193 return False
192
194
193 class unionrepository(localrepo.localrepository):
195 class unionrepository(localrepo.localrepository):
194 def __init__(self, ui, path, path2):
196 def __init__(self, ui, path, path2):
195 localrepo.localrepository.__init__(self, ui, path)
197 localrepo.localrepository.__init__(self, ui, path)
196 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
198 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
197
199
198 self._url = 'union:%s+%s' % (util.expandpath(path),
200 self._url = 'union:%s+%s' % (util.expandpath(path),
199 util.expandpath(path2))
201 util.expandpath(path2))
200 self.repo2 = localrepo.localrepository(ui, path2)
202 self.repo2 = localrepo.localrepository(ui, path2)
201
203
202 @localrepo.unfilteredpropertycache
204 @localrepo.unfilteredpropertycache
203 def changelog(self):
205 def changelog(self):
204 return unionchangelog(self.svfs, self.repo2.svfs)
206 return unionchangelog(self.svfs, self.repo2.svfs)
205
207
206 def _clrev(self, rev2):
208 def _clrev(self, rev2):
207 """map from repo2 changelog rev to temporary rev in self.changelog"""
209 """map from repo2 changelog rev to temporary rev in self.changelog"""
208 node = self.repo2.changelog.node(rev2)
210 node = self.repo2.changelog.node(rev2)
209 return self.changelog.rev(node)
211 return self.changelog.rev(node)
210
212
211 def _constructmanifest(self):
213 def _constructmanifest(self):
212 return unionmanifest(self.svfs, self.repo2.svfs,
214 return unionmanifest(self.svfs, self.repo2.svfs,
213 self.unfiltered()._clrev)
215 self.unfiltered()._clrev)
214
216
215 def url(self):
217 def url(self):
216 return self._url
218 return self._url
217
219
218 def file(self, f):
220 def file(self, f):
219 return unionfilelog(self.svfs, f, self.repo2.svfs,
221 return unionfilelog(self.svfs, f, self.repo2.svfs,
220 self.unfiltered()._clrev, self)
222 self.unfiltered()._clrev, self)
221
223
222 def close(self):
224 def close(self):
223 self.repo2.close()
225 self.repo2.close()
224
226
225 def cancopy(self):
227 def cancopy(self):
226 return False
228 return False
227
229
228 def peer(self):
230 def peer(self):
229 return unionpeer(self)
231 return unionpeer(self)
230
232
231 def getcwd(self):
233 def getcwd(self):
232 return pycompat.getcwd() # always outside the repo
234 return pycompat.getcwd() # always outside the repo
233
235
234 def instance(ui, path, create, intents=None):
236 def instance(ui, path, create, intents=None):
235 if create:
237 if create:
236 raise error.Abort(_('cannot create new union repository'))
238 raise error.Abort(_('cannot create new union repository'))
237 parentpath = ui.config("bundle", "mainreporoot")
239 parentpath = ui.config("bundle", "mainreporoot")
238 if not parentpath:
240 if not parentpath:
239 # try to find the correct path to the working directory repo
241 # try to find the correct path to the working directory repo
240 parentpath = cmdutil.findrepo(pycompat.getcwd())
242 parentpath = cmdutil.findrepo(pycompat.getcwd())
241 if parentpath is None:
243 if parentpath is None:
242 parentpath = ''
244 parentpath = ''
243 if parentpath:
245 if parentpath:
244 # Try to make the full path relative so we get a nice, short URL.
246 # Try to make the full path relative so we get a nice, short URL.
245 # In particular, we don't want temp dir names in test outputs.
247 # In particular, we don't want temp dir names in test outputs.
246 cwd = pycompat.getcwd()
248 cwd = pycompat.getcwd()
247 if parentpath == cwd:
249 if parentpath == cwd:
248 parentpath = ''
250 parentpath = ''
249 else:
251 else:
250 cwd = pathutil.normasprefix(cwd)
252 cwd = pathutil.normasprefix(cwd)
251 if parentpath.startswith(cwd):
253 if parentpath.startswith(cwd):
252 parentpath = parentpath[len(cwd):]
254 parentpath = parentpath[len(cwd):]
253 if path.startswith('union:'):
255 if path.startswith('union:'):
254 s = path.split(":", 1)[1].split("+", 1)
256 s = path.split(":", 1)[1].split("+", 1)
255 if len(s) == 1:
257 if len(s) == 1:
256 repopath, repopath2 = parentpath, s[0]
258 repopath, repopath2 = parentpath, s[0]
257 else:
259 else:
258 repopath, repopath2 = s
260 repopath, repopath2 = s
259 else:
261 else:
260 repopath, repopath2 = parentpath, path
262 repopath, repopath2 = parentpath, path
261 return unionrepository(ui, repopath, repopath2)
263 return unionrepository(ui, repopath, repopath2)
General Comments 0
You need to be logged in to leave comments. Login now