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