##// 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 1 # unionrepo.py - repository class for viewing union of repository changesets
2 2 #
3 3 # Derived from bundlerepo.py
4 4 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
5 5 # Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 """Repository class for "in-memory pull" of one local repository to another,
11 11 allowing operations like diff and log with revsets.
12 12 """
13 13
14 14 from __future__ import absolute_import
15 15
16 16 import os
17 17
18 18 from .i18n import _
19 19 from .node import nullid
20 20
21 21 from . import (
22 22 changelog,
23 23 cmdutil,
24 24 filelog,
25 25 localrepo,
26 26 manifest,
27 27 mdiff,
28 28 pathutil,
29 29 revlog,
30 30 scmutil,
31 31 util,
32 32 )
33 33
34 34 class unionrevlog(revlog.revlog):
35 35 def __init__(self, opener, indexfile, revlog2, linkmapper):
36 36 # How it works:
37 37 # To retrieve a revision, we just need to know the node id so we can
38 38 # look it up in revlog2.
39 39 #
40 40 # To differentiate a rev in the second revlog from a rev in the revlog,
41 41 # we check revision against repotiprev.
42 42 opener = scmutil.readonlyvfs(opener)
43 43 revlog.revlog.__init__(self, opener, indexfile)
44 44 self.revlog2 = revlog2
45 45
46 46 n = len(self)
47 47 self.repotiprev = n - 1
48 48 self.bundlerevs = set() # used by 'bundle()' revset expression
49 49 for rev2 in self.revlog2:
50 50 rev = self.revlog2.index[rev2]
51 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 54 if linkmapper is None: # link is to same revlog
55 55 assert linkrev == rev2 # we never link back
56 56 link = n
57 57 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
58 58 link = linkmapper(linkrev)
59 59
60 if linkmapper is not None: # link is to same revlog
61 base = linkmapper(base)
62
60 63 if node in self.nodemap:
61 64 # this happens for the common revlog revisions
62 65 self.bundlerevs.add(self.nodemap[node])
63 66 continue
64 67
65 68 p1node = self.revlog2.node(p1rev)
66 69 p2node = self.revlog2.node(p2rev)
67 70
68 e = (None, None, None, None,
71 e = (None, None, None, base,
69 72 link, self.rev(p1node), self.rev(p2node), node)
70 73 self.index.insert(-1, e)
71 74 self.nodemap[node] = n
72 75 self.bundlerevs.add(n)
73 76 n += 1
74 77
75 78 def _chunk(self, rev):
76 79 if rev <= self.repotiprev:
77 80 return revlog.revlog._chunk(self, rev)
78 81 return self.revlog2._chunk(self.node(rev))
79 82
80 83 def revdiff(self, rev1, rev2):
81 84 """return or calculate a delta between two revisions"""
82 85 if rev1 > self.repotiprev and rev2 > self.repotiprev:
83 86 return self.revlog2.revdiff(
84 87 self.revlog2.rev(self.node(rev1)),
85 88 self.revlog2.rev(self.node(rev2)))
86 89 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
87 90 return self.baserevdiff(rev1, rev2)
88 91
89 92 return mdiff.textdiff(self.revision(self.node(rev1)),
90 93 self.revision(self.node(rev2)))
91 94
92 95 def revision(self, nodeorrev):
93 96 """return an uncompressed revision of a given node or revision
94 97 number.
95 98 """
96 99 if isinstance(nodeorrev, int):
97 100 rev = nodeorrev
98 101 node = self.node(rev)
99 102 else:
100 103 node = nodeorrev
101 104 rev = self.rev(node)
102 105
103 106 if node == nullid:
104 107 return ""
105 108
106 109 if rev > self.repotiprev:
107 110 text = self.revlog2.revision(node)
108 111 self._cache = (node, rev, text)
109 112 else:
110 113 text = self.baserevision(rev)
111 114 # already cached
112 115 return text
113 116
114 117 def baserevision(self, nodeorrev):
115 118 # Revlog subclasses may override 'revision' method to modify format of
116 119 # content retrieved from revlog. To use unionrevlog with such class one
117 120 # needs to override 'baserevision' and make more specific call here.
118 121 return revlog.revlog.revision(self, nodeorrev)
119 122
120 123 def baserevdiff(self, rev1, rev2):
121 124 # Exists for the same purpose as baserevision.
122 125 return revlog.revlog.revdiff(self, rev1, rev2)
123 126
124 127 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
125 128 raise NotImplementedError
126 129 def addgroup(self, revs, linkmapper, transaction):
127 130 raise NotImplementedError
128 131 def strip(self, rev, minlink):
129 132 raise NotImplementedError
130 133 def checksize(self):
131 134 raise NotImplementedError
132 135
133 136 class unionchangelog(unionrevlog, changelog.changelog):
134 137 def __init__(self, opener, opener2):
135 138 changelog.changelog.__init__(self, opener)
136 139 linkmapper = None
137 140 changelog2 = changelog.changelog(opener2)
138 141 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
139 142 linkmapper)
140 143
141 144 def baserevision(self, nodeorrev):
142 145 # Although changelog doesn't override 'revision' method, some extensions
143 146 # may replace this class with another that does. Same story with
144 147 # manifest and filelog classes.
145 148 return changelog.changelog.revision(self, nodeorrev)
146 149
147 150 def baserevdiff(self, rev1, rev2):
148 151 return changelog.changelog.revdiff(self, rev1, rev2)
149 152
150 153 class unionmanifest(unionrevlog, manifest.manifest):
151 154 def __init__(self, opener, opener2, linkmapper):
152 155 manifest.manifest.__init__(self, opener)
153 156 manifest2 = manifest.manifest(opener2)
154 157 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
155 158 linkmapper)
156 159
157 160 def baserevision(self, nodeorrev):
158 161 return manifest.manifest.revision(self, nodeorrev)
159 162
160 163 def baserevdiff(self, rev1, rev2):
161 164 return manifest.manifest.revdiff(self, rev1, rev2)
162 165
163 166 class unionfilelog(unionrevlog, filelog.filelog):
164 167 def __init__(self, opener, path, opener2, linkmapper, repo):
165 168 filelog.filelog.__init__(self, opener, path)
166 169 filelog2 = filelog.filelog(opener2, path)
167 170 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
168 171 linkmapper)
169 172 self._repo = repo
170 173
171 174 def baserevision(self, nodeorrev):
172 175 return filelog.filelog.revision(self, nodeorrev)
173 176
174 177 def baserevdiff(self, rev1, rev2):
175 178 return filelog.filelog.revdiff(self, rev1, rev2)
176 179
177 180 def iscensored(self, rev):
178 181 """Check if a revision is censored."""
179 182 if rev <= self.repotiprev:
180 183 return filelog.filelog.iscensored(self, rev)
181 184 return self.revlog2.iscensored(rev)
182 185
183 186 class unionpeer(localrepo.localpeer):
184 187 def canpush(self):
185 188 return False
186 189
187 190 class unionrepository(localrepo.localrepository):
188 191 def __init__(self, ui, path, path2):
189 192 localrepo.localrepository.__init__(self, ui, path)
190 193 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
191 194
192 195 self._url = 'union:%s+%s' % (util.expandpath(path),
193 196 util.expandpath(path2))
194 197 self.repo2 = localrepo.localrepository(ui, path2)
195 198
196 199 @localrepo.unfilteredpropertycache
197 200 def changelog(self):
198 201 return unionchangelog(self.svfs, self.repo2.svfs)
199 202
200 203 def _clrev(self, rev2):
201 204 """map from repo2 changelog rev to temporary rev in self.changelog"""
202 205 node = self.repo2.changelog.node(rev2)
203 206 return self.changelog.rev(node)
204 207
205 208 @localrepo.unfilteredpropertycache
206 209 def manifest(self):
207 210 return unionmanifest(self.svfs, self.repo2.svfs,
208 211 self._clrev)
209 212
210 213 def url(self):
211 214 return self._url
212 215
213 216 def file(self, f):
214 217 return unionfilelog(self.svfs, f, self.repo2.svfs,
215 218 self._clrev, self)
216 219
217 220 def close(self):
218 221 self.repo2.close()
219 222
220 223 def cancopy(self):
221 224 return False
222 225
223 226 def peer(self):
224 227 return unionpeer(self)
225 228
226 229 def getcwd(self):
227 230 return os.getcwd() # always outside the repo
228 231
229 232 def instance(ui, path, create):
230 233 if create:
231 234 raise util.Abort(_('cannot create new union repository'))
232 235 parentpath = ui.config("bundle", "mainreporoot", "")
233 236 if not parentpath:
234 237 # try to find the correct path to the working directory repo
235 238 parentpath = cmdutil.findrepo(os.getcwd())
236 239 if parentpath is None:
237 240 parentpath = ''
238 241 if parentpath:
239 242 # Try to make the full path relative so we get a nice, short URL.
240 243 # In particular, we don't want temp dir names in test outputs.
241 244 cwd = os.getcwd()
242 245 if parentpath == cwd:
243 246 parentpath = ''
244 247 else:
245 248 cwd = pathutil.normasprefix(cwd)
246 249 if parentpath.startswith(cwd):
247 250 parentpath = parentpath[len(cwd):]
248 251 if path.startswith('union:'):
249 252 s = path.split(":", 1)[1].split("+", 1)
250 253 if len(s) == 1:
251 254 repopath, repopath2 = parentpath, s[0]
252 255 else:
253 256 repopath, repopath2 = s
254 257 else:
255 258 repopath, repopath2 = parentpath, path
256 259 return unionrepository(ui, repopath, repopath2)
General Comments 0
You need to be logged in to leave comments. Login now