##// END OF EJS Templates
rawdata: add the method to bundlerevlog...
marmoute -
r42947:161d39e9 default
parent child Browse files
Show More
@@ -1,665 +1,668 b''
1 1 # bundlerepo.py - repository class for viewing uncompressed bundles
2 2 #
3 3 # Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """Repository class for viewing uncompressed bundles.
9 9
10 10 This provides a read-only repository interface to bundles as if they
11 11 were part of the actual repository.
12 12 """
13 13
14 14 from __future__ import absolute_import
15 15
16 16 import os
17 17 import shutil
18 18
19 19 from .i18n import _
20 20 from .node import nullid
21 21
22 22 from . import (
23 23 bundle2,
24 24 changegroup,
25 25 changelog,
26 26 cmdutil,
27 27 discovery,
28 28 encoding,
29 29 error,
30 30 exchange,
31 31 filelog,
32 32 localrepo,
33 33 manifest,
34 34 mdiff,
35 35 node as nodemod,
36 36 pathutil,
37 37 phases,
38 38 pycompat,
39 39 revlog,
40 40 util,
41 41 vfs as vfsmod,
42 42 )
43 43
44 44 class bundlerevlog(revlog.revlog):
45 45 def __init__(self, opener, indexfile, cgunpacker, linkmapper):
46 46 # How it works:
47 47 # To retrieve a revision, we need to know the offset of the revision in
48 48 # the bundle (an unbundle object). We store this offset in the index
49 49 # (start). The base of the delta is stored in the base field.
50 50 #
51 51 # To differentiate a rev in the bundle from a rev in the revlog, we
52 52 # check revision against repotiprev.
53 53 opener = vfsmod.readonlyvfs(opener)
54 54 revlog.revlog.__init__(self, opener, indexfile)
55 55 self.bundle = cgunpacker
56 56 n = len(self)
57 57 self.repotiprev = n - 1
58 58 self.bundlerevs = set() # used by 'bundle()' revset expression
59 59 for deltadata in cgunpacker.deltaiter():
60 60 node, p1, p2, cs, deltabase, delta, flags = deltadata
61 61
62 62 size = len(delta)
63 63 start = cgunpacker.tell() - size
64 64
65 65 link = linkmapper(cs)
66 66 if node in self.nodemap:
67 67 # this can happen if two branches make the same change
68 68 self.bundlerevs.add(self.nodemap[node])
69 69 continue
70 70
71 71 for p in (p1, p2):
72 72 if p not in self.nodemap:
73 73 raise error.LookupError(p, self.indexfile,
74 74 _("unknown parent"))
75 75
76 76 if deltabase not in self.nodemap:
77 77 raise LookupError(deltabase, self.indexfile,
78 78 _('unknown delta base'))
79 79
80 80 baserev = self.rev(deltabase)
81 81 # start, size, full unc. size, base (unused), link, p1, p2, node
82 82 e = (revlog.offset_type(start, flags), size, -1, baserev, link,
83 83 self.rev(p1), self.rev(p2), node)
84 84 self.index.append(e)
85 85 self.nodemap[node] = n
86 86 self.bundlerevs.add(n)
87 87 n += 1
88 88
89 89 def _chunk(self, rev, df=None):
90 90 # Warning: in case of bundle, the diff is against what we stored as
91 91 # delta base, not against rev - 1
92 92 # XXX: could use some caching
93 93 if rev <= self.repotiprev:
94 94 return revlog.revlog._chunk(self, rev)
95 95 self.bundle.seek(self.start(rev))
96 96 return self.bundle.read(self.length(rev))
97 97
98 98 def revdiff(self, rev1, rev2):
99 99 """return or calculate a delta between two revisions"""
100 100 if rev1 > self.repotiprev and rev2 > self.repotiprev:
101 101 # hot path for bundle
102 102 revb = self.index[rev2][3]
103 103 if revb == rev1:
104 104 return self._chunk(rev2)
105 105 elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
106 106 return revlog.revlog.revdiff(self, rev1, rev2)
107 107
108 108 return mdiff.textdiff(self.revision(rev1, raw=True),
109 109 self.revision(rev2, raw=True))
110 110
111 111 def revision(self, nodeorrev, _df=None, raw=False):
112 112 """return an uncompressed revision of a given node or revision
113 113 number.
114 114 """
115 115 if isinstance(nodeorrev, int):
116 116 rev = nodeorrev
117 117 node = self.node(rev)
118 118 else:
119 119 node = nodeorrev
120 120 rev = self.rev(node)
121 121
122 122 if node == nullid:
123 123 return ""
124 124
125 125 rawtext = None
126 126 chain = []
127 127 iterrev = rev
128 128 # reconstruct the revision if it is from a changegroup
129 129 while iterrev > self.repotiprev:
130 130 if self._revisioncache and self._revisioncache[1] == iterrev:
131 131 rawtext = self._revisioncache[2]
132 132 break
133 133 chain.append(iterrev)
134 134 iterrev = self.index[iterrev][3]
135 135 if rawtext is None:
136 136 rawtext = self.baserevision(iterrev)
137 137
138 138 while chain:
139 139 delta = self._chunk(chain.pop())
140 140 rawtext = mdiff.patches(rawtext, [delta])
141 141
142 142 text, validatehash = self._processflags(rawtext, self.flags(rev),
143 143 'read', raw=raw)
144 144 if validatehash:
145 145 self.checkhash(text, node, rev=rev)
146 146 self._revisioncache = (node, rev, rawtext)
147 147 return text
148 148
149 def rawdata(self, nodeorrev, _df=None):
150 return self.revision(nodeorrev, _df=_df, raw=True)
151
149 152 def baserevision(self, nodeorrev):
150 153 # Revlog subclasses may override 'revision' method to modify format of
151 154 # content retrieved from revlog. To use bundlerevlog with such class one
152 155 # needs to override 'baserevision' and make more specific call here.
153 156 return revlog.revlog.revision(self, nodeorrev, raw=True)
154 157
155 158 def addrevision(self, *args, **kwargs):
156 159 raise NotImplementedError
157 160
158 161 def addgroup(self, *args, **kwargs):
159 162 raise NotImplementedError
160 163
161 164 def strip(self, *args, **kwargs):
162 165 raise NotImplementedError
163 166
164 167 def checksize(self):
165 168 raise NotImplementedError
166 169
167 170 class bundlechangelog(bundlerevlog, changelog.changelog):
168 171 def __init__(self, opener, cgunpacker):
169 172 changelog.changelog.__init__(self, opener)
170 173 linkmapper = lambda x: x
171 174 bundlerevlog.__init__(self, opener, self.indexfile, cgunpacker,
172 175 linkmapper)
173 176
174 177 def baserevision(self, nodeorrev):
175 178 # Although changelog doesn't override 'revision' method, some extensions
176 179 # may replace this class with another that does. Same story with
177 180 # manifest and filelog classes.
178 181
179 182 # This bypasses filtering on changelog.node() and rev() because we need
180 183 # revision text of the bundle base even if it is hidden.
181 184 oldfilter = self.filteredrevs
182 185 try:
183 186 self.filteredrevs = ()
184 187 return changelog.changelog.revision(self, nodeorrev, raw=True)
185 188 finally:
186 189 self.filteredrevs = oldfilter
187 190
188 191 class bundlemanifest(bundlerevlog, manifest.manifestrevlog):
189 192 def __init__(self, opener, cgunpacker, linkmapper, dirlogstarts=None,
190 193 dir=''):
191 194 manifest.manifestrevlog.__init__(self, opener, tree=dir)
192 195 bundlerevlog.__init__(self, opener, self.indexfile, cgunpacker,
193 196 linkmapper)
194 197 if dirlogstarts is None:
195 198 dirlogstarts = {}
196 199 if self.bundle.version == "03":
197 200 dirlogstarts = _getfilestarts(self.bundle)
198 201 self._dirlogstarts = dirlogstarts
199 202 self._linkmapper = linkmapper
200 203
201 204 def baserevision(self, nodeorrev):
202 205 node = nodeorrev
203 206 if isinstance(node, int):
204 207 node = self.node(node)
205 208
206 209 if node in self.fulltextcache:
207 210 result = '%s' % self.fulltextcache[node]
208 211 else:
209 212 result = manifest.manifestrevlog.revision(self, nodeorrev, raw=True)
210 213 return result
211 214
212 215 def dirlog(self, d):
213 216 if d in self._dirlogstarts:
214 217 self.bundle.seek(self._dirlogstarts[d])
215 218 return bundlemanifest(
216 219 self.opener, self.bundle, self._linkmapper,
217 220 self._dirlogstarts, dir=d)
218 221 return super(bundlemanifest, self).dirlog(d)
219 222
220 223 class bundlefilelog(filelog.filelog):
221 224 def __init__(self, opener, path, cgunpacker, linkmapper):
222 225 filelog.filelog.__init__(self, opener, path)
223 226 self._revlog = bundlerevlog(opener, self.indexfile,
224 227 cgunpacker, linkmapper)
225 228
226 229 def baserevision(self, nodeorrev):
227 230 return filelog.filelog.revision(self, nodeorrev, raw=True)
228 231
229 232 class bundlepeer(localrepo.localpeer):
230 233 def canpush(self):
231 234 return False
232 235
233 236 class bundlephasecache(phases.phasecache):
234 237 def __init__(self, *args, **kwargs):
235 238 super(bundlephasecache, self).__init__(*args, **kwargs)
236 239 if util.safehasattr(self, 'opener'):
237 240 self.opener = vfsmod.readonlyvfs(self.opener)
238 241
239 242 def write(self):
240 243 raise NotImplementedError
241 244
242 245 def _write(self, fp):
243 246 raise NotImplementedError
244 247
245 248 def _updateroots(self, phase, newroots, tr):
246 249 self.phaseroots[phase] = newroots
247 250 self.invalidate()
248 251 self.dirty = True
249 252
250 253 def _getfilestarts(cgunpacker):
251 254 filespos = {}
252 255 for chunkdata in iter(cgunpacker.filelogheader, {}):
253 256 fname = chunkdata['filename']
254 257 filespos[fname] = cgunpacker.tell()
255 258 for chunk in iter(lambda: cgunpacker.deltachunk(None), {}):
256 259 pass
257 260 return filespos
258 261
259 262 class bundlerepository(object):
260 263 """A repository instance that is a union of a local repo and a bundle.
261 264
262 265 Instances represent a read-only repository composed of a local repository
263 266 with the contents of a bundle file applied. The repository instance is
264 267 conceptually similar to the state of a repository after an
265 268 ``hg unbundle`` operation. However, the contents of the bundle are never
266 269 applied to the actual base repository.
267 270
268 271 Instances constructed directly are not usable as repository objects.
269 272 Use instance() or makebundlerepository() to create instances.
270 273 """
271 274 def __init__(self, bundlepath, url, tempparent):
272 275 self._tempparent = tempparent
273 276 self._url = url
274 277
275 278 self.ui.setconfig('phases', 'publish', False, 'bundlerepo')
276 279
277 280 self.tempfile = None
278 281 f = util.posixfile(bundlepath, "rb")
279 282 bundle = exchange.readbundle(self.ui, f, bundlepath)
280 283
281 284 if isinstance(bundle, bundle2.unbundle20):
282 285 self._bundlefile = bundle
283 286 self._cgunpacker = None
284 287
285 288 cgpart = None
286 289 for part in bundle.iterparts(seekable=True):
287 290 if part.type == 'changegroup':
288 291 if cgpart:
289 292 raise NotImplementedError("can't process "
290 293 "multiple changegroups")
291 294 cgpart = part
292 295
293 296 self._handlebundle2part(bundle, part)
294 297
295 298 if not cgpart:
296 299 raise error.Abort(_("No changegroups found"))
297 300
298 301 # This is required to placate a later consumer, which expects
299 302 # the payload offset to be at the beginning of the changegroup.
300 303 # We need to do this after the iterparts() generator advances
301 304 # because iterparts() will seek to end of payload after the
302 305 # generator returns control to iterparts().
303 306 cgpart.seek(0, os.SEEK_SET)
304 307
305 308 elif isinstance(bundle, changegroup.cg1unpacker):
306 309 if bundle.compressed():
307 310 f = self._writetempbundle(bundle.read, '.hg10un',
308 311 header='HG10UN')
309 312 bundle = exchange.readbundle(self.ui, f, bundlepath, self.vfs)
310 313
311 314 self._bundlefile = bundle
312 315 self._cgunpacker = bundle
313 316 else:
314 317 raise error.Abort(_('bundle type %s cannot be read') %
315 318 type(bundle))
316 319
317 320 # dict with the mapping 'filename' -> position in the changegroup.
318 321 self._cgfilespos = {}
319 322
320 323 self.firstnewrev = self.changelog.repotiprev + 1
321 324 phases.retractboundary(self, None, phases.draft,
322 325 [ctx.node() for ctx in self[self.firstnewrev:]])
323 326
324 327 def _handlebundle2part(self, bundle, part):
325 328 if part.type != 'changegroup':
326 329 return
327 330
328 331 cgstream = part
329 332 version = part.params.get('version', '01')
330 333 legalcgvers = changegroup.supportedincomingversions(self)
331 334 if version not in legalcgvers:
332 335 msg = _('Unsupported changegroup version: %s')
333 336 raise error.Abort(msg % version)
334 337 if bundle.compressed():
335 338 cgstream = self._writetempbundle(part.read, '.cg%sun' % version)
336 339
337 340 self._cgunpacker = changegroup.getunbundler(version, cgstream, 'UN')
338 341
339 342 def _writetempbundle(self, readfn, suffix, header=''):
340 343 """Write a temporary file to disk
341 344 """
342 345 fdtemp, temp = self.vfs.mkstemp(prefix="hg-bundle-",
343 346 suffix=suffix)
344 347 self.tempfile = temp
345 348
346 349 with os.fdopen(fdtemp, r'wb') as fptemp:
347 350 fptemp.write(header)
348 351 while True:
349 352 chunk = readfn(2**18)
350 353 if not chunk:
351 354 break
352 355 fptemp.write(chunk)
353 356
354 357 return self.vfs.open(self.tempfile, mode="rb")
355 358
356 359 @localrepo.unfilteredpropertycache
357 360 def _phasecache(self):
358 361 return bundlephasecache(self, self._phasedefaults)
359 362
360 363 @localrepo.unfilteredpropertycache
361 364 def changelog(self):
362 365 # consume the header if it exists
363 366 self._cgunpacker.changelogheader()
364 367 c = bundlechangelog(self.svfs, self._cgunpacker)
365 368 self.manstart = self._cgunpacker.tell()
366 369 return c
367 370
368 371 def _refreshchangelog(self):
369 372 # changelog for bundle repo are not filecache, this method is not
370 373 # applicable.
371 374 pass
372 375
373 376 @localrepo.unfilteredpropertycache
374 377 def manifestlog(self):
375 378 self._cgunpacker.seek(self.manstart)
376 379 # consume the header if it exists
377 380 self._cgunpacker.manifestheader()
378 381 linkmapper = self.unfiltered().changelog.rev
379 382 rootstore = bundlemanifest(self.svfs, self._cgunpacker, linkmapper)
380 383 self.filestart = self._cgunpacker.tell()
381 384
382 385 return manifest.manifestlog(self.svfs, self, rootstore,
383 386 self.narrowmatch())
384 387
385 388 def _consumemanifest(self):
386 389 """Consumes the manifest portion of the bundle, setting filestart so the
387 390 file portion can be read."""
388 391 self._cgunpacker.seek(self.manstart)
389 392 self._cgunpacker.manifestheader()
390 393 for delta in self._cgunpacker.deltaiter():
391 394 pass
392 395 self.filestart = self._cgunpacker.tell()
393 396
394 397 @localrepo.unfilteredpropertycache
395 398 def manstart(self):
396 399 self.changelog
397 400 return self.manstart
398 401
399 402 @localrepo.unfilteredpropertycache
400 403 def filestart(self):
401 404 self.manifestlog
402 405
403 406 # If filestart was not set by self.manifestlog, that means the
404 407 # manifestlog implementation did not consume the manifests from the
405 408 # changegroup (ex: it might be consuming trees from a separate bundle2
406 409 # part instead). So we need to manually consume it.
407 410 if r'filestart' not in self.__dict__:
408 411 self._consumemanifest()
409 412
410 413 return self.filestart
411 414
412 415 def url(self):
413 416 return self._url
414 417
415 418 def file(self, f):
416 419 if not self._cgfilespos:
417 420 self._cgunpacker.seek(self.filestart)
418 421 self._cgfilespos = _getfilestarts(self._cgunpacker)
419 422
420 423 if f in self._cgfilespos:
421 424 self._cgunpacker.seek(self._cgfilespos[f])
422 425 linkmapper = self.unfiltered().changelog.rev
423 426 return bundlefilelog(self.svfs, f, self._cgunpacker, linkmapper)
424 427 else:
425 428 return super(bundlerepository, self).file(f)
426 429
427 430 def close(self):
428 431 """Close assigned bundle file immediately."""
429 432 self._bundlefile.close()
430 433 if self.tempfile is not None:
431 434 self.vfs.unlink(self.tempfile)
432 435 if self._tempparent:
433 436 shutil.rmtree(self._tempparent, True)
434 437
435 438 def cancopy(self):
436 439 return False
437 440
438 441 def peer(self):
439 442 return bundlepeer(self)
440 443
441 444 def getcwd(self):
442 445 return encoding.getcwd() # always outside the repo
443 446
444 447 # Check if parents exist in localrepo before setting
445 448 def setparents(self, p1, p2=nullid):
446 449 p1rev = self.changelog.rev(p1)
447 450 p2rev = self.changelog.rev(p2)
448 451 msg = _("setting parent to node %s that only exists in the bundle\n")
449 452 if self.changelog.repotiprev < p1rev:
450 453 self.ui.warn(msg % nodemod.hex(p1))
451 454 if self.changelog.repotiprev < p2rev:
452 455 self.ui.warn(msg % nodemod.hex(p2))
453 456 return super(bundlerepository, self).setparents(p1, p2)
454 457
455 458 def instance(ui, path, create, intents=None, createopts=None):
456 459 if create:
457 460 raise error.Abort(_('cannot create new bundle repository'))
458 461 # internal config: bundle.mainreporoot
459 462 parentpath = ui.config("bundle", "mainreporoot")
460 463 if not parentpath:
461 464 # try to find the correct path to the working directory repo
462 465 parentpath = cmdutil.findrepo(encoding.getcwd())
463 466 if parentpath is None:
464 467 parentpath = ''
465 468 if parentpath:
466 469 # Try to make the full path relative so we get a nice, short URL.
467 470 # In particular, we don't want temp dir names in test outputs.
468 471 cwd = encoding.getcwd()
469 472 if parentpath == cwd:
470 473 parentpath = ''
471 474 else:
472 475 cwd = pathutil.normasprefix(cwd)
473 476 if parentpath.startswith(cwd):
474 477 parentpath = parentpath[len(cwd):]
475 478 u = util.url(path)
476 479 path = u.localpath()
477 480 if u.scheme == 'bundle':
478 481 s = path.split("+", 1)
479 482 if len(s) == 1:
480 483 repopath, bundlename = parentpath, s[0]
481 484 else:
482 485 repopath, bundlename = s
483 486 else:
484 487 repopath, bundlename = parentpath, path
485 488
486 489 return makebundlerepository(ui, repopath, bundlename)
487 490
488 491 def makebundlerepository(ui, repopath, bundlepath):
489 492 """Make a bundle repository object based on repo and bundle paths."""
490 493 if repopath:
491 494 url = 'bundle:%s+%s' % (util.expandpath(repopath), bundlepath)
492 495 else:
493 496 url = 'bundle:%s' % bundlepath
494 497
495 498 # Because we can't make any guarantees about the type of the base
496 499 # repository, we can't have a static class representing the bundle
497 500 # repository. We also can't make any guarantees about how to even
498 501 # call the base repository's constructor!
499 502 #
500 503 # So, our strategy is to go through ``localrepo.instance()`` to construct
501 504 # a repo instance. Then, we dynamically create a new type derived from
502 505 # both it and our ``bundlerepository`` class which overrides some
503 506 # functionality. We then change the type of the constructed repository
504 507 # to this new type and initialize the bundle-specific bits of it.
505 508
506 509 try:
507 510 repo = localrepo.instance(ui, repopath, create=False)
508 511 tempparent = None
509 512 except error.RepoError:
510 513 tempparent = pycompat.mkdtemp()
511 514 try:
512 515 repo = localrepo.instance(ui, tempparent, create=True)
513 516 except Exception:
514 517 shutil.rmtree(tempparent)
515 518 raise
516 519
517 520 class derivedbundlerepository(bundlerepository, repo.__class__):
518 521 pass
519 522
520 523 repo.__class__ = derivedbundlerepository
521 524 bundlerepository.__init__(repo, bundlepath, url, tempparent)
522 525
523 526 return repo
524 527
525 528 class bundletransactionmanager(object):
526 529 def transaction(self):
527 530 return None
528 531
529 532 def close(self):
530 533 raise NotImplementedError
531 534
532 535 def release(self):
533 536 raise NotImplementedError
534 537
535 538 def getremotechanges(ui, repo, peer, onlyheads=None, bundlename=None,
536 539 force=False):
537 540 '''obtains a bundle of changes incoming from peer
538 541
539 542 "onlyheads" restricts the returned changes to those reachable from the
540 543 specified heads.
541 544 "bundlename", if given, stores the bundle to this file path permanently;
542 545 otherwise it's stored to a temp file and gets deleted again when you call
543 546 the returned "cleanupfn".
544 547 "force" indicates whether to proceed on unrelated repos.
545 548
546 549 Returns a tuple (local, csets, cleanupfn):
547 550
548 551 "local" is a local repo from which to obtain the actual incoming
549 552 changesets; it is a bundlerepo for the obtained bundle when the
550 553 original "peer" is remote.
551 554 "csets" lists the incoming changeset node ids.
552 555 "cleanupfn" must be called without arguments when you're done processing
553 556 the changes; it closes both the original "peer" and the one returned
554 557 here.
555 558 '''
556 559 tmp = discovery.findcommonincoming(repo, peer, heads=onlyheads,
557 560 force=force)
558 561 common, incoming, rheads = tmp
559 562 if not incoming:
560 563 try:
561 564 if bundlename:
562 565 os.unlink(bundlename)
563 566 except OSError:
564 567 pass
565 568 return repo, [], peer.close
566 569
567 570 commonset = set(common)
568 571 rheads = [x for x in rheads if x not in commonset]
569 572
570 573 bundle = None
571 574 bundlerepo = None
572 575 localrepo = peer.local()
573 576 if bundlename or not localrepo:
574 577 # create a bundle (uncompressed if peer repo is not local)
575 578
576 579 # developer config: devel.legacy.exchange
577 580 legexc = ui.configlist('devel', 'legacy.exchange')
578 581 forcebundle1 = 'bundle2' not in legexc and 'bundle1' in legexc
579 582 canbundle2 = (not forcebundle1
580 583 and peer.capable('getbundle')
581 584 and peer.capable('bundle2'))
582 585 if canbundle2:
583 586 with peer.commandexecutor() as e:
584 587 b2 = e.callcommand('getbundle', {
585 588 'source': 'incoming',
586 589 'common': common,
587 590 'heads': rheads,
588 591 'bundlecaps': exchange.caps20to10(repo, role='client'),
589 592 'cg': True,
590 593 }).result()
591 594
592 595 fname = bundle = changegroup.writechunks(ui,
593 596 b2._forwardchunks(),
594 597 bundlename)
595 598 else:
596 599 if peer.capable('getbundle'):
597 600 with peer.commandexecutor() as e:
598 601 cg = e.callcommand('getbundle', {
599 602 'source': 'incoming',
600 603 'common': common,
601 604 'heads': rheads,
602 605 }).result()
603 606 elif onlyheads is None and not peer.capable('changegroupsubset'):
604 607 # compat with older servers when pulling all remote heads
605 608
606 609 with peer.commandexecutor() as e:
607 610 cg = e.callcommand('changegroup', {
608 611 'nodes': incoming,
609 612 'source': 'incoming',
610 613 }).result()
611 614
612 615 rheads = None
613 616 else:
614 617 with peer.commandexecutor() as e:
615 618 cg = e.callcommand('changegroupsubset', {
616 619 'bases': incoming,
617 620 'heads': rheads,
618 621 'source': 'incoming',
619 622 }).result()
620 623
621 624 if localrepo:
622 625 bundletype = "HG10BZ"
623 626 else:
624 627 bundletype = "HG10UN"
625 628 fname = bundle = bundle2.writebundle(ui, cg, bundlename,
626 629 bundletype)
627 630 # keep written bundle?
628 631 if bundlename:
629 632 bundle = None
630 633 if not localrepo:
631 634 # use the created uncompressed bundlerepo
632 635 localrepo = bundlerepo = makebundlerepository(repo. baseui,
633 636 repo.root,
634 637 fname)
635 638
636 639 # this repo contains local and peer now, so filter out local again
637 640 common = repo.heads()
638 641 if localrepo:
639 642 # Part of common may be remotely filtered
640 643 # So use an unfiltered version
641 644 # The discovery process probably need cleanup to avoid that
642 645 localrepo = localrepo.unfiltered()
643 646
644 647 csets = localrepo.changelog.findmissing(common, rheads)
645 648
646 649 if bundlerepo:
647 650 reponodes = [ctx.node() for ctx in bundlerepo[bundlerepo.firstnewrev:]]
648 651
649 652 with peer.commandexecutor() as e:
650 653 remotephases = e.callcommand('listkeys', {
651 654 'namespace': 'phases',
652 655 }).result()
653 656
654 657 pullop = exchange.pulloperation(bundlerepo, peer, heads=reponodes)
655 658 pullop.trmanager = bundletransactionmanager()
656 659 exchange._pullapplyphases(pullop, remotephases)
657 660
658 661 def cleanup():
659 662 if bundlerepo:
660 663 bundlerepo.close()
661 664 if bundle:
662 665 os.unlink(bundle)
663 666 peer.close()
664 667
665 668 return (localrepo, csets, cleanup)
General Comments 0
You need to be logged in to leave comments. Login now