##// END OF EJS Templates
changegroup: remove reordering control (BC)...
Gregory Szorc -
r39897:db5501d9 default
parent child Browse files
Show More
@@ -1,1411 +1,1389 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 stringutil,
40 39 )
41 40
42 41 _CHANGEGROUPV1_DELTA_HEADER = struct.Struct("20s20s20s20s")
43 42 _CHANGEGROUPV2_DELTA_HEADER = struct.Struct("20s20s20s20s20s")
44 43 _CHANGEGROUPV3_DELTA_HEADER = struct.Struct(">20s20s20s20s20sH")
45 44
46 45 LFS_REQUIREMENT = 'lfs'
47 46
48 47 readexactly = util.readexactly
49 48
50 49 def getchunk(stream):
51 50 """return the next chunk from stream as a string"""
52 51 d = readexactly(stream, 4)
53 52 l = struct.unpack(">l", d)[0]
54 53 if l <= 4:
55 54 if l:
56 55 raise error.Abort(_("invalid chunk length %d") % l)
57 56 return ""
58 57 return readexactly(stream, l - 4)
59 58
60 59 def chunkheader(length):
61 60 """return a changegroup chunk header (string)"""
62 61 return struct.pack(">l", length + 4)
63 62
64 63 def closechunk():
65 64 """return a changegroup chunk header (string) for a zero-length chunk"""
66 65 return struct.pack(">l", 0)
67 66
68 67 def _fileheader(path):
69 68 """Obtain a changegroup chunk header for a named path."""
70 69 return chunkheader(len(path)) + path
71 70
72 71 def writechunks(ui, chunks, filename, vfs=None):
73 72 """Write chunks to a file and return its filename.
74 73
75 74 The stream is assumed to be a bundle file.
76 75 Existing files will not be overwritten.
77 76 If no filename is specified, a temporary file is created.
78 77 """
79 78 fh = None
80 79 cleanup = None
81 80 try:
82 81 if filename:
83 82 if vfs:
84 83 fh = vfs.open(filename, "wb")
85 84 else:
86 85 # Increase default buffer size because default is usually
87 86 # small (4k is common on Linux).
88 87 fh = open(filename, "wb", 131072)
89 88 else:
90 89 fd, filename = pycompat.mkstemp(prefix="hg-bundle-", suffix=".hg")
91 90 fh = os.fdopen(fd, r"wb")
92 91 cleanup = filename
93 92 for c in chunks:
94 93 fh.write(c)
95 94 cleanup = None
96 95 return filename
97 96 finally:
98 97 if fh is not None:
99 98 fh.close()
100 99 if cleanup is not None:
101 100 if filename and vfs:
102 101 vfs.unlink(cleanup)
103 102 else:
104 103 os.unlink(cleanup)
105 104
106 105 class cg1unpacker(object):
107 106 """Unpacker for cg1 changegroup streams.
108 107
109 108 A changegroup unpacker handles the framing of the revision data in
110 109 the wire format. Most consumers will want to use the apply()
111 110 method to add the changes from the changegroup to a repository.
112 111
113 112 If you're forwarding a changegroup unmodified to another consumer,
114 113 use getchunks(), which returns an iterator of changegroup
115 114 chunks. This is mostly useful for cases where you need to know the
116 115 data stream has ended by observing the end of the changegroup.
117 116
118 117 deltachunk() is useful only if you're applying delta data. Most
119 118 consumers should prefer apply() instead.
120 119
121 120 A few other public methods exist. Those are used only for
122 121 bundlerepo and some debug commands - their use is discouraged.
123 122 """
124 123 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
125 124 deltaheadersize = deltaheader.size
126 125 version = '01'
127 126 _grouplistcount = 1 # One list of files after the manifests
128 127
129 128 def __init__(self, fh, alg, extras=None):
130 129 if alg is None:
131 130 alg = 'UN'
132 131 if alg not in util.compengines.supportedbundletypes:
133 132 raise error.Abort(_('unknown stream compression type: %s')
134 133 % alg)
135 134 if alg == 'BZ':
136 135 alg = '_truncatedBZ'
137 136
138 137 compengine = util.compengines.forbundletype(alg)
139 138 self._stream = compengine.decompressorreader(fh)
140 139 self._type = alg
141 140 self.extras = extras or {}
142 141 self.callback = None
143 142
144 143 # These methods (compressed, read, seek, tell) all appear to only
145 144 # be used by bundlerepo, but it's a little hard to tell.
146 145 def compressed(self):
147 146 return self._type is not None and self._type != 'UN'
148 147 def read(self, l):
149 148 return self._stream.read(l)
150 149 def seek(self, pos):
151 150 return self._stream.seek(pos)
152 151 def tell(self):
153 152 return self._stream.tell()
154 153 def close(self):
155 154 return self._stream.close()
156 155
157 156 def _chunklength(self):
158 157 d = readexactly(self._stream, 4)
159 158 l = struct.unpack(">l", d)[0]
160 159 if l <= 4:
161 160 if l:
162 161 raise error.Abort(_("invalid chunk length %d") % l)
163 162 return 0
164 163 if self.callback:
165 164 self.callback()
166 165 return l - 4
167 166
168 167 def changelogheader(self):
169 168 """v10 does not have a changelog header chunk"""
170 169 return {}
171 170
172 171 def manifestheader(self):
173 172 """v10 does not have a manifest header chunk"""
174 173 return {}
175 174
176 175 def filelogheader(self):
177 176 """return the header of the filelogs chunk, v10 only has the filename"""
178 177 l = self._chunklength()
179 178 if not l:
180 179 return {}
181 180 fname = readexactly(self._stream, l)
182 181 return {'filename': fname}
183 182
184 183 def _deltaheader(self, headertuple, prevnode):
185 184 node, p1, p2, cs = headertuple
186 185 if prevnode is None:
187 186 deltabase = p1
188 187 else:
189 188 deltabase = prevnode
190 189 flags = 0
191 190 return node, p1, p2, deltabase, cs, flags
192 191
193 192 def deltachunk(self, prevnode):
194 193 l = self._chunklength()
195 194 if not l:
196 195 return {}
197 196 headerdata = readexactly(self._stream, self.deltaheadersize)
198 197 header = self.deltaheader.unpack(headerdata)
199 198 delta = readexactly(self._stream, l - self.deltaheadersize)
200 199 node, p1, p2, deltabase, cs, flags = self._deltaheader(header, prevnode)
201 200 return (node, p1, p2, cs, deltabase, delta, flags)
202 201
203 202 def getchunks(self):
204 203 """returns all the chunks contains in the bundle
205 204
206 205 Used when you need to forward the binary stream to a file or another
207 206 network API. To do so, it parse the changegroup data, otherwise it will
208 207 block in case of sshrepo because it don't know the end of the stream.
209 208 """
210 209 # For changegroup 1 and 2, we expect 3 parts: changelog, manifestlog,
211 210 # and a list of filelogs. For changegroup 3, we expect 4 parts:
212 211 # changelog, manifestlog, a list of tree manifestlogs, and a list of
213 212 # filelogs.
214 213 #
215 214 # Changelog and manifestlog parts are terminated with empty chunks. The
216 215 # tree and file parts are a list of entry sections. Each entry section
217 216 # is a series of chunks terminating in an empty chunk. The list of these
218 217 # entry sections is terminated in yet another empty chunk, so we know
219 218 # we've reached the end of the tree/file list when we reach an empty
220 219 # chunk that was proceeded by no non-empty chunks.
221 220
222 221 parts = 0
223 222 while parts < 2 + self._grouplistcount:
224 223 noentries = True
225 224 while True:
226 225 chunk = getchunk(self)
227 226 if not chunk:
228 227 # The first two empty chunks represent the end of the
229 228 # changelog and the manifestlog portions. The remaining
230 229 # empty chunks represent either A) the end of individual
231 230 # tree or file entries in the file list, or B) the end of
232 231 # the entire list. It's the end of the entire list if there
233 232 # were no entries (i.e. noentries is True).
234 233 if parts < 2:
235 234 parts += 1
236 235 elif noentries:
237 236 parts += 1
238 237 break
239 238 noentries = False
240 239 yield chunkheader(len(chunk))
241 240 pos = 0
242 241 while pos < len(chunk):
243 242 next = pos + 2**20
244 243 yield chunk[pos:next]
245 244 pos = next
246 245 yield closechunk()
247 246
248 247 def _unpackmanifests(self, repo, revmap, trp, prog):
249 248 self.callback = prog.increment
250 249 # no need to check for empty manifest group here:
251 250 # if the result of the merge of 1 and 2 is the same in 3 and 4,
252 251 # no new manifest will be created and the manifest group will
253 252 # be empty during the pull
254 253 self.manifestheader()
255 254 deltas = self.deltaiter()
256 255 repo.manifestlog.getstorage(b'').addgroup(deltas, revmap, trp)
257 256 prog.complete()
258 257 self.callback = None
259 258
260 259 def apply(self, repo, tr, srctype, url, targetphase=phases.draft,
261 260 expectedtotal=None):
262 261 """Add the changegroup returned by source.read() to this repo.
263 262 srctype is a string like 'push', 'pull', or 'unbundle'. url is
264 263 the URL of the repo where this changegroup is coming from.
265 264
266 265 Return an integer summarizing the change to this repo:
267 266 - nothing changed or no source: 0
268 267 - more heads than before: 1+added heads (2..n)
269 268 - fewer heads than before: -1-removed heads (-2..-n)
270 269 - number of heads stays the same: 1
271 270 """
272 271 repo = repo.unfiltered()
273 272 def csmap(x):
274 273 repo.ui.debug("add changeset %s\n" % short(x))
275 274 return len(cl)
276 275
277 276 def revmap(x):
278 277 return cl.rev(x)
279 278
280 279 changesets = files = revisions = 0
281 280
282 281 try:
283 282 # The transaction may already carry source information. In this
284 283 # case we use the top level data. We overwrite the argument
285 284 # because we need to use the top level value (if they exist)
286 285 # in this function.
287 286 srctype = tr.hookargs.setdefault('source', srctype)
288 287 url = tr.hookargs.setdefault('url', url)
289 288 repo.hook('prechangegroup',
290 289 throw=True, **pycompat.strkwargs(tr.hookargs))
291 290
292 291 # write changelog data to temp files so concurrent readers
293 292 # will not see an inconsistent view
294 293 cl = repo.changelog
295 294 cl.delayupdate(tr)
296 295 oldheads = set(cl.heads())
297 296
298 297 trp = weakref.proxy(tr)
299 298 # pull off the changeset group
300 299 repo.ui.status(_("adding changesets\n"))
301 300 clstart = len(cl)
302 301 progress = repo.ui.makeprogress(_('changesets'), unit=_('chunks'),
303 302 total=expectedtotal)
304 303 self.callback = progress.increment
305 304
306 305 efiles = set()
307 306 def onchangelog(cl, node):
308 307 efiles.update(cl.readfiles(node))
309 308
310 309 self.changelogheader()
311 310 deltas = self.deltaiter()
312 311 cgnodes = cl.addgroup(deltas, csmap, trp, addrevisioncb=onchangelog)
313 312 efiles = len(efiles)
314 313
315 314 if not cgnodes:
316 315 repo.ui.develwarn('applied empty changelog from changegroup',
317 316 config='warn-empty-changegroup')
318 317 clend = len(cl)
319 318 changesets = clend - clstart
320 319 progress.complete()
321 320 self.callback = None
322 321
323 322 # pull off the manifest group
324 323 repo.ui.status(_("adding manifests\n"))
325 324 # We know that we'll never have more manifests than we had
326 325 # changesets.
327 326 progress = repo.ui.makeprogress(_('manifests'), unit=_('chunks'),
328 327 total=changesets)
329 328 self._unpackmanifests(repo, revmap, trp, progress)
330 329
331 330 needfiles = {}
332 331 if repo.ui.configbool('server', 'validate'):
333 332 cl = repo.changelog
334 333 ml = repo.manifestlog
335 334 # validate incoming csets have their manifests
336 335 for cset in pycompat.xrange(clstart, clend):
337 336 mfnode = cl.changelogrevision(cset).manifest
338 337 mfest = ml[mfnode].readdelta()
339 338 # store file cgnodes we must see
340 339 for f, n in mfest.iteritems():
341 340 needfiles.setdefault(f, set()).add(n)
342 341
343 342 # process the files
344 343 repo.ui.status(_("adding file changes\n"))
345 344 newrevs, newfiles = _addchangegroupfiles(
346 345 repo, self, revmap, trp, efiles, needfiles)
347 346 revisions += newrevs
348 347 files += newfiles
349 348
350 349 deltaheads = 0
351 350 if oldheads:
352 351 heads = cl.heads()
353 352 deltaheads = len(heads) - len(oldheads)
354 353 for h in heads:
355 354 if h not in oldheads and repo[h].closesbranch():
356 355 deltaheads -= 1
357 356 htext = ""
358 357 if deltaheads:
359 358 htext = _(" (%+d heads)") % deltaheads
360 359
361 360 repo.ui.status(_("added %d changesets"
362 361 " with %d changes to %d files%s\n")
363 362 % (changesets, revisions, files, htext))
364 363 repo.invalidatevolatilesets()
365 364
366 365 if changesets > 0:
367 366 if 'node' not in tr.hookargs:
368 367 tr.hookargs['node'] = hex(cl.node(clstart))
369 368 tr.hookargs['node_last'] = hex(cl.node(clend - 1))
370 369 hookargs = dict(tr.hookargs)
371 370 else:
372 371 hookargs = dict(tr.hookargs)
373 372 hookargs['node'] = hex(cl.node(clstart))
374 373 hookargs['node_last'] = hex(cl.node(clend - 1))
375 374 repo.hook('pretxnchangegroup',
376 375 throw=True, **pycompat.strkwargs(hookargs))
377 376
378 377 added = [cl.node(r) for r in pycompat.xrange(clstart, clend)]
379 378 phaseall = None
380 379 if srctype in ('push', 'serve'):
381 380 # Old servers can not push the boundary themselves.
382 381 # New servers won't push the boundary if changeset already
383 382 # exists locally as secret
384 383 #
385 384 # We should not use added here but the list of all change in
386 385 # the bundle
387 386 if repo.publishing():
388 387 targetphase = phaseall = phases.public
389 388 else:
390 389 # closer target phase computation
391 390
392 391 # Those changesets have been pushed from the
393 392 # outside, their phases are going to be pushed
394 393 # alongside. Therefor `targetphase` is
395 394 # ignored.
396 395 targetphase = phaseall = phases.draft
397 396 if added:
398 397 phases.registernew(repo, tr, targetphase, added)
399 398 if phaseall is not None:
400 399 phases.advanceboundary(repo, tr, phaseall, cgnodes)
401 400
402 401 if changesets > 0:
403 402
404 403 def runhooks():
405 404 # These hooks run when the lock releases, not when the
406 405 # transaction closes. So it's possible for the changelog
407 406 # to have changed since we last saw it.
408 407 if clstart >= len(repo):
409 408 return
410 409
411 410 repo.hook("changegroup", **pycompat.strkwargs(hookargs))
412 411
413 412 for n in added:
414 413 args = hookargs.copy()
415 414 args['node'] = hex(n)
416 415 del args['node_last']
417 416 repo.hook("incoming", **pycompat.strkwargs(args))
418 417
419 418 newheads = [h for h in repo.heads()
420 419 if h not in oldheads]
421 420 repo.ui.log("incoming",
422 421 "%d incoming changes - new heads: %s\n",
423 422 len(added),
424 423 ', '.join([hex(c[:6]) for c in newheads]))
425 424
426 425 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
427 426 lambda tr: repo._afterlock(runhooks))
428 427 finally:
429 428 repo.ui.flush()
430 429 # never return 0 here:
431 430 if deltaheads < 0:
432 431 ret = deltaheads - 1
433 432 else:
434 433 ret = deltaheads + 1
435 434 return ret
436 435
437 436 def deltaiter(self):
438 437 """
439 438 returns an iterator of the deltas in this changegroup
440 439
441 440 Useful for passing to the underlying storage system to be stored.
442 441 """
443 442 chain = None
444 443 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
445 444 # Chunkdata: (node, p1, p2, cs, deltabase, delta, flags)
446 445 yield chunkdata
447 446 chain = chunkdata[0]
448 447
449 448 class cg2unpacker(cg1unpacker):
450 449 """Unpacker for cg2 streams.
451 450
452 451 cg2 streams add support for generaldelta, so the delta header
453 452 format is slightly different. All other features about the data
454 453 remain the same.
455 454 """
456 455 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
457 456 deltaheadersize = deltaheader.size
458 457 version = '02'
459 458
460 459 def _deltaheader(self, headertuple, prevnode):
461 460 node, p1, p2, deltabase, cs = headertuple
462 461 flags = 0
463 462 return node, p1, p2, deltabase, cs, flags
464 463
465 464 class cg3unpacker(cg2unpacker):
466 465 """Unpacker for cg3 streams.
467 466
468 467 cg3 streams add support for exchanging treemanifests and revlog
469 468 flags. It adds the revlog flags to the delta header and an empty chunk
470 469 separating manifests and files.
471 470 """
472 471 deltaheader = _CHANGEGROUPV3_DELTA_HEADER
473 472 deltaheadersize = deltaheader.size
474 473 version = '03'
475 474 _grouplistcount = 2 # One list of manifests and one list of files
476 475
477 476 def _deltaheader(self, headertuple, prevnode):
478 477 node, p1, p2, deltabase, cs, flags = headertuple
479 478 return node, p1, p2, deltabase, cs, flags
480 479
481 480 def _unpackmanifests(self, repo, revmap, trp, prog):
482 481 super(cg3unpacker, self)._unpackmanifests(repo, revmap, trp, prog)
483 482 for chunkdata in iter(self.filelogheader, {}):
484 483 # If we get here, there are directory manifests in the changegroup
485 484 d = chunkdata["filename"]
486 485 repo.ui.debug("adding %s revisions\n" % d)
487 486 deltas = self.deltaiter()
488 487 if not repo.manifestlog.getstorage(d).addgroup(deltas, revmap, trp):
489 488 raise error.Abort(_("received dir revlog group is empty"))
490 489
491 490 class headerlessfixup(object):
492 491 def __init__(self, fh, h):
493 492 self._h = h
494 493 self._fh = fh
495 494 def read(self, n):
496 495 if self._h:
497 496 d, self._h = self._h[:n], self._h[n:]
498 497 if len(d) < n:
499 498 d += readexactly(self._fh, n - len(d))
500 499 return d
501 500 return readexactly(self._fh, n)
502 501
503 502 @interfaceutil.implementer(repository.irevisiondeltarequest)
504 503 @attr.s(slots=True, frozen=True)
505 504 class revisiondeltarequest(object):
506 505 node = attr.ib()
507 506 linknode = attr.ib()
508 507 p1node = attr.ib()
509 508 p2node = attr.ib()
510 509 basenode = attr.ib()
511 510 ellipsis = attr.ib(default=False)
512 511
513 512 def _revisiondeltatochunks(delta, headerfn):
514 513 """Serialize a revisiondelta to changegroup chunks."""
515 514
516 515 # The captured revision delta may be encoded as a delta against
517 516 # a base revision or as a full revision. The changegroup format
518 517 # requires that everything on the wire be deltas. So for full
519 518 # revisions, we need to invent a header that says to rewrite
520 519 # data.
521 520
522 521 if delta.delta is not None:
523 522 prefix, data = b'', delta.delta
524 523 elif delta.basenode == nullid:
525 524 data = delta.revision
526 525 prefix = mdiff.trivialdiffheader(len(data))
527 526 else:
528 527 data = delta.revision
529 528 prefix = mdiff.replacediffheader(delta.baserevisionsize,
530 529 len(data))
531 530
532 531 meta = headerfn(delta)
533 532
534 533 yield chunkheader(len(meta) + len(prefix) + len(data))
535 534 yield meta
536 535 if prefix:
537 536 yield prefix
538 537 yield data
539 538
540 def _sortnodesnormal(store, nodes, reorder):
539 def _sortnodesnormal(store, nodes):
541 540 """Sort nodes for changegroup generation and turn into revnums."""
542 541 # for generaldelta revlogs, we linearize the revs; this will both be
543 542 # much quicker and generate a much smaller bundle
544 if (store._generaldelta and reorder is None) or reorder:
543 if store._generaldelta:
545 544 revs = set(store.rev(n) for n in nodes)
546 545 return dagop.linearize(revs, store.parentrevs)
547 546 else:
548 547 return sorted([store.rev(n) for n in nodes])
549 548
550 549 def _sortnodesellipsis(store, nodes, cl, lookup):
551 550 """Sort nodes for changegroup generation and turn into revnums."""
552 551 # Ellipses serving mode.
553 552 #
554 553 # In a perfect world, we'd generate better ellipsis-ified graphs
555 554 # for non-changelog revlogs. In practice, we haven't started doing
556 555 # that yet, so the resulting DAGs for the manifestlog and filelogs
557 556 # are actually full of bogus parentage on all the ellipsis
558 557 # nodes. This has the side effect that, while the contents are
559 558 # correct, the individual DAGs might be completely out of whack in
560 559 # a case like 882681bc3166 and its ancestors (back about 10
561 560 # revisions or so) in the main hg repo.
562 561 #
563 562 # The one invariant we *know* holds is that the new (potentially
564 563 # bogus) DAG shape will be valid if we order the nodes in the
565 564 # order that they're introduced in dramatis personae by the
566 565 # changelog, so what we do is we sort the non-changelog histories
567 566 # by the order in which they are used by the changelog.
568 567 key = lambda n: cl.rev(lookup(n))
569 568 return [store.rev(n) for n in sorted(nodes, key=key)]
570 569
571 570 def _makenarrowdeltarequest(cl, store, ischangelog, rev, node, linkrev,
572 571 linknode, clrevtolocalrev, fullclnodes,
573 572 precomputedellipsis):
574 573 linkparents = precomputedellipsis[linkrev]
575 574 def local(clrev):
576 575 """Turn a changelog revnum into a local revnum.
577 576
578 577 The ellipsis dag is stored as revnums on the changelog,
579 578 but when we're producing ellipsis entries for
580 579 non-changelog revlogs, we need to turn those numbers into
581 580 something local. This does that for us, and during the
582 581 changelog sending phase will also expand the stored
583 582 mappings as needed.
584 583 """
585 584 if clrev == nullrev:
586 585 return nullrev
587 586
588 587 if ischangelog:
589 588 return clrev
590 589
591 590 # Walk the ellipsis-ized changelog breadth-first looking for a
592 591 # change that has been linked from the current revlog.
593 592 #
594 593 # For a flat manifest revlog only a single step should be necessary
595 594 # as all relevant changelog entries are relevant to the flat
596 595 # manifest.
597 596 #
598 597 # For a filelog or tree manifest dirlog however not every changelog
599 598 # entry will have been relevant, so we need to skip some changelog
600 599 # nodes even after ellipsis-izing.
601 600 walk = [clrev]
602 601 while walk:
603 602 p = walk[0]
604 603 walk = walk[1:]
605 604 if p in clrevtolocalrev:
606 605 return clrevtolocalrev[p]
607 606 elif p in fullclnodes:
608 607 walk.extend([pp for pp in cl.parentrevs(p)
609 608 if pp != nullrev])
610 609 elif p in precomputedellipsis:
611 610 walk.extend([pp for pp in precomputedellipsis[p]
612 611 if pp != nullrev])
613 612 else:
614 613 # In this case, we've got an ellipsis with parents
615 614 # outside the current bundle (likely an
616 615 # incremental pull). We "know" that we can use the
617 616 # value of this same revlog at whatever revision
618 617 # is pointed to by linknode. "Know" is in scare
619 618 # quotes because I haven't done enough examination
620 619 # of edge cases to convince myself this is really
621 620 # a fact - it works for all the (admittedly
622 621 # thorough) cases in our testsuite, but I would be
623 622 # somewhat unsurprised to find a case in the wild
624 623 # where this breaks down a bit. That said, I don't
625 624 # know if it would hurt anything.
626 625 for i in pycompat.xrange(rev, 0, -1):
627 626 if store.linkrev(i) == clrev:
628 627 return i
629 628 # We failed to resolve a parent for this node, so
630 629 # we crash the changegroup construction.
631 630 raise error.Abort(
632 631 'unable to resolve parent while packing %r %r'
633 632 ' for changeset %r' % (store.indexfile, rev, clrev))
634 633
635 634 return nullrev
636 635
637 636 if not linkparents or (
638 637 store.parentrevs(rev) == (nullrev, nullrev)):
639 638 p1, p2 = nullrev, nullrev
640 639 elif len(linkparents) == 1:
641 640 p1, = sorted(local(p) for p in linkparents)
642 641 p2 = nullrev
643 642 else:
644 643 p1, p2 = sorted(local(p) for p in linkparents)
645 644
646 645 p1node, p2node = store.node(p1), store.node(p2)
647 646
648 647 # TODO: try and actually send deltas for ellipsis data blocks
649 648 return revisiondeltarequest(
650 649 node=node,
651 650 p1node=p1node,
652 651 p2node=p2node,
653 652 linknode=linknode,
654 653 basenode=nullid,
655 654 ellipsis=True,
656 655 )
657 656
658 657 def deltagroup(repo, store, nodes, ischangelog, lookup, forcedeltaparentprev,
659 allowreorder,
660 658 topic=None,
661 659 ellipses=False, clrevtolocalrev=None, fullclnodes=None,
662 660 precomputedellipsis=None):
663 661 """Calculate deltas for a set of revisions.
664 662
665 663 Is a generator of ``revisiondelta`` instances.
666 664
667 665 If topic is not None, progress detail will be generated using this
668 666 topic name (e.g. changesets, manifests, etc).
669 667 """
670 668 if not nodes:
671 669 return
672 670
673 671 # We perform two passes over the revisions whose data we will emit.
674 672 #
675 673 # In the first pass, we obtain information about the deltas that will
676 674 # be generated. This involves computing linknodes and adjusting the
677 675 # request to take shallow fetching into account. The end result of
678 676 # this pass is a list of "request" objects stating which deltas
679 677 # to obtain.
680 678 #
681 679 # The second pass is simply resolving the requested deltas.
682 680
683 681 cl = repo.changelog
684 682
685 683 if ischangelog:
686 684 # Changelog doesn't benefit from reordering revisions. So send
687 685 # out revisions in store order.
688 686 # TODO the API would be cleaner if this were controlled by the
689 687 # store producing the deltas.
690 688 revs = sorted(cl.rev(n) for n in nodes)
691 689 elif ellipses:
692 690 revs = _sortnodesellipsis(store, nodes, cl, lookup)
693 691 else:
694 revs = _sortnodesnormal(store, nodes, allowreorder)
692 revs = _sortnodesnormal(store, nodes)
695 693
696 694 # In the first pass, collect info about the deltas we'll be
697 695 # generating.
698 696 requests = []
699 697
700 698 # Add the parent of the first rev.
701 699 revs.insert(0, store.parentrevs(revs[0])[0])
702 700
703 701 for i in pycompat.xrange(len(revs) - 1):
704 702 prev = revs[i]
705 703 curr = revs[i + 1]
706 704
707 705 node = store.node(curr)
708 706 linknode = lookup(node)
709 707 p1node, p2node = store.parents(node)
710 708
711 709 if ellipses:
712 710 linkrev = cl.rev(linknode)
713 711 clrevtolocalrev[linkrev] = curr
714 712
715 713 # This is a node to send in full, because the changeset it
716 714 # corresponds to was a full changeset.
717 715 if linknode in fullclnodes:
718 716 requests.append(revisiondeltarequest(
719 717 node=node,
720 718 p1node=p1node,
721 719 p2node=p2node,
722 720 linknode=linknode,
723 721 basenode=None,
724 722 ))
725 723
726 724 elif linkrev not in precomputedellipsis:
727 725 pass
728 726 else:
729 727 requests.append(_makenarrowdeltarequest(
730 728 cl, store, ischangelog, curr, node, linkrev, linknode,
731 729 clrevtolocalrev, fullclnodes,
732 730 precomputedellipsis))
733 731 else:
734 732 requests.append(revisiondeltarequest(
735 733 node=node,
736 734 p1node=p1node,
737 735 p2node=p2node,
738 736 linknode=linknode,
739 737 basenode=store.node(prev) if forcedeltaparentprev else None,
740 738 ))
741 739
742 740 # We expect the first pass to be fast, so we only engage the progress
743 741 # meter for constructing the revision deltas.
744 742 progress = None
745 743 if topic is not None:
746 744 progress = repo.ui.makeprogress(topic, unit=_('chunks'),
747 745 total=len(requests))
748 746
749 747 for i, delta in enumerate(store.emitrevisiondeltas(requests)):
750 748 if progress:
751 749 progress.update(i + 1)
752 750
753 751 yield delta
754 752
755 753 if progress:
756 754 progress.complete()
757 755
758 756 class cgpacker(object):
759 def __init__(self, repo, filematcher, version, allowreorder,
757 def __init__(self, repo, filematcher, version,
760 758 builddeltaheader, manifestsend,
761 759 forcedeltaparentprev=False,
762 760 bundlecaps=None, ellipses=False,
763 761 shallow=False, ellipsisroots=None, fullnodes=None):
764 762 """Given a source repo, construct a bundler.
765 763
766 764 filematcher is a matcher that matches on files to include in the
767 765 changegroup. Used to facilitate sparse changegroups.
768 766
769 allowreorder controls whether reordering of revisions is allowed.
770 This value is used when ``bundle.reorder`` is ``auto`` or isn't
771 set.
772
773 767 forcedeltaparentprev indicates whether delta parents must be against
774 768 the previous revision in a delta group. This should only be used for
775 769 compatibility with changegroup version 1.
776 770
777 771 builddeltaheader is a callable that constructs the header for a group
778 772 delta.
779 773
780 774 manifestsend is a chunk to send after manifests have been fully emitted.
781 775
782 776 ellipses indicates whether ellipsis serving mode is enabled.
783 777
784 778 bundlecaps is optional and can be used to specify the set of
785 779 capabilities which can be used to build the bundle. While bundlecaps is
786 780 unused in core Mercurial, extensions rely on this feature to communicate
787 781 capabilities to customize the changegroup packer.
788 782
789 783 shallow indicates whether shallow data might be sent. The packer may
790 784 need to pack file contents not introduced by the changes being packed.
791 785
792 786 fullnodes is the set of changelog nodes which should not be ellipsis
793 787 nodes. We store this rather than the set of nodes that should be
794 788 ellipsis because for very large histories we expect this to be
795 789 significantly smaller.
796 790 """
797 791 assert filematcher
798 792 self._filematcher = filematcher
799 793
800 794 self.version = version
801 795 self._forcedeltaparentprev = forcedeltaparentprev
802 796 self._builddeltaheader = builddeltaheader
803 797 self._manifestsend = manifestsend
804 798 self._ellipses = ellipses
805 799
806 800 # Set of capabilities we can use to build the bundle.
807 801 if bundlecaps is None:
808 802 bundlecaps = set()
809 803 self._bundlecaps = bundlecaps
810 804 self._isshallow = shallow
811 805 self._fullclnodes = fullnodes
812 806
813 807 # Maps ellipsis revs to their roots at the changelog level.
814 808 self._precomputedellipsis = ellipsisroots
815 809
816 # experimental config: bundle.reorder
817 reorder = repo.ui.config('bundle', 'reorder')
818 if reorder == 'auto':
819 self._reorder = allowreorder
820 else:
821 self._reorder = stringutil.parsebool(reorder)
822
823 810 self._repo = repo
824 811
825 812 if self._repo.ui.verbose and not self._repo.ui.debugflag:
826 813 self._verbosenote = self._repo.ui.note
827 814 else:
828 815 self._verbosenote = lambda s: None
829 816
830 817 def generate(self, commonrevs, clnodes, fastpathlinkrev, source,
831 818 changelog=True):
832 819 """Yield a sequence of changegroup byte chunks.
833 820 If changelog is False, changelog data won't be added to changegroup
834 821 """
835 822
836 823 repo = self._repo
837 824 cl = repo.changelog
838 825
839 826 self._verbosenote(_('uncompressed size of bundle content:\n'))
840 827 size = 0
841 828
842 829 clstate, deltas = self._generatechangelog(cl, clnodes)
843 830 for delta in deltas:
844 831 if changelog:
845 832 for chunk in _revisiondeltatochunks(delta,
846 833 self._builddeltaheader):
847 834 size += len(chunk)
848 835 yield chunk
849 836
850 837 close = closechunk()
851 838 size += len(close)
852 839 yield closechunk()
853 840
854 841 self._verbosenote(_('%8.i (changelog)\n') % size)
855 842
856 843 clrevorder = clstate['clrevorder']
857 844 manifests = clstate['manifests']
858 845 changedfiles = clstate['changedfiles']
859 846
860 847 # We need to make sure that the linkrev in the changegroup refers to
861 848 # the first changeset that introduced the manifest or file revision.
862 849 # The fastpath is usually safer than the slowpath, because the filelogs
863 850 # are walked in revlog order.
864 851 #
865 # When taking the slowpath with reorder=None and the manifest revlog
866 # uses generaldelta, the manifest may be walked in the "wrong" order.
867 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
868 # cc0ff93d0c0c).
852 # When taking the slowpath when the manifest revlog uses generaldelta,
853 # the manifest may be walked in the "wrong" order. Without 'clrevorder',
854 # we would get an incorrect linkrev (see fix in cc0ff93d0c0c).
869 855 #
870 856 # When taking the fastpath, we are only vulnerable to reordering
871 # of the changelog itself. The changelog never uses generaldelta, so
872 # it is only reordered when reorder=True. To handle this case, we
873 # simply take the slowpath, which already has the 'clrevorder' logic.
874 # This was also fixed in cc0ff93d0c0c.
875 fastpathlinkrev = fastpathlinkrev and not self._reorder
857 # of the changelog itself. The changelog never uses generaldelta and is
858 # never reordered. To handle this case, we simply take the slowpath,
859 # which already has the 'clrevorder' logic. This was also fixed in
860 # cc0ff93d0c0c.
861
876 862 # Treemanifests don't work correctly with fastpathlinkrev
877 863 # either, because we don't discover which directory nodes to
878 864 # send along with files. This could probably be fixed.
879 865 fastpathlinkrev = fastpathlinkrev and (
880 866 'treemanifest' not in repo.requirements)
881 867
882 868 fnodes = {} # needed file nodes
883 869
884 870 size = 0
885 871 it = self.generatemanifests(
886 872 commonrevs, clrevorder, fastpathlinkrev, manifests, fnodes, source,
887 873 clstate['clrevtomanifestrev'])
888 874
889 875 for tree, deltas in it:
890 876 if tree:
891 877 assert self.version == b'03'
892 878 chunk = _fileheader(tree)
893 879 size += len(chunk)
894 880 yield chunk
895 881
896 882 for delta in deltas:
897 883 chunks = _revisiondeltatochunks(delta, self._builddeltaheader)
898 884 for chunk in chunks:
899 885 size += len(chunk)
900 886 yield chunk
901 887
902 888 close = closechunk()
903 889 size += len(close)
904 890 yield close
905 891
906 892 self._verbosenote(_('%8.i (manifests)\n') % size)
907 893 yield self._manifestsend
908 894
909 895 mfdicts = None
910 896 if self._ellipses and self._isshallow:
911 897 mfdicts = [(self._repo.manifestlog[n].read(), lr)
912 898 for (n, lr) in manifests.iteritems()]
913 899
914 900 manifests.clear()
915 901 clrevs = set(cl.rev(x) for x in clnodes)
916 902
917 903 it = self.generatefiles(changedfiles, commonrevs,
918 904 source, mfdicts, fastpathlinkrev,
919 905 fnodes, clrevs)
920 906
921 907 for path, deltas in it:
922 908 h = _fileheader(path)
923 909 size = len(h)
924 910 yield h
925 911
926 912 for delta in deltas:
927 913 chunks = _revisiondeltatochunks(delta, self._builddeltaheader)
928 914 for chunk in chunks:
929 915 size += len(chunk)
930 916 yield chunk
931 917
932 918 close = closechunk()
933 919 size += len(close)
934 920 yield close
935 921
936 922 self._verbosenote(_('%8.i %s\n') % (size, path))
937 923
938 924 yield closechunk()
939 925
940 926 if clnodes:
941 927 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
942 928
943 929 def _generatechangelog(self, cl, nodes):
944 930 """Generate data for changelog chunks.
945 931
946 932 Returns a 2-tuple of a dict containing state and an iterable of
947 933 byte chunks. The state will not be fully populated until the
948 934 chunk stream has been fully consumed.
949 935 """
950 936 clrevorder = {}
951 937 manifests = {}
952 938 mfl = self._repo.manifestlog
953 939 changedfiles = set()
954 940 clrevtomanifestrev = {}
955 941
956 942 # Callback for the changelog, used to collect changed files and
957 943 # manifest nodes.
958 944 # Returns the linkrev node (identity in the changelog case).
959 945 def lookupcl(x):
960 946 c = cl.changelogrevision(x)
961 947 clrevorder[x] = len(clrevorder)
962 948
963 949 if self._ellipses:
964 950 # Only update manifests if x is going to be sent. Otherwise we
965 951 # end up with bogus linkrevs specified for manifests and
966 952 # we skip some manifest nodes that we should otherwise
967 953 # have sent.
968 954 if (x in self._fullclnodes
969 955 or cl.rev(x) in self._precomputedellipsis):
970 956
971 957 manifestnode = c.manifest
972 958 # Record the first changeset introducing this manifest
973 959 # version.
974 960 manifests.setdefault(manifestnode, x)
975 961 # Set this narrow-specific dict so we have the lowest
976 962 # manifest revnum to look up for this cl revnum. (Part of
977 963 # mapping changelog ellipsis parents to manifest ellipsis
978 964 # parents)
979 965 clrevtomanifestrev.setdefault(
980 966 cl.rev(x), mfl.rev(manifestnode))
981 967 # We can't trust the changed files list in the changeset if the
982 968 # client requested a shallow clone.
983 969 if self._isshallow:
984 970 changedfiles.update(mfl[c.manifest].read().keys())
985 971 else:
986 972 changedfiles.update(c.files)
987 973 else:
988 974 # record the first changeset introducing this manifest version
989 975 manifests.setdefault(c.manifest, x)
990 976 # Record a complete list of potentially-changed files in
991 977 # this manifest.
992 978 changedfiles.update(c.files)
993 979
994 980 return x
995 981
996 982 state = {
997 983 'clrevorder': clrevorder,
998 984 'manifests': manifests,
999 985 'changedfiles': changedfiles,
1000 986 'clrevtomanifestrev': clrevtomanifestrev,
1001 987 }
1002 988
1003 989 gen = deltagroup(
1004 990 self._repo, cl, nodes, True, lookupcl,
1005 991 self._forcedeltaparentprev,
1006 # Reorder settings are currently ignored for changelog.
1007 True,
1008 992 ellipses=self._ellipses,
1009 993 topic=_('changesets'),
1010 994 clrevtolocalrev={},
1011 995 fullclnodes=self._fullclnodes,
1012 996 precomputedellipsis=self._precomputedellipsis)
1013 997
1014 998 return state, gen
1015 999
1016 1000 def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev,
1017 1001 manifests, fnodes, source, clrevtolocalrev):
1018 1002 """Returns an iterator of changegroup chunks containing manifests.
1019 1003
1020 1004 `source` is unused here, but is used by extensions like remotefilelog to
1021 1005 change what is sent based in pulls vs pushes, etc.
1022 1006 """
1023 1007 repo = self._repo
1024 1008 mfl = repo.manifestlog
1025 1009 tmfnodes = {'': manifests}
1026 1010
1027 1011 # Callback for the manifest, used to collect linkrevs for filelog
1028 1012 # revisions.
1029 1013 # Returns the linkrev node (collected in lookupcl).
1030 1014 def makelookupmflinknode(tree, nodes):
1031 1015 if fastpathlinkrev:
1032 1016 assert not tree
1033 1017 return manifests.__getitem__
1034 1018
1035 1019 def lookupmflinknode(x):
1036 1020 """Callback for looking up the linknode for manifests.
1037 1021
1038 1022 Returns the linkrev node for the specified manifest.
1039 1023
1040 1024 SIDE EFFECT:
1041 1025
1042 1026 1) fclnodes gets populated with the list of relevant
1043 1027 file nodes if we're not using fastpathlinkrev
1044 1028 2) When treemanifests are in use, collects treemanifest nodes
1045 1029 to send
1046 1030
1047 1031 Note that this means manifests must be completely sent to
1048 1032 the client before you can trust the list of files and
1049 1033 treemanifests to send.
1050 1034 """
1051 1035 clnode = nodes[x]
1052 1036 mdata = mfl.get(tree, x).readfast(shallow=True)
1053 1037 for p, n, fl in mdata.iterentries():
1054 1038 if fl == 't': # subdirectory manifest
1055 1039 subtree = tree + p + '/'
1056 1040 tmfclnodes = tmfnodes.setdefault(subtree, {})
1057 1041 tmfclnode = tmfclnodes.setdefault(n, clnode)
1058 1042 if clrevorder[clnode] < clrevorder[tmfclnode]:
1059 1043 tmfclnodes[n] = clnode
1060 1044 else:
1061 1045 f = tree + p
1062 1046 fclnodes = fnodes.setdefault(f, {})
1063 1047 fclnode = fclnodes.setdefault(n, clnode)
1064 1048 if clrevorder[clnode] < clrevorder[fclnode]:
1065 1049 fclnodes[n] = clnode
1066 1050 return clnode
1067 1051 return lookupmflinknode
1068 1052
1069 1053 while tmfnodes:
1070 1054 tree, nodes = tmfnodes.popitem()
1071 1055 store = mfl.getstorage(tree)
1072 1056
1073 1057 if not self._filematcher.visitdir(store.tree[:-1] or '.'):
1074 1058 # No nodes to send because this directory is out of
1075 1059 # the client's view of the repository (probably
1076 1060 # because of narrow clones).
1077 1061 prunednodes = []
1078 1062 else:
1079 1063 # Avoid sending any manifest nodes we can prove the
1080 1064 # client already has by checking linkrevs. See the
1081 1065 # related comment in generatefiles().
1082 1066 prunednodes = self._prunemanifests(store, nodes, commonrevs)
1083 1067 if tree and not prunednodes:
1084 1068 continue
1085 1069
1086 1070 lookupfn = makelookupmflinknode(tree, nodes)
1087 1071
1088 1072 deltas = deltagroup(
1089 1073 self._repo, store, prunednodes, False, lookupfn,
1090 self._forcedeltaparentprev, self._reorder,
1074 self._forcedeltaparentprev,
1091 1075 ellipses=self._ellipses,
1092 1076 topic=_('manifests'),
1093 1077 clrevtolocalrev=clrevtolocalrev,
1094 1078 fullclnodes=self._fullclnodes,
1095 1079 precomputedellipsis=self._precomputedellipsis)
1096 1080
1097 1081 yield tree, deltas
1098 1082
1099 1083 def _prunemanifests(self, store, nodes, commonrevs):
1100 1084 # This is split out as a separate method to allow filtering
1101 1085 # commonrevs in extension code.
1102 1086 #
1103 1087 # TODO(augie): this shouldn't be required, instead we should
1104 1088 # make filtering of revisions to send delegated to the store
1105 1089 # layer.
1106 1090 frev, flr = store.rev, store.linkrev
1107 1091 return [n for n in nodes if flr(frev(n)) not in commonrevs]
1108 1092
1109 1093 # The 'source' parameter is useful for extensions
1110 1094 def generatefiles(self, changedfiles, commonrevs, source,
1111 1095 mfdicts, fastpathlinkrev, fnodes, clrevs):
1112 1096 changedfiles = list(filter(self._filematcher, changedfiles))
1113 1097
1114 1098 if not fastpathlinkrev:
1115 1099 def normallinknodes(unused, fname):
1116 1100 return fnodes.get(fname, {})
1117 1101 else:
1118 1102 cln = self._repo.changelog.node
1119 1103
1120 1104 def normallinknodes(store, fname):
1121 1105 flinkrev = store.linkrev
1122 1106 fnode = store.node
1123 1107 revs = ((r, flinkrev(r)) for r in store)
1124 1108 return dict((fnode(r), cln(lr))
1125 1109 for r, lr in revs if lr in clrevs)
1126 1110
1127 1111 clrevtolocalrev = {}
1128 1112
1129 1113 if self._isshallow:
1130 1114 # In a shallow clone, the linknodes callback needs to also include
1131 1115 # those file nodes that are in the manifests we sent but weren't
1132 1116 # introduced by those manifests.
1133 1117 commonctxs = [self._repo[c] for c in commonrevs]
1134 1118 clrev = self._repo.changelog.rev
1135 1119
1136 1120 def linknodes(flog, fname):
1137 1121 for c in commonctxs:
1138 1122 try:
1139 1123 fnode = c.filenode(fname)
1140 1124 clrevtolocalrev[c.rev()] = flog.rev(fnode)
1141 1125 except error.ManifestLookupError:
1142 1126 pass
1143 1127 links = normallinknodes(flog, fname)
1144 1128 if len(links) != len(mfdicts):
1145 1129 for mf, lr in mfdicts:
1146 1130 fnode = mf.get(fname, None)
1147 1131 if fnode in links:
1148 1132 links[fnode] = min(links[fnode], lr, key=clrev)
1149 1133 elif fnode:
1150 1134 links[fnode] = lr
1151 1135 return links
1152 1136 else:
1153 1137 linknodes = normallinknodes
1154 1138
1155 1139 repo = self._repo
1156 1140 progress = repo.ui.makeprogress(_('files'), unit=_('files'),
1157 1141 total=len(changedfiles))
1158 1142 for i, fname in enumerate(sorted(changedfiles)):
1159 1143 filerevlog = repo.file(fname)
1160 1144 if not filerevlog:
1161 1145 raise error.Abort(_("empty or missing file data for %s") %
1162 1146 fname)
1163 1147
1164 1148 clrevtolocalrev.clear()
1165 1149
1166 1150 linkrevnodes = linknodes(filerevlog, fname)
1167 1151 # Lookup for filenodes, we collected the linkrev nodes above in the
1168 1152 # fastpath case and with lookupmf in the slowpath case.
1169 1153 def lookupfilelog(x):
1170 1154 return linkrevnodes[x]
1171 1155
1172 1156 frev, flr = filerevlog.rev, filerevlog.linkrev
1173 1157 # Skip sending any filenode we know the client already
1174 1158 # has. This avoids over-sending files relatively
1175 1159 # inexpensively, so it's not a problem if we under-filter
1176 1160 # here.
1177 1161 filenodes = [n for n in linkrevnodes
1178 1162 if flr(frev(n)) not in commonrevs]
1179 1163
1180 1164 if not filenodes:
1181 1165 continue
1182 1166
1183 1167 progress.update(i + 1, item=fname)
1184 1168
1185 1169 deltas = deltagroup(
1186 1170 self._repo, filerevlog, filenodes, False, lookupfilelog,
1187 self._forcedeltaparentprev, self._reorder,
1171 self._forcedeltaparentprev,
1188 1172 ellipses=self._ellipses,
1189 1173 clrevtolocalrev=clrevtolocalrev,
1190 1174 fullclnodes=self._fullclnodes,
1191 1175 precomputedellipsis=self._precomputedellipsis)
1192 1176
1193 1177 yield fname, deltas
1194 1178
1195 1179 progress.complete()
1196 1180
1197 1181 def _makecg1packer(repo, filematcher, bundlecaps, ellipses=False,
1198 1182 shallow=False, ellipsisroots=None, fullnodes=None):
1199 1183 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack(
1200 1184 d.node, d.p1node, d.p2node, d.linknode)
1201 1185
1202 1186 return cgpacker(repo, filematcher, b'01',
1203 allowreorder=None,
1204 1187 builddeltaheader=builddeltaheader,
1205 1188 manifestsend=b'',
1206 1189 forcedeltaparentprev=True,
1207 1190 bundlecaps=bundlecaps,
1208 1191 ellipses=ellipses,
1209 1192 shallow=shallow,
1210 1193 ellipsisroots=ellipsisroots,
1211 1194 fullnodes=fullnodes)
1212 1195
1213 1196 def _makecg2packer(repo, filematcher, bundlecaps, ellipses=False,
1214 1197 shallow=False, ellipsisroots=None, fullnodes=None):
1215 1198 builddeltaheader = lambda d: _CHANGEGROUPV2_DELTA_HEADER.pack(
1216 1199 d.node, d.p1node, d.p2node, d.basenode, d.linknode)
1217 1200
1218 # Since generaldelta is directly supported by cg2, reordering
1219 # generally doesn't help, so we disable it by default (treating
1220 # bundle.reorder=auto just like bundle.reorder=False).
1221 1201 return cgpacker(repo, filematcher, b'02',
1222 allowreorder=False,
1223 1202 builddeltaheader=builddeltaheader,
1224 1203 manifestsend=b'',
1225 1204 bundlecaps=bundlecaps,
1226 1205 ellipses=ellipses,
1227 1206 shallow=shallow,
1228 1207 ellipsisroots=ellipsisroots,
1229 1208 fullnodes=fullnodes)
1230 1209
1231 1210 def _makecg3packer(repo, filematcher, bundlecaps, ellipses=False,
1232 1211 shallow=False, ellipsisroots=None, fullnodes=None):
1233 1212 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack(
1234 1213 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags)
1235 1214
1236 1215 return cgpacker(repo, filematcher, b'03',
1237 allowreorder=False,
1238 1216 builddeltaheader=builddeltaheader,
1239 1217 manifestsend=closechunk(),
1240 1218 bundlecaps=bundlecaps,
1241 1219 ellipses=ellipses,
1242 1220 shallow=shallow,
1243 1221 ellipsisroots=ellipsisroots,
1244 1222 fullnodes=fullnodes)
1245 1223
1246 1224 _packermap = {'01': (_makecg1packer, cg1unpacker),
1247 1225 # cg2 adds support for exchanging generaldelta
1248 1226 '02': (_makecg2packer, cg2unpacker),
1249 1227 # cg3 adds support for exchanging revlog flags and treemanifests
1250 1228 '03': (_makecg3packer, cg3unpacker),
1251 1229 }
1252 1230
1253 1231 def allsupportedversions(repo):
1254 1232 versions = set(_packermap.keys())
1255 1233 if not (repo.ui.configbool('experimental', 'changegroup3') or
1256 1234 repo.ui.configbool('experimental', 'treemanifest') or
1257 1235 'treemanifest' in repo.requirements):
1258 1236 versions.discard('03')
1259 1237 return versions
1260 1238
1261 1239 # Changegroup versions that can be applied to the repo
1262 1240 def supportedincomingversions(repo):
1263 1241 return allsupportedversions(repo)
1264 1242
1265 1243 # Changegroup versions that can be created from the repo
1266 1244 def supportedoutgoingversions(repo):
1267 1245 versions = allsupportedversions(repo)
1268 1246 if 'treemanifest' in repo.requirements:
1269 1247 # Versions 01 and 02 support only flat manifests and it's just too
1270 1248 # expensive to convert between the flat manifest and tree manifest on
1271 1249 # the fly. Since tree manifests are hashed differently, all of history
1272 1250 # would have to be converted. Instead, we simply don't even pretend to
1273 1251 # support versions 01 and 02.
1274 1252 versions.discard('01')
1275 1253 versions.discard('02')
1276 1254 if repository.NARROW_REQUIREMENT in repo.requirements:
1277 1255 # Versions 01 and 02 don't support revlog flags, and we need to
1278 1256 # support that for stripping and unbundling to work.
1279 1257 versions.discard('01')
1280 1258 versions.discard('02')
1281 1259 if LFS_REQUIREMENT in repo.requirements:
1282 1260 # Versions 01 and 02 don't support revlog flags, and we need to
1283 1261 # mark LFS entries with REVIDX_EXTSTORED.
1284 1262 versions.discard('01')
1285 1263 versions.discard('02')
1286 1264
1287 1265 return versions
1288 1266
1289 1267 def localversion(repo):
1290 1268 # Finds the best version to use for bundles that are meant to be used
1291 1269 # locally, such as those from strip and shelve, and temporary bundles.
1292 1270 return max(supportedoutgoingversions(repo))
1293 1271
1294 1272 def safeversion(repo):
1295 1273 # Finds the smallest version that it's safe to assume clients of the repo
1296 1274 # will support. For example, all hg versions that support generaldelta also
1297 1275 # support changegroup 02.
1298 1276 versions = supportedoutgoingversions(repo)
1299 1277 if 'generaldelta' in repo.requirements:
1300 1278 versions.discard('01')
1301 1279 assert versions
1302 1280 return min(versions)
1303 1281
1304 1282 def getbundler(version, repo, bundlecaps=None, filematcher=None,
1305 1283 ellipses=False, shallow=False, ellipsisroots=None,
1306 1284 fullnodes=None):
1307 1285 assert version in supportedoutgoingversions(repo)
1308 1286
1309 1287 if filematcher is None:
1310 1288 filematcher = matchmod.alwaysmatcher(repo.root, '')
1311 1289
1312 1290 if version == '01' and not filematcher.always():
1313 1291 raise error.ProgrammingError('version 01 changegroups do not support '
1314 1292 'sparse file matchers')
1315 1293
1316 1294 if ellipses and version in (b'01', b'02'):
1317 1295 raise error.Abort(
1318 1296 _('ellipsis nodes require at least cg3 on client and server, '
1319 1297 'but negotiated version %s') % version)
1320 1298
1321 1299 # Requested files could include files not in the local store. So
1322 1300 # filter those out.
1323 1301 filematcher = matchmod.intersectmatchers(repo.narrowmatch(),
1324 1302 filematcher)
1325 1303
1326 1304 fn = _packermap[version][0]
1327 1305 return fn(repo, filematcher, bundlecaps, ellipses=ellipses,
1328 1306 shallow=shallow, ellipsisroots=ellipsisroots,
1329 1307 fullnodes=fullnodes)
1330 1308
1331 1309 def getunbundler(version, fh, alg, extras=None):
1332 1310 return _packermap[version][1](fh, alg, extras=extras)
1333 1311
1334 1312 def _changegroupinfo(repo, nodes, source):
1335 1313 if repo.ui.verbose or source == 'bundle':
1336 1314 repo.ui.status(_("%d changesets found\n") % len(nodes))
1337 1315 if repo.ui.debugflag:
1338 1316 repo.ui.debug("list of changesets:\n")
1339 1317 for node in nodes:
1340 1318 repo.ui.debug("%s\n" % hex(node))
1341 1319
1342 1320 def makechangegroup(repo, outgoing, version, source, fastpath=False,
1343 1321 bundlecaps=None):
1344 1322 cgstream = makestream(repo, outgoing, version, source,
1345 1323 fastpath=fastpath, bundlecaps=bundlecaps)
1346 1324 return getunbundler(version, util.chunkbuffer(cgstream), None,
1347 1325 {'clcount': len(outgoing.missing) })
1348 1326
1349 1327 def makestream(repo, outgoing, version, source, fastpath=False,
1350 1328 bundlecaps=None, filematcher=None):
1351 1329 bundler = getbundler(version, repo, bundlecaps=bundlecaps,
1352 1330 filematcher=filematcher)
1353 1331
1354 1332 repo = repo.unfiltered()
1355 1333 commonrevs = outgoing.common
1356 1334 csets = outgoing.missing
1357 1335 heads = outgoing.missingheads
1358 1336 # We go through the fast path if we get told to, or if all (unfiltered
1359 1337 # heads have been requested (since we then know there all linkrevs will
1360 1338 # be pulled by the client).
1361 1339 heads.sort()
1362 1340 fastpathlinkrev = fastpath or (
1363 1341 repo.filtername is None and heads == sorted(repo.heads()))
1364 1342
1365 1343 repo.hook('preoutgoing', throw=True, source=source)
1366 1344 _changegroupinfo(repo, csets, source)
1367 1345 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
1368 1346
1369 1347 def _addchangegroupfiles(repo, source, revmap, trp, expectedfiles, needfiles):
1370 1348 revisions = 0
1371 1349 files = 0
1372 1350 progress = repo.ui.makeprogress(_('files'), unit=_('files'),
1373 1351 total=expectedfiles)
1374 1352 for chunkdata in iter(source.filelogheader, {}):
1375 1353 files += 1
1376 1354 f = chunkdata["filename"]
1377 1355 repo.ui.debug("adding %s revisions\n" % f)
1378 1356 progress.increment()
1379 1357 fl = repo.file(f)
1380 1358 o = len(fl)
1381 1359 try:
1382 1360 deltas = source.deltaiter()
1383 1361 if not fl.addgroup(deltas, revmap, trp):
1384 1362 raise error.Abort(_("received file revlog group is empty"))
1385 1363 except error.CensoredBaseError as e:
1386 1364 raise error.Abort(_("received delta base is censored: %s") % e)
1387 1365 revisions += len(fl) - o
1388 1366 if f in needfiles:
1389 1367 needs = needfiles[f]
1390 1368 for new in pycompat.xrange(o, len(fl)):
1391 1369 n = fl.node(new)
1392 1370 if n in needs:
1393 1371 needs.remove(n)
1394 1372 else:
1395 1373 raise error.Abort(
1396 1374 _("received spurious file revlog entry"))
1397 1375 if not needs:
1398 1376 del needfiles[f]
1399 1377 progress.complete()
1400 1378
1401 1379 for f, needs in needfiles.iteritems():
1402 1380 fl = repo.file(f)
1403 1381 for n in needs:
1404 1382 try:
1405 1383 fl.rev(n)
1406 1384 except error.LookupError:
1407 1385 raise error.Abort(
1408 1386 _('missing file data for %s:%s - run hg verify') %
1409 1387 (f, hex(n)))
1410 1388
1411 1389 return revisions, files
@@ -1,1408 +1,1404 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
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 functools
11 11 import re
12 12
13 13 from . import (
14 14 encoding,
15 15 error,
16 16 )
17 17
18 18 def loadconfigtable(ui, extname, configtable):
19 19 """update config item known to the ui with the extension ones"""
20 20 for section, items in sorted(configtable.items()):
21 21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 22 knownkeys = set(knownitems)
23 23 newkeys = set(items)
24 24 for key in sorted(knownkeys & newkeys):
25 25 msg = "extension '%s' overwrite config item '%s.%s'"
26 26 msg %= (extname, section, key)
27 27 ui.develwarn(msg, config='warn-config')
28 28
29 29 knownitems.update(items)
30 30
31 31 class configitem(object):
32 32 """represent a known config item
33 33
34 34 :section: the official config section where to find this item,
35 35 :name: the official name within the section,
36 36 :default: default value for this item,
37 37 :alias: optional list of tuples as alternatives,
38 38 :generic: this is a generic definition, match name using regular expression.
39 39 """
40 40
41 41 def __init__(self, section, name, default=None, alias=(),
42 42 generic=False, priority=0):
43 43 self.section = section
44 44 self.name = name
45 45 self.default = default
46 46 self.alias = list(alias)
47 47 self.generic = generic
48 48 self.priority = priority
49 49 self._re = None
50 50 if generic:
51 51 self._re = re.compile(self.name)
52 52
53 53 class itemregister(dict):
54 54 """A specialized dictionary that can handle wild-card selection"""
55 55
56 56 def __init__(self):
57 57 super(itemregister, self).__init__()
58 58 self._generics = set()
59 59
60 60 def update(self, other):
61 61 super(itemregister, self).update(other)
62 62 self._generics.update(other._generics)
63 63
64 64 def __setitem__(self, key, item):
65 65 super(itemregister, self).__setitem__(key, item)
66 66 if item.generic:
67 67 self._generics.add(item)
68 68
69 69 def get(self, key):
70 70 baseitem = super(itemregister, self).get(key)
71 71 if baseitem is not None and not baseitem.generic:
72 72 return baseitem
73 73
74 74 # search for a matching generic item
75 75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 76 for item in generics:
77 77 # we use 'match' instead of 'search' to make the matching simpler
78 78 # for people unfamiliar with regular expression. Having the match
79 79 # rooted to the start of the string will produce less surprising
80 80 # result for user writing simple regex for sub-attribute.
81 81 #
82 82 # For example using "color\..*" match produces an unsurprising
83 83 # result, while using search could suddenly match apparently
84 84 # unrelated configuration that happens to contains "color."
85 85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 86 # some match to avoid the need to prefix most pattern with "^".
87 87 # The "^" seems more error prone.
88 88 if item._re.match(key):
89 89 return item
90 90
91 91 return None
92 92
93 93 coreitems = {}
94 94
95 95 def _register(configtable, *args, **kwargs):
96 96 item = configitem(*args, **kwargs)
97 97 section = configtable.setdefault(item.section, itemregister())
98 98 if item.name in section:
99 99 msg = "duplicated config item registration for '%s.%s'"
100 100 raise error.ProgrammingError(msg % (item.section, item.name))
101 101 section[item.name] = item
102 102
103 103 # special value for case where the default is derived from other values
104 104 dynamicdefault = object()
105 105
106 106 # Registering actual config items
107 107
108 108 def getitemregister(configtable):
109 109 f = functools.partial(_register, configtable)
110 110 # export pseudo enum as configitem.*
111 111 f.dynamicdefault = dynamicdefault
112 112 return f
113 113
114 114 coreconfigitem = getitemregister(coreitems)
115 115
116 116 coreconfigitem('alias', '.*',
117 117 default=dynamicdefault,
118 118 generic=True,
119 119 )
120 120 coreconfigitem('annotate', 'nodates',
121 121 default=False,
122 122 )
123 123 coreconfigitem('annotate', 'showfunc',
124 124 default=False,
125 125 )
126 126 coreconfigitem('annotate', 'unified',
127 127 default=None,
128 128 )
129 129 coreconfigitem('annotate', 'git',
130 130 default=False,
131 131 )
132 132 coreconfigitem('annotate', 'ignorews',
133 133 default=False,
134 134 )
135 135 coreconfigitem('annotate', 'ignorewsamount',
136 136 default=False,
137 137 )
138 138 coreconfigitem('annotate', 'ignoreblanklines',
139 139 default=False,
140 140 )
141 141 coreconfigitem('annotate', 'ignorewseol',
142 142 default=False,
143 143 )
144 144 coreconfigitem('annotate', 'nobinary',
145 145 default=False,
146 146 )
147 147 coreconfigitem('annotate', 'noprefix',
148 148 default=False,
149 149 )
150 150 coreconfigitem('annotate', 'word-diff',
151 151 default=False,
152 152 )
153 153 coreconfigitem('auth', 'cookiefile',
154 154 default=None,
155 155 )
156 156 # bookmarks.pushing: internal hack for discovery
157 157 coreconfigitem('bookmarks', 'pushing',
158 158 default=list,
159 159 )
160 160 # bundle.mainreporoot: internal hack for bundlerepo
161 161 coreconfigitem('bundle', 'mainreporoot',
162 162 default='',
163 163 )
164 # bundle.reorder: experimental config
165 coreconfigitem('bundle', 'reorder',
166 default='auto',
167 )
168 164 coreconfigitem('censor', 'policy',
169 165 default='abort',
170 166 )
171 167 coreconfigitem('chgserver', 'idletimeout',
172 168 default=3600,
173 169 )
174 170 coreconfigitem('chgserver', 'skiphash',
175 171 default=False,
176 172 )
177 173 coreconfigitem('cmdserver', 'log',
178 174 default=None,
179 175 )
180 176 coreconfigitem('color', '.*',
181 177 default=None,
182 178 generic=True,
183 179 )
184 180 coreconfigitem('color', 'mode',
185 181 default='auto',
186 182 )
187 183 coreconfigitem('color', 'pagermode',
188 184 default=dynamicdefault,
189 185 )
190 186 coreconfigitem('commands', 'grep.all-files',
191 187 default=False,
192 188 )
193 189 coreconfigitem('commands', 'resolve.confirm',
194 190 default=False,
195 191 )
196 192 coreconfigitem('commands', 'resolve.explicit-re-merge',
197 193 default=False,
198 194 )
199 195 coreconfigitem('commands', 'resolve.mark-check',
200 196 default='none',
201 197 )
202 198 coreconfigitem('commands', 'show.aliasprefix',
203 199 default=list,
204 200 )
205 201 coreconfigitem('commands', 'status.relative',
206 202 default=False,
207 203 )
208 204 coreconfigitem('commands', 'status.skipstates',
209 205 default=[],
210 206 )
211 207 coreconfigitem('commands', 'status.terse',
212 208 default='',
213 209 )
214 210 coreconfigitem('commands', 'status.verbose',
215 211 default=False,
216 212 )
217 213 coreconfigitem('commands', 'update.check',
218 214 default=None,
219 215 )
220 216 coreconfigitem('commands', 'update.requiredest',
221 217 default=False,
222 218 )
223 219 coreconfigitem('committemplate', '.*',
224 220 default=None,
225 221 generic=True,
226 222 )
227 223 coreconfigitem('convert', 'bzr.saverev',
228 224 default=True,
229 225 )
230 226 coreconfigitem('convert', 'cvsps.cache',
231 227 default=True,
232 228 )
233 229 coreconfigitem('convert', 'cvsps.fuzz',
234 230 default=60,
235 231 )
236 232 coreconfigitem('convert', 'cvsps.logencoding',
237 233 default=None,
238 234 )
239 235 coreconfigitem('convert', 'cvsps.mergefrom',
240 236 default=None,
241 237 )
242 238 coreconfigitem('convert', 'cvsps.mergeto',
243 239 default=None,
244 240 )
245 241 coreconfigitem('convert', 'git.committeractions',
246 242 default=lambda: ['messagedifferent'],
247 243 )
248 244 coreconfigitem('convert', 'git.extrakeys',
249 245 default=list,
250 246 )
251 247 coreconfigitem('convert', 'git.findcopiesharder',
252 248 default=False,
253 249 )
254 250 coreconfigitem('convert', 'git.remoteprefix',
255 251 default='remote',
256 252 )
257 253 coreconfigitem('convert', 'git.renamelimit',
258 254 default=400,
259 255 )
260 256 coreconfigitem('convert', 'git.saverev',
261 257 default=True,
262 258 )
263 259 coreconfigitem('convert', 'git.similarity',
264 260 default=50,
265 261 )
266 262 coreconfigitem('convert', 'git.skipsubmodules',
267 263 default=False,
268 264 )
269 265 coreconfigitem('convert', 'hg.clonebranches',
270 266 default=False,
271 267 )
272 268 coreconfigitem('convert', 'hg.ignoreerrors',
273 269 default=False,
274 270 )
275 271 coreconfigitem('convert', 'hg.revs',
276 272 default=None,
277 273 )
278 274 coreconfigitem('convert', 'hg.saverev',
279 275 default=False,
280 276 )
281 277 coreconfigitem('convert', 'hg.sourcename',
282 278 default=None,
283 279 )
284 280 coreconfigitem('convert', 'hg.startrev',
285 281 default=None,
286 282 )
287 283 coreconfigitem('convert', 'hg.tagsbranch',
288 284 default='default',
289 285 )
290 286 coreconfigitem('convert', 'hg.usebranchnames',
291 287 default=True,
292 288 )
293 289 coreconfigitem('convert', 'ignoreancestorcheck',
294 290 default=False,
295 291 )
296 292 coreconfigitem('convert', 'localtimezone',
297 293 default=False,
298 294 )
299 295 coreconfigitem('convert', 'p4.encoding',
300 296 default=dynamicdefault,
301 297 )
302 298 coreconfigitem('convert', 'p4.startrev',
303 299 default=0,
304 300 )
305 301 coreconfigitem('convert', 'skiptags',
306 302 default=False,
307 303 )
308 304 coreconfigitem('convert', 'svn.debugsvnlog',
309 305 default=True,
310 306 )
311 307 coreconfigitem('convert', 'svn.trunk',
312 308 default=None,
313 309 )
314 310 coreconfigitem('convert', 'svn.tags',
315 311 default=None,
316 312 )
317 313 coreconfigitem('convert', 'svn.branches',
318 314 default=None,
319 315 )
320 316 coreconfigitem('convert', 'svn.startrev',
321 317 default=0,
322 318 )
323 319 coreconfigitem('debug', 'dirstate.delaywrite',
324 320 default=0,
325 321 )
326 322 coreconfigitem('defaults', '.*',
327 323 default=None,
328 324 generic=True,
329 325 )
330 326 coreconfigitem('devel', 'all-warnings',
331 327 default=False,
332 328 )
333 329 coreconfigitem('devel', 'bundle2.debug',
334 330 default=False,
335 331 )
336 332 coreconfigitem('devel', 'cache-vfs',
337 333 default=None,
338 334 )
339 335 coreconfigitem('devel', 'check-locks',
340 336 default=False,
341 337 )
342 338 coreconfigitem('devel', 'check-relroot',
343 339 default=False,
344 340 )
345 341 coreconfigitem('devel', 'default-date',
346 342 default=None,
347 343 )
348 344 coreconfigitem('devel', 'deprec-warn',
349 345 default=False,
350 346 )
351 347 coreconfigitem('devel', 'disableloaddefaultcerts',
352 348 default=False,
353 349 )
354 350 coreconfigitem('devel', 'warn-empty-changegroup',
355 351 default=False,
356 352 )
357 353 coreconfigitem('devel', 'legacy.exchange',
358 354 default=list,
359 355 )
360 356 coreconfigitem('devel', 'servercafile',
361 357 default='',
362 358 )
363 359 coreconfigitem('devel', 'serverexactprotocol',
364 360 default='',
365 361 )
366 362 coreconfigitem('devel', 'serverrequirecert',
367 363 default=False,
368 364 )
369 365 coreconfigitem('devel', 'strip-obsmarkers',
370 366 default=True,
371 367 )
372 368 coreconfigitem('devel', 'warn-config',
373 369 default=None,
374 370 )
375 371 coreconfigitem('devel', 'warn-config-default',
376 372 default=None,
377 373 )
378 374 coreconfigitem('devel', 'user.obsmarker',
379 375 default=None,
380 376 )
381 377 coreconfigitem('devel', 'warn-config-unknown',
382 378 default=None,
383 379 )
384 380 coreconfigitem('devel', 'debug.extensions',
385 381 default=False,
386 382 )
387 383 coreconfigitem('devel', 'debug.peer-request',
388 384 default=False,
389 385 )
390 386 coreconfigitem('diff', 'nodates',
391 387 default=False,
392 388 )
393 389 coreconfigitem('diff', 'showfunc',
394 390 default=False,
395 391 )
396 392 coreconfigitem('diff', 'unified',
397 393 default=None,
398 394 )
399 395 coreconfigitem('diff', 'git',
400 396 default=False,
401 397 )
402 398 coreconfigitem('diff', 'ignorews',
403 399 default=False,
404 400 )
405 401 coreconfigitem('diff', 'ignorewsamount',
406 402 default=False,
407 403 )
408 404 coreconfigitem('diff', 'ignoreblanklines',
409 405 default=False,
410 406 )
411 407 coreconfigitem('diff', 'ignorewseol',
412 408 default=False,
413 409 )
414 410 coreconfigitem('diff', 'nobinary',
415 411 default=False,
416 412 )
417 413 coreconfigitem('diff', 'noprefix',
418 414 default=False,
419 415 )
420 416 coreconfigitem('diff', 'word-diff',
421 417 default=False,
422 418 )
423 419 coreconfigitem('email', 'bcc',
424 420 default=None,
425 421 )
426 422 coreconfigitem('email', 'cc',
427 423 default=None,
428 424 )
429 425 coreconfigitem('email', 'charsets',
430 426 default=list,
431 427 )
432 428 coreconfigitem('email', 'from',
433 429 default=None,
434 430 )
435 431 coreconfigitem('email', 'method',
436 432 default='smtp',
437 433 )
438 434 coreconfigitem('email', 'reply-to',
439 435 default=None,
440 436 )
441 437 coreconfigitem('email', 'to',
442 438 default=None,
443 439 )
444 440 coreconfigitem('experimental', 'archivemetatemplate',
445 441 default=dynamicdefault,
446 442 )
447 443 coreconfigitem('experimental', 'bundle-phases',
448 444 default=False,
449 445 )
450 446 coreconfigitem('experimental', 'bundle2-advertise',
451 447 default=True,
452 448 )
453 449 coreconfigitem('experimental', 'bundle2-output-capture',
454 450 default=False,
455 451 )
456 452 coreconfigitem('experimental', 'bundle2.pushback',
457 453 default=False,
458 454 )
459 455 coreconfigitem('experimental', 'bundle2lazylocking',
460 456 default=False,
461 457 )
462 458 coreconfigitem('experimental', 'bundlecomplevel',
463 459 default=None,
464 460 )
465 461 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
466 462 default=None,
467 463 )
468 464 coreconfigitem('experimental', 'bundlecomplevel.gzip',
469 465 default=None,
470 466 )
471 467 coreconfigitem('experimental', 'bundlecomplevel.none',
472 468 default=None,
473 469 )
474 470 coreconfigitem('experimental', 'bundlecomplevel.zstd',
475 471 default=None,
476 472 )
477 473 coreconfigitem('experimental', 'changegroup3',
478 474 default=False,
479 475 )
480 476 coreconfigitem('experimental', 'clientcompressionengines',
481 477 default=list,
482 478 )
483 479 coreconfigitem('experimental', 'copytrace',
484 480 default='on',
485 481 )
486 482 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
487 483 default=100,
488 484 )
489 485 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
490 486 default=100,
491 487 )
492 488 coreconfigitem('experimental', 'crecordtest',
493 489 default=None,
494 490 )
495 491 coreconfigitem('experimental', 'directaccess',
496 492 default=False,
497 493 )
498 494 coreconfigitem('experimental', 'directaccess.revnums',
499 495 default=False,
500 496 )
501 497 coreconfigitem('experimental', 'editortmpinhg',
502 498 default=False,
503 499 )
504 500 coreconfigitem('experimental', 'evolution',
505 501 default=list,
506 502 )
507 503 coreconfigitem('experimental', 'evolution.allowdivergence',
508 504 default=False,
509 505 alias=[('experimental', 'allowdivergence')]
510 506 )
511 507 coreconfigitem('experimental', 'evolution.allowunstable',
512 508 default=None,
513 509 )
514 510 coreconfigitem('experimental', 'evolution.createmarkers',
515 511 default=None,
516 512 )
517 513 coreconfigitem('experimental', 'evolution.effect-flags',
518 514 default=True,
519 515 alias=[('experimental', 'effect-flags')]
520 516 )
521 517 coreconfigitem('experimental', 'evolution.exchange',
522 518 default=None,
523 519 )
524 520 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
525 521 default=False,
526 522 )
527 523 coreconfigitem('experimental', 'evolution.report-instabilities',
528 524 default=True,
529 525 )
530 526 coreconfigitem('experimental', 'evolution.track-operation',
531 527 default=True,
532 528 )
533 529 coreconfigitem('experimental', 'maxdeltachainspan',
534 530 default=-1,
535 531 )
536 532 coreconfigitem('experimental', 'mergetempdirprefix',
537 533 default=None,
538 534 )
539 535 coreconfigitem('experimental', 'mmapindexthreshold',
540 536 default=None,
541 537 )
542 538 coreconfigitem('experimental', 'nonnormalparanoidcheck',
543 539 default=False,
544 540 )
545 541 coreconfigitem('experimental', 'exportableenviron',
546 542 default=list,
547 543 )
548 544 coreconfigitem('experimental', 'extendedheader.index',
549 545 default=None,
550 546 )
551 547 coreconfigitem('experimental', 'extendedheader.similarity',
552 548 default=False,
553 549 )
554 550 coreconfigitem('experimental', 'format.compression',
555 551 default='zlib',
556 552 )
557 553 coreconfigitem('experimental', 'graphshorten',
558 554 default=False,
559 555 )
560 556 coreconfigitem('experimental', 'graphstyle.parent',
561 557 default=dynamicdefault,
562 558 )
563 559 coreconfigitem('experimental', 'graphstyle.missing',
564 560 default=dynamicdefault,
565 561 )
566 562 coreconfigitem('experimental', 'graphstyle.grandparent',
567 563 default=dynamicdefault,
568 564 )
569 565 coreconfigitem('experimental', 'hook-track-tags',
570 566 default=False,
571 567 )
572 568 coreconfigitem('experimental', 'httppeer.advertise-v2',
573 569 default=False,
574 570 )
575 571 coreconfigitem('experimental', 'httppostargs',
576 572 default=False,
577 573 )
578 574 coreconfigitem('experimental', 'mergedriver',
579 575 default=None,
580 576 )
581 577 coreconfigitem('experimental', 'nointerrupt', default=False)
582 578 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
583 579
584 580 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
585 581 default=False,
586 582 )
587 583 coreconfigitem('experimental', 'remotenames',
588 584 default=False,
589 585 )
590 586 coreconfigitem('experimental', 'removeemptydirs',
591 587 default=True,
592 588 )
593 589 coreconfigitem('experimental', 'revisions.prefixhexnode',
594 590 default=False,
595 591 )
596 592 coreconfigitem('experimental', 'revlogv2',
597 593 default=None,
598 594 )
599 595 coreconfigitem('experimental', 'revisions.disambiguatewithin',
600 596 default=None,
601 597 )
602 598 coreconfigitem('experimental', 'single-head-per-branch',
603 599 default=False,
604 600 )
605 601 coreconfigitem('experimental', 'sshserver.support-v2',
606 602 default=False,
607 603 )
608 604 coreconfigitem('experimental', 'spacemovesdown',
609 605 default=False,
610 606 )
611 607 coreconfigitem('experimental', 'sparse-read',
612 608 default=False,
613 609 )
614 610 coreconfigitem('experimental', 'sparse-read.density-threshold',
615 611 default=0.50,
616 612 )
617 613 coreconfigitem('experimental', 'sparse-read.min-gap-size',
618 614 default='65K',
619 615 )
620 616 coreconfigitem('experimental', 'treemanifest',
621 617 default=False,
622 618 )
623 619 coreconfigitem('experimental', 'update.atomic-file',
624 620 default=False,
625 621 )
626 622 coreconfigitem('experimental', 'sshpeer.advertise-v2',
627 623 default=False,
628 624 )
629 625 coreconfigitem('experimental', 'web.apiserver',
630 626 default=False,
631 627 )
632 628 coreconfigitem('experimental', 'web.api.http-v2',
633 629 default=False,
634 630 )
635 631 coreconfigitem('experimental', 'web.api.debugreflect',
636 632 default=False,
637 633 )
638 634 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
639 635 default=False,
640 636 )
641 637 coreconfigitem('experimental', 'xdiff',
642 638 default=False,
643 639 )
644 640 coreconfigitem('extensions', '.*',
645 641 default=None,
646 642 generic=True,
647 643 )
648 644 coreconfigitem('extdata', '.*',
649 645 default=None,
650 646 generic=True,
651 647 )
652 648 coreconfigitem('format', 'chunkcachesize',
653 649 default=None,
654 650 )
655 651 coreconfigitem('format', 'dotencode',
656 652 default=True,
657 653 )
658 654 coreconfigitem('format', 'generaldelta',
659 655 default=False,
660 656 )
661 657 coreconfigitem('format', 'manifestcachesize',
662 658 default=None,
663 659 )
664 660 coreconfigitem('format', 'maxchainlen',
665 661 default=dynamicdefault,
666 662 )
667 663 coreconfigitem('format', 'obsstore-version',
668 664 default=None,
669 665 )
670 666 coreconfigitem('format', 'sparse-revlog',
671 667 default=False,
672 668 )
673 669 coreconfigitem('format', 'usefncache',
674 670 default=True,
675 671 )
676 672 coreconfigitem('format', 'usegeneraldelta',
677 673 default=True,
678 674 )
679 675 coreconfigitem('format', 'usestore',
680 676 default=True,
681 677 )
682 678 coreconfigitem('format', 'internal-phase',
683 679 default=False,
684 680 )
685 681 coreconfigitem('fsmonitor', 'warn_when_unused',
686 682 default=True,
687 683 )
688 684 coreconfigitem('fsmonitor', 'warn_update_file_count',
689 685 default=50000,
690 686 )
691 687 coreconfigitem('hooks', '.*',
692 688 default=dynamicdefault,
693 689 generic=True,
694 690 )
695 691 coreconfigitem('hgweb-paths', '.*',
696 692 default=list,
697 693 generic=True,
698 694 )
699 695 coreconfigitem('hostfingerprints', '.*',
700 696 default=list,
701 697 generic=True,
702 698 )
703 699 coreconfigitem('hostsecurity', 'ciphers',
704 700 default=None,
705 701 )
706 702 coreconfigitem('hostsecurity', 'disabletls10warning',
707 703 default=False,
708 704 )
709 705 coreconfigitem('hostsecurity', 'minimumprotocol',
710 706 default=dynamicdefault,
711 707 )
712 708 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
713 709 default=dynamicdefault,
714 710 generic=True,
715 711 )
716 712 coreconfigitem('hostsecurity', '.*:ciphers$',
717 713 default=dynamicdefault,
718 714 generic=True,
719 715 )
720 716 coreconfigitem('hostsecurity', '.*:fingerprints$',
721 717 default=list,
722 718 generic=True,
723 719 )
724 720 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
725 721 default=None,
726 722 generic=True,
727 723 )
728 724
729 725 coreconfigitem('http_proxy', 'always',
730 726 default=False,
731 727 )
732 728 coreconfigitem('http_proxy', 'host',
733 729 default=None,
734 730 )
735 731 coreconfigitem('http_proxy', 'no',
736 732 default=list,
737 733 )
738 734 coreconfigitem('http_proxy', 'passwd',
739 735 default=None,
740 736 )
741 737 coreconfigitem('http_proxy', 'user',
742 738 default=None,
743 739 )
744 740 coreconfigitem('logtoprocess', 'commandexception',
745 741 default=None,
746 742 )
747 743 coreconfigitem('logtoprocess', 'commandfinish',
748 744 default=None,
749 745 )
750 746 coreconfigitem('logtoprocess', 'command',
751 747 default=None,
752 748 )
753 749 coreconfigitem('logtoprocess', 'develwarn',
754 750 default=None,
755 751 )
756 752 coreconfigitem('logtoprocess', 'uiblocked',
757 753 default=None,
758 754 )
759 755 coreconfigitem('merge', 'checkunknown',
760 756 default='abort',
761 757 )
762 758 coreconfigitem('merge', 'checkignored',
763 759 default='abort',
764 760 )
765 761 coreconfigitem('experimental', 'merge.checkpathconflicts',
766 762 default=False,
767 763 )
768 764 coreconfigitem('merge', 'followcopies',
769 765 default=True,
770 766 )
771 767 coreconfigitem('merge', 'on-failure',
772 768 default='continue',
773 769 )
774 770 coreconfigitem('merge', 'preferancestor',
775 771 default=lambda: ['*'],
776 772 )
777 773 coreconfigitem('merge', 'strict-capability-check',
778 774 default=False,
779 775 )
780 776 coreconfigitem('merge-tools', '.*',
781 777 default=None,
782 778 generic=True,
783 779 )
784 780 coreconfigitem('merge-tools', br'.*\.args$',
785 781 default="$local $base $other",
786 782 generic=True,
787 783 priority=-1,
788 784 )
789 785 coreconfigitem('merge-tools', br'.*\.binary$',
790 786 default=False,
791 787 generic=True,
792 788 priority=-1,
793 789 )
794 790 coreconfigitem('merge-tools', br'.*\.check$',
795 791 default=list,
796 792 generic=True,
797 793 priority=-1,
798 794 )
799 795 coreconfigitem('merge-tools', br'.*\.checkchanged$',
800 796 default=False,
801 797 generic=True,
802 798 priority=-1,
803 799 )
804 800 coreconfigitem('merge-tools', br'.*\.executable$',
805 801 default=dynamicdefault,
806 802 generic=True,
807 803 priority=-1,
808 804 )
809 805 coreconfigitem('merge-tools', br'.*\.fixeol$',
810 806 default=False,
811 807 generic=True,
812 808 priority=-1,
813 809 )
814 810 coreconfigitem('merge-tools', br'.*\.gui$',
815 811 default=False,
816 812 generic=True,
817 813 priority=-1,
818 814 )
819 815 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
820 816 default='basic',
821 817 generic=True,
822 818 priority=-1,
823 819 )
824 820 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
825 821 default=dynamicdefault, # take from ui.mergemarkertemplate
826 822 generic=True,
827 823 priority=-1,
828 824 )
829 825 coreconfigitem('merge-tools', br'.*\.priority$',
830 826 default=0,
831 827 generic=True,
832 828 priority=-1,
833 829 )
834 830 coreconfigitem('merge-tools', br'.*\.premerge$',
835 831 default=dynamicdefault,
836 832 generic=True,
837 833 priority=-1,
838 834 )
839 835 coreconfigitem('merge-tools', br'.*\.symlink$',
840 836 default=False,
841 837 generic=True,
842 838 priority=-1,
843 839 )
844 840 coreconfigitem('pager', 'attend-.*',
845 841 default=dynamicdefault,
846 842 generic=True,
847 843 )
848 844 coreconfigitem('pager', 'ignore',
849 845 default=list,
850 846 )
851 847 coreconfigitem('pager', 'pager',
852 848 default=dynamicdefault,
853 849 )
854 850 coreconfigitem('patch', 'eol',
855 851 default='strict',
856 852 )
857 853 coreconfigitem('patch', 'fuzz',
858 854 default=2,
859 855 )
860 856 coreconfigitem('paths', 'default',
861 857 default=None,
862 858 )
863 859 coreconfigitem('paths', 'default-push',
864 860 default=None,
865 861 )
866 862 coreconfigitem('paths', '.*',
867 863 default=None,
868 864 generic=True,
869 865 )
870 866 coreconfigitem('phases', 'checksubrepos',
871 867 default='follow',
872 868 )
873 869 coreconfigitem('phases', 'new-commit',
874 870 default='draft',
875 871 )
876 872 coreconfigitem('phases', 'publish',
877 873 default=True,
878 874 )
879 875 coreconfigitem('profiling', 'enabled',
880 876 default=False,
881 877 )
882 878 coreconfigitem('profiling', 'format',
883 879 default='text',
884 880 )
885 881 coreconfigitem('profiling', 'freq',
886 882 default=1000,
887 883 )
888 884 coreconfigitem('profiling', 'limit',
889 885 default=30,
890 886 )
891 887 coreconfigitem('profiling', 'nested',
892 888 default=0,
893 889 )
894 890 coreconfigitem('profiling', 'output',
895 891 default=None,
896 892 )
897 893 coreconfigitem('profiling', 'showmax',
898 894 default=0.999,
899 895 )
900 896 coreconfigitem('profiling', 'showmin',
901 897 default=dynamicdefault,
902 898 )
903 899 coreconfigitem('profiling', 'sort',
904 900 default='inlinetime',
905 901 )
906 902 coreconfigitem('profiling', 'statformat',
907 903 default='hotpath',
908 904 )
909 905 coreconfigitem('profiling', 'time-track',
910 906 default='cpu',
911 907 )
912 908 coreconfigitem('profiling', 'type',
913 909 default='stat',
914 910 )
915 911 coreconfigitem('progress', 'assume-tty',
916 912 default=False,
917 913 )
918 914 coreconfigitem('progress', 'changedelay',
919 915 default=1,
920 916 )
921 917 coreconfigitem('progress', 'clear-complete',
922 918 default=True,
923 919 )
924 920 coreconfigitem('progress', 'debug',
925 921 default=False,
926 922 )
927 923 coreconfigitem('progress', 'delay',
928 924 default=3,
929 925 )
930 926 coreconfigitem('progress', 'disable',
931 927 default=False,
932 928 )
933 929 coreconfigitem('progress', 'estimateinterval',
934 930 default=60.0,
935 931 )
936 932 coreconfigitem('progress', 'format',
937 933 default=lambda: ['topic', 'bar', 'number', 'estimate'],
938 934 )
939 935 coreconfigitem('progress', 'refresh',
940 936 default=0.1,
941 937 )
942 938 coreconfigitem('progress', 'width',
943 939 default=dynamicdefault,
944 940 )
945 941 coreconfigitem('push', 'pushvars.server',
946 942 default=False,
947 943 )
948 944 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
949 945 default=True,
950 946 alias=[('format', 'aggressivemergedeltas')],
951 947 )
952 948 coreconfigitem('server', 'bookmarks-pushkey-compat',
953 949 default=True,
954 950 )
955 951 coreconfigitem('server', 'bundle1',
956 952 default=True,
957 953 )
958 954 coreconfigitem('server', 'bundle1gd',
959 955 default=None,
960 956 )
961 957 coreconfigitem('server', 'bundle1.pull',
962 958 default=None,
963 959 )
964 960 coreconfigitem('server', 'bundle1gd.pull',
965 961 default=None,
966 962 )
967 963 coreconfigitem('server', 'bundle1.push',
968 964 default=None,
969 965 )
970 966 coreconfigitem('server', 'bundle1gd.push',
971 967 default=None,
972 968 )
973 969 coreconfigitem('server', 'bundle2.stream',
974 970 default=True,
975 971 alias=[('experimental', 'bundle2.stream')]
976 972 )
977 973 coreconfigitem('server', 'compressionengines',
978 974 default=list,
979 975 )
980 976 coreconfigitem('server', 'concurrent-push-mode',
981 977 default='strict',
982 978 )
983 979 coreconfigitem('server', 'disablefullbundle',
984 980 default=False,
985 981 )
986 982 coreconfigitem('server', 'maxhttpheaderlen',
987 983 default=1024,
988 984 )
989 985 coreconfigitem('server', 'pullbundle',
990 986 default=False,
991 987 )
992 988 coreconfigitem('server', 'preferuncompressed',
993 989 default=False,
994 990 )
995 991 coreconfigitem('server', 'streamunbundle',
996 992 default=False,
997 993 )
998 994 coreconfigitem('server', 'uncompressed',
999 995 default=True,
1000 996 )
1001 997 coreconfigitem('server', 'uncompressedallowsecret',
1002 998 default=False,
1003 999 )
1004 1000 coreconfigitem('server', 'validate',
1005 1001 default=False,
1006 1002 )
1007 1003 coreconfigitem('server', 'zliblevel',
1008 1004 default=-1,
1009 1005 )
1010 1006 coreconfigitem('server', 'zstdlevel',
1011 1007 default=3,
1012 1008 )
1013 1009 coreconfigitem('share', 'pool',
1014 1010 default=None,
1015 1011 )
1016 1012 coreconfigitem('share', 'poolnaming',
1017 1013 default='identity',
1018 1014 )
1019 1015 coreconfigitem('smtp', 'host',
1020 1016 default=None,
1021 1017 )
1022 1018 coreconfigitem('smtp', 'local_hostname',
1023 1019 default=None,
1024 1020 )
1025 1021 coreconfigitem('smtp', 'password',
1026 1022 default=None,
1027 1023 )
1028 1024 coreconfigitem('smtp', 'port',
1029 1025 default=dynamicdefault,
1030 1026 )
1031 1027 coreconfigitem('smtp', 'tls',
1032 1028 default='none',
1033 1029 )
1034 1030 coreconfigitem('smtp', 'username',
1035 1031 default=None,
1036 1032 )
1037 1033 coreconfigitem('sparse', 'missingwarning',
1038 1034 default=True,
1039 1035 )
1040 1036 coreconfigitem('subrepos', 'allowed',
1041 1037 default=dynamicdefault, # to make backporting simpler
1042 1038 )
1043 1039 coreconfigitem('subrepos', 'hg:allowed',
1044 1040 default=dynamicdefault,
1045 1041 )
1046 1042 coreconfigitem('subrepos', 'git:allowed',
1047 1043 default=dynamicdefault,
1048 1044 )
1049 1045 coreconfigitem('subrepos', 'svn:allowed',
1050 1046 default=dynamicdefault,
1051 1047 )
1052 1048 coreconfigitem('templates', '.*',
1053 1049 default=None,
1054 1050 generic=True,
1055 1051 )
1056 1052 coreconfigitem('trusted', 'groups',
1057 1053 default=list,
1058 1054 )
1059 1055 coreconfigitem('trusted', 'users',
1060 1056 default=list,
1061 1057 )
1062 1058 coreconfigitem('ui', '_usedassubrepo',
1063 1059 default=False,
1064 1060 )
1065 1061 coreconfigitem('ui', 'allowemptycommit',
1066 1062 default=False,
1067 1063 )
1068 1064 coreconfigitem('ui', 'archivemeta',
1069 1065 default=True,
1070 1066 )
1071 1067 coreconfigitem('ui', 'askusername',
1072 1068 default=False,
1073 1069 )
1074 1070 coreconfigitem('ui', 'clonebundlefallback',
1075 1071 default=False,
1076 1072 )
1077 1073 coreconfigitem('ui', 'clonebundleprefers',
1078 1074 default=list,
1079 1075 )
1080 1076 coreconfigitem('ui', 'clonebundles',
1081 1077 default=True,
1082 1078 )
1083 1079 coreconfigitem('ui', 'color',
1084 1080 default='auto',
1085 1081 )
1086 1082 coreconfigitem('ui', 'commitsubrepos',
1087 1083 default=False,
1088 1084 )
1089 1085 coreconfigitem('ui', 'debug',
1090 1086 default=False,
1091 1087 )
1092 1088 coreconfigitem('ui', 'debugger',
1093 1089 default=None,
1094 1090 )
1095 1091 coreconfigitem('ui', 'editor',
1096 1092 default=dynamicdefault,
1097 1093 )
1098 1094 coreconfigitem('ui', 'fallbackencoding',
1099 1095 default=None,
1100 1096 )
1101 1097 coreconfigitem('ui', 'forcecwd',
1102 1098 default=None,
1103 1099 )
1104 1100 coreconfigitem('ui', 'forcemerge',
1105 1101 default=None,
1106 1102 )
1107 1103 coreconfigitem('ui', 'formatdebug',
1108 1104 default=False,
1109 1105 )
1110 1106 coreconfigitem('ui', 'formatjson',
1111 1107 default=False,
1112 1108 )
1113 1109 coreconfigitem('ui', 'formatted',
1114 1110 default=None,
1115 1111 )
1116 1112 coreconfigitem('ui', 'graphnodetemplate',
1117 1113 default=None,
1118 1114 )
1119 1115 coreconfigitem('ui', 'history-editing-backup',
1120 1116 default=True,
1121 1117 )
1122 1118 coreconfigitem('ui', 'interactive',
1123 1119 default=None,
1124 1120 )
1125 1121 coreconfigitem('ui', 'interface',
1126 1122 default=None,
1127 1123 )
1128 1124 coreconfigitem('ui', 'interface.chunkselector',
1129 1125 default=None,
1130 1126 )
1131 1127 coreconfigitem('ui', 'large-file-limit',
1132 1128 default=10000000,
1133 1129 )
1134 1130 coreconfigitem('ui', 'logblockedtimes',
1135 1131 default=False,
1136 1132 )
1137 1133 coreconfigitem('ui', 'logtemplate',
1138 1134 default=None,
1139 1135 )
1140 1136 coreconfigitem('ui', 'merge',
1141 1137 default=None,
1142 1138 )
1143 1139 coreconfigitem('ui', 'mergemarkers',
1144 1140 default='basic',
1145 1141 )
1146 1142 coreconfigitem('ui', 'mergemarkertemplate',
1147 1143 default=('{node|short} '
1148 1144 '{ifeq(tags, "tip", "", '
1149 1145 'ifeq(tags, "", "", "{tags} "))}'
1150 1146 '{if(bookmarks, "{bookmarks} ")}'
1151 1147 '{ifeq(branch, "default", "", "{branch} ")}'
1152 1148 '- {author|user}: {desc|firstline}')
1153 1149 )
1154 1150 coreconfigitem('ui', 'nontty',
1155 1151 default=False,
1156 1152 )
1157 1153 coreconfigitem('ui', 'origbackuppath',
1158 1154 default=None,
1159 1155 )
1160 1156 coreconfigitem('ui', 'paginate',
1161 1157 default=True,
1162 1158 )
1163 1159 coreconfigitem('ui', 'patch',
1164 1160 default=None,
1165 1161 )
1166 1162 coreconfigitem('ui', 'portablefilenames',
1167 1163 default='warn',
1168 1164 )
1169 1165 coreconfigitem('ui', 'promptecho',
1170 1166 default=False,
1171 1167 )
1172 1168 coreconfigitem('ui', 'quiet',
1173 1169 default=False,
1174 1170 )
1175 1171 coreconfigitem('ui', 'quietbookmarkmove',
1176 1172 default=False,
1177 1173 )
1178 1174 coreconfigitem('ui', 'remotecmd',
1179 1175 default='hg',
1180 1176 )
1181 1177 coreconfigitem('ui', 'report_untrusted',
1182 1178 default=True,
1183 1179 )
1184 1180 coreconfigitem('ui', 'rollback',
1185 1181 default=True,
1186 1182 )
1187 1183 coreconfigitem('ui', 'signal-safe-lock',
1188 1184 default=True,
1189 1185 )
1190 1186 coreconfigitem('ui', 'slash',
1191 1187 default=False,
1192 1188 )
1193 1189 coreconfigitem('ui', 'ssh',
1194 1190 default='ssh',
1195 1191 )
1196 1192 coreconfigitem('ui', 'ssherrorhint',
1197 1193 default=None,
1198 1194 )
1199 1195 coreconfigitem('ui', 'statuscopies',
1200 1196 default=False,
1201 1197 )
1202 1198 coreconfigitem('ui', 'strict',
1203 1199 default=False,
1204 1200 )
1205 1201 coreconfigitem('ui', 'style',
1206 1202 default='',
1207 1203 )
1208 1204 coreconfigitem('ui', 'supportcontact',
1209 1205 default=None,
1210 1206 )
1211 1207 coreconfigitem('ui', 'textwidth',
1212 1208 default=78,
1213 1209 )
1214 1210 coreconfigitem('ui', 'timeout',
1215 1211 default='600',
1216 1212 )
1217 1213 coreconfigitem('ui', 'timeout.warn',
1218 1214 default=0,
1219 1215 )
1220 1216 coreconfigitem('ui', 'traceback',
1221 1217 default=False,
1222 1218 )
1223 1219 coreconfigitem('ui', 'tweakdefaults',
1224 1220 default=False,
1225 1221 )
1226 1222 coreconfigitem('ui', 'username',
1227 1223 alias=[('ui', 'user')]
1228 1224 )
1229 1225 coreconfigitem('ui', 'verbose',
1230 1226 default=False,
1231 1227 )
1232 1228 coreconfigitem('verify', 'skipflags',
1233 1229 default=None,
1234 1230 )
1235 1231 coreconfigitem('web', 'allowbz2',
1236 1232 default=False,
1237 1233 )
1238 1234 coreconfigitem('web', 'allowgz',
1239 1235 default=False,
1240 1236 )
1241 1237 coreconfigitem('web', 'allow-pull',
1242 1238 alias=[('web', 'allowpull')],
1243 1239 default=True,
1244 1240 )
1245 1241 coreconfigitem('web', 'allow-push',
1246 1242 alias=[('web', 'allow_push')],
1247 1243 default=list,
1248 1244 )
1249 1245 coreconfigitem('web', 'allowzip',
1250 1246 default=False,
1251 1247 )
1252 1248 coreconfigitem('web', 'archivesubrepos',
1253 1249 default=False,
1254 1250 )
1255 1251 coreconfigitem('web', 'cache',
1256 1252 default=True,
1257 1253 )
1258 1254 coreconfigitem('web', 'contact',
1259 1255 default=None,
1260 1256 )
1261 1257 coreconfigitem('web', 'deny_push',
1262 1258 default=list,
1263 1259 )
1264 1260 coreconfigitem('web', 'guessmime',
1265 1261 default=False,
1266 1262 )
1267 1263 coreconfigitem('web', 'hidden',
1268 1264 default=False,
1269 1265 )
1270 1266 coreconfigitem('web', 'labels',
1271 1267 default=list,
1272 1268 )
1273 1269 coreconfigitem('web', 'logoimg',
1274 1270 default='hglogo.png',
1275 1271 )
1276 1272 coreconfigitem('web', 'logourl',
1277 1273 default='https://mercurial-scm.org/',
1278 1274 )
1279 1275 coreconfigitem('web', 'accesslog',
1280 1276 default='-',
1281 1277 )
1282 1278 coreconfigitem('web', 'address',
1283 1279 default='',
1284 1280 )
1285 1281 coreconfigitem('web', 'allow-archive',
1286 1282 alias=[('web', 'allow_archive')],
1287 1283 default=list,
1288 1284 )
1289 1285 coreconfigitem('web', 'allow_read',
1290 1286 default=list,
1291 1287 )
1292 1288 coreconfigitem('web', 'baseurl',
1293 1289 default=None,
1294 1290 )
1295 1291 coreconfigitem('web', 'cacerts',
1296 1292 default=None,
1297 1293 )
1298 1294 coreconfigitem('web', 'certificate',
1299 1295 default=None,
1300 1296 )
1301 1297 coreconfigitem('web', 'collapse',
1302 1298 default=False,
1303 1299 )
1304 1300 coreconfigitem('web', 'csp',
1305 1301 default=None,
1306 1302 )
1307 1303 coreconfigitem('web', 'deny_read',
1308 1304 default=list,
1309 1305 )
1310 1306 coreconfigitem('web', 'descend',
1311 1307 default=True,
1312 1308 )
1313 1309 coreconfigitem('web', 'description',
1314 1310 default="",
1315 1311 )
1316 1312 coreconfigitem('web', 'encoding',
1317 1313 default=lambda: encoding.encoding,
1318 1314 )
1319 1315 coreconfigitem('web', 'errorlog',
1320 1316 default='-',
1321 1317 )
1322 1318 coreconfigitem('web', 'ipv6',
1323 1319 default=False,
1324 1320 )
1325 1321 coreconfigitem('web', 'maxchanges',
1326 1322 default=10,
1327 1323 )
1328 1324 coreconfigitem('web', 'maxfiles',
1329 1325 default=10,
1330 1326 )
1331 1327 coreconfigitem('web', 'maxshortchanges',
1332 1328 default=60,
1333 1329 )
1334 1330 coreconfigitem('web', 'motd',
1335 1331 default='',
1336 1332 )
1337 1333 coreconfigitem('web', 'name',
1338 1334 default=dynamicdefault,
1339 1335 )
1340 1336 coreconfigitem('web', 'port',
1341 1337 default=8000,
1342 1338 )
1343 1339 coreconfigitem('web', 'prefix',
1344 1340 default='',
1345 1341 )
1346 1342 coreconfigitem('web', 'push_ssl',
1347 1343 default=True,
1348 1344 )
1349 1345 coreconfigitem('web', 'refreshinterval',
1350 1346 default=20,
1351 1347 )
1352 1348 coreconfigitem('web', 'server-header',
1353 1349 default=None,
1354 1350 )
1355 1351 coreconfigitem('web', 'static',
1356 1352 default=None,
1357 1353 )
1358 1354 coreconfigitem('web', 'staticurl',
1359 1355 default=None,
1360 1356 )
1361 1357 coreconfigitem('web', 'stripes',
1362 1358 default=1,
1363 1359 )
1364 1360 coreconfigitem('web', 'style',
1365 1361 default='paper',
1366 1362 )
1367 1363 coreconfigitem('web', 'templates',
1368 1364 default=None,
1369 1365 )
1370 1366 coreconfigitem('web', 'view',
1371 1367 default='served',
1372 1368 )
1373 1369 coreconfigitem('worker', 'backgroundclose',
1374 1370 default=dynamicdefault,
1375 1371 )
1376 1372 # Windows defaults to a limit of 512 open files. A buffer of 128
1377 1373 # should give us enough headway.
1378 1374 coreconfigitem('worker', 'backgroundclosemaxqueue',
1379 1375 default=384,
1380 1376 )
1381 1377 coreconfigitem('worker', 'backgroundcloseminfilecount',
1382 1378 default=2048,
1383 1379 )
1384 1380 coreconfigitem('worker', 'backgroundclosethreadcount',
1385 1381 default=4,
1386 1382 )
1387 1383 coreconfigitem('worker', 'enabled',
1388 1384 default=True,
1389 1385 )
1390 1386 coreconfigitem('worker', 'numcpus',
1391 1387 default=None,
1392 1388 )
1393 1389
1394 1390 # Rebase related configuration moved to core because other extension are doing
1395 1391 # strange things. For example, shelve import the extensions to reuse some bit
1396 1392 # without formally loading it.
1397 1393 coreconfigitem('commands', 'rebase.requiredest',
1398 1394 default=False,
1399 1395 )
1400 1396 coreconfigitem('experimental', 'rebaseskipobsolete',
1401 1397 default=True,
1402 1398 )
1403 1399 coreconfigitem('rebase', 'singletransaction',
1404 1400 default=False,
1405 1401 )
1406 1402 coreconfigitem('rebase', 'experimental.inmemory',
1407 1403 default=False,
1408 1404 )
@@ -1,402 +1,402 b''
1 1 #require no-reposimplestore
2 2
3 3 Check whether size of generaldelta revlog is not bigger than its
4 4 regular equivalent. Test would fail if generaldelta was naive
5 5 implementation of parentdelta: third manifest revision would be fully
6 6 inserted due to big distance from its paren revision (zero).
7 7
8 8 $ hg init repo --config format.generaldelta=no --config format.usegeneraldelta=no
9 9 $ cd repo
10 10 $ echo foo > foo
11 11 $ echo bar > bar
12 12 $ echo baz > baz
13 13 $ hg commit -q -Am boo
14 14 $ hg clone --pull . ../gdrepo -q --config format.generaldelta=yes
15 15 $ for r in 1 2 3; do
16 16 > echo $r > foo
17 17 > hg commit -q -m $r
18 18 > hg up -q -r 0
19 19 > hg pull . -q -r $r -R ../gdrepo
20 20 > done
21 21
22 22 $ cd ..
23 23 >>> from __future__ import print_function
24 24 >>> import os
25 25 >>> regsize = os.stat("repo/.hg/store/00manifest.i").st_size
26 26 >>> gdsize = os.stat("gdrepo/.hg/store/00manifest.i").st_size
27 27 >>> if regsize < gdsize:
28 28 ... print('generaldata increased size of manifest')
29 29
30 30 Verify rev reordering doesnt create invalid bundles (issue4462)
31 31 This requires a commit tree that when pulled will reorder manifest revs such
32 32 that the second manifest to create a file rev will be ordered before the first
33 33 manifest to create that file rev. We also need to do a partial pull to ensure
34 34 reordering happens. At the end we verify the linkrev points at the earliest
35 35 commit.
36 36
37 37 $ hg init server --config format.generaldelta=True
38 38 $ cd server
39 39 $ touch a
40 40 $ hg commit -Aqm a
41 41 $ echo x > x
42 42 $ echo y > y
43 43 $ hg commit -Aqm xy
44 44 $ hg up -q '.^'
45 45 $ echo x > x
46 46 $ echo z > z
47 47 $ hg commit -Aqm xz
48 48 $ hg up -q 1
49 49 $ echo b > b
50 50 $ hg commit -Aqm b
51 51 $ hg merge -q 2
52 52 $ hg commit -Aqm merge
53 53 $ echo c > c
54 54 $ hg commit -Aqm c
55 55 $ hg log -G -T '{rev} {shortest(node)} {desc}'
56 56 @ 5 ebb8 c
57 57 |
58 58 o 4 baf7 merge
59 59 |\
60 60 | o 3 a129 b
61 61 | |
62 62 o | 2 958c xz
63 63 | |
64 64 | o 1 f00c xy
65 65 |/
66 66 o 0 3903 a
67 67
68 68 $ cd ..
69 69 $ hg init client --config format.generaldelta=false --config format.usegeneraldelta=false
70 70 $ cd client
71 71 $ hg pull -q ../server -r 4
72 72 $ hg debugdeltachain x
73 73 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
74 74 0 1 1 -1 base 3 2 3 1.50000 3 0 0.00000
75 75
76 76 $ cd ..
77 77
78 78 Test "usegeneraldelta" config
79 79 (repo are general delta, but incoming bundle are not re-deltafied)
80 80
81 81 delta coming from the server base delta server are not recompressed.
82 82 (also include the aggressive version for comparison)
83 83
84 84 $ hg clone repo --pull --config format.usegeneraldelta=1 usegd
85 85 requesting all changes
86 86 adding changesets
87 87 adding manifests
88 88 adding file changes
89 89 added 4 changesets with 6 changes to 3 files (+2 heads)
90 90 new changesets 0ea3fcf9d01d:bba78d330d9c
91 91 updating to branch default
92 92 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 93 $ hg clone repo --pull --config format.generaldelta=1 full
94 94 requesting all changes
95 95 adding changesets
96 96 adding manifests
97 97 adding file changes
98 98 added 4 changesets with 6 changes to 3 files (+2 heads)
99 99 new changesets 0ea3fcf9d01d:bba78d330d9c
100 100 updating to branch default
101 101 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 102 $ hg -R repo debugdeltachain -m
103 103 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
104 104 0 1 1 -1 base 104 135 104 0.77037 104 0 0.00000
105 105 1 1 2 0 prev 57 135 161 1.19259 161 0 0.00000
106 106 2 1 3 1 prev 57 135 218 1.61481 218 0 0.00000
107 107 3 2 1 -1 base 104 135 104 0.77037 104 0 0.00000
108 108 $ hg -R usegd debugdeltachain -m
109 109 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
110 110 0 1 1 -1 base 104 135 104 0.77037 104 0 0.00000
111 111 1 1 2 0 p1 57 135 161 1.19259 161 0 0.00000
112 112 2 1 3 1 prev 57 135 218 1.61481 218 0 0.00000
113 113 3 1 2 0 p1 57 135 161 1.19259 275 114 0.70807
114 114 $ hg -R full debugdeltachain -m
115 115 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
116 116 0 1 1 -1 base 104 135 104 0.77037 104 0 0.00000
117 117 1 1 2 0 p1 57 135 161 1.19259 161 0 0.00000
118 118 2 1 2 0 p1 57 135 161 1.19259 218 57 0.35404
119 119 3 1 2 0 p1 57 135 161 1.19259 275 114 0.70807
120 120
121 121 Test revlog.optimize-delta-parent-choice
122 122
123 123 $ hg init --config format.generaldelta=1 aggressive
124 124 $ cd aggressive
125 125 $ cat << EOF >> .hg/hgrc
126 126 > [format]
127 127 > generaldelta = 1
128 128 > EOF
129 129 $ touch a b c d e
130 130 $ hg commit -Aqm side1
131 131 $ hg up -q null
132 132 $ touch x y
133 133 $ hg commit -Aqm side2
134 134
135 135 - Verify non-aggressive merge uses p1 (commit 1) as delta parent
136 136 $ hg merge -q 0
137 137 $ hg commit -q -m merge
138 138 $ hg debugdeltachain -m
139 139 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
140 140 0 1 1 -1 base 59 215 59 0.27442 59 0 0.00000
141 141 1 1 2 0 prev 61 86 120 1.39535 120 0 0.00000
142 142 2 1 2 0 p2 62 301 121 0.40199 182 61 0.50413
143 143
144 144 $ hg strip -q -r . --config extensions.strip=
145 145
146 146 - Verify aggressive merge uses p2 (commit 0) as delta parent
147 147 $ hg up -q -C 1
148 148 $ hg merge -q 0
149 149 $ hg commit -q -m merge --config storage.revlog.optimize-delta-parent-choice=yes
150 150 $ hg debugdeltachain -m
151 151 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
152 152 0 1 1 -1 base 59 215 59 0.27442 59 0 0.00000
153 153 1 1 2 0 prev 61 86 120 1.39535 120 0 0.00000
154 154 2 1 2 0 p2 62 301 121 0.40199 182 61 0.50413
155 155
156 156 Test that strip bundle use bundle2
157 157 $ hg --config extensions.strip= strip .
158 158 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
159 159 saved backup bundle to $TESTTMP/aggressive/.hg/strip-backup/1c5d4dc9a8b8-6c68e60c-backup.hg
160 160 $ hg debugbundle .hg/strip-backup/*
161 161 Stream params: {Compression: BZ}
162 162 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
163 163 1c5d4dc9a8b8d6e1750966d343e94db665e7a1e9
164 164 cache:rev-branch-cache -- {} (mandatory: False)
165 165 phase-heads -- {} (mandatory: True)
166 166 1c5d4dc9a8b8d6e1750966d343e94db665e7a1e9 draft
167 167
168 168 $ cd ..
169 169
170 170 test maxdeltachainspan
171 171
172 172 $ hg init source-repo
173 173 $ cd source-repo
174 174 $ hg debugbuilddag --new-file '.+5:brancha$.+11:branchb$.+30:branchc<brancha+2<branchb+2'
175 175 # add an empty revision somewhere
176 176 $ hg up tip
177 177 14 files updated, 0 files merged, 0 files removed, 0 files unresolved
178 178 $ hg rm .
179 179 removing nf10
180 180 removing nf11
181 181 removing nf12
182 182 removing nf13
183 183 removing nf14
184 184 removing nf15
185 185 removing nf16
186 186 removing nf17
187 187 removing nf51
188 188 removing nf52
189 189 removing nf6
190 190 removing nf7
191 191 removing nf8
192 192 removing nf9
193 193 $ hg commit -m 'empty all'
194 194 $ hg revert --all --rev 'p1(.)'
195 195 adding nf10
196 196 adding nf11
197 197 adding nf12
198 198 adding nf13
199 199 adding nf14
200 200 adding nf15
201 201 adding nf16
202 202 adding nf17
203 203 adding nf51
204 204 adding nf52
205 205 adding nf6
206 206 adding nf7
207 207 adding nf8
208 208 adding nf9
209 209 $ hg commit -m 'restore all'
210 210 $ hg up null
211 211 0 files updated, 0 files merged, 14 files removed, 0 files unresolved
212 212 $
213 213 $ cd ..
214 214 $ hg -R source-repo debugdeltachain -m
215 215 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
216 216 0 1 1 -1 base 46 45 46 1.02222 46 0 0.00000
217 217 1 1 2 0 p1 57 90 103 1.14444 103 0 0.00000
218 218 2 1 3 1 p1 57 135 160 1.18519 160 0 0.00000
219 219 3 1 4 2 p1 57 180 217 1.20556 217 0 0.00000
220 220 4 1 5 3 p1 57 225 274 1.21778 274 0 0.00000
221 221 5 1 6 4 p1 57 270 331 1.22593 331 0 0.00000
222 222 6 2 1 -1 base 46 45 46 1.02222 46 0 0.00000
223 223 7 2 2 6 p1 57 90 103 1.14444 103 0 0.00000
224 224 8 2 3 7 p1 57 135 160 1.18519 160 0 0.00000
225 225 9 2 4 8 p1 57 180 217 1.20556 217 0 0.00000
226 226 10 2 5 9 p1 58 226 275 1.21681 275 0 0.00000
227 227 11 2 6 10 p1 58 272 333 1.22426 333 0 0.00000
228 228 12 2 7 11 p1 58 318 391 1.22956 391 0 0.00000
229 229 13 2 8 12 p1 58 364 449 1.23352 449 0 0.00000
230 230 14 2 9 13 p1 58 410 507 1.23659 507 0 0.00000
231 231 15 2 10 14 p1 58 456 565 1.23904 565 0 0.00000
232 232 16 2 11 15 p1 58 502 623 1.24104 623 0 0.00000
233 233 17 2 12 16 p1 58 548 681 1.24270 681 0 0.00000
234 234 18 3 1 -1 base 47 46 47 1.02174 47 0 0.00000
235 235 19 3 2 18 p1 58 92 105 1.14130 105 0 0.00000
236 236 20 3 3 19 p1 58 138 163 1.18116 163 0 0.00000
237 237 21 3 4 20 p1 58 184 221 1.20109 221 0 0.00000
238 238 22 3 5 21 p1 58 230 279 1.21304 279 0 0.00000
239 239 23 3 6 22 p1 58 276 337 1.22101 337 0 0.00000
240 240 24 3 7 23 p1 58 322 395 1.22671 395 0 0.00000
241 241 25 3 8 24 p1 58 368 453 1.23098 453 0 0.00000
242 242 26 3 9 25 p1 58 414 511 1.23430 511 0 0.00000
243 243 27 3 10 26 p1 58 460 569 1.23696 569 0 0.00000
244 244 28 3 11 27 p1 58 506 627 1.23913 627 0 0.00000
245 245 29 3 12 28 p1 58 552 685 1.24094 685 0 0.00000
246 246 30 3 13 29 p1 58 598 743 1.24247 743 0 0.00000
247 247 31 3 14 30 p1 58 644 801 1.24379 801 0 0.00000
248 248 32 3 15 31 p1 58 690 859 1.24493 859 0 0.00000
249 249 33 3 16 32 p1 58 736 917 1.24592 917 0 0.00000
250 250 34 3 17 33 p1 58 782 975 1.24680 975 0 0.00000
251 251 35 3 18 34 p1 58 828 1033 1.24758 1033 0 0.00000
252 252 36 3 19 35 p1 58 874 1091 1.24828 1091 0 0.00000
253 253 37 3 20 36 p1 58 920 1149 1.24891 1149 0 0.00000
254 254 38 3 21 37 p1 58 966 1207 1.24948 1207 0 0.00000
255 255 39 3 22 38 p1 58 1012 1265 1.25000 1265 0 0.00000
256 256 40 3 23 39 p1 58 1058 1323 1.25047 1323 0 0.00000
257 257 41 3 24 40 p1 58 1104 1381 1.25091 1381 0 0.00000
258 258 42 3 25 41 p1 58 1150 1439 1.25130 1439 0 0.00000
259 259 43 3 26 42 p1 58 1196 1497 1.25167 1497 0 0.00000
260 260 44 3 27 43 p1 58 1242 1555 1.25201 1555 0 0.00000
261 261 45 3 28 44 p1 58 1288 1613 1.25233 1613 0 0.00000
262 262 46 3 29 45 p1 58 1334 1671 1.25262 1671 0 0.00000
263 263 47 3 30 46 p1 58 1380 1729 1.25290 1729 0 0.00000
264 264 48 3 31 47 p1 58 1426 1787 1.25316 1787 0 0.00000
265 265 49 4 1 -1 base 197 316 197 0.62342 197 0 0.00000
266 266 50 4 2 49 p1 58 362 255 0.70442 255 0 0.00000
267 267 51 4 3 50 prev 356 594 611 1.02862 611 0 0.00000
268 268 52 4 4 51 p1 58 640 669 1.04531 669 0 0.00000
269 269 53 5 1 -1 base 0 0 0 0.00000 0 0 0.00000
270 270 54 6 1 -1 base 369 640 369 0.57656 369 0 0.00000
271 271 $ hg clone --pull source-repo --config experimental.maxdeltachainspan=2800 relax-chain --config format.generaldelta=yes
272 272 requesting all changes
273 273 adding changesets
274 274 adding manifests
275 275 adding file changes
276 276 added 55 changesets with 53 changes to 53 files (+2 heads)
277 277 new changesets 61246295ee1e:c930ac4a5b32
278 278 updating to branch default
279 279 14 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 280 $ hg -R relax-chain debugdeltachain -m
281 281 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
282 0 1 1 -1 base 46 45 46 1.02222 46 0 0.00000
283 1 1 2 0 p1 57 90 103 1.14444 103 0 0.00000
284 2 1 3 1 p1 57 135 160 1.18519 160 0 0.00000
285 3 1 4 2 p1 57 180 217 1.20556 217 0 0.00000
286 4 1 5 3 p1 57 225 274 1.21778 274 0 0.00000
287 5 1 6 4 p1 57 270 331 1.22593 331 0 0.00000
288 6 2 1 -1 base 46 45 46 1.02222 46 0 0.00000
289 7 2 2 6 p1 57 90 103 1.14444 103 0 0.00000
290 8 2 3 7 p1 57 135 160 1.18519 160 0 0.00000
291 9 2 4 8 p1 57 180 217 1.20556 217 0 0.00000
292 10 2 5 9 p1 58 226 275 1.21681 275 0 0.00000
293 11 2 6 10 p1 58 272 333 1.22426 333 0 0.00000
294 12 2 7 11 p1 58 318 391 1.22956 391 0 0.00000
295 13 2 8 12 p1 58 364 449 1.23352 449 0 0.00000
296 14 2 9 13 p1 58 410 507 1.23659 507 0 0.00000
297 15 2 10 14 p1 58 456 565 1.23904 565 0 0.00000
298 16 2 11 15 p1 58 502 623 1.24104 623 0 0.00000
299 17 2 12 16 p1 58 548 681 1.24270 681 0 0.00000
300 18 3 1 -1 base 47 46 47 1.02174 47 0 0.00000
301 19 3 2 18 p1 58 92 105 1.14130 105 0 0.00000
302 20 3 3 19 p1 58 138 163 1.18116 163 0 0.00000
303 21 3 4 20 p1 58 184 221 1.20109 221 0 0.00000
304 22 3 5 21 p1 58 230 279 1.21304 279 0 0.00000
305 23 3 6 22 p1 58 276 337 1.22101 337 0 0.00000
306 24 3 7 23 p1 58 322 395 1.22671 395 0 0.00000
307 25 3 8 24 p1 58 368 453 1.23098 453 0 0.00000
308 26 3 9 25 p1 58 414 511 1.23430 511 0 0.00000
309 27 3 10 26 p1 58 460 569 1.23696 569 0 0.00000
310 28 3 11 27 p1 58 506 627 1.23913 627 0 0.00000
311 29 3 12 28 p1 58 552 685 1.24094 685 0 0.00000
312 30 3 13 29 p1 58 598 743 1.24247 743 0 0.00000
313 31 3 14 30 p1 58 644 801 1.24379 801 0 0.00000
314 32 3 15 31 p1 58 690 859 1.24493 859 0 0.00000
315 33 3 16 32 p1 58 736 917 1.24592 917 0 0.00000
316 34 3 17 33 p1 58 782 975 1.24680 975 0 0.00000
317 35 3 18 34 p1 58 828 1033 1.24758 1033 0 0.00000
318 36 3 19 35 p1 58 874 1091 1.24828 1091 0 0.00000
319 37 3 20 36 p1 58 920 1149 1.24891 1149 0 0.00000
320 38 3 21 37 p1 58 966 1207 1.24948 1207 0 0.00000
321 39 3 22 38 p1 58 1012 1265 1.25000 1265 0 0.00000
322 40 3 23 39 p1 58 1058 1323 1.25047 1323 0 0.00000
323 41 3 24 40 p1 58 1104 1381 1.25091 1381 0 0.00000
324 42 3 25 41 p1 58 1150 1439 1.25130 1439 0 0.00000
325 43 3 26 42 p1 58 1196 1497 1.25167 1497 0 0.00000
326 44 3 27 43 p1 58 1242 1555 1.25201 1555 0 0.00000
327 45 3 28 44 p1 58 1288 1613 1.25233 1613 0 0.00000
328 46 3 29 45 p1 58 1334 1671 1.25262 1671 0 0.00000
329 47 3 30 46 p1 58 1380 1729 1.25290 1729 0 0.00000
330 48 3 31 47 p1 58 1426 1787 1.25316 1787 0 0.00000
331 49 4 1 -1 base 197 316 197 0.62342 197 0 0.00000
332 50 4 2 49 p1 58 362 255 0.70442 255 0 0.00000
333 51 2 13 17 p1 58 594 739 1.24411 2781 2042 2.76319
334 52 5 1 -1 base 369 640 369 0.57656 369 0 0.00000
335 53 6 1 -1 base 0 0 0 0.00000 0 0 0.00000
336 54 7 1 -1 base 369 640 369 0.57656 369 0 0.00000
282 0 1 1 -1 base 47 46 47 1.02174 47 0 0.00000
283 1 1 2 0 p1 58 92 105 1.14130 105 0 0.00000
284 2 1 3 1 p1 58 138 163 1.18116 163 0 0.00000
285 3 1 4 2 p1 58 184 221 1.20109 221 0 0.00000
286 4 1 5 3 p1 58 230 279 1.21304 279 0 0.00000
287 5 1 6 4 p1 58 276 337 1.22101 337 0 0.00000
288 6 1 7 5 p1 58 322 395 1.22671 395 0 0.00000
289 7 1 8 6 p1 58 368 453 1.23098 453 0 0.00000
290 8 1 9 7 p1 58 414 511 1.23430 511 0 0.00000
291 9 1 10 8 p1 58 460 569 1.23696 569 0 0.00000
292 10 1 11 9 p1 58 506 627 1.23913 627 0 0.00000
293 11 1 12 10 p1 58 552 685 1.24094 685 0 0.00000
294 12 1 13 11 p1 58 598 743 1.24247 743 0 0.00000
295 13 1 14 12 p1 58 644 801 1.24379 801 0 0.00000
296 14 1 15 13 p1 58 690 859 1.24493 859 0 0.00000
297 15 1 16 14 p1 58 736 917 1.24592 917 0 0.00000
298 16 1 17 15 p1 58 782 975 1.24680 975 0 0.00000
299 17 1 18 16 p1 58 828 1033 1.24758 1033 0 0.00000
300 18 1 19 17 p1 58 874 1091 1.24828 1091 0 0.00000
301 19 1 20 18 p1 58 920 1149 1.24891 1149 0 0.00000
302 20 1 21 19 p1 58 966 1207 1.24948 1207 0 0.00000
303 21 1 22 20 p1 58 1012 1265 1.25000 1265 0 0.00000
304 22 1 23 21 p1 58 1058 1323 1.25047 1323 0 0.00000
305 23 1 24 22 p1 58 1104 1381 1.25091 1381 0 0.00000
306 24 1 25 23 p1 58 1150 1439 1.25130 1439 0 0.00000
307 25 1 26 24 p1 58 1196 1497 1.25167 1497 0 0.00000
308 26 1 27 25 p1 58 1242 1555 1.25201 1555 0 0.00000
309 27 1 28 26 p1 58 1288 1613 1.25233 1613 0 0.00000
310 28 1 29 27 p1 58 1334 1671 1.25262 1671 0 0.00000
311 29 1 30 28 p1 58 1380 1729 1.25290 1729 0 0.00000
312 30 1 31 29 p1 58 1426 1787 1.25316 1787 0 0.00000
313 31 2 1 -1 base 46 45 46 1.02222 46 0 0.00000
314 32 2 2 31 p1 57 90 103 1.14444 103 0 0.00000
315 33 2 3 32 p1 57 135 160 1.18519 160 0 0.00000
316 34 2 4 33 p1 57 180 217 1.20556 217 0 0.00000
317 35 2 5 34 p1 57 225 274 1.21778 274 0 0.00000
318 36 2 6 35 p1 57 270 331 1.22593 331 0 0.00000
319 37 2 7 36 p1 58 316 389 1.23101 389 0 0.00000
320 38 2 8 37 p1 58 362 447 1.23481 447 0 0.00000
321 39 3 1 -1 base 46 45 46 1.02222 46 0 0.00000
322 40 3 2 39 p1 57 90 103 1.14444 103 0 0.00000
323 41 3 3 40 p1 57 135 160 1.18519 160 0 0.00000
324 42 3 4 41 p1 57 180 217 1.20556 217 0 0.00000
325 43 3 5 42 p1 58 226 275 1.21681 275 0 0.00000
326 44 3 6 43 p1 58 272 333 1.22426 333 0 0.00000
327 45 3 7 44 p1 58 318 391 1.22956 391 0 0.00000
328 46 3 8 45 p1 58 364 449 1.23352 449 0 0.00000
329 47 3 9 46 p1 58 410 507 1.23659 507 0 0.00000
330 48 3 10 47 p1 58 456 565 1.23904 565 0 0.00000
331 49 3 11 48 p1 58 502 623 1.24104 623 0 0.00000
332 50 3 12 49 p1 58 548 681 1.24270 681 0 0.00000
333 51 3 13 50 p1 58 594 739 1.24411 739 0 0.00000
334 52 3 14 51 p1 58 640 797 1.24531 797 0 0.00000
335 53 4 1 -1 base 0 0 0 0.00000 0 0 0.00000
336 54 5 1 -1 base 369 640 369 0.57656 369 0 0.00000
337 337 $ hg clone --pull source-repo --config experimental.maxdeltachainspan=0 noconst-chain --config format.generaldelta=yes
338 338 requesting all changes
339 339 adding changesets
340 340 adding manifests
341 341 adding file changes
342 342 added 55 changesets with 53 changes to 53 files (+2 heads)
343 343 new changesets 61246295ee1e:c930ac4a5b32
344 344 updating to branch default
345 345 14 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 346 $ hg -R noconst-chain debugdeltachain -m
347 347 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio
348 0 1 1 -1 base 46 45 46 1.02222 46 0 0.00000
349 1 1 2 0 p1 57 90 103 1.14444 103 0 0.00000
350 2 1 3 1 p1 57 135 160 1.18519 160 0 0.00000
351 3 1 4 2 p1 57 180 217 1.20556 217 0 0.00000
352 4 1 5 3 p1 57 225 274 1.21778 274 0 0.00000
353 5 1 6 4 p1 57 270 331 1.22593 331 0 0.00000
354 6 2 1 -1 base 46 45 46 1.02222 46 0 0.00000
355 7 2 2 6 p1 57 90 103 1.14444 103 0 0.00000
356 8 2 3 7 p1 57 135 160 1.18519 160 0 0.00000
357 9 2 4 8 p1 57 180 217 1.20556 217 0 0.00000
358 10 2 5 9 p1 58 226 275 1.21681 275 0 0.00000
359 11 2 6 10 p1 58 272 333 1.22426 333 0 0.00000
360 12 2 7 11 p1 58 318 391 1.22956 391 0 0.00000
361 13 2 8 12 p1 58 364 449 1.23352 449 0 0.00000
362 14 2 9 13 p1 58 410 507 1.23659 507 0 0.00000
363 15 2 10 14 p1 58 456 565 1.23904 565 0 0.00000
364 16 2 11 15 p1 58 502 623 1.24104 623 0 0.00000
365 17 2 12 16 p1 58 548 681 1.24270 681 0 0.00000
366 18 3 1 -1 base 47 46 47 1.02174 47 0 0.00000
367 19 3 2 18 p1 58 92 105 1.14130 105 0 0.00000
368 20 3 3 19 p1 58 138 163 1.18116 163 0 0.00000
369 21 3 4 20 p1 58 184 221 1.20109 221 0 0.00000
370 22 3 5 21 p1 58 230 279 1.21304 279 0 0.00000
371 23 3 6 22 p1 58 276 337 1.22101 337 0 0.00000
372 24 3 7 23 p1 58 322 395 1.22671 395 0 0.00000
373 25 3 8 24 p1 58 368 453 1.23098 453 0 0.00000
374 26 3 9 25 p1 58 414 511 1.23430 511 0 0.00000
375 27 3 10 26 p1 58 460 569 1.23696 569 0 0.00000
376 28 3 11 27 p1 58 506 627 1.23913 627 0 0.00000
377 29 3 12 28 p1 58 552 685 1.24094 685 0 0.00000
378 30 3 13 29 p1 58 598 743 1.24247 743 0 0.00000
379 31 3 14 30 p1 58 644 801 1.24379 801 0 0.00000
380 32 3 15 31 p1 58 690 859 1.24493 859 0 0.00000
381 33 3 16 32 p1 58 736 917 1.24592 917 0 0.00000
382 34 3 17 33 p1 58 782 975 1.24680 975 0 0.00000
383 35 3 18 34 p1 58 828 1033 1.24758 1033 0 0.00000
384 36 3 19 35 p1 58 874 1091 1.24828 1091 0 0.00000
385 37 3 20 36 p1 58 920 1149 1.24891 1149 0 0.00000
386 38 3 21 37 p1 58 966 1207 1.24948 1207 0 0.00000
387 39 3 22 38 p1 58 1012 1265 1.25000 1265 0 0.00000
388 40 3 23 39 p1 58 1058 1323 1.25047 1323 0 0.00000
389 41 3 24 40 p1 58 1104 1381 1.25091 1381 0 0.00000
390 42 3 25 41 p1 58 1150 1439 1.25130 1439 0 0.00000
391 43 3 26 42 p1 58 1196 1497 1.25167 1497 0 0.00000
392 44 3 27 43 p1 58 1242 1555 1.25201 1555 0 0.00000
393 45 3 28 44 p1 58 1288 1613 1.25233 1613 0 0.00000
394 46 3 29 45 p1 58 1334 1671 1.25262 1671 0 0.00000
395 47 3 30 46 p1 58 1380 1729 1.25290 1729 0 0.00000
396 48 3 31 47 p1 58 1426 1787 1.25316 1787 0 0.00000
397 49 1 7 5 p1 58 316 389 1.23101 2857 2468 6.34447
398 50 1 8 49 p1 58 362 447 1.23481 2915 2468 5.52125
399 51 2 13 17 p1 58 594 739 1.24411 2642 1903 2.57510
400 52 2 14 51 p1 58 640 797 1.24531 2700 1903 2.38770
348 0 1 1 -1 base 47 46 47 1.02174 47 0 0.00000
349 1 1 2 0 p1 58 92 105 1.14130 105 0 0.00000
350 2 1 3 1 p1 58 138 163 1.18116 163 0 0.00000
351 3 1 4 2 p1 58 184 221 1.20109 221 0 0.00000
352 4 1 5 3 p1 58 230 279 1.21304 279 0 0.00000
353 5 1 6 4 p1 58 276 337 1.22101 337 0 0.00000
354 6 1 7 5 p1 58 322 395 1.22671 395 0 0.00000
355 7 1 8 6 p1 58 368 453 1.23098 453 0 0.00000
356 8 1 9 7 p1 58 414 511 1.23430 511 0 0.00000
357 9 1 10 8 p1 58 460 569 1.23696 569 0 0.00000
358 10 1 11 9 p1 58 506 627 1.23913 627 0 0.00000
359 11 1 12 10 p1 58 552 685 1.24094 685 0 0.00000
360 12 1 13 11 p1 58 598 743 1.24247 743 0 0.00000
361 13 1 14 12 p1 58 644 801 1.24379 801 0 0.00000
362 14 1 15 13 p1 58 690 859 1.24493 859 0 0.00000
363 15 1 16 14 p1 58 736 917 1.24592 917 0 0.00000
364 16 1 17 15 p1 58 782 975 1.24680 975 0 0.00000
365 17 1 18 16 p1 58 828 1033 1.24758 1033 0 0.00000
366 18 1 19 17 p1 58 874 1091 1.24828 1091 0 0.00000
367 19 1 20 18 p1 58 920 1149 1.24891 1149 0 0.00000
368 20 1 21 19 p1 58 966 1207 1.24948 1207 0 0.00000
369 21 1 22 20 p1 58 1012 1265 1.25000 1265 0 0.00000
370 22 1 23 21 p1 58 1058 1323 1.25047 1323 0 0.00000
371 23 1 24 22 p1 58 1104 1381 1.25091 1381 0 0.00000
372 24 1 25 23 p1 58 1150 1439 1.25130 1439 0 0.00000
373 25 1 26 24 p1 58 1196 1497 1.25167 1497 0 0.00000
374 26 1 27 25 p1 58 1242 1555 1.25201 1555 0 0.00000
375 27 1 28 26 p1 58 1288 1613 1.25233 1613 0 0.00000
376 28 1 29 27 p1 58 1334 1671 1.25262 1671 0 0.00000
377 29 1 30 28 p1 58 1380 1729 1.25290 1729 0 0.00000
378 30 1 31 29 p1 58 1426 1787 1.25316 1787 0 0.00000
379 31 2 1 -1 base 46 45 46 1.02222 46 0 0.00000
380 32 2 2 31 p1 57 90 103 1.14444 103 0 0.00000
381 33 2 3 32 p1 57 135 160 1.18519 160 0 0.00000
382 34 2 4 33 p1 57 180 217 1.20556 217 0 0.00000
383 35 2 5 34 p1 57 225 274 1.21778 274 0 0.00000
384 36 2 6 35 p1 57 270 331 1.22593 331 0 0.00000
385 37 2 7 36 p1 58 316 389 1.23101 389 0 0.00000
386 38 2 8 37 p1 58 362 447 1.23481 447 0 0.00000
387 39 3 1 -1 base 46 45 46 1.02222 46 0 0.00000
388 40 3 2 39 p1 57 90 103 1.14444 103 0 0.00000
389 41 3 3 40 p1 57 135 160 1.18519 160 0 0.00000
390 42 3 4 41 p1 57 180 217 1.20556 217 0 0.00000
391 43 3 5 42 p1 58 226 275 1.21681 275 0 0.00000
392 44 3 6 43 p1 58 272 333 1.22426 333 0 0.00000
393 45 3 7 44 p1 58 318 391 1.22956 391 0 0.00000
394 46 3 8 45 p1 58 364 449 1.23352 449 0 0.00000
395 47 3 9 46 p1 58 410 507 1.23659 507 0 0.00000
396 48 3 10 47 p1 58 456 565 1.23904 565 0 0.00000
397 49 3 11 48 p1 58 502 623 1.24104 623 0 0.00000
398 50 3 12 49 p1 58 548 681 1.24270 681 0 0.00000
399 51 3 13 50 p1 58 594 739 1.24411 739 0 0.00000
400 52 3 14 51 p1 58 640 797 1.24531 797 0 0.00000
401 401 53 4 1 -1 base 0 0 0 0.00000 0 0 0.00000
402 402 54 5 1 -1 base 369 640 369 0.57656 369 0 0.00000
General Comments 0
You need to be logged in to leave comments. Login now