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