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