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