##// END OF EJS Templates
unionrepo: get rid of `baserevision`...
marmoute -
r43093:62a39c86 default
parent child Browse files
Show More
@@ -1,284 +1,271 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 self.baserevdiff(rev1, rev2)
92 return self.baserevdiff(rev1, rev2)
93
93
94 return mdiff.textdiff(self.revision(rev1), self.revision(rev2))
94 return mdiff.textdiff(self.revision(rev1), self.revision(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 baserevision(self, nodeorrev):
115 def baserevdiff(self, rev1, rev2):
116 # Revlog subclasses may override 'revision' method to modify format of
116 # Revlog subclasses may override 'revdiff' method to modify format of
117 # content retrieved from revlog. To use unionrevlog with such class one
117 # content retrieved from revlog. To use unionrevlog with such class one
118 # needs to override 'baserevision' and make more specific call here.
118 # needs to override 'baserevdiff' and make more specific call here.
119 return revlog.revlog.revision(self, nodeorrev)
120
121 def baserevdiff(self, rev1, rev2):
122 # Exists for the same purpose as baserevision.
123 return revlog.revlog.revdiff(self, rev1, rev2)
119 return revlog.revlog.revdiff(self, rev1, rev2)
124
120
125 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
121 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
126 raise NotImplementedError
122 raise NotImplementedError
127 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None,
123 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None,
128 maybemissingparents=False):
124 maybemissingparents=False):
129 raise NotImplementedError
125 raise NotImplementedError
130 def strip(self, minlink, transaction):
126 def strip(self, minlink, transaction):
131 raise NotImplementedError
127 raise NotImplementedError
132 def checksize(self):
128 def checksize(self):
133 raise NotImplementedError
129 raise NotImplementedError
134
130
135 class unionchangelog(unionrevlog, changelog.changelog):
131 class unionchangelog(unionrevlog, changelog.changelog):
136 def __init__(self, opener, opener2):
132 def __init__(self, opener, opener2):
137 changelog.changelog.__init__(self, opener)
133 changelog.changelog.__init__(self, opener)
138 linkmapper = None
134 linkmapper = None
139 changelog2 = changelog.changelog(opener2)
135 changelog2 = changelog.changelog(opener2)
140 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
136 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
141 linkmapper)
137 linkmapper)
142
138
143 def baserevision(self, nodeorrev):
139 def baserevdiff(self, rev1, rev2):
144 # Although changelog doesn't override 'revision' method, some extensions
140 # Although changelog doesn't override 'revdiff' method, some extensions
145 # may replace this class with another that does. Same story with
141 # may replace this class with another that does. Same story with
146 # manifest and filelog classes.
142 # manifest and filelog classes.
147 return changelog.changelog.revision(self, nodeorrev)
148
149 def baserevdiff(self, rev1, rev2):
150 return changelog.changelog.revdiff(self, rev1, rev2)
143 return changelog.changelog.revdiff(self, rev1, rev2)
151
144
152 class unionmanifest(unionrevlog, manifest.manifestrevlog):
145 class unionmanifest(unionrevlog, manifest.manifestrevlog):
153 def __init__(self, opener, opener2, linkmapper):
146 def __init__(self, opener, opener2, linkmapper):
154 manifest.manifestrevlog.__init__(self, opener)
147 manifest.manifestrevlog.__init__(self, opener)
155 manifest2 = manifest.manifestrevlog(opener2)
148 manifest2 = manifest.manifestrevlog(opener2)
156 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
149 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
157 linkmapper)
150 linkmapper)
158
151
159 def baserevision(self, nodeorrev):
160 return manifest.manifestrevlog.revision(self, nodeorrev)
161
162 def baserevdiff(self, rev1, rev2):
152 def baserevdiff(self, rev1, rev2):
163 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
153 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
164
154
165 class unionfilelog(filelog.filelog):
155 class unionfilelog(filelog.filelog):
166 def __init__(self, opener, path, opener2, linkmapper, repo):
156 def __init__(self, opener, path, opener2, linkmapper, repo):
167 filelog.filelog.__init__(self, opener, path)
157 filelog.filelog.__init__(self, opener, path)
168 filelog2 = filelog.filelog(opener2, path)
158 filelog2 = filelog.filelog(opener2, path)
169 self._revlog = unionrevlog(opener, self.indexfile,
159 self._revlog = unionrevlog(opener, self.indexfile,
170 filelog2._revlog, linkmapper)
160 filelog2._revlog, linkmapper)
171 self._repo = repo
161 self._repo = repo
172 self.repotiprev = self._revlog.repotiprev
162 self.repotiprev = self._revlog.repotiprev
173 self.revlog2 = self._revlog.revlog2
163 self.revlog2 = self._revlog.revlog2
174
164
175 def baserevision(self, nodeorrev):
176 return filelog.filelog.revision(self, nodeorrev)
177
178 def baserevdiff(self, rev1, rev2):
165 def baserevdiff(self, rev1, rev2):
179 return filelog.filelog.revdiff(self, rev1, rev2)
166 return filelog.filelog.revdiff(self, rev1, rev2)
180
167
181 def iscensored(self, rev):
168 def iscensored(self, rev):
182 """Check if a revision is censored."""
169 """Check if a revision is censored."""
183 if rev <= self.repotiprev:
170 if rev <= self.repotiprev:
184 return filelog.filelog.iscensored(self, rev)
171 return filelog.filelog.iscensored(self, rev)
185 node = self.node(rev)
172 node = self.node(rev)
186 return self.revlog2.iscensored(self.revlog2.rev(node))
173 return self.revlog2.iscensored(self.revlog2.rev(node))
187
174
188 class unionpeer(localrepo.localpeer):
175 class unionpeer(localrepo.localpeer):
189 def canpush(self):
176 def canpush(self):
190 return False
177 return False
191
178
192 class unionrepository(object):
179 class unionrepository(object):
193 """Represents the union of data in 2 repositories.
180 """Represents the union of data in 2 repositories.
194
181
195 Instances are not usable if constructed directly. Use ``instance()``
182 Instances are not usable if constructed directly. Use ``instance()``
196 or ``makeunionrepository()`` to create a usable instance.
183 or ``makeunionrepository()`` to create a usable instance.
197 """
184 """
198 def __init__(self, repo2, url):
185 def __init__(self, repo2, url):
199 self.repo2 = repo2
186 self.repo2 = repo2
200 self._url = url
187 self._url = url
201
188
202 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
189 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
203
190
204 @localrepo.unfilteredpropertycache
191 @localrepo.unfilteredpropertycache
205 def changelog(self):
192 def changelog(self):
206 return unionchangelog(self.svfs, self.repo2.svfs)
193 return unionchangelog(self.svfs, self.repo2.svfs)
207
194
208 @localrepo.unfilteredpropertycache
195 @localrepo.unfilteredpropertycache
209 def manifestlog(self):
196 def manifestlog(self):
210 rootstore = unionmanifest(self.svfs, self.repo2.svfs,
197 rootstore = unionmanifest(self.svfs, self.repo2.svfs,
211 self.unfiltered()._clrev)
198 self.unfiltered()._clrev)
212 return manifest.manifestlog(self.svfs, self, rootstore,
199 return manifest.manifestlog(self.svfs, self, rootstore,
213 self.narrowmatch())
200 self.narrowmatch())
214
201
215 def _clrev(self, rev2):
202 def _clrev(self, rev2):
216 """map from repo2 changelog rev to temporary rev in self.changelog"""
203 """map from repo2 changelog rev to temporary rev in self.changelog"""
217 node = self.repo2.changelog.node(rev2)
204 node = self.repo2.changelog.node(rev2)
218 return self.changelog.rev(node)
205 return self.changelog.rev(node)
219
206
220 def url(self):
207 def url(self):
221 return self._url
208 return self._url
222
209
223 def file(self, f):
210 def file(self, f):
224 return unionfilelog(self.svfs, f, self.repo2.svfs,
211 return unionfilelog(self.svfs, f, self.repo2.svfs,
225 self.unfiltered()._clrev, self)
212 self.unfiltered()._clrev, self)
226
213
227 def close(self):
214 def close(self):
228 self.repo2.close()
215 self.repo2.close()
229
216
230 def cancopy(self):
217 def cancopy(self):
231 return False
218 return False
232
219
233 def peer(self):
220 def peer(self):
234 return unionpeer(self)
221 return unionpeer(self)
235
222
236 def getcwd(self):
223 def getcwd(self):
237 return encoding.getcwd() # always outside the repo
224 return encoding.getcwd() # always outside the repo
238
225
239 def instance(ui, path, create, intents=None, createopts=None):
226 def instance(ui, path, create, intents=None, createopts=None):
240 if create:
227 if create:
241 raise error.Abort(_('cannot create new union repository'))
228 raise error.Abort(_('cannot create new union repository'))
242 parentpath = ui.config("bundle", "mainreporoot")
229 parentpath = ui.config("bundle", "mainreporoot")
243 if not parentpath:
230 if not parentpath:
244 # try to find the correct path to the working directory repo
231 # try to find the correct path to the working directory repo
245 parentpath = cmdutil.findrepo(encoding.getcwd())
232 parentpath = cmdutil.findrepo(encoding.getcwd())
246 if parentpath is None:
233 if parentpath is None:
247 parentpath = ''
234 parentpath = ''
248 if parentpath:
235 if parentpath:
249 # Try to make the full path relative so we get a nice, short URL.
236 # Try to make the full path relative so we get a nice, short URL.
250 # In particular, we don't want temp dir names in test outputs.
237 # In particular, we don't want temp dir names in test outputs.
251 cwd = encoding.getcwd()
238 cwd = encoding.getcwd()
252 if parentpath == cwd:
239 if parentpath == cwd:
253 parentpath = ''
240 parentpath = ''
254 else:
241 else:
255 cwd = pathutil.normasprefix(cwd)
242 cwd = pathutil.normasprefix(cwd)
256 if parentpath.startswith(cwd):
243 if parentpath.startswith(cwd):
257 parentpath = parentpath[len(cwd):]
244 parentpath = parentpath[len(cwd):]
258 if path.startswith('union:'):
245 if path.startswith('union:'):
259 s = path.split(":", 1)[1].split("+", 1)
246 s = path.split(":", 1)[1].split("+", 1)
260 if len(s) == 1:
247 if len(s) == 1:
261 repopath, repopath2 = parentpath, s[0]
248 repopath, repopath2 = parentpath, s[0]
262 else:
249 else:
263 repopath, repopath2 = s
250 repopath, repopath2 = s
264 else:
251 else:
265 repopath, repopath2 = parentpath, path
252 repopath, repopath2 = parentpath, path
266
253
267 return makeunionrepository(ui, repopath, repopath2)
254 return makeunionrepository(ui, repopath, repopath2)
268
255
269 def makeunionrepository(ui, repopath1, repopath2):
256 def makeunionrepository(ui, repopath1, repopath2):
270 """Make a union repository object from 2 local repo paths."""
257 """Make a union repository object from 2 local repo paths."""
271 repo1 = localrepo.instance(ui, repopath1, create=False)
258 repo1 = localrepo.instance(ui, repopath1, create=False)
272 repo2 = localrepo.instance(ui, repopath2, create=False)
259 repo2 = localrepo.instance(ui, repopath2, create=False)
273
260
274 url = 'union:%s+%s' % (util.expandpath(repopath1),
261 url = 'union:%s+%s' % (util.expandpath(repopath1),
275 util.expandpath(repopath2))
262 util.expandpath(repopath2))
276
263
277 class derivedunionrepository(unionrepository, repo1.__class__):
264 class derivedunionrepository(unionrepository, repo1.__class__):
278 pass
265 pass
279
266
280 repo = repo1
267 repo = repo1
281 repo.__class__ = derivedunionrepository
268 repo.__class__ = derivedunionrepository
282 unionrepository.__init__(repo1, repo2, url)
269 unionrepository.__init__(repo1, repo2, url)
283
270
284 return repo
271 return repo
General Comments 0
You need to be logged in to leave comments. Login now