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