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