##// END OF EJS Templates
revlog: update signature of dummy addgroup() in bundlerepo and unionrepo...
Yuya Nishihara -
r34216:21fc747e default
parent child Browse files
Show More
@@ -1,563 +1,563 b''
1 # bundlerepo.py - repository class for viewing uncompressed bundles
1 # bundlerepo.py - repository class for viewing uncompressed bundles
2 #
2 #
3 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
3 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """Repository class for viewing uncompressed bundles.
8 """Repository class for viewing uncompressed bundles.
9
9
10 This provides a read-only repository interface to bundles as if they
10 This provides a read-only repository interface to bundles as if they
11 were part of the actual repository.
11 were part of the actual repository.
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 import shutil
17 import shutil
18 import tempfile
18 import tempfile
19
19
20 from .i18n import _
20 from .i18n import _
21 from .node import nullid
21 from .node import nullid
22
22
23 from . import (
23 from . import (
24 bundle2,
24 bundle2,
25 changegroup,
25 changegroup,
26 changelog,
26 changelog,
27 cmdutil,
27 cmdutil,
28 discovery,
28 discovery,
29 error,
29 error,
30 exchange,
30 exchange,
31 filelog,
31 filelog,
32 localrepo,
32 localrepo,
33 manifest,
33 manifest,
34 mdiff,
34 mdiff,
35 node as nodemod,
35 node as nodemod,
36 pathutil,
36 pathutil,
37 phases,
37 phases,
38 pycompat,
38 pycompat,
39 revlog,
39 revlog,
40 util,
40 util,
41 vfs as vfsmod,
41 vfs as vfsmod,
42 )
42 )
43
43
44 class bundlerevlog(revlog.revlog):
44 class bundlerevlog(revlog.revlog):
45 def __init__(self, opener, indexfile, bundle, linkmapper):
45 def __init__(self, opener, indexfile, bundle, linkmapper):
46 # How it works:
46 # How it works:
47 # To retrieve a revision, we need to know the offset of the revision in
47 # To retrieve a revision, we need to know the offset of the revision in
48 # the bundle (an unbundle object). We store this offset in the index
48 # the bundle (an unbundle object). We store this offset in the index
49 # (start). The base of the delta is stored in the base field.
49 # (start). The base of the delta is stored in the base field.
50 #
50 #
51 # To differentiate a rev in the bundle from a rev in the revlog, we
51 # To differentiate a rev in the bundle from a rev in the revlog, we
52 # check revision against repotiprev.
52 # check revision against repotiprev.
53 opener = vfsmod.readonlyvfs(opener)
53 opener = vfsmod.readonlyvfs(opener)
54 revlog.revlog.__init__(self, opener, indexfile)
54 revlog.revlog.__init__(self, opener, indexfile)
55 self.bundle = bundle
55 self.bundle = bundle
56 n = len(self)
56 n = len(self)
57 self.repotiprev = n - 1
57 self.repotiprev = n - 1
58 chain = None
58 chain = None
59 self.bundlerevs = set() # used by 'bundle()' revset expression
59 self.bundlerevs = set() # used by 'bundle()' revset expression
60 getchunk = lambda: bundle.deltachunk(chain)
60 getchunk = lambda: bundle.deltachunk(chain)
61 for chunkdata in iter(getchunk, {}):
61 for chunkdata in iter(getchunk, {}):
62 node = chunkdata['node']
62 node = chunkdata['node']
63 p1 = chunkdata['p1']
63 p1 = chunkdata['p1']
64 p2 = chunkdata['p2']
64 p2 = chunkdata['p2']
65 cs = chunkdata['cs']
65 cs = chunkdata['cs']
66 deltabase = chunkdata['deltabase']
66 deltabase = chunkdata['deltabase']
67 delta = chunkdata['delta']
67 delta = chunkdata['delta']
68 flags = chunkdata['flags']
68 flags = chunkdata['flags']
69
69
70 size = len(delta)
70 size = len(delta)
71 start = bundle.tell() - size
71 start = bundle.tell() - size
72
72
73 link = linkmapper(cs)
73 link = linkmapper(cs)
74 if node in self.nodemap:
74 if node in self.nodemap:
75 # this can happen if two branches make the same change
75 # this can happen if two branches make the same change
76 chain = node
76 chain = node
77 self.bundlerevs.add(self.nodemap[node])
77 self.bundlerevs.add(self.nodemap[node])
78 continue
78 continue
79
79
80 for p in (p1, p2):
80 for p in (p1, p2):
81 if p not in self.nodemap:
81 if p not in self.nodemap:
82 raise error.LookupError(p, self.indexfile,
82 raise error.LookupError(p, self.indexfile,
83 _("unknown parent"))
83 _("unknown parent"))
84
84
85 if deltabase not in self.nodemap:
85 if deltabase not in self.nodemap:
86 raise LookupError(deltabase, self.indexfile,
86 raise LookupError(deltabase, self.indexfile,
87 _('unknown delta base'))
87 _('unknown delta base'))
88
88
89 baserev = self.rev(deltabase)
89 baserev = self.rev(deltabase)
90 # start, size, full unc. size, base (unused), link, p1, p2, node
90 # start, size, full unc. size, base (unused), link, p1, p2, node
91 e = (revlog.offset_type(start, flags), size, -1, baserev, link,
91 e = (revlog.offset_type(start, flags), size, -1, baserev, link,
92 self.rev(p1), self.rev(p2), node)
92 self.rev(p1), self.rev(p2), node)
93 self.index.insert(-1, e)
93 self.index.insert(-1, e)
94 self.nodemap[node] = n
94 self.nodemap[node] = n
95 self.bundlerevs.add(n)
95 self.bundlerevs.add(n)
96 chain = node
96 chain = node
97 n += 1
97 n += 1
98
98
99 def _chunk(self, rev):
99 def _chunk(self, rev):
100 # Warning: in case of bundle, the diff is against what we stored as
100 # Warning: in case of bundle, the diff is against what we stored as
101 # delta base, not against rev - 1
101 # delta base, not against rev - 1
102 # XXX: could use some caching
102 # XXX: could use some caching
103 if rev <= self.repotiprev:
103 if rev <= self.repotiprev:
104 return revlog.revlog._chunk(self, rev)
104 return revlog.revlog._chunk(self, rev)
105 self.bundle.seek(self.start(rev))
105 self.bundle.seek(self.start(rev))
106 return self.bundle.read(self.length(rev))
106 return self.bundle.read(self.length(rev))
107
107
108 def revdiff(self, rev1, rev2):
108 def revdiff(self, rev1, rev2):
109 """return or calculate a delta between two revisions"""
109 """return or calculate a delta between two revisions"""
110 if rev1 > self.repotiprev and rev2 > self.repotiprev:
110 if rev1 > self.repotiprev and rev2 > self.repotiprev:
111 # hot path for bundle
111 # hot path for bundle
112 revb = self.index[rev2][3]
112 revb = self.index[rev2][3]
113 if revb == rev1:
113 if revb == rev1:
114 return self._chunk(rev2)
114 return self._chunk(rev2)
115 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
115 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
116 return revlog.revlog.revdiff(self, rev1, rev2)
116 return revlog.revlog.revdiff(self, rev1, rev2)
117
117
118 return mdiff.textdiff(self.revision(rev1, raw=True),
118 return mdiff.textdiff(self.revision(rev1, raw=True),
119 self.revision(rev2, raw=True))
119 self.revision(rev2, raw=True))
120
120
121 def revision(self, nodeorrev, raw=False):
121 def revision(self, nodeorrev, raw=False):
122 """return an uncompressed revision of a given node or revision
122 """return an uncompressed revision of a given node or revision
123 number.
123 number.
124 """
124 """
125 if isinstance(nodeorrev, int):
125 if isinstance(nodeorrev, int):
126 rev = nodeorrev
126 rev = nodeorrev
127 node = self.node(rev)
127 node = self.node(rev)
128 else:
128 else:
129 node = nodeorrev
129 node = nodeorrev
130 rev = self.rev(node)
130 rev = self.rev(node)
131
131
132 if node == nullid:
132 if node == nullid:
133 return ""
133 return ""
134
134
135 rawtext = None
135 rawtext = None
136 chain = []
136 chain = []
137 iterrev = rev
137 iterrev = rev
138 # reconstruct the revision if it is from a changegroup
138 # reconstruct the revision if it is from a changegroup
139 while iterrev > self.repotiprev:
139 while iterrev > self.repotiprev:
140 if self._cache and self._cache[1] == iterrev:
140 if self._cache and self._cache[1] == iterrev:
141 rawtext = self._cache[2]
141 rawtext = self._cache[2]
142 break
142 break
143 chain.append(iterrev)
143 chain.append(iterrev)
144 iterrev = self.index[iterrev][3]
144 iterrev = self.index[iterrev][3]
145 if rawtext is None:
145 if rawtext is None:
146 rawtext = self.baserevision(iterrev)
146 rawtext = self.baserevision(iterrev)
147
147
148 while chain:
148 while chain:
149 delta = self._chunk(chain.pop())
149 delta = self._chunk(chain.pop())
150 rawtext = mdiff.patches(rawtext, [delta])
150 rawtext = mdiff.patches(rawtext, [delta])
151
151
152 text, validatehash = self._processflags(rawtext, self.flags(rev),
152 text, validatehash = self._processflags(rawtext, self.flags(rev),
153 'read', raw=raw)
153 'read', raw=raw)
154 if validatehash:
154 if validatehash:
155 self.checkhash(text, node, rev=rev)
155 self.checkhash(text, node, rev=rev)
156 self._cache = (node, rev, rawtext)
156 self._cache = (node, rev, rawtext)
157 return text
157 return text
158
158
159 def baserevision(self, nodeorrev):
159 def baserevision(self, nodeorrev):
160 # Revlog subclasses may override 'revision' method to modify format of
160 # Revlog subclasses may override 'revision' method to modify format of
161 # content retrieved from revlog. To use bundlerevlog with such class one
161 # content retrieved from revlog. To use bundlerevlog with such class one
162 # needs to override 'baserevision' and make more specific call here.
162 # needs to override 'baserevision' and make more specific call here.
163 return revlog.revlog.revision(self, nodeorrev, raw=True)
163 return revlog.revlog.revision(self, nodeorrev, raw=True)
164
164
165 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
165 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
166 raise NotImplementedError
166 raise NotImplementedError
167 def addgroup(self, revs, linkmapper, transaction):
167 def addgroup(self, deltas, transaction, addrevisioncb=None):
168 raise NotImplementedError
168 raise NotImplementedError
169 def strip(self, rev, minlink):
169 def strip(self, rev, minlink):
170 raise NotImplementedError
170 raise NotImplementedError
171 def checksize(self):
171 def checksize(self):
172 raise NotImplementedError
172 raise NotImplementedError
173
173
174 class bundlechangelog(bundlerevlog, changelog.changelog):
174 class bundlechangelog(bundlerevlog, changelog.changelog):
175 def __init__(self, opener, bundle):
175 def __init__(self, opener, bundle):
176 changelog.changelog.__init__(self, opener)
176 changelog.changelog.__init__(self, opener)
177 linkmapper = lambda x: x
177 linkmapper = lambda x: x
178 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
178 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
179 linkmapper)
179 linkmapper)
180
180
181 def baserevision(self, nodeorrev):
181 def baserevision(self, nodeorrev):
182 # Although changelog doesn't override 'revision' method, some extensions
182 # Although changelog doesn't override 'revision' method, some extensions
183 # may replace this class with another that does. Same story with
183 # may replace this class with another that does. Same story with
184 # manifest and filelog classes.
184 # manifest and filelog classes.
185
185
186 # This bypasses filtering on changelog.node() and rev() because we need
186 # This bypasses filtering on changelog.node() and rev() because we need
187 # revision text of the bundle base even if it is hidden.
187 # revision text of the bundle base even if it is hidden.
188 oldfilter = self.filteredrevs
188 oldfilter = self.filteredrevs
189 try:
189 try:
190 self.filteredrevs = ()
190 self.filteredrevs = ()
191 return changelog.changelog.revision(self, nodeorrev, raw=True)
191 return changelog.changelog.revision(self, nodeorrev, raw=True)
192 finally:
192 finally:
193 self.filteredrevs = oldfilter
193 self.filteredrevs = oldfilter
194
194
195 class bundlemanifest(bundlerevlog, manifest.manifestrevlog):
195 class bundlemanifest(bundlerevlog, manifest.manifestrevlog):
196 def __init__(self, opener, bundle, linkmapper, dirlogstarts=None, dir=''):
196 def __init__(self, opener, bundle, linkmapper, dirlogstarts=None, dir=''):
197 manifest.manifestrevlog.__init__(self, opener, dir=dir)
197 manifest.manifestrevlog.__init__(self, opener, dir=dir)
198 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
198 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
199 linkmapper)
199 linkmapper)
200 if dirlogstarts is None:
200 if dirlogstarts is None:
201 dirlogstarts = {}
201 dirlogstarts = {}
202 if self.bundle.version == "03":
202 if self.bundle.version == "03":
203 dirlogstarts = _getfilestarts(self.bundle)
203 dirlogstarts = _getfilestarts(self.bundle)
204 self._dirlogstarts = dirlogstarts
204 self._dirlogstarts = dirlogstarts
205 self._linkmapper = linkmapper
205 self._linkmapper = linkmapper
206
206
207 def baserevision(self, nodeorrev):
207 def baserevision(self, nodeorrev):
208 node = nodeorrev
208 node = nodeorrev
209 if isinstance(node, int):
209 if isinstance(node, int):
210 node = self.node(node)
210 node = self.node(node)
211
211
212 if node in self.fulltextcache:
212 if node in self.fulltextcache:
213 result = '%s' % self.fulltextcache[node]
213 result = '%s' % self.fulltextcache[node]
214 else:
214 else:
215 result = manifest.manifestrevlog.revision(self, nodeorrev, raw=True)
215 result = manifest.manifestrevlog.revision(self, nodeorrev, raw=True)
216 return result
216 return result
217
217
218 def dirlog(self, d):
218 def dirlog(self, d):
219 if d in self._dirlogstarts:
219 if d in self._dirlogstarts:
220 self.bundle.seek(self._dirlogstarts[d])
220 self.bundle.seek(self._dirlogstarts[d])
221 return bundlemanifest(
221 return bundlemanifest(
222 self.opener, self.bundle, self._linkmapper,
222 self.opener, self.bundle, self._linkmapper,
223 self._dirlogstarts, dir=d)
223 self._dirlogstarts, dir=d)
224 return super(bundlemanifest, self).dirlog(d)
224 return super(bundlemanifest, self).dirlog(d)
225
225
226 class bundlefilelog(bundlerevlog, filelog.filelog):
226 class bundlefilelog(bundlerevlog, filelog.filelog):
227 def __init__(self, opener, path, bundle, linkmapper):
227 def __init__(self, opener, path, bundle, linkmapper):
228 filelog.filelog.__init__(self, opener, path)
228 filelog.filelog.__init__(self, opener, path)
229 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
229 bundlerevlog.__init__(self, opener, self.indexfile, bundle,
230 linkmapper)
230 linkmapper)
231
231
232 def baserevision(self, nodeorrev):
232 def baserevision(self, nodeorrev):
233 return filelog.filelog.revision(self, nodeorrev, raw=True)
233 return filelog.filelog.revision(self, nodeorrev, raw=True)
234
234
235 class bundlepeer(localrepo.localpeer):
235 class bundlepeer(localrepo.localpeer):
236 def canpush(self):
236 def canpush(self):
237 return False
237 return False
238
238
239 class bundlephasecache(phases.phasecache):
239 class bundlephasecache(phases.phasecache):
240 def __init__(self, *args, **kwargs):
240 def __init__(self, *args, **kwargs):
241 super(bundlephasecache, self).__init__(*args, **kwargs)
241 super(bundlephasecache, self).__init__(*args, **kwargs)
242 if util.safehasattr(self, 'opener'):
242 if util.safehasattr(self, 'opener'):
243 self.opener = vfsmod.readonlyvfs(self.opener)
243 self.opener = vfsmod.readonlyvfs(self.opener)
244
244
245 def write(self):
245 def write(self):
246 raise NotImplementedError
246 raise NotImplementedError
247
247
248 def _write(self, fp):
248 def _write(self, fp):
249 raise NotImplementedError
249 raise NotImplementedError
250
250
251 def _updateroots(self, phase, newroots, tr):
251 def _updateroots(self, phase, newroots, tr):
252 self.phaseroots[phase] = newroots
252 self.phaseroots[phase] = newroots
253 self.invalidate()
253 self.invalidate()
254 self.dirty = True
254 self.dirty = True
255
255
256 def _getfilestarts(bundle):
256 def _getfilestarts(bundle):
257 bundlefilespos = {}
257 bundlefilespos = {}
258 for chunkdata in iter(bundle.filelogheader, {}):
258 for chunkdata in iter(bundle.filelogheader, {}):
259 fname = chunkdata['filename']
259 fname = chunkdata['filename']
260 bundlefilespos[fname] = bundle.tell()
260 bundlefilespos[fname] = bundle.tell()
261 for chunk in iter(lambda: bundle.deltachunk(None), {}):
261 for chunk in iter(lambda: bundle.deltachunk(None), {}):
262 pass
262 pass
263 return bundlefilespos
263 return bundlefilespos
264
264
265 class bundlerepository(localrepo.localrepository):
265 class bundlerepository(localrepo.localrepository):
266 def __init__(self, ui, path, bundlename):
266 def __init__(self, ui, path, bundlename):
267 self._tempparent = None
267 self._tempparent = None
268 try:
268 try:
269 localrepo.localrepository.__init__(self, ui, path)
269 localrepo.localrepository.__init__(self, ui, path)
270 except error.RepoError:
270 except error.RepoError:
271 self._tempparent = tempfile.mkdtemp()
271 self._tempparent = tempfile.mkdtemp()
272 localrepo.instance(ui, self._tempparent, 1)
272 localrepo.instance(ui, self._tempparent, 1)
273 localrepo.localrepository.__init__(self, ui, self._tempparent)
273 localrepo.localrepository.__init__(self, ui, self._tempparent)
274 self.ui.setconfig('phases', 'publish', False, 'bundlerepo')
274 self.ui.setconfig('phases', 'publish', False, 'bundlerepo')
275
275
276 if path:
276 if path:
277 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename
277 self._url = 'bundle:' + util.expandpath(path) + '+' + bundlename
278 else:
278 else:
279 self._url = 'bundle:' + bundlename
279 self._url = 'bundle:' + bundlename
280
280
281 self.tempfile = None
281 self.tempfile = None
282 f = util.posixfile(bundlename, "rb")
282 f = util.posixfile(bundlename, "rb")
283 self.bundlefile = self.bundle = exchange.readbundle(ui, f, bundlename)
283 self.bundlefile = self.bundle = exchange.readbundle(ui, f, bundlename)
284
284
285 if isinstance(self.bundle, bundle2.unbundle20):
285 if isinstance(self.bundle, bundle2.unbundle20):
286 hadchangegroup = False
286 hadchangegroup = False
287 for part in self.bundle.iterparts():
287 for part in self.bundle.iterparts():
288 if part.type == 'changegroup':
288 if part.type == 'changegroup':
289 if hadchangegroup:
289 if hadchangegroup:
290 raise NotImplementedError("can't process "
290 raise NotImplementedError("can't process "
291 "multiple changegroups")
291 "multiple changegroups")
292 hadchangegroup = True
292 hadchangegroup = True
293
293
294 self._handlebundle2part(part)
294 self._handlebundle2part(part)
295
295
296 if not hadchangegroup:
296 if not hadchangegroup:
297 raise error.Abort(_("No changegroups found"))
297 raise error.Abort(_("No changegroups found"))
298
298
299 elif self.bundle.compressed():
299 elif self.bundle.compressed():
300 f = self._writetempbundle(self.bundle.read, '.hg10un',
300 f = self._writetempbundle(self.bundle.read, '.hg10un',
301 header='HG10UN')
301 header='HG10UN')
302 self.bundlefile = self.bundle = exchange.readbundle(ui, f,
302 self.bundlefile = self.bundle = exchange.readbundle(ui, f,
303 bundlename,
303 bundlename,
304 self.vfs)
304 self.vfs)
305
305
306 # dict with the mapping 'filename' -> position in the bundle
306 # dict with the mapping 'filename' -> position in the bundle
307 self.bundlefilespos = {}
307 self.bundlefilespos = {}
308
308
309 self.firstnewrev = self.changelog.repotiprev + 1
309 self.firstnewrev = self.changelog.repotiprev + 1
310 phases.retractboundary(self, None, phases.draft,
310 phases.retractboundary(self, None, phases.draft,
311 [ctx.node() for ctx in self[self.firstnewrev:]])
311 [ctx.node() for ctx in self[self.firstnewrev:]])
312
312
313 def _handlebundle2part(self, part):
313 def _handlebundle2part(self, part):
314 if part.type == 'changegroup':
314 if part.type == 'changegroup':
315 cgstream = part
315 cgstream = part
316 version = part.params.get('version', '01')
316 version = part.params.get('version', '01')
317 legalcgvers = changegroup.supportedincomingversions(self)
317 legalcgvers = changegroup.supportedincomingversions(self)
318 if version not in legalcgvers:
318 if version not in legalcgvers:
319 msg = _('Unsupported changegroup version: %s')
319 msg = _('Unsupported changegroup version: %s')
320 raise error.Abort(msg % version)
320 raise error.Abort(msg % version)
321 if self.bundle.compressed():
321 if self.bundle.compressed():
322 cgstream = self._writetempbundle(part.read,
322 cgstream = self._writetempbundle(part.read,
323 ".cg%sun" % version)
323 ".cg%sun" % version)
324
324
325 self.bundle = changegroup.getunbundler(version, cgstream, 'UN')
325 self.bundle = changegroup.getunbundler(version, cgstream, 'UN')
326
326
327 def _writetempbundle(self, readfn, suffix, header=''):
327 def _writetempbundle(self, readfn, suffix, header=''):
328 """Write a temporary file to disk
328 """Write a temporary file to disk
329 """
329 """
330 fdtemp, temp = self.vfs.mkstemp(prefix="hg-bundle-",
330 fdtemp, temp = self.vfs.mkstemp(prefix="hg-bundle-",
331 suffix=".hg10un")
331 suffix=".hg10un")
332 self.tempfile = temp
332 self.tempfile = temp
333
333
334 with os.fdopen(fdtemp, pycompat.sysstr('wb')) as fptemp:
334 with os.fdopen(fdtemp, pycompat.sysstr('wb')) as fptemp:
335 fptemp.write(header)
335 fptemp.write(header)
336 while True:
336 while True:
337 chunk = readfn(2**18)
337 chunk = readfn(2**18)
338 if not chunk:
338 if not chunk:
339 break
339 break
340 fptemp.write(chunk)
340 fptemp.write(chunk)
341
341
342 return self.vfs.open(self.tempfile, mode="rb")
342 return self.vfs.open(self.tempfile, mode="rb")
343
343
344 @localrepo.unfilteredpropertycache
344 @localrepo.unfilteredpropertycache
345 def _phasecache(self):
345 def _phasecache(self):
346 return bundlephasecache(self, self._phasedefaults)
346 return bundlephasecache(self, self._phasedefaults)
347
347
348 @localrepo.unfilteredpropertycache
348 @localrepo.unfilteredpropertycache
349 def changelog(self):
349 def changelog(self):
350 # consume the header if it exists
350 # consume the header if it exists
351 self.bundle.changelogheader()
351 self.bundle.changelogheader()
352 c = bundlechangelog(self.svfs, self.bundle)
352 c = bundlechangelog(self.svfs, self.bundle)
353 self.manstart = self.bundle.tell()
353 self.manstart = self.bundle.tell()
354 return c
354 return c
355
355
356 def _constructmanifest(self):
356 def _constructmanifest(self):
357 self.bundle.seek(self.manstart)
357 self.bundle.seek(self.manstart)
358 # consume the header if it exists
358 # consume the header if it exists
359 self.bundle.manifestheader()
359 self.bundle.manifestheader()
360 linkmapper = self.unfiltered().changelog.rev
360 linkmapper = self.unfiltered().changelog.rev
361 m = bundlemanifest(self.svfs, self.bundle, linkmapper)
361 m = bundlemanifest(self.svfs, self.bundle, linkmapper)
362 self.filestart = self.bundle.tell()
362 self.filestart = self.bundle.tell()
363 return m
363 return m
364
364
365 @localrepo.unfilteredpropertycache
365 @localrepo.unfilteredpropertycache
366 def manstart(self):
366 def manstart(self):
367 self.changelog
367 self.changelog
368 return self.manstart
368 return self.manstart
369
369
370 @localrepo.unfilteredpropertycache
370 @localrepo.unfilteredpropertycache
371 def filestart(self):
371 def filestart(self):
372 self.manifestlog
372 self.manifestlog
373 return self.filestart
373 return self.filestart
374
374
375 def url(self):
375 def url(self):
376 return self._url
376 return self._url
377
377
378 def file(self, f):
378 def file(self, f):
379 if not self.bundlefilespos:
379 if not self.bundlefilespos:
380 self.bundle.seek(self.filestart)
380 self.bundle.seek(self.filestart)
381 self.bundlefilespos = _getfilestarts(self.bundle)
381 self.bundlefilespos = _getfilestarts(self.bundle)
382
382
383 if f in self.bundlefilespos:
383 if f in self.bundlefilespos:
384 self.bundle.seek(self.bundlefilespos[f])
384 self.bundle.seek(self.bundlefilespos[f])
385 linkmapper = self.unfiltered().changelog.rev
385 linkmapper = self.unfiltered().changelog.rev
386 return bundlefilelog(self.svfs, f, self.bundle, linkmapper)
386 return bundlefilelog(self.svfs, f, self.bundle, linkmapper)
387 else:
387 else:
388 return filelog.filelog(self.svfs, f)
388 return filelog.filelog(self.svfs, f)
389
389
390 def close(self):
390 def close(self):
391 """Close assigned bundle file immediately."""
391 """Close assigned bundle file immediately."""
392 self.bundlefile.close()
392 self.bundlefile.close()
393 if self.tempfile is not None:
393 if self.tempfile is not None:
394 self.vfs.unlink(self.tempfile)
394 self.vfs.unlink(self.tempfile)
395 if self._tempparent:
395 if self._tempparent:
396 shutil.rmtree(self._tempparent, True)
396 shutil.rmtree(self._tempparent, True)
397
397
398 def cancopy(self):
398 def cancopy(self):
399 return False
399 return False
400
400
401 def peer(self):
401 def peer(self):
402 return bundlepeer(self)
402 return bundlepeer(self)
403
403
404 def getcwd(self):
404 def getcwd(self):
405 return pycompat.getcwd() # always outside the repo
405 return pycompat.getcwd() # always outside the repo
406
406
407 # Check if parents exist in localrepo before setting
407 # Check if parents exist in localrepo before setting
408 def setparents(self, p1, p2=nullid):
408 def setparents(self, p1, p2=nullid):
409 p1rev = self.changelog.rev(p1)
409 p1rev = self.changelog.rev(p1)
410 p2rev = self.changelog.rev(p2)
410 p2rev = self.changelog.rev(p2)
411 msg = _("setting parent to node %s that only exists in the bundle\n")
411 msg = _("setting parent to node %s that only exists in the bundle\n")
412 if self.changelog.repotiprev < p1rev:
412 if self.changelog.repotiprev < p1rev:
413 self.ui.warn(msg % nodemod.hex(p1))
413 self.ui.warn(msg % nodemod.hex(p1))
414 if self.changelog.repotiprev < p2rev:
414 if self.changelog.repotiprev < p2rev:
415 self.ui.warn(msg % nodemod.hex(p2))
415 self.ui.warn(msg % nodemod.hex(p2))
416 return super(bundlerepository, self).setparents(p1, p2)
416 return super(bundlerepository, self).setparents(p1, p2)
417
417
418 def instance(ui, path, create):
418 def instance(ui, path, create):
419 if create:
419 if create:
420 raise error.Abort(_('cannot create new bundle repository'))
420 raise error.Abort(_('cannot create new bundle repository'))
421 # internal config: bundle.mainreporoot
421 # internal config: bundle.mainreporoot
422 parentpath = ui.config("bundle", "mainreporoot")
422 parentpath = ui.config("bundle", "mainreporoot")
423 if not parentpath:
423 if not parentpath:
424 # try to find the correct path to the working directory repo
424 # try to find the correct path to the working directory repo
425 parentpath = cmdutil.findrepo(pycompat.getcwd())
425 parentpath = cmdutil.findrepo(pycompat.getcwd())
426 if parentpath is None:
426 if parentpath is None:
427 parentpath = ''
427 parentpath = ''
428 if parentpath:
428 if parentpath:
429 # Try to make the full path relative so we get a nice, short URL.
429 # Try to make the full path relative so we get a nice, short URL.
430 # In particular, we don't want temp dir names in test outputs.
430 # In particular, we don't want temp dir names in test outputs.
431 cwd = pycompat.getcwd()
431 cwd = pycompat.getcwd()
432 if parentpath == cwd:
432 if parentpath == cwd:
433 parentpath = ''
433 parentpath = ''
434 else:
434 else:
435 cwd = pathutil.normasprefix(cwd)
435 cwd = pathutil.normasprefix(cwd)
436 if parentpath.startswith(cwd):
436 if parentpath.startswith(cwd):
437 parentpath = parentpath[len(cwd):]
437 parentpath = parentpath[len(cwd):]
438 u = util.url(path)
438 u = util.url(path)
439 path = u.localpath()
439 path = u.localpath()
440 if u.scheme == 'bundle':
440 if u.scheme == 'bundle':
441 s = path.split("+", 1)
441 s = path.split("+", 1)
442 if len(s) == 1:
442 if len(s) == 1:
443 repopath, bundlename = parentpath, s[0]
443 repopath, bundlename = parentpath, s[0]
444 else:
444 else:
445 repopath, bundlename = s
445 repopath, bundlename = s
446 else:
446 else:
447 repopath, bundlename = parentpath, path
447 repopath, bundlename = parentpath, path
448 return bundlerepository(ui, repopath, bundlename)
448 return bundlerepository(ui, repopath, bundlename)
449
449
450 class bundletransactionmanager(object):
450 class bundletransactionmanager(object):
451 def transaction(self):
451 def transaction(self):
452 return None
452 return None
453
453
454 def close(self):
454 def close(self):
455 raise NotImplementedError
455 raise NotImplementedError
456
456
457 def release(self):
457 def release(self):
458 raise NotImplementedError
458 raise NotImplementedError
459
459
460 def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
460 def getremotechanges(ui, repo, other, onlyheads=None, bundlename=None,
461 force=False):
461 force=False):
462 '''obtains a bundle of changes incoming from other
462 '''obtains a bundle of changes incoming from other
463
463
464 "onlyheads" restricts the returned changes to those reachable from the
464 "onlyheads" restricts the returned changes to those reachable from the
465 specified heads.
465 specified heads.
466 "bundlename", if given, stores the bundle to this file path permanently;
466 "bundlename", if given, stores the bundle to this file path permanently;
467 otherwise it's stored to a temp file and gets deleted again when you call
467 otherwise it's stored to a temp file and gets deleted again when you call
468 the returned "cleanupfn".
468 the returned "cleanupfn".
469 "force" indicates whether to proceed on unrelated repos.
469 "force" indicates whether to proceed on unrelated repos.
470
470
471 Returns a tuple (local, csets, cleanupfn):
471 Returns a tuple (local, csets, cleanupfn):
472
472
473 "local" is a local repo from which to obtain the actual incoming
473 "local" is a local repo from which to obtain the actual incoming
474 changesets; it is a bundlerepo for the obtained bundle when the
474 changesets; it is a bundlerepo for the obtained bundle when the
475 original "other" is remote.
475 original "other" is remote.
476 "csets" lists the incoming changeset node ids.
476 "csets" lists the incoming changeset node ids.
477 "cleanupfn" must be called without arguments when you're done processing
477 "cleanupfn" must be called without arguments when you're done processing
478 the changes; it closes both the original "other" and the one returned
478 the changes; it closes both the original "other" and the one returned
479 here.
479 here.
480 '''
480 '''
481 tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
481 tmp = discovery.findcommonincoming(repo, other, heads=onlyheads,
482 force=force)
482 force=force)
483 common, incoming, rheads = tmp
483 common, incoming, rheads = tmp
484 if not incoming:
484 if not incoming:
485 try:
485 try:
486 if bundlename:
486 if bundlename:
487 os.unlink(bundlename)
487 os.unlink(bundlename)
488 except OSError:
488 except OSError:
489 pass
489 pass
490 return repo, [], other.close
490 return repo, [], other.close
491
491
492 commonset = set(common)
492 commonset = set(common)
493 rheads = [x for x in rheads if x not in commonset]
493 rheads = [x for x in rheads if x not in commonset]
494
494
495 bundle = None
495 bundle = None
496 bundlerepo = None
496 bundlerepo = None
497 localrepo = other.local()
497 localrepo = other.local()
498 if bundlename or not localrepo:
498 if bundlename or not localrepo:
499 # create a bundle (uncompressed if other repo is not local)
499 # create a bundle (uncompressed if other repo is not local)
500
500
501 # developer config: devel.legacy.exchange
501 # developer config: devel.legacy.exchange
502 legexc = ui.configlist('devel', 'legacy.exchange')
502 legexc = ui.configlist('devel', 'legacy.exchange')
503 forcebundle1 = 'bundle2' not in legexc and 'bundle1' in legexc
503 forcebundle1 = 'bundle2' not in legexc and 'bundle1' in legexc
504 canbundle2 = (not forcebundle1
504 canbundle2 = (not forcebundle1
505 and other.capable('getbundle')
505 and other.capable('getbundle')
506 and other.capable('bundle2'))
506 and other.capable('bundle2'))
507 if canbundle2:
507 if canbundle2:
508 kwargs = {}
508 kwargs = {}
509 kwargs['common'] = common
509 kwargs['common'] = common
510 kwargs['heads'] = rheads
510 kwargs['heads'] = rheads
511 kwargs['bundlecaps'] = exchange.caps20to10(repo)
511 kwargs['bundlecaps'] = exchange.caps20to10(repo)
512 kwargs['cg'] = True
512 kwargs['cg'] = True
513 b2 = other.getbundle('incoming', **kwargs)
513 b2 = other.getbundle('incoming', **kwargs)
514 fname = bundle = changegroup.writechunks(ui, b2._forwardchunks(),
514 fname = bundle = changegroup.writechunks(ui, b2._forwardchunks(),
515 bundlename)
515 bundlename)
516 else:
516 else:
517 if other.capable('getbundle'):
517 if other.capable('getbundle'):
518 cg = other.getbundle('incoming', common=common, heads=rheads)
518 cg = other.getbundle('incoming', common=common, heads=rheads)
519 elif onlyheads is None and not other.capable('changegroupsubset'):
519 elif onlyheads is None and not other.capable('changegroupsubset'):
520 # compat with older servers when pulling all remote heads
520 # compat with older servers when pulling all remote heads
521 cg = other.changegroup(incoming, "incoming")
521 cg = other.changegroup(incoming, "incoming")
522 rheads = None
522 rheads = None
523 else:
523 else:
524 cg = other.changegroupsubset(incoming, rheads, 'incoming')
524 cg = other.changegroupsubset(incoming, rheads, 'incoming')
525 if localrepo:
525 if localrepo:
526 bundletype = "HG10BZ"
526 bundletype = "HG10BZ"
527 else:
527 else:
528 bundletype = "HG10UN"
528 bundletype = "HG10UN"
529 fname = bundle = bundle2.writebundle(ui, cg, bundlename,
529 fname = bundle = bundle2.writebundle(ui, cg, bundlename,
530 bundletype)
530 bundletype)
531 # keep written bundle?
531 # keep written bundle?
532 if bundlename:
532 if bundlename:
533 bundle = None
533 bundle = None
534 if not localrepo:
534 if not localrepo:
535 # use the created uncompressed bundlerepo
535 # use the created uncompressed bundlerepo
536 localrepo = bundlerepo = bundlerepository(repo.baseui, repo.root,
536 localrepo = bundlerepo = bundlerepository(repo.baseui, repo.root,
537 fname)
537 fname)
538 # this repo contains local and other now, so filter out local again
538 # this repo contains local and other now, so filter out local again
539 common = repo.heads()
539 common = repo.heads()
540 if localrepo:
540 if localrepo:
541 # Part of common may be remotely filtered
541 # Part of common may be remotely filtered
542 # So use an unfiltered version
542 # So use an unfiltered version
543 # The discovery process probably need cleanup to avoid that
543 # The discovery process probably need cleanup to avoid that
544 localrepo = localrepo.unfiltered()
544 localrepo = localrepo.unfiltered()
545
545
546 csets = localrepo.changelog.findmissing(common, rheads)
546 csets = localrepo.changelog.findmissing(common, rheads)
547
547
548 if bundlerepo:
548 if bundlerepo:
549 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
549 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
550 remotephases = other.listkeys('phases')
550 remotephases = other.listkeys('phases')
551
551
552 pullop = exchange.pulloperation(bundlerepo, other, heads=reponodes)
552 pullop = exchange.pulloperation(bundlerepo, other, heads=reponodes)
553 pullop.trmanager = bundletransactionmanager()
553 pullop.trmanager = bundletransactionmanager()
554 exchange._pullapplyphases(pullop, remotephases)
554 exchange._pullapplyphases(pullop, remotephases)
555
555
556 def cleanup():
556 def cleanup():
557 if bundlerepo:
557 if bundlerepo:
558 bundlerepo.close()
558 bundlerepo.close()
559 if bundle:
559 if bundle:
560 os.unlink(bundle)
560 os.unlink(bundle)
561 other.close()
561 other.close()
562
562
563 return (localrepo, csets, cleanup)
563 return (localrepo, csets, cleanup)
@@ -1,259 +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 from .i18n import _
16 from .i18n import _
17 from .node import nullid
17 from .node import nullid
18
18
19 from . import (
19 from . import (
20 changelog,
20 changelog,
21 cmdutil,
21 cmdutil,
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 pycompat,
28 pycompat,
29 revlog,
29 revlog,
30 util,
30 util,
31 vfs as vfsmod,
31 vfs as vfsmod,
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 = vfsmod.readonlyvfs(opener)
42 opener = vfsmod.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 flags = _start & 0xFFFF
53 flags = _start & 0xFFFF
54
54
55 if linkmapper is None: # link is to same revlog
55 if linkmapper is None: # link is to same revlog
56 assert linkrev == rev2 # we never link back
56 assert linkrev == rev2 # we never link back
57 link = n
57 link = n
58 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
58 else: # rev must be mapped from repo2 cl to unified cl by linkmapper
59 link = linkmapper(linkrev)
59 link = linkmapper(linkrev)
60
60
61 if linkmapper is not None: # link is to same revlog
61 if linkmapper is not None: # link is to same revlog
62 base = linkmapper(base)
62 base = linkmapper(base)
63
63
64 if node in self.nodemap:
64 if node in self.nodemap:
65 # this happens for the common revlog revisions
65 # this happens for the common revlog revisions
66 self.bundlerevs.add(self.nodemap[node])
66 self.bundlerevs.add(self.nodemap[node])
67 continue
67 continue
68
68
69 p1node = self.revlog2.node(p1rev)
69 p1node = self.revlog2.node(p1rev)
70 p2node = self.revlog2.node(p2rev)
70 p2node = self.revlog2.node(p2rev)
71
71
72 e = (flags, None, None, base,
72 e = (flags, None, None, base,
73 link, self.rev(p1node), self.rev(p2node), node)
73 link, self.rev(p1node), self.rev(p2node), node)
74 self.index.insert(-1, e)
74 self.index.insert(-1, e)
75 self.nodemap[node] = n
75 self.nodemap[node] = n
76 self.bundlerevs.add(n)
76 self.bundlerevs.add(n)
77 n += 1
77 n += 1
78
78
79 def _chunk(self, rev):
79 def _chunk(self, rev):
80 if rev <= self.repotiprev:
80 if rev <= self.repotiprev:
81 return revlog.revlog._chunk(self, rev)
81 return revlog.revlog._chunk(self, rev)
82 return self.revlog2._chunk(self.node(rev))
82 return self.revlog2._chunk(self.node(rev))
83
83
84 def revdiff(self, rev1, rev2):
84 def revdiff(self, rev1, rev2):
85 """return or calculate a delta between two revisions"""
85 """return or calculate a delta between two revisions"""
86 if rev1 > self.repotiprev and rev2 > self.repotiprev:
86 if rev1 > self.repotiprev and rev2 > self.repotiprev:
87 return self.revlog2.revdiff(
87 return self.revlog2.revdiff(
88 self.revlog2.rev(self.node(rev1)),
88 self.revlog2.rev(self.node(rev1)),
89 self.revlog2.rev(self.node(rev2)))
89 self.revlog2.rev(self.node(rev2)))
90 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
90 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
91 return self.baserevdiff(rev1, rev2)
91 return self.baserevdiff(rev1, rev2)
92
92
93 return mdiff.textdiff(self.revision(rev1), self.revision(rev2))
93 return mdiff.textdiff(self.revision(rev1), self.revision(rev2))
94
94
95 def revision(self, nodeorrev, raw=False):
95 def revision(self, nodeorrev, raw=False):
96 """return an uncompressed revision of a given node or revision
96 """return an uncompressed revision of a given node or revision
97 number.
97 number.
98 """
98 """
99 if isinstance(nodeorrev, int):
99 if isinstance(nodeorrev, int):
100 rev = nodeorrev
100 rev = nodeorrev
101 node = self.node(rev)
101 node = self.node(rev)
102 else:
102 else:
103 node = nodeorrev
103 node = nodeorrev
104 rev = self.rev(node)
104 rev = self.rev(node)
105
105
106 if node == nullid:
106 if node == nullid:
107 return ""
107 return ""
108
108
109 if rev > self.repotiprev:
109 if rev > self.repotiprev:
110 text = self.revlog2.revision(node)
110 text = self.revlog2.revision(node)
111 self._cache = (node, rev, text)
111 self._cache = (node, rev, text)
112 else:
112 else:
113 text = self.baserevision(rev)
113 text = self.baserevision(rev)
114 # already cached
114 # already cached
115 return text
115 return text
116
116
117 def baserevision(self, nodeorrev):
117 def baserevision(self, nodeorrev):
118 # Revlog subclasses may override 'revision' method to modify format of
118 # Revlog subclasses may override 'revision' method to modify format of
119 # content retrieved from revlog. To use unionrevlog with such class one
119 # content retrieved from revlog. To use unionrevlog with such class one
120 # needs to override 'baserevision' and make more specific call here.
120 # needs to override 'baserevision' and make more specific call here.
121 return revlog.revlog.revision(self, nodeorrev)
121 return revlog.revlog.revision(self, nodeorrev)
122
122
123 def baserevdiff(self, rev1, rev2):
123 def baserevdiff(self, rev1, rev2):
124 # Exists for the same purpose as baserevision.
124 # Exists for the same purpose as baserevision.
125 return revlog.revlog.revdiff(self, rev1, rev2)
125 return revlog.revlog.revdiff(self, rev1, rev2)
126
126
127 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):
128 raise NotImplementedError
128 raise NotImplementedError
129 def addgroup(self, revs, linkmapper, transaction):
129 def addgroup(self, deltas, transaction, addrevisioncb=None):
130 raise NotImplementedError
130 raise NotImplementedError
131 def strip(self, rev, minlink):
131 def strip(self, rev, minlink):
132 raise NotImplementedError
132 raise NotImplementedError
133 def checksize(self):
133 def checksize(self):
134 raise NotImplementedError
134 raise NotImplementedError
135
135
136 class unionchangelog(unionrevlog, changelog.changelog):
136 class unionchangelog(unionrevlog, changelog.changelog):
137 def __init__(self, opener, opener2):
137 def __init__(self, opener, opener2):
138 changelog.changelog.__init__(self, opener)
138 changelog.changelog.__init__(self, opener)
139 linkmapper = None
139 linkmapper = None
140 changelog2 = changelog.changelog(opener2)
140 changelog2 = changelog.changelog(opener2)
141 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
141 unionrevlog.__init__(self, opener, self.indexfile, changelog2,
142 linkmapper)
142 linkmapper)
143
143
144 def baserevision(self, nodeorrev):
144 def baserevision(self, nodeorrev):
145 # Although changelog doesn't override 'revision' method, some extensions
145 # Although changelog doesn't override 'revision' method, some extensions
146 # may replace this class with another that does. Same story with
146 # may replace this class with another that does. Same story with
147 # manifest and filelog classes.
147 # manifest and filelog classes.
148 return changelog.changelog.revision(self, nodeorrev)
148 return changelog.changelog.revision(self, nodeorrev)
149
149
150 def baserevdiff(self, rev1, rev2):
150 def baserevdiff(self, rev1, rev2):
151 return changelog.changelog.revdiff(self, rev1, rev2)
151 return changelog.changelog.revdiff(self, rev1, rev2)
152
152
153 class unionmanifest(unionrevlog, manifest.manifestrevlog):
153 class unionmanifest(unionrevlog, manifest.manifestrevlog):
154 def __init__(self, opener, opener2, linkmapper):
154 def __init__(self, opener, opener2, linkmapper):
155 manifest.manifestrevlog.__init__(self, opener)
155 manifest.manifestrevlog.__init__(self, opener)
156 manifest2 = manifest.manifestrevlog(opener2)
156 manifest2 = manifest.manifestrevlog(opener2)
157 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
157 unionrevlog.__init__(self, opener, self.indexfile, manifest2,
158 linkmapper)
158 linkmapper)
159
159
160 def baserevision(self, nodeorrev):
160 def baserevision(self, nodeorrev):
161 return manifest.manifestrevlog.revision(self, nodeorrev)
161 return manifest.manifestrevlog.revision(self, nodeorrev)
162
162
163 def baserevdiff(self, rev1, rev2):
163 def baserevdiff(self, rev1, rev2):
164 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
164 return manifest.manifestrevlog.revdiff(self, rev1, rev2)
165
165
166 class unionfilelog(unionrevlog, filelog.filelog):
166 class unionfilelog(unionrevlog, filelog.filelog):
167 def __init__(self, opener, path, opener2, linkmapper, repo):
167 def __init__(self, opener, path, opener2, linkmapper, repo):
168 filelog.filelog.__init__(self, opener, path)
168 filelog.filelog.__init__(self, opener, path)
169 filelog2 = filelog.filelog(opener2, path)
169 filelog2 = filelog.filelog(opener2, path)
170 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
170 unionrevlog.__init__(self, opener, self.indexfile, filelog2,
171 linkmapper)
171 linkmapper)
172 self._repo = repo
172 self._repo = repo
173
173
174 def baserevision(self, nodeorrev):
174 def baserevision(self, nodeorrev):
175 return filelog.filelog.revision(self, nodeorrev)
175 return filelog.filelog.revision(self, nodeorrev)
176
176
177 def baserevdiff(self, rev1, rev2):
177 def baserevdiff(self, rev1, rev2):
178 return filelog.filelog.revdiff(self, rev1, rev2)
178 return filelog.filelog.revdiff(self, rev1, rev2)
179
179
180 def iscensored(self, rev):
180 def iscensored(self, rev):
181 """Check if a revision is censored."""
181 """Check if a revision is censored."""
182 if rev <= self.repotiprev:
182 if rev <= self.repotiprev:
183 return filelog.filelog.iscensored(self, rev)
183 return filelog.filelog.iscensored(self, rev)
184 node = self.node(rev)
184 node = self.node(rev)
185 return self.revlog2.iscensored(self.revlog2.rev(node))
185 return self.revlog2.iscensored(self.revlog2.rev(node))
186
186
187 class unionpeer(localrepo.localpeer):
187 class unionpeer(localrepo.localpeer):
188 def canpush(self):
188 def canpush(self):
189 return False
189 return False
190
190
191 class unionrepository(localrepo.localrepository):
191 class unionrepository(localrepo.localrepository):
192 def __init__(self, ui, path, path2):
192 def __init__(self, ui, path, path2):
193 localrepo.localrepository.__init__(self, ui, path)
193 localrepo.localrepository.__init__(self, ui, path)
194 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
194 self.ui.setconfig('phases', 'publish', False, 'unionrepo')
195
195
196 self._url = 'union:%s+%s' % (util.expandpath(path),
196 self._url = 'union:%s+%s' % (util.expandpath(path),
197 util.expandpath(path2))
197 util.expandpath(path2))
198 self.repo2 = localrepo.localrepository(ui, path2)
198 self.repo2 = localrepo.localrepository(ui, path2)
199
199
200 @localrepo.unfilteredpropertycache
200 @localrepo.unfilteredpropertycache
201 def changelog(self):
201 def changelog(self):
202 return unionchangelog(self.svfs, self.repo2.svfs)
202 return unionchangelog(self.svfs, self.repo2.svfs)
203
203
204 def _clrev(self, rev2):
204 def _clrev(self, rev2):
205 """map from repo2 changelog rev to temporary rev in self.changelog"""
205 """map from repo2 changelog rev to temporary rev in self.changelog"""
206 node = self.repo2.changelog.node(rev2)
206 node = self.repo2.changelog.node(rev2)
207 return self.changelog.rev(node)
207 return self.changelog.rev(node)
208
208
209 def _constructmanifest(self):
209 def _constructmanifest(self):
210 return unionmanifest(self.svfs, self.repo2.svfs,
210 return unionmanifest(self.svfs, self.repo2.svfs,
211 self.unfiltered()._clrev)
211 self.unfiltered()._clrev)
212
212
213 def url(self):
213 def url(self):
214 return self._url
214 return self._url
215
215
216 def file(self, f):
216 def file(self, f):
217 return unionfilelog(self.svfs, f, self.repo2.svfs,
217 return unionfilelog(self.svfs, f, self.repo2.svfs,
218 self.unfiltered()._clrev, self)
218 self.unfiltered()._clrev, self)
219
219
220 def close(self):
220 def close(self):
221 self.repo2.close()
221 self.repo2.close()
222
222
223 def cancopy(self):
223 def cancopy(self):
224 return False
224 return False
225
225
226 def peer(self):
226 def peer(self):
227 return unionpeer(self)
227 return unionpeer(self)
228
228
229 def getcwd(self):
229 def getcwd(self):
230 return pycompat.getcwd() # always outside the repo
230 return pycompat.getcwd() # always outside the repo
231
231
232 def instance(ui, path, create):
232 def instance(ui, path, create):
233 if create:
233 if create:
234 raise error.Abort(_('cannot create new union repository'))
234 raise error.Abort(_('cannot create new union repository'))
235 parentpath = ui.config("bundle", "mainreporoot")
235 parentpath = ui.config("bundle", "mainreporoot")
236 if not parentpath:
236 if not parentpath:
237 # try to find the correct path to the working directory repo
237 # try to find the correct path to the working directory repo
238 parentpath = cmdutil.findrepo(pycompat.getcwd())
238 parentpath = cmdutil.findrepo(pycompat.getcwd())
239 if parentpath is None:
239 if parentpath is None:
240 parentpath = ''
240 parentpath = ''
241 if parentpath:
241 if parentpath:
242 # 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.
243 # 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.
244 cwd = pycompat.getcwd()
244 cwd = pycompat.getcwd()
245 if parentpath == cwd:
245 if parentpath == cwd:
246 parentpath = ''
246 parentpath = ''
247 else:
247 else:
248 cwd = pathutil.normasprefix(cwd)
248 cwd = pathutil.normasprefix(cwd)
249 if parentpath.startswith(cwd):
249 if parentpath.startswith(cwd):
250 parentpath = parentpath[len(cwd):]
250 parentpath = parentpath[len(cwd):]
251 if path.startswith('union:'):
251 if path.startswith('union:'):
252 s = path.split(":", 1)[1].split("+", 1)
252 s = path.split(":", 1)[1].split("+", 1)
253 if len(s) == 1:
253 if len(s) == 1:
254 repopath, repopath2 = parentpath, s[0]
254 repopath, repopath2 = parentpath, s[0]
255 else:
255 else:
256 repopath, repopath2 = s
256 repopath, repopath2 = s
257 else:
257 else:
258 repopath, repopath2 = parentpath, path
258 repopath, repopath2 = parentpath, path
259 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