##// END OF EJS Templates
changegroup: change topics during generation...
Gregory Szorc -
r39275:0617a700 default
parent child Browse files
Show More
@@ -1,1394 +1,1394 b''
1 1 # changegroup.py - Mercurial changegroup manipulation functions
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.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 from __future__ import absolute_import
9 9
10 10 import os
11 11 import struct
12 12 import weakref
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 hex,
17 17 nullid,
18 18 nullrev,
19 19 short,
20 20 )
21 21
22 22 from .thirdparty import (
23 23 attr,
24 24 )
25 25
26 26 from . import (
27 27 dagop,
28 28 error,
29 29 match as matchmod,
30 30 mdiff,
31 31 phases,
32 32 pycompat,
33 33 repository,
34 34 util,
35 35 )
36 36
37 37 from .utils import (
38 38 interfaceutil,
39 39 stringutil,
40 40 )
41 41
42 42 _CHANGEGROUPV1_DELTA_HEADER = struct.Struct("20s20s20s20s")
43 43 _CHANGEGROUPV2_DELTA_HEADER = struct.Struct("20s20s20s20s20s")
44 44 _CHANGEGROUPV3_DELTA_HEADER = struct.Struct(">20s20s20s20s20sH")
45 45
46 46 LFS_REQUIREMENT = 'lfs'
47 47
48 48 readexactly = util.readexactly
49 49
50 50 def getchunk(stream):
51 51 """return the next chunk from stream as a string"""
52 52 d = readexactly(stream, 4)
53 53 l = struct.unpack(">l", d)[0]
54 54 if l <= 4:
55 55 if l:
56 56 raise error.Abort(_("invalid chunk length %d") % l)
57 57 return ""
58 58 return readexactly(stream, l - 4)
59 59
60 60 def chunkheader(length):
61 61 """return a changegroup chunk header (string)"""
62 62 return struct.pack(">l", length + 4)
63 63
64 64 def closechunk():
65 65 """return a changegroup chunk header (string) for a zero-length chunk"""
66 66 return struct.pack(">l", 0)
67 67
68 68 def _fileheader(path):
69 69 """Obtain a changegroup chunk header for a named path."""
70 70 return chunkheader(len(path)) + path
71 71
72 72 def writechunks(ui, chunks, filename, vfs=None):
73 73 """Write chunks to a file and return its filename.
74 74
75 75 The stream is assumed to be a bundle file.
76 76 Existing files will not be overwritten.
77 77 If no filename is specified, a temporary file is created.
78 78 """
79 79 fh = None
80 80 cleanup = None
81 81 try:
82 82 if filename:
83 83 if vfs:
84 84 fh = vfs.open(filename, "wb")
85 85 else:
86 86 # Increase default buffer size because default is usually
87 87 # small (4k is common on Linux).
88 88 fh = open(filename, "wb", 131072)
89 89 else:
90 90 fd, filename = pycompat.mkstemp(prefix="hg-bundle-", suffix=".hg")
91 91 fh = os.fdopen(fd, r"wb")
92 92 cleanup = filename
93 93 for c in chunks:
94 94 fh.write(c)
95 95 cleanup = None
96 96 return filename
97 97 finally:
98 98 if fh is not None:
99 99 fh.close()
100 100 if cleanup is not None:
101 101 if filename and vfs:
102 102 vfs.unlink(cleanup)
103 103 else:
104 104 os.unlink(cleanup)
105 105
106 106 class cg1unpacker(object):
107 107 """Unpacker for cg1 changegroup streams.
108 108
109 109 A changegroup unpacker handles the framing of the revision data in
110 110 the wire format. Most consumers will want to use the apply()
111 111 method to add the changes from the changegroup to a repository.
112 112
113 113 If you're forwarding a changegroup unmodified to another consumer,
114 114 use getchunks(), which returns an iterator of changegroup
115 115 chunks. This is mostly useful for cases where you need to know the
116 116 data stream has ended by observing the end of the changegroup.
117 117
118 118 deltachunk() is useful only if you're applying delta data. Most
119 119 consumers should prefer apply() instead.
120 120
121 121 A few other public methods exist. Those are used only for
122 122 bundlerepo and some debug commands - their use is discouraged.
123 123 """
124 124 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
125 125 deltaheadersize = deltaheader.size
126 126 version = '01'
127 127 _grouplistcount = 1 # One list of files after the manifests
128 128
129 129 def __init__(self, fh, alg, extras=None):
130 130 if alg is None:
131 131 alg = 'UN'
132 132 if alg not in util.compengines.supportedbundletypes:
133 133 raise error.Abort(_('unknown stream compression type: %s')
134 134 % alg)
135 135 if alg == 'BZ':
136 136 alg = '_truncatedBZ'
137 137
138 138 compengine = util.compengines.forbundletype(alg)
139 139 self._stream = compengine.decompressorreader(fh)
140 140 self._type = alg
141 141 self.extras = extras or {}
142 142 self.callback = None
143 143
144 144 # These methods (compressed, read, seek, tell) all appear to only
145 145 # be used by bundlerepo, but it's a little hard to tell.
146 146 def compressed(self):
147 147 return self._type is not None and self._type != 'UN'
148 148 def read(self, l):
149 149 return self._stream.read(l)
150 150 def seek(self, pos):
151 151 return self._stream.seek(pos)
152 152 def tell(self):
153 153 return self._stream.tell()
154 154 def close(self):
155 155 return self._stream.close()
156 156
157 157 def _chunklength(self):
158 158 d = readexactly(self._stream, 4)
159 159 l = struct.unpack(">l", d)[0]
160 160 if l <= 4:
161 161 if l:
162 162 raise error.Abort(_("invalid chunk length %d") % l)
163 163 return 0
164 164 if self.callback:
165 165 self.callback()
166 166 return l - 4
167 167
168 168 def changelogheader(self):
169 169 """v10 does not have a changelog header chunk"""
170 170 return {}
171 171
172 172 def manifestheader(self):
173 173 """v10 does not have a manifest header chunk"""
174 174 return {}
175 175
176 176 def filelogheader(self):
177 177 """return the header of the filelogs chunk, v10 only has the filename"""
178 178 l = self._chunklength()
179 179 if not l:
180 180 return {}
181 181 fname = readexactly(self._stream, l)
182 182 return {'filename': fname}
183 183
184 184 def _deltaheader(self, headertuple, prevnode):
185 185 node, p1, p2, cs = headertuple
186 186 if prevnode is None:
187 187 deltabase = p1
188 188 else:
189 189 deltabase = prevnode
190 190 flags = 0
191 191 return node, p1, p2, deltabase, cs, flags
192 192
193 193 def deltachunk(self, prevnode):
194 194 l = self._chunklength()
195 195 if not l:
196 196 return {}
197 197 headerdata = readexactly(self._stream, self.deltaheadersize)
198 198 header = self.deltaheader.unpack(headerdata)
199 199 delta = readexactly(self._stream, l - self.deltaheadersize)
200 200 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode)
201 201 return (node, p1, p2, cs, deltabase, delta, flags)
202 202
203 203 def getchunks(self):
204 204 """returns all the chunks contains in the bundle
205 205
206 206 Used when you need to forward the binary stream to a file or another
207 207 network API. To do so, it parse the changegroup data, otherwise it will
208 208 block in case of sshrepo because it don't know the end of the stream.
209 209 """
210 210 # For changegroup 1 and 2, we expect 3 parts: changelog, manifestlog,
211 211 # and a list of filelogs. For changegroup 3, we expect 4 parts:
212 212 # changelog, manifestlog, a list of tree manifestlogs, and a list of
213 213 # filelogs.
214 214 #
215 215 # Changelog and manifestlog parts are terminated with empty chunks. The
216 216 # tree and file parts are a list of entry sections. Each entry section
217 217 # is a series of chunks terminating in an empty chunk. The list of these
218 218 # entry sections is terminated in yet another empty chunk, so we know
219 219 # we've reached the end of the tree/file list when we reach an empty
220 220 # chunk that was proceeded by no non-empty chunks.
221 221
222 222 parts = 0
223 223 while parts < 2 + self._grouplistcount:
224 224 noentries = True
225 225 while True:
226 226 chunk = getchunk(self)
227 227 if not chunk:
228 228 # The first two empty chunks represent the end of the
229 229 # changelog and the manifestlog portions. The remaining
230 230 # empty chunks represent either A) the end of individual
231 231 # tree or file entries in the file list, or B) the end of
232 232 # the entire list. It's the end of the entire list if there
233 233 # were no entries (i.e. noentries is True).
234 234 if parts < 2:
235 235 parts += 1
236 236 elif noentries:
237 237 parts += 1
238 238 break
239 239 noentries = False
240 240 yield chunkheader(len(chunk))
241 241 pos = 0
242 242 while pos < len(chunk):
243 243 next = pos + 2**20
244 244 yield chunk[pos:next]
245 245 pos = next
246 246 yield closechunk()
247 247
248 248 def _unpackmanifests(self, repo, revmap, trp, prog):
249 249 self.callback = prog.increment
250 250 # no need to check for empty manifest group here:
251 251 # if the result of the merge of 1 and 2 is the same in 3 and 4,
252 252 # no new manifest will be created and the manifest group will
253 253 # be empty during the pull
254 254 self.manifestheader()
255 255 deltas = self.deltaiter()
256 256 repo.manifestlog.addgroup(deltas, revmap, trp)
257 257 prog.complete()
258 258 self.callback = None
259 259
260 260 def apply(self, repo, tr, srctype, url, targetphase=phases.draft,
261 261 expectedtotal=None):
262 262 """Add the changegroup returned by source.read() to this repo.
263 263 srctype is a string like 'push', 'pull', or 'unbundle'. url is
264 264 the URL of the repo where this changegroup is coming from.
265 265
266 266 Return an integer summarizing the change to this repo:
267 267 - nothing changed or no source: 0
268 268 - more heads than before: 1+added heads (2..n)
269 269 - fewer heads than before: -1-removed heads (-2..-n)
270 270 - number of heads stays the same: 1
271 271 """
272 272 repo = repo.unfiltered()
273 273 def csmap(x):
274 274 repo.ui.debug("add changeset %s\n" % short(x))
275 275 return len(cl)
276 276
277 277 def revmap(x):
278 278 return cl.rev(x)
279 279
280 280 changesets = files = revisions = 0
281 281
282 282 try:
283 283 # The transaction may already carry source information. In this
284 284 # case we use the top level data. We overwrite the argument
285 285 # because we need to use the top level value (if they exist)
286 286 # in this function.
287 287 srctype = tr.hookargs.setdefault('source', srctype)
288 288 url = tr.hookargs.setdefault('url', url)
289 289 repo.hook('prechangegroup',
290 290 throw=True, **pycompat.strkwargs(tr.hookargs))
291 291
292 292 # write changelog data to temp files so concurrent readers
293 293 # will not see an inconsistent view
294 294 cl = repo.changelog
295 295 cl.delayupdate(tr)
296 296 oldheads = set(cl.heads())
297 297
298 298 trp = weakref.proxy(tr)
299 299 # pull off the changeset group
300 300 repo.ui.status(_("adding changesets\n"))
301 301 clstart = len(cl)
302 302 progress = repo.ui.makeprogress(_('changesets'), unit=_('chunks'),
303 303 total=expectedtotal)
304 304 self.callback = progress.increment
305 305
306 306 efiles = set()
307 307 def onchangelog(cl, node):
308 308 efiles.update(cl.readfiles(node))
309 309
310 310 self.changelogheader()
311 311 deltas = self.deltaiter()
312 312 cgnodes = cl.addgroup(deltas, csmap, trp, addrevisioncb=onchangelog)
313 313 efiles = len(efiles)
314 314
315 315 if not cgnodes:
316 316 repo.ui.develwarn('applied empty changegroup',
317 317 config='warn-empty-changegroup')
318 318 clend = len(cl)
319 319 changesets = clend - clstart
320 320 progress.complete()
321 321 self.callback = None
322 322
323 323 # pull off the manifest group
324 324 repo.ui.status(_("adding manifests\n"))
325 325 # We know that we'll never have more manifests than we had
326 326 # changesets.
327 327 progress = repo.ui.makeprogress(_('manifests'), unit=_('chunks'),
328 328 total=changesets)
329 329 self._unpackmanifests(repo, revmap, trp, progress)
330 330
331 331 needfiles = {}
332 332 if repo.ui.configbool('server', 'validate'):
333 333 cl = repo.changelog
334 334 ml = repo.manifestlog
335 335 # validate incoming csets have their manifests
336 336 for cset in pycompat.xrange(clstart, clend):
337 337 mfnode = cl.changelogrevision(cset).manifest
338 338 mfest = ml[mfnode].readdelta()
339 339 # store file cgnodes we must see
340 340 for f, n in mfest.iteritems():
341 341 needfiles.setdefault(f, set()).add(n)
342 342
343 343 # process the files
344 344 repo.ui.status(_("adding file changes\n"))
345 345 newrevs, newfiles = _addchangegroupfiles(
346 346 repo, self, revmap, trp, efiles, needfiles)
347 347 revisions += newrevs
348 348 files += newfiles
349 349
350 350 deltaheads = 0
351 351 if oldheads:
352 352 heads = cl.heads()
353 353 deltaheads = len(heads) - len(oldheads)
354 354 for h in heads:
355 355 if h not in oldheads and repo[h].closesbranch():
356 356 deltaheads -= 1
357 357 htext = ""
358 358 if deltaheads:
359 359 htext = _(" (%+d heads)") % deltaheads
360 360
361 361 repo.ui.status(_("added %d changesets"
362 362 " with %d changes to %d files%s\n")
363 363 % (changesets, revisions, files, htext))
364 364 repo.invalidatevolatilesets()
365 365
366 366 if changesets > 0:
367 367 if 'node' not in tr.hookargs:
368 368 tr.hookargs['node'] = hex(cl.node(clstart))
369 369 tr.hookargs['node_last'] = hex(cl.node(clend - 1))
370 370 hookargs = dict(tr.hookargs)
371 371 else:
372 372 hookargs = dict(tr.hookargs)
373 373 hookargs['node'] = hex(cl.node(clstart))
374 374 hookargs['node_last'] = hex(cl.node(clend - 1))
375 375 repo.hook('pretxnchangegroup',
376 376 throw=True, **pycompat.strkwargs(hookargs))
377 377
378 378 added = [cl.node(r) for r in pycompat.xrange(clstart, clend)]
379 379 phaseall = None
380 380 if srctype in ('push', 'serve'):
381 381 # Old servers can not push the boundary themselves.
382 382 # New servers won't push the boundary if changeset already
383 383 # exists locally as secret
384 384 #
385 385 # We should not use added here but the list of all change in
386 386 # the bundle
387 387 if repo.publishing():
388 388 targetphase = phaseall = phases.public
389 389 else:
390 390 # closer target phase computation
391 391
392 392 # Those changesets have been pushed from the
393 393 # outside, their phases are going to be pushed
394 394 # alongside. Therefor `targetphase` is
395 395 # ignored.
396 396 targetphase = phaseall = phases.draft
397 397 if added:
398 398 phases.registernew(repo, tr, targetphase, added)
399 399 if phaseall is not None:
400 400 phases.advanceboundary(repo, tr, phaseall, cgnodes)
401 401
402 402 if changesets > 0:
403 403
404 404 def runhooks():
405 405 # These hooks run when the lock releases, not when the
406 406 # transaction closes. So it's possible for the changelog
407 407 # to have changed since we last saw it.
408 408 if clstart >= len(repo):
409 409 return
410 410
411 411 repo.hook("changegroup", **pycompat.strkwargs(hookargs))
412 412
413 413 for n in added:
414 414 args = hookargs.copy()
415 415 args['node'] = hex(n)
416 416 del args['node_last']
417 417 repo.hook("incoming", **pycompat.strkwargs(args))
418 418
419 419 newheads = [h for h in repo.heads()
420 420 if h not in oldheads]
421 421 repo.ui.log("incoming",
422 422 "%d incoming changes - new heads: %s\n",
423 423 len(added),
424 424 ', '.join([hex(c[:6]) for c in newheads]))
425 425
426 426 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
427 427 lambda tr: repo._afterlock(runhooks))
428 428 finally:
429 429 repo.ui.flush()
430 430 # never return 0 here:
431 431 if deltaheads < 0:
432 432 ret = deltaheads - 1
433 433 else:
434 434 ret = deltaheads + 1
435 435 return ret
436 436
437 437 def deltaiter(self):
438 438 """
439 439 returns an iterator of the deltas in this changegroup
440 440
441 441 Useful for passing to the underlying storage system to be stored.
442 442 """
443 443 chain = None
444 444 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
445 445 # Chunkdata: (node, p1, p2, cs, deltabase, delta, flags)
446 446 yield chunkdata
447 447 chain = chunkdata[0]
448 448
449 449 class cg2unpacker(cg1unpacker):
450 450 """Unpacker for cg2 streams.
451 451
452 452 cg2 streams add support for generaldelta, so the delta header
453 453 format is slightly different. All other features about the data
454 454 remain the same.
455 455 """
456 456 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
457 457 deltaheadersize = deltaheader.size
458 458 version = '02'
459 459
460 460 def _deltaheader(self, headertuple, prevnode):
461 461 node, p1, p2, deltabase, cs = headertuple
462 462 flags = 0
463 463 return node, p1, p2, deltabase, cs, flags
464 464
465 465 class cg3unpacker(cg2unpacker):
466 466 """Unpacker for cg3 streams.
467 467
468 468 cg3 streams add support for exchanging treemanifests and revlog
469 469 flags. It adds the revlog flags to the delta header and an empty chunk
470 470 separating manifests and files.
471 471 """
472 472 deltaheader = _CHANGEGROUPV3_DELTA_HEADER
473 473 deltaheadersize = deltaheader.size
474 474 version = '03'
475 475 _grouplistcount = 2 # One list of manifests and one list of files
476 476
477 477 def _deltaheader(self, headertuple, prevnode):
478 478 node, p1, p2, deltabase, cs, flags = headertuple
479 479 return node, p1, p2, deltabase, cs, flags
480 480
481 481 def _unpackmanifests(self, repo, revmap, trp, prog):
482 482 super(cg3unpacker, self)._unpackmanifests(repo, revmap, trp, prog)
483 483 for chunkdata in iter(self.filelogheader, {}):
484 484 # If we get here, there are directory manifests in the changegroup
485 485 d = chunkdata["filename"]
486 486 repo.ui.debug("adding %s revisions\n" % d)
487 487 dirlog = repo.manifestlog._revlog.dirlog(d)
488 488 deltas = self.deltaiter()
489 489 if not dirlog.addgroup(deltas, revmap, trp):
490 490 raise error.Abort(_("received dir revlog group is empty"))
491 491
492 492 class headerlessfixup(object):
493 493 def __init__(self, fh, h):
494 494 self._h = h
495 495 self._fh = fh
496 496 def read(self, n):
497 497 if self._h:
498 498 d, self._h = self._h[:n], self._h[n:]
499 499 if len(d) < n:
500 500 d += readexactly(self._fh, n - len(d))
501 501 return d
502 502 return readexactly(self._fh, n)
503 503
504 504 @interfaceutil.implementer(repository.irevisiondeltarequest)
505 505 @attr.s(slots=True, frozen=True)
506 506 class revisiondeltarequest(object):
507 507 node = attr.ib()
508 508 linknode = attr.ib()
509 509 p1node = attr.ib()
510 510 p2node = attr.ib()
511 511 basenode = attr.ib()
512 512 ellipsis = attr.ib(default=False)
513 513
514 514 def _revisiondeltatochunks(delta, headerfn):
515 515 """Serialize a revisiondelta to changegroup chunks."""
516 516
517 517 # The captured revision delta may be encoded as a delta against
518 518 # a base revision or as a full revision. The changegroup format
519 519 # requires that everything on the wire be deltas. So for full
520 520 # revisions, we need to invent a header that says to rewrite
521 521 # data.
522 522
523 523 if delta.delta is not None:
524 524 prefix, data = b'', delta.delta
525 525 elif delta.basenode == nullid:
526 526 data = delta.revision
527 527 prefix = mdiff.trivialdiffheader(len(data))
528 528 else:
529 529 data = delta.revision
530 530 prefix = mdiff.replacediffheader(delta.baserevisionsize,
531 531 len(data))
532 532
533 533 meta = headerfn(delta)
534 534
535 535 yield chunkheader(len(meta) + len(prefix) + len(data))
536 536 yield meta
537 537 if prefix:
538 538 yield prefix
539 539 yield data
540 540
541 541 def _sortnodesnormal(store, nodes, reorder):
542 542 """Sort nodes for changegroup generation and turn into revnums."""
543 543 # for generaldelta revlogs, we linearize the revs; this will both be
544 544 # much quicker and generate a much smaller bundle
545 545 if (store._generaldelta and reorder is None) or reorder:
546 546 revs = set(store.rev(n) for n in nodes)
547 547 return dagop.linearize(revs, store.parentrevs)
548 548 else:
549 549 return sorted([store.rev(n) for n in nodes])
550 550
551 551 def _sortnodesellipsis(store, nodes, cl, lookup):
552 552 """Sort nodes for changegroup generation and turn into revnums."""
553 553 # Ellipses serving mode.
554 554 #
555 555 # In a perfect world, we'd generate better ellipsis-ified graphs
556 556 # for non-changelog revlogs. In practice, we haven't started doing
557 557 # that yet, so the resulting DAGs for the manifestlog and filelogs
558 558 # are actually full of bogus parentage on all the ellipsis
559 559 # nodes. This has the side effect that, while the contents are
560 560 # correct, the individual DAGs might be completely out of whack in
561 561 # a case like 882681bc3166 and its ancestors (back about 10
562 562 # revisions or so) in the main hg repo.
563 563 #
564 564 # The one invariant we *know* holds is that the new (potentially
565 565 # bogus) DAG shape will be valid if we order the nodes in the
566 566 # order that they're introduced in dramatis personae by the
567 567 # changelog, so what we do is we sort the non-changelog histories
568 568 # by the order in which they are used by the changelog.
569 569 key = lambda n: cl.rev(lookup(n))
570 570 return [store.rev(n) for n in sorted(nodes, key=key)]
571 571
572 572 def _makenarrowdeltarequest(cl, store, ischangelog, rev, node, linkrev,
573 573 linknode, clrevtolocalrev, fullclnodes,
574 574 precomputedellipsis):
575 575 linkparents = precomputedellipsis[linkrev]
576 576 def local(clrev):
577 577 """Turn a changelog revnum into a local revnum.
578 578
579 579 The ellipsis dag is stored as revnums on the changelog,
580 580 but when we're producing ellipsis entries for
581 581 non-changelog revlogs, we need to turn those numbers into
582 582 something local. This does that for us, and during the
583 583 changelog sending phase will also expand the stored
584 584 mappings as needed.
585 585 """
586 586 if clrev == nullrev:
587 587 return nullrev
588 588
589 589 if ischangelog:
590 590 return clrev
591 591
592 592 # Walk the ellipsis-ized changelog breadth-first looking for a
593 593 # change that has been linked from the current revlog.
594 594 #
595 595 # For a flat manifest revlog only a single step should be necessary
596 596 # as all relevant changelog entries are relevant to the flat
597 597 # manifest.
598 598 #
599 599 # For a filelog or tree manifest dirlog however not every changelog
600 600 # entry will have been relevant, so we need to skip some changelog
601 601 # nodes even after ellipsis-izing.
602 602 walk = [clrev]
603 603 while walk:
604 604 p = walk[0]
605 605 walk = walk[1:]
606 606 if p in clrevtolocalrev:
607 607 return clrevtolocalrev[p]
608 608 elif p in fullclnodes:
609 609 walk.extend([pp for pp in cl.parentrevs(p)
610 610 if pp != nullrev])
611 611 elif p in precomputedellipsis:
612 612 walk.extend([pp for pp in precomputedellipsis[p]
613 613 if pp != nullrev])
614 614 else:
615 615 # In this case, we've got an ellipsis with parents
616 616 # outside the current bundle (likely an
617 617 # incremental pull). We "know" that we can use the
618 618 # value of this same revlog at whatever revision
619 619 # is pointed to by linknode. "Know" is in scare
620 620 # quotes because I haven't done enough examination
621 621 # of edge cases to convince myself this is really
622 622 # a fact - it works for all the (admittedly
623 623 # thorough) cases in our testsuite, but I would be
624 624 # somewhat unsurprised to find a case in the wild
625 625 # where this breaks down a bit. That said, I don't
626 626 # know if it would hurt anything.
627 627 for i in pycompat.xrange(rev, 0, -1):
628 628 if store.linkrev(i) == clrev:
629 629 return i
630 630 # We failed to resolve a parent for this node, so
631 631 # we crash the changegroup construction.
632 632 raise error.Abort(
633 633 'unable to resolve parent while packing %r %r'
634 634 ' for changeset %r' % (store.indexfile, rev, clrev))
635 635
636 636 return nullrev
637 637
638 638 if not linkparents or (
639 639 store.parentrevs(rev) == (nullrev, nullrev)):
640 640 p1, p2 = nullrev, nullrev
641 641 elif len(linkparents) == 1:
642 642 p1, = sorted(local(p) for p in linkparents)
643 643 p2 = nullrev
644 644 else:
645 645 p1, p2 = sorted(local(p) for p in linkparents)
646 646
647 647 p1node, p2node = store.node(p1), store.node(p2)
648 648
649 649 # TODO: try and actually send deltas for ellipsis data blocks
650 650 return revisiondeltarequest(
651 651 node=node,
652 652 p1node=p1node,
653 653 p2node=p2node,
654 654 linknode=linknode,
655 655 basenode=nullid,
656 656 ellipsis=True,
657 657 )
658 658
659 659 def deltagroup(repo, store, nodes, ischangelog, lookup, forcedeltaparentprev,
660 660 allowreorder,
661 units=None,
661 topic=None,
662 662 ellipses=False, clrevtolocalrev=None, fullclnodes=None,
663 663 precomputedellipsis=None):
664 664 """Calculate deltas for a set of revisions.
665 665
666 666 Is a generator of ``revisiondelta`` instances.
667 667
668 If units is not None, progress detail will be generated, units specifies
669 the type of revlog that is touched (changelog, manifest, etc.).
668 If topic is not None, progress detail will be generated using this
669 topic name (e.g. changesets, manifests, etc).
670 670 """
671 671 if not nodes:
672 672 return
673 673
674 674 # We perform two passes over the revisions whose data we will emit.
675 675 #
676 676 # In the first pass, we obtain information about the deltas that will
677 677 # be generated. This involves computing linknodes and adjusting the
678 678 # request to take shallow fetching into account. The end result of
679 679 # this pass is a list of "request" objects stating which deltas
680 680 # to obtain.
681 681 #
682 682 # The second pass is simply resolving the requested deltas.
683 683
684 684 cl = repo.changelog
685 685
686 686 if ischangelog:
687 687 # Changelog doesn't benefit from reordering revisions. So send
688 688 # out revisions in store order.
689 689 # TODO the API would be cleaner if this were controlled by the
690 690 # store producing the deltas.
691 691 revs = sorted(cl.rev(n) for n in nodes)
692 692 elif ellipses:
693 693 revs = _sortnodesellipsis(store, nodes, cl, lookup)
694 694 else:
695 695 revs = _sortnodesnormal(store, nodes, allowreorder)
696 696
697 697 # In the first pass, collect info about the deltas we'll be
698 698 # generating.
699 699 requests = []
700 700
701 701 # Add the parent of the first rev.
702 702 revs.insert(0, store.parentrevs(revs[0])[0])
703 703
704 704 for i in pycompat.xrange(len(revs) - 1):
705 705 prev = revs[i]
706 706 curr = revs[i + 1]
707 707
708 708 node = store.node(curr)
709 709 linknode = lookup(node)
710 710 p1node, p2node = store.parents(node)
711 711
712 712 if ellipses:
713 713 linkrev = cl.rev(linknode)
714 714 clrevtolocalrev[linkrev] = curr
715 715
716 716 # This is a node to send in full, because the changeset it
717 717 # corresponds to was a full changeset.
718 718 if linknode in fullclnodes:
719 719 requests.append(revisiondeltarequest(
720 720 node=node,
721 721 p1node=p1node,
722 722 p2node=p2node,
723 723 linknode=linknode,
724 724 basenode=None,
725 725 ))
726 726
727 727 elif linkrev not in precomputedellipsis:
728 728 pass
729 729 else:
730 730 requests.append(_makenarrowdeltarequest(
731 731 cl, store, ischangelog, curr, node, linkrev, linknode,
732 732 clrevtolocalrev, fullclnodes,
733 733 precomputedellipsis))
734 734 else:
735 735 requests.append(revisiondeltarequest(
736 736 node=node,
737 737 p1node=p1node,
738 738 p2node=p2node,
739 739 linknode=linknode,
740 740 basenode=store.node(prev) if forcedeltaparentprev else None,
741 741 ))
742 742
743 743 # We expect the first pass to be fast, so we only engage the progress
744 744 # meter for constructing the revision deltas.
745 745 progress = None
746 if units is not None:
747 progress = repo.ui.makeprogress(_('bundling'), unit=units,
746 if topic is not None:
747 progress = repo.ui.makeprogress(topic, unit=_('chunks'),
748 748 total=len(requests))
749 749
750 750 for i, delta in enumerate(store.emitrevisiondeltas(requests)):
751 751 if progress:
752 752 progress.update(i + 1)
753 753
754 754 yield delta
755 755
756 756 if progress:
757 757 progress.complete()
758 758
759 759 class cgpacker(object):
760 760 def __init__(self, repo, filematcher, version, allowreorder,
761 761 builddeltaheader, manifestsend,
762 762 forcedeltaparentprev=False,
763 763 bundlecaps=None, ellipses=False,
764 764 shallow=False, ellipsisroots=None, fullnodes=None):
765 765 """Given a source repo, construct a bundler.
766 766
767 767 filematcher is a matcher that matches on files to include in the
768 768 changegroup. Used to facilitate sparse changegroups.
769 769
770 770 allowreorder controls whether reordering of revisions is allowed.
771 771 This value is used when ``bundle.reorder`` is ``auto`` or isn't
772 772 set.
773 773
774 774 forcedeltaparentprev indicates whether delta parents must be against
775 775 the previous revision in a delta group. This should only be used for
776 776 compatibility with changegroup version 1.
777 777
778 778 builddeltaheader is a callable that constructs the header for a group
779 779 delta.
780 780
781 781 manifestsend is a chunk to send after manifests have been fully emitted.
782 782
783 783 ellipses indicates whether ellipsis serving mode is enabled.
784 784
785 785 bundlecaps is optional and can be used to specify the set of
786 786 capabilities which can be used to build the bundle. While bundlecaps is
787 787 unused in core Mercurial, extensions rely on this feature to communicate
788 788 capabilities to customize the changegroup packer.
789 789
790 790 shallow indicates whether shallow data might be sent. The packer may
791 791 need to pack file contents not introduced by the changes being packed.
792 792
793 793 fullnodes is the set of changelog nodes which should not be ellipsis
794 794 nodes. We store this rather than the set of nodes that should be
795 795 ellipsis because for very large histories we expect this to be
796 796 significantly smaller.
797 797 """
798 798 assert filematcher
799 799 self._filematcher = filematcher
800 800
801 801 self.version = version
802 802 self._forcedeltaparentprev = forcedeltaparentprev
803 803 self._builddeltaheader = builddeltaheader
804 804 self._manifestsend = manifestsend
805 805 self._ellipses = ellipses
806 806
807 807 # Set of capabilities we can use to build the bundle.
808 808 if bundlecaps is None:
809 809 bundlecaps = set()
810 810 self._bundlecaps = bundlecaps
811 811 self._isshallow = shallow
812 812 self._fullclnodes = fullnodes
813 813
814 814 # Maps ellipsis revs to their roots at the changelog level.
815 815 self._precomputedellipsis = ellipsisroots
816 816
817 817 # experimental config: bundle.reorder
818 818 reorder = repo.ui.config('bundle', 'reorder')
819 819 if reorder == 'auto':
820 820 self._reorder = allowreorder
821 821 else:
822 822 self._reorder = stringutil.parsebool(reorder)
823 823
824 824 self._repo = repo
825 825
826 826 if self._repo.ui.verbose and not self._repo.ui.debugflag:
827 827 self._verbosenote = self._repo.ui.note
828 828 else:
829 829 self._verbosenote = lambda s: None
830 830
831 831 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
832 832 """Yield a sequence of changegroup byte chunks."""
833 833
834 834 repo = self._repo
835 835 cl = repo.changelog
836 836
837 837 self._verbosenote(_('uncompressed size of bundle content:\n'))
838 838 size = 0
839 839
840 840 clstate, deltas = self._generatechangelog(cl, clnodes)
841 841 for delta in deltas:
842 842 for chunk in _revisiondeltatochunks(delta, self._builddeltaheader):
843 843 size += len(chunk)
844 844 yield chunk
845 845
846 846 close = closechunk()
847 847 size += len(close)
848 848 yield closechunk()
849 849
850 850 self._verbosenote(_('%8.i (changelog)\n') % size)
851 851
852 852 clrevorder = clstate['clrevorder']
853 853 manifests = clstate['manifests']
854 854 changedfiles = clstate['changedfiles']
855 855
856 856 # We need to make sure that the linkrev in the changegroup refers to
857 857 # the first changeset that introduced the manifest or file revision.
858 858 # The fastpath is usually safer than the slowpath, because the filelogs
859 859 # are walked in revlog order.
860 860 #
861 861 # When taking the slowpath with reorder=None and the manifest revlog
862 862 # uses generaldelta, the manifest may be walked in the "wrong" order.
863 863 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
864 864 # cc0ff93d0c0c).
865 865 #
866 866 # When taking the fastpath, we are only vulnerable to reordering
867 867 # of the changelog itself. The changelog never uses generaldelta, so
868 868 # it is only reordered when reorder=True. To handle this case, we
869 869 # simply take the slowpath, which already has the 'clrevorder' logic.
870 870 # This was also fixed in cc0ff93d0c0c.
871 871 fastpathlinkrev = fastpathlinkrev and not self._reorder
872 872 # Treemanifests don't work correctly with fastpathlinkrev
873 873 # either, because we don't discover which directory nodes to
874 874 # send along with files. This could probably be fixed.
875 875 fastpathlinkrev = fastpathlinkrev and (
876 876 'treemanifest' not in repo.requirements)
877 877
878 878 fnodes = {} # needed file nodes
879 879
880 880 size = 0
881 881 it = self.generatemanifests(
882 882 commonrevs, clrevorder, fastpathlinkrev, manifests, fnodes, source,
883 883 clstate['clrevtomanifestrev'])
884 884
885 885 for tree, deltas in it:
886 886 if tree:
887 887 assert self.version == b'03'
888 888 chunk = _fileheader(tree)
889 889 size += len(chunk)
890 890 yield chunk
891 891
892 892 for delta in deltas:
893 893 chunks = _revisiondeltatochunks(delta, self._builddeltaheader)
894 894 for chunk in chunks:
895 895 size += len(chunk)
896 896 yield chunk
897 897
898 898 close = closechunk()
899 899 size += len(close)
900 900 yield close
901 901
902 902 self._verbosenote(_('%8.i (manifests)\n') % size)
903 903 yield self._manifestsend
904 904
905 905 mfdicts = None
906 906 if self._ellipses and self._isshallow:
907 907 mfdicts = [(self._repo.manifestlog[n].read(), lr)
908 908 for (n, lr) in manifests.iteritems()]
909 909
910 910 manifests.clear()
911 911 clrevs = set(cl.rev(x) for x in clnodes)
912 912
913 913 it = self.generatefiles(changedfiles, commonrevs,
914 914 source, mfdicts, fastpathlinkrev,
915 915 fnodes, clrevs)
916 916
917 917 for path, deltas in it:
918 918 h = _fileheader(path)
919 919 size = len(h)
920 920 yield h
921 921
922 922 for delta in deltas:
923 923 chunks = _revisiondeltatochunks(delta, self._builddeltaheader)
924 924 for chunk in chunks:
925 925 size += len(chunk)
926 926 yield chunk
927 927
928 928 close = closechunk()
929 929 size += len(close)
930 930 yield close
931 931
932 932 self._verbosenote(_('%8.i %s\n') % (size, path))
933 933
934 934 yield closechunk()
935 935
936 936 if clnodes:
937 937 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
938 938
939 939 def _generatechangelog(self, cl, nodes):
940 940 """Generate data for changelog chunks.
941 941
942 942 Returns a 2-tuple of a dict containing state and an iterable of
943 943 byte chunks. The state will not be fully populated until the
944 944 chunk stream has been fully consumed.
945 945 """
946 946 clrevorder = {}
947 947 manifests = {}
948 948 mfl = self._repo.manifestlog
949 949 changedfiles = set()
950 950 clrevtomanifestrev = {}
951 951
952 952 # Callback for the changelog, used to collect changed files and
953 953 # manifest nodes.
954 954 # Returns the linkrev node (identity in the changelog case).
955 955 def lookupcl(x):
956 956 c = cl.changelogrevision(x)
957 957 clrevorder[x] = len(clrevorder)
958 958
959 959 if self._ellipses:
960 960 # Only update manifests if x is going to be sent. Otherwise we
961 961 # end up with bogus linkrevs specified for manifests and
962 962 # we skip some manifest nodes that we should otherwise
963 963 # have sent.
964 964 if (x in self._fullclnodes
965 965 or cl.rev(x) in self._precomputedellipsis):
966 966
967 967 manifestnode = c.manifest
968 968 # Record the first changeset introducing this manifest
969 969 # version.
970 970 manifests.setdefault(manifestnode, x)
971 971 # Set this narrow-specific dict so we have the lowest
972 972 # manifest revnum to look up for this cl revnum. (Part of
973 973 # mapping changelog ellipsis parents to manifest ellipsis
974 974 # parents)
975 975 clrevtomanifestrev.setdefault(
976 976 cl.rev(x), mfl.rev(manifestnode))
977 977 # We can't trust the changed files list in the changeset if the
978 978 # client requested a shallow clone.
979 979 if self._isshallow:
980 980 changedfiles.update(mfl[c.manifest].read().keys())
981 981 else:
982 982 changedfiles.update(c.files)
983 983 else:
984 984 # record the first changeset introducing this manifest version
985 985 manifests.setdefault(c.manifest, x)
986 986 # Record a complete list of potentially-changed files in
987 987 # this manifest.
988 988 changedfiles.update(c.files)
989 989
990 990 return x
991 991
992 992 state = {
993 993 'clrevorder': clrevorder,
994 994 'manifests': manifests,
995 995 'changedfiles': changedfiles,
996 996 'clrevtomanifestrev': clrevtomanifestrev,
997 997 }
998 998
999 999 gen = deltagroup(
1000 1000 self._repo, cl, nodes, True, lookupcl,
1001 1001 self._forcedeltaparentprev,
1002 1002 # Reorder settings are currently ignored for changelog.
1003 1003 True,
1004 1004 ellipses=self._ellipses,
1005 units=_('changesets'),
1005 topic=_('changesets'),
1006 1006 clrevtolocalrev={},
1007 1007 fullclnodes=self._fullclnodes,
1008 1008 precomputedellipsis=self._precomputedellipsis)
1009 1009
1010 1010 return state, gen
1011 1011
1012 1012 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev,
1013 1013 manifests, fnodes, source, clrevtolocalrev):
1014 1014 """Returns an iterator of changegroup chunks containing manifests.
1015 1015
1016 1016 `source` is unused here, but is used by extensions like remotefilelog to
1017 1017 change what is sent based in pulls vs pushes, etc.
1018 1018 """
1019 1019 repo = self._repo
1020 1020 mfl = repo.manifestlog
1021 1021 dirlog = mfl._revlog.dirlog
1022 1022 tmfnodes = {'': manifests}
1023 1023
1024 1024 # Callback for the manifest, used to collect linkrevs for filelog
1025 1025 # revisions.
1026 1026 # Returns the linkrev node (collected in lookupcl).
1027 1027 def makelookupmflinknode(tree, nodes):
1028 1028 if fastpathlinkrev:
1029 1029 assert not tree
1030 1030 return manifests.__getitem__
1031 1031
1032 1032 def lookupmflinknode(x):
1033 1033 """Callback for looking up the linknode for manifests.
1034 1034
1035 1035 Returns the linkrev node for the specified manifest.
1036 1036
1037 1037 SIDE EFFECT:
1038 1038
1039 1039 1) fclnodes gets populated with the list of relevant
1040 1040 file nodes if we're not using fastpathlinkrev
1041 1041 2) When treemanifests are in use, collects treemanifest nodes
1042 1042 to send
1043 1043
1044 1044 Note that this means manifests must be completely sent to
1045 1045 the client before you can trust the list of files and
1046 1046 treemanifests to send.
1047 1047 """
1048 1048 clnode = nodes[x]
1049 1049 mdata = mfl.get(tree, x).readfast(shallow=True)
1050 1050 for p, n, fl in mdata.iterentries():
1051 1051 if fl == 't': # subdirectory manifest
1052 1052 subtree = tree + p + '/'
1053 1053 tmfclnodes = tmfnodes.setdefault(subtree, {})
1054 1054 tmfclnode = tmfclnodes.setdefault(n, clnode)
1055 1055 if clrevorder[clnode] < clrevorder[tmfclnode]:
1056 1056 tmfclnodes[n] = clnode
1057 1057 else:
1058 1058 f = tree + p
1059 1059 fclnodes = fnodes.setdefault(f, {})
1060 1060 fclnode = fclnodes.setdefault(n, clnode)
1061 1061 if clrevorder[clnode] < clrevorder[fclnode]:
1062 1062 fclnodes[n] = clnode
1063 1063 return clnode
1064 1064 return lookupmflinknode
1065 1065
1066 1066 while tmfnodes:
1067 1067 tree, nodes = tmfnodes.popitem()
1068 1068 store = dirlog(tree)
1069 1069
1070 1070 if not self._filematcher.visitdir(store._dir[:-1] or '.'):
1071 1071 prunednodes = []
1072 1072 else:
1073 1073 frev, flr = store.rev, store.linkrev
1074 1074 prunednodes = [n for n in nodes
1075 1075 if flr(frev(n)) not in commonrevs]
1076 1076
1077 1077 if tree and not prunednodes:
1078 1078 continue
1079 1079
1080 1080 lookupfn = makelookupmflinknode(tree, nodes)
1081 1081
1082 1082 deltas = deltagroup(
1083 1083 self._repo, store, prunednodes, False, lookupfn,
1084 1084 self._forcedeltaparentprev, self._reorder,
1085 1085 ellipses=self._ellipses,
1086 units=_('manifests'),
1086 topic=_('manifests'),
1087 1087 clrevtolocalrev=clrevtolocalrev,
1088 1088 fullclnodes=self._fullclnodes,
1089 1089 precomputedellipsis=self._precomputedellipsis)
1090 1090
1091 1091 yield tree, deltas
1092 1092
1093 1093 # The 'source' parameter is useful for extensions
1094 1094 def generatefiles(self, changedfiles, commonrevs, source,
1095 1095 mfdicts, fastpathlinkrev, fnodes, clrevs):
1096 1096 changedfiles = list(filter(self._filematcher, changedfiles))
1097 1097
1098 1098 if not fastpathlinkrev:
1099 1099 def normallinknodes(unused, fname):
1100 1100 return fnodes.get(fname, {})
1101 1101 else:
1102 1102 cln = self._repo.changelog.node
1103 1103
1104 1104 def normallinknodes(store, fname):
1105 1105 flinkrev = store.linkrev
1106 1106 fnode = store.node
1107 1107 revs = ((r, flinkrev(r)) for r in store)
1108 1108 return dict((fnode(r), cln(lr))
1109 1109 for r, lr in revs if lr in clrevs)
1110 1110
1111 1111 clrevtolocalrev = {}
1112 1112
1113 1113 if self._isshallow:
1114 1114 # In a shallow clone, the linknodes callback needs to also include
1115 1115 # those file nodes that are in the manifests we sent but weren't
1116 1116 # introduced by those manifests.
1117 1117 commonctxs = [self._repo[c] for c in commonrevs]
1118 1118 clrev = self._repo.changelog.rev
1119 1119
1120 1120 # Defining this function has a side-effect of overriding the
1121 1121 # function of the same name that was passed in as an argument.
1122 1122 # TODO have caller pass in appropriate function.
1123 1123 def linknodes(flog, fname):
1124 1124 for c in commonctxs:
1125 1125 try:
1126 1126 fnode = c.filenode(fname)
1127 1127 clrevtolocalrev[c.rev()] = flog.rev(fnode)
1128 1128 except error.ManifestLookupError:
1129 1129 pass
1130 1130 links = normallinknodes(flog, fname)
1131 1131 if len(links) != len(mfdicts):
1132 1132 for mf, lr in mfdicts:
1133 1133 fnode = mf.get(fname, None)
1134 1134 if fnode in links:
1135 1135 links[fnode] = min(links[fnode], lr, key=clrev)
1136 1136 elif fnode:
1137 1137 links[fnode] = lr
1138 1138 return links
1139 1139 else:
1140 1140 linknodes = normallinknodes
1141 1141
1142 1142 repo = self._repo
1143 progress = repo.ui.makeprogress(_('bundling'), unit=_('files'),
1143 progress = repo.ui.makeprogress(_('files'), unit=_('files'),
1144 1144 total=len(changedfiles))
1145 1145 for i, fname in enumerate(sorted(changedfiles)):
1146 1146 filerevlog = repo.file(fname)
1147 1147 if not filerevlog:
1148 1148 raise error.Abort(_("empty or missing file data for %s") %
1149 1149 fname)
1150 1150
1151 1151 clrevtolocalrev.clear()
1152 1152
1153 1153 linkrevnodes = linknodes(filerevlog, fname)
1154 1154 # Lookup for filenodes, we collected the linkrev nodes above in the
1155 1155 # fastpath case and with lookupmf in the slowpath case.
1156 1156 def lookupfilelog(x):
1157 1157 return linkrevnodes[x]
1158 1158
1159 1159 frev, flr = filerevlog.rev, filerevlog.linkrev
1160 1160 filenodes = [n for n in linkrevnodes
1161 1161 if flr(frev(n)) not in commonrevs]
1162 1162
1163 1163 if not filenodes:
1164 1164 continue
1165 1165
1166 1166 progress.update(i + 1, item=fname)
1167 1167
1168 1168 deltas = deltagroup(
1169 1169 self._repo, filerevlog, filenodes, False, lookupfilelog,
1170 1170 self._forcedeltaparentprev, self._reorder,
1171 1171 ellipses=self._ellipses,
1172 1172 clrevtolocalrev=clrevtolocalrev,
1173 1173 fullclnodes=self._fullclnodes,
1174 1174 precomputedellipsis=self._precomputedellipsis)
1175 1175
1176 1176 yield fname, deltas
1177 1177
1178 1178 progress.complete()
1179 1179
1180 1180 def _makecg1packer(repo, filematcher, bundlecaps, ellipses=False,
1181 1181 shallow=False, ellipsisroots=None, fullnodes=None):
1182 1182 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack(
1183 1183 d.node, d.p1node, d.p2node, d.linknode)
1184 1184
1185 1185 return cgpacker(repo, filematcher, b'01',
1186 1186 allowreorder=None,
1187 1187 builddeltaheader=builddeltaheader,
1188 1188 manifestsend=b'',
1189 1189 forcedeltaparentprev=True,
1190 1190 bundlecaps=bundlecaps,
1191 1191 ellipses=ellipses,
1192 1192 shallow=shallow,
1193 1193 ellipsisroots=ellipsisroots,
1194 1194 fullnodes=fullnodes)
1195 1195
1196 1196 def _makecg2packer(repo, filematcher, bundlecaps, ellipses=False,
1197 1197 shallow=False, ellipsisroots=None, fullnodes=None):
1198 1198 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack(
1199 1199 d.node, d.p1node, d.p2node, d.basenode, d.linknode)
1200 1200
1201 1201 # Since generaldelta is directly supported by cg2, reordering
1202 1202 # generally doesn't help, so we disable it by default (treating
1203 1203 # bundle.reorder=auto just like bundle.reorder=False).
1204 1204 return cgpacker(repo, filematcher, b'02',
1205 1205 allowreorder=False,
1206 1206 builddeltaheader=builddeltaheader,
1207 1207 manifestsend=b'',
1208 1208 bundlecaps=bundlecaps,
1209 1209 ellipses=ellipses,
1210 1210 shallow=shallow,
1211 1211 ellipsisroots=ellipsisroots,
1212 1212 fullnodes=fullnodes)
1213 1213
1214 1214 def _makecg3packer(repo, filematcher, bundlecaps, ellipses=False,
1215 1215 shallow=False, ellipsisroots=None, fullnodes=None):
1216 1216 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
1217 1217 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags)
1218 1218
1219 1219 return cgpacker(repo, filematcher, b'03',
1220 1220 allowreorder=False,
1221 1221 builddeltaheader=builddeltaheader,
1222 1222 manifestsend=closechunk(),
1223 1223 bundlecaps=bundlecaps,
1224 1224 ellipses=ellipses,
1225 1225 shallow=shallow,
1226 1226 ellipsisroots=ellipsisroots,
1227 1227 fullnodes=fullnodes)
1228 1228
1229 1229 _packermap = {'01': (_makecg1packer, cg1unpacker),
1230 1230 # cg2 adds support for exchanging generaldelta
1231 1231 '02': (_makecg2packer, cg2unpacker),
1232 1232 # cg3 adds support for exchanging revlog flags and treemanifests
1233 1233 '03': (_makecg3packer, cg3unpacker),
1234 1234 }
1235 1235
1236 1236 def allsupportedversions(repo):
1237 1237 versions = set(_packermap.keys())
1238 1238 if not (repo.ui.configbool('experimental', 'changegroup3') or
1239 1239 repo.ui.configbool('experimental', 'treemanifest') or
1240 1240 'treemanifest' in repo.requirements):
1241 1241 versions.discard('03')
1242 1242 return versions
1243 1243
1244 1244 # Changegroup versions that can be applied to the repo
1245 1245 def supportedincomingversions(repo):
1246 1246 return allsupportedversions(repo)
1247 1247
1248 1248 # Changegroup versions that can be created from the repo
1249 1249 def supportedoutgoingversions(repo):
1250 1250 versions = allsupportedversions(repo)
1251 1251 if 'treemanifest' in repo.requirements:
1252 1252 # Versions 01 and 02 support only flat manifests and it's just too
1253 1253 # expensive to convert between the flat manifest and tree manifest on
1254 1254 # the fly. Since tree manifests are hashed differently, all of history
1255 1255 # would have to be converted. Instead, we simply don't even pretend to
1256 1256 # support versions 01 and 02.
1257 1257 versions.discard('01')
1258 1258 versions.discard('02')
1259 1259 if repository.NARROW_REQUIREMENT in repo.requirements:
1260 1260 # Versions 01 and 02 don't support revlog flags, and we need to
1261 1261 # support that for stripping and unbundling to work.
1262 1262 versions.discard('01')
1263 1263 versions.discard('02')
1264 1264 if LFS_REQUIREMENT in repo.requirements:
1265 1265 # Versions 01 and 02 don't support revlog flags, and we need to
1266 1266 # mark LFS entries with REVIDX_EXTSTORED.
1267 1267 versions.discard('01')
1268 1268 versions.discard('02')
1269 1269
1270 1270 return versions
1271 1271
1272 1272 def localversion(repo):
1273 1273 # Finds the best version to use for bundles that are meant to be used
1274 1274 # locally, such as those from strip and shelve, and temporary bundles.
1275 1275 return max(supportedoutgoingversions(repo))
1276 1276
1277 1277 def safeversion(repo):
1278 1278 # Finds the smallest version that it's safe to assume clients of the repo
1279 1279 # will support. For example, all hg versions that support generaldelta also
1280 1280 # support changegroup 02.
1281 1281 versions = supportedoutgoingversions(repo)
1282 1282 if 'generaldelta' in repo.requirements:
1283 1283 versions.discard('01')
1284 1284 assert versions
1285 1285 return min(versions)
1286 1286
1287 1287 def getbundler(version, repo, bundlecaps=None, filematcher=None,
1288 1288 ellipses=False, shallow=False, ellipsisroots=None,
1289 1289 fullnodes=None):
1290 1290 assert version in supportedoutgoingversions(repo)
1291 1291
1292 1292 if filematcher is None:
1293 1293 filematcher = matchmod.alwaysmatcher(repo.root, '')
1294 1294
1295 1295 if version == '01' and not filematcher.always():
1296 1296 raise error.ProgrammingError('version 01 changegroups do not support '
1297 1297 'sparse file matchers')
1298 1298
1299 1299 if ellipses and version in (b'01', b'02'):
1300 1300 raise error.Abort(
1301 1301 _('ellipsis nodes require at least cg3 on client and server, '
1302 1302 'but negotiated version %s') % version)
1303 1303
1304 1304 # Requested files could include files not in the local store. So
1305 1305 # filter those out.
1306 1306 filematcher = matchmod.intersectmatchers(repo.narrowmatch(),
1307 1307 filematcher)
1308 1308
1309 1309 fn = _packermap[version][0]
1310 1310 return fn(repo, filematcher, bundlecaps, ellipses=ellipses,
1311 1311 shallow=shallow, ellipsisroots=ellipsisroots,
1312 1312 fullnodes=fullnodes)
1313 1313
1314 1314 def getunbundler(version, fh, alg, extras=None):
1315 1315 return _packermap[version][1](fh, alg, extras=extras)
1316 1316
1317 1317 def _changegroupinfo(repo, nodes, source):
1318 1318 if repo.ui.verbose or source == 'bundle':
1319 1319 repo.ui.status(_("%d changesets found\n") % len(nodes))
1320 1320 if repo.ui.debugflag:
1321 1321 repo.ui.debug("list of changesets:\n")
1322 1322 for node in nodes:
1323 1323 repo.ui.debug("%s\n" % hex(node))
1324 1324
1325 1325 def makechangegroup(repo, outgoing, version, source, fastpath=False,
1326 1326 bundlecaps=None):
1327 1327 cgstream = makestream(repo, outgoing, version, source,
1328 1328 fastpath=fastpath, bundlecaps=bundlecaps)
1329 1329 return getunbundler(version, util.chunkbuffer(cgstream), None,
1330 1330 {'clcount': len(outgoing.missing) })
1331 1331
1332 1332 def makestream(repo, outgoing, version, source, fastpath=False,
1333 1333 bundlecaps=None, filematcher=None):
1334 1334 bundler = getbundler(version, repo, bundlecaps=bundlecaps,
1335 1335 filematcher=filematcher)
1336 1336
1337 1337 repo = repo.unfiltered()
1338 1338 commonrevs = outgoing.common
1339 1339 csets = outgoing.missing
1340 1340 heads = outgoing.missingheads
1341 1341 # We go through the fast path if we get told to, or if all (unfiltered
1342 1342 # heads have been requested (since we then know there all linkrevs will
1343 1343 # be pulled by the client).
1344 1344 heads.sort()
1345 1345 fastpathlinkrev = fastpath or (
1346 1346 repo.filtername is None and heads == sorted(repo.heads()))
1347 1347
1348 1348 repo.hook('preoutgoing', throw=True, source=source)
1349 1349 _changegroupinfo(repo, csets, source)
1350 1350 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
1351 1351
1352 1352 def _addchangegroupfiles(repo, source, revmap, trp, expectedfiles, needfiles):
1353 1353 revisions = 0
1354 1354 files = 0
1355 1355 progress = repo.ui.makeprogress(_('files'), unit=_('files'),
1356 1356 total=expectedfiles)
1357 1357 for chunkdata in iter(source.filelogheader, {}):
1358 1358 files += 1
1359 1359 f = chunkdata["filename"]
1360 1360 repo.ui.debug("adding %s revisions\n" % f)
1361 1361 progress.increment()
1362 1362 fl = repo.file(f)
1363 1363 o = len(fl)
1364 1364 try:
1365 1365 deltas = source.deltaiter()
1366 1366 if not fl.addgroup(deltas, revmap, trp):
1367 1367 raise error.Abort(_("received file revlog group is empty"))
1368 1368 except error.CensoredBaseError as e:
1369 1369 raise error.Abort(_("received delta base is censored: %s") % e)
1370 1370 revisions += len(fl) - o
1371 1371 if f in needfiles:
1372 1372 needs = needfiles[f]
1373 1373 for new in pycompat.xrange(o, len(fl)):
1374 1374 n = fl.node(new)
1375 1375 if n in needs:
1376 1376 needs.remove(n)
1377 1377 else:
1378 1378 raise error.Abort(
1379 1379 _("received spurious file revlog entry"))
1380 1380 if not needs:
1381 1381 del needfiles[f]
1382 1382 progress.complete()
1383 1383
1384 1384 for f, needs in needfiles.iteritems():
1385 1385 fl = repo.file(f)
1386 1386 for n in needs:
1387 1387 try:
1388 1388 fl.rev(n)
1389 1389 except error.LookupError:
1390 1390 raise error.Abort(
1391 1391 _('missing file data for %s:%s - run hg verify') %
1392 1392 (f, hex(n)))
1393 1393
1394 1394 return revisions, files
@@ -1,902 +1,902 b''
1 1 Setting up test
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo 0 > afile
6 6 $ hg add afile
7 7 $ hg commit -m "0.0"
8 8 $ echo 1 >> afile
9 9 $ hg commit -m "0.1"
10 10 $ echo 2 >> afile
11 11 $ hg commit -m "0.2"
12 12 $ echo 3 >> afile
13 13 $ hg commit -m "0.3"
14 14 $ hg update -C 0
15 15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 16 $ echo 1 >> afile
17 17 $ hg commit -m "1.1"
18 18 created new head
19 19 $ echo 2 >> afile
20 20 $ hg commit -m "1.2"
21 21 $ echo "a line" > fred
22 22 $ echo 3 >> afile
23 23 $ hg add fred
24 24 $ hg commit -m "1.3"
25 25 $ hg mv afile adifferentfile
26 26 $ hg commit -m "1.3m"
27 27 $ hg update -C 3
28 28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
29 29 $ hg mv afile anotherfile
30 30 $ hg commit -m "0.3m"
31 31 $ hg verify
32 32 checking changesets
33 33 checking manifests
34 34 crosschecking files in changesets and manifests
35 35 checking files
36 36 4 files, 9 changesets, 7 total revisions
37 37 $ cd ..
38 38 $ hg init empty
39 39
40 40 Bundle and phase
41 41
42 42 $ hg -R test phase --force --secret 0
43 43 $ hg -R test bundle phase.hg empty
44 44 searching for changes
45 45 no changes found (ignored 9 secret changesets)
46 46 [1]
47 47 $ hg -R test phase --draft -r 'head()'
48 48
49 49 Bundle --all
50 50
51 51 $ hg -R test bundle --all all.hg
52 52 9 changesets found
53 53
54 54 Bundle test to full.hg
55 55
56 56 $ hg -R test bundle full.hg empty
57 57 searching for changes
58 58 9 changesets found
59 59
60 60 Unbundle full.hg in test
61 61
62 62 $ hg -R test unbundle full.hg
63 63 adding changesets
64 64 adding manifests
65 65 adding file changes
66 66 added 0 changesets with 0 changes to 4 files
67 67 (run 'hg update' to get a working copy)
68 68
69 69 Verify empty
70 70
71 71 $ hg -R empty heads
72 72 [1]
73 73 $ hg -R empty verify
74 74 checking changesets
75 75 checking manifests
76 76 crosschecking files in changesets and manifests
77 77 checking files
78 78 0 files, 0 changesets, 0 total revisions
79 79
80 80 #if repobundlerepo
81 81
82 82 Pull full.hg into test (using --cwd)
83 83
84 84 $ hg --cwd test pull ../full.hg
85 85 pulling from ../full.hg
86 86 searching for changes
87 87 no changes found
88 88
89 89 Verify that there are no leaked temporary files after pull (issue2797)
90 90
91 91 $ ls test/.hg | grep .hg10un
92 92 [1]
93 93
94 94 Pull full.hg into empty (using --cwd)
95 95
96 96 $ hg --cwd empty pull ../full.hg
97 97 pulling from ../full.hg
98 98 requesting all changes
99 99 adding changesets
100 100 adding manifests
101 101 adding file changes
102 102 added 9 changesets with 7 changes to 4 files (+1 heads)
103 103 new changesets f9ee2f85a263:aa35859c02ea
104 104 (run 'hg heads' to see heads, 'hg merge' to merge)
105 105
106 106 Rollback empty
107 107
108 108 $ hg -R empty rollback
109 109 repository tip rolled back to revision -1 (undo pull)
110 110
111 111 Pull full.hg into empty again (using --cwd)
112 112
113 113 $ hg --cwd empty pull ../full.hg
114 114 pulling from ../full.hg
115 115 requesting all changes
116 116 adding changesets
117 117 adding manifests
118 118 adding file changes
119 119 added 9 changesets with 7 changes to 4 files (+1 heads)
120 120 new changesets f9ee2f85a263:aa35859c02ea
121 121 (run 'hg heads' to see heads, 'hg merge' to merge)
122 122
123 123 Pull full.hg into test (using -R)
124 124
125 125 $ hg -R test pull full.hg
126 126 pulling from full.hg
127 127 searching for changes
128 128 no changes found
129 129
130 130 Pull full.hg into empty (using -R)
131 131
132 132 $ hg -R empty pull full.hg
133 133 pulling from full.hg
134 134 searching for changes
135 135 no changes found
136 136
137 137 Rollback empty
138 138
139 139 $ hg -R empty rollback
140 140 repository tip rolled back to revision -1 (undo pull)
141 141
142 142 Pull full.hg into empty again (using -R)
143 143
144 144 $ hg -R empty pull full.hg
145 145 pulling from full.hg
146 146 requesting all changes
147 147 adding changesets
148 148 adding manifests
149 149 adding file changes
150 150 added 9 changesets with 7 changes to 4 files (+1 heads)
151 151 new changesets f9ee2f85a263:aa35859c02ea
152 152 (run 'hg heads' to see heads, 'hg merge' to merge)
153 153
154 154 Log -R full.hg in fresh empty
155 155
156 156 $ rm -r empty
157 157 $ hg init empty
158 158 $ cd empty
159 159 $ hg -R bundle://../full.hg log
160 160 changeset: 8:aa35859c02ea
161 161 tag: tip
162 162 parent: 3:eebf5a27f8ca
163 163 user: test
164 164 date: Thu Jan 01 00:00:00 1970 +0000
165 165 summary: 0.3m
166 166
167 167 changeset: 7:a6a34bfa0076
168 168 user: test
169 169 date: Thu Jan 01 00:00:00 1970 +0000
170 170 summary: 1.3m
171 171
172 172 changeset: 6:7373c1169842
173 173 user: test
174 174 date: Thu Jan 01 00:00:00 1970 +0000
175 175 summary: 1.3
176 176
177 177 changeset: 5:1bb50a9436a7
178 178 user: test
179 179 date: Thu Jan 01 00:00:00 1970 +0000
180 180 summary: 1.2
181 181
182 182 changeset: 4:095197eb4973
183 183 parent: 0:f9ee2f85a263
184 184 user: test
185 185 date: Thu Jan 01 00:00:00 1970 +0000
186 186 summary: 1.1
187 187
188 188 changeset: 3:eebf5a27f8ca
189 189 user: test
190 190 date: Thu Jan 01 00:00:00 1970 +0000
191 191 summary: 0.3
192 192
193 193 changeset: 2:e38ba6f5b7e0
194 194 user: test
195 195 date: Thu Jan 01 00:00:00 1970 +0000
196 196 summary: 0.2
197 197
198 198 changeset: 1:34c2bf6b0626
199 199 user: test
200 200 date: Thu Jan 01 00:00:00 1970 +0000
201 201 summary: 0.1
202 202
203 203 changeset: 0:f9ee2f85a263
204 204 user: test
205 205 date: Thu Jan 01 00:00:00 1970 +0000
206 206 summary: 0.0
207 207
208 208 Make sure bundlerepo doesn't leak tempfiles (issue2491)
209 209
210 210 $ ls .hg
211 211 00changelog.i
212 212 cache
213 213 requires
214 214 store
215 215
216 216 Pull ../full.hg into empty (with hook)
217 217
218 218 $ cat >> .hg/hgrc <<EOF
219 219 > [hooks]
220 220 > changegroup = sh -c "printenv.py changegroup"
221 221 > EOF
222 222
223 223 doesn't work (yet ?)
224 224
225 225 hg -R bundle://../full.hg verify
226 226
227 227 $ hg pull bundle://../full.hg
228 228 pulling from bundle:../full.hg
229 229 requesting all changes
230 230 adding changesets
231 231 adding manifests
232 232 adding file changes
233 233 added 9 changesets with 7 changes to 4 files (+1 heads)
234 234 new changesets f9ee2f85a263:aa35859c02ea
235 235 changegroup hook: HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=bundle*../full.hg (glob)
236 236 (run 'hg heads' to see heads, 'hg merge' to merge)
237 237
238 238 Rollback empty
239 239
240 240 $ hg rollback
241 241 repository tip rolled back to revision -1 (undo pull)
242 242 $ cd ..
243 243
244 244 Log -R bundle:empty+full.hg
245 245
246 246 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
247 247 8 7 6 5 4 3 2 1 0
248 248
249 249 Pull full.hg into empty again (using -R; with hook)
250 250
251 251 $ hg -R empty pull full.hg
252 252 pulling from full.hg
253 253 requesting all changes
254 254 adding changesets
255 255 adding manifests
256 256 adding file changes
257 257 added 9 changesets with 7 changes to 4 files (+1 heads)
258 258 new changesets f9ee2f85a263:aa35859c02ea
259 259 changegroup hook: HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=bundle:empty+full.hg
260 260 (run 'hg heads' to see heads, 'hg merge' to merge)
261 261
262 262 #endif
263 263
264 264 Cannot produce streaming clone bundles with "hg bundle"
265 265
266 266 $ hg -R test bundle -t packed1 packed.hg
267 267 abort: packed bundles cannot be produced by "hg bundle"
268 268 (use 'hg debugcreatestreamclonebundle')
269 269 [255]
270 270
271 271 packed1 is produced properly
272 272
273 273 #if reporevlogstore
274 274
275 275 $ hg -R test debugcreatestreamclonebundle packed.hg
276 276 writing 2664 bytes for 6 files
277 277 bundle requirements: generaldelta, revlogv1
278 278
279 279 $ f -B 64 --size --sha1 --hexdump packed.hg
280 280 packed.hg: size=2827, sha1=9d14cb90c66a21462d915ab33656f38b9deed686
281 281 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
282 282 0010: 00 00 00 00 0a 68 00 16 67 65 6e 65 72 61 6c 64 |.....h..generald|
283 283 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 76 31 00 64 61 |elta,revlogv1.da|
284 284 0030: 74 61 2f 61 64 69 66 66 65 72 65 6e 74 66 69 6c |ta/adifferentfil|
285 285
286 286 $ hg debugbundle --spec packed.hg
287 287 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1
288 288
289 289 generaldelta requirement is not listed in stream clone bundles unless used
290 290
291 291 $ hg --config format.usegeneraldelta=false init testnongd
292 292 $ cd testnongd
293 293 $ touch foo
294 294 $ hg -q commit -A -m initial
295 295 $ cd ..
296 296 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
297 297 writing 301 bytes for 3 files
298 298 bundle requirements: revlogv1
299 299
300 300 $ f -B 64 --size --sha1 --hexdump packednongd.hg
301 301 packednongd.hg: size=383, sha1=1d9c230238edd5d38907100b729ba72b1831fe6f
302 302 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
303 303 0010: 00 00 00 00 01 2d 00 09 72 65 76 6c 6f 67 76 31 |.....-..revlogv1|
304 304 0020: 00 64 61 74 61 2f 66 6f 6f 2e 69 00 36 34 0a 00 |.data/foo.i.64..|
305 305 0030: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
306 306
307 307 $ hg debugbundle --spec packednongd.hg
308 308 none-packed1;requirements%3Drevlogv1
309 309
310 310 Warning emitted when packed bundles contain secret changesets
311 311
312 312 $ hg init testsecret
313 313 $ cd testsecret
314 314 $ touch foo
315 315 $ hg -q commit -A -m initial
316 316 $ hg phase --force --secret -r .
317 317 $ cd ..
318 318
319 319 $ hg -R testsecret debugcreatestreamclonebundle packedsecret.hg
320 320 (warning: stream clone bundle will contain secret revisions)
321 321 writing 301 bytes for 3 files
322 322 bundle requirements: generaldelta, revlogv1
323 323
324 324 Unpacking packed1 bundles with "hg unbundle" isn't allowed
325 325
326 326 $ hg init packed
327 327 $ hg -R packed unbundle packed.hg
328 328 abort: packed bundles cannot be applied with "hg unbundle"
329 329 (use "hg debugapplystreamclonebundle")
330 330 [255]
331 331
332 332 packed1 can be consumed from debug command
333 333
334 334 (this also confirms that streamclone-ed changes are visible via
335 335 @filecache properties to in-process procedures before closing
336 336 transaction)
337 337
338 338 $ cat > $TESTTMP/showtip.py <<EOF
339 339 > from __future__ import absolute_import
340 340 >
341 341 > def showtip(ui, repo, hooktype, **kwargs):
342 342 > ui.warn(b'%s: %s\n' % (hooktype, repo[b'tip'].hex()[:12]))
343 343 >
344 344 > def reposetup(ui, repo):
345 345 > # this confirms (and ensures) that (empty) 00changelog.i
346 346 > # before streamclone is already cached as repo.changelog
347 347 > ui.setconfig(b'hooks', b'pretxnopen.showtip', showtip)
348 348 >
349 349 > # this confirms that streamclone-ed changes are visible to
350 350 > # in-process procedures before closing transaction
351 351 > ui.setconfig(b'hooks', b'pretxnclose.showtip', showtip)
352 352 >
353 353 > # this confirms that streamclone-ed changes are still visible
354 354 > # after closing transaction
355 355 > ui.setconfig(b'hooks', b'txnclose.showtip', showtip)
356 356 > EOF
357 357 $ cat >> $HGRCPATH <<EOF
358 358 > [extensions]
359 359 > showtip = $TESTTMP/showtip.py
360 360 > EOF
361 361
362 362 $ hg -R packed debugapplystreamclonebundle packed.hg
363 363 6 files to transfer, 2.60 KB of data
364 364 pretxnopen: 000000000000
365 365 pretxnclose: aa35859c02ea
366 366 transferred 2.60 KB in *.* seconds (* */sec) (glob)
367 367 txnclose: aa35859c02ea
368 368
369 369 (for safety, confirm visibility of streamclone-ed changes by another
370 370 process, too)
371 371
372 372 $ hg -R packed tip -T "{node|short}\n"
373 373 aa35859c02ea
374 374
375 375 $ cat >> $HGRCPATH <<EOF
376 376 > [extensions]
377 377 > showtip = !
378 378 > EOF
379 379
380 380 Does not work on non-empty repo
381 381
382 382 $ hg -R packed debugapplystreamclonebundle packed.hg
383 383 abort: cannot apply stream clone bundle on non-empty repo
384 384 [255]
385 385
386 386 #endif
387 387
388 388 Create partial clones
389 389
390 390 $ rm -r empty
391 391 $ hg init empty
392 392 $ hg clone -r 3 test partial
393 393 adding changesets
394 394 adding manifests
395 395 adding file changes
396 396 added 4 changesets with 4 changes to 1 files
397 397 new changesets f9ee2f85a263:eebf5a27f8ca
398 398 updating to branch default
399 399 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
400 400 $ hg clone partial partial2
401 401 updating to branch default
402 402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 403 $ cd partial
404 404
405 405 #if repobundlerepo
406 406
407 407 Log -R full.hg in partial
408 408
409 409 $ hg -R bundle://../full.hg log -T phases
410 410 changeset: 8:aa35859c02ea
411 411 tag: tip
412 412 phase: draft
413 413 parent: 3:eebf5a27f8ca
414 414 user: test
415 415 date: Thu Jan 01 00:00:00 1970 +0000
416 416 summary: 0.3m
417 417
418 418 changeset: 7:a6a34bfa0076
419 419 phase: draft
420 420 user: test
421 421 date: Thu Jan 01 00:00:00 1970 +0000
422 422 summary: 1.3m
423 423
424 424 changeset: 6:7373c1169842
425 425 phase: draft
426 426 user: test
427 427 date: Thu Jan 01 00:00:00 1970 +0000
428 428 summary: 1.3
429 429
430 430 changeset: 5:1bb50a9436a7
431 431 phase: draft
432 432 user: test
433 433 date: Thu Jan 01 00:00:00 1970 +0000
434 434 summary: 1.2
435 435
436 436 changeset: 4:095197eb4973
437 437 phase: draft
438 438 parent: 0:f9ee2f85a263
439 439 user: test
440 440 date: Thu Jan 01 00:00:00 1970 +0000
441 441 summary: 1.1
442 442
443 443 changeset: 3:eebf5a27f8ca
444 444 phase: public
445 445 user: test
446 446 date: Thu Jan 01 00:00:00 1970 +0000
447 447 summary: 0.3
448 448
449 449 changeset: 2:e38ba6f5b7e0
450 450 phase: public
451 451 user: test
452 452 date: Thu Jan 01 00:00:00 1970 +0000
453 453 summary: 0.2
454 454
455 455 changeset: 1:34c2bf6b0626
456 456 phase: public
457 457 user: test
458 458 date: Thu Jan 01 00:00:00 1970 +0000
459 459 summary: 0.1
460 460
461 461 changeset: 0:f9ee2f85a263
462 462 phase: public
463 463 user: test
464 464 date: Thu Jan 01 00:00:00 1970 +0000
465 465 summary: 0.0
466 466
467 467
468 468 Incoming full.hg in partial
469 469
470 470 $ hg incoming bundle://../full.hg
471 471 comparing with bundle:../full.hg
472 472 searching for changes
473 473 changeset: 4:095197eb4973
474 474 parent: 0:f9ee2f85a263
475 475 user: test
476 476 date: Thu Jan 01 00:00:00 1970 +0000
477 477 summary: 1.1
478 478
479 479 changeset: 5:1bb50a9436a7
480 480 user: test
481 481 date: Thu Jan 01 00:00:00 1970 +0000
482 482 summary: 1.2
483 483
484 484 changeset: 6:7373c1169842
485 485 user: test
486 486 date: Thu Jan 01 00:00:00 1970 +0000
487 487 summary: 1.3
488 488
489 489 changeset: 7:a6a34bfa0076
490 490 user: test
491 491 date: Thu Jan 01 00:00:00 1970 +0000
492 492 summary: 1.3m
493 493
494 494 changeset: 8:aa35859c02ea
495 495 tag: tip
496 496 parent: 3:eebf5a27f8ca
497 497 user: test
498 498 date: Thu Jan 01 00:00:00 1970 +0000
499 499 summary: 0.3m
500 500
501 501
502 502 Outgoing -R full.hg vs partial2 in partial
503 503
504 504 $ hg -R bundle://../full.hg outgoing ../partial2
505 505 comparing with ../partial2
506 506 searching for changes
507 507 changeset: 4:095197eb4973
508 508 parent: 0:f9ee2f85a263
509 509 user: test
510 510 date: Thu Jan 01 00:00:00 1970 +0000
511 511 summary: 1.1
512 512
513 513 changeset: 5:1bb50a9436a7
514 514 user: test
515 515 date: Thu Jan 01 00:00:00 1970 +0000
516 516 summary: 1.2
517 517
518 518 changeset: 6:7373c1169842
519 519 user: test
520 520 date: Thu Jan 01 00:00:00 1970 +0000
521 521 summary: 1.3
522 522
523 523 changeset: 7:a6a34bfa0076
524 524 user: test
525 525 date: Thu Jan 01 00:00:00 1970 +0000
526 526 summary: 1.3m
527 527
528 528 changeset: 8:aa35859c02ea
529 529 tag: tip
530 530 parent: 3:eebf5a27f8ca
531 531 user: test
532 532 date: Thu Jan 01 00:00:00 1970 +0000
533 533 summary: 0.3m
534 534
535 535
536 536 Outgoing -R does-not-exist.hg vs partial2 in partial
537 537
538 538 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
539 539 abort: *../does-not-exist.hg* (glob)
540 540 [255]
541 541
542 542 #endif
543 543
544 544 $ cd ..
545 545
546 546 hide outer repo
547 547 $ hg init
548 548
549 549 Direct clone from bundle (all-history)
550 550
551 551 #if repobundlerepo
552 552
553 553 $ hg clone full.hg full-clone
554 554 requesting all changes
555 555 adding changesets
556 556 adding manifests
557 557 adding file changes
558 558 added 9 changesets with 7 changes to 4 files (+1 heads)
559 559 new changesets f9ee2f85a263:aa35859c02ea
560 560 updating to branch default
561 561 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
562 562 $ hg -R full-clone heads
563 563 changeset: 8:aa35859c02ea
564 564 tag: tip
565 565 parent: 3:eebf5a27f8ca
566 566 user: test
567 567 date: Thu Jan 01 00:00:00 1970 +0000
568 568 summary: 0.3m
569 569
570 570 changeset: 7:a6a34bfa0076
571 571 user: test
572 572 date: Thu Jan 01 00:00:00 1970 +0000
573 573 summary: 1.3m
574 574
575 575 $ rm -r full-clone
576 576
577 577 When cloning from a non-copiable repository into '', do not
578 578 recurse infinitely (issue2528)
579 579
580 580 $ hg clone full.hg ''
581 581 abort: empty destination path is not valid
582 582 [255]
583 583
584 584 test for https://bz.mercurial-scm.org/216
585 585
586 586 Unbundle incremental bundles into fresh empty in one go
587 587
588 588 $ rm -r empty
589 589 $ hg init empty
590 590 $ hg -R test bundle --base null -r 0 ../0.hg
591 591 1 changesets found
592 592 $ hg -R test bundle --base 0 -r 1 ../1.hg
593 593 1 changesets found
594 594 $ hg -R empty unbundle -u ../0.hg ../1.hg
595 595 adding changesets
596 596 adding manifests
597 597 adding file changes
598 598 added 1 changesets with 1 changes to 1 files
599 599 new changesets f9ee2f85a263
600 600 adding changesets
601 601 adding manifests
602 602 adding file changes
603 603 added 1 changesets with 1 changes to 1 files
604 604 new changesets 34c2bf6b0626
605 605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
606 606
607 607 View full contents of the bundle
608 608 $ hg -R test bundle --base null -r 3 ../partial.hg
609 609 4 changesets found
610 610 $ cd test
611 611 $ hg -R ../../partial.hg log -r "bundle()"
612 612 changeset: 0:f9ee2f85a263
613 613 user: test
614 614 date: Thu Jan 01 00:00:00 1970 +0000
615 615 summary: 0.0
616 616
617 617 changeset: 1:34c2bf6b0626
618 618 user: test
619 619 date: Thu Jan 01 00:00:00 1970 +0000
620 620 summary: 0.1
621 621
622 622 changeset: 2:e38ba6f5b7e0
623 623 user: test
624 624 date: Thu Jan 01 00:00:00 1970 +0000
625 625 summary: 0.2
626 626
627 627 changeset: 3:eebf5a27f8ca
628 628 user: test
629 629 date: Thu Jan 01 00:00:00 1970 +0000
630 630 summary: 0.3
631 631
632 632 $ cd ..
633 633
634 634 #endif
635 635
636 636 test for 540d1059c802
637 637
638 638 $ hg init orig
639 639 $ cd orig
640 640 $ echo foo > foo
641 641 $ hg add foo
642 642 $ hg ci -m 'add foo'
643 643
644 644 $ hg clone . ../copy
645 645 updating to branch default
646 646 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 647 $ hg tag foo
648 648
649 649 $ cd ../copy
650 650 $ echo >> foo
651 651 $ hg ci -m 'change foo'
652 652 $ hg bundle ../bundle.hg ../orig
653 653 searching for changes
654 654 1 changesets found
655 655
656 656 $ cd ..
657 657
658 658 #if repobundlerepo
659 659 $ cd orig
660 660 $ hg incoming ../bundle.hg
661 661 comparing with ../bundle.hg
662 662 searching for changes
663 663 changeset: 2:ed1b79f46b9a
664 664 tag: tip
665 665 parent: 0:bbd179dfa0a7
666 666 user: test
667 667 date: Thu Jan 01 00:00:00 1970 +0000
668 668 summary: change foo
669 669
670 670 $ cd ..
671 671
672 672 test bundle with # in the filename (issue2154):
673 673
674 674 $ cp bundle.hg 'test#bundle.hg'
675 675 $ cd orig
676 676 $ hg incoming '../test#bundle.hg'
677 677 comparing with ../test
678 678 abort: unknown revision 'bundle.hg'!
679 679 [255]
680 680
681 681 note that percent encoding is not handled:
682 682
683 683 $ hg incoming ../test%23bundle.hg
684 684 abort: repository ../test%23bundle.hg not found!
685 685 [255]
686 686 $ cd ..
687 687
688 688 #endif
689 689
690 690 test to bundle revisions on the newly created branch (issue3828):
691 691
692 692 $ hg -q clone -U test test-clone
693 693 $ cd test
694 694
695 695 $ hg -q branch foo
696 696 $ hg commit -m "create foo branch"
697 697 $ hg -q outgoing ../test-clone
698 698 9:b4f5acb1ee27
699 699 $ hg -q bundle --branch foo foo.hg ../test-clone
700 700 #if repobundlerepo
701 701 $ hg -R foo.hg -q log -r "bundle()"
702 702 9:b4f5acb1ee27
703 703 #endif
704 704
705 705 $ cd ..
706 706
707 707 test for https://bz.mercurial-scm.org/1144
708 708
709 709 test that verify bundle does not traceback
710 710
711 711 partial history bundle, fails w/ unknown parent
712 712
713 713 $ hg -R bundle.hg verify
714 714 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
715 715 [255]
716 716
717 717 full history bundle, refuses to verify non-local repo
718 718
719 719 #if repobundlerepo
720 720 $ hg -R all.hg verify
721 721 abort: cannot verify bundle or remote repos
722 722 [255]
723 723 #endif
724 724
725 725 but, regular verify must continue to work
726 726
727 727 $ hg -R orig verify
728 728 checking changesets
729 729 checking manifests
730 730 crosschecking files in changesets and manifests
731 731 checking files
732 732 2 files, 2 changesets, 2 total revisions
733 733
734 734 #if repobundlerepo
735 735 diff against bundle
736 736
737 737 $ hg init b
738 738 $ cd b
739 739 $ hg -R ../all.hg diff -r tip
740 740 diff -r aa35859c02ea anotherfile
741 741 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
742 742 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
743 743 @@ -1,4 +0,0 @@
744 744 -0
745 745 -1
746 746 -2
747 747 -3
748 748 $ cd ..
749 749 #endif
750 750
751 751 bundle single branch
752 752
753 753 $ hg init branchy
754 754 $ cd branchy
755 755 $ echo a >a
756 756 $ echo x >x
757 757 $ hg ci -Ama
758 758 adding a
759 759 adding x
760 760 $ echo c >c
761 761 $ echo xx >x
762 762 $ hg ci -Amc
763 763 adding c
764 764 $ echo c1 >c1
765 765 $ hg ci -Amc1
766 766 adding c1
767 767 $ hg up 0
768 768 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
769 769 $ echo b >b
770 770 $ hg ci -Amb
771 771 adding b
772 772 created new head
773 773 $ echo b1 >b1
774 774 $ echo xx >x
775 775 $ hg ci -Amb1
776 776 adding b1
777 777 $ hg clone -q -r2 . part
778 778
779 779 == bundling via incoming
780 780
781 781 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
782 782 comparing with .
783 783 searching for changes
784 784 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
785 785 057f4db07f61970e1c11e83be79e9d08adc4dc31
786 786
787 787 == bundling
788 788
789 789 $ hg bundle bundle.hg part --debug --config progress.debug=true
790 790 query 1; heads
791 791 searching for changes
792 792 all remote heads known locally
793 793 2 changesets found
794 794 list of changesets:
795 795 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
796 796 057f4db07f61970e1c11e83be79e9d08adc4dc31
797 797 bundle2-output-bundle: "HG20", (1 params) 2 parts total
798 798 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
799 bundling: 1/2 changesets (50.00%)
800 bundling: 2/2 changesets (100.00%)
801 bundling: 1/2 manifests (50.00%)
802 bundling: 2/2 manifests (100.00%)
803 bundling: b 1/3 files (33.33%)
804 bundling: b1 2/3 files (66.67%)
805 bundling: x 3/3 files (100.00%)
799 changesets: 1/2 chunks (50.00%)
800 changesets: 2/2 chunks (100.00%)
801 manifests: 1/2 chunks (50.00%)
802 manifests: 2/2 chunks (100.00%)
803 files: b 1/3 files (33.33%)
804 files: b1 2/3 files (66.67%)
805 files: x 3/3 files (100.00%)
806 806 bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload
807 807
808 808 #if repobundlerepo
809 809 == Test for issue3441
810 810
811 811 $ hg clone -q -r0 . part2
812 812 $ hg -q -R part2 pull bundle.hg
813 813 $ hg -R part2 verify
814 814 checking changesets
815 815 checking manifests
816 816 crosschecking files in changesets and manifests
817 817 checking files
818 818 4 files, 3 changesets, 5 total revisions
819 819 #endif
820 820
821 821 == Test bundling no commits
822 822
823 823 $ hg bundle -r 'public()' no-output.hg
824 824 abort: no commits to bundle
825 825 [255]
826 826
827 827 $ cd ..
828 828
829 829 When user merges to the revision existing only in the bundle,
830 830 it should show warning that second parent of the working
831 831 directory does not exist
832 832
833 833 $ hg init update2bundled
834 834 $ cd update2bundled
835 835 $ cat <<EOF >> .hg/hgrc
836 836 > [extensions]
837 837 > strip =
838 838 > EOF
839 839 $ echo "aaa" >> a
840 840 $ hg commit -A -m 0
841 841 adding a
842 842 $ echo "bbb" >> b
843 843 $ hg commit -A -m 1
844 844 adding b
845 845 $ echo "ccc" >> c
846 846 $ hg commit -A -m 2
847 847 adding c
848 848 $ hg update -r 1
849 849 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
850 850 $ echo "ddd" >> d
851 851 $ hg commit -A -m 3
852 852 adding d
853 853 created new head
854 854 $ hg update -r 2
855 855 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
856 856 $ hg log -G
857 857 o changeset: 3:8bd3e1f196af
858 858 | tag: tip
859 859 | parent: 1:a01eca7af26d
860 860 | user: test
861 861 | date: Thu Jan 01 00:00:00 1970 +0000
862 862 | summary: 3
863 863 |
864 864 | @ changeset: 2:4652c276ac4f
865 865 |/ user: test
866 866 | date: Thu Jan 01 00:00:00 1970 +0000
867 867 | summary: 2
868 868 |
869 869 o changeset: 1:a01eca7af26d
870 870 | user: test
871 871 | date: Thu Jan 01 00:00:00 1970 +0000
872 872 | summary: 1
873 873 |
874 874 o changeset: 0:4fe08cd4693e
875 875 user: test
876 876 date: Thu Jan 01 00:00:00 1970 +0000
877 877 summary: 0
878 878
879 879
880 880 #if repobundlerepo
881 881 $ hg bundle --base 1 -r 3 ../update2bundled.hg
882 882 1 changesets found
883 883 $ hg strip -r 3
884 884 saved backup bundle to $TESTTMP/update2bundled/.hg/strip-backup/8bd3e1f196af-017e56d8-backup.hg
885 885 $ hg merge -R ../update2bundled.hg -r 3
886 886 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
887 887 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
888 888 (branch merge, don't forget to commit)
889 889
890 890 When user updates to the revision existing only in the bundle,
891 891 it should show warning
892 892
893 893 $ hg update -R ../update2bundled.hg --clean -r 3
894 894 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
895 895 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
896 896
897 897 When user updates to the revision existing in the local repository
898 898 the warning shouldn't be emitted
899 899
900 900 $ hg update -R ../update2bundled.hg -r 0
901 901 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
902 902 #endif
@@ -1,1236 +1,1236 b''
1 1 This test is dedicated to test the bundle2 container format
2 2
3 3 It test multiple existing parts to test different feature of the container. You
4 4 probably do not need to touch this test unless you change the binary encoding
5 5 of the bundle2 format itself.
6 6
7 7 Create an extension to test bundle2 API
8 8
9 9 $ cat > bundle2.py << EOF
10 10 > """A small extension to test bundle2 implementation
11 11 >
12 12 > This extension allows detailed testing of the various bundle2 API and
13 13 > behaviors.
14 14 > """
15 15 > import gc
16 16 > import os
17 17 > import sys
18 18 > from mercurial import util
19 19 > from mercurial import bundle2
20 20 > from mercurial import scmutil
21 21 > from mercurial import discovery
22 22 > from mercurial import changegroup
23 23 > from mercurial import error
24 24 > from mercurial import obsolete
25 25 > from mercurial import pycompat
26 26 > from mercurial import registrar
27 27 >
28 28 >
29 29 > try:
30 30 > import msvcrt
31 31 > msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
32 32 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
33 33 > msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
34 34 > except ImportError:
35 35 > pass
36 36 >
37 37 > cmdtable = {}
38 38 > command = registrar.command(cmdtable)
39 39 >
40 40 > ELEPHANTSSONG = b"""Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
41 41 > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
42 42 > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
43 43 > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
44 44 >
45 45 > @bundle2.parthandler(b'test:song')
46 46 > def songhandler(op, part):
47 47 > """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
48 48 > op.ui.write(b'The choir starts singing:\n')
49 49 > verses = 0
50 50 > for line in part.read().split(b'\n'):
51 51 > op.ui.write(b' %s\n' % line)
52 52 > verses += 1
53 53 > op.records.add(b'song', {b'verses': verses})
54 54 >
55 55 > @bundle2.parthandler(b'test:ping')
56 56 > def pinghandler(op, part):
57 57 > op.ui.write(b'received ping request (id %i)\n' % part.id)
58 58 > if op.reply is not None and b'ping-pong' in op.reply.capabilities:
59 59 > op.ui.write_err(b'replying to ping request (id %i)\n' % part.id)
60 60 > op.reply.newpart(b'test:pong', [(b'in-reply-to', b'%d' % part.id)],
61 61 > mandatory=False)
62 62 >
63 63 > @bundle2.parthandler(b'test:debugreply')
64 64 > def debugreply(op, part):
65 65 > """print data about the capacity of the bundle reply"""
66 66 > if op.reply is None:
67 67 > op.ui.write(b'debugreply: no reply\n')
68 68 > else:
69 69 > op.ui.write(b'debugreply: capabilities:\n')
70 70 > for cap in sorted(op.reply.capabilities):
71 71 > op.ui.write(b"debugreply: '%s'\n" % cap)
72 72 > for val in op.reply.capabilities[cap]:
73 73 > op.ui.write(b"debugreply: '%s'\n" % val)
74 74 >
75 75 > @command(b'bundle2',
76 76 > [(b'', b'param', [], b'stream level parameter'),
77 77 > (b'', b'unknown', False, b'include an unknown mandatory part in the bundle'),
78 78 > (b'', b'unknownparams', False, b'include an unknown part parameters in the bundle'),
79 79 > (b'', b'parts', False, b'include some arbitrary parts to the bundle'),
80 80 > (b'', b'reply', False, b'produce a reply bundle'),
81 81 > (b'', b'pushrace', False, b'includes a check:head part with unknown nodes'),
82 82 > (b'', b'genraise', False, b'includes a part that raise an exception during generation'),
83 83 > (b'', b'timeout', False, b'emulate a timeout during bundle generation'),
84 84 > (b'r', b'rev', [], b'includes those changeset in the bundle'),
85 85 > (b'', b'compress', b'', b'compress the stream'),],
86 86 > b'[OUTPUTFILE]')
87 87 > def cmdbundle2(ui, repo, path=None, **opts):
88 88 > """write a bundle2 container on standard output"""
89 89 > bundler = bundle2.bundle20(ui)
90 90 > for p in opts['param']:
91 91 > p = p.split(b'=', 1)
92 92 > try:
93 93 > bundler.addparam(*p)
94 94 > except error.ProgrammingError as exc:
95 95 > raise error.Abort(b'%s' % exc)
96 96 >
97 97 > if opts['compress']:
98 98 > bundler.setcompression(opts['compress'])
99 99 >
100 100 > if opts['reply']:
101 101 > capsstring = b'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville'
102 102 > bundler.newpart(b'replycaps', data=capsstring)
103 103 >
104 104 > if opts['pushrace']:
105 105 > # also serve to test the assignement of data outside of init
106 106 > part = bundler.newpart(b'check:heads')
107 107 > part.data = b'01234567890123456789'
108 108 >
109 109 > revs = opts['rev']
110 110 > if 'rev' in opts:
111 111 > revs = scmutil.revrange(repo, opts['rev'])
112 112 > if revs:
113 113 > # very crude version of a changegroup part creation
114 114 > bundled = repo.revs('%ld::%ld', revs, revs)
115 115 > headmissing = [c.node() for c in repo.set('heads(%ld)', revs)]
116 116 > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)]
117 117 > outgoing = discovery.outgoing(repo, headcommon, headmissing)
118 118 > cg = changegroup.makechangegroup(repo, outgoing, b'01',
119 119 > b'test:bundle2')
120 120 > bundler.newpart(b'changegroup', data=cg.getchunks(),
121 121 > mandatory=False)
122 122 >
123 123 > if opts['parts']:
124 124 > bundler.newpart(b'test:empty', mandatory=False)
125 125 > # add a second one to make sure we handle multiple parts
126 126 > bundler.newpart(b'test:empty', mandatory=False)
127 127 > bundler.newpart(b'test:song', data=ELEPHANTSSONG, mandatory=False)
128 128 > bundler.newpart(b'test:debugreply', mandatory=False)
129 129 > mathpart = bundler.newpart(b'test:math')
130 130 > mathpart.addparam(b'pi', b'3.14')
131 131 > mathpart.addparam(b'e', b'2.72')
132 132 > mathpart.addparam(b'cooking', b'raw', mandatory=False)
133 133 > mathpart.data = b'42'
134 134 > mathpart.mandatory = False
135 135 > # advisory known part with unknown mandatory param
136 136 > bundler.newpart(b'test:song', [(b'randomparam', b'')], mandatory=False)
137 137 > if opts['unknown']:
138 138 > bundler.newpart(b'test:unknown', data=b'some random content')
139 139 > if opts['unknownparams']:
140 140 > bundler.newpart(b'test:song', [(b'randomparams', b'')])
141 141 > if opts['parts']:
142 142 > bundler.newpart(b'test:ping', mandatory=False)
143 143 > if opts['genraise']:
144 144 > def genraise():
145 145 > yield b'first line\n'
146 146 > raise RuntimeError('Someone set up us the bomb!')
147 147 > bundler.newpart(b'output', data=genraise(), mandatory=False)
148 148 >
149 149 > if path is None:
150 150 > file = pycompat.stdout
151 151 > else:
152 152 > file = open(path, 'wb')
153 153 >
154 154 > if opts['timeout']:
155 155 > bundler.newpart(b'test:song', data=ELEPHANTSSONG, mandatory=False)
156 156 > for idx, junk in enumerate(bundler.getchunks()):
157 157 > ui.write(b'%d chunk\n' % idx)
158 158 > if idx > 4:
159 159 > # This throws a GeneratorExit inside the generator, which
160 160 > # can cause problems if the exception-recovery code is
161 161 > # too zealous. It's important for this test that the break
162 162 > # occur while we're in the middle of a part.
163 163 > break
164 164 > gc.collect()
165 165 > ui.write(b'fake timeout complete.\n')
166 166 > return
167 167 > try:
168 168 > for chunk in bundler.getchunks():
169 169 > file.write(chunk)
170 170 > except RuntimeError as exc:
171 171 > raise error.Abort(exc)
172 172 > finally:
173 173 > file.flush()
174 174 >
175 175 > @command(b'unbundle2', [], b'')
176 176 > def cmdunbundle2(ui, repo, replypath=None):
177 177 > """process a bundle2 stream from stdin on the current repo"""
178 178 > try:
179 179 > tr = None
180 180 > lock = repo.lock()
181 181 > tr = repo.transaction(b'processbundle')
182 182 > try:
183 183 > unbundler = bundle2.getunbundler(ui, pycompat.stdin)
184 184 > op = bundle2.processbundle(repo, unbundler, lambda: tr)
185 185 > tr.close()
186 186 > except error.BundleValueError as exc:
187 187 > raise error.Abort(b'missing support for %s' % exc)
188 188 > except error.PushRaced as exc:
189 189 > raise error.Abort(b'push race: %s' % exc)
190 190 > finally:
191 191 > if tr is not None:
192 192 > tr.release()
193 193 > lock.release()
194 194 > remains = pycompat.stdin.read()
195 195 > ui.write(b'%i unread bytes\n' % len(remains))
196 196 > if op.records[b'song']:
197 197 > totalverses = sum(r[b'verses'] for r in op.records[b'song'])
198 198 > ui.write(b'%i total verses sung\n' % totalverses)
199 199 > for rec in op.records[b'changegroup']:
200 200 > ui.write(b'addchangegroup return: %i\n' % rec[b'return'])
201 201 > if op.reply is not None and replypath is not None:
202 202 > with open(replypath, 'wb') as file:
203 203 > for chunk in op.reply.getchunks():
204 204 > file.write(chunk)
205 205 >
206 206 > @command(b'statbundle2', [], b'')
207 207 > def cmdstatbundle2(ui, repo):
208 208 > """print statistic on the bundle2 container read from stdin"""
209 209 > unbundler = bundle2.getunbundler(ui, pycompat.stdin)
210 210 > try:
211 211 > params = unbundler.params
212 212 > except error.BundleValueError as exc:
213 213 > raise error.Abort(b'unknown parameters: %s' % exc)
214 214 > ui.write(b'options count: %i\n' % len(params))
215 215 > for key in sorted(params):
216 216 > ui.write(b'- %s\n' % key)
217 217 > value = params[key]
218 218 > if value is not None:
219 219 > ui.write(b' %s\n' % value)
220 220 > count = 0
221 221 > for p in unbundler.iterparts():
222 222 > count += 1
223 223 > ui.write(b' :%s:\n' % p.type)
224 224 > ui.write(b' mandatory: %i\n' % len(p.mandatoryparams))
225 225 > ui.write(b' advisory: %i\n' % len(p.advisoryparams))
226 226 > ui.write(b' payload: %i bytes\n' % len(p.read()))
227 227 > ui.write(b'parts count: %i\n' % count)
228 228 > EOF
229 229 $ cat >> $HGRCPATH << EOF
230 230 > [extensions]
231 231 > bundle2=$TESTTMP/bundle2.py
232 232 > [experimental]
233 233 > evolution.createmarkers=True
234 234 > [ui]
235 235 > ssh=$PYTHON "$TESTDIR/dummyssh"
236 236 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
237 237 > [web]
238 238 > push_ssl = false
239 239 > allow_push = *
240 240 > [phases]
241 241 > publish=False
242 242 > EOF
243 243
244 244 The extension requires a repo (currently unused)
245 245
246 246 $ hg init main
247 247 $ cd main
248 248 $ touch a
249 249 $ hg add a
250 250 $ hg commit -m 'a'
251 251
252 252
253 253 Empty bundle
254 254 =================
255 255
256 256 - no option
257 257 - no parts
258 258
259 259 Test bundling
260 260
261 261 $ hg bundle2 | f --hexdump
262 262
263 263 0000: 48 47 32 30 00 00 00 00 00 00 00 00 |HG20........|
264 264
265 265 Test timeouts during bundling
266 266 $ hg bundle2 --timeout --debug --config devel.bundle2.debug=yes
267 267 bundle2-output-bundle: "HG20", 1 parts total
268 268 bundle2-output: start emission of HG20 stream
269 269 0 chunk
270 270 bundle2-output: bundle parameter:
271 271 1 chunk
272 272 bundle2-output: start of parts
273 273 bundle2-output: bundle part: "test:song"
274 274 bundle2-output-part: "test:song" (advisory) 178 bytes payload
275 275 bundle2-output: part 0: "test:song"
276 276 bundle2-output: header chunk size: 16
277 277 2 chunk
278 278 3 chunk
279 279 bundle2-output: payload chunk size: 178
280 280 4 chunk
281 281 5 chunk
282 282 bundle2-generatorexit
283 283 fake timeout complete.
284 284
285 285 Test unbundling
286 286
287 287 $ hg bundle2 | hg statbundle2
288 288 options count: 0
289 289 parts count: 0
290 290
291 291 Test old style bundle are detected and refused
292 292
293 293 $ hg bundle --all --type v1 ../bundle.hg
294 294 1 changesets found
295 295 $ hg statbundle2 < ../bundle.hg
296 296 abort: unknown bundle version 10
297 297 [255]
298 298
299 299 Test parameters
300 300 =================
301 301
302 302 - some options
303 303 - no parts
304 304
305 305 advisory parameters, no value
306 306 -------------------------------
307 307
308 308 Simplest possible parameters form
309 309
310 310 Test generation simple option
311 311
312 312 $ hg bundle2 --param 'caution' | f --hexdump
313 313
314 314 0000: 48 47 32 30 00 00 00 07 63 61 75 74 69 6f 6e 00 |HG20....caution.|
315 315 0010: 00 00 00 |...|
316 316
317 317 Test unbundling
318 318
319 319 $ hg bundle2 --param 'caution' | hg statbundle2
320 320 options count: 1
321 321 - caution
322 322 parts count: 0
323 323
324 324 Test generation multiple option
325 325
326 326 $ hg bundle2 --param 'caution' --param 'meal' | f --hexdump
327 327
328 328 0000: 48 47 32 30 00 00 00 0c 63 61 75 74 69 6f 6e 20 |HG20....caution |
329 329 0010: 6d 65 61 6c 00 00 00 00 |meal....|
330 330
331 331 Test unbundling
332 332
333 333 $ hg bundle2 --param 'caution' --param 'meal' | hg statbundle2
334 334 options count: 2
335 335 - caution
336 336 - meal
337 337 parts count: 0
338 338
339 339 advisory parameters, with value
340 340 -------------------------------
341 341
342 342 Test generation
343 343
344 344 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants' | f --hexdump
345 345
346 346 0000: 48 47 32 30 00 00 00 1c 63 61 75 74 69 6f 6e 20 |HG20....caution |
347 347 0010: 6d 65 61 6c 3d 76 65 67 61 6e 20 65 6c 65 70 68 |meal=vegan eleph|
348 348 0020: 61 6e 74 73 00 00 00 00 |ants....|
349 349
350 350 Test unbundling
351 351
352 352 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants' | hg statbundle2
353 353 options count: 3
354 354 - caution
355 355 - elephants
356 356 - meal
357 357 vegan
358 358 parts count: 0
359 359
360 360 parameter with special char in value
361 361 ---------------------------------------------------
362 362
363 363 Test generation
364 364
365 365 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple | f --hexdump
366 366
367 367 0000: 48 47 32 30 00 00 00 29 65 25 37 43 25 32 31 25 |HG20...)e%7C%21%|
368 368 0010: 32 30 37 2f 3d 62 61 62 61 72 25 32 35 25 32 33 |207/=babar%25%23|
369 369 0020: 25 33 44 25 33 44 74 75 74 75 20 73 69 6d 70 6c |%3D%3Dtutu simpl|
370 370 0030: 65 00 00 00 00 |e....|
371 371
372 372 Test unbundling
373 373
374 374 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple | hg statbundle2
375 375 options count: 2
376 376 - e|! 7/
377 377 babar%#==tutu
378 378 - simple
379 379 parts count: 0
380 380
381 381 Test unknown mandatory option
382 382 ---------------------------------------------------
383 383
384 384 $ hg bundle2 --param 'Gravity' | hg statbundle2
385 385 abort: unknown parameters: Stream Parameter - Gravity
386 386 [255]
387 387
388 388 Test debug output
389 389 ---------------------------------------------------
390 390
391 391 bundling debug
392 392
393 393 $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2 --config progress.debug=true --config devel.bundle2.debug=true
394 394 bundle2-output-bundle: "HG20", (2 params) 0 parts total
395 395 bundle2-output: start emission of HG20 stream
396 396 bundle2-output: bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
397 397 bundle2-output: start of parts
398 398 bundle2-output: end of bundle
399 399
400 400 file content is ok
401 401
402 402 $ f --hexdump ../out.hg2
403 403 ../out.hg2:
404 404 0000: 48 47 32 30 00 00 00 29 65 25 37 43 25 32 31 25 |HG20...)e%7C%21%|
405 405 0010: 32 30 37 2f 3d 62 61 62 61 72 25 32 35 25 32 33 |207/=babar%25%23|
406 406 0020: 25 33 44 25 33 44 74 75 74 75 20 73 69 6d 70 6c |%3D%3Dtutu simpl|
407 407 0030: 65 00 00 00 00 |e....|
408 408
409 409 unbundling debug
410 410
411 411 $ hg statbundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true < ../out.hg2
412 412 bundle2-input: start processing of HG20 stream
413 413 bundle2-input: reading bundle2 stream parameters
414 414 bundle2-input: ignoring unknown parameter e|! 7/
415 415 bundle2-input: ignoring unknown parameter simple
416 416 options count: 2
417 417 - e|! 7/
418 418 babar%#==tutu
419 419 - simple
420 420 bundle2-input: start extraction of bundle2 parts
421 421 bundle2-input: part header size: 0
422 422 bundle2-input: end of bundle2 stream
423 423 parts count: 0
424 424
425 425
426 426 Test buggy input
427 427 ---------------------------------------------------
428 428
429 429 empty parameter name
430 430
431 431 $ hg bundle2 --param '' --quiet
432 432 abort: empty parameter name
433 433 [255]
434 434
435 435 bad parameter name
436 436
437 437 $ hg bundle2 --param 42babar
438 438 abort: non letter first character: 42babar
439 439 [255]
440 440
441 441
442 442 Test part
443 443 =================
444 444
445 445 $ hg bundle2 --parts ../parts.hg2 --debug --config progress.debug=true --config devel.bundle2.debug=true
446 446 bundle2-output-bundle: "HG20", 7 parts total
447 447 bundle2-output: start emission of HG20 stream
448 448 bundle2-output: bundle parameter:
449 449 bundle2-output: start of parts
450 450 bundle2-output: bundle part: "test:empty"
451 451 bundle2-output-part: "test:empty" (advisory) empty payload
452 452 bundle2-output: part 0: "test:empty"
453 453 bundle2-output: header chunk size: 17
454 454 bundle2-output: closing payload chunk
455 455 bundle2-output: bundle part: "test:empty"
456 456 bundle2-output-part: "test:empty" (advisory) empty payload
457 457 bundle2-output: part 1: "test:empty"
458 458 bundle2-output: header chunk size: 17
459 459 bundle2-output: closing payload chunk
460 460 bundle2-output: bundle part: "test:song"
461 461 bundle2-output-part: "test:song" (advisory) 178 bytes payload
462 462 bundle2-output: part 2: "test:song"
463 463 bundle2-output: header chunk size: 16
464 464 bundle2-output: payload chunk size: 178
465 465 bundle2-output: closing payload chunk
466 466 bundle2-output: bundle part: "test:debugreply"
467 467 bundle2-output-part: "test:debugreply" (advisory) empty payload
468 468 bundle2-output: part 3: "test:debugreply"
469 469 bundle2-output: header chunk size: 22
470 470 bundle2-output: closing payload chunk
471 471 bundle2-output: bundle part: "test:math"
472 472 bundle2-output-part: "test:math" (advisory) (params: 2 mandatory 2 advisory) 2 bytes payload
473 473 bundle2-output: part 4: "test:math"
474 474 bundle2-output: header chunk size: 43
475 475 bundle2-output: payload chunk size: 2
476 476 bundle2-output: closing payload chunk
477 477 bundle2-output: bundle part: "test:song"
478 478 bundle2-output-part: "test:song" (advisory) (params: 1 mandatory) empty payload
479 479 bundle2-output: part 5: "test:song"
480 480 bundle2-output: header chunk size: 29
481 481 bundle2-output: closing payload chunk
482 482 bundle2-output: bundle part: "test:ping"
483 483 bundle2-output-part: "test:ping" (advisory) empty payload
484 484 bundle2-output: part 6: "test:ping"
485 485 bundle2-output: header chunk size: 16
486 486 bundle2-output: closing payload chunk
487 487 bundle2-output: end of bundle
488 488
489 489 $ f --hexdump ../parts.hg2
490 490 ../parts.hg2:
491 491 0000: 48 47 32 30 00 00 00 00 00 00 00 11 0a 74 65 73 |HG20.........tes|
492 492 0010: 74 3a 65 6d 70 74 79 00 00 00 00 00 00 00 00 00 |t:empty.........|
493 493 0020: 00 00 00 00 11 0a 74 65 73 74 3a 65 6d 70 74 79 |......test:empty|
494 494 0030: 00 00 00 01 00 00 00 00 00 00 00 00 00 10 09 74 |...............t|
495 495 0040: 65 73 74 3a 73 6f 6e 67 00 00 00 02 00 00 00 00 |est:song........|
496 496 0050: 00 b2 50 61 74 61 6c 69 20 44 69 72 61 70 61 74 |..Patali Dirapat|
497 497 0060: 61 2c 20 43 72 6f 6d 64 61 20 43 72 6f 6d 64 61 |a, Cromda Cromda|
498 498 0070: 20 52 69 70 61 6c 6f 2c 20 50 61 74 61 20 50 61 | Ripalo, Pata Pa|
499 499 0080: 74 61 2c 20 4b 6f 20 4b 6f 20 4b 6f 0a 42 6f 6b |ta, Ko Ko Ko.Bok|
500 500 0090: 6f 72 6f 20 44 69 70 6f 75 6c 69 74 6f 2c 20 52 |oro Dipoulito, R|
501 501 00a0: 6f 6e 64 69 20 52 6f 6e 64 69 20 50 65 70 69 6e |ondi Rondi Pepin|
502 502 00b0: 6f 2c 20 50 61 74 61 20 50 61 74 61 2c 20 4b 6f |o, Pata Pata, Ko|
503 503 00c0: 20 4b 6f 20 4b 6f 0a 45 6d 61 6e 61 20 4b 61 72 | Ko Ko.Emana Kar|
504 504 00d0: 61 73 73 6f 6c 69 2c 20 4c 6f 75 63 72 61 20 4c |assoli, Loucra L|
505 505 00e0: 6f 75 63 72 61 20 50 6f 6e 70 6f 6e 74 6f 2c 20 |oucra Ponponto, |
506 506 00f0: 50 61 74 61 20 50 61 74 61 2c 20 4b 6f 20 4b 6f |Pata Pata, Ko Ko|
507 507 0100: 20 4b 6f 2e 00 00 00 00 00 00 00 16 0f 74 65 73 | Ko..........tes|
508 508 0110: 74 3a 64 65 62 75 67 72 65 70 6c 79 00 00 00 03 |t:debugreply....|
509 509 0120: 00 00 00 00 00 00 00 00 00 2b 09 74 65 73 74 3a |.........+.test:|
510 510 0130: 6d 61 74 68 00 00 00 04 02 01 02 04 01 04 07 03 |math............|
511 511 0140: 70 69 33 2e 31 34 65 32 2e 37 32 63 6f 6f 6b 69 |pi3.14e2.72cooki|
512 512 0150: 6e 67 72 61 77 00 00 00 02 34 32 00 00 00 00 00 |ngraw....42.....|
513 513 0160: 00 00 1d 09 74 65 73 74 3a 73 6f 6e 67 00 00 00 |....test:song...|
514 514 0170: 05 01 00 0b 00 72 61 6e 64 6f 6d 70 61 72 61 6d |.....randomparam|
515 515 0180: 00 00 00 00 00 00 00 10 09 74 65 73 74 3a 70 69 |.........test:pi|
516 516 0190: 6e 67 00 00 00 06 00 00 00 00 00 00 00 00 00 00 |ng..............|
517 517
518 518
519 519 $ hg statbundle2 < ../parts.hg2
520 520 options count: 0
521 521 :test:empty:
522 522 mandatory: 0
523 523 advisory: 0
524 524 payload: 0 bytes
525 525 :test:empty:
526 526 mandatory: 0
527 527 advisory: 0
528 528 payload: 0 bytes
529 529 :test:song:
530 530 mandatory: 0
531 531 advisory: 0
532 532 payload: 178 bytes
533 533 :test:debugreply:
534 534 mandatory: 0
535 535 advisory: 0
536 536 payload: 0 bytes
537 537 :test:math:
538 538 mandatory: 2
539 539 advisory: 1
540 540 payload: 2 bytes
541 541 :test:song:
542 542 mandatory: 1
543 543 advisory: 0
544 544 payload: 0 bytes
545 545 :test:ping:
546 546 mandatory: 0
547 547 advisory: 0
548 548 payload: 0 bytes
549 549 parts count: 7
550 550
551 551 $ hg statbundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true < ../parts.hg2
552 552 bundle2-input: start processing of HG20 stream
553 553 bundle2-input: reading bundle2 stream parameters
554 554 options count: 0
555 555 bundle2-input: start extraction of bundle2 parts
556 556 bundle2-input: part header size: 17
557 557 bundle2-input: part type: "test:empty"
558 558 bundle2-input: part id: "0"
559 559 bundle2-input: part parameters: 0
560 560 :test:empty:
561 561 mandatory: 0
562 562 advisory: 0
563 563 bundle2-input: payload chunk size: 0
564 564 payload: 0 bytes
565 565 bundle2-input: part header size: 17
566 566 bundle2-input: part type: "test:empty"
567 567 bundle2-input: part id: "1"
568 568 bundle2-input: part parameters: 0
569 569 :test:empty:
570 570 mandatory: 0
571 571 advisory: 0
572 572 bundle2-input: payload chunk size: 0
573 573 payload: 0 bytes
574 574 bundle2-input: part header size: 16
575 575 bundle2-input: part type: "test:song"
576 576 bundle2-input: part id: "2"
577 577 bundle2-input: part parameters: 0
578 578 :test:song:
579 579 mandatory: 0
580 580 advisory: 0
581 581 bundle2-input: payload chunk size: 178
582 582 bundle2-input: payload chunk size: 0
583 583 bundle2-input-part: total payload size 178
584 584 payload: 178 bytes
585 585 bundle2-input: part header size: 22
586 586 bundle2-input: part type: "test:debugreply"
587 587 bundle2-input: part id: "3"
588 588 bundle2-input: part parameters: 0
589 589 :test:debugreply:
590 590 mandatory: 0
591 591 advisory: 0
592 592 bundle2-input: payload chunk size: 0
593 593 payload: 0 bytes
594 594 bundle2-input: part header size: 43
595 595 bundle2-input: part type: "test:math"
596 596 bundle2-input: part id: "4"
597 597 bundle2-input: part parameters: 3
598 598 :test:math:
599 599 mandatory: 2
600 600 advisory: 1
601 601 bundle2-input: payload chunk size: 2
602 602 bundle2-input: payload chunk size: 0
603 603 bundle2-input-part: total payload size 2
604 604 payload: 2 bytes
605 605 bundle2-input: part header size: 29
606 606 bundle2-input: part type: "test:song"
607 607 bundle2-input: part id: "5"
608 608 bundle2-input: part parameters: 1
609 609 :test:song:
610 610 mandatory: 1
611 611 advisory: 0
612 612 bundle2-input: payload chunk size: 0
613 613 payload: 0 bytes
614 614 bundle2-input: part header size: 16
615 615 bundle2-input: part type: "test:ping"
616 616 bundle2-input: part id: "6"
617 617 bundle2-input: part parameters: 0
618 618 :test:ping:
619 619 mandatory: 0
620 620 advisory: 0
621 621 bundle2-input: payload chunk size: 0
622 622 payload: 0 bytes
623 623 bundle2-input: part header size: 0
624 624 bundle2-input: end of bundle2 stream
625 625 parts count: 7
626 626
627 627 Test actual unbundling of test part
628 628 =======================================
629 629
630 630 Process the bundle
631 631
632 632 $ hg unbundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true < ../parts.hg2
633 633 bundle2-input: start processing of HG20 stream
634 634 bundle2-input: reading bundle2 stream parameters
635 635 bundle2-input-bundle: with-transaction
636 636 bundle2-input: start extraction of bundle2 parts
637 637 bundle2-input: part header size: 17
638 638 bundle2-input: part type: "test:empty"
639 639 bundle2-input: part id: "0"
640 640 bundle2-input: part parameters: 0
641 641 bundle2-input: ignoring unsupported advisory part test:empty
642 642 bundle2-input-part: "test:empty" (advisory) unsupported-type
643 643 bundle2-input: payload chunk size: 0
644 644 bundle2-input: part header size: 17
645 645 bundle2-input: part type: "test:empty"
646 646 bundle2-input: part id: "1"
647 647 bundle2-input: part parameters: 0
648 648 bundle2-input: ignoring unsupported advisory part test:empty
649 649 bundle2-input-part: "test:empty" (advisory) unsupported-type
650 650 bundle2-input: payload chunk size: 0
651 651 bundle2-input: part header size: 16
652 652 bundle2-input: part type: "test:song"
653 653 bundle2-input: part id: "2"
654 654 bundle2-input: part parameters: 0
655 655 bundle2-input: found a handler for part test:song
656 656 bundle2-input-part: "test:song" (advisory) supported
657 657 The choir starts singing:
658 658 bundle2-input: payload chunk size: 178
659 659 bundle2-input: payload chunk size: 0
660 660 bundle2-input-part: total payload size 178
661 661 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
662 662 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
663 663 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
664 664 bundle2-input: part header size: 22
665 665 bundle2-input: part type: "test:debugreply"
666 666 bundle2-input: part id: "3"
667 667 bundle2-input: part parameters: 0
668 668 bundle2-input: found a handler for part test:debugreply
669 669 bundle2-input-part: "test:debugreply" (advisory) supported
670 670 debugreply: no reply
671 671 bundle2-input: payload chunk size: 0
672 672 bundle2-input: part header size: 43
673 673 bundle2-input: part type: "test:math"
674 674 bundle2-input: part id: "4"
675 675 bundle2-input: part parameters: 3
676 676 bundle2-input: ignoring unsupported advisory part test:math
677 677 bundle2-input-part: "test:math" (advisory) (params: 2 mandatory 2 advisory) unsupported-type
678 678 bundle2-input: payload chunk size: 2
679 679 bundle2-input: payload chunk size: 0
680 680 bundle2-input-part: total payload size 2
681 681 bundle2-input: part header size: 29
682 682 bundle2-input: part type: "test:song"
683 683 bundle2-input: part id: "5"
684 684 bundle2-input: part parameters: 1
685 685 bundle2-input: found a handler for part test:song
686 686 bundle2-input: ignoring unsupported advisory part test:song - randomparam
687 687 bundle2-input-part: "test:song" (advisory) (params: 1 mandatory) unsupported-params (randomparam)
688 688 bundle2-input: payload chunk size: 0
689 689 bundle2-input: part header size: 16
690 690 bundle2-input: part type: "test:ping"
691 691 bundle2-input: part id: "6"
692 692 bundle2-input: part parameters: 0
693 693 bundle2-input: found a handler for part test:ping
694 694 bundle2-input-part: "test:ping" (advisory) supported
695 695 received ping request (id 6)
696 696 bundle2-input: payload chunk size: 0
697 697 bundle2-input: part header size: 0
698 698 bundle2-input: end of bundle2 stream
699 699 bundle2-input-bundle: 6 parts total
700 700 0 unread bytes
701 701 3 total verses sung
702 702
703 703 Unbundle with an unknown mandatory part
704 704 (should abort)
705 705
706 706 $ hg bundle2 --parts --unknown ../unknown.hg2
707 707
708 708 $ hg unbundle2 < ../unknown.hg2
709 709 The choir starts singing:
710 710 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
711 711 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
712 712 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
713 713 debugreply: no reply
714 714 0 unread bytes
715 715 abort: missing support for test:unknown
716 716 [255]
717 717
718 718 Unbundle with an unknown mandatory part parameters
719 719 (should abort)
720 720
721 721 $ hg bundle2 --unknownparams ../unknown.hg2
722 722
723 723 $ hg unbundle2 < ../unknown.hg2
724 724 0 unread bytes
725 725 abort: missing support for test:song - randomparams
726 726 [255]
727 727
728 728 unbundle with a reply
729 729
730 730 $ hg bundle2 --parts --reply ../parts-reply.hg2
731 731 $ hg unbundle2 ../reply.hg2 < ../parts-reply.hg2
732 732 0 unread bytes
733 733 3 total verses sung
734 734
735 735 The reply is a bundle
736 736
737 737 $ f --hexdump ../reply.hg2
738 738 ../reply.hg2:
739 739 0000: 48 47 32 30 00 00 00 00 00 00 00 1b 06 6f 75 74 |HG20.........out|
740 740 0010: 70 75 74 00 00 00 00 00 01 0b 01 69 6e 2d 72 65 |put........in-re|
741 741 0020: 70 6c 79 2d 74 6f 33 00 00 00 d9 54 68 65 20 63 |ply-to3....The c|
742 742 0030: 68 6f 69 72 20 73 74 61 72 74 73 20 73 69 6e 67 |hoir starts sing|
743 743 0040: 69 6e 67 3a 0a 20 20 20 20 50 61 74 61 6c 69 20 |ing:. Patali |
744 744 0050: 44 69 72 61 70 61 74 61 2c 20 43 72 6f 6d 64 61 |Dirapata, Cromda|
745 745 0060: 20 43 72 6f 6d 64 61 20 52 69 70 61 6c 6f 2c 20 | Cromda Ripalo, |
746 746 0070: 50 61 74 61 20 50 61 74 61 2c 20 4b 6f 20 4b 6f |Pata Pata, Ko Ko|
747 747 0080: 20 4b 6f 0a 20 20 20 20 42 6f 6b 6f 72 6f 20 44 | Ko. Bokoro D|
748 748 0090: 69 70 6f 75 6c 69 74 6f 2c 20 52 6f 6e 64 69 20 |ipoulito, Rondi |
749 749 00a0: 52 6f 6e 64 69 20 50 65 70 69 6e 6f 2c 20 50 61 |Rondi Pepino, Pa|
750 750 00b0: 74 61 20 50 61 74 61 2c 20 4b 6f 20 4b 6f 20 4b |ta Pata, Ko Ko K|
751 751 00c0: 6f 0a 20 20 20 20 45 6d 61 6e 61 20 4b 61 72 61 |o. Emana Kara|
752 752 00d0: 73 73 6f 6c 69 2c 20 4c 6f 75 63 72 61 20 4c 6f |ssoli, Loucra Lo|
753 753 00e0: 75 63 72 61 20 50 6f 6e 70 6f 6e 74 6f 2c 20 50 |ucra Ponponto, P|
754 754 00f0: 61 74 61 20 50 61 74 61 2c 20 4b 6f 20 4b 6f 20 |ata Pata, Ko Ko |
755 755 0100: 4b 6f 2e 0a 00 00 00 00 00 00 00 1b 06 6f 75 74 |Ko...........out|
756 756 0110: 70 75 74 00 00 00 01 00 01 0b 01 69 6e 2d 72 65 |put........in-re|
757 757 0120: 70 6c 79 2d 74 6f 34 00 00 00 c9 64 65 62 75 67 |ply-to4....debug|
758 758 0130: 72 65 70 6c 79 3a 20 63 61 70 61 62 69 6c 69 74 |reply: capabilit|
759 759 0140: 69 65 73 3a 0a 64 65 62 75 67 72 65 70 6c 79 3a |ies:.debugreply:|
760 760 0150: 20 20 20 20 20 27 63 69 74 79 3d 21 27 0a 64 65 | 'city=!'.de|
761 761 0160: 62 75 67 72 65 70 6c 79 3a 20 20 20 20 20 20 20 |bugreply: |
762 762 0170: 20 20 27 63 65 6c 65 73 74 65 2c 76 69 6c 6c 65 | 'celeste,ville|
763 763 0180: 27 0a 64 65 62 75 67 72 65 70 6c 79 3a 20 20 20 |'.debugreply: |
764 764 0190: 20 20 27 65 6c 65 70 68 61 6e 74 73 27 0a 64 65 | 'elephants'.de|
765 765 01a0: 62 75 67 72 65 70 6c 79 3a 20 20 20 20 20 20 20 |bugreply: |
766 766 01b0: 20 20 27 62 61 62 61 72 27 0a 64 65 62 75 67 72 | 'babar'.debugr|
767 767 01c0: 65 70 6c 79 3a 20 20 20 20 20 20 20 20 20 27 63 |eply: 'c|
768 768 01d0: 65 6c 65 73 74 65 27 0a 64 65 62 75 67 72 65 70 |eleste'.debugrep|
769 769 01e0: 6c 79 3a 20 20 20 20 20 27 70 69 6e 67 2d 70 6f |ly: 'ping-po|
770 770 01f0: 6e 67 27 0a 00 00 00 00 00 00 00 1e 09 74 65 73 |ng'..........tes|
771 771 0200: 74 3a 70 6f 6e 67 00 00 00 02 01 00 0b 01 69 6e |t:pong........in|
772 772 0210: 2d 72 65 70 6c 79 2d 74 6f 37 00 00 00 00 00 00 |-reply-to7......|
773 773 0220: 00 1b 06 6f 75 74 70 75 74 00 00 00 03 00 01 0b |...output.......|
774 774 0230: 01 69 6e 2d 72 65 70 6c 79 2d 74 6f 37 00 00 00 |.in-reply-to7...|
775 775 0240: 3d 72 65 63 65 69 76 65 64 20 70 69 6e 67 20 72 |=received ping r|
776 776 0250: 65 71 75 65 73 74 20 28 69 64 20 37 29 0a 72 65 |equest (id 7).re|
777 777 0260: 70 6c 79 69 6e 67 20 74 6f 20 70 69 6e 67 20 72 |plying to ping r|
778 778 0270: 65 71 75 65 73 74 20 28 69 64 20 37 29 0a 00 00 |equest (id 7)...|
779 779 0280: 00 00 00 00 00 00 |......|
780 780
781 781 The reply is valid
782 782
783 783 $ hg statbundle2 < ../reply.hg2
784 784 options count: 0
785 785 :output:
786 786 mandatory: 0
787 787 advisory: 1
788 788 payload: 217 bytes
789 789 :output:
790 790 mandatory: 0
791 791 advisory: 1
792 792 payload: 201 bytes
793 793 :test:pong:
794 794 mandatory: 1
795 795 advisory: 0
796 796 payload: 0 bytes
797 797 :output:
798 798 mandatory: 0
799 799 advisory: 1
800 800 payload: 61 bytes
801 801 parts count: 4
802 802
803 803 Unbundle the reply to get the output:
804 804
805 805 $ hg unbundle2 < ../reply.hg2
806 806 remote: The choir starts singing:
807 807 remote: Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
808 808 remote: Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
809 809 remote: Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
810 810 remote: debugreply: capabilities:
811 811 remote: debugreply: 'city=!'
812 812 remote: debugreply: 'celeste,ville'
813 813 remote: debugreply: 'elephants'
814 814 remote: debugreply: 'babar'
815 815 remote: debugreply: 'celeste'
816 816 remote: debugreply: 'ping-pong'
817 817 remote: received ping request (id 7)
818 818 remote: replying to ping request (id 7)
819 819 0 unread bytes
820 820
821 821 Test push race detection
822 822
823 823 $ hg bundle2 --pushrace ../part-race.hg2
824 824
825 825 $ hg unbundle2 < ../part-race.hg2
826 826 0 unread bytes
827 827 abort: push race: repository changed while pushing - please try again
828 828 [255]
829 829
830 830 Support for changegroup
831 831 ===================================
832 832
833 833 $ hg unbundle $TESTDIR/bundles/rebase.hg
834 834 adding changesets
835 835 adding manifests
836 836 adding file changes
837 837 added 8 changesets with 7 changes to 7 files (+3 heads)
838 838 new changesets cd010b8cd998:02de42196ebe
839 839 (run 'hg heads' to see heads, 'hg merge' to merge)
840 840
841 841 $ hg log -G
842 842 o 8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H
843 843 |
844 844 | o 7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com> G
845 845 |/|
846 846 o | 6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
847 847 | |
848 848 | o 5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
849 849 |/
850 850 | o 4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com> D
851 851 | |
852 852 | o 3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C
853 853 | |
854 854 | o 2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B
855 855 |/
856 856 o 1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com> A
857 857
858 858 @ 0:3903775176ed draft test a
859 859
860 860
861 861 $ hg bundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true --rev '8+7+5+4' ../rev.hg2
862 862 4 changesets found
863 863 list of changesets:
864 864 32af7686d403cf45b5d95f2d70cebea587ac806a
865 865 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
866 866 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
867 867 02de42196ebee42ef284b6780a87cdc96e8eaab6
868 868 bundle2-output-bundle: "HG20", 1 parts total
869 869 bundle2-output: start emission of HG20 stream
870 870 bundle2-output: bundle parameter:
871 871 bundle2-output: start of parts
872 872 bundle2-output: bundle part: "changegroup"
873 873 bundle2-output-part: "changegroup" (advisory) streamed payload
874 874 bundle2-output: part 0: "changegroup"
875 875 bundle2-output: header chunk size: 18
876 bundling: 1/4 changesets (25.00%)
877 bundling: 2/4 changesets (50.00%)
878 bundling: 3/4 changesets (75.00%)
879 bundling: 4/4 changesets (100.00%)
880 bundling: 1/4 manifests (25.00%)
881 bundling: 2/4 manifests (50.00%)
882 bundling: 3/4 manifests (75.00%)
883 bundling: 4/4 manifests (100.00%)
884 bundling: D 1/3 files (33.33%)
885 bundling: E 2/3 files (66.67%)
886 bundling: H 3/3 files (100.00%)
876 changesets: 1/4 chunks (25.00%)
877 changesets: 2/4 chunks (50.00%)
878 changesets: 3/4 chunks (75.00%)
879 changesets: 4/4 chunks (100.00%)
880 manifests: 1/4 chunks (25.00%)
881 manifests: 2/4 chunks (50.00%)
882 manifests: 3/4 chunks (75.00%)
883 manifests: 4/4 chunks (100.00%)
884 files: D 1/3 files (33.33%)
885 files: E 2/3 files (66.67%)
886 files: H 3/3 files (100.00%)
887 887 bundle2-output: payload chunk size: 1555
888 888 bundle2-output: closing payload chunk
889 889 bundle2-output: end of bundle
890 890
891 891 $ f --hexdump ../rev.hg2
892 892 ../rev.hg2:
893 893 0000: 48 47 32 30 00 00 00 00 00 00 00 12 0b 63 68 61 |HG20.........cha|
894 894 0010: 6e 67 65 67 72 6f 75 70 00 00 00 00 00 00 00 00 |ngegroup........|
895 895 0020: 06 13 00 00 00 a4 32 af 76 86 d4 03 cf 45 b5 d9 |......2.v....E..|
896 896 0030: 5f 2d 70 ce be a5 87 ac 80 6a 5f dd d9 89 57 c8 |_-p......j_...W.|
897 897 0040: a5 4a 4d 43 6d fe 1d a9 d8 7f 21 a1 b9 7b 00 00 |.JMCm.....!..{..|
898 898 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
899 899 0060: 00 00 32 af 76 86 d4 03 cf 45 b5 d9 5f 2d 70 ce |..2.v....E.._-p.|
900 900 0070: be a5 87 ac 80 6a 00 00 00 00 00 00 00 29 00 00 |.....j.......)..|
901 901 0080: 00 29 36 65 31 66 34 63 34 37 65 63 62 35 33 33 |.)6e1f4c47ecb533|
902 902 0090: 66 66 64 30 63 38 65 35 32 63 64 63 38 38 61 66 |ffd0c8e52cdc88af|
903 903 00a0: 62 36 63 64 33 39 65 32 30 63 0a 00 00 00 66 00 |b6cd39e20c....f.|
904 904 00b0: 00 00 68 00 00 00 02 44 0a 00 00 00 69 00 00 00 |..h....D....i...|
905 905 00c0: 6a 00 00 00 01 44 00 00 00 a4 95 20 ee a7 81 bc |j....D..... ....|
906 906 00d0: ca 16 c1 e1 5a cc 0b a1 43 35 a0 e8 e5 ba cd 01 |....Z...C5......|
907 907 00e0: 0b 8c d9 98 f3 98 1a 5a 81 15 f9 4f 8d a4 ab 50 |.......Z...O...P|
908 908 00f0: 60 89 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |`...............|
909 909 0100: 00 00 00 00 00 00 95 20 ee a7 81 bc ca 16 c1 e1 |....... ........|
910 910 0110: 5a cc 0b a1 43 35 a0 e8 e5 ba 00 00 00 00 00 00 |Z...C5..........|
911 911 0120: 00 29 00 00 00 29 34 64 65 63 65 39 63 38 32 36 |.)...)4dece9c826|
912 912 0130: 66 36 39 34 39 30 35 30 37 62 39 38 63 36 33 38 |f69490507b98c638|
913 913 0140: 33 61 33 30 30 39 62 32 39 35 38 33 37 64 0a 00 |3a3009b295837d..|
914 914 0150: 00 00 66 00 00 00 68 00 00 00 02 45 0a 00 00 00 |..f...h....E....|
915 915 0160: 69 00 00 00 6a 00 00 00 01 45 00 00 00 a2 ee a1 |i...j....E......|
916 916 0170: 37 46 79 9a 9e 0b fd 88 f2 9d 3c 2e 9d c9 38 9f |7Fy.......<...8.|
917 917 0180: 52 4f 24 b6 38 7c 8c 8c ae 37 17 88 80 f3 fa 95 |RO$.8|...7......|
918 918 0190: de d3 cb 1c f7 85 95 20 ee a7 81 bc ca 16 c1 e1 |....... ........|
919 919 01a0: 5a cc 0b a1 43 35 a0 e8 e5 ba ee a1 37 46 79 9a |Z...C5......7Fy.|
920 920 01b0: 9e 0b fd 88 f2 9d 3c 2e 9d c9 38 9f 52 4f 00 00 |......<...8.RO..|
921 921 01c0: 00 00 00 00 00 29 00 00 00 29 33 36 35 62 39 33 |.....)...)365b93|
922 922 01d0: 64 35 37 66 64 66 34 38 31 34 65 32 62 35 39 31 |d57fdf4814e2b591|
923 923 01e0: 31 64 36 62 61 63 66 66 32 62 31 32 30 31 34 34 |1d6bacff2b120144|
924 924 01f0: 34 31 0a 00 00 00 66 00 00 00 68 00 00 00 00 00 |41....f...h.....|
925 925 0200: 00 00 69 00 00 00 6a 00 00 00 01 47 00 00 00 a4 |..i...j....G....|
926 926 0210: 02 de 42 19 6e be e4 2e f2 84 b6 78 0a 87 cd c9 |..B.n......x....|
927 927 0220: 6e 8e aa b6 24 b6 38 7c 8c 8c ae 37 17 88 80 f3 |n...$.8|...7....|
928 928 0230: fa 95 de d3 cb 1c f7 85 00 00 00 00 00 00 00 00 |................|
929 929 0240: 00 00 00 00 00 00 00 00 00 00 00 00 02 de 42 19 |..............B.|
930 930 0250: 6e be e4 2e f2 84 b6 78 0a 87 cd c9 6e 8e aa b6 |n......x....n...|
931 931 0260: 00 00 00 00 00 00 00 29 00 00 00 29 38 62 65 65 |.......)...)8bee|
932 932 0270: 34 38 65 64 63 37 33 31 38 35 34 31 66 63 30 30 |48edc7318541fc00|
933 933 0280: 31 33 65 65 34 31 62 30 38 39 32 37 36 61 38 63 |13ee41b089276a8c|
934 934 0290: 32 34 62 66 0a 00 00 00 66 00 00 00 66 00 00 00 |24bf....f...f...|
935 935 02a0: 02 48 0a 00 00 00 67 00 00 00 68 00 00 00 01 48 |.H....g...h....H|
936 936 02b0: 00 00 00 00 00 00 00 8b 6e 1f 4c 47 ec b5 33 ff |........n.LG..3.|
937 937 02c0: d0 c8 e5 2c dc 88 af b6 cd 39 e2 0c 66 a5 a0 18 |...,.....9..f...|
938 938 02d0: 17 fd f5 23 9c 27 38 02 b5 b7 61 8d 05 1c 89 e4 |...#.'8...a.....|
939 939 02e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
940 940 02f0: 00 00 00 00 32 af 76 86 d4 03 cf 45 b5 d9 5f 2d |....2.v....E.._-|
941 941 0300: 70 ce be a5 87 ac 80 6a 00 00 00 81 00 00 00 81 |p......j........|
942 942 0310: 00 00 00 2b 44 00 63 33 66 31 63 61 32 39 32 34 |...+D.c3f1ca2924|
943 943 0320: 63 31 36 61 31 39 62 30 36 35 36 61 38 34 39 30 |c16a19b0656a8490|
944 944 0330: 30 65 35 30 34 65 35 62 30 61 65 63 32 64 0a 00 |0e504e5b0aec2d..|
945 945 0340: 00 00 8b 4d ec e9 c8 26 f6 94 90 50 7b 98 c6 38 |...M...&...P{..8|
946 946 0350: 3a 30 09 b2 95 83 7d 00 7d 8c 9d 88 84 13 25 f5 |:0....}.}.....%.|
947 947 0360: c6 b0 63 71 b3 5b 4e 8a 2b 1a 83 00 00 00 00 00 |..cq.[N.+.......|
948 948 0370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 95 |................|
949 949 0380: 20 ee a7 81 bc ca 16 c1 e1 5a cc 0b a1 43 35 a0 | ........Z...C5.|
950 950 0390: e8 e5 ba 00 00 00 2b 00 00 00 ac 00 00 00 2b 45 |......+.......+E|
951 951 03a0: 00 39 63 36 66 64 30 33 35 30 61 36 63 30 64 30 |.9c6fd0350a6c0d0|
952 952 03b0: 63 34 39 64 34 61 39 63 35 30 31 37 63 66 30 37 |c49d4a9c5017cf07|
953 953 03c0: 30 34 33 66 35 34 65 35 38 0a 00 00 00 8b 36 5b |043f54e58.....6[|
954 954 03d0: 93 d5 7f df 48 14 e2 b5 91 1d 6b ac ff 2b 12 01 |....H.....k..+..|
955 955 03e0: 44 41 28 a5 84 c6 5e f1 21 f8 9e b6 6a b7 d0 bc |DA(...^.!...j...|
956 956 03f0: 15 3d 80 99 e7 ce 4d ec e9 c8 26 f6 94 90 50 7b |.=....M...&...P{|
957 957 0400: 98 c6 38 3a 30 09 b2 95 83 7d ee a1 37 46 79 9a |..8:0....}..7Fy.|
958 958 0410: 9e 0b fd 88 f2 9d 3c 2e 9d c9 38 9f 52 4f 00 00 |......<...8.RO..|
959 959 0420: 00 56 00 00 00 56 00 00 00 2b 46 00 32 32 62 66 |.V...V...+F.22bf|
960 960 0430: 63 66 64 36 32 61 32 31 61 33 32 38 37 65 64 62 |cfd62a21a3287edb|
961 961 0440: 64 34 64 36 35 36 32 31 38 64 30 66 35 32 35 65 |d4d656218d0f525e|
962 962 0450: 64 37 36 61 0a 00 00 00 97 8b ee 48 ed c7 31 85 |d76a.......H..1.|
963 963 0460: 41 fc 00 13 ee 41 b0 89 27 6a 8c 24 bf 28 a5 84 |A....A..'j.$.(..|
964 964 0470: c6 5e f1 21 f8 9e b6 6a b7 d0 bc 15 3d 80 99 e7 |.^.!...j....=...|
965 965 0480: ce 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
966 966 0490: 00 00 00 00 00 02 de 42 19 6e be e4 2e f2 84 b6 |.......B.n......|
967 967 04a0: 78 0a 87 cd c9 6e 8e aa b6 00 00 00 2b 00 00 00 |x....n......+...|
968 968 04b0: 56 00 00 00 00 00 00 00 81 00 00 00 81 00 00 00 |V...............|
969 969 04c0: 2b 48 00 38 35 30 30 31 38 39 65 37 34 61 39 65 |+H.8500189e74a9e|
970 970 04d0: 30 34 37 35 65 38 32 32 30 39 33 62 63 37 64 62 |0475e822093bc7db|
971 971 04e0: 30 64 36 33 31 61 65 62 30 62 34 0a 00 00 00 00 |0d631aeb0b4.....|
972 972 04f0: 00 00 00 05 44 00 00 00 62 c3 f1 ca 29 24 c1 6a |....D...b...)$.j|
973 973 0500: 19 b0 65 6a 84 90 0e 50 4e 5b 0a ec 2d 00 00 00 |..ej...PN[..-...|
974 974 0510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
975 975 0520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
976 976 0530: 00 00 00 00 00 32 af 76 86 d4 03 cf 45 b5 d9 5f |.....2.v....E.._|
977 977 0540: 2d 70 ce be a5 87 ac 80 6a 00 00 00 00 00 00 00 |-p......j.......|
978 978 0550: 00 00 00 00 02 44 0a 00 00 00 00 00 00 00 05 45 |.....D.........E|
979 979 0560: 00 00 00 62 9c 6f d0 35 0a 6c 0d 0c 49 d4 a9 c5 |...b.o.5.l..I...|
980 980 0570: 01 7c f0 70 43 f5 4e 58 00 00 00 00 00 00 00 00 |.|.pC.NX........|
981 981 0580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
982 982 0590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
983 983 05a0: 95 20 ee a7 81 bc ca 16 c1 e1 5a cc 0b a1 43 35 |. ........Z...C5|
984 984 05b0: a0 e8 e5 ba 00 00 00 00 00 00 00 00 00 00 00 02 |................|
985 985 05c0: 45 0a 00 00 00 00 00 00 00 05 48 00 00 00 62 85 |E.........H...b.|
986 986 05d0: 00 18 9e 74 a9 e0 47 5e 82 20 93 bc 7d b0 d6 31 |...t..G^. ..}..1|
987 987 05e0: ae b0 b4 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
988 988 05f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
989 989 0600: 00 00 00 00 00 00 00 00 00 00 00 02 de 42 19 6e |.............B.n|
990 990 0610: be e4 2e f2 84 b6 78 0a 87 cd c9 6e 8e aa b6 00 |......x....n....|
991 991 0620: 00 00 00 00 00 00 00 00 00 00 02 48 0a 00 00 00 |...........H....|
992 992 0630: 00 00 00 00 00 00 00 00 00 00 00 00 00 |.............|
993 993
994 994 $ hg debugbundle ../rev.hg2
995 995 Stream params: {}
996 996 changegroup -- {} (mandatory: False)
997 997 32af7686d403cf45b5d95f2d70cebea587ac806a
998 998 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
999 999 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
1000 1000 02de42196ebee42ef284b6780a87cdc96e8eaab6
1001 1001 $ hg unbundle ../rev.hg2
1002 1002 adding changesets
1003 1003 adding manifests
1004 1004 adding file changes
1005 1005 added 0 changesets with 0 changes to 3 files
1006 1006 (run 'hg update' to get a working copy)
1007 1007
1008 1008 with reply
1009 1009
1010 1010 $ hg bundle2 --rev '8+7+5+4' --reply ../rev-rr.hg2
1011 1011 $ hg unbundle2 ../rev-reply.hg2 < ../rev-rr.hg2
1012 1012 0 unread bytes
1013 1013 addchangegroup return: 1
1014 1014
1015 1015 $ f --hexdump ../rev-reply.hg2
1016 1016 ../rev-reply.hg2:
1017 1017 0000: 48 47 32 30 00 00 00 00 00 00 00 2f 11 72 65 70 |HG20......./.rep|
1018 1018 0010: 6c 79 3a 63 68 61 6e 67 65 67 72 6f 75 70 00 00 |ly:changegroup..|
1019 1019 0020: 00 00 00 02 0b 01 06 01 69 6e 2d 72 65 70 6c 79 |........in-reply|
1020 1020 0030: 2d 74 6f 31 72 65 74 75 72 6e 31 00 00 00 00 00 |-to1return1.....|
1021 1021 0040: 00 00 1b 06 6f 75 74 70 75 74 00 00 00 01 00 01 |....output......|
1022 1022 0050: 0b 01 69 6e 2d 72 65 70 6c 79 2d 74 6f 31 00 00 |..in-reply-to1..|
1023 1023 0060: 00 64 61 64 64 69 6e 67 20 63 68 61 6e 67 65 73 |.dadding changes|
1024 1024 0070: 65 74 73 0a 61 64 64 69 6e 67 20 6d 61 6e 69 66 |ets.adding manif|
1025 1025 0080: 65 73 74 73 0a 61 64 64 69 6e 67 20 66 69 6c 65 |ests.adding file|
1026 1026 0090: 20 63 68 61 6e 67 65 73 0a 61 64 64 65 64 20 30 | changes.added 0|
1027 1027 00a0: 20 63 68 61 6e 67 65 73 65 74 73 20 77 69 74 68 | changesets with|
1028 1028 00b0: 20 30 20 63 68 61 6e 67 65 73 20 74 6f 20 33 20 | 0 changes to 3 |
1029 1029 00c0: 66 69 6c 65 73 0a 00 00 00 00 00 00 00 00 |files.........|
1030 1030
1031 1031 Check handling of exception during generation.
1032 1032 ----------------------------------------------
1033 1033
1034 1034 $ hg bundle2 --genraise > ../genfailed.hg2
1035 1035 abort: Someone set up us the bomb!
1036 1036 [255]
1037 1037
1038 1038 Should still be a valid bundle
1039 1039
1040 1040 $ f --hexdump ../genfailed.hg2
1041 1041 ../genfailed.hg2:
1042 1042 0000: 48 47 32 30 00 00 00 00 00 00 00 0d 06 6f 75 74 |HG20.........out|
1043 1043 0010: 70 75 74 00 00 00 00 00 00 ff ff ff ff 00 00 00 |put.............|
1044 1044 0020: 48 0b 65 72 72 6f 72 3a 61 62 6f 72 74 00 00 00 |H.error:abort...|
1045 1045 0030: 00 01 00 07 2d 6d 65 73 73 61 67 65 75 6e 65 78 |....-messageunex|
1046 1046 0040: 70 65 63 74 65 64 20 65 72 72 6f 72 3a 20 53 6f |pected error: So|
1047 1047 0050: 6d 65 6f 6e 65 20 73 65 74 20 75 70 20 75 73 20 |meone set up us |
1048 1048 0060: 74 68 65 20 62 6f 6d 62 21 00 00 00 00 00 00 00 |the bomb!.......|
1049 1049 0070: 00 |.|
1050 1050
1051 1051 And its handling on the other size raise a clean exception
1052 1052
1053 1053 $ cat ../genfailed.hg2 | hg unbundle2
1054 1054 0 unread bytes
1055 1055 abort: unexpected error: Someone set up us the bomb!
1056 1056 [255]
1057 1057
1058 1058 Test compression
1059 1059 ================
1060 1060
1061 1061 Simple case where it just work: GZ
1062 1062 ----------------------------------
1063 1063
1064 1064 $ hg bundle2 --compress GZ --rev '8+7+5+4' ../rev.hg2.bz
1065 1065 $ f --hexdump ../rev.hg2.bz
1066 1066 ../rev.hg2.bz:
1067 1067 0000: 48 47 32 30 00 00 00 0e 43 6f 6d 70 72 65 73 73 |HG20....Compress|
1068 1068 0010: 69 6f 6e 3d 47 5a 78 9c 95 94 7d 68 95 55 1c c7 |ion=GZx...}h.U..|
1069 1069 0020: 9f 3b 31 e8 ce fa c3 65 be a0 a4 b4 52 b9 29 e7 |.;1....e....R.).|
1070 1070 0030: f5 79 ce 89 fa 63 ed 5e 77 8b 9c c3 3f 2a 1c 68 |.y...c.^w...?*.h|
1071 1071 0040: cf 79 9b dd 6a ae b0 28 74 b8 e5 96 5b bb 86 61 |.y..j..(t...[..a|
1072 1072 0050: a3 15 6e 3a 71 c8 6a e8 a5 da 95 64 28 22 ce 69 |..n:q.j....d(".i|
1073 1073 0060: cd 06 59 34 28 2b 51 2a 58 c3 17 56 2a 9a 9d 67 |..Y4(+Q*X..V*..g|
1074 1074 0070: dc c6 35 9e c4 1d f8 9e 87 f3 9c f3 3b bf 0f bf |..5.........;...|
1075 1075 0080: 97 e3 38 ce f4 42 b9 d6 af ae d2 55 af ae 7b ad |..8..B.....U..{.|
1076 1076 0090: c6 c9 8d bb 8a ec b4 07 ed 7f fd ed d3 53 be 4e |.............S.N|
1077 1077 00a0: f4 0e af 59 52 73 ea 50 d7 96 9e ba d4 9a 1f 87 |...YRs.P........|
1078 1078 00b0: 9b 9f 1d e8 7a 6a 79 e9 cb 7f cf eb fe 7e d3 82 |....zjy......~..|
1079 1079 00c0: ce 2f 36 38 21 23 cc 36 b7 b5 38 90 ab a1 21 92 |./68!#.6..8...!.|
1080 1080 00d0: 78 5a 0a 8a b1 31 0a 48 a6 29 92 4a 32 e6 1b e1 |xZ...1.H.).J2...|
1081 1081 00e0: 4a 85 b9 46 40 46 ed 61 63 b5 d6 aa 20 1e ac 5e |J..F@F.ac... ..^|
1082 1082 00f0: b0 0a ae 8a c4 03 c6 d6 f9 a3 7b eb fb 4e de 7f |..........{..N..|
1083 1083 0100: e4 97 55 5f 15 76 96 d2 5d bf 9d 3f 38 18 29 4c |..U_.v..]..?8.)L|
1084 1084 0110: 0f b7 5d 6e 9b b3 aa 7e c6 d5 15 5b f7 7c 52 f1 |..]n...~...[.|R.|
1085 1085 0120: 7c 73 18 63 98 6d 3e 23 51 5a 6a 2e 19 72 8d cb ||s.c.m>#QZj..r..|
1086 1086 0130: 09 07 14 78 82 33 e9 62 86 7d 0c 00 17 88 53 86 |...x.3.b.}....S.|
1087 1087 0140: 3d 75 0b 63 e2 16 c6 84 9d 76 8f 76 7a cb de fc |=u.c.....v.vz...|
1088 1088 0150: a8 a3 f0 46 d3 a5 f6 c7 96 b6 9f 60 3b 57 ae 28 |...F.......`;W.(|
1089 1089 0160: ce b2 8d e9 f4 3e 6f 66 53 dd e5 6b ad 67 be f9 |.....>ofS..k.g..|
1090 1090 0170: 72 ee 5f 8d 61 3c 61 b6 f9 8c d8 a5 82 63 45 3d |r._.a<a......cE=|
1091 1091 0180: a3 0c 61 90 68 24 28 87 50 b9 c2 97 c6 20 01 11 |..a.h$(.P.... ..|
1092 1092 0190: 80 84 10 98 cf e8 e4 13 96 05 51 2c 38 f3 c4 ec |..........Q,8...|
1093 1093 01a0: ea 43 e7 96 5e 6a c8 be 11 dd 32 78 a2 fa dd 8f |.C..^j....2x....|
1094 1094 01b0: b3 61 84 61 51 0c b3 cd 27 64 42 6b c2 b4 92 1e |.a.aQ...'dBk....|
1095 1095 01c0: 86 8c 12 68 24 00 10 db 7f 50 00 c6 91 e7 fa 4c |...h$....P.....L|
1096 1096 01d0: 22 22 cc bf 84 81 0a 92 c1 aa 2a c7 1b 49 e6 ee |""........*..I..|
1097 1097 01e0: 6b a9 7e e0 e9 b2 91 5e 7c 73 68 e0 fc 23 3f 34 |k.~....^|sh..#?4|
1098 1098 01f0: ed cf 0e f2 b3 d3 4c d7 ae 59 33 6f 8c 3d b8 63 |......L..Y3o.=.c|
1099 1099 0200: 21 2b e8 3d e0 6f 9d 3a b7 f9 dc 24 2a b2 3e a7 |!+.=.o.:...$*.>.|
1100 1100 0210: 58 dc 91 d8 40 e9 23 8e 88 84 ae 0f b9 00 2e b5 |X...@.#.........|
1101 1101 0220: 74 36 f3 40 53 40 34 15 c0 d7 12 8d e7 bb 65 f9 |t6.@S@4.......e.|
1102 1102 0230: c8 ef 03 0f ff f9 fe b6 8a 0d 6d fd ec 51 70 f7 |..........m..Qp.|
1103 1103 0240: a7 ad 9b 6b 9d da 74 7b 53 43 d1 43 63 fd 19 f9 |...k..t{SC.Cc...|
1104 1104 0250: ca 67 95 e5 ef c4 e6 6c 9e 44 e1 c5 ac 7a 82 6f |.g.....l.D...z.o|
1105 1105 0260: c2 e1 d2 b5 2d 81 29 f0 5d 09 6c 6f 10 ae 88 cf |....-.).].lo....|
1106 1106 0270: 25 05 d0 93 06 78 80 60 43 2d 10 1b 47 71 2b b7 |%....x.`C-..Gq+.|
1107 1107 0280: 7f bb e9 a7 e4 7d 67 7b df 9b f7 62 cf cd d8 f4 |.....}g{...b....|
1108 1108 0290: 48 bc 64 51 57 43 ff ea 8b 0b ae 74 64 53 07 86 |H.dQWC.....tdS..|
1109 1109 02a0: fa 66 3c 5e f7 e1 af a7 c2 90 ff a7 be 9e c9 29 |.f<^...........)|
1110 1110 02b0: b6 cc 41 48 18 69 94 8b 7c 04 7d 8c 98 a7 95 50 |..AH.i..|.}....P|
1111 1111 02c0: 44 d9 d0 20 c8 14 30 14 51 ad 6c 16 03 94 0f 5a |D.. ..0.Q.l....Z|
1112 1112 02d0: 46 93 7f 1c 87 8d 25 d7 9d a2 d1 92 4c f3 c2 54 |F.....%.....L..T|
1113 1113 02e0: ba f8 70 18 ca 24 0a 29 96 43 71 f2 93 95 74 18 |..p..$.).Cq...t.|
1114 1114 02f0: b5 65 c4 b8 f6 6c 5c 34 20 1e d5 0c 21 c0 b1 90 |.e...l\4 ...!...|
1115 1115 0300: 9e 12 40 b9 18 fa 5a 00 41 a2 39 d3 a9 c1 73 21 |..@...Z.A.9...s!|
1116 1116 0310: 8e 5e 3c b9 b8 f8 48 6a 76 46 a7 1a b6 dd 5b 51 |.^<...HjvF....[Q|
1117 1117 0320: 5e 19 1d 59 12 c6 32 89 02 9a c0 8f 4f b8 0a ba |^..Y..2.....O...|
1118 1118 0330: 5e ec 58 37 44 a3 2f dd 33 ed c9 d3 dd c7 22 1b |^.X7D./.3.....".|
1119 1119 0340: 2f d4 94 8e 95 3f 77 a7 ae 6e f3 32 8d bb 4a 4c |/....?w..n.2..JL|
1120 1120 0350: b8 0a 5a 43 34 3a b3 3a d6 77 ff 5c b6 fa ad f9 |..ZC4:.:.w.\....|
1121 1121 0360: db fb 6a 33 df c1 7d 99 cf ef d4 d5 6d da 77 7c |..j3..}.....m.w||
1122 1122 0370: 3b 19 fd af c5 3f f1 60 c3 17 |;....?.`..|
1123 1123 $ hg debugbundle ../rev.hg2.bz
1124 1124 Stream params: {Compression: GZ}
1125 1125 changegroup -- {} (mandatory: False)
1126 1126 32af7686d403cf45b5d95f2d70cebea587ac806a
1127 1127 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
1128 1128 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
1129 1129 02de42196ebee42ef284b6780a87cdc96e8eaab6
1130 1130 $ hg unbundle ../rev.hg2.bz
1131 1131 adding changesets
1132 1132 adding manifests
1133 1133 adding file changes
1134 1134 added 0 changesets with 0 changes to 3 files
1135 1135 (run 'hg update' to get a working copy)
1136 1136 Simple case where it just work: BZ
1137 1137 ----------------------------------
1138 1138
1139 1139 $ hg bundle2 --compress BZ --rev '8+7+5+4' ../rev.hg2.bz
1140 1140 $ f --hexdump ../rev.hg2.bz
1141 1141 ../rev.hg2.bz:
1142 1142 0000: 48 47 32 30 00 00 00 0e 43 6f 6d 70 72 65 73 73 |HG20....Compress|
1143 1143 0010: 69 6f 6e 3d 42 5a 42 5a 68 39 31 41 59 26 53 59 |ion=BZBZh91AY&SY|
1144 1144 0020: a3 4b 18 3d 00 00 1a 7f ff ff bf 5f f6 ef ef 7f |.K.=......._....|
1145 1145 0030: f6 3f f7 d1 d9 ff ff f7 6e ff ff 6e f7 f6 bd df |.?......n..n....|
1146 1146 0040: b5 ab ff cf 67 f6 e7 7b f7 c0 02 d7 33 82 8b 51 |....g..{....3..Q|
1147 1147 0050: 04 a5 53 d5 3d 27 a0 99 18 4d 0d 34 00 d1 a1 e8 |..S.='...M.4....|
1148 1148 0060: 80 c8 7a 87 a9 a3 43 6a 3d 46 86 26 80 34 3d 40 |..z...Cj=F.&.4=@|
1149 1149 0070: c8 c9 b5 34 f4 8f 48 0f 51 ea 34 34 fd 4d aa 19 |...4..H.Q.44.M..|
1150 1150 0080: 03 40 0c 08 da 86 43 d4 f5 0f 42 1e a0 f3 54 33 |.@....C...B...T3|
1151 1151 0090: 54 d3 13 4d 03 40 32 00 00 32 03 26 80 0d 00 0d |T..M.@2..2.&....|
1152 1152 00a0: 00 68 c8 c8 03 20 32 30 98 8c 80 00 00 03 4d 00 |.h... 20......M.|
1153 1153 00b0: c8 00 00 0d 00 00 22 99 a1 34 c2 64 a6 d5 34 1a |......"..4.d..4.|
1154 1154 00c0: 00 00 06 86 83 4d 07 a8 d1 a0 68 01 a0 00 00 00 |.....M....h.....|
1155 1155 00d0: 00 0d 06 80 00 00 00 0d 00 03 40 00 00 04 a4 a1 |..........@.....|
1156 1156 00e0: 4d a9 89 89 b4 9a 32 0c 43 46 86 87 a9 8d 41 9a |M.....2.CF....A.|
1157 1157 00f0: 98 46 9a 0d 31 32 1a 34 0d 0c 8d a2 0c 98 4d 06 |.F..12.4......M.|
1158 1158 0100: 8c 40 c2 60 8d 0d 0c 20 c9 89 fa a0 d0 d3 21 a1 |.@.`... ......!.|
1159 1159 0110: ea 34 d3 68 9e a6 d1 74 05 33 cb 66 96 93 28 64 |.4.h...t.3.f..(d|
1160 1160 0120: 40 91 22 ac 55 9b ea 40 7b 38 94 e2 f8 06 00 cb |@.".U..@{8......|
1161 1161 0130: 28 02 00 4d ab 40 24 10 43 18 cf 64 b4 06 83 0c |(..M.@$.C..d....|
1162 1162 0140: 34 6c b4 a3 d4 0a 0a e4 a8 5c 4e 23 c0 c9 7a 31 |4l.......\N#..z1|
1163 1163 0150: 97 87 77 7a 64 88 80 8e 60 97 20 93 0f 8e eb c4 |..wzd...`. .....|
1164 1164 0160: 62 a4 44 a3 52 20 b2 99 a9 2e e1 d7 29 4a 54 ac |b.D.R ......)JT.|
1165 1165 0170: 44 7a bb cc 04 3d e0 aa bd 6a 33 5e 9b a2 57 36 |Dz...=...j3^..W6|
1166 1166 0180: fa cb 45 bb 6d 3e c1 d9 d9 f5 83 69 8a d0 e0 e2 |..E.m>.....i....|
1167 1167 0190: e7 ae 90 55 24 da 3f ab 78 c0 4c b4 56 a3 9e a4 |...U$.?.x.L.V...|
1168 1168 01a0: af 9c 65 74 86 ec 6d dc 62 dc 33 ca c8 50 dd 9d |..et..m.b.3..P..|
1169 1169 01b0: 98 8e 9e 59 20 f3 f0 42 91 4a 09 f5 75 8d 3d a5 |...Y ..B.J..u.=.|
1170 1170 01c0: a5 15 cb 8d 10 63 b0 c2 2e b2 81 f7 c1 76 0e 53 |.....c.......v.S|
1171 1171 01d0: 6c 0e 46 73 b5 ae 67 f9 4c 0b 45 6b a8 32 2a 2f |l.Fs..g.L.Ek.2*/|
1172 1172 01e0: a2 54 a4 44 05 20 a1 38 d1 a4 c6 09 a8 2b 08 99 |.T.D. .8.....+..|
1173 1173 01f0: a4 14 ae 8d a3 e3 aa 34 27 d8 44 ca c3 5d 21 8b |.......4'.D..]!.|
1174 1174 0200: 1a 1e 97 29 71 2b 09 4a 4a 55 55 94 58 65 b2 bc |...)q+.JJUU.Xe..|
1175 1175 0210: f3 a5 90 26 36 76 67 7a 51 98 d6 8a 4a 99 50 b5 |...&6vgzQ...J.P.|
1176 1176 0220: 99 8f 94 21 17 a9 8b f3 ad 4c 33 d4 2e 40 c8 0c |...!.....L3..@..|
1177 1177 0230: 3b 90 53 39 db 48 02 34 83 48 d6 b3 99 13 d2 58 |;.S9.H.4.H.....X|
1178 1178 0240: 65 8e 71 ac a9 06 95 f2 c4 8e b4 08 6b d3 0c ae |e.q.........k...|
1179 1179 0250: d9 90 56 71 43 a7 a2 62 16 3e 50 63 d3 57 3c 2d |..VqC..b.>Pc.W<-|
1180 1180 0260: 9f 0f 34 05 08 d8 a6 4b 59 31 54 66 3a 45 0c 8a |..4....KY1Tf:E..|
1181 1181 0270: c7 90 3a f0 6a 83 1b f5 ca fb 80 2b 50 06 fb 51 |..:.j......+P..Q|
1182 1182 0280: 7e a6 a4 d4 81 44 82 21 54 00 5b 1a 30 83 62 a3 |~....D.!T.[.0.b.|
1183 1183 0290: 18 b6 24 19 1e 45 df 4d 5c db a6 af 5b ac 90 fa |..$..E.M\...[...|
1184 1184 02a0: 3e ed f9 ec 4c ba 36 ee d8 60 20 a7 c7 3b cb d1 |>...L.6..` ..;..|
1185 1185 02b0: 90 43 7d 27 16 50 5d ad f4 14 07 0b 90 5c cc 6b |.C}'.P]......\.k|
1186 1186 02c0: 8d 3f a6 88 f4 34 37 a8 cf 14 63 36 19 f7 3e 28 |.?...47...c6..>(|
1187 1187 02d0: de 99 e8 16 a4 9d 0d 40 a1 a7 24 52 14 a6 72 62 |.......@..$R..rb|
1188 1188 02e0: 59 5a ca 2d e5 51 90 78 88 d9 c6 c7 21 d0 f7 46 |YZ.-.Q.x....!..F|
1189 1189 02f0: b2 04 46 44 4e 20 9c 12 b1 03 4e 25 e0 a9 0c 58 |..FDN ....N%...X|
1190 1190 0300: 5b 1d 3c 93 20 01 51 de a9 1c 69 23 32 46 14 b4 |[.<. .Q...i#2F..|
1191 1191 0310: 90 db 17 98 98 50 03 90 29 aa 40 b0 13 d8 43 d2 |.....P..).@...C.|
1192 1192 0320: 5f c5 9d eb f3 f2 ad 41 e8 7a a9 ed a1 58 84 a6 |_......A.z...X..|
1193 1193 0330: 42 bf d6 fc 24 82 c1 20 32 26 4a 15 a6 1d 29 7f |B...$.. 2&J...).|
1194 1194 0340: 7e f4 3d 07 bc 62 9a 5b ec 44 3d 72 1d 41 8b 5c |~.=..b.[.D=r.A.\|
1195 1195 0350: 80 de 0e 62 9a 2e f8 83 00 d5 07 a0 9c c6 74 98 |...b..........t.|
1196 1196 0360: 11 b2 5e a9 38 02 03 ee fd 86 5c f4 86 b3 ae da |..^.8.....\.....|
1197 1197 0370: 05 94 01 c5 c6 ea 18 e6 ba 2a ba b3 04 5c 96 89 |.........*...\..|
1198 1198 0380: 72 63 5b 10 11 f6 67 34 98 cb e4 c0 4e fa e6 99 |rc[...g4....N...|
1199 1199 0390: 19 6e 50 e8 26 8d 0c 17 e0 be ef e1 8e 02 6f 32 |.nP.&.........o2|
1200 1200 03a0: 82 dc 26 f8 a1 08 f3 8a 0d f3 c4 75 00 48 73 b8 |..&........u.Hs.|
1201 1201 03b0: be 3b 0d 7f d0 fd c7 78 96 ec e0 03 80 68 4d 8d |.;.....x.....hM.|
1202 1202 03c0: 43 8c d7 68 58 f9 50 f0 18 cb 21 58 1b 60 cd 1f |C..hX.P...!X.`..|
1203 1203 03d0: 84 36 2e 16 1f 0a f7 4e 8f eb df 01 2d c2 79 0b |.6.....N....-.y.|
1204 1204 03e0: f7 24 ea 0d e8 59 86 51 6e 1c 30 a3 ad 2f ee 8c |.$...Y.Qn.0../..|
1205 1205 03f0: 90 c8 84 d5 e8 34 c1 95 b2 c9 f6 4d 87 1c 7d 19 |.....4.....M..}.|
1206 1206 0400: d6 41 58 56 7a e0 6c ba 10 c7 e8 33 39 36 96 e7 |.AXVz.l....396..|
1207 1207 0410: d2 f9 59 9a 08 95 48 38 e7 0b b7 0a 24 67 c4 39 |..Y...H8....$g.9|
1208 1208 0420: 8b 43 88 57 9c 01 f5 61 b5 e1 27 41 7e af 83 fe |.C.W...a..'A~...|
1209 1209 0430: 2e e4 8a 70 a1 21 46 96 30 7a |...p.!F.0z|
1210 1210 $ hg debugbundle ../rev.hg2.bz
1211 1211 Stream params: {Compression: BZ}
1212 1212 changegroup -- {} (mandatory: False)
1213 1213 32af7686d403cf45b5d95f2d70cebea587ac806a
1214 1214 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
1215 1215 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
1216 1216 02de42196ebee42ef284b6780a87cdc96e8eaab6
1217 1217 $ hg unbundle ../rev.hg2.bz
1218 1218 adding changesets
1219 1219 adding manifests
1220 1220 adding file changes
1221 1221 added 0 changesets with 0 changes to 3 files
1222 1222 (run 'hg update' to get a working copy)
1223 1223
1224 1224 unknown compression while unbundling
1225 1225 -----------------------------
1226 1226
1227 1227 $ hg bundle2 --param Compression=FooBarUnknown --rev '8+7+5+4' ../rev.hg2.bz
1228 1228 $ cat ../rev.hg2.bz | hg statbundle2
1229 1229 abort: unknown parameters: Stream Parameter - Compression='FooBarUnknown'
1230 1230 [255]
1231 1231 $ hg unbundle ../rev.hg2.bz
1232 1232 abort: ../rev.hg2.bz: unknown bundle feature, Stream Parameter - Compression='FooBarUnknown'
1233 1233 (see https://mercurial-scm.org/wiki/BundleFeature for more information)
1234 1234 [255]
1235 1235
1236 1236 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now