##// END OF EJS Templates
dirstate: add a synchronisation point before doing a full dirstate read...
marmoute -
r51508:fc8e37c3 stable
parent child Browse files
Show More
@@ -1,2902 +1,2912 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
9 9 import functools
10 10 import re
11 11
12 12 from . import (
13 13 encoding,
14 14 error,
15 15 )
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 = b"extension '%s' overwrite config item '%s.%s'"
26 26 msg %= (extname, section, key)
27 27 ui.develwarn(msg, config=b'warn-config')
28 28
29 29 knownitems.update(items)
30 30
31 31
32 32 class configitem:
33 33 """represent a known config item
34 34
35 35 :section: the official config section where to find this item,
36 36 :name: the official name within the section,
37 37 :default: default value for this item,
38 38 :alias: optional list of tuples as alternatives,
39 39 :generic: this is a generic definition, match name using regular expression.
40 40 """
41 41
42 42 def __init__(
43 43 self,
44 44 section,
45 45 name,
46 46 default=None,
47 47 alias=(),
48 48 generic=False,
49 49 priority=0,
50 50 experimental=False,
51 51 ):
52 52 self.section = section
53 53 self.name = name
54 54 self.default = default
55 55 self.alias = list(alias)
56 56 self.generic = generic
57 57 self.priority = priority
58 58 self.experimental = experimental
59 59 self._re = None
60 60 if generic:
61 61 self._re = re.compile(self.name)
62 62
63 63
64 64 class itemregister(dict):
65 65 """A specialized dictionary that can handle wild-card selection"""
66 66
67 67 def __init__(self):
68 68 super(itemregister, self).__init__()
69 69 self._generics = set()
70 70
71 71 def update(self, other):
72 72 super(itemregister, self).update(other)
73 73 self._generics.update(other._generics)
74 74
75 75 def __setitem__(self, key, item):
76 76 super(itemregister, self).__setitem__(key, item)
77 77 if item.generic:
78 78 self._generics.add(item)
79 79
80 80 def get(self, key):
81 81 baseitem = super(itemregister, self).get(key)
82 82 if baseitem is not None and not baseitem.generic:
83 83 return baseitem
84 84
85 85 # search for a matching generic item
86 86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 87 for item in generics:
88 88 # we use 'match' instead of 'search' to make the matching simpler
89 89 # for people unfamiliar with regular expression. Having the match
90 90 # rooted to the start of the string will produce less surprising
91 91 # result for user writing simple regex for sub-attribute.
92 92 #
93 93 # For example using "color\..*" match produces an unsurprising
94 94 # result, while using search could suddenly match apparently
95 95 # unrelated configuration that happens to contains "color."
96 96 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 97 # some match to avoid the need to prefix most pattern with "^".
98 98 # The "^" seems more error prone.
99 99 if item._re.match(key):
100 100 return item
101 101
102 102 return None
103 103
104 104
105 105 coreitems = {}
106 106
107 107
108 108 def _register(configtable, *args, **kwargs):
109 109 item = configitem(*args, **kwargs)
110 110 section = configtable.setdefault(item.section, itemregister())
111 111 if item.name in section:
112 112 msg = b"duplicated config item registration for '%s.%s'"
113 113 raise error.ProgrammingError(msg % (item.section, item.name))
114 114 section[item.name] = item
115 115
116 116
117 117 # special value for case where the default is derived from other values
118 118 dynamicdefault = object()
119 119
120 120 # Registering actual config items
121 121
122 122
123 123 def getitemregister(configtable):
124 124 f = functools.partial(_register, configtable)
125 125 # export pseudo enum as configitem.*
126 126 f.dynamicdefault = dynamicdefault
127 127 return f
128 128
129 129
130 130 coreconfigitem = getitemregister(coreitems)
131 131
132 132
133 133 def _registerdiffopts(section, configprefix=b''):
134 134 coreconfigitem(
135 135 section,
136 136 configprefix + b'nodates',
137 137 default=False,
138 138 )
139 139 coreconfigitem(
140 140 section,
141 141 configprefix + b'showfunc',
142 142 default=False,
143 143 )
144 144 coreconfigitem(
145 145 section,
146 146 configprefix + b'unified',
147 147 default=None,
148 148 )
149 149 coreconfigitem(
150 150 section,
151 151 configprefix + b'git',
152 152 default=False,
153 153 )
154 154 coreconfigitem(
155 155 section,
156 156 configprefix + b'ignorews',
157 157 default=False,
158 158 )
159 159 coreconfigitem(
160 160 section,
161 161 configprefix + b'ignorewsamount',
162 162 default=False,
163 163 )
164 164 coreconfigitem(
165 165 section,
166 166 configprefix + b'ignoreblanklines',
167 167 default=False,
168 168 )
169 169 coreconfigitem(
170 170 section,
171 171 configprefix + b'ignorewseol',
172 172 default=False,
173 173 )
174 174 coreconfigitem(
175 175 section,
176 176 configprefix + b'nobinary',
177 177 default=False,
178 178 )
179 179 coreconfigitem(
180 180 section,
181 181 configprefix + b'noprefix',
182 182 default=False,
183 183 )
184 184 coreconfigitem(
185 185 section,
186 186 configprefix + b'word-diff',
187 187 default=False,
188 188 )
189 189
190 190
191 191 coreconfigitem(
192 192 b'alias',
193 193 b'.*',
194 194 default=dynamicdefault,
195 195 generic=True,
196 196 )
197 197 coreconfigitem(
198 198 b'auth',
199 199 b'cookiefile',
200 200 default=None,
201 201 )
202 202 _registerdiffopts(section=b'annotate')
203 203 # bookmarks.pushing: internal hack for discovery
204 204 coreconfigitem(
205 205 b'bookmarks',
206 206 b'pushing',
207 207 default=list,
208 208 )
209 209 # bundle.mainreporoot: internal hack for bundlerepo
210 210 coreconfigitem(
211 211 b'bundle',
212 212 b'mainreporoot',
213 213 default=b'',
214 214 )
215 215 coreconfigitem(
216 216 b'censor',
217 217 b'policy',
218 218 default=b'abort',
219 219 experimental=True,
220 220 )
221 221 coreconfigitem(
222 222 b'chgserver',
223 223 b'idletimeout',
224 224 default=3600,
225 225 )
226 226 coreconfigitem(
227 227 b'chgserver',
228 228 b'skiphash',
229 229 default=False,
230 230 )
231 231 coreconfigitem(
232 232 b'cmdserver',
233 233 b'log',
234 234 default=None,
235 235 )
236 236 coreconfigitem(
237 237 b'cmdserver',
238 238 b'max-log-files',
239 239 default=7,
240 240 )
241 241 coreconfigitem(
242 242 b'cmdserver',
243 243 b'max-log-size',
244 244 default=b'1 MB',
245 245 )
246 246 coreconfigitem(
247 247 b'cmdserver',
248 248 b'max-repo-cache',
249 249 default=0,
250 250 experimental=True,
251 251 )
252 252 coreconfigitem(
253 253 b'cmdserver',
254 254 b'message-encodings',
255 255 default=list,
256 256 )
257 257 coreconfigitem(
258 258 b'cmdserver',
259 259 b'track-log',
260 260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 261 )
262 262 coreconfigitem(
263 263 b'cmdserver',
264 264 b'shutdown-on-interrupt',
265 265 default=True,
266 266 )
267 267 coreconfigitem(
268 268 b'color',
269 269 b'.*',
270 270 default=None,
271 271 generic=True,
272 272 )
273 273 coreconfigitem(
274 274 b'color',
275 275 b'mode',
276 276 default=b'auto',
277 277 )
278 278 coreconfigitem(
279 279 b'color',
280 280 b'pagermode',
281 281 default=dynamicdefault,
282 282 )
283 283 coreconfigitem(
284 284 b'command-templates',
285 285 b'graphnode',
286 286 default=None,
287 287 alias=[(b'ui', b'graphnodetemplate')],
288 288 )
289 289 coreconfigitem(
290 290 b'command-templates',
291 291 b'log',
292 292 default=None,
293 293 alias=[(b'ui', b'logtemplate')],
294 294 )
295 295 coreconfigitem(
296 296 b'command-templates',
297 297 b'mergemarker',
298 298 default=(
299 299 b'{node|short} '
300 300 b'{ifeq(tags, "tip", "", '
301 301 b'ifeq(tags, "", "", "{tags} "))}'
302 302 b'{if(bookmarks, "{bookmarks} ")}'
303 303 b'{ifeq(branch, "default", "", "{branch} ")}'
304 304 b'- {author|user}: {desc|firstline}'
305 305 ),
306 306 alias=[(b'ui', b'mergemarkertemplate')],
307 307 )
308 308 coreconfigitem(
309 309 b'command-templates',
310 310 b'pre-merge-tool-output',
311 311 default=None,
312 312 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 313 )
314 314 coreconfigitem(
315 315 b'command-templates',
316 316 b'oneline-summary',
317 317 default=None,
318 318 )
319 319 coreconfigitem(
320 320 b'command-templates',
321 321 b'oneline-summary.*',
322 322 default=dynamicdefault,
323 323 generic=True,
324 324 )
325 325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 326 coreconfigitem(
327 327 b'commands',
328 328 b'commit.post-status',
329 329 default=False,
330 330 )
331 331 coreconfigitem(
332 332 b'commands',
333 333 b'grep.all-files',
334 334 default=False,
335 335 experimental=True,
336 336 )
337 337 coreconfigitem(
338 338 b'commands',
339 339 b'merge.require-rev',
340 340 default=False,
341 341 )
342 342 coreconfigitem(
343 343 b'commands',
344 344 b'push.require-revs',
345 345 default=False,
346 346 )
347 347 coreconfigitem(
348 348 b'commands',
349 349 b'resolve.confirm',
350 350 default=False,
351 351 )
352 352 coreconfigitem(
353 353 b'commands',
354 354 b'resolve.explicit-re-merge',
355 355 default=False,
356 356 )
357 357 coreconfigitem(
358 358 b'commands',
359 359 b'resolve.mark-check',
360 360 default=b'none',
361 361 )
362 362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 363 coreconfigitem(
364 364 b'commands',
365 365 b'show.aliasprefix',
366 366 default=list,
367 367 )
368 368 coreconfigitem(
369 369 b'commands',
370 370 b'status.relative',
371 371 default=False,
372 372 )
373 373 coreconfigitem(
374 374 b'commands',
375 375 b'status.skipstates',
376 376 default=[],
377 377 experimental=True,
378 378 )
379 379 coreconfigitem(
380 380 b'commands',
381 381 b'status.terse',
382 382 default=b'',
383 383 )
384 384 coreconfigitem(
385 385 b'commands',
386 386 b'status.verbose',
387 387 default=False,
388 388 )
389 389 coreconfigitem(
390 390 b'commands',
391 391 b'update.check',
392 392 default=None,
393 393 )
394 394 coreconfigitem(
395 395 b'commands',
396 396 b'update.requiredest',
397 397 default=False,
398 398 )
399 399 coreconfigitem(
400 400 b'committemplate',
401 401 b'.*',
402 402 default=None,
403 403 generic=True,
404 404 )
405 405 coreconfigitem(
406 406 b'convert',
407 407 b'bzr.saverev',
408 408 default=True,
409 409 )
410 410 coreconfigitem(
411 411 b'convert',
412 412 b'cvsps.cache',
413 413 default=True,
414 414 )
415 415 coreconfigitem(
416 416 b'convert',
417 417 b'cvsps.fuzz',
418 418 default=60,
419 419 )
420 420 coreconfigitem(
421 421 b'convert',
422 422 b'cvsps.logencoding',
423 423 default=None,
424 424 )
425 425 coreconfigitem(
426 426 b'convert',
427 427 b'cvsps.mergefrom',
428 428 default=None,
429 429 )
430 430 coreconfigitem(
431 431 b'convert',
432 432 b'cvsps.mergeto',
433 433 default=None,
434 434 )
435 435 coreconfigitem(
436 436 b'convert',
437 437 b'git.committeractions',
438 438 default=lambda: [b'messagedifferent'],
439 439 )
440 440 coreconfigitem(
441 441 b'convert',
442 442 b'git.extrakeys',
443 443 default=list,
444 444 )
445 445 coreconfigitem(
446 446 b'convert',
447 447 b'git.findcopiesharder',
448 448 default=False,
449 449 )
450 450 coreconfigitem(
451 451 b'convert',
452 452 b'git.remoteprefix',
453 453 default=b'remote',
454 454 )
455 455 coreconfigitem(
456 456 b'convert',
457 457 b'git.renamelimit',
458 458 default=400,
459 459 )
460 460 coreconfigitem(
461 461 b'convert',
462 462 b'git.saverev',
463 463 default=True,
464 464 )
465 465 coreconfigitem(
466 466 b'convert',
467 467 b'git.similarity',
468 468 default=50,
469 469 )
470 470 coreconfigitem(
471 471 b'convert',
472 472 b'git.skipsubmodules',
473 473 default=False,
474 474 )
475 475 coreconfigitem(
476 476 b'convert',
477 477 b'hg.clonebranches',
478 478 default=False,
479 479 )
480 480 coreconfigitem(
481 481 b'convert',
482 482 b'hg.ignoreerrors',
483 483 default=False,
484 484 )
485 485 coreconfigitem(
486 486 b'convert',
487 487 b'hg.preserve-hash',
488 488 default=False,
489 489 )
490 490 coreconfigitem(
491 491 b'convert',
492 492 b'hg.revs',
493 493 default=None,
494 494 )
495 495 coreconfigitem(
496 496 b'convert',
497 497 b'hg.saverev',
498 498 default=False,
499 499 )
500 500 coreconfigitem(
501 501 b'convert',
502 502 b'hg.sourcename',
503 503 default=None,
504 504 )
505 505 coreconfigitem(
506 506 b'convert',
507 507 b'hg.startrev',
508 508 default=None,
509 509 )
510 510 coreconfigitem(
511 511 b'convert',
512 512 b'hg.tagsbranch',
513 513 default=b'default',
514 514 )
515 515 coreconfigitem(
516 516 b'convert',
517 517 b'hg.usebranchnames',
518 518 default=True,
519 519 )
520 520 coreconfigitem(
521 521 b'convert',
522 522 b'ignoreancestorcheck',
523 523 default=False,
524 524 experimental=True,
525 525 )
526 526 coreconfigitem(
527 527 b'convert',
528 528 b'localtimezone',
529 529 default=False,
530 530 )
531 531 coreconfigitem(
532 532 b'convert',
533 533 b'p4.encoding',
534 534 default=dynamicdefault,
535 535 )
536 536 coreconfigitem(
537 537 b'convert',
538 538 b'p4.startrev',
539 539 default=0,
540 540 )
541 541 coreconfigitem(
542 542 b'convert',
543 543 b'skiptags',
544 544 default=False,
545 545 )
546 546 coreconfigitem(
547 547 b'convert',
548 548 b'svn.debugsvnlog',
549 549 default=True,
550 550 )
551 551 coreconfigitem(
552 552 b'convert',
553 553 b'svn.trunk',
554 554 default=None,
555 555 )
556 556 coreconfigitem(
557 557 b'convert',
558 558 b'svn.tags',
559 559 default=None,
560 560 )
561 561 coreconfigitem(
562 562 b'convert',
563 563 b'svn.branches',
564 564 default=None,
565 565 )
566 566 coreconfigitem(
567 567 b'convert',
568 568 b'svn.startrev',
569 569 default=0,
570 570 )
571 571 coreconfigitem(
572 572 b'convert',
573 573 b'svn.dangerous-set-commit-dates',
574 574 default=False,
575 575 )
576 576 coreconfigitem(
577 577 b'debug',
578 578 b'dirstate.delaywrite',
579 579 default=0,
580 580 )
581 581 coreconfigitem(
582 582 b'debug',
583 583 b'revlog.verifyposition.changelog',
584 584 default=b'',
585 585 )
586 586 coreconfigitem(
587 587 b'debug',
588 588 b'revlog.debug-delta',
589 589 default=False,
590 590 )
591 591 coreconfigitem(
592 592 b'defaults',
593 593 b'.*',
594 594 default=None,
595 595 generic=True,
596 596 )
597 597 coreconfigitem(
598 598 b'devel',
599 599 b'all-warnings',
600 600 default=False,
601 601 )
602 602 coreconfigitem(
603 603 b'devel',
604 604 b'bundle2.debug',
605 605 default=False,
606 606 )
607 607 coreconfigitem(
608 608 b'devel',
609 609 b'bundle.delta',
610 610 default=b'',
611 611 )
612 612 coreconfigitem(
613 613 b'devel',
614 614 b'cache-vfs',
615 615 default=None,
616 616 )
617 617 coreconfigitem(
618 618 b'devel',
619 619 b'check-locks',
620 620 default=False,
621 621 )
622 622 coreconfigitem(
623 623 b'devel',
624 624 b'check-relroot',
625 625 default=False,
626 626 )
627 627 # Track copy information for all file, not just "added" one (very slow)
628 628 coreconfigitem(
629 629 b'devel',
630 630 b'copy-tracing.trace-all-files',
631 631 default=False,
632 632 )
633 633 coreconfigitem(
634 634 b'devel',
635 635 b'default-date',
636 636 default=None,
637 637 )
638 638 coreconfigitem(
639 639 b'devel',
640 640 b'deprec-warn',
641 641 default=False,
642 642 )
643 643 # possible values:
644 644 # - auto (the default)
645 645 # - force-append
646 646 # - force-new
647 647 coreconfigitem(
648 648 b'devel',
649 649 b'dirstate.v2.data_update_mode',
650 650 default="auto",
651 651 )
652 652 coreconfigitem(
653 653 b'devel',
654 654 b'disableloaddefaultcerts',
655 655 default=False,
656 656 )
657 657 coreconfigitem(
658 658 b'devel',
659 659 b'warn-empty-changegroup',
660 660 default=False,
661 661 )
662 662 coreconfigitem(
663 663 b'devel',
664 664 b'legacy.exchange',
665 665 default=list,
666 666 )
667 667 # When True, revlogs use a special reference version of the nodemap, that is not
668 668 # performant but is "known" to behave properly.
669 669 coreconfigitem(
670 670 b'devel',
671 671 b'persistent-nodemap',
672 672 default=False,
673 673 )
674 674 coreconfigitem(
675 675 b'devel',
676 676 b'servercafile',
677 677 default=b'',
678 678 )
679 679 coreconfigitem(
680 680 b'devel',
681 681 b'serverexactprotocol',
682 682 default=b'',
683 683 )
684 684 coreconfigitem(
685 685 b'devel',
686 686 b'serverrequirecert',
687 687 default=False,
688 688 )
689 689 # Makes the status algorithm wait for the existence of this file
690 690 # (or until a timeout of `devel.sync.status.pre-dirstate-write-file-timeout`
691 691 # seconds) before taking the lock and writing the dirstate.
692 692 # Status signals that it's ready to wait by creating a file
693 693 # with the same name + `.waiting`.
694 694 # Useful when testing race conditions.
695 695 coreconfigitem(
696 696 b'devel',
697 697 b'sync.status.pre-dirstate-write-file',
698 698 default=None,
699 699 )
700 700 coreconfigitem(
701 701 b'devel',
702 702 b'sync.status.pre-dirstate-write-file-timeout',
703 703 default=2,
704 704 )
705 705 coreconfigitem(
706 706 b'devel',
707 b'sync.dirstate.pre-read-file',
708 default=None,
709 )
710 coreconfigitem(
711 b'devel',
712 b'sync.dirstate.pre-read-file-timeout',
713 default=2,
714 )
715 coreconfigitem(
716 b'devel',
707 717 b'strip-obsmarkers',
708 718 default=True,
709 719 )
710 720 coreconfigitem(
711 721 b'devel',
712 722 b'warn-config',
713 723 default=None,
714 724 )
715 725 coreconfigitem(
716 726 b'devel',
717 727 b'warn-config-default',
718 728 default=None,
719 729 )
720 730 coreconfigitem(
721 731 b'devel',
722 732 b'user.obsmarker',
723 733 default=None,
724 734 )
725 735 coreconfigitem(
726 736 b'devel',
727 737 b'warn-config-unknown',
728 738 default=None,
729 739 )
730 740 coreconfigitem(
731 741 b'devel',
732 742 b'debug.copies',
733 743 default=False,
734 744 )
735 745 coreconfigitem(
736 746 b'devel',
737 747 b'copy-tracing.multi-thread',
738 748 default=True,
739 749 )
740 750 coreconfigitem(
741 751 b'devel',
742 752 b'debug.extensions',
743 753 default=False,
744 754 )
745 755 coreconfigitem(
746 756 b'devel',
747 757 b'debug.repo-filters',
748 758 default=False,
749 759 )
750 760 coreconfigitem(
751 761 b'devel',
752 762 b'debug.peer-request',
753 763 default=False,
754 764 )
755 765 # If discovery.exchange-heads is False, the discovery will not start with
756 766 # remote head fetching and local head querying.
757 767 coreconfigitem(
758 768 b'devel',
759 769 b'discovery.exchange-heads',
760 770 default=True,
761 771 )
762 772 # If discovery.grow-sample is False, the sample size used in set discovery will
763 773 # not be increased through the process
764 774 coreconfigitem(
765 775 b'devel',
766 776 b'discovery.grow-sample',
767 777 default=True,
768 778 )
769 779 # When discovery.grow-sample.dynamic is True, the default, the sample size is
770 780 # adapted to the shape of the undecided set (it is set to the max of:
771 781 # <target-size>, len(roots(undecided)), len(heads(undecided)
772 782 coreconfigitem(
773 783 b'devel',
774 784 b'discovery.grow-sample.dynamic',
775 785 default=True,
776 786 )
777 787 # discovery.grow-sample.rate control the rate at which the sample grow
778 788 coreconfigitem(
779 789 b'devel',
780 790 b'discovery.grow-sample.rate',
781 791 default=1.05,
782 792 )
783 793 # If discovery.randomize is False, random sampling during discovery are
784 794 # deterministic. It is meant for integration tests.
785 795 coreconfigitem(
786 796 b'devel',
787 797 b'discovery.randomize',
788 798 default=True,
789 799 )
790 800 # Control the initial size of the discovery sample
791 801 coreconfigitem(
792 802 b'devel',
793 803 b'discovery.sample-size',
794 804 default=200,
795 805 )
796 806 # Control the initial size of the discovery for initial change
797 807 coreconfigitem(
798 808 b'devel',
799 809 b'discovery.sample-size.initial',
800 810 default=100,
801 811 )
802 812 _registerdiffopts(section=b'diff')
803 813 coreconfigitem(
804 814 b'diff',
805 815 b'merge',
806 816 default=False,
807 817 experimental=True,
808 818 )
809 819 coreconfigitem(
810 820 b'email',
811 821 b'bcc',
812 822 default=None,
813 823 )
814 824 coreconfigitem(
815 825 b'email',
816 826 b'cc',
817 827 default=None,
818 828 )
819 829 coreconfigitem(
820 830 b'email',
821 831 b'charsets',
822 832 default=list,
823 833 )
824 834 coreconfigitem(
825 835 b'email',
826 836 b'from',
827 837 default=None,
828 838 )
829 839 coreconfigitem(
830 840 b'email',
831 841 b'method',
832 842 default=b'smtp',
833 843 )
834 844 coreconfigitem(
835 845 b'email',
836 846 b'reply-to',
837 847 default=None,
838 848 )
839 849 coreconfigitem(
840 850 b'email',
841 851 b'to',
842 852 default=None,
843 853 )
844 854 coreconfigitem(
845 855 b'experimental',
846 856 b'archivemetatemplate',
847 857 default=dynamicdefault,
848 858 )
849 859 coreconfigitem(
850 860 b'experimental',
851 861 b'auto-publish',
852 862 default=b'publish',
853 863 )
854 864 coreconfigitem(
855 865 b'experimental',
856 866 b'bundle-phases',
857 867 default=False,
858 868 )
859 869 coreconfigitem(
860 870 b'experimental',
861 871 b'bundle2-advertise',
862 872 default=True,
863 873 )
864 874 coreconfigitem(
865 875 b'experimental',
866 876 b'bundle2-output-capture',
867 877 default=False,
868 878 )
869 879 coreconfigitem(
870 880 b'experimental',
871 881 b'bundle2.pushback',
872 882 default=False,
873 883 )
874 884 coreconfigitem(
875 885 b'experimental',
876 886 b'bundle2lazylocking',
877 887 default=False,
878 888 )
879 889 coreconfigitem(
880 890 b'experimental',
881 891 b'bundlecomplevel',
882 892 default=None,
883 893 )
884 894 coreconfigitem(
885 895 b'experimental',
886 896 b'bundlecomplevel.bzip2',
887 897 default=None,
888 898 )
889 899 coreconfigitem(
890 900 b'experimental',
891 901 b'bundlecomplevel.gzip',
892 902 default=None,
893 903 )
894 904 coreconfigitem(
895 905 b'experimental',
896 906 b'bundlecomplevel.none',
897 907 default=None,
898 908 )
899 909 coreconfigitem(
900 910 b'experimental',
901 911 b'bundlecomplevel.zstd',
902 912 default=None,
903 913 )
904 914 coreconfigitem(
905 915 b'experimental',
906 916 b'bundlecompthreads',
907 917 default=None,
908 918 )
909 919 coreconfigitem(
910 920 b'experimental',
911 921 b'bundlecompthreads.bzip2',
912 922 default=None,
913 923 )
914 924 coreconfigitem(
915 925 b'experimental',
916 926 b'bundlecompthreads.gzip',
917 927 default=None,
918 928 )
919 929 coreconfigitem(
920 930 b'experimental',
921 931 b'bundlecompthreads.none',
922 932 default=None,
923 933 )
924 934 coreconfigitem(
925 935 b'experimental',
926 936 b'bundlecompthreads.zstd',
927 937 default=None,
928 938 )
929 939 coreconfigitem(
930 940 b'experimental',
931 941 b'changegroup3',
932 942 default=False,
933 943 )
934 944 coreconfigitem(
935 945 b'experimental',
936 946 b'changegroup4',
937 947 default=False,
938 948 )
939 949 coreconfigitem(
940 950 b'experimental',
941 951 b'cleanup-as-archived',
942 952 default=False,
943 953 )
944 954 coreconfigitem(
945 955 b'experimental',
946 956 b'clientcompressionengines',
947 957 default=list,
948 958 )
949 959 coreconfigitem(
950 960 b'experimental',
951 961 b'copytrace',
952 962 default=b'on',
953 963 )
954 964 coreconfigitem(
955 965 b'experimental',
956 966 b'copytrace.movecandidateslimit',
957 967 default=100,
958 968 )
959 969 coreconfigitem(
960 970 b'experimental',
961 971 b'copytrace.sourcecommitlimit',
962 972 default=100,
963 973 )
964 974 coreconfigitem(
965 975 b'experimental',
966 976 b'copies.read-from',
967 977 default=b"filelog-only",
968 978 )
969 979 coreconfigitem(
970 980 b'experimental',
971 981 b'copies.write-to',
972 982 default=b'filelog-only',
973 983 )
974 984 coreconfigitem(
975 985 b'experimental',
976 986 b'crecordtest',
977 987 default=None,
978 988 )
979 989 coreconfigitem(
980 990 b'experimental',
981 991 b'directaccess',
982 992 default=False,
983 993 )
984 994 coreconfigitem(
985 995 b'experimental',
986 996 b'directaccess.revnums',
987 997 default=False,
988 998 )
989 999 coreconfigitem(
990 1000 b'experimental',
991 1001 b'editortmpinhg',
992 1002 default=False,
993 1003 )
994 1004 coreconfigitem(
995 1005 b'experimental',
996 1006 b'evolution',
997 1007 default=list,
998 1008 )
999 1009 coreconfigitem(
1000 1010 b'experimental',
1001 1011 b'evolution.allowdivergence',
1002 1012 default=False,
1003 1013 alias=[(b'experimental', b'allowdivergence')],
1004 1014 )
1005 1015 coreconfigitem(
1006 1016 b'experimental',
1007 1017 b'evolution.allowunstable',
1008 1018 default=None,
1009 1019 )
1010 1020 coreconfigitem(
1011 1021 b'experimental',
1012 1022 b'evolution.createmarkers',
1013 1023 default=None,
1014 1024 )
1015 1025 coreconfigitem(
1016 1026 b'experimental',
1017 1027 b'evolution.effect-flags',
1018 1028 default=True,
1019 1029 alias=[(b'experimental', b'effect-flags')],
1020 1030 )
1021 1031 coreconfigitem(
1022 1032 b'experimental',
1023 1033 b'evolution.exchange',
1024 1034 default=None,
1025 1035 )
1026 1036 coreconfigitem(
1027 1037 b'experimental',
1028 1038 b'evolution.bundle-obsmarker',
1029 1039 default=False,
1030 1040 )
1031 1041 coreconfigitem(
1032 1042 b'experimental',
1033 1043 b'evolution.bundle-obsmarker:mandatory',
1034 1044 default=True,
1035 1045 )
1036 1046 coreconfigitem(
1037 1047 b'experimental',
1038 1048 b'log.topo',
1039 1049 default=False,
1040 1050 )
1041 1051 coreconfigitem(
1042 1052 b'experimental',
1043 1053 b'evolution.report-instabilities',
1044 1054 default=True,
1045 1055 )
1046 1056 coreconfigitem(
1047 1057 b'experimental',
1048 1058 b'evolution.track-operation',
1049 1059 default=True,
1050 1060 )
1051 1061 # repo-level config to exclude a revset visibility
1052 1062 #
1053 1063 # The target use case is to use `share` to expose different subset of the same
1054 1064 # repository, especially server side. See also `server.view`.
1055 1065 coreconfigitem(
1056 1066 b'experimental',
1057 1067 b'extra-filter-revs',
1058 1068 default=None,
1059 1069 )
1060 1070 coreconfigitem(
1061 1071 b'experimental',
1062 1072 b'maxdeltachainspan',
1063 1073 default=-1,
1064 1074 )
1065 1075 # tracks files which were undeleted (merge might delete them but we explicitly
1066 1076 # kept/undeleted them) and creates new filenodes for them
1067 1077 coreconfigitem(
1068 1078 b'experimental',
1069 1079 b'merge-track-salvaged',
1070 1080 default=False,
1071 1081 )
1072 1082 coreconfigitem(
1073 1083 b'experimental',
1074 1084 b'mmapindexthreshold',
1075 1085 default=None,
1076 1086 )
1077 1087 coreconfigitem(
1078 1088 b'experimental',
1079 1089 b'narrow',
1080 1090 default=False,
1081 1091 )
1082 1092 coreconfigitem(
1083 1093 b'experimental',
1084 1094 b'nonnormalparanoidcheck',
1085 1095 default=False,
1086 1096 )
1087 1097 coreconfigitem(
1088 1098 b'experimental',
1089 1099 b'exportableenviron',
1090 1100 default=list,
1091 1101 )
1092 1102 coreconfigitem(
1093 1103 b'experimental',
1094 1104 b'extendedheader.index',
1095 1105 default=None,
1096 1106 )
1097 1107 coreconfigitem(
1098 1108 b'experimental',
1099 1109 b'extendedheader.similarity',
1100 1110 default=False,
1101 1111 )
1102 1112 coreconfigitem(
1103 1113 b'experimental',
1104 1114 b'graphshorten',
1105 1115 default=False,
1106 1116 )
1107 1117 coreconfigitem(
1108 1118 b'experimental',
1109 1119 b'graphstyle.parent',
1110 1120 default=dynamicdefault,
1111 1121 )
1112 1122 coreconfigitem(
1113 1123 b'experimental',
1114 1124 b'graphstyle.missing',
1115 1125 default=dynamicdefault,
1116 1126 )
1117 1127 coreconfigitem(
1118 1128 b'experimental',
1119 1129 b'graphstyle.grandparent',
1120 1130 default=dynamicdefault,
1121 1131 )
1122 1132 coreconfigitem(
1123 1133 b'experimental',
1124 1134 b'hook-track-tags',
1125 1135 default=False,
1126 1136 )
1127 1137 coreconfigitem(
1128 1138 b'experimental',
1129 1139 b'httppostargs',
1130 1140 default=False,
1131 1141 )
1132 1142 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1133 1143 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1134 1144
1135 1145 coreconfigitem(
1136 1146 b'experimental',
1137 1147 b'obsmarkers-exchange-debug',
1138 1148 default=False,
1139 1149 )
1140 1150 coreconfigitem(
1141 1151 b'experimental',
1142 1152 b'remotenames',
1143 1153 default=False,
1144 1154 )
1145 1155 coreconfigitem(
1146 1156 b'experimental',
1147 1157 b'removeemptydirs',
1148 1158 default=True,
1149 1159 )
1150 1160 coreconfigitem(
1151 1161 b'experimental',
1152 1162 b'revert.interactive.select-to-keep',
1153 1163 default=False,
1154 1164 )
1155 1165 coreconfigitem(
1156 1166 b'experimental',
1157 1167 b'revisions.prefixhexnode',
1158 1168 default=False,
1159 1169 )
1160 1170 # "out of experimental" todo list.
1161 1171 #
1162 1172 # * include management of a persistent nodemap in the main docket
1163 1173 # * enforce a "no-truncate" policy for mmap safety
1164 1174 # - for censoring operation
1165 1175 # - for stripping operation
1166 1176 # - for rollback operation
1167 1177 # * proper streaming (race free) of the docket file
1168 1178 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1169 1179 # * Exchange-wise, we will also need to do something more efficient than
1170 1180 # keeping references to the affected revlogs, especially memory-wise when
1171 1181 # rewriting sidedata.
1172 1182 # * introduce a proper solution to reduce the number of filelog related files.
1173 1183 # * use caching for reading sidedata (similar to what we do for data).
1174 1184 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1175 1185 # * Improvement to consider
1176 1186 # - avoid compression header in chunk using the default compression?
1177 1187 # - forbid "inline" compression mode entirely?
1178 1188 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1179 1189 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1180 1190 # - keep track of chain base or size (probably not that useful anymore)
1181 1191 coreconfigitem(
1182 1192 b'experimental',
1183 1193 b'revlogv2',
1184 1194 default=None,
1185 1195 )
1186 1196 coreconfigitem(
1187 1197 b'experimental',
1188 1198 b'revisions.disambiguatewithin',
1189 1199 default=None,
1190 1200 )
1191 1201 coreconfigitem(
1192 1202 b'experimental',
1193 1203 b'rust.index',
1194 1204 default=False,
1195 1205 )
1196 1206 coreconfigitem(
1197 1207 b'experimental',
1198 1208 b'server.filesdata.recommended-batch-size',
1199 1209 default=50000,
1200 1210 )
1201 1211 coreconfigitem(
1202 1212 b'experimental',
1203 1213 b'server.manifestdata.recommended-batch-size',
1204 1214 default=100000,
1205 1215 )
1206 1216 coreconfigitem(
1207 1217 b'experimental',
1208 1218 b'server.stream-narrow-clones',
1209 1219 default=False,
1210 1220 )
1211 1221 coreconfigitem(
1212 1222 b'experimental',
1213 1223 b'single-head-per-branch',
1214 1224 default=False,
1215 1225 )
1216 1226 coreconfigitem(
1217 1227 b'experimental',
1218 1228 b'single-head-per-branch:account-closed-heads',
1219 1229 default=False,
1220 1230 )
1221 1231 coreconfigitem(
1222 1232 b'experimental',
1223 1233 b'single-head-per-branch:public-changes-only',
1224 1234 default=False,
1225 1235 )
1226 1236 coreconfigitem(
1227 1237 b'experimental',
1228 1238 b'sparse-read',
1229 1239 default=False,
1230 1240 )
1231 1241 coreconfigitem(
1232 1242 b'experimental',
1233 1243 b'sparse-read.density-threshold',
1234 1244 default=0.50,
1235 1245 )
1236 1246 coreconfigitem(
1237 1247 b'experimental',
1238 1248 b'sparse-read.min-gap-size',
1239 1249 default=b'65K',
1240 1250 )
1241 1251 coreconfigitem(
1242 1252 b'experimental',
1243 1253 b'treemanifest',
1244 1254 default=False,
1245 1255 )
1246 1256 coreconfigitem(
1247 1257 b'experimental',
1248 1258 b'update.atomic-file',
1249 1259 default=False,
1250 1260 )
1251 1261 coreconfigitem(
1252 1262 b'experimental',
1253 1263 b'web.full-garbage-collection-rate',
1254 1264 default=1, # still forcing a full collection on each request
1255 1265 )
1256 1266 coreconfigitem(
1257 1267 b'experimental',
1258 1268 b'worker.wdir-get-thread-safe',
1259 1269 default=False,
1260 1270 )
1261 1271 coreconfigitem(
1262 1272 b'experimental',
1263 1273 b'worker.repository-upgrade',
1264 1274 default=False,
1265 1275 )
1266 1276 coreconfigitem(
1267 1277 b'experimental',
1268 1278 b'xdiff',
1269 1279 default=False,
1270 1280 )
1271 1281 coreconfigitem(
1272 1282 b'extensions',
1273 1283 b'[^:]*',
1274 1284 default=None,
1275 1285 generic=True,
1276 1286 )
1277 1287 coreconfigitem(
1278 1288 b'extensions',
1279 1289 b'[^:]*:required',
1280 1290 default=False,
1281 1291 generic=True,
1282 1292 )
1283 1293 coreconfigitem(
1284 1294 b'extdata',
1285 1295 b'.*',
1286 1296 default=None,
1287 1297 generic=True,
1288 1298 )
1289 1299 coreconfigitem(
1290 1300 b'format',
1291 1301 b'bookmarks-in-store',
1292 1302 default=False,
1293 1303 )
1294 1304 coreconfigitem(
1295 1305 b'format',
1296 1306 b'chunkcachesize',
1297 1307 default=None,
1298 1308 experimental=True,
1299 1309 )
1300 1310 coreconfigitem(
1301 1311 # Enable this dirstate format *when creating a new repository*.
1302 1312 # Which format to use for existing repos is controlled by .hg/requires
1303 1313 b'format',
1304 1314 b'use-dirstate-v2',
1305 1315 default=False,
1306 1316 experimental=True,
1307 1317 alias=[(b'format', b'exp-rc-dirstate-v2')],
1308 1318 )
1309 1319 coreconfigitem(
1310 1320 b'format',
1311 1321 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories',
1312 1322 default=False,
1313 1323 experimental=True,
1314 1324 )
1315 1325 coreconfigitem(
1316 1326 b'format',
1317 1327 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet',
1318 1328 default=False,
1319 1329 experimental=True,
1320 1330 )
1321 1331 coreconfigitem(
1322 1332 b'format',
1323 1333 b'use-dirstate-tracked-hint',
1324 1334 default=False,
1325 1335 experimental=True,
1326 1336 )
1327 1337 coreconfigitem(
1328 1338 b'format',
1329 1339 b'use-dirstate-tracked-hint.version',
1330 1340 default=1,
1331 1341 experimental=True,
1332 1342 )
1333 1343 coreconfigitem(
1334 1344 b'format',
1335 1345 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories',
1336 1346 default=False,
1337 1347 experimental=True,
1338 1348 )
1339 1349 coreconfigitem(
1340 1350 b'format',
1341 1351 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet',
1342 1352 default=False,
1343 1353 experimental=True,
1344 1354 )
1345 1355 coreconfigitem(
1346 1356 b'format',
1347 1357 b'dotencode',
1348 1358 default=True,
1349 1359 )
1350 1360 coreconfigitem(
1351 1361 b'format',
1352 1362 b'generaldelta',
1353 1363 default=False,
1354 1364 experimental=True,
1355 1365 )
1356 1366 coreconfigitem(
1357 1367 b'format',
1358 1368 b'manifestcachesize',
1359 1369 default=None,
1360 1370 experimental=True,
1361 1371 )
1362 1372 coreconfigitem(
1363 1373 b'format',
1364 1374 b'maxchainlen',
1365 1375 default=dynamicdefault,
1366 1376 experimental=True,
1367 1377 )
1368 1378 coreconfigitem(
1369 1379 b'format',
1370 1380 b'obsstore-version',
1371 1381 default=None,
1372 1382 )
1373 1383 coreconfigitem(
1374 1384 b'format',
1375 1385 b'sparse-revlog',
1376 1386 default=True,
1377 1387 )
1378 1388 coreconfigitem(
1379 1389 b'format',
1380 1390 b'revlog-compression',
1381 1391 default=lambda: [b'zstd', b'zlib'],
1382 1392 alias=[(b'experimental', b'format.compression')],
1383 1393 )
1384 1394 # Experimental TODOs:
1385 1395 #
1386 1396 # * Same as for revlogv2 (but for the reduction of the number of files)
1387 1397 # * Actually computing the rank of changesets
1388 1398 # * Improvement to investigate
1389 1399 # - storing .hgtags fnode
1390 1400 # - storing branch related identifier
1391 1401
1392 1402 coreconfigitem(
1393 1403 b'format',
1394 1404 b'exp-use-changelog-v2',
1395 1405 default=None,
1396 1406 experimental=True,
1397 1407 )
1398 1408 coreconfigitem(
1399 1409 b'format',
1400 1410 b'usefncache',
1401 1411 default=True,
1402 1412 )
1403 1413 coreconfigitem(
1404 1414 b'format',
1405 1415 b'usegeneraldelta',
1406 1416 default=True,
1407 1417 )
1408 1418 coreconfigitem(
1409 1419 b'format',
1410 1420 b'usestore',
1411 1421 default=True,
1412 1422 )
1413 1423
1414 1424
1415 1425 def _persistent_nodemap_default():
1416 1426 """compute `use-persistent-nodemap` default value
1417 1427
1418 1428 The feature is disabled unless a fast implementation is available.
1419 1429 """
1420 1430 from . import policy
1421 1431
1422 1432 return policy.importrust('revlog') is not None
1423 1433
1424 1434
1425 1435 coreconfigitem(
1426 1436 b'format',
1427 1437 b'use-persistent-nodemap',
1428 1438 default=_persistent_nodemap_default,
1429 1439 )
1430 1440 coreconfigitem(
1431 1441 b'format',
1432 1442 b'exp-use-copies-side-data-changeset',
1433 1443 default=False,
1434 1444 experimental=True,
1435 1445 )
1436 1446 coreconfigitem(
1437 1447 b'format',
1438 1448 b'use-share-safe',
1439 1449 default=True,
1440 1450 )
1441 1451 coreconfigitem(
1442 1452 b'format',
1443 1453 b'use-share-safe.automatic-upgrade-of-mismatching-repositories',
1444 1454 default=False,
1445 1455 experimental=True,
1446 1456 )
1447 1457 coreconfigitem(
1448 1458 b'format',
1449 1459 b'use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet',
1450 1460 default=False,
1451 1461 experimental=True,
1452 1462 )
1453 1463
1454 1464 # Moving this on by default means we are confident about the scaling of phases.
1455 1465 # This is not garanteed to be the case at the time this message is written.
1456 1466 coreconfigitem(
1457 1467 b'format',
1458 1468 b'use-internal-phase',
1459 1469 default=False,
1460 1470 experimental=True,
1461 1471 )
1462 1472 # The interaction between the archived phase and obsolescence markers needs to
1463 1473 # be sorted out before wider usage of this are to be considered.
1464 1474 #
1465 1475 # At the time this message is written, behavior when archiving obsolete
1466 1476 # changeset differ significantly from stripping. As part of stripping, we also
1467 1477 # remove the obsolescence marker associated to the stripped changesets,
1468 1478 # revealing the precedecessors changesets when applicable. When archiving, we
1469 1479 # don't touch the obsolescence markers, keeping everything hidden. This can
1470 1480 # result in quite confusing situation for people combining exchanging draft
1471 1481 # with the archived phases. As some markers needed by others may be skipped
1472 1482 # during exchange.
1473 1483 coreconfigitem(
1474 1484 b'format',
1475 1485 b'exp-archived-phase',
1476 1486 default=False,
1477 1487 experimental=True,
1478 1488 )
1479 1489 coreconfigitem(
1480 1490 b'shelve',
1481 1491 b'store',
1482 1492 default=b'internal',
1483 1493 experimental=True,
1484 1494 )
1485 1495 coreconfigitem(
1486 1496 b'fsmonitor',
1487 1497 b'warn_when_unused',
1488 1498 default=True,
1489 1499 )
1490 1500 coreconfigitem(
1491 1501 b'fsmonitor',
1492 1502 b'warn_update_file_count',
1493 1503 default=50000,
1494 1504 )
1495 1505 coreconfigitem(
1496 1506 b'fsmonitor',
1497 1507 b'warn_update_file_count_rust',
1498 1508 default=400000,
1499 1509 )
1500 1510 coreconfigitem(
1501 1511 b'help',
1502 1512 br'hidden-command\..*',
1503 1513 default=False,
1504 1514 generic=True,
1505 1515 )
1506 1516 coreconfigitem(
1507 1517 b'help',
1508 1518 br'hidden-topic\..*',
1509 1519 default=False,
1510 1520 generic=True,
1511 1521 )
1512 1522 coreconfigitem(
1513 1523 b'hooks',
1514 1524 b'[^:]*',
1515 1525 default=dynamicdefault,
1516 1526 generic=True,
1517 1527 )
1518 1528 coreconfigitem(
1519 1529 b'hooks',
1520 1530 b'.*:run-with-plain',
1521 1531 default=True,
1522 1532 generic=True,
1523 1533 )
1524 1534 coreconfigitem(
1525 1535 b'hgweb-paths',
1526 1536 b'.*',
1527 1537 default=list,
1528 1538 generic=True,
1529 1539 )
1530 1540 coreconfigitem(
1531 1541 b'hostfingerprints',
1532 1542 b'.*',
1533 1543 default=list,
1534 1544 generic=True,
1535 1545 )
1536 1546 coreconfigitem(
1537 1547 b'hostsecurity',
1538 1548 b'ciphers',
1539 1549 default=None,
1540 1550 )
1541 1551 coreconfigitem(
1542 1552 b'hostsecurity',
1543 1553 b'minimumprotocol',
1544 1554 default=dynamicdefault,
1545 1555 )
1546 1556 coreconfigitem(
1547 1557 b'hostsecurity',
1548 1558 b'.*:minimumprotocol$',
1549 1559 default=dynamicdefault,
1550 1560 generic=True,
1551 1561 )
1552 1562 coreconfigitem(
1553 1563 b'hostsecurity',
1554 1564 b'.*:ciphers$',
1555 1565 default=dynamicdefault,
1556 1566 generic=True,
1557 1567 )
1558 1568 coreconfigitem(
1559 1569 b'hostsecurity',
1560 1570 b'.*:fingerprints$',
1561 1571 default=list,
1562 1572 generic=True,
1563 1573 )
1564 1574 coreconfigitem(
1565 1575 b'hostsecurity',
1566 1576 b'.*:verifycertsfile$',
1567 1577 default=None,
1568 1578 generic=True,
1569 1579 )
1570 1580
1571 1581 coreconfigitem(
1572 1582 b'http_proxy',
1573 1583 b'always',
1574 1584 default=False,
1575 1585 )
1576 1586 coreconfigitem(
1577 1587 b'http_proxy',
1578 1588 b'host',
1579 1589 default=None,
1580 1590 )
1581 1591 coreconfigitem(
1582 1592 b'http_proxy',
1583 1593 b'no',
1584 1594 default=list,
1585 1595 )
1586 1596 coreconfigitem(
1587 1597 b'http_proxy',
1588 1598 b'passwd',
1589 1599 default=None,
1590 1600 )
1591 1601 coreconfigitem(
1592 1602 b'http_proxy',
1593 1603 b'user',
1594 1604 default=None,
1595 1605 )
1596 1606
1597 1607 coreconfigitem(
1598 1608 b'http',
1599 1609 b'timeout',
1600 1610 default=None,
1601 1611 )
1602 1612
1603 1613 coreconfigitem(
1604 1614 b'logtoprocess',
1605 1615 b'commandexception',
1606 1616 default=None,
1607 1617 )
1608 1618 coreconfigitem(
1609 1619 b'logtoprocess',
1610 1620 b'commandfinish',
1611 1621 default=None,
1612 1622 )
1613 1623 coreconfigitem(
1614 1624 b'logtoprocess',
1615 1625 b'command',
1616 1626 default=None,
1617 1627 )
1618 1628 coreconfigitem(
1619 1629 b'logtoprocess',
1620 1630 b'develwarn',
1621 1631 default=None,
1622 1632 )
1623 1633 coreconfigitem(
1624 1634 b'logtoprocess',
1625 1635 b'uiblocked',
1626 1636 default=None,
1627 1637 )
1628 1638 coreconfigitem(
1629 1639 b'merge',
1630 1640 b'checkunknown',
1631 1641 default=b'abort',
1632 1642 )
1633 1643 coreconfigitem(
1634 1644 b'merge',
1635 1645 b'checkignored',
1636 1646 default=b'abort',
1637 1647 )
1638 1648 coreconfigitem(
1639 1649 b'experimental',
1640 1650 b'merge.checkpathconflicts',
1641 1651 default=False,
1642 1652 )
1643 1653 coreconfigitem(
1644 1654 b'merge',
1645 1655 b'followcopies',
1646 1656 default=True,
1647 1657 )
1648 1658 coreconfigitem(
1649 1659 b'merge',
1650 1660 b'on-failure',
1651 1661 default=b'continue',
1652 1662 )
1653 1663 coreconfigitem(
1654 1664 b'merge',
1655 1665 b'preferancestor',
1656 1666 default=lambda: [b'*'],
1657 1667 experimental=True,
1658 1668 )
1659 1669 coreconfigitem(
1660 1670 b'merge',
1661 1671 b'strict-capability-check',
1662 1672 default=False,
1663 1673 )
1664 1674 coreconfigitem(
1665 1675 b'merge',
1666 1676 b'disable-partial-tools',
1667 1677 default=False,
1668 1678 experimental=True,
1669 1679 )
1670 1680 coreconfigitem(
1671 1681 b'partial-merge-tools',
1672 1682 b'.*',
1673 1683 default=None,
1674 1684 generic=True,
1675 1685 experimental=True,
1676 1686 )
1677 1687 coreconfigitem(
1678 1688 b'partial-merge-tools',
1679 1689 br'.*\.patterns',
1680 1690 default=dynamicdefault,
1681 1691 generic=True,
1682 1692 priority=-1,
1683 1693 experimental=True,
1684 1694 )
1685 1695 coreconfigitem(
1686 1696 b'partial-merge-tools',
1687 1697 br'.*\.executable$',
1688 1698 default=dynamicdefault,
1689 1699 generic=True,
1690 1700 priority=-1,
1691 1701 experimental=True,
1692 1702 )
1693 1703 coreconfigitem(
1694 1704 b'partial-merge-tools',
1695 1705 br'.*\.order',
1696 1706 default=0,
1697 1707 generic=True,
1698 1708 priority=-1,
1699 1709 experimental=True,
1700 1710 )
1701 1711 coreconfigitem(
1702 1712 b'partial-merge-tools',
1703 1713 br'.*\.args',
1704 1714 default=b"$local $base $other",
1705 1715 generic=True,
1706 1716 priority=-1,
1707 1717 experimental=True,
1708 1718 )
1709 1719 coreconfigitem(
1710 1720 b'partial-merge-tools',
1711 1721 br'.*\.disable',
1712 1722 default=False,
1713 1723 generic=True,
1714 1724 priority=-1,
1715 1725 experimental=True,
1716 1726 )
1717 1727 coreconfigitem(
1718 1728 b'merge-tools',
1719 1729 b'.*',
1720 1730 default=None,
1721 1731 generic=True,
1722 1732 )
1723 1733 coreconfigitem(
1724 1734 b'merge-tools',
1725 1735 br'.*\.args$',
1726 1736 default=b"$local $base $other",
1727 1737 generic=True,
1728 1738 priority=-1,
1729 1739 )
1730 1740 coreconfigitem(
1731 1741 b'merge-tools',
1732 1742 br'.*\.binary$',
1733 1743 default=False,
1734 1744 generic=True,
1735 1745 priority=-1,
1736 1746 )
1737 1747 coreconfigitem(
1738 1748 b'merge-tools',
1739 1749 br'.*\.check$',
1740 1750 default=list,
1741 1751 generic=True,
1742 1752 priority=-1,
1743 1753 )
1744 1754 coreconfigitem(
1745 1755 b'merge-tools',
1746 1756 br'.*\.checkchanged$',
1747 1757 default=False,
1748 1758 generic=True,
1749 1759 priority=-1,
1750 1760 )
1751 1761 coreconfigitem(
1752 1762 b'merge-tools',
1753 1763 br'.*\.executable$',
1754 1764 default=dynamicdefault,
1755 1765 generic=True,
1756 1766 priority=-1,
1757 1767 )
1758 1768 coreconfigitem(
1759 1769 b'merge-tools',
1760 1770 br'.*\.fixeol$',
1761 1771 default=False,
1762 1772 generic=True,
1763 1773 priority=-1,
1764 1774 )
1765 1775 coreconfigitem(
1766 1776 b'merge-tools',
1767 1777 br'.*\.gui$',
1768 1778 default=False,
1769 1779 generic=True,
1770 1780 priority=-1,
1771 1781 )
1772 1782 coreconfigitem(
1773 1783 b'merge-tools',
1774 1784 br'.*\.mergemarkers$',
1775 1785 default=b'basic',
1776 1786 generic=True,
1777 1787 priority=-1,
1778 1788 )
1779 1789 coreconfigitem(
1780 1790 b'merge-tools',
1781 1791 br'.*\.mergemarkertemplate$',
1782 1792 default=dynamicdefault, # take from command-templates.mergemarker
1783 1793 generic=True,
1784 1794 priority=-1,
1785 1795 )
1786 1796 coreconfigitem(
1787 1797 b'merge-tools',
1788 1798 br'.*\.priority$',
1789 1799 default=0,
1790 1800 generic=True,
1791 1801 priority=-1,
1792 1802 )
1793 1803 coreconfigitem(
1794 1804 b'merge-tools',
1795 1805 br'.*\.premerge$',
1796 1806 default=dynamicdefault,
1797 1807 generic=True,
1798 1808 priority=-1,
1799 1809 )
1800 1810 coreconfigitem(
1801 1811 b'merge-tools',
1802 1812 br'.*\.symlink$',
1803 1813 default=False,
1804 1814 generic=True,
1805 1815 priority=-1,
1806 1816 )
1807 1817 coreconfigitem(
1808 1818 b'pager',
1809 1819 b'attend-.*',
1810 1820 default=dynamicdefault,
1811 1821 generic=True,
1812 1822 )
1813 1823 coreconfigitem(
1814 1824 b'pager',
1815 1825 b'ignore',
1816 1826 default=list,
1817 1827 )
1818 1828 coreconfigitem(
1819 1829 b'pager',
1820 1830 b'pager',
1821 1831 default=dynamicdefault,
1822 1832 )
1823 1833 coreconfigitem(
1824 1834 b'patch',
1825 1835 b'eol',
1826 1836 default=b'strict',
1827 1837 )
1828 1838 coreconfigitem(
1829 1839 b'patch',
1830 1840 b'fuzz',
1831 1841 default=2,
1832 1842 )
1833 1843 coreconfigitem(
1834 1844 b'paths',
1835 1845 b'default',
1836 1846 default=None,
1837 1847 )
1838 1848 coreconfigitem(
1839 1849 b'paths',
1840 1850 b'default-push',
1841 1851 default=None,
1842 1852 )
1843 1853 coreconfigitem(
1844 1854 b'paths',
1845 1855 b'.*',
1846 1856 default=None,
1847 1857 generic=True,
1848 1858 )
1849 1859 coreconfigitem(
1850 1860 b'paths',
1851 1861 b'.*:bookmarks.mode',
1852 1862 default='default',
1853 1863 generic=True,
1854 1864 )
1855 1865 coreconfigitem(
1856 1866 b'paths',
1857 1867 b'.*:multi-urls',
1858 1868 default=False,
1859 1869 generic=True,
1860 1870 )
1861 1871 coreconfigitem(
1862 1872 b'paths',
1863 1873 b'.*:pushrev',
1864 1874 default=None,
1865 1875 generic=True,
1866 1876 )
1867 1877 coreconfigitem(
1868 1878 b'paths',
1869 1879 b'.*:pushurl',
1870 1880 default=None,
1871 1881 generic=True,
1872 1882 )
1873 1883 coreconfigitem(
1874 1884 b'phases',
1875 1885 b'checksubrepos',
1876 1886 default=b'follow',
1877 1887 )
1878 1888 coreconfigitem(
1879 1889 b'phases',
1880 1890 b'new-commit',
1881 1891 default=b'draft',
1882 1892 )
1883 1893 coreconfigitem(
1884 1894 b'phases',
1885 1895 b'publish',
1886 1896 default=True,
1887 1897 )
1888 1898 coreconfigitem(
1889 1899 b'profiling',
1890 1900 b'enabled',
1891 1901 default=False,
1892 1902 )
1893 1903 coreconfigitem(
1894 1904 b'profiling',
1895 1905 b'format',
1896 1906 default=b'text',
1897 1907 )
1898 1908 coreconfigitem(
1899 1909 b'profiling',
1900 1910 b'freq',
1901 1911 default=1000,
1902 1912 )
1903 1913 coreconfigitem(
1904 1914 b'profiling',
1905 1915 b'limit',
1906 1916 default=30,
1907 1917 )
1908 1918 coreconfigitem(
1909 1919 b'profiling',
1910 1920 b'nested',
1911 1921 default=0,
1912 1922 )
1913 1923 coreconfigitem(
1914 1924 b'profiling',
1915 1925 b'output',
1916 1926 default=None,
1917 1927 )
1918 1928 coreconfigitem(
1919 1929 b'profiling',
1920 1930 b'showmax',
1921 1931 default=0.999,
1922 1932 )
1923 1933 coreconfigitem(
1924 1934 b'profiling',
1925 1935 b'showmin',
1926 1936 default=dynamicdefault,
1927 1937 )
1928 1938 coreconfigitem(
1929 1939 b'profiling',
1930 1940 b'showtime',
1931 1941 default=True,
1932 1942 )
1933 1943 coreconfigitem(
1934 1944 b'profiling',
1935 1945 b'sort',
1936 1946 default=b'inlinetime',
1937 1947 )
1938 1948 coreconfigitem(
1939 1949 b'profiling',
1940 1950 b'statformat',
1941 1951 default=b'hotpath',
1942 1952 )
1943 1953 coreconfigitem(
1944 1954 b'profiling',
1945 1955 b'time-track',
1946 1956 default=dynamicdefault,
1947 1957 )
1948 1958 coreconfigitem(
1949 1959 b'profiling',
1950 1960 b'type',
1951 1961 default=b'stat',
1952 1962 )
1953 1963 coreconfigitem(
1954 1964 b'progress',
1955 1965 b'assume-tty',
1956 1966 default=False,
1957 1967 )
1958 1968 coreconfigitem(
1959 1969 b'progress',
1960 1970 b'changedelay',
1961 1971 default=1,
1962 1972 )
1963 1973 coreconfigitem(
1964 1974 b'progress',
1965 1975 b'clear-complete',
1966 1976 default=True,
1967 1977 )
1968 1978 coreconfigitem(
1969 1979 b'progress',
1970 1980 b'debug',
1971 1981 default=False,
1972 1982 )
1973 1983 coreconfigitem(
1974 1984 b'progress',
1975 1985 b'delay',
1976 1986 default=3,
1977 1987 )
1978 1988 coreconfigitem(
1979 1989 b'progress',
1980 1990 b'disable',
1981 1991 default=False,
1982 1992 )
1983 1993 coreconfigitem(
1984 1994 b'progress',
1985 1995 b'estimateinterval',
1986 1996 default=60.0,
1987 1997 )
1988 1998 coreconfigitem(
1989 1999 b'progress',
1990 2000 b'format',
1991 2001 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1992 2002 )
1993 2003 coreconfigitem(
1994 2004 b'progress',
1995 2005 b'refresh',
1996 2006 default=0.1,
1997 2007 )
1998 2008 coreconfigitem(
1999 2009 b'progress',
2000 2010 b'width',
2001 2011 default=dynamicdefault,
2002 2012 )
2003 2013 coreconfigitem(
2004 2014 b'pull',
2005 2015 b'confirm',
2006 2016 default=False,
2007 2017 )
2008 2018 coreconfigitem(
2009 2019 b'push',
2010 2020 b'pushvars.server',
2011 2021 default=False,
2012 2022 )
2013 2023 coreconfigitem(
2014 2024 b'rewrite',
2015 2025 b'backup-bundle',
2016 2026 default=True,
2017 2027 alias=[(b'ui', b'history-editing-backup')],
2018 2028 )
2019 2029 coreconfigitem(
2020 2030 b'rewrite',
2021 2031 b'update-timestamp',
2022 2032 default=False,
2023 2033 )
2024 2034 coreconfigitem(
2025 2035 b'rewrite',
2026 2036 b'empty-successor',
2027 2037 default=b'skip',
2028 2038 experimental=True,
2029 2039 )
2030 2040 # experimental as long as format.use-dirstate-v2 is.
2031 2041 coreconfigitem(
2032 2042 b'storage',
2033 2043 b'dirstate-v2.slow-path',
2034 2044 default=b"abort",
2035 2045 experimental=True,
2036 2046 )
2037 2047 coreconfigitem(
2038 2048 b'storage',
2039 2049 b'new-repo-backend',
2040 2050 default=b'revlogv1',
2041 2051 experimental=True,
2042 2052 )
2043 2053 coreconfigitem(
2044 2054 b'storage',
2045 2055 b'revlog.optimize-delta-parent-choice',
2046 2056 default=True,
2047 2057 alias=[(b'format', b'aggressivemergedeltas')],
2048 2058 )
2049 2059 coreconfigitem(
2050 2060 b'storage',
2051 2061 b'revlog.issue6528.fix-incoming',
2052 2062 default=True,
2053 2063 )
2054 2064 # experimental as long as rust is experimental (or a C version is implemented)
2055 2065 coreconfigitem(
2056 2066 b'storage',
2057 2067 b'revlog.persistent-nodemap.mmap',
2058 2068 default=True,
2059 2069 )
2060 2070 # experimental as long as format.use-persistent-nodemap is.
2061 2071 coreconfigitem(
2062 2072 b'storage',
2063 2073 b'revlog.persistent-nodemap.slow-path',
2064 2074 default=b"abort",
2065 2075 )
2066 2076
2067 2077 coreconfigitem(
2068 2078 b'storage',
2069 2079 b'revlog.reuse-external-delta',
2070 2080 default=True,
2071 2081 )
2072 2082 coreconfigitem(
2073 2083 b'storage',
2074 2084 b'revlog.reuse-external-delta-parent',
2075 2085 default=None,
2076 2086 )
2077 2087 coreconfigitem(
2078 2088 b'storage',
2079 2089 b'revlog.zlib.level',
2080 2090 default=None,
2081 2091 )
2082 2092 coreconfigitem(
2083 2093 b'storage',
2084 2094 b'revlog.zstd.level',
2085 2095 default=None,
2086 2096 )
2087 2097 coreconfigitem(
2088 2098 b'server',
2089 2099 b'bookmarks-pushkey-compat',
2090 2100 default=True,
2091 2101 )
2092 2102 coreconfigitem(
2093 2103 b'server',
2094 2104 b'bundle1',
2095 2105 default=True,
2096 2106 )
2097 2107 coreconfigitem(
2098 2108 b'server',
2099 2109 b'bundle1gd',
2100 2110 default=None,
2101 2111 )
2102 2112 coreconfigitem(
2103 2113 b'server',
2104 2114 b'bundle1.pull',
2105 2115 default=None,
2106 2116 )
2107 2117 coreconfigitem(
2108 2118 b'server',
2109 2119 b'bundle1gd.pull',
2110 2120 default=None,
2111 2121 )
2112 2122 coreconfigitem(
2113 2123 b'server',
2114 2124 b'bundle1.push',
2115 2125 default=None,
2116 2126 )
2117 2127 coreconfigitem(
2118 2128 b'server',
2119 2129 b'bundle1gd.push',
2120 2130 default=None,
2121 2131 )
2122 2132 coreconfigitem(
2123 2133 b'server',
2124 2134 b'bundle2.stream',
2125 2135 default=True,
2126 2136 alias=[(b'experimental', b'bundle2.stream')],
2127 2137 )
2128 2138 coreconfigitem(
2129 2139 b'server',
2130 2140 b'compressionengines',
2131 2141 default=list,
2132 2142 )
2133 2143 coreconfigitem(
2134 2144 b'server',
2135 2145 b'concurrent-push-mode',
2136 2146 default=b'check-related',
2137 2147 )
2138 2148 coreconfigitem(
2139 2149 b'server',
2140 2150 b'disablefullbundle',
2141 2151 default=False,
2142 2152 )
2143 2153 coreconfigitem(
2144 2154 b'server',
2145 2155 b'maxhttpheaderlen',
2146 2156 default=1024,
2147 2157 )
2148 2158 coreconfigitem(
2149 2159 b'server',
2150 2160 b'pullbundle',
2151 2161 default=False,
2152 2162 )
2153 2163 coreconfigitem(
2154 2164 b'server',
2155 2165 b'preferuncompressed',
2156 2166 default=False,
2157 2167 )
2158 2168 coreconfigitem(
2159 2169 b'server',
2160 2170 b'streamunbundle',
2161 2171 default=False,
2162 2172 )
2163 2173 coreconfigitem(
2164 2174 b'server',
2165 2175 b'uncompressed',
2166 2176 default=True,
2167 2177 )
2168 2178 coreconfigitem(
2169 2179 b'server',
2170 2180 b'uncompressedallowsecret',
2171 2181 default=False,
2172 2182 )
2173 2183 coreconfigitem(
2174 2184 b'server',
2175 2185 b'view',
2176 2186 default=b'served',
2177 2187 )
2178 2188 coreconfigitem(
2179 2189 b'server',
2180 2190 b'validate',
2181 2191 default=False,
2182 2192 )
2183 2193 coreconfigitem(
2184 2194 b'server',
2185 2195 b'zliblevel',
2186 2196 default=-1,
2187 2197 )
2188 2198 coreconfigitem(
2189 2199 b'server',
2190 2200 b'zstdlevel',
2191 2201 default=3,
2192 2202 )
2193 2203 coreconfigitem(
2194 2204 b'share',
2195 2205 b'pool',
2196 2206 default=None,
2197 2207 )
2198 2208 coreconfigitem(
2199 2209 b'share',
2200 2210 b'poolnaming',
2201 2211 default=b'identity',
2202 2212 )
2203 2213 coreconfigitem(
2204 2214 b'share',
2205 2215 b'safe-mismatch.source-not-safe',
2206 2216 default=b'abort',
2207 2217 )
2208 2218 coreconfigitem(
2209 2219 b'share',
2210 2220 b'safe-mismatch.source-safe',
2211 2221 default=b'abort',
2212 2222 )
2213 2223 coreconfigitem(
2214 2224 b'share',
2215 2225 b'safe-mismatch.source-not-safe.warn',
2216 2226 default=True,
2217 2227 )
2218 2228 coreconfigitem(
2219 2229 b'share',
2220 2230 b'safe-mismatch.source-safe.warn',
2221 2231 default=True,
2222 2232 )
2223 2233 coreconfigitem(
2224 2234 b'share',
2225 2235 b'safe-mismatch.source-not-safe:verbose-upgrade',
2226 2236 default=True,
2227 2237 )
2228 2238 coreconfigitem(
2229 2239 b'share',
2230 2240 b'safe-mismatch.source-safe:verbose-upgrade',
2231 2241 default=True,
2232 2242 )
2233 2243 coreconfigitem(
2234 2244 b'shelve',
2235 2245 b'maxbackups',
2236 2246 default=10,
2237 2247 )
2238 2248 coreconfigitem(
2239 2249 b'smtp',
2240 2250 b'host',
2241 2251 default=None,
2242 2252 )
2243 2253 coreconfigitem(
2244 2254 b'smtp',
2245 2255 b'local_hostname',
2246 2256 default=None,
2247 2257 )
2248 2258 coreconfigitem(
2249 2259 b'smtp',
2250 2260 b'password',
2251 2261 default=None,
2252 2262 )
2253 2263 coreconfigitem(
2254 2264 b'smtp',
2255 2265 b'port',
2256 2266 default=dynamicdefault,
2257 2267 )
2258 2268 coreconfigitem(
2259 2269 b'smtp',
2260 2270 b'tls',
2261 2271 default=b'none',
2262 2272 )
2263 2273 coreconfigitem(
2264 2274 b'smtp',
2265 2275 b'username',
2266 2276 default=None,
2267 2277 )
2268 2278 coreconfigitem(
2269 2279 b'sparse',
2270 2280 b'missingwarning',
2271 2281 default=True,
2272 2282 experimental=True,
2273 2283 )
2274 2284 coreconfigitem(
2275 2285 b'subrepos',
2276 2286 b'allowed',
2277 2287 default=dynamicdefault, # to make backporting simpler
2278 2288 )
2279 2289 coreconfigitem(
2280 2290 b'subrepos',
2281 2291 b'hg:allowed',
2282 2292 default=dynamicdefault,
2283 2293 )
2284 2294 coreconfigitem(
2285 2295 b'subrepos',
2286 2296 b'git:allowed',
2287 2297 default=dynamicdefault,
2288 2298 )
2289 2299 coreconfigitem(
2290 2300 b'subrepos',
2291 2301 b'svn:allowed',
2292 2302 default=dynamicdefault,
2293 2303 )
2294 2304 coreconfigitem(
2295 2305 b'templates',
2296 2306 b'.*',
2297 2307 default=None,
2298 2308 generic=True,
2299 2309 )
2300 2310 coreconfigitem(
2301 2311 b'templateconfig',
2302 2312 b'.*',
2303 2313 default=dynamicdefault,
2304 2314 generic=True,
2305 2315 )
2306 2316 coreconfigitem(
2307 2317 b'trusted',
2308 2318 b'groups',
2309 2319 default=list,
2310 2320 )
2311 2321 coreconfigitem(
2312 2322 b'trusted',
2313 2323 b'users',
2314 2324 default=list,
2315 2325 )
2316 2326 coreconfigitem(
2317 2327 b'ui',
2318 2328 b'_usedassubrepo',
2319 2329 default=False,
2320 2330 )
2321 2331 coreconfigitem(
2322 2332 b'ui',
2323 2333 b'allowemptycommit',
2324 2334 default=False,
2325 2335 )
2326 2336 coreconfigitem(
2327 2337 b'ui',
2328 2338 b'archivemeta',
2329 2339 default=True,
2330 2340 )
2331 2341 coreconfigitem(
2332 2342 b'ui',
2333 2343 b'askusername',
2334 2344 default=False,
2335 2345 )
2336 2346 coreconfigitem(
2337 2347 b'ui',
2338 2348 b'available-memory',
2339 2349 default=None,
2340 2350 )
2341 2351
2342 2352 coreconfigitem(
2343 2353 b'ui',
2344 2354 b'clonebundlefallback',
2345 2355 default=False,
2346 2356 )
2347 2357 coreconfigitem(
2348 2358 b'ui',
2349 2359 b'clonebundleprefers',
2350 2360 default=list,
2351 2361 )
2352 2362 coreconfigitem(
2353 2363 b'ui',
2354 2364 b'clonebundles',
2355 2365 default=True,
2356 2366 )
2357 2367 coreconfigitem(
2358 2368 b'ui',
2359 2369 b'color',
2360 2370 default=b'auto',
2361 2371 )
2362 2372 coreconfigitem(
2363 2373 b'ui',
2364 2374 b'commitsubrepos',
2365 2375 default=False,
2366 2376 )
2367 2377 coreconfigitem(
2368 2378 b'ui',
2369 2379 b'debug',
2370 2380 default=False,
2371 2381 )
2372 2382 coreconfigitem(
2373 2383 b'ui',
2374 2384 b'debugger',
2375 2385 default=None,
2376 2386 )
2377 2387 coreconfigitem(
2378 2388 b'ui',
2379 2389 b'editor',
2380 2390 default=dynamicdefault,
2381 2391 )
2382 2392 coreconfigitem(
2383 2393 b'ui',
2384 2394 b'detailed-exit-code',
2385 2395 default=False,
2386 2396 experimental=True,
2387 2397 )
2388 2398 coreconfigitem(
2389 2399 b'ui',
2390 2400 b'fallbackencoding',
2391 2401 default=None,
2392 2402 )
2393 2403 coreconfigitem(
2394 2404 b'ui',
2395 2405 b'forcecwd',
2396 2406 default=None,
2397 2407 )
2398 2408 coreconfigitem(
2399 2409 b'ui',
2400 2410 b'forcemerge',
2401 2411 default=None,
2402 2412 )
2403 2413 coreconfigitem(
2404 2414 b'ui',
2405 2415 b'formatdebug',
2406 2416 default=False,
2407 2417 )
2408 2418 coreconfigitem(
2409 2419 b'ui',
2410 2420 b'formatjson',
2411 2421 default=False,
2412 2422 )
2413 2423 coreconfigitem(
2414 2424 b'ui',
2415 2425 b'formatted',
2416 2426 default=None,
2417 2427 )
2418 2428 coreconfigitem(
2419 2429 b'ui',
2420 2430 b'interactive',
2421 2431 default=None,
2422 2432 )
2423 2433 coreconfigitem(
2424 2434 b'ui',
2425 2435 b'interface',
2426 2436 default=None,
2427 2437 )
2428 2438 coreconfigitem(
2429 2439 b'ui',
2430 2440 b'interface.chunkselector',
2431 2441 default=None,
2432 2442 )
2433 2443 coreconfigitem(
2434 2444 b'ui',
2435 2445 b'large-file-limit',
2436 2446 default=10 * (2 ** 20),
2437 2447 )
2438 2448 coreconfigitem(
2439 2449 b'ui',
2440 2450 b'logblockedtimes',
2441 2451 default=False,
2442 2452 )
2443 2453 coreconfigitem(
2444 2454 b'ui',
2445 2455 b'merge',
2446 2456 default=None,
2447 2457 )
2448 2458 coreconfigitem(
2449 2459 b'ui',
2450 2460 b'mergemarkers',
2451 2461 default=b'basic',
2452 2462 )
2453 2463 coreconfigitem(
2454 2464 b'ui',
2455 2465 b'message-output',
2456 2466 default=b'stdio',
2457 2467 )
2458 2468 coreconfigitem(
2459 2469 b'ui',
2460 2470 b'nontty',
2461 2471 default=False,
2462 2472 )
2463 2473 coreconfigitem(
2464 2474 b'ui',
2465 2475 b'origbackuppath',
2466 2476 default=None,
2467 2477 )
2468 2478 coreconfigitem(
2469 2479 b'ui',
2470 2480 b'paginate',
2471 2481 default=True,
2472 2482 )
2473 2483 coreconfigitem(
2474 2484 b'ui',
2475 2485 b'patch',
2476 2486 default=None,
2477 2487 )
2478 2488 coreconfigitem(
2479 2489 b'ui',
2480 2490 b'portablefilenames',
2481 2491 default=b'warn',
2482 2492 )
2483 2493 coreconfigitem(
2484 2494 b'ui',
2485 2495 b'promptecho',
2486 2496 default=False,
2487 2497 )
2488 2498 coreconfigitem(
2489 2499 b'ui',
2490 2500 b'quiet',
2491 2501 default=False,
2492 2502 )
2493 2503 coreconfigitem(
2494 2504 b'ui',
2495 2505 b'quietbookmarkmove',
2496 2506 default=False,
2497 2507 )
2498 2508 coreconfigitem(
2499 2509 b'ui',
2500 2510 b'relative-paths',
2501 2511 default=b'legacy',
2502 2512 )
2503 2513 coreconfigitem(
2504 2514 b'ui',
2505 2515 b'remotecmd',
2506 2516 default=b'hg',
2507 2517 )
2508 2518 coreconfigitem(
2509 2519 b'ui',
2510 2520 b'report_untrusted',
2511 2521 default=True,
2512 2522 )
2513 2523 coreconfigitem(
2514 2524 b'ui',
2515 2525 b'rollback',
2516 2526 default=True,
2517 2527 )
2518 2528 coreconfigitem(
2519 2529 b'ui',
2520 2530 b'signal-safe-lock',
2521 2531 default=True,
2522 2532 )
2523 2533 coreconfigitem(
2524 2534 b'ui',
2525 2535 b'slash',
2526 2536 default=False,
2527 2537 )
2528 2538 coreconfigitem(
2529 2539 b'ui',
2530 2540 b'ssh',
2531 2541 default=b'ssh',
2532 2542 )
2533 2543 coreconfigitem(
2534 2544 b'ui',
2535 2545 b'ssherrorhint',
2536 2546 default=None,
2537 2547 )
2538 2548 coreconfigitem(
2539 2549 b'ui',
2540 2550 b'statuscopies',
2541 2551 default=False,
2542 2552 )
2543 2553 coreconfigitem(
2544 2554 b'ui',
2545 2555 b'strict',
2546 2556 default=False,
2547 2557 )
2548 2558 coreconfigitem(
2549 2559 b'ui',
2550 2560 b'style',
2551 2561 default=b'',
2552 2562 )
2553 2563 coreconfigitem(
2554 2564 b'ui',
2555 2565 b'supportcontact',
2556 2566 default=None,
2557 2567 )
2558 2568 coreconfigitem(
2559 2569 b'ui',
2560 2570 b'textwidth',
2561 2571 default=78,
2562 2572 )
2563 2573 coreconfigitem(
2564 2574 b'ui',
2565 2575 b'timeout',
2566 2576 default=b'600',
2567 2577 )
2568 2578 coreconfigitem(
2569 2579 b'ui',
2570 2580 b'timeout.warn',
2571 2581 default=0,
2572 2582 )
2573 2583 coreconfigitem(
2574 2584 b'ui',
2575 2585 b'timestamp-output',
2576 2586 default=False,
2577 2587 )
2578 2588 coreconfigitem(
2579 2589 b'ui',
2580 2590 b'traceback',
2581 2591 default=False,
2582 2592 )
2583 2593 coreconfigitem(
2584 2594 b'ui',
2585 2595 b'tweakdefaults',
2586 2596 default=False,
2587 2597 )
2588 2598 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2589 2599 coreconfigitem(
2590 2600 b'ui',
2591 2601 b'verbose',
2592 2602 default=False,
2593 2603 )
2594 2604 coreconfigitem(
2595 2605 b'verify',
2596 2606 b'skipflags',
2597 2607 default=0,
2598 2608 )
2599 2609 coreconfigitem(
2600 2610 b'web',
2601 2611 b'allowbz2',
2602 2612 default=False,
2603 2613 )
2604 2614 coreconfigitem(
2605 2615 b'web',
2606 2616 b'allowgz',
2607 2617 default=False,
2608 2618 )
2609 2619 coreconfigitem(
2610 2620 b'web',
2611 2621 b'allow-pull',
2612 2622 alias=[(b'web', b'allowpull')],
2613 2623 default=True,
2614 2624 )
2615 2625 coreconfigitem(
2616 2626 b'web',
2617 2627 b'allow-push',
2618 2628 alias=[(b'web', b'allow_push')],
2619 2629 default=list,
2620 2630 )
2621 2631 coreconfigitem(
2622 2632 b'web',
2623 2633 b'allowzip',
2624 2634 default=False,
2625 2635 )
2626 2636 coreconfigitem(
2627 2637 b'web',
2628 2638 b'archivesubrepos',
2629 2639 default=False,
2630 2640 )
2631 2641 coreconfigitem(
2632 2642 b'web',
2633 2643 b'cache',
2634 2644 default=True,
2635 2645 )
2636 2646 coreconfigitem(
2637 2647 b'web',
2638 2648 b'comparisoncontext',
2639 2649 default=5,
2640 2650 )
2641 2651 coreconfigitem(
2642 2652 b'web',
2643 2653 b'contact',
2644 2654 default=None,
2645 2655 )
2646 2656 coreconfigitem(
2647 2657 b'web',
2648 2658 b'deny_push',
2649 2659 default=list,
2650 2660 )
2651 2661 coreconfigitem(
2652 2662 b'web',
2653 2663 b'guessmime',
2654 2664 default=False,
2655 2665 )
2656 2666 coreconfigitem(
2657 2667 b'web',
2658 2668 b'hidden',
2659 2669 default=False,
2660 2670 )
2661 2671 coreconfigitem(
2662 2672 b'web',
2663 2673 b'labels',
2664 2674 default=list,
2665 2675 )
2666 2676 coreconfigitem(
2667 2677 b'web',
2668 2678 b'logoimg',
2669 2679 default=b'hglogo.png',
2670 2680 )
2671 2681 coreconfigitem(
2672 2682 b'web',
2673 2683 b'logourl',
2674 2684 default=b'https://mercurial-scm.org/',
2675 2685 )
2676 2686 coreconfigitem(
2677 2687 b'web',
2678 2688 b'accesslog',
2679 2689 default=b'-',
2680 2690 )
2681 2691 coreconfigitem(
2682 2692 b'web',
2683 2693 b'address',
2684 2694 default=b'',
2685 2695 )
2686 2696 coreconfigitem(
2687 2697 b'web',
2688 2698 b'allow-archive',
2689 2699 alias=[(b'web', b'allow_archive')],
2690 2700 default=list,
2691 2701 )
2692 2702 coreconfigitem(
2693 2703 b'web',
2694 2704 b'allow_read',
2695 2705 default=list,
2696 2706 )
2697 2707 coreconfigitem(
2698 2708 b'web',
2699 2709 b'baseurl',
2700 2710 default=None,
2701 2711 )
2702 2712 coreconfigitem(
2703 2713 b'web',
2704 2714 b'cacerts',
2705 2715 default=None,
2706 2716 )
2707 2717 coreconfigitem(
2708 2718 b'web',
2709 2719 b'certificate',
2710 2720 default=None,
2711 2721 )
2712 2722 coreconfigitem(
2713 2723 b'web',
2714 2724 b'collapse',
2715 2725 default=False,
2716 2726 )
2717 2727 coreconfigitem(
2718 2728 b'web',
2719 2729 b'csp',
2720 2730 default=None,
2721 2731 )
2722 2732 coreconfigitem(
2723 2733 b'web',
2724 2734 b'deny_read',
2725 2735 default=list,
2726 2736 )
2727 2737 coreconfigitem(
2728 2738 b'web',
2729 2739 b'descend',
2730 2740 default=True,
2731 2741 )
2732 2742 coreconfigitem(
2733 2743 b'web',
2734 2744 b'description',
2735 2745 default=b"",
2736 2746 )
2737 2747 coreconfigitem(
2738 2748 b'web',
2739 2749 b'encoding',
2740 2750 default=lambda: encoding.encoding,
2741 2751 )
2742 2752 coreconfigitem(
2743 2753 b'web',
2744 2754 b'errorlog',
2745 2755 default=b'-',
2746 2756 )
2747 2757 coreconfigitem(
2748 2758 b'web',
2749 2759 b'ipv6',
2750 2760 default=False,
2751 2761 )
2752 2762 coreconfigitem(
2753 2763 b'web',
2754 2764 b'maxchanges',
2755 2765 default=10,
2756 2766 )
2757 2767 coreconfigitem(
2758 2768 b'web',
2759 2769 b'maxfiles',
2760 2770 default=10,
2761 2771 )
2762 2772 coreconfigitem(
2763 2773 b'web',
2764 2774 b'maxshortchanges',
2765 2775 default=60,
2766 2776 )
2767 2777 coreconfigitem(
2768 2778 b'web',
2769 2779 b'motd',
2770 2780 default=b'',
2771 2781 )
2772 2782 coreconfigitem(
2773 2783 b'web',
2774 2784 b'name',
2775 2785 default=dynamicdefault,
2776 2786 )
2777 2787 coreconfigitem(
2778 2788 b'web',
2779 2789 b'port',
2780 2790 default=8000,
2781 2791 )
2782 2792 coreconfigitem(
2783 2793 b'web',
2784 2794 b'prefix',
2785 2795 default=b'',
2786 2796 )
2787 2797 coreconfigitem(
2788 2798 b'web',
2789 2799 b'push_ssl',
2790 2800 default=True,
2791 2801 )
2792 2802 coreconfigitem(
2793 2803 b'web',
2794 2804 b'refreshinterval',
2795 2805 default=20,
2796 2806 )
2797 2807 coreconfigitem(
2798 2808 b'web',
2799 2809 b'server-header',
2800 2810 default=None,
2801 2811 )
2802 2812 coreconfigitem(
2803 2813 b'web',
2804 2814 b'static',
2805 2815 default=None,
2806 2816 )
2807 2817 coreconfigitem(
2808 2818 b'web',
2809 2819 b'staticurl',
2810 2820 default=None,
2811 2821 )
2812 2822 coreconfigitem(
2813 2823 b'web',
2814 2824 b'stripes',
2815 2825 default=1,
2816 2826 )
2817 2827 coreconfigitem(
2818 2828 b'web',
2819 2829 b'style',
2820 2830 default=b'paper',
2821 2831 )
2822 2832 coreconfigitem(
2823 2833 b'web',
2824 2834 b'templates',
2825 2835 default=None,
2826 2836 )
2827 2837 coreconfigitem(
2828 2838 b'web',
2829 2839 b'view',
2830 2840 default=b'served',
2831 2841 experimental=True,
2832 2842 )
2833 2843 coreconfigitem(
2834 2844 b'worker',
2835 2845 b'backgroundclose',
2836 2846 default=dynamicdefault,
2837 2847 )
2838 2848 # Windows defaults to a limit of 512 open files. A buffer of 128
2839 2849 # should give us enough headway.
2840 2850 coreconfigitem(
2841 2851 b'worker',
2842 2852 b'backgroundclosemaxqueue',
2843 2853 default=384,
2844 2854 )
2845 2855 coreconfigitem(
2846 2856 b'worker',
2847 2857 b'backgroundcloseminfilecount',
2848 2858 default=2048,
2849 2859 )
2850 2860 coreconfigitem(
2851 2861 b'worker',
2852 2862 b'backgroundclosethreadcount',
2853 2863 default=4,
2854 2864 )
2855 2865 coreconfigitem(
2856 2866 b'worker',
2857 2867 b'enabled',
2858 2868 default=True,
2859 2869 )
2860 2870 coreconfigitem(
2861 2871 b'worker',
2862 2872 b'numcpus',
2863 2873 default=None,
2864 2874 )
2865 2875
2866 2876 # Rebase related configuration moved to core because other extension are doing
2867 2877 # strange things. For example, shelve import the extensions to reuse some bit
2868 2878 # without formally loading it.
2869 2879 coreconfigitem(
2870 2880 b'commands',
2871 2881 b'rebase.requiredest',
2872 2882 default=False,
2873 2883 )
2874 2884 coreconfigitem(
2875 2885 b'experimental',
2876 2886 b'rebaseskipobsolete',
2877 2887 default=True,
2878 2888 )
2879 2889 coreconfigitem(
2880 2890 b'rebase',
2881 2891 b'singletransaction',
2882 2892 default=False,
2883 2893 )
2884 2894 coreconfigitem(
2885 2895 b'rebase',
2886 2896 b'experimental.inmemory',
2887 2897 default=False,
2888 2898 )
2889 2899
2890 2900 # This setting controls creation of a rebase_source extra field
2891 2901 # during rebase. When False, no such field is created. This is
2892 2902 # useful eg for incrementally converting changesets and then
2893 2903 # rebasing them onto an existing repo.
2894 2904 # WARNING: this is an advanced setting reserved for people who know
2895 2905 # exactly what they are doing. Misuse of this setting can easily
2896 2906 # result in obsmarker cycles and a vivid headache.
2897 2907 coreconfigitem(
2898 2908 b'rebase',
2899 2909 b'store-source',
2900 2910 default=True,
2901 2911 experimental=True,
2902 2912 )
@@ -1,704 +1,708 b''
1 1 # dirstatemap.py
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6
7 7 from .i18n import _
8 8
9 9 from . import (
10 10 error,
11 11 pathutil,
12 12 policy,
13 testing,
13 14 txnutil,
14 15 util,
15 16 )
16 17
17 18 from .dirstateutils import (
18 19 docket as docketmod,
19 20 v2,
20 21 )
21 22
22 23 parsers = policy.importmod('parsers')
23 24 rustmod = policy.importrust('dirstate')
24 25
25 26 propertycache = util.propertycache
26 27
27 28 if rustmod is None:
28 29 DirstateItem = parsers.DirstateItem
29 30 else:
30 31 DirstateItem = rustmod.DirstateItem
31 32
32 33 rangemask = 0x7FFFFFFF
33 34
34 35 WRITE_MODE_AUTO = 0
35 36 WRITE_MODE_FORCE_NEW = 1
36 37 WRITE_MODE_FORCE_APPEND = 2
37 38
38 39
39 40 class _dirstatemapcommon:
40 41 """
41 42 Methods that are identical for both implementations of the dirstatemap
42 43 class, with and without Rust extensions enabled.
43 44 """
44 45
45 46 # please pytype
46 47
47 48 _map = None
48 49 copymap = None
49 50
50 51 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
51 52 self._use_dirstate_v2 = use_dirstate_v2
52 53 self._nodeconstants = nodeconstants
53 54 self._ui = ui
54 55 self._opener = opener
55 56 self._root = root
56 57 self._filename = b'dirstate'
57 58 self._nodelen = 20 # Also update Rust code when changing this!
58 59 self._parents = None
59 60 self._dirtyparents = False
60 61 self._docket = None
61 62 write_mode = ui.config(b"devel", b"dirstate.v2.data_update_mode")
62 63 if write_mode == b"auto":
63 64 self._write_mode = WRITE_MODE_AUTO
64 65 elif write_mode == b"force-append":
65 66 self._write_mode = WRITE_MODE_FORCE_APPEND
66 67 elif write_mode == b"force-new":
67 68 self._write_mode = WRITE_MODE_FORCE_NEW
68 69 else:
69 70 # unknown value, fallback to default
70 71 self._write_mode = WRITE_MODE_AUTO
71 72
72 73 # for consistent view between _pl() and _read() invocations
73 74 self._pendingmode = None
74 75
75 76 def preload(self):
76 77 """Loads the underlying data, if it's not already loaded"""
77 78 self._map
78 79
79 80 def get(self, key, default=None):
80 81 return self._map.get(key, default)
81 82
82 83 def __len__(self):
83 84 return len(self._map)
84 85
85 86 def __iter__(self):
86 87 return iter(self._map)
87 88
88 89 def __contains__(self, key):
89 90 return key in self._map
90 91
91 92 def __getitem__(self, item):
92 93 return self._map[item]
93 94
94 95 ### disk interaction
95 96
96 97 def _opendirstatefile(self):
97 98 fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
98 99 if self._pendingmode is not None and self._pendingmode != mode:
99 100 fp.close()
100 101 raise error.Abort(
101 102 _(b'working directory state may be changed parallelly')
102 103 )
103 104 self._pendingmode = mode
104 105 return fp
105 106
106 107 def _readdirstatefile(self, size=-1):
107 108 try:
108 109 with self._opendirstatefile() as fp:
109 110 return fp.read(size)
110 111 except FileNotFoundError:
111 112 # File doesn't exist, so the current state is empty
112 113 return b''
113 114
114 115 @property
115 116 def docket(self):
116 117 if not self._docket:
117 118 if not self._use_dirstate_v2:
118 119 raise error.ProgrammingError(
119 120 b'dirstate only has a docket in v2 format'
120 121 )
121 122 self._docket = docketmod.DirstateDocket.parse(
122 123 self._readdirstatefile(), self._nodeconstants
123 124 )
124 125 return self._docket
125 126
126 127 def write_v2_no_append(self, tr, st, meta, packed):
127 128 old_docket = self.docket
128 129 new_docket = docketmod.DirstateDocket.with_new_uuid(
129 130 self.parents(), len(packed), meta
130 131 )
131 132 if old_docket.uuid == new_docket.uuid:
132 133 raise error.ProgrammingError(b'dirstate docket name collision')
133 134 data_filename = new_docket.data_filename()
134 135 self._opener.write(data_filename, packed)
135 136 # Write the new docket after the new data file has been
136 137 # written. Because `st` was opened with `atomictemp=True`,
137 138 # the actual `.hg/dirstate` file is only affected on close.
138 139 st.write(new_docket.serialize())
139 140 st.close()
140 141 # Remove the old data file after the new docket pointing to
141 142 # the new data file was written.
142 143 if old_docket.uuid:
143 144 data_filename = old_docket.data_filename()
144 145 unlink = lambda _tr=None: self._opener.unlink(data_filename)
145 146 if tr:
146 147 category = b"dirstate-v2-clean-" + old_docket.uuid
147 148 tr.addpostclose(category, unlink)
148 149 else:
149 150 unlink()
150 151 self._docket = new_docket
151 152
152 153 ### reading/setting parents
153 154
154 155 def parents(self):
155 156 if not self._parents:
156 157 if self._use_dirstate_v2:
157 158 self._parents = self.docket.parents
158 159 else:
159 160 read_len = self._nodelen * 2
160 161 st = self._readdirstatefile(read_len)
161 162 l = len(st)
162 163 if l == read_len:
163 164 self._parents = (
164 165 st[: self._nodelen],
165 166 st[self._nodelen : 2 * self._nodelen],
166 167 )
167 168 elif l == 0:
168 169 self._parents = (
169 170 self._nodeconstants.nullid,
170 171 self._nodeconstants.nullid,
171 172 )
172 173 else:
173 174 raise error.Abort(
174 175 _(b'working directory state appears damaged!')
175 176 )
176 177
177 178 return self._parents
178 179
179 180
180 181 class dirstatemap(_dirstatemapcommon):
181 182 """Map encapsulating the dirstate's contents.
182 183
183 184 The dirstate contains the following state:
184 185
185 186 - `identity` is the identity of the dirstate file, which can be used to
186 187 detect when changes have occurred to the dirstate file.
187 188
188 189 - `parents` is a pair containing the parents of the working copy. The
189 190 parents are updated by calling `setparents`.
190 191
191 192 - the state map maps filenames to tuples of (state, mode, size, mtime),
192 193 where state is a single character representing 'normal', 'added',
193 194 'removed', or 'merged'. It is read by treating the dirstate as a
194 195 dict. File state is updated by calling various methods (see each
195 196 documentation for details):
196 197
197 198 - `reset_state`,
198 199 - `set_tracked`
199 200 - `set_untracked`
200 201 - `set_clean`
201 202 - `set_possibly_dirty`
202 203
203 204 - `copymap` maps destination filenames to their source filename.
204 205
205 206 The dirstate also provides the following views onto the state:
206 207
207 208 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
208 209 form that they appear as in the dirstate.
209 210
210 211 - `dirfoldmap` is a dict mapping normalized directory names to the
211 212 denormalized form that they appear as in the dirstate.
212 213 """
213 214
214 215 ### Core data storage and access
215 216
216 217 @propertycache
217 218 def _map(self):
218 219 self._map = {}
219 220 self.read()
220 221 return self._map
221 222
222 223 @propertycache
223 224 def copymap(self):
224 225 self.copymap = {}
225 226 self._map
226 227 return self.copymap
227 228
228 229 def clear(self):
229 230 self._map.clear()
230 231 self.copymap.clear()
231 232 self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid)
232 233 util.clearcachedproperty(self, b"_dirs")
233 234 util.clearcachedproperty(self, b"_alldirs")
234 235 util.clearcachedproperty(self, b"filefoldmap")
235 236 util.clearcachedproperty(self, b"dirfoldmap")
236 237
237 238 def items(self):
238 239 return self._map.items()
239 240
240 241 # forward for python2,3 compat
241 242 iteritems = items
242 243
243 244 def debug_iter(self, all):
244 245 """
245 246 Return an iterator of (filename, state, mode, size, mtime) tuples
246 247
247 248 `all` is unused when Rust is not enabled
248 249 """
249 250 for (filename, item) in self.items():
250 251 yield (filename, item.state, item.mode, item.size, item.mtime)
251 252
252 253 def keys(self):
253 254 return self._map.keys()
254 255
255 256 ### reading/setting parents
256 257
257 258 def setparents(self, p1, p2, fold_p2=False):
258 259 self._parents = (p1, p2)
259 260 self._dirtyparents = True
260 261 copies = {}
261 262 if fold_p2:
262 263 for f, s in self._map.items():
263 264 # Discard "merged" markers when moving away from a merge state
264 265 if s.p2_info:
265 266 source = self.copymap.pop(f, None)
266 267 if source:
267 268 copies[f] = source
268 269 s.drop_merge_data()
269 270 return copies
270 271
271 272 ### disk interaction
272 273
273 274 def read(self):
274 275 # ignore HG_PENDING because identity is used only for writing
275 276 self.identity = util.filestat.frompath(
276 277 self._opener.join(self._filename)
277 278 )
278 279
280 testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
279 281 if self._use_dirstate_v2:
282
280 283 if not self.docket.uuid:
281 284 return
282 285 st = self._opener.read(self.docket.data_filename())
283 286 else:
284 287 st = self._readdirstatefile()
285 288
286 289 if not st:
287 290 return
288 291
289 292 # TODO: adjust this estimate for dirstate-v2
290 293 if util.safehasattr(parsers, b'dict_new_presized'):
291 294 # Make an estimate of the number of files in the dirstate based on
292 295 # its size. This trades wasting some memory for avoiding costly
293 296 # resizes. Each entry have a prefix of 17 bytes followed by one or
294 297 # two path names. Studies on various large-scale real-world repositories
295 298 # found 54 bytes a reasonable upper limit for the average path names.
296 299 # Copy entries are ignored for the sake of this estimate.
297 300 self._map = parsers.dict_new_presized(len(st) // 71)
298 301
299 302 # Python's garbage collector triggers a GC each time a certain number
300 303 # of container objects (the number being defined by
301 304 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
302 305 # for each file in the dirstate. The C version then immediately marks
303 306 # them as not to be tracked by the collector. However, this has no
304 307 # effect on when GCs are triggered, only on what objects the GC looks
305 308 # into. This means that O(number of files) GCs are unavoidable.
306 309 # Depending on when in the process's lifetime the dirstate is parsed,
307 310 # this can get very expensive. As a workaround, disable GC while
308 311 # parsing the dirstate.
309 312 #
310 313 # (we cannot decorate the function directly since it is in a C module)
311 314 if self._use_dirstate_v2:
312 315 p = self.docket.parents
313 316 meta = self.docket.tree_metadata
314 317 parse_dirstate = util.nogc(v2.parse_dirstate)
315 318 parse_dirstate(self._map, self.copymap, st, meta)
316 319 else:
317 320 parse_dirstate = util.nogc(parsers.parse_dirstate)
318 321 p = parse_dirstate(self._map, self.copymap, st)
319 322 if not self._dirtyparents:
320 323 self.setparents(*p)
321 324
322 325 # Avoid excess attribute lookups by fast pathing certain checks
323 326 self.__contains__ = self._map.__contains__
324 327 self.__getitem__ = self._map.__getitem__
325 328 self.get = self._map.get
326 329
327 330 def write(self, tr, st):
328 331 if self._use_dirstate_v2:
329 332 packed, meta = v2.pack_dirstate(self._map, self.copymap)
330 333 self.write_v2_no_append(tr, st, meta, packed)
331 334 else:
332 335 packed = parsers.pack_dirstate(
333 336 self._map, self.copymap, self.parents()
334 337 )
335 338 st.write(packed)
336 339 st.close()
337 340 self._dirtyparents = False
338 341
339 342 @propertycache
340 343 def identity(self):
341 344 self._map
342 345 return self.identity
343 346
344 347 ### code related to maintaining and accessing "extra" property
345 348 # (e.g. "has_dir")
346 349
347 350 def _dirs_incr(self, filename, old_entry=None):
348 351 """increment the dirstate counter if applicable"""
349 352 if (
350 353 old_entry is None or old_entry.removed
351 354 ) and "_dirs" in self.__dict__:
352 355 self._dirs.addpath(filename)
353 356 if old_entry is None and "_alldirs" in self.__dict__:
354 357 self._alldirs.addpath(filename)
355 358
356 359 def _dirs_decr(self, filename, old_entry=None, remove_variant=False):
357 360 """decrement the dirstate counter if applicable"""
358 361 if old_entry is not None:
359 362 if "_dirs" in self.__dict__ and not old_entry.removed:
360 363 self._dirs.delpath(filename)
361 364 if "_alldirs" in self.__dict__ and not remove_variant:
362 365 self._alldirs.delpath(filename)
363 366 elif remove_variant and "_alldirs" in self.__dict__:
364 367 self._alldirs.addpath(filename)
365 368 if "filefoldmap" in self.__dict__:
366 369 normed = util.normcase(filename)
367 370 self.filefoldmap.pop(normed, None)
368 371
369 372 @propertycache
370 373 def filefoldmap(self):
371 374 """Returns a dictionary mapping normalized case paths to their
372 375 non-normalized versions.
373 376 """
374 377 try:
375 378 makefilefoldmap = parsers.make_file_foldmap
376 379 except AttributeError:
377 380 pass
378 381 else:
379 382 return makefilefoldmap(
380 383 self._map, util.normcasespec, util.normcasefallback
381 384 )
382 385
383 386 f = {}
384 387 normcase = util.normcase
385 388 for name, s in self._map.items():
386 389 if not s.removed:
387 390 f[normcase(name)] = name
388 391 f[b'.'] = b'.' # prevents useless util.fspath() invocation
389 392 return f
390 393
391 394 @propertycache
392 395 def dirfoldmap(self):
393 396 f = {}
394 397 normcase = util.normcase
395 398 for name in self._dirs:
396 399 f[normcase(name)] = name
397 400 return f
398 401
399 402 def hastrackeddir(self, d):
400 403 """
401 404 Returns True if the dirstate contains a tracked (not removed) file
402 405 in this directory.
403 406 """
404 407 return d in self._dirs
405 408
406 409 def hasdir(self, d):
407 410 """
408 411 Returns True if the dirstate contains a file (tracked or removed)
409 412 in this directory.
410 413 """
411 414 return d in self._alldirs
412 415
413 416 @propertycache
414 417 def _dirs(self):
415 418 return pathutil.dirs(self._map, only_tracked=True)
416 419
417 420 @propertycache
418 421 def _alldirs(self):
419 422 return pathutil.dirs(self._map)
420 423
421 424 ### code related to manipulation of entries and copy-sources
422 425
423 426 def reset_state(
424 427 self,
425 428 filename,
426 429 wc_tracked=False,
427 430 p1_tracked=False,
428 431 p2_info=False,
429 432 has_meaningful_mtime=True,
430 433 parentfiledata=None,
431 434 ):
432 435 """Set a entry to a given state, diregarding all previous state
433 436
434 437 This is to be used by the part of the dirstate API dedicated to
435 438 adjusting the dirstate after a update/merge.
436 439
437 440 note: calling this might result to no entry existing at all if the
438 441 dirstate map does not see any point at having one for this file
439 442 anymore.
440 443 """
441 444 # copy information are now outdated
442 445 # (maybe new information should be in directly passed to this function)
443 446 self.copymap.pop(filename, None)
444 447
445 448 if not (p1_tracked or p2_info or wc_tracked):
446 449 old_entry = self._map.get(filename)
447 450 self._drop_entry(filename)
448 451 self._dirs_decr(filename, old_entry=old_entry)
449 452 return
450 453
451 454 old_entry = self._map.get(filename)
452 455 self._dirs_incr(filename, old_entry)
453 456 entry = DirstateItem(
454 457 wc_tracked=wc_tracked,
455 458 p1_tracked=p1_tracked,
456 459 p2_info=p2_info,
457 460 has_meaningful_mtime=has_meaningful_mtime,
458 461 parentfiledata=parentfiledata,
459 462 )
460 463 self._map[filename] = entry
461 464
462 465 def set_tracked(self, filename):
463 466 new = False
464 467 entry = self.get(filename)
465 468 if entry is None:
466 469 self._dirs_incr(filename)
467 470 entry = DirstateItem(
468 471 wc_tracked=True,
469 472 )
470 473
471 474 self._map[filename] = entry
472 475 new = True
473 476 elif not entry.tracked:
474 477 self._dirs_incr(filename, entry)
475 478 entry.set_tracked()
476 479 self._refresh_entry(filename, entry)
477 480 new = True
478 481 else:
479 482 # XXX This is probably overkill for more case, but we need this to
480 483 # fully replace the `normallookup` call with `set_tracked` one.
481 484 # Consider smoothing this in the future.
482 485 entry.set_possibly_dirty()
483 486 self._refresh_entry(filename, entry)
484 487 return new
485 488
486 489 def set_untracked(self, f):
487 490 """Mark a file as no longer tracked in the dirstate map"""
488 491 entry = self.get(f)
489 492 if entry is None:
490 493 return False
491 494 else:
492 495 self._dirs_decr(f, old_entry=entry, remove_variant=not entry.added)
493 496 if not entry.p2_info:
494 497 self.copymap.pop(f, None)
495 498 entry.set_untracked()
496 499 self._refresh_entry(f, entry)
497 500 return True
498 501
499 502 def set_clean(self, filename, mode, size, mtime):
500 503 """mark a file as back to a clean state"""
501 504 entry = self[filename]
502 505 size = size & rangemask
503 506 entry.set_clean(mode, size, mtime)
504 507 self._refresh_entry(filename, entry)
505 508 self.copymap.pop(filename, None)
506 509
507 510 def set_possibly_dirty(self, filename):
508 511 """record that the current state of the file on disk is unknown"""
509 512 entry = self[filename]
510 513 entry.set_possibly_dirty()
511 514 self._refresh_entry(filename, entry)
512 515
513 516 def _refresh_entry(self, f, entry):
514 517 """record updated state of an entry"""
515 518 if not entry.any_tracked:
516 519 self._map.pop(f, None)
517 520
518 521 def _drop_entry(self, f):
519 522 """remove any entry for file f
520 523
521 524 This should also drop associated copy information
522 525
523 526 The fact we actually need to drop it is the responsability of the caller"""
524 527 self._map.pop(f, None)
525 528 self.copymap.pop(f, None)
526 529
527 530
528 531 if rustmod is not None:
529 532
530 533 class dirstatemap(_dirstatemapcommon):
531 534
532 535 ### Core data storage and access
533 536
534 537 @propertycache
535 538 def _map(self):
536 539 """
537 540 Fills the Dirstatemap when called.
538 541 """
539 542 # ignore HG_PENDING because identity is used only for writing
540 543 self.identity = util.filestat.frompath(
541 544 self._opener.join(self._filename)
542 545 )
543 546
547 testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
544 548 if self._use_dirstate_v2:
545 549 if self.docket.uuid:
546 550 # TODO: use mmap when possible
547 551 data = self._opener.read(self.docket.data_filename())
548 552 else:
549 553 data = b''
550 554 self._map = rustmod.DirstateMap.new_v2(
551 555 data, self.docket.data_size, self.docket.tree_metadata
552 556 )
553 557 parents = self.docket.parents
554 558 else:
555 559 self._map, parents = rustmod.DirstateMap.new_v1(
556 560 self._readdirstatefile()
557 561 )
558 562
559 563 if parents and not self._dirtyparents:
560 564 self.setparents(*parents)
561 565
562 566 self.__contains__ = self._map.__contains__
563 567 self.__getitem__ = self._map.__getitem__
564 568 self.get = self._map.get
565 569 return self._map
566 570
567 571 @property
568 572 def copymap(self):
569 573 return self._map.copymap()
570 574
571 575 def debug_iter(self, all):
572 576 """
573 577 Return an iterator of (filename, state, mode, size, mtime) tuples
574 578
575 579 `all`: also include with `state == b' '` dirstate tree nodes that
576 580 don't have an associated `DirstateItem`.
577 581
578 582 """
579 583 return self._map.debug_iter(all)
580 584
581 585 def clear(self):
582 586 self._map.clear()
583 587 self.setparents(
584 588 self._nodeconstants.nullid, self._nodeconstants.nullid
585 589 )
586 590 util.clearcachedproperty(self, b"_dirs")
587 591 util.clearcachedproperty(self, b"_alldirs")
588 592 util.clearcachedproperty(self, b"dirfoldmap")
589 593
590 594 def items(self):
591 595 return self._map.items()
592 596
593 597 # forward for python2,3 compat
594 598 iteritems = items
595 599
596 600 def keys(self):
597 601 return iter(self._map)
598 602
599 603 ### reading/setting parents
600 604
601 605 def setparents(self, p1, p2, fold_p2=False):
602 606 self._parents = (p1, p2)
603 607 self._dirtyparents = True
604 608 copies = {}
605 609 if fold_p2:
606 610 copies = self._map.setparents_fixup()
607 611 return copies
608 612
609 613 ### disk interaction
610 614
611 615 @propertycache
612 616 def identity(self):
613 617 self._map
614 618 return self.identity
615 619
616 620 def write(self, tr, st):
617 621 if not self._use_dirstate_v2:
618 622 p1, p2 = self.parents()
619 623 packed = self._map.write_v1(p1, p2)
620 624 st.write(packed)
621 625 st.close()
622 626 self._dirtyparents = False
623 627 return
624 628
625 629 # We can only append to an existing data file if there is one
626 630 write_mode = self._write_mode
627 631 if self.docket.uuid is None:
628 632 write_mode = WRITE_MODE_FORCE_NEW
629 633 packed, meta, append = self._map.write_v2(write_mode)
630 634 if append:
631 635 docket = self.docket
632 636 data_filename = docket.data_filename()
633 637 with self._opener(data_filename, b'r+b') as fp:
634 638 fp.seek(docket.data_size)
635 639 assert fp.tell() == docket.data_size
636 640 written = fp.write(packed)
637 641 if written is not None: # py2 may return None
638 642 assert written == len(packed), (written, len(packed))
639 643 docket.data_size += len(packed)
640 644 docket.parents = self.parents()
641 645 docket.tree_metadata = meta
642 646 st.write(docket.serialize())
643 647 st.close()
644 648 else:
645 649 self.write_v2_no_append(tr, st, meta, packed)
646 650 # Reload from the newly-written file
647 651 util.clearcachedproperty(self, b"_map")
648 652 self._dirtyparents = False
649 653
650 654 ### code related to maintaining and accessing "extra" property
651 655 # (e.g. "has_dir")
652 656
653 657 @propertycache
654 658 def filefoldmap(self):
655 659 """Returns a dictionary mapping normalized case paths to their
656 660 non-normalized versions.
657 661 """
658 662 return self._map.filefoldmapasdict()
659 663
660 664 def hastrackeddir(self, d):
661 665 return self._map.hastrackeddir(d)
662 666
663 667 def hasdir(self, d):
664 668 return self._map.hasdir(d)
665 669
666 670 @propertycache
667 671 def dirfoldmap(self):
668 672 f = {}
669 673 normcase = util.normcase
670 674 for name in self._map.tracked_dirs():
671 675 f[normcase(name)] = name
672 676 return f
673 677
674 678 ### code related to manipulation of entries and copy-sources
675 679
676 680 def set_tracked(self, f):
677 681 return self._map.set_tracked(f)
678 682
679 683 def set_untracked(self, f):
680 684 return self._map.set_untracked(f)
681 685
682 686 def set_clean(self, filename, mode, size, mtime):
683 687 self._map.set_clean(filename, mode, size, mtime)
684 688
685 689 def set_possibly_dirty(self, f):
686 690 self._map.set_possibly_dirty(f)
687 691
688 692 def reset_state(
689 693 self,
690 694 filename,
691 695 wc_tracked=False,
692 696 p1_tracked=False,
693 697 p2_info=False,
694 698 has_meaningful_mtime=True,
695 699 parentfiledata=None,
696 700 ):
697 701 return self._map.reset_state(
698 702 filename,
699 703 wc_tracked,
700 704 p1_tracked,
701 705 p2_info,
702 706 has_meaningful_mtime,
703 707 parentfiledata,
704 708 )
@@ -1,609 +1,615 b''
1 1 use crate::changelog::Changelog;
2 2 use crate::config::{Config, ConfigError, ConfigParseError};
3 3 use crate::dirstate::DirstateParents;
4 4 use crate::dirstate_tree::dirstate_map::DirstateMapWriteMode;
5 5 use crate::dirstate_tree::on_disk::Docket as DirstateDocket;
6 6 use crate::dirstate_tree::owning::OwningDirstateMap;
7 7 use crate::errors::HgResultExt;
8 8 use crate::errors::{HgError, IoResultExt};
9 9 use crate::lock::{try_with_lock_no_wait, LockError};
10 10 use crate::manifest::{Manifest, Manifestlog};
11 11 use crate::revlog::filelog::Filelog;
12 12 use crate::revlog::revlog::RevlogError;
13 use crate::utils::debug::debug_wait_for_file_or_print;
13 14 use crate::utils::files::get_path_from_bytes;
14 15 use crate::utils::hg_path::HgPath;
15 16 use crate::utils::SliceExt;
16 17 use crate::vfs::{is_dir, is_file, Vfs};
17 18 use crate::{requirements, NodePrefix};
18 19 use crate::{DirstateError, Revision};
19 20 use std::cell::{Ref, RefCell, RefMut};
20 21 use std::collections::HashSet;
21 22 use std::io::Seek;
22 23 use std::io::SeekFrom;
23 24 use std::io::Write as IoWrite;
24 25 use std::path::{Path, PathBuf};
25 26
26 27 /// A repository on disk
27 28 pub struct Repo {
28 29 working_directory: PathBuf,
29 30 dot_hg: PathBuf,
30 31 store: PathBuf,
31 32 requirements: HashSet<String>,
32 33 config: Config,
33 34 dirstate_parents: LazyCell<DirstateParents>,
34 35 dirstate_data_file_uuid: LazyCell<Option<Vec<u8>>>,
35 36 dirstate_map: LazyCell<OwningDirstateMap>,
36 37 changelog: LazyCell<Changelog>,
37 38 manifestlog: LazyCell<Manifestlog>,
38 39 }
39 40
40 41 #[derive(Debug, derive_more::From)]
41 42 pub enum RepoError {
42 43 NotFound {
43 44 at: PathBuf,
44 45 },
45 46 #[from]
46 47 ConfigParseError(ConfigParseError),
47 48 #[from]
48 49 Other(HgError),
49 50 }
50 51
51 52 impl From<ConfigError> for RepoError {
52 53 fn from(error: ConfigError) -> Self {
53 54 match error {
54 55 ConfigError::Parse(error) => error.into(),
55 56 ConfigError::Other(error) => error.into(),
56 57 }
57 58 }
58 59 }
59 60
60 61 impl Repo {
61 62 /// tries to find nearest repository root in current working directory or
62 63 /// its ancestors
63 64 pub fn find_repo_root() -> Result<PathBuf, RepoError> {
64 65 let current_directory = crate::utils::current_dir()?;
65 66 // ancestors() is inclusive: it first yields `current_directory`
66 67 // as-is.
67 68 for ancestor in current_directory.ancestors() {
68 69 if is_dir(ancestor.join(".hg"))? {
69 70 return Ok(ancestor.to_path_buf());
70 71 }
71 72 }
72 73 return Err(RepoError::NotFound {
73 74 at: current_directory,
74 75 });
75 76 }
76 77
77 78 /// Find a repository, either at the given path (which must contain a `.hg`
78 79 /// sub-directory) or by searching the current directory and its
79 80 /// ancestors.
80 81 ///
81 82 /// A method with two very different "modes" like this usually a code smell
82 83 /// to make two methods instead, but in this case an `Option` is what rhg
83 84 /// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
84 85 /// Having two methods would just move that `if` to almost all callers.
85 86 pub fn find(
86 87 config: &Config,
87 88 explicit_path: Option<PathBuf>,
88 89 ) -> Result<Self, RepoError> {
89 90 if let Some(root) = explicit_path {
90 91 if is_dir(root.join(".hg"))? {
91 92 Self::new_at_path(root.to_owned(), config)
92 93 } else if is_file(&root)? {
93 94 Err(HgError::unsupported("bundle repository").into())
94 95 } else {
95 96 Err(RepoError::NotFound {
96 97 at: root.to_owned(),
97 98 })
98 99 }
99 100 } else {
100 101 let root = Self::find_repo_root()?;
101 102 Self::new_at_path(root, config)
102 103 }
103 104 }
104 105
105 106 /// To be called after checking that `.hg` is a sub-directory
106 107 fn new_at_path(
107 108 working_directory: PathBuf,
108 109 config: &Config,
109 110 ) -> Result<Self, RepoError> {
110 111 let dot_hg = working_directory.join(".hg");
111 112
112 113 let mut repo_config_files = Vec::new();
113 114 repo_config_files.push(dot_hg.join("hgrc"));
114 115 repo_config_files.push(dot_hg.join("hgrc-not-shared"));
115 116
116 117 let hg_vfs = Vfs { base: &dot_hg };
117 118 let mut reqs = requirements::load_if_exists(hg_vfs)?;
118 119 let relative =
119 120 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
120 121 let shared =
121 122 reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
122 123
123 124 // From `mercurial/localrepo.py`:
124 125 //
125 126 // if .hg/requires contains the sharesafe requirement, it means
126 127 // there exists a `.hg/store/requires` too and we should read it
127 128 // NOTE: presence of SHARESAFE_REQUIREMENT imply that store requirement
128 129 // is present. We never write SHARESAFE_REQUIREMENT for a repo if store
129 130 // is not present, refer checkrequirementscompat() for that
130 131 //
131 132 // However, if SHARESAFE_REQUIREMENT is not present, it means that the
132 133 // repository was shared the old way. We check the share source
133 134 // .hg/requires for SHARESAFE_REQUIREMENT to detect whether the
134 135 // current repository needs to be reshared
135 136 let share_safe = reqs.contains(requirements::SHARESAFE_REQUIREMENT);
136 137
137 138 let store_path;
138 139 if !shared {
139 140 store_path = dot_hg.join("store");
140 141 } else {
141 142 let bytes = hg_vfs.read("sharedpath")?;
142 143 let mut shared_path =
143 144 get_path_from_bytes(bytes.trim_end_matches(|b| b == b'\n'))
144 145 .to_owned();
145 146 if relative {
146 147 shared_path = dot_hg.join(shared_path)
147 148 }
148 149 if !is_dir(&shared_path)? {
149 150 return Err(HgError::corrupted(format!(
150 151 ".hg/sharedpath points to nonexistent directory {}",
151 152 shared_path.display()
152 153 ))
153 154 .into());
154 155 }
155 156
156 157 store_path = shared_path.join("store");
157 158
158 159 let source_is_share_safe =
159 160 requirements::load(Vfs { base: &shared_path })?
160 161 .contains(requirements::SHARESAFE_REQUIREMENT);
161 162
162 163 if share_safe != source_is_share_safe {
163 164 return Err(HgError::unsupported("share-safe mismatch").into());
164 165 }
165 166
166 167 if share_safe {
167 168 repo_config_files.insert(0, shared_path.join("hgrc"))
168 169 }
169 170 }
170 171 if share_safe {
171 172 reqs.extend(requirements::load(Vfs { base: &store_path })?);
172 173 }
173 174
174 175 let repo_config = if std::env::var_os("HGRCSKIPREPO").is_none() {
175 176 config.combine_with_repo(&repo_config_files)?
176 177 } else {
177 178 config.clone()
178 179 };
179 180
180 181 let repo = Self {
181 182 requirements: reqs,
182 183 working_directory,
183 184 store: store_path,
184 185 dot_hg,
185 186 config: repo_config,
186 187 dirstate_parents: LazyCell::new(),
187 188 dirstate_data_file_uuid: LazyCell::new(),
188 189 dirstate_map: LazyCell::new(),
189 190 changelog: LazyCell::new(),
190 191 manifestlog: LazyCell::new(),
191 192 };
192 193
193 194 requirements::check(&repo)?;
194 195
195 196 Ok(repo)
196 197 }
197 198
198 199 pub fn working_directory_path(&self) -> &Path {
199 200 &self.working_directory
200 201 }
201 202
202 203 pub fn requirements(&self) -> &HashSet<String> {
203 204 &self.requirements
204 205 }
205 206
206 207 pub fn config(&self) -> &Config {
207 208 &self.config
208 209 }
209 210
210 211 /// For accessing repository files (in `.hg`), except for the store
211 212 /// (`.hg/store`).
212 213 pub fn hg_vfs(&self) -> Vfs<'_> {
213 214 Vfs { base: &self.dot_hg }
214 215 }
215 216
216 217 /// For accessing repository store files (in `.hg/store`)
217 218 pub fn store_vfs(&self) -> Vfs<'_> {
218 219 Vfs { base: &self.store }
219 220 }
220 221
221 222 /// For accessing the working copy
222 223 pub fn working_directory_vfs(&self) -> Vfs<'_> {
223 224 Vfs {
224 225 base: &self.working_directory,
225 226 }
226 227 }
227 228
228 229 pub fn try_with_wlock_no_wait<R>(
229 230 &self,
230 231 f: impl FnOnce() -> R,
231 232 ) -> Result<R, LockError> {
232 233 try_with_lock_no_wait(self.hg_vfs(), "wlock", f)
233 234 }
234 235
235 236 pub fn has_dirstate_v2(&self) -> bool {
236 237 self.requirements
237 238 .contains(requirements::DIRSTATE_V2_REQUIREMENT)
238 239 }
239 240
240 241 pub fn has_sparse(&self) -> bool {
241 242 self.requirements.contains(requirements::SPARSE_REQUIREMENT)
242 243 }
243 244
244 245 pub fn has_narrow(&self) -> bool {
245 246 self.requirements.contains(requirements::NARROW_REQUIREMENT)
246 247 }
247 248
248 249 pub fn has_nodemap(&self) -> bool {
249 250 self.requirements
250 251 .contains(requirements::NODEMAP_REQUIREMENT)
251 252 }
252 253
253 254 fn dirstate_file_contents(&self) -> Result<Vec<u8>, HgError> {
254 255 Ok(self
255 256 .hg_vfs()
256 257 .read("dirstate")
257 258 .io_not_found_as_none()?
258 259 .unwrap_or(Vec::new()))
259 260 }
260 261
261 262 pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> {
262 263 Ok(*self
263 264 .dirstate_parents
264 265 .get_or_init(|| self.read_dirstate_parents())?)
265 266 }
266 267
267 268 fn read_dirstate_parents(&self) -> Result<DirstateParents, HgError> {
268 269 let dirstate = self.dirstate_file_contents()?;
269 270 let parents = if dirstate.is_empty() {
270 271 if self.has_dirstate_v2() {
271 272 self.dirstate_data_file_uuid.set(None);
272 273 }
273 274 DirstateParents::NULL
274 275 } else if self.has_dirstate_v2() {
275 276 let docket =
276 277 crate::dirstate_tree::on_disk::read_docket(&dirstate)?;
277 278 self.dirstate_data_file_uuid
278 279 .set(Some(docket.uuid.to_owned()));
279 280 docket.parents()
280 281 } else {
281 282 crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?
282 283 .clone()
283 284 };
284 285 self.dirstate_parents.set(parents);
285 286 Ok(parents)
286 287 }
287 288
288 289 fn read_dirstate_data_file_uuid(
289 290 &self,
290 291 ) -> Result<Option<Vec<u8>>, HgError> {
291 292 assert!(
292 293 self.has_dirstate_v2(),
293 294 "accessing dirstate data file ID without dirstate-v2"
294 295 );
295 296 let dirstate = self.dirstate_file_contents()?;
296 297 if dirstate.is_empty() {
297 298 self.dirstate_parents.set(DirstateParents::NULL);
298 299 Ok(None)
299 300 } else {
300 301 let docket =
301 302 crate::dirstate_tree::on_disk::read_docket(&dirstate)?;
302 303 self.dirstate_parents.set(docket.parents());
303 304 Ok(Some(docket.uuid.to_owned()))
304 305 }
305 306 }
306 307
307 308 fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> {
308 309 if self.has_dirstate_v2() {
309 310 self.read_docket_and_data_file()
310 311 } else {
312 debug_wait_for_file_or_print(
313 self.config(),
314 "dirstate.pre-read-file",
315 );
311 316 let dirstate_file_contents = self.dirstate_file_contents()?;
312 317 if dirstate_file_contents.is_empty() {
313 318 self.dirstate_parents.set(DirstateParents::NULL);
314 319 Ok(OwningDirstateMap::new_empty(Vec::new()))
315 320 } else {
316 321 let (map, parents) =
317 322 OwningDirstateMap::new_v1(dirstate_file_contents)?;
318 323 self.dirstate_parents.set(parents);
319 324 Ok(map)
320 325 }
321 326 }
322 327 }
323 328
324 329 fn read_docket_and_data_file(
325 330 &self,
326 331 ) -> Result<OwningDirstateMap, DirstateError> {
332 debug_wait_for_file_or_print(self.config(), "dirstate.pre-read-file");
327 333 let dirstate_file_contents = self.dirstate_file_contents()?;
328 334 if dirstate_file_contents.is_empty() {
329 335 self.dirstate_parents.set(DirstateParents::NULL);
330 336 self.dirstate_data_file_uuid.set(None);
331 337 return Ok(OwningDirstateMap::new_empty(Vec::new()));
332 338 }
333 339 let docket = crate::dirstate_tree::on_disk::read_docket(
334 340 &dirstate_file_contents,
335 341 )?;
336 342 self.dirstate_parents.set(docket.parents());
337 343 self.dirstate_data_file_uuid
338 344 .set(Some(docket.uuid.to_owned()));
339 345 let data_size = docket.data_size();
340 346 let metadata = docket.tree_metadata();
341 347 let mut map = if crate::vfs::is_on_nfs_mount(docket.data_filename()) {
342 348 // Don't mmap on NFS to prevent `SIGBUS` error on deletion
343 349 OwningDirstateMap::new_v2(
344 350 self.hg_vfs().read(docket.data_filename())?,
345 351 data_size,
346 352 metadata,
347 353 )
348 354 } else if let Some(data_mmap) = self
349 355 .hg_vfs()
350 356 .mmap_open(docket.data_filename())
351 357 .io_not_found_as_none()?
352 358 {
353 359 OwningDirstateMap::new_v2(data_mmap, data_size, metadata)
354 360 } else {
355 361 OwningDirstateMap::new_v2(Vec::new(), data_size, metadata)
356 362 }?;
357 363
358 364 let write_mode_config = self
359 365 .config()
360 366 .get_str(b"devel", b"dirstate.v2.data_update_mode")
361 367 .unwrap_or(Some("auto"))
362 368 .unwrap_or("auto"); // don't bother for devel options
363 369 let write_mode = match write_mode_config {
364 370 "auto" => DirstateMapWriteMode::Auto,
365 371 "force-new" => DirstateMapWriteMode::ForceNewDataFile,
366 372 "force-append" => DirstateMapWriteMode::ForceAppend,
367 373 _ => DirstateMapWriteMode::Auto,
368 374 };
369 375
370 376 map.with_dmap_mut(|m| m.set_write_mode(write_mode));
371 377
372 378 Ok(map)
373 379 }
374 380
375 381 pub fn dirstate_map(
376 382 &self,
377 383 ) -> Result<Ref<OwningDirstateMap>, DirstateError> {
378 384 self.dirstate_map.get_or_init(|| self.new_dirstate_map())
379 385 }
380 386
381 387 pub fn dirstate_map_mut(
382 388 &self,
383 389 ) -> Result<RefMut<OwningDirstateMap>, DirstateError> {
384 390 self.dirstate_map
385 391 .get_mut_or_init(|| self.new_dirstate_map())
386 392 }
387 393
388 394 fn new_changelog(&self) -> Result<Changelog, HgError> {
389 395 Changelog::open(&self.store_vfs(), self.has_nodemap())
390 396 }
391 397
392 398 pub fn changelog(&self) -> Result<Ref<Changelog>, HgError> {
393 399 self.changelog.get_or_init(|| self.new_changelog())
394 400 }
395 401
396 402 pub fn changelog_mut(&self) -> Result<RefMut<Changelog>, HgError> {
397 403 self.changelog.get_mut_or_init(|| self.new_changelog())
398 404 }
399 405
400 406 fn new_manifestlog(&self) -> Result<Manifestlog, HgError> {
401 407 Manifestlog::open(&self.store_vfs(), self.has_nodemap())
402 408 }
403 409
404 410 pub fn manifestlog(&self) -> Result<Ref<Manifestlog>, HgError> {
405 411 self.manifestlog.get_or_init(|| self.new_manifestlog())
406 412 }
407 413
408 414 pub fn manifestlog_mut(&self) -> Result<RefMut<Manifestlog>, HgError> {
409 415 self.manifestlog.get_mut_or_init(|| self.new_manifestlog())
410 416 }
411 417
412 418 /// Returns the manifest of the *changeset* with the given node ID
413 419 pub fn manifest_for_node(
414 420 &self,
415 421 node: impl Into<NodePrefix>,
416 422 ) -> Result<Manifest, RevlogError> {
417 423 self.manifestlog()?.data_for_node(
418 424 self.changelog()?
419 425 .data_for_node(node.into())?
420 426 .manifest_node()?
421 427 .into(),
422 428 )
423 429 }
424 430
425 431 /// Returns the manifest of the *changeset* with the given revision number
426 432 pub fn manifest_for_rev(
427 433 &self,
428 434 revision: Revision,
429 435 ) -> Result<Manifest, RevlogError> {
430 436 self.manifestlog()?.data_for_node(
431 437 self.changelog()?
432 438 .data_for_rev(revision)?
433 439 .manifest_node()?
434 440 .into(),
435 441 )
436 442 }
437 443
438 444 pub fn has_subrepos(&self) -> Result<bool, DirstateError> {
439 445 if let Some(entry) = self.dirstate_map()?.get(HgPath::new(".hgsub"))? {
440 446 Ok(entry.tracked())
441 447 } else {
442 448 Ok(false)
443 449 }
444 450 }
445 451
446 452 pub fn filelog(&self, path: &HgPath) -> Result<Filelog, HgError> {
447 453 Filelog::open(self, path)
448 454 }
449 455
450 456 /// Write to disk any updates that were made through `dirstate_map_mut`.
451 457 ///
452 458 /// The "wlock" must be held while calling this.
453 459 /// See for example `try_with_wlock_no_wait`.
454 460 ///
455 461 /// TODO: have a `WritableRepo` type only accessible while holding the
456 462 /// lock?
457 463 pub fn write_dirstate(&self) -> Result<(), DirstateError> {
458 464 let map = self.dirstate_map()?;
459 465 // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if
460 466 // it’s unset
461 467 let parents = self.dirstate_parents()?;
462 468 let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() {
463 469 let uuid_opt = self
464 470 .dirstate_data_file_uuid
465 471 .get_or_init(|| self.read_dirstate_data_file_uuid())?;
466 472 let uuid_opt = uuid_opt.as_ref();
467 473 let write_mode = if uuid_opt.is_some() {
468 474 DirstateMapWriteMode::Auto
469 475 } else {
470 476 DirstateMapWriteMode::ForceNewDataFile
471 477 };
472 478 let (data, tree_metadata, append, old_data_size) =
473 479 map.pack_v2(write_mode)?;
474 480
475 481 // Reuse the uuid, or generate a new one, keeping the old for
476 482 // deletion.
477 483 let (uuid, old_uuid) = match uuid_opt {
478 484 Some(uuid) => {
479 485 let as_str = std::str::from_utf8(uuid)
480 486 .map_err(|_| {
481 487 HgError::corrupted(
482 488 "non-UTF-8 dirstate data file ID",
483 489 )
484 490 })?
485 491 .to_owned();
486 492 if append {
487 493 (as_str, None)
488 494 } else {
489 495 (DirstateDocket::new_uid(), Some(as_str))
490 496 }
491 497 }
492 498 None => (DirstateDocket::new_uid(), None),
493 499 };
494 500
495 501 let data_filename = format!("dirstate.{}", uuid);
496 502 let data_filename = self.hg_vfs().join(data_filename);
497 503 let mut options = std::fs::OpenOptions::new();
498 504 options.write(true);
499 505
500 506 // Why are we not using the O_APPEND flag when appending?
501 507 //
502 508 // - O_APPEND makes it trickier to deal with garbage at the end of
503 509 // the file, left by a previous uncommitted transaction. By
504 510 // starting the write at [old_data_size] we make sure we erase
505 511 // all such garbage.
506 512 //
507 513 // - O_APPEND requires to special-case 0-byte writes, whereas we
508 514 // don't need that.
509 515 //
510 516 // - Some OSes have bugs in implementation O_APPEND:
511 517 // revlog.py talks about a Solaris bug, but we also saw some ZFS
512 518 // bug: https://github.com/openzfs/zfs/pull/3124,
513 519 // https://github.com/openzfs/zfs/issues/13370
514 520 //
515 521 if !append {
516 522 log::trace!("creating a new dirstate data file");
517 523 options.create_new(true);
518 524 } else {
519 525 log::trace!("appending to the dirstate data file");
520 526 }
521 527
522 528 let data_size = (|| {
523 529 // TODO: loop and try another random ID if !append and this
524 530 // returns `ErrorKind::AlreadyExists`? Collision chance of two
525 531 // random IDs is one in 2**32
526 532 let mut file = options.open(&data_filename)?;
527 533 if append {
528 534 file.seek(SeekFrom::Start(old_data_size as u64))?;
529 535 }
530 536 file.write_all(&data)?;
531 537 file.flush()?;
532 538 file.seek(SeekFrom::Current(0))
533 539 })()
534 540 .when_writing_file(&data_filename)?;
535 541
536 542 let packed_dirstate = DirstateDocket::serialize(
537 543 parents,
538 544 tree_metadata,
539 545 data_size,
540 546 uuid.as_bytes(),
541 547 )
542 548 .map_err(|_: std::num::TryFromIntError| {
543 549 HgError::corrupted("overflow in dirstate docket serialization")
544 550 })?;
545 551
546 552 (packed_dirstate, old_uuid)
547 553 } else {
548 554 (map.pack_v1(parents)?, None)
549 555 };
550 556
551 557 let vfs = self.hg_vfs();
552 558 vfs.atomic_write("dirstate", &packed_dirstate)?;
553 559 if let Some(uuid) = old_uuid_to_remove {
554 560 // Remove the old data file after the new docket pointing to the
555 561 // new data file was written.
556 562 vfs.remove_file(format!("dirstate.{}", uuid))?;
557 563 }
558 564 Ok(())
559 565 }
560 566 }
561 567
562 568 /// Lazily-initialized component of `Repo` with interior mutability
563 569 ///
564 570 /// This differs from `OnceCell` in that the value can still be "deinitialized"
565 571 /// later by setting its inner `Option` to `None`. It also takes the
566 572 /// initialization function as an argument when the value is requested, not
567 573 /// when the instance is created.
568 574 struct LazyCell<T> {
569 575 value: RefCell<Option<T>>,
570 576 }
571 577
572 578 impl<T> LazyCell<T> {
573 579 fn new() -> Self {
574 580 Self {
575 581 value: RefCell::new(None),
576 582 }
577 583 }
578 584
579 585 fn set(&self, value: T) {
580 586 *self.value.borrow_mut() = Some(value)
581 587 }
582 588
583 589 fn get_or_init<E>(
584 590 &self,
585 591 init: impl Fn() -> Result<T, E>,
586 592 ) -> Result<Ref<T>, E> {
587 593 let mut borrowed = self.value.borrow();
588 594 if borrowed.is_none() {
589 595 drop(borrowed);
590 596 // Only use `borrow_mut` if it is really needed to avoid panic in
591 597 // case there is another outstanding borrow but mutation is not
592 598 // needed.
593 599 *self.value.borrow_mut() = Some(init()?);
594 600 borrowed = self.value.borrow()
595 601 }
596 602 Ok(Ref::map(borrowed, |option| option.as_ref().unwrap()))
597 603 }
598 604
599 605 fn get_mut_or_init<E>(
600 606 &self,
601 607 init: impl Fn() -> Result<T, E>,
602 608 ) -> Result<RefMut<T>, E> {
603 609 let mut borrowed = self.value.borrow_mut();
604 610 if borrowed.is_none() {
605 611 *borrowed = Some(init()?);
606 612 }
607 613 Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap()))
608 614 }
609 615 }
@@ -1,81 +1,87 b''
1 1 //! Utils for debugging hg-core
2 2
3 3 use crate::config::Config;
4 4
5 5 /// Write the file path given by the config option `devel.<config_option>` with
6 6 /// the suffix `.waiting`, then wait for the file path given by the
7 7 /// config option `devel.<config_option>` to appear on disk
8 8 /// up to `devel.<config_option>-timeout` seconds.
9 9 /// Note that the timeout may be higher because we scale it if global
10 10 /// `run-tests` timeouts are raised to prevent flakiness on slower hardware.
11 11 ///
12 12 /// Useful for testing race conditions.
13 13 pub fn debug_wait_for_file(
14 14 config: &Config,
15 15 config_option: &str,
16 16 ) -> Result<(), String> {
17 17 let path_opt = format!("sync.{config_option}");
18 18 let file_path = match config.get_str(b"devel", path_opt.as_bytes()).ok() {
19 19 Some(Some(file_path)) => file_path,
20 20 _ => return Ok(()),
21 21 };
22 22
23 23 // TODO make it so `configitems` is shared between Rust and Python so that
24 24 // defaults work out of the box, etc.
25 25 let default_timeout = 2;
26 26 let timeout_opt = format!("sync.{config_option}-timeout");
27 27 let timeout_seconds =
28 28 match config.get_u32(b"devel", timeout_opt.as_bytes()) {
29 29 Ok(Some(timeout)) => timeout,
30 30 Err(e) => {
31 31 log::debug!("{e}");
32 32 default_timeout
33 33 }
34 34 _ => default_timeout,
35 35 };
36 36 let timeout_seconds = timeout_seconds as u64;
37 37
38 38 log::debug!(
39 39 "Config option `{config_option}` found, \
40 40 waiting for file `{file_path}` to be created"
41 41 );
42 42 std::fs::File::create(format!("{file_path}.waiting")).ok();
43 43 // If the test timeout have been extended, scale the timer relative
44 44 // to the normal timing.
45 45 let global_default_timeout: u64 = std::env::var("HGTEST_TIMEOUT_DEFAULT")
46 46 .map(|t| t.parse())
47 47 .unwrap_or(Ok(0))
48 48 .unwrap();
49 49 let global_timeout_override: u64 = std::env::var("HGTEST_TIMEOUT")
50 50 .map(|t| t.parse())
51 51 .unwrap_or(Ok(0))
52 52 .unwrap();
53 53 let timeout_seconds = if global_default_timeout < global_timeout_override {
54 54 timeout_seconds * global_timeout_override / global_default_timeout
55 55 } else {
56 56 timeout_seconds
57 57 };
58 58 let timeout = std::time::Duration::from_secs(timeout_seconds);
59 59
60 60 let start = std::time::Instant::now();
61 61 let path = std::path::Path::new(file_path);
62 62 let mut found = false;
63 63 while start.elapsed() < timeout {
64 64 if path.exists() {
65 65 log::debug!("File `{file_path}` was created");
66 66 found = true;
67 67 break;
68 68 } else {
69 69 std::thread::sleep(std::time::Duration::from_millis(10));
70 70 }
71 71 }
72 72 if !found {
73 73 let msg = format!(
74 74 "File `{file_path}` set by `{config_option}` was not found \
75 75 within the allocated {timeout_seconds} seconds timeout"
76 76 );
77 77 Err(msg)
78 78 } else {
79 79 Ok(())
80 80 }
81 81 }
82
83 pub fn debug_wait_for_file_or_print(config: &Config, config_option: &str) {
84 if let Err(e) = debug_wait_for_file(&config, config_option) {
85 eprintln!("{e}");
86 };
87 }
General Comments 0
You need to be logged in to leave comments. Login now