##// END OF EJS Templates
partial-merge: add support for `.args` config (`$local` etc.)...
Martin von Zweigbergk -
r49839:9dfbea54 default
parent child Browse files
Show More
@@ -1,2740 +1,2748 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import functools
10 10 import re
11 11
12 12 from . import (
13 13 encoding,
14 14 error,
15 15 )
16 16
17 17
18 18 def loadconfigtable(ui, extname, configtable):
19 19 """update config item known to the ui with the extension ones"""
20 20 for section, items in sorted(configtable.items()):
21 21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 22 knownkeys = set(knownitems)
23 23 newkeys = set(items)
24 24 for key in sorted(knownkeys & newkeys):
25 25 msg = b"extension '%s' overwrite config item '%s.%s'"
26 26 msg %= (extname, section, key)
27 27 ui.develwarn(msg, config=b'warn-config')
28 28
29 29 knownitems.update(items)
30 30
31 31
32 32 class configitem:
33 33 """represent a known config item
34 34
35 35 :section: the official config section where to find this item,
36 36 :name: the official name within the section,
37 37 :default: default value for this item,
38 38 :alias: optional list of tuples as alternatives,
39 39 :generic: this is a generic definition, match name using regular expression.
40 40 """
41 41
42 42 def __init__(
43 43 self,
44 44 section,
45 45 name,
46 46 default=None,
47 47 alias=(),
48 48 generic=False,
49 49 priority=0,
50 50 experimental=False,
51 51 ):
52 52 self.section = section
53 53 self.name = name
54 54 self.default = default
55 55 self.alias = list(alias)
56 56 self.generic = generic
57 57 self.priority = priority
58 58 self.experimental = experimental
59 59 self._re = None
60 60 if generic:
61 61 self._re = re.compile(self.name)
62 62
63 63
64 64 class itemregister(dict):
65 65 """A specialized dictionary that can handle wild-card selection"""
66 66
67 67 def __init__(self):
68 68 super(itemregister, self).__init__()
69 69 self._generics = set()
70 70
71 71 def update(self, other):
72 72 super(itemregister, self).update(other)
73 73 self._generics.update(other._generics)
74 74
75 75 def __setitem__(self, key, item):
76 76 super(itemregister, self).__setitem__(key, item)
77 77 if item.generic:
78 78 self._generics.add(item)
79 79
80 80 def get(self, key):
81 81 baseitem = super(itemregister, self).get(key)
82 82 if baseitem is not None and not baseitem.generic:
83 83 return baseitem
84 84
85 85 # search for a matching generic item
86 86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 87 for item in generics:
88 88 # we use 'match' instead of 'search' to make the matching simpler
89 89 # for people unfamiliar with regular expression. Having the match
90 90 # rooted to the start of the string will produce less surprising
91 91 # result for user writing simple regex for sub-attribute.
92 92 #
93 93 # For example using "color\..*" match produces an unsurprising
94 94 # result, while using search could suddenly match apparently
95 95 # unrelated configuration that happens to contains "color."
96 96 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 97 # some match to avoid the need to prefix most pattern with "^".
98 98 # The "^" seems more error prone.
99 99 if item._re.match(key):
100 100 return item
101 101
102 102 return None
103 103
104 104
105 105 coreitems = {}
106 106
107 107
108 108 def _register(configtable, *args, **kwargs):
109 109 item = configitem(*args, **kwargs)
110 110 section = configtable.setdefault(item.section, itemregister())
111 111 if item.name in section:
112 112 msg = b"duplicated config item registration for '%s.%s'"
113 113 raise error.ProgrammingError(msg % (item.section, item.name))
114 114 section[item.name] = item
115 115
116 116
117 117 # special value for case where the default is derived from other values
118 118 dynamicdefault = object()
119 119
120 120 # Registering actual config items
121 121
122 122
123 123 def getitemregister(configtable):
124 124 f = functools.partial(_register, configtable)
125 125 # export pseudo enum as configitem.*
126 126 f.dynamicdefault = dynamicdefault
127 127 return f
128 128
129 129
130 130 coreconfigitem = getitemregister(coreitems)
131 131
132 132
133 133 def _registerdiffopts(section, configprefix=b''):
134 134 coreconfigitem(
135 135 section,
136 136 configprefix + b'nodates',
137 137 default=False,
138 138 )
139 139 coreconfigitem(
140 140 section,
141 141 configprefix + b'showfunc',
142 142 default=False,
143 143 )
144 144 coreconfigitem(
145 145 section,
146 146 configprefix + b'unified',
147 147 default=None,
148 148 )
149 149 coreconfigitem(
150 150 section,
151 151 configprefix + b'git',
152 152 default=False,
153 153 )
154 154 coreconfigitem(
155 155 section,
156 156 configprefix + b'ignorews',
157 157 default=False,
158 158 )
159 159 coreconfigitem(
160 160 section,
161 161 configprefix + b'ignorewsamount',
162 162 default=False,
163 163 )
164 164 coreconfigitem(
165 165 section,
166 166 configprefix + b'ignoreblanklines',
167 167 default=False,
168 168 )
169 169 coreconfigitem(
170 170 section,
171 171 configprefix + b'ignorewseol',
172 172 default=False,
173 173 )
174 174 coreconfigitem(
175 175 section,
176 176 configprefix + b'nobinary',
177 177 default=False,
178 178 )
179 179 coreconfigitem(
180 180 section,
181 181 configprefix + b'noprefix',
182 182 default=False,
183 183 )
184 184 coreconfigitem(
185 185 section,
186 186 configprefix + b'word-diff',
187 187 default=False,
188 188 )
189 189
190 190
191 191 coreconfigitem(
192 192 b'alias',
193 193 b'.*',
194 194 default=dynamicdefault,
195 195 generic=True,
196 196 )
197 197 coreconfigitem(
198 198 b'auth',
199 199 b'cookiefile',
200 200 default=None,
201 201 )
202 202 _registerdiffopts(section=b'annotate')
203 203 # bookmarks.pushing: internal hack for discovery
204 204 coreconfigitem(
205 205 b'bookmarks',
206 206 b'pushing',
207 207 default=list,
208 208 )
209 209 # bundle.mainreporoot: internal hack for bundlerepo
210 210 coreconfigitem(
211 211 b'bundle',
212 212 b'mainreporoot',
213 213 default=b'',
214 214 )
215 215 coreconfigitem(
216 216 b'censor',
217 217 b'policy',
218 218 default=b'abort',
219 219 experimental=True,
220 220 )
221 221 coreconfigitem(
222 222 b'chgserver',
223 223 b'idletimeout',
224 224 default=3600,
225 225 )
226 226 coreconfigitem(
227 227 b'chgserver',
228 228 b'skiphash',
229 229 default=False,
230 230 )
231 231 coreconfigitem(
232 232 b'cmdserver',
233 233 b'log',
234 234 default=None,
235 235 )
236 236 coreconfigitem(
237 237 b'cmdserver',
238 238 b'max-log-files',
239 239 default=7,
240 240 )
241 241 coreconfigitem(
242 242 b'cmdserver',
243 243 b'max-log-size',
244 244 default=b'1 MB',
245 245 )
246 246 coreconfigitem(
247 247 b'cmdserver',
248 248 b'max-repo-cache',
249 249 default=0,
250 250 experimental=True,
251 251 )
252 252 coreconfigitem(
253 253 b'cmdserver',
254 254 b'message-encodings',
255 255 default=list,
256 256 )
257 257 coreconfigitem(
258 258 b'cmdserver',
259 259 b'track-log',
260 260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 261 )
262 262 coreconfigitem(
263 263 b'cmdserver',
264 264 b'shutdown-on-interrupt',
265 265 default=True,
266 266 )
267 267 coreconfigitem(
268 268 b'color',
269 269 b'.*',
270 270 default=None,
271 271 generic=True,
272 272 )
273 273 coreconfigitem(
274 274 b'color',
275 275 b'mode',
276 276 default=b'auto',
277 277 )
278 278 coreconfigitem(
279 279 b'color',
280 280 b'pagermode',
281 281 default=dynamicdefault,
282 282 )
283 283 coreconfigitem(
284 284 b'command-templates',
285 285 b'graphnode',
286 286 default=None,
287 287 alias=[(b'ui', b'graphnodetemplate')],
288 288 )
289 289 coreconfigitem(
290 290 b'command-templates',
291 291 b'log',
292 292 default=None,
293 293 alias=[(b'ui', b'logtemplate')],
294 294 )
295 295 coreconfigitem(
296 296 b'command-templates',
297 297 b'mergemarker',
298 298 default=(
299 299 b'{node|short} '
300 300 b'{ifeq(tags, "tip", "", '
301 301 b'ifeq(tags, "", "", "{tags} "))}'
302 302 b'{if(bookmarks, "{bookmarks} ")}'
303 303 b'{ifeq(branch, "default", "", "{branch} ")}'
304 304 b'- {author|user}: {desc|firstline}'
305 305 ),
306 306 alias=[(b'ui', b'mergemarkertemplate')],
307 307 )
308 308 coreconfigitem(
309 309 b'command-templates',
310 310 b'pre-merge-tool-output',
311 311 default=None,
312 312 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 313 )
314 314 coreconfigitem(
315 315 b'command-templates',
316 316 b'oneline-summary',
317 317 default=None,
318 318 )
319 319 coreconfigitem(
320 320 b'command-templates',
321 321 b'oneline-summary.*',
322 322 default=dynamicdefault,
323 323 generic=True,
324 324 )
325 325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 326 coreconfigitem(
327 327 b'commands',
328 328 b'commit.post-status',
329 329 default=False,
330 330 )
331 331 coreconfigitem(
332 332 b'commands',
333 333 b'grep.all-files',
334 334 default=False,
335 335 experimental=True,
336 336 )
337 337 coreconfigitem(
338 338 b'commands',
339 339 b'merge.require-rev',
340 340 default=False,
341 341 )
342 342 coreconfigitem(
343 343 b'commands',
344 344 b'push.require-revs',
345 345 default=False,
346 346 )
347 347 coreconfigitem(
348 348 b'commands',
349 349 b'resolve.confirm',
350 350 default=False,
351 351 )
352 352 coreconfigitem(
353 353 b'commands',
354 354 b'resolve.explicit-re-merge',
355 355 default=False,
356 356 )
357 357 coreconfigitem(
358 358 b'commands',
359 359 b'resolve.mark-check',
360 360 default=b'none',
361 361 )
362 362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 363 coreconfigitem(
364 364 b'commands',
365 365 b'show.aliasprefix',
366 366 default=list,
367 367 )
368 368 coreconfigitem(
369 369 b'commands',
370 370 b'status.relative',
371 371 default=False,
372 372 )
373 373 coreconfigitem(
374 374 b'commands',
375 375 b'status.skipstates',
376 376 default=[],
377 377 experimental=True,
378 378 )
379 379 coreconfigitem(
380 380 b'commands',
381 381 b'status.terse',
382 382 default=b'',
383 383 )
384 384 coreconfigitem(
385 385 b'commands',
386 386 b'status.verbose',
387 387 default=False,
388 388 )
389 389 coreconfigitem(
390 390 b'commands',
391 391 b'update.check',
392 392 default=None,
393 393 )
394 394 coreconfigitem(
395 395 b'commands',
396 396 b'update.requiredest',
397 397 default=False,
398 398 )
399 399 coreconfigitem(
400 400 b'committemplate',
401 401 b'.*',
402 402 default=None,
403 403 generic=True,
404 404 )
405 405 coreconfigitem(
406 406 b'convert',
407 407 b'bzr.saverev',
408 408 default=True,
409 409 )
410 410 coreconfigitem(
411 411 b'convert',
412 412 b'cvsps.cache',
413 413 default=True,
414 414 )
415 415 coreconfigitem(
416 416 b'convert',
417 417 b'cvsps.fuzz',
418 418 default=60,
419 419 )
420 420 coreconfigitem(
421 421 b'convert',
422 422 b'cvsps.logencoding',
423 423 default=None,
424 424 )
425 425 coreconfigitem(
426 426 b'convert',
427 427 b'cvsps.mergefrom',
428 428 default=None,
429 429 )
430 430 coreconfigitem(
431 431 b'convert',
432 432 b'cvsps.mergeto',
433 433 default=None,
434 434 )
435 435 coreconfigitem(
436 436 b'convert',
437 437 b'git.committeractions',
438 438 default=lambda: [b'messagedifferent'],
439 439 )
440 440 coreconfigitem(
441 441 b'convert',
442 442 b'git.extrakeys',
443 443 default=list,
444 444 )
445 445 coreconfigitem(
446 446 b'convert',
447 447 b'git.findcopiesharder',
448 448 default=False,
449 449 )
450 450 coreconfigitem(
451 451 b'convert',
452 452 b'git.remoteprefix',
453 453 default=b'remote',
454 454 )
455 455 coreconfigitem(
456 456 b'convert',
457 457 b'git.renamelimit',
458 458 default=400,
459 459 )
460 460 coreconfigitem(
461 461 b'convert',
462 462 b'git.saverev',
463 463 default=True,
464 464 )
465 465 coreconfigitem(
466 466 b'convert',
467 467 b'git.similarity',
468 468 default=50,
469 469 )
470 470 coreconfigitem(
471 471 b'convert',
472 472 b'git.skipsubmodules',
473 473 default=False,
474 474 )
475 475 coreconfigitem(
476 476 b'convert',
477 477 b'hg.clonebranches',
478 478 default=False,
479 479 )
480 480 coreconfigitem(
481 481 b'convert',
482 482 b'hg.ignoreerrors',
483 483 default=False,
484 484 )
485 485 coreconfigitem(
486 486 b'convert',
487 487 b'hg.preserve-hash',
488 488 default=False,
489 489 )
490 490 coreconfigitem(
491 491 b'convert',
492 492 b'hg.revs',
493 493 default=None,
494 494 )
495 495 coreconfigitem(
496 496 b'convert',
497 497 b'hg.saverev',
498 498 default=False,
499 499 )
500 500 coreconfigitem(
501 501 b'convert',
502 502 b'hg.sourcename',
503 503 default=None,
504 504 )
505 505 coreconfigitem(
506 506 b'convert',
507 507 b'hg.startrev',
508 508 default=None,
509 509 )
510 510 coreconfigitem(
511 511 b'convert',
512 512 b'hg.tagsbranch',
513 513 default=b'default',
514 514 )
515 515 coreconfigitem(
516 516 b'convert',
517 517 b'hg.usebranchnames',
518 518 default=True,
519 519 )
520 520 coreconfigitem(
521 521 b'convert',
522 522 b'ignoreancestorcheck',
523 523 default=False,
524 524 experimental=True,
525 525 )
526 526 coreconfigitem(
527 527 b'convert',
528 528 b'localtimezone',
529 529 default=False,
530 530 )
531 531 coreconfigitem(
532 532 b'convert',
533 533 b'p4.encoding',
534 534 default=dynamicdefault,
535 535 )
536 536 coreconfigitem(
537 537 b'convert',
538 538 b'p4.startrev',
539 539 default=0,
540 540 )
541 541 coreconfigitem(
542 542 b'convert',
543 543 b'skiptags',
544 544 default=False,
545 545 )
546 546 coreconfigitem(
547 547 b'convert',
548 548 b'svn.debugsvnlog',
549 549 default=True,
550 550 )
551 551 coreconfigitem(
552 552 b'convert',
553 553 b'svn.trunk',
554 554 default=None,
555 555 )
556 556 coreconfigitem(
557 557 b'convert',
558 558 b'svn.tags',
559 559 default=None,
560 560 )
561 561 coreconfigitem(
562 562 b'convert',
563 563 b'svn.branches',
564 564 default=None,
565 565 )
566 566 coreconfigitem(
567 567 b'convert',
568 568 b'svn.startrev',
569 569 default=0,
570 570 )
571 571 coreconfigitem(
572 572 b'convert',
573 573 b'svn.dangerous-set-commit-dates',
574 574 default=False,
575 575 )
576 576 coreconfigitem(
577 577 b'debug',
578 578 b'dirstate.delaywrite',
579 579 default=0,
580 580 )
581 581 coreconfigitem(
582 582 b'debug',
583 583 b'revlog.verifyposition.changelog',
584 584 default=b'',
585 585 )
586 586 coreconfigitem(
587 587 b'defaults',
588 588 b'.*',
589 589 default=None,
590 590 generic=True,
591 591 )
592 592 coreconfigitem(
593 593 b'devel',
594 594 b'all-warnings',
595 595 default=False,
596 596 )
597 597 coreconfigitem(
598 598 b'devel',
599 599 b'bundle2.debug',
600 600 default=False,
601 601 )
602 602 coreconfigitem(
603 603 b'devel',
604 604 b'bundle.delta',
605 605 default=b'',
606 606 )
607 607 coreconfigitem(
608 608 b'devel',
609 609 b'cache-vfs',
610 610 default=None,
611 611 )
612 612 coreconfigitem(
613 613 b'devel',
614 614 b'check-locks',
615 615 default=False,
616 616 )
617 617 coreconfigitem(
618 618 b'devel',
619 619 b'check-relroot',
620 620 default=False,
621 621 )
622 622 # Track copy information for all file, not just "added" one (very slow)
623 623 coreconfigitem(
624 624 b'devel',
625 625 b'copy-tracing.trace-all-files',
626 626 default=False,
627 627 )
628 628 coreconfigitem(
629 629 b'devel',
630 630 b'default-date',
631 631 default=None,
632 632 )
633 633 coreconfigitem(
634 634 b'devel',
635 635 b'deprec-warn',
636 636 default=False,
637 637 )
638 638 coreconfigitem(
639 639 b'devel',
640 640 b'disableloaddefaultcerts',
641 641 default=False,
642 642 )
643 643 coreconfigitem(
644 644 b'devel',
645 645 b'warn-empty-changegroup',
646 646 default=False,
647 647 )
648 648 coreconfigitem(
649 649 b'devel',
650 650 b'legacy.exchange',
651 651 default=list,
652 652 )
653 653 # When True, revlogs use a special reference version of the nodemap, that is not
654 654 # performant but is "known" to behave properly.
655 655 coreconfigitem(
656 656 b'devel',
657 657 b'persistent-nodemap',
658 658 default=False,
659 659 )
660 660 coreconfigitem(
661 661 b'devel',
662 662 b'servercafile',
663 663 default=b'',
664 664 )
665 665 coreconfigitem(
666 666 b'devel',
667 667 b'serverexactprotocol',
668 668 default=b'',
669 669 )
670 670 coreconfigitem(
671 671 b'devel',
672 672 b'serverrequirecert',
673 673 default=False,
674 674 )
675 675 coreconfigitem(
676 676 b'devel',
677 677 b'strip-obsmarkers',
678 678 default=True,
679 679 )
680 680 coreconfigitem(
681 681 b'devel',
682 682 b'warn-config',
683 683 default=None,
684 684 )
685 685 coreconfigitem(
686 686 b'devel',
687 687 b'warn-config-default',
688 688 default=None,
689 689 )
690 690 coreconfigitem(
691 691 b'devel',
692 692 b'user.obsmarker',
693 693 default=None,
694 694 )
695 695 coreconfigitem(
696 696 b'devel',
697 697 b'warn-config-unknown',
698 698 default=None,
699 699 )
700 700 coreconfigitem(
701 701 b'devel',
702 702 b'debug.copies',
703 703 default=False,
704 704 )
705 705 coreconfigitem(
706 706 b'devel',
707 707 b'copy-tracing.multi-thread',
708 708 default=True,
709 709 )
710 710 coreconfigitem(
711 711 b'devel',
712 712 b'debug.extensions',
713 713 default=False,
714 714 )
715 715 coreconfigitem(
716 716 b'devel',
717 717 b'debug.repo-filters',
718 718 default=False,
719 719 )
720 720 coreconfigitem(
721 721 b'devel',
722 722 b'debug.peer-request',
723 723 default=False,
724 724 )
725 725 # If discovery.exchange-heads is False, the discovery will not start with
726 726 # remote head fetching and local head querying.
727 727 coreconfigitem(
728 728 b'devel',
729 729 b'discovery.exchange-heads',
730 730 default=True,
731 731 )
732 732 # If discovery.grow-sample is False, the sample size used in set discovery will
733 733 # not be increased through the process
734 734 coreconfigitem(
735 735 b'devel',
736 736 b'discovery.grow-sample',
737 737 default=True,
738 738 )
739 739 # When discovery.grow-sample.dynamic is True, the default, the sample size is
740 740 # adapted to the shape of the undecided set (it is set to the max of:
741 741 # <target-size>, len(roots(undecided)), len(heads(undecided)
742 742 coreconfigitem(
743 743 b'devel',
744 744 b'discovery.grow-sample.dynamic',
745 745 default=True,
746 746 )
747 747 # discovery.grow-sample.rate control the rate at which the sample grow
748 748 coreconfigitem(
749 749 b'devel',
750 750 b'discovery.grow-sample.rate',
751 751 default=1.05,
752 752 )
753 753 # If discovery.randomize is False, random sampling during discovery are
754 754 # deterministic. It is meant for integration tests.
755 755 coreconfigitem(
756 756 b'devel',
757 757 b'discovery.randomize',
758 758 default=True,
759 759 )
760 760 # Control the initial size of the discovery sample
761 761 coreconfigitem(
762 762 b'devel',
763 763 b'discovery.sample-size',
764 764 default=200,
765 765 )
766 766 # Control the initial size of the discovery for initial change
767 767 coreconfigitem(
768 768 b'devel',
769 769 b'discovery.sample-size.initial',
770 770 default=100,
771 771 )
772 772 _registerdiffopts(section=b'diff')
773 773 coreconfigitem(
774 774 b'diff',
775 775 b'merge',
776 776 default=False,
777 777 experimental=True,
778 778 )
779 779 coreconfigitem(
780 780 b'email',
781 781 b'bcc',
782 782 default=None,
783 783 )
784 784 coreconfigitem(
785 785 b'email',
786 786 b'cc',
787 787 default=None,
788 788 )
789 789 coreconfigitem(
790 790 b'email',
791 791 b'charsets',
792 792 default=list,
793 793 )
794 794 coreconfigitem(
795 795 b'email',
796 796 b'from',
797 797 default=None,
798 798 )
799 799 coreconfigitem(
800 800 b'email',
801 801 b'method',
802 802 default=b'smtp',
803 803 )
804 804 coreconfigitem(
805 805 b'email',
806 806 b'reply-to',
807 807 default=None,
808 808 )
809 809 coreconfigitem(
810 810 b'email',
811 811 b'to',
812 812 default=None,
813 813 )
814 814 coreconfigitem(
815 815 b'experimental',
816 816 b'archivemetatemplate',
817 817 default=dynamicdefault,
818 818 )
819 819 coreconfigitem(
820 820 b'experimental',
821 821 b'auto-publish',
822 822 default=b'publish',
823 823 )
824 824 coreconfigitem(
825 825 b'experimental',
826 826 b'bundle-phases',
827 827 default=False,
828 828 )
829 829 coreconfigitem(
830 830 b'experimental',
831 831 b'bundle2-advertise',
832 832 default=True,
833 833 )
834 834 coreconfigitem(
835 835 b'experimental',
836 836 b'bundle2-output-capture',
837 837 default=False,
838 838 )
839 839 coreconfigitem(
840 840 b'experimental',
841 841 b'bundle2.pushback',
842 842 default=False,
843 843 )
844 844 coreconfigitem(
845 845 b'experimental',
846 846 b'bundle2lazylocking',
847 847 default=False,
848 848 )
849 849 coreconfigitem(
850 850 b'experimental',
851 851 b'bundlecomplevel',
852 852 default=None,
853 853 )
854 854 coreconfigitem(
855 855 b'experimental',
856 856 b'bundlecomplevel.bzip2',
857 857 default=None,
858 858 )
859 859 coreconfigitem(
860 860 b'experimental',
861 861 b'bundlecomplevel.gzip',
862 862 default=None,
863 863 )
864 864 coreconfigitem(
865 865 b'experimental',
866 866 b'bundlecomplevel.none',
867 867 default=None,
868 868 )
869 869 coreconfigitem(
870 870 b'experimental',
871 871 b'bundlecomplevel.zstd',
872 872 default=None,
873 873 )
874 874 coreconfigitem(
875 875 b'experimental',
876 876 b'bundlecompthreads',
877 877 default=None,
878 878 )
879 879 coreconfigitem(
880 880 b'experimental',
881 881 b'bundlecompthreads.bzip2',
882 882 default=None,
883 883 )
884 884 coreconfigitem(
885 885 b'experimental',
886 886 b'bundlecompthreads.gzip',
887 887 default=None,
888 888 )
889 889 coreconfigitem(
890 890 b'experimental',
891 891 b'bundlecompthreads.none',
892 892 default=None,
893 893 )
894 894 coreconfigitem(
895 895 b'experimental',
896 896 b'bundlecompthreads.zstd',
897 897 default=None,
898 898 )
899 899 coreconfigitem(
900 900 b'experimental',
901 901 b'changegroup3',
902 902 default=False,
903 903 )
904 904 coreconfigitem(
905 905 b'experimental',
906 906 b'changegroup4',
907 907 default=False,
908 908 )
909 909 coreconfigitem(
910 910 b'experimental',
911 911 b'cleanup-as-archived',
912 912 default=False,
913 913 )
914 914 coreconfigitem(
915 915 b'experimental',
916 916 b'clientcompressionengines',
917 917 default=list,
918 918 )
919 919 coreconfigitem(
920 920 b'experimental',
921 921 b'copytrace',
922 922 default=b'on',
923 923 )
924 924 coreconfigitem(
925 925 b'experimental',
926 926 b'copytrace.movecandidateslimit',
927 927 default=100,
928 928 )
929 929 coreconfigitem(
930 930 b'experimental',
931 931 b'copytrace.sourcecommitlimit',
932 932 default=100,
933 933 )
934 934 coreconfigitem(
935 935 b'experimental',
936 936 b'copies.read-from',
937 937 default=b"filelog-only",
938 938 )
939 939 coreconfigitem(
940 940 b'experimental',
941 941 b'copies.write-to',
942 942 default=b'filelog-only',
943 943 )
944 944 coreconfigitem(
945 945 b'experimental',
946 946 b'crecordtest',
947 947 default=None,
948 948 )
949 949 coreconfigitem(
950 950 b'experimental',
951 951 b'directaccess',
952 952 default=False,
953 953 )
954 954 coreconfigitem(
955 955 b'experimental',
956 956 b'directaccess.revnums',
957 957 default=False,
958 958 )
959 959 coreconfigitem(
960 960 b'experimental',
961 961 b'editortmpinhg',
962 962 default=False,
963 963 )
964 964 coreconfigitem(
965 965 b'experimental',
966 966 b'evolution',
967 967 default=list,
968 968 )
969 969 coreconfigitem(
970 970 b'experimental',
971 971 b'evolution.allowdivergence',
972 972 default=False,
973 973 alias=[(b'experimental', b'allowdivergence')],
974 974 )
975 975 coreconfigitem(
976 976 b'experimental',
977 977 b'evolution.allowunstable',
978 978 default=None,
979 979 )
980 980 coreconfigitem(
981 981 b'experimental',
982 982 b'evolution.createmarkers',
983 983 default=None,
984 984 )
985 985 coreconfigitem(
986 986 b'experimental',
987 987 b'evolution.effect-flags',
988 988 default=True,
989 989 alias=[(b'experimental', b'effect-flags')],
990 990 )
991 991 coreconfigitem(
992 992 b'experimental',
993 993 b'evolution.exchange',
994 994 default=None,
995 995 )
996 996 coreconfigitem(
997 997 b'experimental',
998 998 b'evolution.bundle-obsmarker',
999 999 default=False,
1000 1000 )
1001 1001 coreconfigitem(
1002 1002 b'experimental',
1003 1003 b'evolution.bundle-obsmarker:mandatory',
1004 1004 default=True,
1005 1005 )
1006 1006 coreconfigitem(
1007 1007 b'experimental',
1008 1008 b'log.topo',
1009 1009 default=False,
1010 1010 )
1011 1011 coreconfigitem(
1012 1012 b'experimental',
1013 1013 b'evolution.report-instabilities',
1014 1014 default=True,
1015 1015 )
1016 1016 coreconfigitem(
1017 1017 b'experimental',
1018 1018 b'evolution.track-operation',
1019 1019 default=True,
1020 1020 )
1021 1021 # repo-level config to exclude a revset visibility
1022 1022 #
1023 1023 # The target use case is to use `share` to expose different subset of the same
1024 1024 # repository, especially server side. See also `server.view`.
1025 1025 coreconfigitem(
1026 1026 b'experimental',
1027 1027 b'extra-filter-revs',
1028 1028 default=None,
1029 1029 )
1030 1030 coreconfigitem(
1031 1031 b'experimental',
1032 1032 b'maxdeltachainspan',
1033 1033 default=-1,
1034 1034 )
1035 1035 # tracks files which were undeleted (merge might delete them but we explicitly
1036 1036 # kept/undeleted them) and creates new filenodes for them
1037 1037 coreconfigitem(
1038 1038 b'experimental',
1039 1039 b'merge-track-salvaged',
1040 1040 default=False,
1041 1041 )
1042 1042 coreconfigitem(
1043 1043 b'experimental',
1044 1044 b'mmapindexthreshold',
1045 1045 default=None,
1046 1046 )
1047 1047 coreconfigitem(
1048 1048 b'experimental',
1049 1049 b'narrow',
1050 1050 default=False,
1051 1051 )
1052 1052 coreconfigitem(
1053 1053 b'experimental',
1054 1054 b'nonnormalparanoidcheck',
1055 1055 default=False,
1056 1056 )
1057 1057 coreconfigitem(
1058 1058 b'experimental',
1059 1059 b'exportableenviron',
1060 1060 default=list,
1061 1061 )
1062 1062 coreconfigitem(
1063 1063 b'experimental',
1064 1064 b'extendedheader.index',
1065 1065 default=None,
1066 1066 )
1067 1067 coreconfigitem(
1068 1068 b'experimental',
1069 1069 b'extendedheader.similarity',
1070 1070 default=False,
1071 1071 )
1072 1072 coreconfigitem(
1073 1073 b'experimental',
1074 1074 b'graphshorten',
1075 1075 default=False,
1076 1076 )
1077 1077 coreconfigitem(
1078 1078 b'experimental',
1079 1079 b'graphstyle.parent',
1080 1080 default=dynamicdefault,
1081 1081 )
1082 1082 coreconfigitem(
1083 1083 b'experimental',
1084 1084 b'graphstyle.missing',
1085 1085 default=dynamicdefault,
1086 1086 )
1087 1087 coreconfigitem(
1088 1088 b'experimental',
1089 1089 b'graphstyle.grandparent',
1090 1090 default=dynamicdefault,
1091 1091 )
1092 1092 coreconfigitem(
1093 1093 b'experimental',
1094 1094 b'hook-track-tags',
1095 1095 default=False,
1096 1096 )
1097 1097 coreconfigitem(
1098 1098 b'experimental',
1099 1099 b'httppostargs',
1100 1100 default=False,
1101 1101 )
1102 1102 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1103 1103 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1104 1104
1105 1105 coreconfigitem(
1106 1106 b'experimental',
1107 1107 b'obsmarkers-exchange-debug',
1108 1108 default=False,
1109 1109 )
1110 1110 coreconfigitem(
1111 1111 b'experimental',
1112 1112 b'remotenames',
1113 1113 default=False,
1114 1114 )
1115 1115 coreconfigitem(
1116 1116 b'experimental',
1117 1117 b'removeemptydirs',
1118 1118 default=True,
1119 1119 )
1120 1120 coreconfigitem(
1121 1121 b'experimental',
1122 1122 b'revert.interactive.select-to-keep',
1123 1123 default=False,
1124 1124 )
1125 1125 coreconfigitem(
1126 1126 b'experimental',
1127 1127 b'revisions.prefixhexnode',
1128 1128 default=False,
1129 1129 )
1130 1130 # "out of experimental" todo list.
1131 1131 #
1132 1132 # * include management of a persistent nodemap in the main docket
1133 1133 # * enforce a "no-truncate" policy for mmap safety
1134 1134 # - for censoring operation
1135 1135 # - for stripping operation
1136 1136 # - for rollback operation
1137 1137 # * proper streaming (race free) of the docket file
1138 1138 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1139 1139 # * Exchange-wise, we will also need to do something more efficient than
1140 1140 # keeping references to the affected revlogs, especially memory-wise when
1141 1141 # rewriting sidedata.
1142 1142 # * introduce a proper solution to reduce the number of filelog related files.
1143 1143 # * use caching for reading sidedata (similar to what we do for data).
1144 1144 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1145 1145 # * Improvement to consider
1146 1146 # - avoid compression header in chunk using the default compression?
1147 1147 # - forbid "inline" compression mode entirely?
1148 1148 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1149 1149 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1150 1150 # - keep track of chain base or size (probably not that useful anymore)
1151 1151 coreconfigitem(
1152 1152 b'experimental',
1153 1153 b'revlogv2',
1154 1154 default=None,
1155 1155 )
1156 1156 coreconfigitem(
1157 1157 b'experimental',
1158 1158 b'revisions.disambiguatewithin',
1159 1159 default=None,
1160 1160 )
1161 1161 coreconfigitem(
1162 1162 b'experimental',
1163 1163 b'rust.index',
1164 1164 default=False,
1165 1165 )
1166 1166 coreconfigitem(
1167 1167 b'experimental',
1168 1168 b'server.filesdata.recommended-batch-size',
1169 1169 default=50000,
1170 1170 )
1171 1171 coreconfigitem(
1172 1172 b'experimental',
1173 1173 b'server.manifestdata.recommended-batch-size',
1174 1174 default=100000,
1175 1175 )
1176 1176 coreconfigitem(
1177 1177 b'experimental',
1178 1178 b'server.stream-narrow-clones',
1179 1179 default=False,
1180 1180 )
1181 1181 coreconfigitem(
1182 1182 b'experimental',
1183 1183 b'single-head-per-branch',
1184 1184 default=False,
1185 1185 )
1186 1186 coreconfigitem(
1187 1187 b'experimental',
1188 1188 b'single-head-per-branch:account-closed-heads',
1189 1189 default=False,
1190 1190 )
1191 1191 coreconfigitem(
1192 1192 b'experimental',
1193 1193 b'single-head-per-branch:public-changes-only',
1194 1194 default=False,
1195 1195 )
1196 1196 coreconfigitem(
1197 1197 b'experimental',
1198 1198 b'sparse-read',
1199 1199 default=False,
1200 1200 )
1201 1201 coreconfigitem(
1202 1202 b'experimental',
1203 1203 b'sparse-read.density-threshold',
1204 1204 default=0.50,
1205 1205 )
1206 1206 coreconfigitem(
1207 1207 b'experimental',
1208 1208 b'sparse-read.min-gap-size',
1209 1209 default=b'65K',
1210 1210 )
1211 1211 coreconfigitem(
1212 1212 b'experimental',
1213 1213 b'treemanifest',
1214 1214 default=False,
1215 1215 )
1216 1216 coreconfigitem(
1217 1217 b'experimental',
1218 1218 b'update.atomic-file',
1219 1219 default=False,
1220 1220 )
1221 1221 coreconfigitem(
1222 1222 b'experimental',
1223 1223 b'web.full-garbage-collection-rate',
1224 1224 default=1, # still forcing a full collection on each request
1225 1225 )
1226 1226 coreconfigitem(
1227 1227 b'experimental',
1228 1228 b'worker.wdir-get-thread-safe',
1229 1229 default=False,
1230 1230 )
1231 1231 coreconfigitem(
1232 1232 b'experimental',
1233 1233 b'worker.repository-upgrade',
1234 1234 default=False,
1235 1235 )
1236 1236 coreconfigitem(
1237 1237 b'experimental',
1238 1238 b'xdiff',
1239 1239 default=False,
1240 1240 )
1241 1241 coreconfigitem(
1242 1242 b'extensions',
1243 1243 b'[^:]*',
1244 1244 default=None,
1245 1245 generic=True,
1246 1246 )
1247 1247 coreconfigitem(
1248 1248 b'extensions',
1249 1249 b'[^:]*:required',
1250 1250 default=False,
1251 1251 generic=True,
1252 1252 )
1253 1253 coreconfigitem(
1254 1254 b'extdata',
1255 1255 b'.*',
1256 1256 default=None,
1257 1257 generic=True,
1258 1258 )
1259 1259 coreconfigitem(
1260 1260 b'format',
1261 1261 b'bookmarks-in-store',
1262 1262 default=False,
1263 1263 )
1264 1264 coreconfigitem(
1265 1265 b'format',
1266 1266 b'chunkcachesize',
1267 1267 default=None,
1268 1268 experimental=True,
1269 1269 )
1270 1270 coreconfigitem(
1271 1271 # Enable this dirstate format *when creating a new repository*.
1272 1272 # Which format to use for existing repos is controlled by .hg/requires
1273 1273 b'format',
1274 1274 b'use-dirstate-v2',
1275 1275 default=False,
1276 1276 experimental=True,
1277 1277 alias=[(b'format', b'exp-rc-dirstate-v2')],
1278 1278 )
1279 1279 coreconfigitem(
1280 1280 b'format',
1281 1281 b'use-dirstate-tracked-hint',
1282 1282 default=False,
1283 1283 experimental=True,
1284 1284 )
1285 1285 coreconfigitem(
1286 1286 b'format',
1287 1287 b'use-dirstate-tracked-hint.version',
1288 1288 default=1,
1289 1289 experimental=True,
1290 1290 )
1291 1291 coreconfigitem(
1292 1292 b'format',
1293 1293 b'dotencode',
1294 1294 default=True,
1295 1295 )
1296 1296 coreconfigitem(
1297 1297 b'format',
1298 1298 b'generaldelta',
1299 1299 default=False,
1300 1300 experimental=True,
1301 1301 )
1302 1302 coreconfigitem(
1303 1303 b'format',
1304 1304 b'manifestcachesize',
1305 1305 default=None,
1306 1306 experimental=True,
1307 1307 )
1308 1308 coreconfigitem(
1309 1309 b'format',
1310 1310 b'maxchainlen',
1311 1311 default=dynamicdefault,
1312 1312 experimental=True,
1313 1313 )
1314 1314 coreconfigitem(
1315 1315 b'format',
1316 1316 b'obsstore-version',
1317 1317 default=None,
1318 1318 )
1319 1319 coreconfigitem(
1320 1320 b'format',
1321 1321 b'sparse-revlog',
1322 1322 default=True,
1323 1323 )
1324 1324 coreconfigitem(
1325 1325 b'format',
1326 1326 b'revlog-compression',
1327 1327 default=lambda: [b'zstd', b'zlib'],
1328 1328 alias=[(b'experimental', b'format.compression')],
1329 1329 )
1330 1330 # Experimental TODOs:
1331 1331 #
1332 1332 # * Same as for revlogv2 (but for the reduction of the number of files)
1333 1333 # * Actually computing the rank of changesets
1334 1334 # * Improvement to investigate
1335 1335 # - storing .hgtags fnode
1336 1336 # - storing branch related identifier
1337 1337
1338 1338 coreconfigitem(
1339 1339 b'format',
1340 1340 b'exp-use-changelog-v2',
1341 1341 default=None,
1342 1342 experimental=True,
1343 1343 )
1344 1344 coreconfigitem(
1345 1345 b'format',
1346 1346 b'usefncache',
1347 1347 default=True,
1348 1348 )
1349 1349 coreconfigitem(
1350 1350 b'format',
1351 1351 b'usegeneraldelta',
1352 1352 default=True,
1353 1353 )
1354 1354 coreconfigitem(
1355 1355 b'format',
1356 1356 b'usestore',
1357 1357 default=True,
1358 1358 )
1359 1359
1360 1360
1361 1361 def _persistent_nodemap_default():
1362 1362 """compute `use-persistent-nodemap` default value
1363 1363
1364 1364 The feature is disabled unless a fast implementation is available.
1365 1365 """
1366 1366 from . import policy
1367 1367
1368 1368 return policy.importrust('revlog') is not None
1369 1369
1370 1370
1371 1371 coreconfigitem(
1372 1372 b'format',
1373 1373 b'use-persistent-nodemap',
1374 1374 default=_persistent_nodemap_default,
1375 1375 )
1376 1376 coreconfigitem(
1377 1377 b'format',
1378 1378 b'exp-use-copies-side-data-changeset',
1379 1379 default=False,
1380 1380 experimental=True,
1381 1381 )
1382 1382 coreconfigitem(
1383 1383 b'format',
1384 1384 b'use-share-safe',
1385 1385 default=True,
1386 1386 )
1387 1387 coreconfigitem(
1388 1388 b'format',
1389 1389 b'internal-phase',
1390 1390 default=False,
1391 1391 experimental=True,
1392 1392 )
1393 1393 coreconfigitem(
1394 1394 b'fsmonitor',
1395 1395 b'warn_when_unused',
1396 1396 default=True,
1397 1397 )
1398 1398 coreconfigitem(
1399 1399 b'fsmonitor',
1400 1400 b'warn_update_file_count',
1401 1401 default=50000,
1402 1402 )
1403 1403 coreconfigitem(
1404 1404 b'fsmonitor',
1405 1405 b'warn_update_file_count_rust',
1406 1406 default=400000,
1407 1407 )
1408 1408 coreconfigitem(
1409 1409 b'help',
1410 1410 br'hidden-command\..*',
1411 1411 default=False,
1412 1412 generic=True,
1413 1413 )
1414 1414 coreconfigitem(
1415 1415 b'help',
1416 1416 br'hidden-topic\..*',
1417 1417 default=False,
1418 1418 generic=True,
1419 1419 )
1420 1420 coreconfigitem(
1421 1421 b'hooks',
1422 1422 b'[^:]*',
1423 1423 default=dynamicdefault,
1424 1424 generic=True,
1425 1425 )
1426 1426 coreconfigitem(
1427 1427 b'hooks',
1428 1428 b'.*:run-with-plain',
1429 1429 default=True,
1430 1430 generic=True,
1431 1431 )
1432 1432 coreconfigitem(
1433 1433 b'hgweb-paths',
1434 1434 b'.*',
1435 1435 default=list,
1436 1436 generic=True,
1437 1437 )
1438 1438 coreconfigitem(
1439 1439 b'hostfingerprints',
1440 1440 b'.*',
1441 1441 default=list,
1442 1442 generic=True,
1443 1443 )
1444 1444 coreconfigitem(
1445 1445 b'hostsecurity',
1446 1446 b'ciphers',
1447 1447 default=None,
1448 1448 )
1449 1449 coreconfigitem(
1450 1450 b'hostsecurity',
1451 1451 b'minimumprotocol',
1452 1452 default=dynamicdefault,
1453 1453 )
1454 1454 coreconfigitem(
1455 1455 b'hostsecurity',
1456 1456 b'.*:minimumprotocol$',
1457 1457 default=dynamicdefault,
1458 1458 generic=True,
1459 1459 )
1460 1460 coreconfigitem(
1461 1461 b'hostsecurity',
1462 1462 b'.*:ciphers$',
1463 1463 default=dynamicdefault,
1464 1464 generic=True,
1465 1465 )
1466 1466 coreconfigitem(
1467 1467 b'hostsecurity',
1468 1468 b'.*:fingerprints$',
1469 1469 default=list,
1470 1470 generic=True,
1471 1471 )
1472 1472 coreconfigitem(
1473 1473 b'hostsecurity',
1474 1474 b'.*:verifycertsfile$',
1475 1475 default=None,
1476 1476 generic=True,
1477 1477 )
1478 1478
1479 1479 coreconfigitem(
1480 1480 b'http_proxy',
1481 1481 b'always',
1482 1482 default=False,
1483 1483 )
1484 1484 coreconfigitem(
1485 1485 b'http_proxy',
1486 1486 b'host',
1487 1487 default=None,
1488 1488 )
1489 1489 coreconfigitem(
1490 1490 b'http_proxy',
1491 1491 b'no',
1492 1492 default=list,
1493 1493 )
1494 1494 coreconfigitem(
1495 1495 b'http_proxy',
1496 1496 b'passwd',
1497 1497 default=None,
1498 1498 )
1499 1499 coreconfigitem(
1500 1500 b'http_proxy',
1501 1501 b'user',
1502 1502 default=None,
1503 1503 )
1504 1504
1505 1505 coreconfigitem(
1506 1506 b'http',
1507 1507 b'timeout',
1508 1508 default=None,
1509 1509 )
1510 1510
1511 1511 coreconfigitem(
1512 1512 b'logtoprocess',
1513 1513 b'commandexception',
1514 1514 default=None,
1515 1515 )
1516 1516 coreconfigitem(
1517 1517 b'logtoprocess',
1518 1518 b'commandfinish',
1519 1519 default=None,
1520 1520 )
1521 1521 coreconfigitem(
1522 1522 b'logtoprocess',
1523 1523 b'command',
1524 1524 default=None,
1525 1525 )
1526 1526 coreconfigitem(
1527 1527 b'logtoprocess',
1528 1528 b'develwarn',
1529 1529 default=None,
1530 1530 )
1531 1531 coreconfigitem(
1532 1532 b'logtoprocess',
1533 1533 b'uiblocked',
1534 1534 default=None,
1535 1535 )
1536 1536 coreconfigitem(
1537 1537 b'merge',
1538 1538 b'checkunknown',
1539 1539 default=b'abort',
1540 1540 )
1541 1541 coreconfigitem(
1542 1542 b'merge',
1543 1543 b'checkignored',
1544 1544 default=b'abort',
1545 1545 )
1546 1546 coreconfigitem(
1547 1547 b'experimental',
1548 1548 b'merge.checkpathconflicts',
1549 1549 default=False,
1550 1550 )
1551 1551 coreconfigitem(
1552 1552 b'merge',
1553 1553 b'followcopies',
1554 1554 default=True,
1555 1555 )
1556 1556 coreconfigitem(
1557 1557 b'merge',
1558 1558 b'on-failure',
1559 1559 default=b'continue',
1560 1560 )
1561 1561 coreconfigitem(
1562 1562 b'merge',
1563 1563 b'preferancestor',
1564 1564 default=lambda: [b'*'],
1565 1565 experimental=True,
1566 1566 )
1567 1567 coreconfigitem(
1568 1568 b'merge',
1569 1569 b'strict-capability-check',
1570 1570 default=False,
1571 1571 )
1572 1572 coreconfigitem(
1573 1573 b'partial-merge-tools',
1574 1574 b'.*',
1575 1575 default=None,
1576 1576 generic=True,
1577 1577 experimental=True,
1578 1578 )
1579 1579 coreconfigitem(
1580 1580 b'partial-merge-tools',
1581 1581 br'.*\.patterns',
1582 1582 default=dynamicdefault,
1583 1583 generic=True,
1584 1584 priority=-1,
1585 1585 experimental=True,
1586 1586 )
1587 1587 coreconfigitem(
1588 1588 b'partial-merge-tools',
1589 1589 br'.*\.executable$',
1590 1590 default=dynamicdefault,
1591 1591 generic=True,
1592 1592 priority=-1,
1593 1593 experimental=True,
1594 1594 )
1595 1595 coreconfigitem(
1596 1596 b'partial-merge-tools',
1597 1597 br'.*\.order',
1598 1598 default=0,
1599 1599 generic=True,
1600 1600 priority=-1,
1601 1601 experimental=True,
1602 1602 )
1603 1603 coreconfigitem(
1604 b'partial-merge-tools',
1605 br'.*\.args',
1606 default=b"$local $base $other",
1607 generic=True,
1608 priority=-1,
1609 experimental=True,
1610 )
1611 coreconfigitem(
1604 1612 b'merge-tools',
1605 1613 b'.*',
1606 1614 default=None,
1607 1615 generic=True,
1608 1616 )
1609 1617 coreconfigitem(
1610 1618 b'merge-tools',
1611 1619 br'.*\.args$',
1612 1620 default=b"$local $base $other",
1613 1621 generic=True,
1614 1622 priority=-1,
1615 1623 )
1616 1624 coreconfigitem(
1617 1625 b'merge-tools',
1618 1626 br'.*\.binary$',
1619 1627 default=False,
1620 1628 generic=True,
1621 1629 priority=-1,
1622 1630 )
1623 1631 coreconfigitem(
1624 1632 b'merge-tools',
1625 1633 br'.*\.check$',
1626 1634 default=list,
1627 1635 generic=True,
1628 1636 priority=-1,
1629 1637 )
1630 1638 coreconfigitem(
1631 1639 b'merge-tools',
1632 1640 br'.*\.checkchanged$',
1633 1641 default=False,
1634 1642 generic=True,
1635 1643 priority=-1,
1636 1644 )
1637 1645 coreconfigitem(
1638 1646 b'merge-tools',
1639 1647 br'.*\.executable$',
1640 1648 default=dynamicdefault,
1641 1649 generic=True,
1642 1650 priority=-1,
1643 1651 )
1644 1652 coreconfigitem(
1645 1653 b'merge-tools',
1646 1654 br'.*\.fixeol$',
1647 1655 default=False,
1648 1656 generic=True,
1649 1657 priority=-1,
1650 1658 )
1651 1659 coreconfigitem(
1652 1660 b'merge-tools',
1653 1661 br'.*\.gui$',
1654 1662 default=False,
1655 1663 generic=True,
1656 1664 priority=-1,
1657 1665 )
1658 1666 coreconfigitem(
1659 1667 b'merge-tools',
1660 1668 br'.*\.mergemarkers$',
1661 1669 default=b'basic',
1662 1670 generic=True,
1663 1671 priority=-1,
1664 1672 )
1665 1673 coreconfigitem(
1666 1674 b'merge-tools',
1667 1675 br'.*\.mergemarkertemplate$',
1668 1676 default=dynamicdefault, # take from command-templates.mergemarker
1669 1677 generic=True,
1670 1678 priority=-1,
1671 1679 )
1672 1680 coreconfigitem(
1673 1681 b'merge-tools',
1674 1682 br'.*\.priority$',
1675 1683 default=0,
1676 1684 generic=True,
1677 1685 priority=-1,
1678 1686 )
1679 1687 coreconfigitem(
1680 1688 b'merge-tools',
1681 1689 br'.*\.premerge$',
1682 1690 default=dynamicdefault,
1683 1691 generic=True,
1684 1692 priority=-1,
1685 1693 )
1686 1694 coreconfigitem(
1687 1695 b'merge-tools',
1688 1696 br'.*\.symlink$',
1689 1697 default=False,
1690 1698 generic=True,
1691 1699 priority=-1,
1692 1700 )
1693 1701 coreconfigitem(
1694 1702 b'pager',
1695 1703 b'attend-.*',
1696 1704 default=dynamicdefault,
1697 1705 generic=True,
1698 1706 )
1699 1707 coreconfigitem(
1700 1708 b'pager',
1701 1709 b'ignore',
1702 1710 default=list,
1703 1711 )
1704 1712 coreconfigitem(
1705 1713 b'pager',
1706 1714 b'pager',
1707 1715 default=dynamicdefault,
1708 1716 )
1709 1717 coreconfigitem(
1710 1718 b'patch',
1711 1719 b'eol',
1712 1720 default=b'strict',
1713 1721 )
1714 1722 coreconfigitem(
1715 1723 b'patch',
1716 1724 b'fuzz',
1717 1725 default=2,
1718 1726 )
1719 1727 coreconfigitem(
1720 1728 b'paths',
1721 1729 b'default',
1722 1730 default=None,
1723 1731 )
1724 1732 coreconfigitem(
1725 1733 b'paths',
1726 1734 b'default-push',
1727 1735 default=None,
1728 1736 )
1729 1737 coreconfigitem(
1730 1738 b'paths',
1731 1739 b'.*',
1732 1740 default=None,
1733 1741 generic=True,
1734 1742 )
1735 1743 coreconfigitem(
1736 1744 b'phases',
1737 1745 b'checksubrepos',
1738 1746 default=b'follow',
1739 1747 )
1740 1748 coreconfigitem(
1741 1749 b'phases',
1742 1750 b'new-commit',
1743 1751 default=b'draft',
1744 1752 )
1745 1753 coreconfigitem(
1746 1754 b'phases',
1747 1755 b'publish',
1748 1756 default=True,
1749 1757 )
1750 1758 coreconfigitem(
1751 1759 b'profiling',
1752 1760 b'enabled',
1753 1761 default=False,
1754 1762 )
1755 1763 coreconfigitem(
1756 1764 b'profiling',
1757 1765 b'format',
1758 1766 default=b'text',
1759 1767 )
1760 1768 coreconfigitem(
1761 1769 b'profiling',
1762 1770 b'freq',
1763 1771 default=1000,
1764 1772 )
1765 1773 coreconfigitem(
1766 1774 b'profiling',
1767 1775 b'limit',
1768 1776 default=30,
1769 1777 )
1770 1778 coreconfigitem(
1771 1779 b'profiling',
1772 1780 b'nested',
1773 1781 default=0,
1774 1782 )
1775 1783 coreconfigitem(
1776 1784 b'profiling',
1777 1785 b'output',
1778 1786 default=None,
1779 1787 )
1780 1788 coreconfigitem(
1781 1789 b'profiling',
1782 1790 b'showmax',
1783 1791 default=0.999,
1784 1792 )
1785 1793 coreconfigitem(
1786 1794 b'profiling',
1787 1795 b'showmin',
1788 1796 default=dynamicdefault,
1789 1797 )
1790 1798 coreconfigitem(
1791 1799 b'profiling',
1792 1800 b'showtime',
1793 1801 default=True,
1794 1802 )
1795 1803 coreconfigitem(
1796 1804 b'profiling',
1797 1805 b'sort',
1798 1806 default=b'inlinetime',
1799 1807 )
1800 1808 coreconfigitem(
1801 1809 b'profiling',
1802 1810 b'statformat',
1803 1811 default=b'hotpath',
1804 1812 )
1805 1813 coreconfigitem(
1806 1814 b'profiling',
1807 1815 b'time-track',
1808 1816 default=dynamicdefault,
1809 1817 )
1810 1818 coreconfigitem(
1811 1819 b'profiling',
1812 1820 b'type',
1813 1821 default=b'stat',
1814 1822 )
1815 1823 coreconfigitem(
1816 1824 b'progress',
1817 1825 b'assume-tty',
1818 1826 default=False,
1819 1827 )
1820 1828 coreconfigitem(
1821 1829 b'progress',
1822 1830 b'changedelay',
1823 1831 default=1,
1824 1832 )
1825 1833 coreconfigitem(
1826 1834 b'progress',
1827 1835 b'clear-complete',
1828 1836 default=True,
1829 1837 )
1830 1838 coreconfigitem(
1831 1839 b'progress',
1832 1840 b'debug',
1833 1841 default=False,
1834 1842 )
1835 1843 coreconfigitem(
1836 1844 b'progress',
1837 1845 b'delay',
1838 1846 default=3,
1839 1847 )
1840 1848 coreconfigitem(
1841 1849 b'progress',
1842 1850 b'disable',
1843 1851 default=False,
1844 1852 )
1845 1853 coreconfigitem(
1846 1854 b'progress',
1847 1855 b'estimateinterval',
1848 1856 default=60.0,
1849 1857 )
1850 1858 coreconfigitem(
1851 1859 b'progress',
1852 1860 b'format',
1853 1861 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1854 1862 )
1855 1863 coreconfigitem(
1856 1864 b'progress',
1857 1865 b'refresh',
1858 1866 default=0.1,
1859 1867 )
1860 1868 coreconfigitem(
1861 1869 b'progress',
1862 1870 b'width',
1863 1871 default=dynamicdefault,
1864 1872 )
1865 1873 coreconfigitem(
1866 1874 b'pull',
1867 1875 b'confirm',
1868 1876 default=False,
1869 1877 )
1870 1878 coreconfigitem(
1871 1879 b'push',
1872 1880 b'pushvars.server',
1873 1881 default=False,
1874 1882 )
1875 1883 coreconfigitem(
1876 1884 b'rewrite',
1877 1885 b'backup-bundle',
1878 1886 default=True,
1879 1887 alias=[(b'ui', b'history-editing-backup')],
1880 1888 )
1881 1889 coreconfigitem(
1882 1890 b'rewrite',
1883 1891 b'update-timestamp',
1884 1892 default=False,
1885 1893 )
1886 1894 coreconfigitem(
1887 1895 b'rewrite',
1888 1896 b'empty-successor',
1889 1897 default=b'skip',
1890 1898 experimental=True,
1891 1899 )
1892 1900 # experimental as long as format.use-dirstate-v2 is.
1893 1901 coreconfigitem(
1894 1902 b'storage',
1895 1903 b'dirstate-v2.slow-path',
1896 1904 default=b"abort",
1897 1905 experimental=True,
1898 1906 )
1899 1907 coreconfigitem(
1900 1908 b'storage',
1901 1909 b'new-repo-backend',
1902 1910 default=b'revlogv1',
1903 1911 experimental=True,
1904 1912 )
1905 1913 coreconfigitem(
1906 1914 b'storage',
1907 1915 b'revlog.optimize-delta-parent-choice',
1908 1916 default=True,
1909 1917 alias=[(b'format', b'aggressivemergedeltas')],
1910 1918 )
1911 1919 coreconfigitem(
1912 1920 b'storage',
1913 1921 b'revlog.issue6528.fix-incoming',
1914 1922 default=True,
1915 1923 )
1916 1924 # experimental as long as rust is experimental (or a C version is implemented)
1917 1925 coreconfigitem(
1918 1926 b'storage',
1919 1927 b'revlog.persistent-nodemap.mmap',
1920 1928 default=True,
1921 1929 )
1922 1930 # experimental as long as format.use-persistent-nodemap is.
1923 1931 coreconfigitem(
1924 1932 b'storage',
1925 1933 b'revlog.persistent-nodemap.slow-path',
1926 1934 default=b"abort",
1927 1935 )
1928 1936
1929 1937 coreconfigitem(
1930 1938 b'storage',
1931 1939 b'revlog.reuse-external-delta',
1932 1940 default=True,
1933 1941 )
1934 1942 coreconfigitem(
1935 1943 b'storage',
1936 1944 b'revlog.reuse-external-delta-parent',
1937 1945 default=None,
1938 1946 )
1939 1947 coreconfigitem(
1940 1948 b'storage',
1941 1949 b'revlog.zlib.level',
1942 1950 default=None,
1943 1951 )
1944 1952 coreconfigitem(
1945 1953 b'storage',
1946 1954 b'revlog.zstd.level',
1947 1955 default=None,
1948 1956 )
1949 1957 coreconfigitem(
1950 1958 b'server',
1951 1959 b'bookmarks-pushkey-compat',
1952 1960 default=True,
1953 1961 )
1954 1962 coreconfigitem(
1955 1963 b'server',
1956 1964 b'bundle1',
1957 1965 default=True,
1958 1966 )
1959 1967 coreconfigitem(
1960 1968 b'server',
1961 1969 b'bundle1gd',
1962 1970 default=None,
1963 1971 )
1964 1972 coreconfigitem(
1965 1973 b'server',
1966 1974 b'bundle1.pull',
1967 1975 default=None,
1968 1976 )
1969 1977 coreconfigitem(
1970 1978 b'server',
1971 1979 b'bundle1gd.pull',
1972 1980 default=None,
1973 1981 )
1974 1982 coreconfigitem(
1975 1983 b'server',
1976 1984 b'bundle1.push',
1977 1985 default=None,
1978 1986 )
1979 1987 coreconfigitem(
1980 1988 b'server',
1981 1989 b'bundle1gd.push',
1982 1990 default=None,
1983 1991 )
1984 1992 coreconfigitem(
1985 1993 b'server',
1986 1994 b'bundle2.stream',
1987 1995 default=True,
1988 1996 alias=[(b'experimental', b'bundle2.stream')],
1989 1997 )
1990 1998 coreconfigitem(
1991 1999 b'server',
1992 2000 b'compressionengines',
1993 2001 default=list,
1994 2002 )
1995 2003 coreconfigitem(
1996 2004 b'server',
1997 2005 b'concurrent-push-mode',
1998 2006 default=b'check-related',
1999 2007 )
2000 2008 coreconfigitem(
2001 2009 b'server',
2002 2010 b'disablefullbundle',
2003 2011 default=False,
2004 2012 )
2005 2013 coreconfigitem(
2006 2014 b'server',
2007 2015 b'maxhttpheaderlen',
2008 2016 default=1024,
2009 2017 )
2010 2018 coreconfigitem(
2011 2019 b'server',
2012 2020 b'pullbundle',
2013 2021 default=False,
2014 2022 )
2015 2023 coreconfigitem(
2016 2024 b'server',
2017 2025 b'preferuncompressed',
2018 2026 default=False,
2019 2027 )
2020 2028 coreconfigitem(
2021 2029 b'server',
2022 2030 b'streamunbundle',
2023 2031 default=False,
2024 2032 )
2025 2033 coreconfigitem(
2026 2034 b'server',
2027 2035 b'uncompressed',
2028 2036 default=True,
2029 2037 )
2030 2038 coreconfigitem(
2031 2039 b'server',
2032 2040 b'uncompressedallowsecret',
2033 2041 default=False,
2034 2042 )
2035 2043 coreconfigitem(
2036 2044 b'server',
2037 2045 b'view',
2038 2046 default=b'served',
2039 2047 )
2040 2048 coreconfigitem(
2041 2049 b'server',
2042 2050 b'validate',
2043 2051 default=False,
2044 2052 )
2045 2053 coreconfigitem(
2046 2054 b'server',
2047 2055 b'zliblevel',
2048 2056 default=-1,
2049 2057 )
2050 2058 coreconfigitem(
2051 2059 b'server',
2052 2060 b'zstdlevel',
2053 2061 default=3,
2054 2062 )
2055 2063 coreconfigitem(
2056 2064 b'share',
2057 2065 b'pool',
2058 2066 default=None,
2059 2067 )
2060 2068 coreconfigitem(
2061 2069 b'share',
2062 2070 b'poolnaming',
2063 2071 default=b'identity',
2064 2072 )
2065 2073 coreconfigitem(
2066 2074 b'share',
2067 2075 b'safe-mismatch.source-not-safe',
2068 2076 default=b'abort',
2069 2077 )
2070 2078 coreconfigitem(
2071 2079 b'share',
2072 2080 b'safe-mismatch.source-safe',
2073 2081 default=b'abort',
2074 2082 )
2075 2083 coreconfigitem(
2076 2084 b'share',
2077 2085 b'safe-mismatch.source-not-safe.warn',
2078 2086 default=True,
2079 2087 )
2080 2088 coreconfigitem(
2081 2089 b'share',
2082 2090 b'safe-mismatch.source-safe.warn',
2083 2091 default=True,
2084 2092 )
2085 2093 coreconfigitem(
2086 2094 b'shelve',
2087 2095 b'maxbackups',
2088 2096 default=10,
2089 2097 )
2090 2098 coreconfigitem(
2091 2099 b'smtp',
2092 2100 b'host',
2093 2101 default=None,
2094 2102 )
2095 2103 coreconfigitem(
2096 2104 b'smtp',
2097 2105 b'local_hostname',
2098 2106 default=None,
2099 2107 )
2100 2108 coreconfigitem(
2101 2109 b'smtp',
2102 2110 b'password',
2103 2111 default=None,
2104 2112 )
2105 2113 coreconfigitem(
2106 2114 b'smtp',
2107 2115 b'port',
2108 2116 default=dynamicdefault,
2109 2117 )
2110 2118 coreconfigitem(
2111 2119 b'smtp',
2112 2120 b'tls',
2113 2121 default=b'none',
2114 2122 )
2115 2123 coreconfigitem(
2116 2124 b'smtp',
2117 2125 b'username',
2118 2126 default=None,
2119 2127 )
2120 2128 coreconfigitem(
2121 2129 b'sparse',
2122 2130 b'missingwarning',
2123 2131 default=True,
2124 2132 experimental=True,
2125 2133 )
2126 2134 coreconfigitem(
2127 2135 b'subrepos',
2128 2136 b'allowed',
2129 2137 default=dynamicdefault, # to make backporting simpler
2130 2138 )
2131 2139 coreconfigitem(
2132 2140 b'subrepos',
2133 2141 b'hg:allowed',
2134 2142 default=dynamicdefault,
2135 2143 )
2136 2144 coreconfigitem(
2137 2145 b'subrepos',
2138 2146 b'git:allowed',
2139 2147 default=dynamicdefault,
2140 2148 )
2141 2149 coreconfigitem(
2142 2150 b'subrepos',
2143 2151 b'svn:allowed',
2144 2152 default=dynamicdefault,
2145 2153 )
2146 2154 coreconfigitem(
2147 2155 b'templates',
2148 2156 b'.*',
2149 2157 default=None,
2150 2158 generic=True,
2151 2159 )
2152 2160 coreconfigitem(
2153 2161 b'templateconfig',
2154 2162 b'.*',
2155 2163 default=dynamicdefault,
2156 2164 generic=True,
2157 2165 )
2158 2166 coreconfigitem(
2159 2167 b'trusted',
2160 2168 b'groups',
2161 2169 default=list,
2162 2170 )
2163 2171 coreconfigitem(
2164 2172 b'trusted',
2165 2173 b'users',
2166 2174 default=list,
2167 2175 )
2168 2176 coreconfigitem(
2169 2177 b'ui',
2170 2178 b'_usedassubrepo',
2171 2179 default=False,
2172 2180 )
2173 2181 coreconfigitem(
2174 2182 b'ui',
2175 2183 b'allowemptycommit',
2176 2184 default=False,
2177 2185 )
2178 2186 coreconfigitem(
2179 2187 b'ui',
2180 2188 b'archivemeta',
2181 2189 default=True,
2182 2190 )
2183 2191 coreconfigitem(
2184 2192 b'ui',
2185 2193 b'askusername',
2186 2194 default=False,
2187 2195 )
2188 2196 coreconfigitem(
2189 2197 b'ui',
2190 2198 b'available-memory',
2191 2199 default=None,
2192 2200 )
2193 2201
2194 2202 coreconfigitem(
2195 2203 b'ui',
2196 2204 b'clonebundlefallback',
2197 2205 default=False,
2198 2206 )
2199 2207 coreconfigitem(
2200 2208 b'ui',
2201 2209 b'clonebundleprefers',
2202 2210 default=list,
2203 2211 )
2204 2212 coreconfigitem(
2205 2213 b'ui',
2206 2214 b'clonebundles',
2207 2215 default=True,
2208 2216 )
2209 2217 coreconfigitem(
2210 2218 b'ui',
2211 2219 b'color',
2212 2220 default=b'auto',
2213 2221 )
2214 2222 coreconfigitem(
2215 2223 b'ui',
2216 2224 b'commitsubrepos',
2217 2225 default=False,
2218 2226 )
2219 2227 coreconfigitem(
2220 2228 b'ui',
2221 2229 b'debug',
2222 2230 default=False,
2223 2231 )
2224 2232 coreconfigitem(
2225 2233 b'ui',
2226 2234 b'debugger',
2227 2235 default=None,
2228 2236 )
2229 2237 coreconfigitem(
2230 2238 b'ui',
2231 2239 b'editor',
2232 2240 default=dynamicdefault,
2233 2241 )
2234 2242 coreconfigitem(
2235 2243 b'ui',
2236 2244 b'detailed-exit-code',
2237 2245 default=False,
2238 2246 experimental=True,
2239 2247 )
2240 2248 coreconfigitem(
2241 2249 b'ui',
2242 2250 b'fallbackencoding',
2243 2251 default=None,
2244 2252 )
2245 2253 coreconfigitem(
2246 2254 b'ui',
2247 2255 b'forcecwd',
2248 2256 default=None,
2249 2257 )
2250 2258 coreconfigitem(
2251 2259 b'ui',
2252 2260 b'forcemerge',
2253 2261 default=None,
2254 2262 )
2255 2263 coreconfigitem(
2256 2264 b'ui',
2257 2265 b'formatdebug',
2258 2266 default=False,
2259 2267 )
2260 2268 coreconfigitem(
2261 2269 b'ui',
2262 2270 b'formatjson',
2263 2271 default=False,
2264 2272 )
2265 2273 coreconfigitem(
2266 2274 b'ui',
2267 2275 b'formatted',
2268 2276 default=None,
2269 2277 )
2270 2278 coreconfigitem(
2271 2279 b'ui',
2272 2280 b'interactive',
2273 2281 default=None,
2274 2282 )
2275 2283 coreconfigitem(
2276 2284 b'ui',
2277 2285 b'interface',
2278 2286 default=None,
2279 2287 )
2280 2288 coreconfigitem(
2281 2289 b'ui',
2282 2290 b'interface.chunkselector',
2283 2291 default=None,
2284 2292 )
2285 2293 coreconfigitem(
2286 2294 b'ui',
2287 2295 b'large-file-limit',
2288 2296 default=10000000,
2289 2297 )
2290 2298 coreconfigitem(
2291 2299 b'ui',
2292 2300 b'logblockedtimes',
2293 2301 default=False,
2294 2302 )
2295 2303 coreconfigitem(
2296 2304 b'ui',
2297 2305 b'merge',
2298 2306 default=None,
2299 2307 )
2300 2308 coreconfigitem(
2301 2309 b'ui',
2302 2310 b'mergemarkers',
2303 2311 default=b'basic',
2304 2312 )
2305 2313 coreconfigitem(
2306 2314 b'ui',
2307 2315 b'message-output',
2308 2316 default=b'stdio',
2309 2317 )
2310 2318 coreconfigitem(
2311 2319 b'ui',
2312 2320 b'nontty',
2313 2321 default=False,
2314 2322 )
2315 2323 coreconfigitem(
2316 2324 b'ui',
2317 2325 b'origbackuppath',
2318 2326 default=None,
2319 2327 )
2320 2328 coreconfigitem(
2321 2329 b'ui',
2322 2330 b'paginate',
2323 2331 default=True,
2324 2332 )
2325 2333 coreconfigitem(
2326 2334 b'ui',
2327 2335 b'patch',
2328 2336 default=None,
2329 2337 )
2330 2338 coreconfigitem(
2331 2339 b'ui',
2332 2340 b'portablefilenames',
2333 2341 default=b'warn',
2334 2342 )
2335 2343 coreconfigitem(
2336 2344 b'ui',
2337 2345 b'promptecho',
2338 2346 default=False,
2339 2347 )
2340 2348 coreconfigitem(
2341 2349 b'ui',
2342 2350 b'quiet',
2343 2351 default=False,
2344 2352 )
2345 2353 coreconfigitem(
2346 2354 b'ui',
2347 2355 b'quietbookmarkmove',
2348 2356 default=False,
2349 2357 )
2350 2358 coreconfigitem(
2351 2359 b'ui',
2352 2360 b'relative-paths',
2353 2361 default=b'legacy',
2354 2362 )
2355 2363 coreconfigitem(
2356 2364 b'ui',
2357 2365 b'remotecmd',
2358 2366 default=b'hg',
2359 2367 )
2360 2368 coreconfigitem(
2361 2369 b'ui',
2362 2370 b'report_untrusted',
2363 2371 default=True,
2364 2372 )
2365 2373 coreconfigitem(
2366 2374 b'ui',
2367 2375 b'rollback',
2368 2376 default=True,
2369 2377 )
2370 2378 coreconfigitem(
2371 2379 b'ui',
2372 2380 b'signal-safe-lock',
2373 2381 default=True,
2374 2382 )
2375 2383 coreconfigitem(
2376 2384 b'ui',
2377 2385 b'slash',
2378 2386 default=False,
2379 2387 )
2380 2388 coreconfigitem(
2381 2389 b'ui',
2382 2390 b'ssh',
2383 2391 default=b'ssh',
2384 2392 )
2385 2393 coreconfigitem(
2386 2394 b'ui',
2387 2395 b'ssherrorhint',
2388 2396 default=None,
2389 2397 )
2390 2398 coreconfigitem(
2391 2399 b'ui',
2392 2400 b'statuscopies',
2393 2401 default=False,
2394 2402 )
2395 2403 coreconfigitem(
2396 2404 b'ui',
2397 2405 b'strict',
2398 2406 default=False,
2399 2407 )
2400 2408 coreconfigitem(
2401 2409 b'ui',
2402 2410 b'style',
2403 2411 default=b'',
2404 2412 )
2405 2413 coreconfigitem(
2406 2414 b'ui',
2407 2415 b'supportcontact',
2408 2416 default=None,
2409 2417 )
2410 2418 coreconfigitem(
2411 2419 b'ui',
2412 2420 b'textwidth',
2413 2421 default=78,
2414 2422 )
2415 2423 coreconfigitem(
2416 2424 b'ui',
2417 2425 b'timeout',
2418 2426 default=b'600',
2419 2427 )
2420 2428 coreconfigitem(
2421 2429 b'ui',
2422 2430 b'timeout.warn',
2423 2431 default=0,
2424 2432 )
2425 2433 coreconfigitem(
2426 2434 b'ui',
2427 2435 b'timestamp-output',
2428 2436 default=False,
2429 2437 )
2430 2438 coreconfigitem(
2431 2439 b'ui',
2432 2440 b'traceback',
2433 2441 default=False,
2434 2442 )
2435 2443 coreconfigitem(
2436 2444 b'ui',
2437 2445 b'tweakdefaults',
2438 2446 default=False,
2439 2447 )
2440 2448 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2441 2449 coreconfigitem(
2442 2450 b'ui',
2443 2451 b'verbose',
2444 2452 default=False,
2445 2453 )
2446 2454 coreconfigitem(
2447 2455 b'verify',
2448 2456 b'skipflags',
2449 2457 default=None,
2450 2458 )
2451 2459 coreconfigitem(
2452 2460 b'web',
2453 2461 b'allowbz2',
2454 2462 default=False,
2455 2463 )
2456 2464 coreconfigitem(
2457 2465 b'web',
2458 2466 b'allowgz',
2459 2467 default=False,
2460 2468 )
2461 2469 coreconfigitem(
2462 2470 b'web',
2463 2471 b'allow-pull',
2464 2472 alias=[(b'web', b'allowpull')],
2465 2473 default=True,
2466 2474 )
2467 2475 coreconfigitem(
2468 2476 b'web',
2469 2477 b'allow-push',
2470 2478 alias=[(b'web', b'allow_push')],
2471 2479 default=list,
2472 2480 )
2473 2481 coreconfigitem(
2474 2482 b'web',
2475 2483 b'allowzip',
2476 2484 default=False,
2477 2485 )
2478 2486 coreconfigitem(
2479 2487 b'web',
2480 2488 b'archivesubrepos',
2481 2489 default=False,
2482 2490 )
2483 2491 coreconfigitem(
2484 2492 b'web',
2485 2493 b'cache',
2486 2494 default=True,
2487 2495 )
2488 2496 coreconfigitem(
2489 2497 b'web',
2490 2498 b'comparisoncontext',
2491 2499 default=5,
2492 2500 )
2493 2501 coreconfigitem(
2494 2502 b'web',
2495 2503 b'contact',
2496 2504 default=None,
2497 2505 )
2498 2506 coreconfigitem(
2499 2507 b'web',
2500 2508 b'deny_push',
2501 2509 default=list,
2502 2510 )
2503 2511 coreconfigitem(
2504 2512 b'web',
2505 2513 b'guessmime',
2506 2514 default=False,
2507 2515 )
2508 2516 coreconfigitem(
2509 2517 b'web',
2510 2518 b'hidden',
2511 2519 default=False,
2512 2520 )
2513 2521 coreconfigitem(
2514 2522 b'web',
2515 2523 b'labels',
2516 2524 default=list,
2517 2525 )
2518 2526 coreconfigitem(
2519 2527 b'web',
2520 2528 b'logoimg',
2521 2529 default=b'hglogo.png',
2522 2530 )
2523 2531 coreconfigitem(
2524 2532 b'web',
2525 2533 b'logourl',
2526 2534 default=b'https://mercurial-scm.org/',
2527 2535 )
2528 2536 coreconfigitem(
2529 2537 b'web',
2530 2538 b'accesslog',
2531 2539 default=b'-',
2532 2540 )
2533 2541 coreconfigitem(
2534 2542 b'web',
2535 2543 b'address',
2536 2544 default=b'',
2537 2545 )
2538 2546 coreconfigitem(
2539 2547 b'web',
2540 2548 b'allow-archive',
2541 2549 alias=[(b'web', b'allow_archive')],
2542 2550 default=list,
2543 2551 )
2544 2552 coreconfigitem(
2545 2553 b'web',
2546 2554 b'allow_read',
2547 2555 default=list,
2548 2556 )
2549 2557 coreconfigitem(
2550 2558 b'web',
2551 2559 b'baseurl',
2552 2560 default=None,
2553 2561 )
2554 2562 coreconfigitem(
2555 2563 b'web',
2556 2564 b'cacerts',
2557 2565 default=None,
2558 2566 )
2559 2567 coreconfigitem(
2560 2568 b'web',
2561 2569 b'certificate',
2562 2570 default=None,
2563 2571 )
2564 2572 coreconfigitem(
2565 2573 b'web',
2566 2574 b'collapse',
2567 2575 default=False,
2568 2576 )
2569 2577 coreconfigitem(
2570 2578 b'web',
2571 2579 b'csp',
2572 2580 default=None,
2573 2581 )
2574 2582 coreconfigitem(
2575 2583 b'web',
2576 2584 b'deny_read',
2577 2585 default=list,
2578 2586 )
2579 2587 coreconfigitem(
2580 2588 b'web',
2581 2589 b'descend',
2582 2590 default=True,
2583 2591 )
2584 2592 coreconfigitem(
2585 2593 b'web',
2586 2594 b'description',
2587 2595 default=b"",
2588 2596 )
2589 2597 coreconfigitem(
2590 2598 b'web',
2591 2599 b'encoding',
2592 2600 default=lambda: encoding.encoding,
2593 2601 )
2594 2602 coreconfigitem(
2595 2603 b'web',
2596 2604 b'errorlog',
2597 2605 default=b'-',
2598 2606 )
2599 2607 coreconfigitem(
2600 2608 b'web',
2601 2609 b'ipv6',
2602 2610 default=False,
2603 2611 )
2604 2612 coreconfigitem(
2605 2613 b'web',
2606 2614 b'maxchanges',
2607 2615 default=10,
2608 2616 )
2609 2617 coreconfigitem(
2610 2618 b'web',
2611 2619 b'maxfiles',
2612 2620 default=10,
2613 2621 )
2614 2622 coreconfigitem(
2615 2623 b'web',
2616 2624 b'maxshortchanges',
2617 2625 default=60,
2618 2626 )
2619 2627 coreconfigitem(
2620 2628 b'web',
2621 2629 b'motd',
2622 2630 default=b'',
2623 2631 )
2624 2632 coreconfigitem(
2625 2633 b'web',
2626 2634 b'name',
2627 2635 default=dynamicdefault,
2628 2636 )
2629 2637 coreconfigitem(
2630 2638 b'web',
2631 2639 b'port',
2632 2640 default=8000,
2633 2641 )
2634 2642 coreconfigitem(
2635 2643 b'web',
2636 2644 b'prefix',
2637 2645 default=b'',
2638 2646 )
2639 2647 coreconfigitem(
2640 2648 b'web',
2641 2649 b'push_ssl',
2642 2650 default=True,
2643 2651 )
2644 2652 coreconfigitem(
2645 2653 b'web',
2646 2654 b'refreshinterval',
2647 2655 default=20,
2648 2656 )
2649 2657 coreconfigitem(
2650 2658 b'web',
2651 2659 b'server-header',
2652 2660 default=None,
2653 2661 )
2654 2662 coreconfigitem(
2655 2663 b'web',
2656 2664 b'static',
2657 2665 default=None,
2658 2666 )
2659 2667 coreconfigitem(
2660 2668 b'web',
2661 2669 b'staticurl',
2662 2670 default=None,
2663 2671 )
2664 2672 coreconfigitem(
2665 2673 b'web',
2666 2674 b'stripes',
2667 2675 default=1,
2668 2676 )
2669 2677 coreconfigitem(
2670 2678 b'web',
2671 2679 b'style',
2672 2680 default=b'paper',
2673 2681 )
2674 2682 coreconfigitem(
2675 2683 b'web',
2676 2684 b'templates',
2677 2685 default=None,
2678 2686 )
2679 2687 coreconfigitem(
2680 2688 b'web',
2681 2689 b'view',
2682 2690 default=b'served',
2683 2691 experimental=True,
2684 2692 )
2685 2693 coreconfigitem(
2686 2694 b'worker',
2687 2695 b'backgroundclose',
2688 2696 default=dynamicdefault,
2689 2697 )
2690 2698 # Windows defaults to a limit of 512 open files. A buffer of 128
2691 2699 # should give us enough headway.
2692 2700 coreconfigitem(
2693 2701 b'worker',
2694 2702 b'backgroundclosemaxqueue',
2695 2703 default=384,
2696 2704 )
2697 2705 coreconfigitem(
2698 2706 b'worker',
2699 2707 b'backgroundcloseminfilecount',
2700 2708 default=2048,
2701 2709 )
2702 2710 coreconfigitem(
2703 2711 b'worker',
2704 2712 b'backgroundclosethreadcount',
2705 2713 default=4,
2706 2714 )
2707 2715 coreconfigitem(
2708 2716 b'worker',
2709 2717 b'enabled',
2710 2718 default=True,
2711 2719 )
2712 2720 coreconfigitem(
2713 2721 b'worker',
2714 2722 b'numcpus',
2715 2723 default=None,
2716 2724 )
2717 2725
2718 2726 # Rebase related configuration moved to core because other extension are doing
2719 2727 # strange things. For example, shelve import the extensions to reuse some bit
2720 2728 # without formally loading it.
2721 2729 coreconfigitem(
2722 2730 b'commands',
2723 2731 b'rebase.requiredest',
2724 2732 default=False,
2725 2733 )
2726 2734 coreconfigitem(
2727 2735 b'experimental',
2728 2736 b'rebaseskipobsolete',
2729 2737 default=True,
2730 2738 )
2731 2739 coreconfigitem(
2732 2740 b'rebase',
2733 2741 b'singletransaction',
2734 2742 default=False,
2735 2743 )
2736 2744 coreconfigitem(
2737 2745 b'rebase',
2738 2746 b'experimental.inmemory',
2739 2747 default=False,
2740 2748 )
@@ -1,1288 +1,1299 b''
1 1 # filemerge.py - file-level merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007, 2008 Olivia Mackall <olivia@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import contextlib
10 10 import os
11 11 import re
12 12 import shutil
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 hex,
17 17 short,
18 18 )
19 19 from .pycompat import (
20 20 getattr,
21 21 )
22 22
23 23 from . import (
24 24 encoding,
25 25 error,
26 26 formatter,
27 27 match,
28 28 pycompat,
29 29 registrar,
30 30 scmutil,
31 31 simplemerge,
32 32 tagmerge,
33 33 templatekw,
34 34 templater,
35 35 templateutil,
36 36 util,
37 37 )
38 38
39 39 from .utils import (
40 40 procutil,
41 41 stringutil,
42 42 )
43 43
44 44
45 45 def _toolstr(ui, tool, part, *args):
46 46 return ui.config(b"merge-tools", tool + b"." + part, *args)
47 47
48 48
49 49 def _toolbool(ui, tool, part, *args):
50 50 return ui.configbool(b"merge-tools", tool + b"." + part, *args)
51 51
52 52
53 53 def _toollist(ui, tool, part):
54 54 return ui.configlist(b"merge-tools", tool + b"." + part)
55 55
56 56
57 57 internals = {}
58 58 # Merge tools to document.
59 59 internalsdoc = {}
60 60
61 61 internaltool = registrar.internalmerge()
62 62
63 63 # internal tool merge types
64 64 nomerge = internaltool.nomerge
65 65 mergeonly = internaltool.mergeonly # just the full merge, no premerge
66 66 fullmerge = internaltool.fullmerge # both premerge and merge
67 67
68 68 # IMPORTANT: keep the last line of this prompt very short ("What do you want to
69 69 # do?") because of issue6158, ideally to <40 English characters (to allow other
70 70 # languages that may take more columns to still have a chance to fit in an
71 71 # 80-column screen).
72 72 _localchangedotherdeletedmsg = _(
73 73 b"file '%(fd)s' was deleted in other%(o)s but was modified in local%(l)s.\n"
74 74 b"You can use (c)hanged version, (d)elete, or leave (u)nresolved.\n"
75 75 b"What do you want to do?"
76 76 b"$$ &Changed $$ &Delete $$ &Unresolved"
77 77 )
78 78
79 79 _otherchangedlocaldeletedmsg = _(
80 80 b"file '%(fd)s' was deleted in local%(l)s but was modified in other%(o)s.\n"
81 81 b"You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.\n"
82 82 b"What do you want to do?"
83 83 b"$$ &Changed $$ &Deleted $$ &Unresolved"
84 84 )
85 85
86 86
87 87 class absentfilectx:
88 88 """Represents a file that's ostensibly in a context but is actually not
89 89 present in it.
90 90
91 91 This is here because it's very specific to the filemerge code for now --
92 92 other code is likely going to break with the values this returns."""
93 93
94 94 def __init__(self, ctx, f):
95 95 self._ctx = ctx
96 96 self._f = f
97 97
98 98 def __bytes__(self):
99 99 return b'absent file %s@%s' % (self._f, self._ctx)
100 100
101 101 def path(self):
102 102 return self._f
103 103
104 104 def size(self):
105 105 return None
106 106
107 107 def data(self):
108 108 return None
109 109
110 110 def filenode(self):
111 111 return self._ctx.repo().nullid
112 112
113 113 _customcmp = True
114 114
115 115 def cmp(self, fctx):
116 116 """compare with other file context
117 117
118 118 returns True if different from fctx.
119 119 """
120 120 return not (
121 121 fctx.isabsent()
122 122 and fctx.changectx() == self.changectx()
123 123 and fctx.path() == self.path()
124 124 )
125 125
126 126 def flags(self):
127 127 return b''
128 128
129 129 def changectx(self):
130 130 return self._ctx
131 131
132 132 def isbinary(self):
133 133 return False
134 134
135 135 def isabsent(self):
136 136 return True
137 137
138 138
139 139 def _findtool(ui, tool):
140 140 if tool in internals:
141 141 return tool
142 142 cmd = _toolstr(ui, tool, b"executable", tool)
143 143 if cmd.startswith(b'python:'):
144 144 return cmd
145 145 return findexternaltool(ui, tool)
146 146
147 147
148 148 def _quotetoolpath(cmd):
149 149 if cmd.startswith(b'python:'):
150 150 return cmd
151 151 return procutil.shellquote(cmd)
152 152
153 153
154 154 def findexternaltool(ui, tool):
155 155 for kn in (b"regkey", b"regkeyalt"):
156 156 k = _toolstr(ui, tool, kn)
157 157 if not k:
158 158 continue
159 159 p = util.lookupreg(k, _toolstr(ui, tool, b"regname"))
160 160 if p:
161 161 p = procutil.findexe(p + _toolstr(ui, tool, b"regappend", b""))
162 162 if p:
163 163 return p
164 164 exe = _toolstr(ui, tool, b"executable", tool)
165 165 return procutil.findexe(util.expandpath(exe))
166 166
167 167
168 168 def _picktool(repo, ui, path, binary, symlink, changedelete):
169 169 strictcheck = ui.configbool(b'merge', b'strict-capability-check')
170 170
171 171 def hascapability(tool, capability, strict=False):
172 172 if tool in internals:
173 173 return strict and internals[tool].capabilities.get(capability)
174 174 return _toolbool(ui, tool, capability)
175 175
176 176 def supportscd(tool):
177 177 return tool in internals and internals[tool].mergetype == nomerge
178 178
179 179 def check(tool, pat, symlink, binary, changedelete):
180 180 tmsg = tool
181 181 if pat:
182 182 tmsg = _(b"%s (for pattern %s)") % (tool, pat)
183 183 if not _findtool(ui, tool):
184 184 if pat: # explicitly requested tool deserves a warning
185 185 ui.warn(_(b"couldn't find merge tool %s\n") % tmsg)
186 186 else: # configured but non-existing tools are more silent
187 187 ui.note(_(b"couldn't find merge tool %s\n") % tmsg)
188 188 elif symlink and not hascapability(tool, b"symlink", strictcheck):
189 189 ui.warn(_(b"tool %s can't handle symlinks\n") % tmsg)
190 190 elif binary and not hascapability(tool, b"binary", strictcheck):
191 191 ui.warn(_(b"tool %s can't handle binary\n") % tmsg)
192 192 elif changedelete and not supportscd(tool):
193 193 # the nomerge tools are the only tools that support change/delete
194 194 # conflicts
195 195 pass
196 196 elif not procutil.gui() and _toolbool(ui, tool, b"gui"):
197 197 ui.warn(_(b"tool %s requires a GUI\n") % tmsg)
198 198 else:
199 199 return True
200 200 return False
201 201
202 202 # internal config: ui.forcemerge
203 203 # forcemerge comes from command line arguments, highest priority
204 204 force = ui.config(b'ui', b'forcemerge')
205 205 if force:
206 206 toolpath = _findtool(ui, force)
207 207 if changedelete and not supportscd(toolpath):
208 208 return b":prompt", None
209 209 else:
210 210 if toolpath:
211 211 return (force, _quotetoolpath(toolpath))
212 212 else:
213 213 # mimic HGMERGE if given tool not found
214 214 return (force, force)
215 215
216 216 # HGMERGE takes next precedence
217 217 hgmerge = encoding.environ.get(b"HGMERGE")
218 218 if hgmerge:
219 219 if changedelete and not supportscd(hgmerge):
220 220 return b":prompt", None
221 221 else:
222 222 return (hgmerge, hgmerge)
223 223
224 224 # then patterns
225 225
226 226 # whether binary capability should be checked strictly
227 227 binarycap = binary and strictcheck
228 228
229 229 for pat, tool in ui.configitems(b"merge-patterns"):
230 230 mf = match.match(repo.root, b'', [pat])
231 231 if mf(path) and check(tool, pat, symlink, binarycap, changedelete):
232 232 if binary and not hascapability(tool, b"binary", strict=True):
233 233 ui.warn(
234 234 _(
235 235 b"warning: check merge-patterns configurations,"
236 236 b" if %r for binary file %r is unintentional\n"
237 237 b"(see 'hg help merge-tools'"
238 238 b" for binary files capability)\n"
239 239 )
240 240 % (pycompat.bytestr(tool), pycompat.bytestr(path))
241 241 )
242 242 toolpath = _findtool(ui, tool)
243 243 return (tool, _quotetoolpath(toolpath))
244 244
245 245 # then merge tools
246 246 tools = {}
247 247 disabled = set()
248 248 for k, v in ui.configitems(b"merge-tools"):
249 249 t = k.split(b'.')[0]
250 250 if t not in tools:
251 251 tools[t] = int(_toolstr(ui, t, b"priority"))
252 252 if _toolbool(ui, t, b"disabled"):
253 253 disabled.add(t)
254 254 names = tools.keys()
255 255 tools = sorted(
256 256 [(-p, tool) for tool, p in tools.items() if tool not in disabled]
257 257 )
258 258 uimerge = ui.config(b"ui", b"merge")
259 259 if uimerge:
260 260 # external tools defined in uimerge won't be able to handle
261 261 # change/delete conflicts
262 262 if check(uimerge, path, symlink, binary, changedelete):
263 263 if uimerge not in names and not changedelete:
264 264 return (uimerge, uimerge)
265 265 tools.insert(0, (None, uimerge)) # highest priority
266 266 tools.append((None, b"hgmerge")) # the old default, if found
267 267 for p, t in tools:
268 268 if check(t, None, symlink, binary, changedelete):
269 269 toolpath = _findtool(ui, t)
270 270 return (t, _quotetoolpath(toolpath))
271 271
272 272 # internal merge or prompt as last resort
273 273 if symlink or binary or changedelete:
274 274 if not changedelete and len(tools):
275 275 # any tool is rejected by capability for symlink or binary
276 276 ui.warn(_(b"no tool found to merge %s\n") % path)
277 277 return b":prompt", None
278 278 return b":merge", None
279 279
280 280
281 281 def _eoltype(data):
282 282 """Guess the EOL type of a file"""
283 283 if b'\0' in data: # binary
284 284 return None
285 285 if b'\r\n' in data: # Windows
286 286 return b'\r\n'
287 287 if b'\r' in data: # Old Mac
288 288 return b'\r'
289 289 if b'\n' in data: # UNIX
290 290 return b'\n'
291 291 return None # unknown
292 292
293 293
294 294 def _matcheol(file, backup):
295 295 """Convert EOL markers in a file to match origfile"""
296 296 tostyle = _eoltype(backup.data()) # No repo.wread filters?
297 297 if tostyle:
298 298 data = util.readfile(file)
299 299 style = _eoltype(data)
300 300 if style:
301 301 newdata = data.replace(style, tostyle)
302 302 if newdata != data:
303 303 util.writefile(file, newdata)
304 304
305 305
306 306 @internaltool(b'prompt', nomerge)
307 307 def _iprompt(repo, mynode, local, other, base, toolconf):
308 308 """Asks the user which of the local `p1()` or the other `p2()` version to
309 309 keep as the merged version."""
310 310 ui = repo.ui
311 311 fd = local.fctx.path()
312 312 uipathfn = scmutil.getuipathfn(repo)
313 313
314 314 # Avoid prompting during an in-memory merge since it doesn't support merge
315 315 # conflicts.
316 316 if local.fctx.changectx().isinmemory():
317 317 raise error.InMemoryMergeConflictsError(
318 318 b'in-memory merge does not support file conflicts'
319 319 )
320 320
321 321 prompts = partextras([local.label, other.label])
322 322 prompts[b'fd'] = uipathfn(fd)
323 323 try:
324 324 if other.fctx.isabsent():
325 325 index = ui.promptchoice(_localchangedotherdeletedmsg % prompts, 2)
326 326 choice = [b'local', b'other', b'unresolved'][index]
327 327 elif local.fctx.isabsent():
328 328 index = ui.promptchoice(_otherchangedlocaldeletedmsg % prompts, 2)
329 329 choice = [b'other', b'local', b'unresolved'][index]
330 330 else:
331 331 # IMPORTANT: keep the last line of this prompt ("What do you want to
332 332 # do?") very short, see comment next to _localchangedotherdeletedmsg
333 333 # at the top of the file for details.
334 334 index = ui.promptchoice(
335 335 _(
336 336 b"file '%(fd)s' needs to be resolved.\n"
337 337 b"You can keep (l)ocal%(l)s, take (o)ther%(o)s, or leave "
338 338 b"(u)nresolved.\n"
339 339 b"What do you want to do?"
340 340 b"$$ &Local $$ &Other $$ &Unresolved"
341 341 )
342 342 % prompts,
343 343 2,
344 344 )
345 345 choice = [b'local', b'other', b'unresolved'][index]
346 346
347 347 if choice == b'other':
348 348 return _iother(repo, mynode, local, other, base, toolconf)
349 349 elif choice == b'local':
350 350 return _ilocal(repo, mynode, local, other, base, toolconf)
351 351 elif choice == b'unresolved':
352 352 return _ifail(repo, mynode, local, other, base, toolconf)
353 353 except error.ResponseExpected:
354 354 ui.write(b"\n")
355 355 return _ifail(repo, mynode, local, other, base, toolconf)
356 356
357 357
358 358 @internaltool(b'local', nomerge)
359 359 def _ilocal(repo, mynode, local, other, base, toolconf):
360 360 """Uses the local `p1()` version of files as the merged version."""
361 361 return 0, local.fctx.isabsent()
362 362
363 363
364 364 @internaltool(b'other', nomerge)
365 365 def _iother(repo, mynode, local, other, base, toolconf):
366 366 """Uses the other `p2()` version of files as the merged version."""
367 367 if other.fctx.isabsent():
368 368 # local changed, remote deleted -- 'deleted' picked
369 369 _underlyingfctxifabsent(local.fctx).remove()
370 370 deleted = True
371 371 else:
372 372 _underlyingfctxifabsent(local.fctx).write(
373 373 other.fctx.data(), other.fctx.flags()
374 374 )
375 375 deleted = False
376 376 return 0, deleted
377 377
378 378
379 379 @internaltool(b'fail', nomerge)
380 380 def _ifail(repo, mynode, local, other, base, toolconf):
381 381 """
382 382 Rather than attempting to merge files that were modified on both
383 383 branches, it marks them as unresolved. The resolve command must be
384 384 used to resolve these conflicts."""
385 385 # for change/delete conflicts write out the changed version, then fail
386 386 if local.fctx.isabsent():
387 387 _underlyingfctxifabsent(local.fctx).write(
388 388 other.fctx.data(), other.fctx.flags()
389 389 )
390 390 return 1, False
391 391
392 392
393 393 def _underlyingfctxifabsent(filectx):
394 394 """Sometimes when resolving, our fcd is actually an absentfilectx, but
395 395 we want to write to it (to do the resolve). This helper returns the
396 396 underyling workingfilectx in that case.
397 397 """
398 398 if filectx.isabsent():
399 399 return filectx.changectx()[filectx.path()]
400 400 else:
401 401 return filectx
402 402
403 403
404 404 def _verifytext(input, ui):
405 405 """verifies that text is non-binary"""
406 406 if stringutil.binary(input.text()):
407 407 msg = _(b"%s looks like a binary file.") % input.fctx.path()
408 408 ui.warn(_(b'warning: %s\n') % msg)
409 409 raise error.Abort(msg)
410 410
411 411
412 412 def _premerge(repo, local, other, base, toolconf):
413 413 tool, toolpath, binary, symlink, scriptfn = toolconf
414 414 if symlink or local.fctx.isabsent() or other.fctx.isabsent():
415 415 return 1
416 416
417 417 ui = repo.ui
418 418
419 419 validkeep = [b'keep', b'keep-merge3', b'keep-mergediff']
420 420
421 421 # do we attempt to simplemerge first?
422 422 try:
423 423 premerge = _toolbool(ui, tool, b"premerge", not binary)
424 424 except error.ConfigError:
425 425 premerge = _toolstr(ui, tool, b"premerge", b"").lower()
426 426 if premerge not in validkeep:
427 427 _valid = b', '.join([b"'" + v + b"'" for v in validkeep])
428 428 raise error.ConfigError(
429 429 _(b"%s.premerge not valid ('%s' is neither boolean nor %s)")
430 430 % (tool, premerge, _valid)
431 431 )
432 432
433 433 if premerge:
434 434 mode = b'merge'
435 435 if premerge == b'keep-mergediff':
436 436 mode = b'mergediff'
437 437 elif premerge == b'keep-merge3':
438 438 mode = b'merge3'
439 439 if any(
440 440 stringutil.binary(input.text()) for input in (local, base, other)
441 441 ):
442 442 return 1 # continue merging
443 443 merged_text, conflicts = simplemerge.simplemerge(
444 444 local, base, other, mode=mode
445 445 )
446 446 if not conflicts or premerge in validkeep:
447 447 # fcd.flags() already has the merged flags (done in
448 448 # mergestate.resolve())
449 449 local.fctx.write(merged_text, local.fctx.flags())
450 450 if not conflicts:
451 451 ui.debug(b" premerge successful\n")
452 452 return 0
453 453 return 1 # continue merging
454 454
455 455
456 456 def _mergecheck(repo, mynode, fcd, fco, fca, toolconf):
457 457 tool, toolpath, binary, symlink, scriptfn = toolconf
458 458 uipathfn = scmutil.getuipathfn(repo)
459 459 if symlink:
460 460 repo.ui.warn(
461 461 _(b'warning: internal %s cannot merge symlinks for %s\n')
462 462 % (tool, uipathfn(fcd.path()))
463 463 )
464 464 return False
465 465 if fcd.isabsent() or fco.isabsent():
466 466 repo.ui.warn(
467 467 _(
468 468 b'warning: internal %s cannot merge change/delete '
469 469 b'conflict for %s\n'
470 470 )
471 471 % (tool, uipathfn(fcd.path()))
472 472 )
473 473 return False
474 474 return True
475 475
476 476
477 477 def _merge(repo, local, other, base, mode):
478 478 """
479 479 Uses the internal non-interactive simple merge algorithm for merging
480 480 files. It will fail if there are any conflicts and leave markers in
481 481 the partially merged file. Markers will have two sections, one for each side
482 482 of merge, unless mode equals 'union' which suppresses the markers."""
483 483 ui = repo.ui
484 484
485 485 try:
486 486 _verifytext(local, ui)
487 487 _verifytext(base, ui)
488 488 _verifytext(other, ui)
489 489 except error.Abort:
490 490 return True, True, False
491 491 else:
492 492 merged_text, conflicts = simplemerge.simplemerge(
493 493 local, base, other, mode=mode
494 494 )
495 495 # fcd.flags() already has the merged flags (done in
496 496 # mergestate.resolve())
497 497 local.fctx.write(merged_text, local.fctx.flags())
498 498 return True, conflicts, False
499 499
500 500
501 501 @internaltool(
502 502 b'union',
503 503 fullmerge,
504 504 _(
505 505 b"warning: conflicts while merging %s! "
506 506 b"(edit, then use 'hg resolve --mark')\n"
507 507 ),
508 508 precheck=_mergecheck,
509 509 )
510 510 def _iunion(repo, mynode, local, other, base, toolconf, backup):
511 511 """
512 512 Uses the internal non-interactive simple merge algorithm for merging
513 513 files. It will use both left and right sides for conflict regions.
514 514 No markers are inserted."""
515 515 return _merge(repo, local, other, base, b'union')
516 516
517 517
518 518 @internaltool(
519 519 b'merge',
520 520 fullmerge,
521 521 _(
522 522 b"warning: conflicts while merging %s! "
523 523 b"(edit, then use 'hg resolve --mark')\n"
524 524 ),
525 525 precheck=_mergecheck,
526 526 )
527 527 def _imerge(repo, mynode, local, other, base, toolconf, backup):
528 528 """
529 529 Uses the internal non-interactive simple merge algorithm for merging
530 530 files. It will fail if there are any conflicts and leave markers in
531 531 the partially merged file. Markers will have two sections, one for each side
532 532 of merge."""
533 533 return _merge(repo, local, other, base, b'merge')
534 534
535 535
536 536 @internaltool(
537 537 b'merge3',
538 538 fullmerge,
539 539 _(
540 540 b"warning: conflicts while merging %s! "
541 541 b"(edit, then use 'hg resolve --mark')\n"
542 542 ),
543 543 precheck=_mergecheck,
544 544 )
545 545 def _imerge3(repo, mynode, local, other, base, toolconf, backup):
546 546 """
547 547 Uses the internal non-interactive simple merge algorithm for merging
548 548 files. It will fail if there are any conflicts and leave markers in
549 549 the partially merged file. Marker will have three sections, one from each
550 550 side of the merge and one for the base content."""
551 551 return _merge(repo, local, other, base, b'merge3')
552 552
553 553
554 554 @internaltool(
555 555 b'merge3-lie-about-conflicts',
556 556 fullmerge,
557 557 b'',
558 558 precheck=_mergecheck,
559 559 )
560 560 def _imerge3alwaysgood(*args, **kwargs):
561 561 # Like merge3, but record conflicts as resolved with markers in place.
562 562 #
563 563 # This is used for `diff.merge` to show the differences between
564 564 # the auto-merge state and the committed merge state. It may be
565 565 # useful for other things.
566 566 b1, junk, b2 = _imerge3(*args, **kwargs)
567 567 # TODO is this right? I'm not sure what these return values mean,
568 568 # but as far as I can tell this will indicate to callers tha the
569 569 # merge succeeded.
570 570 return b1, False, b2
571 571
572 572
573 573 @internaltool(
574 574 b'mergediff',
575 575 fullmerge,
576 576 _(
577 577 b"warning: conflicts while merging %s! "
578 578 b"(edit, then use 'hg resolve --mark')\n"
579 579 ),
580 580 precheck=_mergecheck,
581 581 )
582 582 def _imerge_diff(repo, mynode, local, other, base, toolconf, backup):
583 583 """
584 584 Uses the internal non-interactive simple merge algorithm for merging
585 585 files. It will fail if there are any conflicts and leave markers in
586 586 the partially merged file. The marker will have two sections, one with the
587 587 content from one side of the merge, and one with a diff from the base
588 588 content to the content on the other side. (experimental)"""
589 589 return _merge(repo, local, other, base, b'mergediff')
590 590
591 591
592 592 @internaltool(b'merge-local', mergeonly, precheck=_mergecheck)
593 593 def _imergelocal(repo, mynode, local, other, base, toolconf, backup):
594 594 """
595 595 Like :merge, but resolve all conflicts non-interactively in favor
596 596 of the local `p1()` changes."""
597 597 return _merge(repo, local, other, base, b'local')
598 598
599 599
600 600 @internaltool(b'merge-other', mergeonly, precheck=_mergecheck)
601 601 def _imergeother(repo, mynode, local, other, base, toolconf, backup):
602 602 """
603 603 Like :merge, but resolve all conflicts non-interactively in favor
604 604 of the other `p2()` changes."""
605 605 return _merge(repo, local, other, base, b'other')
606 606
607 607
608 608 @internaltool(
609 609 b'tagmerge',
610 610 mergeonly,
611 611 _(
612 612 b"automatic tag merging of %s failed! "
613 613 b"(use 'hg resolve --tool :merge' or another merge "
614 614 b"tool of your choice)\n"
615 615 ),
616 616 )
617 617 def _itagmerge(repo, mynode, local, other, base, toolconf, backup):
618 618 """
619 619 Uses the internal tag merge algorithm (experimental).
620 620 """
621 621 success, status = tagmerge.merge(repo, local.fctx, other.fctx, base.fctx)
622 622 return success, status, False
623 623
624 624
625 625 @internaltool(b'dump', fullmerge, binary=True, symlink=True)
626 626 def _idump(repo, mynode, local, other, base, toolconf, backup):
627 627 """
628 628 Creates three versions of the files to merge, containing the
629 629 contents of local, other and base. These files can then be used to
630 630 perform a merge manually. If the file to be merged is named
631 631 ``a.txt``, these files will accordingly be named ``a.txt.local``,
632 632 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
633 633 same directory as ``a.txt``.
634 634
635 635 This implies premerge. Therefore, files aren't dumped, if premerge
636 636 runs successfully. Use :forcedump to forcibly write files out.
637 637 """
638 638 a = _workingpath(repo, local.fctx)
639 639 fd = local.fctx.path()
640 640
641 641 from . import context
642 642
643 643 if isinstance(local.fctx, context.overlayworkingfilectx):
644 644 raise error.InMemoryMergeConflictsError(
645 645 b'in-memory merge does not support the :dump tool.'
646 646 )
647 647
648 648 util.writefile(a + b".local", local.fctx.decodeddata())
649 649 repo.wwrite(fd + b".other", other.fctx.data(), other.fctx.flags())
650 650 repo.wwrite(fd + b".base", base.fctx.data(), base.fctx.flags())
651 651 return False, 1, False
652 652
653 653
654 654 @internaltool(b'forcedump', mergeonly, binary=True, symlink=True)
655 655 def _forcedump(repo, mynode, local, other, base, toolconf, backup):
656 656 """
657 657 Creates three versions of the files as same as :dump, but omits premerge.
658 658 """
659 659 return _idump(repo, mynode, local, other, base, toolconf, backup)
660 660
661 661
662 662 def _xmergeimm(repo, mynode, local, other, base, toolconf, backup):
663 663 # In-memory merge simply raises an exception on all external merge tools,
664 664 # for now.
665 665 #
666 666 # It would be possible to run most tools with temporary files, but this
667 667 # raises the question of what to do if the user only partially resolves the
668 668 # file -- we can't leave a merge state. (Copy to somewhere in the .hg/
669 669 # directory and tell the user how to get it is my best idea, but it's
670 670 # clunky.)
671 671 raise error.InMemoryMergeConflictsError(
672 672 b'in-memory merge does not support external merge tools'
673 673 )
674 674
675 675
676 676 def _describemerge(ui, repo, mynode, fcl, fcb, fco, env, toolpath, args):
677 677 tmpl = ui.config(b'command-templates', b'pre-merge-tool-output')
678 678 if not tmpl:
679 679 return
680 680
681 681 mappingdict = templateutil.mappingdict
682 682 props = {
683 683 b'ctx': fcl.changectx(),
684 684 b'node': hex(mynode),
685 685 b'path': fcl.path(),
686 686 b'local': mappingdict(
687 687 {
688 688 b'ctx': fcl.changectx(),
689 689 b'fctx': fcl,
690 690 b'node': hex(mynode),
691 691 b'name': _(b'local'),
692 692 b'islink': b'l' in fcl.flags(),
693 693 b'label': env[b'HG_MY_LABEL'],
694 694 }
695 695 ),
696 696 b'base': mappingdict(
697 697 {
698 698 b'ctx': fcb.changectx(),
699 699 b'fctx': fcb,
700 700 b'name': _(b'base'),
701 701 b'islink': b'l' in fcb.flags(),
702 702 b'label': env[b'HG_BASE_LABEL'],
703 703 }
704 704 ),
705 705 b'other': mappingdict(
706 706 {
707 707 b'ctx': fco.changectx(),
708 708 b'fctx': fco,
709 709 b'name': _(b'other'),
710 710 b'islink': b'l' in fco.flags(),
711 711 b'label': env[b'HG_OTHER_LABEL'],
712 712 }
713 713 ),
714 714 b'toolpath': toolpath,
715 715 b'toolargs': args,
716 716 }
717 717
718 718 # TODO: make all of this something that can be specified on a per-tool basis
719 719 tmpl = templater.unquotestring(tmpl)
720 720
721 721 # Not using cmdutil.rendertemplate here since it causes errors importing
722 722 # things for us to import cmdutil.
723 723 tres = formatter.templateresources(ui, repo)
724 724 t = formatter.maketemplater(
725 725 ui, tmpl, defaults=templatekw.keywords, resources=tres
726 726 )
727 727 ui.status(t.renderdefault(props))
728 728
729 729
730 730 def _xmerge(repo, mynode, local, other, base, toolconf, backup):
731 731 fcd = local.fctx
732 732 fco = other.fctx
733 733 fca = base.fctx
734 734 tool, toolpath, binary, symlink, scriptfn = toolconf
735 735 uipathfn = scmutil.getuipathfn(repo)
736 736 if fcd.isabsent() or fco.isabsent():
737 737 repo.ui.warn(
738 738 _(b'warning: %s cannot merge change/delete conflict for %s\n')
739 739 % (tool, uipathfn(fcd.path()))
740 740 )
741 741 return False, 1, None
742 742 localpath = _workingpath(repo, fcd)
743 743 args = _toolstr(repo.ui, tool, b"args")
744 744
745 745 files = [
746 746 (b"base", fca.path(), fca.decodeddata()),
747 747 (b"other", fco.path(), fco.decodeddata()),
748 748 ]
749 749 outpath = b""
750 750 if b"$output" in args:
751 751 # read input from backup, write to original
752 752 outpath = localpath
753 753 localoutputpath = backup.path()
754 754 # Remove the .orig to make syntax-highlighting more likely.
755 755 if localoutputpath.endswith(b'.orig'):
756 756 localoutputpath, ext = os.path.splitext(localoutputpath)
757 757 files.append((b"local", localoutputpath, backup.data()))
758 758
759 759 with _maketempfiles(files) as temppaths:
760 760 basepath, otherpath = temppaths[:2]
761 761 if len(temppaths) == 3:
762 762 localpath = temppaths[2]
763 763
764 764 def format_label(input):
765 765 if input.label_detail:
766 766 return b'%s: %s' % (input.label, input.label_detail)
767 767 else:
768 768 return input.label
769 769
770 770 env = {
771 771 b'HG_FILE': fcd.path(),
772 772 b'HG_MY_NODE': short(mynode),
773 773 b'HG_OTHER_NODE': short(fco.changectx().node()),
774 774 b'HG_BASE_NODE': short(fca.changectx().node()),
775 775 b'HG_MY_ISLINK': b'l' in fcd.flags(),
776 776 b'HG_OTHER_ISLINK': b'l' in fco.flags(),
777 777 b'HG_BASE_ISLINK': b'l' in fca.flags(),
778 778 b'HG_MY_LABEL': format_label(local),
779 779 b'HG_OTHER_LABEL': format_label(other),
780 780 b'HG_BASE_LABEL': format_label(base),
781 781 }
782 782 ui = repo.ui
783 783
784 784 replace = {
785 785 b'local': localpath,
786 786 b'base': basepath,
787 787 b'other': otherpath,
788 788 b'output': outpath,
789 789 b'labellocal': format_label(local),
790 790 b'labelother': format_label(other),
791 791 b'labelbase': format_label(base),
792 792 }
793 793 args = util.interpolate(
794 794 br'\$',
795 795 replace,
796 796 args,
797 797 lambda s: procutil.shellquote(util.localpath(s)),
798 798 )
799 799 if _toolbool(ui, tool, b"gui"):
800 800 repo.ui.status(
801 801 _(b'running merge tool %s for file %s\n')
802 802 % (tool, uipathfn(fcd.path()))
803 803 )
804 804 if scriptfn is None:
805 805 cmd = toolpath + b' ' + args
806 806 repo.ui.debug(b'launching merge tool: %s\n' % cmd)
807 807 _describemerge(ui, repo, mynode, fcd, fca, fco, env, toolpath, args)
808 808 r = ui.system(
809 809 cmd, cwd=repo.root, environ=env, blockedtag=b'mergetool'
810 810 )
811 811 else:
812 812 repo.ui.debug(
813 813 b'launching python merge script: %s:%s\n' % (toolpath, scriptfn)
814 814 )
815 815 r = 0
816 816 try:
817 817 # avoid cycle cmdutil->merge->filemerge->extensions->cmdutil
818 818 from . import extensions
819 819
820 820 mod = extensions.loadpath(toolpath, b'hgmerge.%s' % tool)
821 821 except Exception:
822 822 raise error.Abort(
823 823 _(b"loading python merge script failed: %s") % toolpath
824 824 )
825 825 mergefn = getattr(mod, scriptfn, None)
826 826 if mergefn is None:
827 827 raise error.Abort(
828 828 _(b"%s does not have function: %s") % (toolpath, scriptfn)
829 829 )
830 830 argslist = procutil.shellsplit(args)
831 831 # avoid cycle cmdutil->merge->filemerge->hook->extensions->cmdutil
832 832 from . import hook
833 833
834 834 ret, raised = hook.pythonhook(
835 835 ui, repo, b"merge", toolpath, mergefn, {b'args': argslist}, True
836 836 )
837 837 if raised:
838 838 r = 1
839 839 repo.ui.debug(b'merge tool returned: %d\n' % r)
840 840 return True, r, False
841 841
842 842
843 843 def _populate_label_detail(input, template):
844 844 """Applies the given template to the ctx and stores it in the input."""
845 845 ctx = input.fctx.changectx()
846 846 if ctx.node() is None:
847 847 ctx = ctx.p1()
848 848
849 849 props = {b'ctx': ctx}
850 850 templateresult = template.renderdefault(props)
851 851 input.label_detail = templateresult.splitlines()[0] # split for safety
852 852
853 853
854 854 def _populate_label_details(repo, inputs, tool=None):
855 855 """Populates the label details using the conflict marker template."""
856 856 ui = repo.ui
857 857 template = ui.config(b'command-templates', b'mergemarker')
858 858 if tool is not None:
859 859 template = _toolstr(ui, tool, b'mergemarkertemplate', template)
860 860 template = templater.unquotestring(template)
861 861 tres = formatter.templateresources(ui, repo)
862 862 tmpl = formatter.maketemplater(
863 863 ui, template, defaults=templatekw.keywords, resources=tres
864 864 )
865 865
866 866 for input in inputs:
867 867 _populate_label_detail(input, tmpl)
868 868
869 869
870 870 def partextras(labels):
871 871 """Return a dictionary of extra labels for use in prompts to the user
872 872
873 873 Intended use is in strings of the form "(l)ocal%(l)s".
874 874 """
875 875 if labels is None:
876 876 return {
877 877 b"l": b"",
878 878 b"o": b"",
879 879 }
880 880
881 881 return {
882 882 b"l": b" [%s]" % labels[0],
883 883 b"o": b" [%s]" % labels[1],
884 884 }
885 885
886 886
887 887 def _makebackup(repo, ui, fcd):
888 888 """Makes and returns a filectx-like object for ``fcd``'s backup file.
889 889
890 890 In addition to preserving the user's pre-existing modifications to `fcd`
891 891 (if any), the backup is used to undo certain premerges, confirm whether a
892 892 merge changed anything, and determine what line endings the new file should
893 893 have.
894 894
895 895 Backups only need to be written once since their content doesn't change
896 896 afterwards.
897 897 """
898 898 if fcd.isabsent():
899 899 return None
900 900 # TODO: Break this import cycle somehow. (filectx -> ctx -> fileset ->
901 901 # merge -> filemerge). (I suspect the fileset import is the weakest link)
902 902 from . import context
903 903
904 904 if isinstance(fcd, context.overlayworkingfilectx):
905 905 # If we're merging in-memory, we're free to put the backup anywhere.
906 906 fd, backup = pycompat.mkstemp(b'hg-merge-backup')
907 907 with os.fdopen(fd, 'wb') as f:
908 908 f.write(fcd.data())
909 909 else:
910 910 backup = scmutil.backuppath(ui, repo, fcd.path())
911 911 a = _workingpath(repo, fcd)
912 912 util.copyfile(a, backup)
913 913
914 914 return context.arbitraryfilectx(backup, repo=repo)
915 915
916 916
917 917 @contextlib.contextmanager
918 918 def _maketempfiles(files):
919 919 """Creates a temporary file for each (prefix, path, data) tuple in `files`,
920 920 so an external merge tool may use them.
921 921 """
922 922 tmproot = pycompat.mkdtemp(prefix=b'hgmerge-')
923 923
924 924 def maketempfrompath(prefix, path, data):
925 925 fullbase, ext = os.path.splitext(path)
926 926 pre = b"%s~%s" % (os.path.basename(fullbase), prefix)
927 927 name = os.path.join(tmproot, pre)
928 928 if ext:
929 929 name += ext
930 930 util.writefile(name, data)
931 931 return name
932 932
933 933 temp_files = []
934 934 for prefix, path, data in files:
935 935 temp_files.append(maketempfrompath(prefix, path, data))
936 936 try:
937 937 yield temp_files
938 938 finally:
939 939 shutil.rmtree(tmproot)
940 940
941 941
942 942 def filemerge(repo, wctx, mynode, orig, fcd, fco, fca, labels=None):
943 943 """perform a 3-way merge in the working directory
944 944
945 945 mynode = parent node before merge
946 946 orig = original local filename before merge
947 947 fco = other file context
948 948 fca = ancestor file context
949 949 fcd = local file context for current/destination file
950 950
951 951 Returns whether the merge is complete, the return value of the merge, and
952 952 a boolean indicating whether the file was deleted from disk."""
953 953 ui = repo.ui
954 954 fd = fcd.path()
955 955 uipathfn = scmutil.getuipathfn(repo)
956 956 fduipath = uipathfn(fd)
957 957 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
958 958 symlink = b'l' in fcd.flags() + fco.flags()
959 959 changedelete = fcd.isabsent() or fco.isabsent()
960 960 tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
961 961 scriptfn = None
962 962 if tool in internals and tool.startswith(b'internal:'):
963 963 # normalize to new-style names (':merge' etc)
964 964 tool = tool[len(b'internal') :]
965 965 if toolpath and toolpath.startswith(b'python:'):
966 966 invalidsyntax = False
967 967 if toolpath.count(b':') >= 2:
968 968 script, scriptfn = toolpath[7:].rsplit(b':', 1)
969 969 if not scriptfn:
970 970 invalidsyntax = True
971 971 # missing :callable can lead to spliting on windows drive letter
972 972 if b'\\' in scriptfn or b'/' in scriptfn:
973 973 invalidsyntax = True
974 974 else:
975 975 invalidsyntax = True
976 976 if invalidsyntax:
977 977 raise error.Abort(_(b"invalid 'python:' syntax: %s") % toolpath)
978 978 toolpath = script
979 979 ui.debug(
980 980 b"picked tool '%s' for %s (binary %s symlink %s changedelete %s)\n"
981 981 % (
982 982 tool,
983 983 fduipath,
984 984 pycompat.bytestr(binary),
985 985 pycompat.bytestr(symlink),
986 986 pycompat.bytestr(changedelete),
987 987 )
988 988 )
989 989
990 990 if tool in internals:
991 991 func = internals[tool]
992 992 mergetype = func.mergetype
993 993 onfailure = func.onfailure
994 994 precheck = func.precheck
995 995 isexternal = False
996 996 else:
997 997 if wctx.isinmemory():
998 998 func = _xmergeimm
999 999 else:
1000 1000 func = _xmerge
1001 1001 mergetype = fullmerge
1002 1002 onfailure = _(b"merging %s failed!\n")
1003 1003 precheck = None
1004 1004 isexternal = True
1005 1005
1006 1006 toolconf = tool, toolpath, binary, symlink, scriptfn
1007 1007
1008 1008 if not labels:
1009 1009 labels = [b'local', b'other']
1010 1010 if len(labels) < 3:
1011 1011 labels.append(b'base')
1012 1012 local = simplemerge.MergeInput(fcd, labels[0])
1013 1013 other = simplemerge.MergeInput(fco, labels[1])
1014 1014 base = simplemerge.MergeInput(fca, labels[2])
1015 1015 if mergetype == nomerge:
1016 1016 return func(
1017 1017 repo,
1018 1018 mynode,
1019 1019 local,
1020 1020 other,
1021 1021 base,
1022 1022 toolconf,
1023 1023 )
1024 1024
1025 1025 if orig != fco.path():
1026 1026 ui.status(
1027 1027 _(b"merging %s and %s to %s\n")
1028 1028 % (uipathfn(orig), uipathfn(fco.path()), fduipath)
1029 1029 )
1030 1030 else:
1031 1031 ui.status(_(b"merging %s\n") % fduipath)
1032 1032
1033 1033 ui.debug(b"my %s other %s ancestor %s\n" % (fcd, fco, fca))
1034 1034
1035 1035 if precheck and not precheck(repo, mynode, fcd, fco, fca, toolconf):
1036 1036 if onfailure:
1037 1037 if wctx.isinmemory():
1038 1038 raise error.InMemoryMergeConflictsError(
1039 1039 b'in-memory merge does not support merge conflicts'
1040 1040 )
1041 1041 ui.warn(onfailure % fduipath)
1042 1042 return 1, False
1043 1043
1044 1044 backup = _makebackup(repo, ui, fcd)
1045 1045 r = 1
1046 1046 try:
1047 1047 internalmarkerstyle = ui.config(b'ui', b'mergemarkers')
1048 1048 if isexternal:
1049 1049 markerstyle = _toolstr(ui, tool, b'mergemarkers')
1050 1050 else:
1051 1051 markerstyle = internalmarkerstyle
1052 1052
1053 1053 if mergetype == fullmerge:
1054 1054 _run_partial_resolution_tools(repo, local, other, base)
1055 1055 # conflict markers generated by premerge will use 'detailed'
1056 1056 # settings if either ui.mergemarkers or the tool's mergemarkers
1057 1057 # setting is 'detailed'. This way tools can have basic labels in
1058 1058 # space-constrained areas of the UI, but still get full information
1059 1059 # in conflict markers if premerge is 'keep' or 'keep-merge3'.
1060 1060 labeltool = None
1061 1061 if markerstyle != b'basic':
1062 1062 # respect 'tool's mergemarkertemplate (which defaults to
1063 1063 # command-templates.mergemarker)
1064 1064 labeltool = tool
1065 1065 if internalmarkerstyle != b'basic' or markerstyle != b'basic':
1066 1066 _populate_label_details(
1067 1067 repo, [local, other, base], tool=labeltool
1068 1068 )
1069 1069
1070 1070 r = _premerge(
1071 1071 repo,
1072 1072 local,
1073 1073 other,
1074 1074 base,
1075 1075 toolconf,
1076 1076 )
1077 1077 # we're done if premerge was successful (r is 0)
1078 1078 if not r:
1079 1079 return r, False
1080 1080
1081 1081 # Reset to basic labels
1082 1082 local.label_detail = None
1083 1083 other.label_detail = None
1084 1084 base.label_detail = None
1085 1085
1086 1086 if markerstyle != b'basic':
1087 1087 _populate_label_details(repo, [local, other, base], tool=tool)
1088 1088
1089 1089 needcheck, r, deleted = func(
1090 1090 repo,
1091 1091 mynode,
1092 1092 local,
1093 1093 other,
1094 1094 base,
1095 1095 toolconf,
1096 1096 backup,
1097 1097 )
1098 1098
1099 1099 if needcheck:
1100 1100 r = _check(repo, r, ui, tool, fcd, backup)
1101 1101
1102 1102 if r:
1103 1103 if onfailure:
1104 1104 if wctx.isinmemory():
1105 1105 raise error.InMemoryMergeConflictsError(
1106 1106 b'in-memory merge '
1107 1107 b'does not support '
1108 1108 b'merge conflicts'
1109 1109 )
1110 1110 ui.warn(onfailure % fduipath)
1111 1111 _onfilemergefailure(ui)
1112 1112
1113 1113 return r, deleted
1114 1114 finally:
1115 1115 if not r and backup is not None:
1116 1116 backup.remove()
1117 1117
1118 1118
1119 1119 def _run_partial_resolution_tools(repo, local, other, base):
1120 1120 """Runs partial-resolution tools on the three inputs and updates them."""
1121 1121 ui = repo.ui
1122 # Tuples of (order, name, executable path)
1122 # Tuples of (order, name, executable path, args)
1123 1123 tools = []
1124 1124 seen = set()
1125 1125 section = b"partial-merge-tools"
1126 1126 for k, v in ui.configitems(section):
1127 1127 name = k.split(b'.')[0]
1128 1128 if name in seen:
1129 1129 continue
1130 1130 patterns = ui.configlist(section, b'%s.patterns' % name, [])
1131 1131 is_match = True
1132 1132 if patterns:
1133 1133 m = match.match(repo.root, b'', patterns)
1134 1134 is_match = m(local.fctx.path())
1135 1135 if is_match:
1136 1136 order = ui.configint(section, b'%s.order' % name, 0)
1137 1137 executable = ui.config(section, b'%s.executable' % name, name)
1138 tools.append((order, name, executable))
1138 args = ui.config(section, b'%s.args' % name)
1139 tools.append((order, name, executable, args))
1139 1140
1140 1141 if not tools:
1141 1142 return
1142 1143 # Sort in configured order (first in tuple)
1143 1144 tools.sort()
1144 1145
1145 1146 files = [
1146 1147 (b"local", local.fctx.path(), local.text()),
1147 1148 (b"base", base.fctx.path(), base.text()),
1148 1149 (b"other", other.fctx.path(), other.text()),
1149 1150 ]
1150 1151
1151 1152 with _maketempfiles(files) as temppaths:
1152 1153 localpath, basepath, otherpath = temppaths
1153 1154
1154 for order, name, executable in tools:
1155 for order, name, executable, args in tools:
1155 1156 cmd = procutil.shellquote(executable)
1156 # TODO: Allow the user to configure the command line using
1157 # $local, $base, $other.
1158 cmd = b'%s %s %s %s' % (cmd, localpath, basepath, otherpath)
1157 replace = {
1158 b'local': localpath,
1159 b'base': basepath,
1160 b'other': otherpath,
1161 }
1162 args = util.interpolate(
1163 br'\$',
1164 replace,
1165 args,
1166 lambda s: procutil.shellquote(util.localpath(s)),
1167 )
1168
1169 cmd = b'%s %s' % (cmd, args)
1159 1170 r = ui.system(cmd, cwd=repo.root, blockedtag=b'partial-mergetool')
1160 1171 if r:
1161 1172 raise error.StateError(
1162 1173 b'partial merge tool %s exited with code %d' % (name, r)
1163 1174 )
1164 1175 local_text = util.readfile(localpath)
1165 1176 other_text = util.readfile(otherpath)
1166 1177 if local_text == other_text:
1167 1178 # No need to run other tools if all conflicts have been resolved
1168 1179 break
1169 1180
1170 1181 local.set_text(local_text)
1171 1182 base.set_text(util.readfile(basepath))
1172 1183 other.set_text(other_text)
1173 1184
1174 1185
1175 1186 def _haltmerge():
1176 1187 msg = _(b'merge halted after failed merge (see hg resolve)')
1177 1188 raise error.InterventionRequired(msg)
1178 1189
1179 1190
1180 1191 def _onfilemergefailure(ui):
1181 1192 action = ui.config(b'merge', b'on-failure')
1182 1193 if action == b'prompt':
1183 1194 msg = _(b'continue merge operation (yn)?$$ &Yes $$ &No')
1184 1195 if ui.promptchoice(msg, 0) == 1:
1185 1196 _haltmerge()
1186 1197 if action == b'halt':
1187 1198 _haltmerge()
1188 1199 # default action is 'continue', in which case we neither prompt nor halt
1189 1200
1190 1201
1191 1202 def hasconflictmarkers(data):
1192 1203 # Detect lines starting with a string of 7 identical characters from the
1193 1204 # subset Mercurial uses for conflict markers, followed by either the end of
1194 1205 # line or a space and some text. Note that using [<>=+|-]{7} would detect
1195 1206 # `<><><><><` as a conflict marker, which we don't want.
1196 1207 return bool(
1197 1208 re.search(
1198 1209 br"^([<>=+|-])\1{6}( .*)$",
1199 1210 data,
1200 1211 re.MULTILINE,
1201 1212 )
1202 1213 )
1203 1214
1204 1215
1205 1216 def _check(repo, r, ui, tool, fcd, backup):
1206 1217 fd = fcd.path()
1207 1218 uipathfn = scmutil.getuipathfn(repo)
1208 1219
1209 1220 if not r and (
1210 1221 _toolbool(ui, tool, b"checkconflicts")
1211 1222 or b'conflicts' in _toollist(ui, tool, b"check")
1212 1223 ):
1213 1224 if hasconflictmarkers(fcd.data()):
1214 1225 r = 1
1215 1226
1216 1227 checked = False
1217 1228 if b'prompt' in _toollist(ui, tool, b"check"):
1218 1229 checked = True
1219 1230 if ui.promptchoice(
1220 1231 _(b"was merge of '%s' successful (yn)?$$ &Yes $$ &No")
1221 1232 % uipathfn(fd),
1222 1233 1,
1223 1234 ):
1224 1235 r = 1
1225 1236
1226 1237 if (
1227 1238 not r
1228 1239 and not checked
1229 1240 and (
1230 1241 _toolbool(ui, tool, b"checkchanged")
1231 1242 or b'changed' in _toollist(ui, tool, b"check")
1232 1243 )
1233 1244 ):
1234 1245 if backup is not None and not fcd.cmp(backup):
1235 1246 if ui.promptchoice(
1236 1247 _(
1237 1248 b" output file %s appears unchanged\n"
1238 1249 b"was merge successful (yn)?"
1239 1250 b"$$ &Yes $$ &No"
1240 1251 )
1241 1252 % uipathfn(fd),
1242 1253 1,
1243 1254 ):
1244 1255 r = 1
1245 1256
1246 1257 if backup is not None and _toolbool(ui, tool, b"fixeol"):
1247 1258 _matcheol(_workingpath(repo, fcd), backup)
1248 1259
1249 1260 return r
1250 1261
1251 1262
1252 1263 def _workingpath(repo, ctx):
1253 1264 return repo.wjoin(ctx.path())
1254 1265
1255 1266
1256 1267 def loadinternalmerge(ui, extname, registrarobj):
1257 1268 """Load internal merge tool from specified registrarobj"""
1258 1269 for name, func in registrarobj._table.items():
1259 1270 fullname = b':' + name
1260 1271 internals[fullname] = func
1261 1272 internals[b'internal:' + name] = func
1262 1273 internalsdoc[fullname] = func
1263 1274
1264 1275 capabilities = sorted([k for k, v in func.capabilities.items() if v])
1265 1276 if capabilities:
1266 1277 capdesc = b" (actual capabilities: %s)" % b', '.join(
1267 1278 capabilities
1268 1279 )
1269 1280 func.__doc__ = func.__doc__ + pycompat.sysstr(b"\n\n%s" % capdesc)
1270 1281
1271 1282 # to put i18n comments into hg.pot for automatically generated texts
1272 1283
1273 1284 # i18n: "binary" and "symlink" are keywords
1274 1285 # i18n: this text is added automatically
1275 1286 _(b" (actual capabilities: binary, symlink)")
1276 1287 # i18n: "binary" is keyword
1277 1288 # i18n: this text is added automatically
1278 1289 _(b" (actual capabilities: binary)")
1279 1290 # i18n: "symlink" is keyword
1280 1291 # i18n: this text is added automatically
1281 1292 _(b" (actual capabilities: symlink)")
1282 1293
1283 1294
1284 1295 # load built-in merge tools explicitly to setup internalsdoc
1285 1296 loadinternalmerge(None, None, internaltool)
1286 1297
1287 1298 # tell hggettext to extract docstrings from these functions:
1288 1299 i18nfunctions = internals.values()
@@ -1,209 +1,241 b''
1 1 Test support for partial-resolution tools
2 2
3 3 Create a tool that resolves conflicts after line 5 by simply dropping those
4 4 lines (even if there are no conflicts there)
5 5 $ cat >> "$TESTTMP/head.sh" <<'EOF'
6 6 > #!/bin/sh
7 7 > for f in "$@"; do
8 8 > head -5 $f > tmp
9 9 > mv -f tmp $f
10 10 > done
11 11 > EOF
12 12 $ chmod +x "$TESTTMP/head.sh"
13 13 ...and another tool that keeps only the last 5 lines instead of the first 5.
14 14 $ cat >> "$TESTTMP/tail.sh" <<'EOF'
15 15 > #!/bin/sh
16 16 > for f in "$@"; do
17 17 > tail -5 $f > tmp
18 18 > mv -f tmp $f
19 19 > done
20 20 > EOF
21 21 $ chmod +x "$TESTTMP/tail.sh"
22 22
23 23 Set up both tools to run on all patterns (the default), and let the `tail` tool
24 24 run after the `head` tool, which means it will have no effect (we'll override it
25 25 to test order later)
26 26 $ cat >> "$HGRCPATH" <<EOF
27 27 > [partial-merge-tools]
28 28 > head.executable=$TESTTMP/head.sh
29 29 > tail.executable=$TESTTMP/tail.sh
30 30 > tail.order=1
31 31 > EOF
32 32
33 33 $ make_commit() {
34 34 > echo "$@" | xargs -n1 > file
35 35 > hg add file 2> /dev/null
36 36 > hg ci -m "$*"
37 37 > }
38 38
39 39
40 40 Let a partial-resolution tool resolve some conflicts and leave other conflicts
41 41 for the regular merge tool (:merge3 here)
42 42
43 43 $ hg init repo
44 44 $ cd repo
45 45 $ make_commit a b c d e f
46 46 $ make_commit a b2 c d e f2
47 47 $ hg up 0
48 48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 49 $ make_commit a b3 c d e f3
50 50 created new head
51 51 $ hg merge 1 -t :merge3
52 52 merging file
53 53 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
54 54 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
55 55 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
56 56 [1]
57 57 $ cat file
58 58 a
59 59 <<<<<<< working copy: e11a49d4b620 - test: a b3 c d e f3
60 60 b3
61 61 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
62 62 b
63 63 =======
64 64 b2
65 65 >>>>>>> merge rev: fbc096a40cc5 - test: a b2 c d e f2
66 66 c
67 67 d
68 68 e
69 69
70 70
71 71 With premerge=keep, the partial-resolution tools runs before and doesn't see
72 72 the conflict markers
73 73
74 74 $ hg up -C 2
75 75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 76 $ cat >> .hg/hgrc <<EOF
77 77 > [merge-tools]
78 78 > my-local.executable = cat
79 79 > my-local.args = $local
80 80 > my-local.premerge = keep-merge3
81 81 > EOF
82 82 $ hg merge 1 -t my-local
83 83 merging file
84 84 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
85 85 (branch merge, don't forget to commit)
86 86 $ cat file
87 87 a
88 88 <<<<<<< working copy: e11a49d4b620 - test: a b3 c d e f3
89 89 b3
90 90 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
91 91 b
92 92 =======
93 93 b2
94 94 >>>>>>> merge rev: fbc096a40cc5 - test: a b2 c d e f2
95 95 c
96 96 d
97 97 e
98 98
99 99
100 100 When a partial-resolution tool resolves all conflicts, the resolution should
101 101 be recorded and the regular merge tool should not be invoked for the file.
102 102
103 103 $ hg up -C 0
104 104 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 105 $ make_commit a b c d e f2
106 106 created new head
107 107 $ hg up 0
108 108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 109 $ make_commit a b c d e f3
110 110 created new head
111 111 $ hg merge 3 -t false
112 112 merging file
113 113 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
114 114 (branch merge, don't forget to commit)
115 115 $ cat file
116 116 a
117 117 b
118 118 c
119 119 d
120 120 e
121 121
122 122
123 123 Only tools whose patterns match are run. We make `head` not match here, so
124 124 only `tail` should run
125 125
126 126 $ hg up -C 4
127 127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
128 128 $ hg merge 3 -t :merge3 --config partial-merge-tools.head.patterns=other
129 129 merging file
130 130 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
131 131 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
132 132 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
133 133 [1]
134 134 $ cat file
135 135 b
136 136 c
137 137 d
138 138 e
139 139 <<<<<<< working copy: d57edaa6e21a - test: a b c d e f3
140 140 f3
141 141 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
142 142 f
143 143 =======
144 144 f2
145 145 >>>>>>> merge rev: 8c217da987be - test: a b c d e f2
146 146
147 147
148 148 If there are several matching tools, they are run in requested order. We move
149 149 `head` after `tail` in order here so it has no effect (the conflict in "f" thus
150 150 remains).
151 151
152 152 $ hg up -C 4
153 153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 154 $ hg merge 3 -t :merge3 --config partial-merge-tools.head.order=2
155 155 merging file
156 156 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
157 157 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
158 158 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
159 159 [1]
160 160 $ cat file
161 161 b
162 162 c
163 163 d
164 164 e
165 165 <<<<<<< working copy: d57edaa6e21a - test: a b c d e f3
166 166 f3
167 167 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
168 168 f
169 169 =======
170 170 f2
171 171 >>>>>>> merge rev: 8c217da987be - test: a b c d e f2
172 172
173 173
174 174 When using "nomerge" tools (e.g. `:other`), the partial-resolution tools
175 175 should not be run.
176 176
177 177 $ hg up -C 4
178 178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 179 $ hg merge 3 -t :other
180 180 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
181 181 (branch merge, don't forget to commit)
182 182 $ cat file
183 183 a
184 184 b
185 185 c
186 186 d
187 187 e
188 188 f2
189 189
190 190
191 191 If a partial-resolution tool resolved some conflict and simplemerge can
192 192 merge the rest, then the regular merge tool should not be used. Here we merge
193 193 "a b c d e3 f3" with "a b2 c d e f2". The `head` tool resolves the conflict in
194 194 "f" and the internal simplemerge merges the remaining changes in "b" and "e".
195 195
196 196 $ hg up -C 0
197 197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 198 $ make_commit a b c d e3 f3
199 199 created new head
200 200 $ hg merge 1 -t false
201 201 merging file
202 202 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
203 203 (branch merge, don't forget to commit)
204 204 $ cat file
205 205 a
206 206 b2
207 207 c
208 208 d
209 209 e3
210
211 Test that arguments get passed as expected.
212
213 $ cat >> "$TESTTMP/log-args.sh" <<'EOF'
214 > #!/bin/sh
215 > echo "$@" > args.log
216 > EOF
217 $ chmod +x "$TESTTMP/log-args.sh"
218 $ cat >> "$HGRCPATH" <<EOF
219 > [partial-merge-tools]
220 > log-args.executable=$TESTTMP/log-args.sh
221 > EOF
222 $ hg up -C 2
223 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 $ hg merge 1
225 merging file
226 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
227 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
228 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
229 [1]
230 $ cat args.log
231 */hgmerge-*/file~local */hgmerge-*/file~base */hgmerge-*/file~other (glob)
232 $ hg up -C 2
233 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 $ hg merge 1 --config partial-merge-tools.log-args.args='--other $other $base --foo --local $local --also-other $other'
235 merging file
236 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
237 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
238 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
239 [1]
240 $ cat args.log
241 --other */hgmerge-*/file~other */hgmerge-*/file~base --foo --local */hgmerge-*/file~local --also-other */hgmerge-*/file~other (glob)
General Comments 0
You need to be logged in to leave comments. Login now