##// END OF EJS Templates
upgraderepo: add a config option for parallel computation...
marmoute -
r44258:acbb55b8 default
parent child Browse files
Show More
@@ -1,1546 +1,1549 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import functools
11 11 import re
12 12
13 13 from . import (
14 14 encoding,
15 15 error,
16 16 )
17 17
18 18
19 19 def loadconfigtable(ui, extname, configtable):
20 20 """update config item known to the ui with the extension ones"""
21 21 for section, items in sorted(configtable.items()):
22 22 knownitems = ui._knownconfig.setdefault(section, itemregister())
23 23 knownkeys = set(knownitems)
24 24 newkeys = set(items)
25 25 for key in sorted(knownkeys & newkeys):
26 26 msg = b"extension '%s' overwrite config item '%s.%s'"
27 27 msg %= (extname, section, key)
28 28 ui.develwarn(msg, config=b'warn-config')
29 29
30 30 knownitems.update(items)
31 31
32 32
33 33 class configitem(object):
34 34 """represent a known config item
35 35
36 36 :section: the official config section where to find this item,
37 37 :name: the official name within the section,
38 38 :default: default value for this item,
39 39 :alias: optional list of tuples as alternatives,
40 40 :generic: this is a generic definition, match name using regular expression.
41 41 """
42 42
43 43 def __init__(
44 44 self,
45 45 section,
46 46 name,
47 47 default=None,
48 48 alias=(),
49 49 generic=False,
50 50 priority=0,
51 51 experimental=False,
52 52 ):
53 53 self.section = section
54 54 self.name = name
55 55 self.default = default
56 56 self.alias = list(alias)
57 57 self.generic = generic
58 58 self.priority = priority
59 59 self.experimental = experimental
60 60 self._re = None
61 61 if generic:
62 62 self._re = re.compile(self.name)
63 63
64 64
65 65 class itemregister(dict):
66 66 """A specialized dictionary that can handle wild-card selection"""
67 67
68 68 def __init__(self):
69 69 super(itemregister, self).__init__()
70 70 self._generics = set()
71 71
72 72 def update(self, other):
73 73 super(itemregister, self).update(other)
74 74 self._generics.update(other._generics)
75 75
76 76 def __setitem__(self, key, item):
77 77 super(itemregister, self).__setitem__(key, item)
78 78 if item.generic:
79 79 self._generics.add(item)
80 80
81 81 def get(self, key):
82 82 baseitem = super(itemregister, self).get(key)
83 83 if baseitem is not None and not baseitem.generic:
84 84 return baseitem
85 85
86 86 # search for a matching generic item
87 87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
88 88 for item in generics:
89 89 # we use 'match' instead of 'search' to make the matching simpler
90 90 # for people unfamiliar with regular expression. Having the match
91 91 # rooted to the start of the string will produce less surprising
92 92 # result for user writing simple regex for sub-attribute.
93 93 #
94 94 # For example using "color\..*" match produces an unsurprising
95 95 # result, while using search could suddenly match apparently
96 96 # unrelated configuration that happens to contains "color."
97 97 # anywhere. This is a tradeoff where we favor requiring ".*" on
98 98 # some match to avoid the need to prefix most pattern with "^".
99 99 # The "^" seems more error prone.
100 100 if item._re.match(key):
101 101 return item
102 102
103 103 return None
104 104
105 105
106 106 coreitems = {}
107 107
108 108
109 109 def _register(configtable, *args, **kwargs):
110 110 item = configitem(*args, **kwargs)
111 111 section = configtable.setdefault(item.section, itemregister())
112 112 if item.name in section:
113 113 msg = b"duplicated config item registration for '%s.%s'"
114 114 raise error.ProgrammingError(msg % (item.section, item.name))
115 115 section[item.name] = item
116 116
117 117
118 118 # special value for case where the default is derived from other values
119 119 dynamicdefault = object()
120 120
121 121 # Registering actual config items
122 122
123 123
124 124 def getitemregister(configtable):
125 125 f = functools.partial(_register, configtable)
126 126 # export pseudo enum as configitem.*
127 127 f.dynamicdefault = dynamicdefault
128 128 return f
129 129
130 130
131 131 coreconfigitem = getitemregister(coreitems)
132 132
133 133
134 134 def _registerdiffopts(section, configprefix=b''):
135 135 coreconfigitem(
136 136 section, configprefix + b'nodates', default=False,
137 137 )
138 138 coreconfigitem(
139 139 section, configprefix + b'showfunc', default=False,
140 140 )
141 141 coreconfigitem(
142 142 section, configprefix + b'unified', default=None,
143 143 )
144 144 coreconfigitem(
145 145 section, configprefix + b'git', default=False,
146 146 )
147 147 coreconfigitem(
148 148 section, configprefix + b'ignorews', default=False,
149 149 )
150 150 coreconfigitem(
151 151 section, configprefix + b'ignorewsamount', default=False,
152 152 )
153 153 coreconfigitem(
154 154 section, configprefix + b'ignoreblanklines', default=False,
155 155 )
156 156 coreconfigitem(
157 157 section, configprefix + b'ignorewseol', default=False,
158 158 )
159 159 coreconfigitem(
160 160 section, configprefix + b'nobinary', default=False,
161 161 )
162 162 coreconfigitem(
163 163 section, configprefix + b'noprefix', default=False,
164 164 )
165 165 coreconfigitem(
166 166 section, configprefix + b'word-diff', default=False,
167 167 )
168 168
169 169
170 170 coreconfigitem(
171 171 b'alias', b'.*', default=dynamicdefault, generic=True,
172 172 )
173 173 coreconfigitem(
174 174 b'auth', b'cookiefile', default=None,
175 175 )
176 176 _registerdiffopts(section=b'annotate')
177 177 # bookmarks.pushing: internal hack for discovery
178 178 coreconfigitem(
179 179 b'bookmarks', b'pushing', default=list,
180 180 )
181 181 # bundle.mainreporoot: internal hack for bundlerepo
182 182 coreconfigitem(
183 183 b'bundle', b'mainreporoot', default=b'',
184 184 )
185 185 coreconfigitem(
186 186 b'censor', b'policy', default=b'abort', experimental=True,
187 187 )
188 188 coreconfigitem(
189 189 b'chgserver', b'idletimeout', default=3600,
190 190 )
191 191 coreconfigitem(
192 192 b'chgserver', b'skiphash', default=False,
193 193 )
194 194 coreconfigitem(
195 195 b'cmdserver', b'log', default=None,
196 196 )
197 197 coreconfigitem(
198 198 b'cmdserver', b'max-log-files', default=7,
199 199 )
200 200 coreconfigitem(
201 201 b'cmdserver', b'max-log-size', default=b'1 MB',
202 202 )
203 203 coreconfigitem(
204 204 b'cmdserver', b'max-repo-cache', default=0, experimental=True,
205 205 )
206 206 coreconfigitem(
207 207 b'cmdserver', b'message-encodings', default=list, experimental=True,
208 208 )
209 209 coreconfigitem(
210 210 b'cmdserver',
211 211 b'track-log',
212 212 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
213 213 )
214 214 coreconfigitem(
215 215 b'color', b'.*', default=None, generic=True,
216 216 )
217 217 coreconfigitem(
218 218 b'color', b'mode', default=b'auto',
219 219 )
220 220 coreconfigitem(
221 221 b'color', b'pagermode', default=dynamicdefault,
222 222 )
223 223 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
224 224 coreconfigitem(
225 225 b'commands', b'commit.post-status', default=False,
226 226 )
227 227 coreconfigitem(
228 228 b'commands', b'grep.all-files', default=False, experimental=True,
229 229 )
230 230 coreconfigitem(
231 231 b'commands', b'push.require-revs', default=False,
232 232 )
233 233 coreconfigitem(
234 234 b'commands', b'resolve.confirm', default=False,
235 235 )
236 236 coreconfigitem(
237 237 b'commands', b'resolve.explicit-re-merge', default=False,
238 238 )
239 239 coreconfigitem(
240 240 b'commands', b'resolve.mark-check', default=b'none',
241 241 )
242 242 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
243 243 coreconfigitem(
244 244 b'commands', b'show.aliasprefix', default=list,
245 245 )
246 246 coreconfigitem(
247 247 b'commands', b'status.relative', default=False,
248 248 )
249 249 coreconfigitem(
250 250 b'commands', b'status.skipstates', default=[], experimental=True,
251 251 )
252 252 coreconfigitem(
253 253 b'commands', b'status.terse', default=b'',
254 254 )
255 255 coreconfigitem(
256 256 b'commands', b'status.verbose', default=False,
257 257 )
258 258 coreconfigitem(
259 259 b'commands', b'update.check', default=None,
260 260 )
261 261 coreconfigitem(
262 262 b'commands', b'update.requiredest', default=False,
263 263 )
264 264 coreconfigitem(
265 265 b'committemplate', b'.*', default=None, generic=True,
266 266 )
267 267 coreconfigitem(
268 268 b'convert', b'bzr.saverev', default=True,
269 269 )
270 270 coreconfigitem(
271 271 b'convert', b'cvsps.cache', default=True,
272 272 )
273 273 coreconfigitem(
274 274 b'convert', b'cvsps.fuzz', default=60,
275 275 )
276 276 coreconfigitem(
277 277 b'convert', b'cvsps.logencoding', default=None,
278 278 )
279 279 coreconfigitem(
280 280 b'convert', b'cvsps.mergefrom', default=None,
281 281 )
282 282 coreconfigitem(
283 283 b'convert', b'cvsps.mergeto', default=None,
284 284 )
285 285 coreconfigitem(
286 286 b'convert', b'git.committeractions', default=lambda: [b'messagedifferent'],
287 287 )
288 288 coreconfigitem(
289 289 b'convert', b'git.extrakeys', default=list,
290 290 )
291 291 coreconfigitem(
292 292 b'convert', b'git.findcopiesharder', default=False,
293 293 )
294 294 coreconfigitem(
295 295 b'convert', b'git.remoteprefix', default=b'remote',
296 296 )
297 297 coreconfigitem(
298 298 b'convert', b'git.renamelimit', default=400,
299 299 )
300 300 coreconfigitem(
301 301 b'convert', b'git.saverev', default=True,
302 302 )
303 303 coreconfigitem(
304 304 b'convert', b'git.similarity', default=50,
305 305 )
306 306 coreconfigitem(
307 307 b'convert', b'git.skipsubmodules', default=False,
308 308 )
309 309 coreconfigitem(
310 310 b'convert', b'hg.clonebranches', default=False,
311 311 )
312 312 coreconfigitem(
313 313 b'convert', b'hg.ignoreerrors', default=False,
314 314 )
315 315 coreconfigitem(
316 316 b'convert', b'hg.preserve-hash', default=False,
317 317 )
318 318 coreconfigitem(
319 319 b'convert', b'hg.revs', default=None,
320 320 )
321 321 coreconfigitem(
322 322 b'convert', b'hg.saverev', default=False,
323 323 )
324 324 coreconfigitem(
325 325 b'convert', b'hg.sourcename', default=None,
326 326 )
327 327 coreconfigitem(
328 328 b'convert', b'hg.startrev', default=None,
329 329 )
330 330 coreconfigitem(
331 331 b'convert', b'hg.tagsbranch', default=b'default',
332 332 )
333 333 coreconfigitem(
334 334 b'convert', b'hg.usebranchnames', default=True,
335 335 )
336 336 coreconfigitem(
337 337 b'convert', b'ignoreancestorcheck', default=False, experimental=True,
338 338 )
339 339 coreconfigitem(
340 340 b'convert', b'localtimezone', default=False,
341 341 )
342 342 coreconfigitem(
343 343 b'convert', b'p4.encoding', default=dynamicdefault,
344 344 )
345 345 coreconfigitem(
346 346 b'convert', b'p4.startrev', default=0,
347 347 )
348 348 coreconfigitem(
349 349 b'convert', b'skiptags', default=False,
350 350 )
351 351 coreconfigitem(
352 352 b'convert', b'svn.debugsvnlog', default=True,
353 353 )
354 354 coreconfigitem(
355 355 b'convert', b'svn.trunk', default=None,
356 356 )
357 357 coreconfigitem(
358 358 b'convert', b'svn.tags', default=None,
359 359 )
360 360 coreconfigitem(
361 361 b'convert', b'svn.branches', default=None,
362 362 )
363 363 coreconfigitem(
364 364 b'convert', b'svn.startrev', default=0,
365 365 )
366 366 coreconfigitem(
367 367 b'debug', b'dirstate.delaywrite', default=0,
368 368 )
369 369 coreconfigitem(
370 370 b'defaults', b'.*', default=None, generic=True,
371 371 )
372 372 coreconfigitem(
373 373 b'devel', b'all-warnings', default=False,
374 374 )
375 375 coreconfigitem(
376 376 b'devel', b'bundle2.debug', default=False,
377 377 )
378 378 coreconfigitem(
379 379 b'devel', b'bundle.delta', default=b'',
380 380 )
381 381 coreconfigitem(
382 382 b'devel', b'cache-vfs', default=None,
383 383 )
384 384 coreconfigitem(
385 385 b'devel', b'check-locks', default=False,
386 386 )
387 387 coreconfigitem(
388 388 b'devel', b'check-relroot', default=False,
389 389 )
390 390 coreconfigitem(
391 391 b'devel', b'default-date', default=None,
392 392 )
393 393 coreconfigitem(
394 394 b'devel', b'deprec-warn', default=False,
395 395 )
396 396 coreconfigitem(
397 397 b'devel', b'disableloaddefaultcerts', default=False,
398 398 )
399 399 coreconfigitem(
400 400 b'devel', b'warn-empty-changegroup', default=False,
401 401 )
402 402 coreconfigitem(
403 403 b'devel', b'legacy.exchange', default=list,
404 404 )
405 405 coreconfigitem(
406 406 b'devel', b'servercafile', default=b'',
407 407 )
408 408 coreconfigitem(
409 409 b'devel', b'serverexactprotocol', default=b'',
410 410 )
411 411 coreconfigitem(
412 412 b'devel', b'serverrequirecert', default=False,
413 413 )
414 414 coreconfigitem(
415 415 b'devel', b'strip-obsmarkers', default=True,
416 416 )
417 417 coreconfigitem(
418 418 b'devel', b'warn-config', default=None,
419 419 )
420 420 coreconfigitem(
421 421 b'devel', b'warn-config-default', default=None,
422 422 )
423 423 coreconfigitem(
424 424 b'devel', b'user.obsmarker', default=None,
425 425 )
426 426 coreconfigitem(
427 427 b'devel', b'warn-config-unknown', default=None,
428 428 )
429 429 coreconfigitem(
430 430 b'devel', b'debug.copies', default=False,
431 431 )
432 432 coreconfigitem(
433 433 b'devel', b'debug.extensions', default=False,
434 434 )
435 435 coreconfigitem(
436 436 b'devel', b'debug.repo-filters', default=False,
437 437 )
438 438 coreconfigitem(
439 439 b'devel', b'debug.peer-request', default=False,
440 440 )
441 441 coreconfigitem(
442 442 b'devel', b'discovery.randomize', default=True,
443 443 )
444 444 _registerdiffopts(section=b'diff')
445 445 coreconfigitem(
446 446 b'email', b'bcc', default=None,
447 447 )
448 448 coreconfigitem(
449 449 b'email', b'cc', default=None,
450 450 )
451 451 coreconfigitem(
452 452 b'email', b'charsets', default=list,
453 453 )
454 454 coreconfigitem(
455 455 b'email', b'from', default=None,
456 456 )
457 457 coreconfigitem(
458 458 b'email', b'method', default=b'smtp',
459 459 )
460 460 coreconfigitem(
461 461 b'email', b'reply-to', default=None,
462 462 )
463 463 coreconfigitem(
464 464 b'email', b'to', default=None,
465 465 )
466 466 coreconfigitem(
467 467 b'experimental', b'archivemetatemplate', default=dynamicdefault,
468 468 )
469 469 coreconfigitem(
470 470 b'experimental', b'auto-publish', default=b'publish',
471 471 )
472 472 coreconfigitem(
473 473 b'experimental', b'bundle-phases', default=False,
474 474 )
475 475 coreconfigitem(
476 476 b'experimental', b'bundle2-advertise', default=True,
477 477 )
478 478 coreconfigitem(
479 479 b'experimental', b'bundle2-output-capture', default=False,
480 480 )
481 481 coreconfigitem(
482 482 b'experimental', b'bundle2.pushback', default=False,
483 483 )
484 484 coreconfigitem(
485 485 b'experimental', b'bundle2lazylocking', default=False,
486 486 )
487 487 coreconfigitem(
488 488 b'experimental', b'bundlecomplevel', default=None,
489 489 )
490 490 coreconfigitem(
491 491 b'experimental', b'bundlecomplevel.bzip2', default=None,
492 492 )
493 493 coreconfigitem(
494 494 b'experimental', b'bundlecomplevel.gzip', default=None,
495 495 )
496 496 coreconfigitem(
497 497 b'experimental', b'bundlecomplevel.none', default=None,
498 498 )
499 499 coreconfigitem(
500 500 b'experimental', b'bundlecomplevel.zstd', default=None,
501 501 )
502 502 coreconfigitem(
503 503 b'experimental', b'changegroup3', default=False,
504 504 )
505 505 coreconfigitem(
506 506 b'experimental', b'cleanup-as-archived', default=False,
507 507 )
508 508 coreconfigitem(
509 509 b'experimental', b'clientcompressionengines', default=list,
510 510 )
511 511 coreconfigitem(
512 512 b'experimental', b'copytrace', default=b'on',
513 513 )
514 514 coreconfigitem(
515 515 b'experimental', b'copytrace.movecandidateslimit', default=100,
516 516 )
517 517 coreconfigitem(
518 518 b'experimental', b'copytrace.sourcecommitlimit', default=100,
519 519 )
520 520 coreconfigitem(
521 521 b'experimental', b'copies.read-from', default=b"filelog-only",
522 522 )
523 523 coreconfigitem(
524 524 b'experimental', b'copies.write-to', default=b'filelog-only',
525 525 )
526 526 coreconfigitem(
527 527 b'experimental', b'crecordtest', default=None,
528 528 )
529 529 coreconfigitem(
530 530 b'experimental', b'directaccess', default=False,
531 531 )
532 532 coreconfigitem(
533 533 b'experimental', b'directaccess.revnums', default=False,
534 534 )
535 535 coreconfigitem(
536 536 b'experimental', b'editortmpinhg', default=False,
537 537 )
538 538 coreconfigitem(
539 539 b'experimental', b'evolution', default=list,
540 540 )
541 541 coreconfigitem(
542 542 b'experimental',
543 543 b'evolution.allowdivergence',
544 544 default=False,
545 545 alias=[(b'experimental', b'allowdivergence')],
546 546 )
547 547 coreconfigitem(
548 548 b'experimental', b'evolution.allowunstable', default=None,
549 549 )
550 550 coreconfigitem(
551 551 b'experimental', b'evolution.createmarkers', default=None,
552 552 )
553 553 coreconfigitem(
554 554 b'experimental',
555 555 b'evolution.effect-flags',
556 556 default=True,
557 557 alias=[(b'experimental', b'effect-flags')],
558 558 )
559 559 coreconfigitem(
560 560 b'experimental', b'evolution.exchange', default=None,
561 561 )
562 562 coreconfigitem(
563 563 b'experimental', b'evolution.bundle-obsmarker', default=False,
564 564 )
565 565 coreconfigitem(
566 566 b'experimental', b'log.topo', default=False,
567 567 )
568 568 coreconfigitem(
569 569 b'experimental', b'evolution.report-instabilities', default=True,
570 570 )
571 571 coreconfigitem(
572 572 b'experimental', b'evolution.track-operation', default=True,
573 573 )
574 574 # repo-level config to exclude a revset visibility
575 575 #
576 576 # The target use case is to use `share` to expose different subset of the same
577 577 # repository, especially server side. See also `server.view`.
578 578 coreconfigitem(
579 579 b'experimental', b'extra-filter-revs', default=None,
580 580 )
581 581 coreconfigitem(
582 582 b'experimental', b'maxdeltachainspan', default=-1,
583 583 )
584 584 coreconfigitem(
585 585 b'experimental', b'mergetempdirprefix', default=None,
586 586 )
587 587 coreconfigitem(
588 588 b'experimental', b'mmapindexthreshold', default=None,
589 589 )
590 590 coreconfigitem(
591 591 b'experimental', b'narrow', default=False,
592 592 )
593 593 coreconfigitem(
594 594 b'experimental', b'nonnormalparanoidcheck', default=False,
595 595 )
596 596 coreconfigitem(
597 597 b'experimental', b'exportableenviron', default=list,
598 598 )
599 599 coreconfigitem(
600 600 b'experimental', b'extendedheader.index', default=None,
601 601 )
602 602 coreconfigitem(
603 603 b'experimental', b'extendedheader.similarity', default=False,
604 604 )
605 605 coreconfigitem(
606 606 b'experimental', b'graphshorten', default=False,
607 607 )
608 608 coreconfigitem(
609 609 b'experimental', b'graphstyle.parent', default=dynamicdefault,
610 610 )
611 611 coreconfigitem(
612 612 b'experimental', b'graphstyle.missing', default=dynamicdefault,
613 613 )
614 614 coreconfigitem(
615 615 b'experimental', b'graphstyle.grandparent', default=dynamicdefault,
616 616 )
617 617 coreconfigitem(
618 618 b'experimental', b'hook-track-tags', default=False,
619 619 )
620 620 coreconfigitem(
621 621 b'experimental', b'httppeer.advertise-v2', default=False,
622 622 )
623 623 coreconfigitem(
624 624 b'experimental', b'httppeer.v2-encoder-order', default=None,
625 625 )
626 626 coreconfigitem(
627 627 b'experimental', b'httppostargs', default=False,
628 628 )
629 629 coreconfigitem(
630 630 b'experimental', b'mergedriver', default=None,
631 631 )
632 632 coreconfigitem(b'experimental', b'nointerrupt', default=False)
633 633 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
634 634
635 635 coreconfigitem(
636 636 b'experimental', b'obsmarkers-exchange-debug', default=False,
637 637 )
638 638 coreconfigitem(
639 639 b'experimental', b'remotenames', default=False,
640 640 )
641 641 coreconfigitem(
642 642 b'experimental', b'removeemptydirs', default=True,
643 643 )
644 644 coreconfigitem(
645 645 b'experimental', b'revert.interactive.select-to-keep', default=False,
646 646 )
647 647 coreconfigitem(
648 648 b'experimental', b'revisions.prefixhexnode', default=False,
649 649 )
650 650 coreconfigitem(
651 651 b'experimental', b'revlogv2', default=None,
652 652 )
653 653 coreconfigitem(
654 654 b'experimental', b'revisions.disambiguatewithin', default=None,
655 655 )
656 656 coreconfigitem(
657 657 b'experimental', b'server.filesdata.recommended-batch-size', default=50000,
658 658 )
659 659 coreconfigitem(
660 660 b'experimental',
661 661 b'server.manifestdata.recommended-batch-size',
662 662 default=100000,
663 663 )
664 664 coreconfigitem(
665 665 b'experimental', b'server.stream-narrow-clones', default=False,
666 666 )
667 667 coreconfigitem(
668 668 b'experimental', b'single-head-per-branch', default=False,
669 669 )
670 670 coreconfigitem(
671 671 b'experimental',
672 672 b'single-head-per-branch:account-closed-heads',
673 673 default=False,
674 674 )
675 675 coreconfigitem(
676 676 b'experimental', b'sshserver.support-v2', default=False,
677 677 )
678 678 coreconfigitem(
679 679 b'experimental', b'sparse-read', default=False,
680 680 )
681 681 coreconfigitem(
682 682 b'experimental', b'sparse-read.density-threshold', default=0.50,
683 683 )
684 684 coreconfigitem(
685 685 b'experimental', b'sparse-read.min-gap-size', default=b'65K',
686 686 )
687 687 coreconfigitem(
688 688 b'experimental', b'treemanifest', default=False,
689 689 )
690 690 coreconfigitem(
691 691 b'experimental', b'update.atomic-file', default=False,
692 692 )
693 693 coreconfigitem(
694 694 b'experimental', b'sshpeer.advertise-v2', default=False,
695 695 )
696 696 coreconfigitem(
697 697 b'experimental', b'web.apiserver', default=False,
698 698 )
699 699 coreconfigitem(
700 700 b'experimental', b'web.api.http-v2', default=False,
701 701 )
702 702 coreconfigitem(
703 703 b'experimental', b'web.api.debugreflect', default=False,
704 704 )
705 705 coreconfigitem(
706 706 b'experimental', b'worker.wdir-get-thread-safe', default=False,
707 707 )
708 708 coreconfigitem(
709 b'experimental', b'worker.repository-upgrade', default=False,
710 )
711 coreconfigitem(
709 712 b'experimental', b'xdiff', default=False,
710 713 )
711 714 coreconfigitem(
712 715 b'extensions', b'.*', default=None, generic=True,
713 716 )
714 717 coreconfigitem(
715 718 b'extdata', b'.*', default=None, generic=True,
716 719 )
717 720 coreconfigitem(
718 721 b'format', b'bookmarks-in-store', default=False,
719 722 )
720 723 coreconfigitem(
721 724 b'format', b'chunkcachesize', default=None, experimental=True,
722 725 )
723 726 coreconfigitem(
724 727 b'format', b'dotencode', default=True,
725 728 )
726 729 coreconfigitem(
727 730 b'format', b'generaldelta', default=False, experimental=True,
728 731 )
729 732 coreconfigitem(
730 733 b'format', b'manifestcachesize', default=None, experimental=True,
731 734 )
732 735 coreconfigitem(
733 736 b'format', b'maxchainlen', default=dynamicdefault, experimental=True,
734 737 )
735 738 coreconfigitem(
736 739 b'format', b'obsstore-version', default=None,
737 740 )
738 741 coreconfigitem(
739 742 b'format', b'sparse-revlog', default=True,
740 743 )
741 744 coreconfigitem(
742 745 b'format',
743 746 b'revlog-compression',
744 747 default=b'zlib',
745 748 alias=[(b'experimental', b'format.compression')],
746 749 )
747 750 coreconfigitem(
748 751 b'format', b'usefncache', default=True,
749 752 )
750 753 coreconfigitem(
751 754 b'format', b'usegeneraldelta', default=True,
752 755 )
753 756 coreconfigitem(
754 757 b'format', b'usestore', default=True,
755 758 )
756 759 coreconfigitem(
757 760 b'format',
758 761 b'exp-use-copies-side-data-changeset',
759 762 default=False,
760 763 experimental=True,
761 764 )
762 765 coreconfigitem(
763 766 b'format', b'exp-use-side-data', default=False, experimental=True,
764 767 )
765 768 coreconfigitem(
766 769 b'format', b'internal-phase', default=False, experimental=True,
767 770 )
768 771 coreconfigitem(
769 772 b'fsmonitor', b'warn_when_unused', default=True,
770 773 )
771 774 coreconfigitem(
772 775 b'fsmonitor', b'warn_update_file_count', default=50000,
773 776 )
774 777 coreconfigitem(
775 778 b'help', br'hidden-command\..*', default=False, generic=True,
776 779 )
777 780 coreconfigitem(
778 781 b'help', br'hidden-topic\..*', default=False, generic=True,
779 782 )
780 783 coreconfigitem(
781 784 b'hooks', b'.*', default=dynamicdefault, generic=True,
782 785 )
783 786 coreconfigitem(
784 787 b'hgweb-paths', b'.*', default=list, generic=True,
785 788 )
786 789 coreconfigitem(
787 790 b'hostfingerprints', b'.*', default=list, generic=True,
788 791 )
789 792 coreconfigitem(
790 793 b'hostsecurity', b'ciphers', default=None,
791 794 )
792 795 coreconfigitem(
793 796 b'hostsecurity', b'disabletls10warning', default=False,
794 797 )
795 798 coreconfigitem(
796 799 b'hostsecurity', b'minimumprotocol', default=dynamicdefault,
797 800 )
798 801 coreconfigitem(
799 802 b'hostsecurity',
800 803 b'.*:minimumprotocol$',
801 804 default=dynamicdefault,
802 805 generic=True,
803 806 )
804 807 coreconfigitem(
805 808 b'hostsecurity', b'.*:ciphers$', default=dynamicdefault, generic=True,
806 809 )
807 810 coreconfigitem(
808 811 b'hostsecurity', b'.*:fingerprints$', default=list, generic=True,
809 812 )
810 813 coreconfigitem(
811 814 b'hostsecurity', b'.*:verifycertsfile$', default=None, generic=True,
812 815 )
813 816
814 817 coreconfigitem(
815 818 b'http_proxy', b'always', default=False,
816 819 )
817 820 coreconfigitem(
818 821 b'http_proxy', b'host', default=None,
819 822 )
820 823 coreconfigitem(
821 824 b'http_proxy', b'no', default=list,
822 825 )
823 826 coreconfigitem(
824 827 b'http_proxy', b'passwd', default=None,
825 828 )
826 829 coreconfigitem(
827 830 b'http_proxy', b'user', default=None,
828 831 )
829 832
830 833 coreconfigitem(
831 834 b'http', b'timeout', default=None,
832 835 )
833 836
834 837 coreconfigitem(
835 838 b'logtoprocess', b'commandexception', default=None,
836 839 )
837 840 coreconfigitem(
838 841 b'logtoprocess', b'commandfinish', default=None,
839 842 )
840 843 coreconfigitem(
841 844 b'logtoprocess', b'command', default=None,
842 845 )
843 846 coreconfigitem(
844 847 b'logtoprocess', b'develwarn', default=None,
845 848 )
846 849 coreconfigitem(
847 850 b'logtoprocess', b'uiblocked', default=None,
848 851 )
849 852 coreconfigitem(
850 853 b'merge', b'checkunknown', default=b'abort',
851 854 )
852 855 coreconfigitem(
853 856 b'merge', b'checkignored', default=b'abort',
854 857 )
855 858 coreconfigitem(
856 859 b'experimental', b'merge.checkpathconflicts', default=False,
857 860 )
858 861 coreconfigitem(
859 862 b'merge', b'followcopies', default=True,
860 863 )
861 864 coreconfigitem(
862 865 b'merge', b'on-failure', default=b'continue',
863 866 )
864 867 coreconfigitem(
865 868 b'merge', b'preferancestor', default=lambda: [b'*'], experimental=True,
866 869 )
867 870 coreconfigitem(
868 871 b'merge', b'strict-capability-check', default=False,
869 872 )
870 873 coreconfigitem(
871 874 b'merge-tools', b'.*', default=None, generic=True,
872 875 )
873 876 coreconfigitem(
874 877 b'merge-tools',
875 878 br'.*\.args$',
876 879 default=b"$local $base $other",
877 880 generic=True,
878 881 priority=-1,
879 882 )
880 883 coreconfigitem(
881 884 b'merge-tools', br'.*\.binary$', default=False, generic=True, priority=-1,
882 885 )
883 886 coreconfigitem(
884 887 b'merge-tools', br'.*\.check$', default=list, generic=True, priority=-1,
885 888 )
886 889 coreconfigitem(
887 890 b'merge-tools',
888 891 br'.*\.checkchanged$',
889 892 default=False,
890 893 generic=True,
891 894 priority=-1,
892 895 )
893 896 coreconfigitem(
894 897 b'merge-tools',
895 898 br'.*\.executable$',
896 899 default=dynamicdefault,
897 900 generic=True,
898 901 priority=-1,
899 902 )
900 903 coreconfigitem(
901 904 b'merge-tools', br'.*\.fixeol$', default=False, generic=True, priority=-1,
902 905 )
903 906 coreconfigitem(
904 907 b'merge-tools', br'.*\.gui$', default=False, generic=True, priority=-1,
905 908 )
906 909 coreconfigitem(
907 910 b'merge-tools',
908 911 br'.*\.mergemarkers$',
909 912 default=b'basic',
910 913 generic=True,
911 914 priority=-1,
912 915 )
913 916 coreconfigitem(
914 917 b'merge-tools',
915 918 br'.*\.mergemarkertemplate$',
916 919 default=dynamicdefault, # take from ui.mergemarkertemplate
917 920 generic=True,
918 921 priority=-1,
919 922 )
920 923 coreconfigitem(
921 924 b'merge-tools', br'.*\.priority$', default=0, generic=True, priority=-1,
922 925 )
923 926 coreconfigitem(
924 927 b'merge-tools',
925 928 br'.*\.premerge$',
926 929 default=dynamicdefault,
927 930 generic=True,
928 931 priority=-1,
929 932 )
930 933 coreconfigitem(
931 934 b'merge-tools', br'.*\.symlink$', default=False, generic=True, priority=-1,
932 935 )
933 936 coreconfigitem(
934 937 b'pager', b'attend-.*', default=dynamicdefault, generic=True,
935 938 )
936 939 coreconfigitem(
937 940 b'pager', b'ignore', default=list,
938 941 )
939 942 coreconfigitem(
940 943 b'pager', b'pager', default=dynamicdefault,
941 944 )
942 945 coreconfigitem(
943 946 b'patch', b'eol', default=b'strict',
944 947 )
945 948 coreconfigitem(
946 949 b'patch', b'fuzz', default=2,
947 950 )
948 951 coreconfigitem(
949 952 b'paths', b'default', default=None,
950 953 )
951 954 coreconfigitem(
952 955 b'paths', b'default-push', default=None,
953 956 )
954 957 coreconfigitem(
955 958 b'paths', b'.*', default=None, generic=True,
956 959 )
957 960 coreconfigitem(
958 961 b'phases', b'checksubrepos', default=b'follow',
959 962 )
960 963 coreconfigitem(
961 964 b'phases', b'new-commit', default=b'draft',
962 965 )
963 966 coreconfigitem(
964 967 b'phases', b'publish', default=True,
965 968 )
966 969 coreconfigitem(
967 970 b'profiling', b'enabled', default=False,
968 971 )
969 972 coreconfigitem(
970 973 b'profiling', b'format', default=b'text',
971 974 )
972 975 coreconfigitem(
973 976 b'profiling', b'freq', default=1000,
974 977 )
975 978 coreconfigitem(
976 979 b'profiling', b'limit', default=30,
977 980 )
978 981 coreconfigitem(
979 982 b'profiling', b'nested', default=0,
980 983 )
981 984 coreconfigitem(
982 985 b'profiling', b'output', default=None,
983 986 )
984 987 coreconfigitem(
985 988 b'profiling', b'showmax', default=0.999,
986 989 )
987 990 coreconfigitem(
988 991 b'profiling', b'showmin', default=dynamicdefault,
989 992 )
990 993 coreconfigitem(
991 994 b'profiling', b'showtime', default=True,
992 995 )
993 996 coreconfigitem(
994 997 b'profiling', b'sort', default=b'inlinetime',
995 998 )
996 999 coreconfigitem(
997 1000 b'profiling', b'statformat', default=b'hotpath',
998 1001 )
999 1002 coreconfigitem(
1000 1003 b'profiling', b'time-track', default=dynamicdefault,
1001 1004 )
1002 1005 coreconfigitem(
1003 1006 b'profiling', b'type', default=b'stat',
1004 1007 )
1005 1008 coreconfigitem(
1006 1009 b'progress', b'assume-tty', default=False,
1007 1010 )
1008 1011 coreconfigitem(
1009 1012 b'progress', b'changedelay', default=1,
1010 1013 )
1011 1014 coreconfigitem(
1012 1015 b'progress', b'clear-complete', default=True,
1013 1016 )
1014 1017 coreconfigitem(
1015 1018 b'progress', b'debug', default=False,
1016 1019 )
1017 1020 coreconfigitem(
1018 1021 b'progress', b'delay', default=3,
1019 1022 )
1020 1023 coreconfigitem(
1021 1024 b'progress', b'disable', default=False,
1022 1025 )
1023 1026 coreconfigitem(
1024 1027 b'progress', b'estimateinterval', default=60.0,
1025 1028 )
1026 1029 coreconfigitem(
1027 1030 b'progress',
1028 1031 b'format',
1029 1032 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1030 1033 )
1031 1034 coreconfigitem(
1032 1035 b'progress', b'refresh', default=0.1,
1033 1036 )
1034 1037 coreconfigitem(
1035 1038 b'progress', b'width', default=dynamicdefault,
1036 1039 )
1037 1040 coreconfigitem(
1038 1041 b'push', b'pushvars.server', default=False,
1039 1042 )
1040 1043 coreconfigitem(
1041 1044 b'rewrite',
1042 1045 b'backup-bundle',
1043 1046 default=True,
1044 1047 alias=[(b'ui', b'history-editing-backup')],
1045 1048 )
1046 1049 coreconfigitem(
1047 1050 b'rewrite', b'update-timestamp', default=False,
1048 1051 )
1049 1052 coreconfigitem(
1050 1053 b'storage', b'new-repo-backend', default=b'revlogv1', experimental=True,
1051 1054 )
1052 1055 coreconfigitem(
1053 1056 b'storage',
1054 1057 b'revlog.optimize-delta-parent-choice',
1055 1058 default=True,
1056 1059 alias=[(b'format', b'aggressivemergedeltas')],
1057 1060 )
1058 1061 coreconfigitem(
1059 1062 b'storage', b'revlog.reuse-external-delta', default=True,
1060 1063 )
1061 1064 coreconfigitem(
1062 1065 b'storage', b'revlog.reuse-external-delta-parent', default=None,
1063 1066 )
1064 1067 coreconfigitem(
1065 1068 b'storage', b'revlog.zlib.level', default=None,
1066 1069 )
1067 1070 coreconfigitem(
1068 1071 b'storage', b'revlog.zstd.level', default=None,
1069 1072 )
1070 1073 coreconfigitem(
1071 1074 b'server', b'bookmarks-pushkey-compat', default=True,
1072 1075 )
1073 1076 coreconfigitem(
1074 1077 b'server', b'bundle1', default=True,
1075 1078 )
1076 1079 coreconfigitem(
1077 1080 b'server', b'bundle1gd', default=None,
1078 1081 )
1079 1082 coreconfigitem(
1080 1083 b'server', b'bundle1.pull', default=None,
1081 1084 )
1082 1085 coreconfigitem(
1083 1086 b'server', b'bundle1gd.pull', default=None,
1084 1087 )
1085 1088 coreconfigitem(
1086 1089 b'server', b'bundle1.push', default=None,
1087 1090 )
1088 1091 coreconfigitem(
1089 1092 b'server', b'bundle1gd.push', default=None,
1090 1093 )
1091 1094 coreconfigitem(
1092 1095 b'server',
1093 1096 b'bundle2.stream',
1094 1097 default=True,
1095 1098 alias=[(b'experimental', b'bundle2.stream')],
1096 1099 )
1097 1100 coreconfigitem(
1098 1101 b'server', b'compressionengines', default=list,
1099 1102 )
1100 1103 coreconfigitem(
1101 1104 b'server', b'concurrent-push-mode', default=b'strict',
1102 1105 )
1103 1106 coreconfigitem(
1104 1107 b'server', b'disablefullbundle', default=False,
1105 1108 )
1106 1109 coreconfigitem(
1107 1110 b'server', b'maxhttpheaderlen', default=1024,
1108 1111 )
1109 1112 coreconfigitem(
1110 1113 b'server', b'pullbundle', default=False,
1111 1114 )
1112 1115 coreconfigitem(
1113 1116 b'server', b'preferuncompressed', default=False,
1114 1117 )
1115 1118 coreconfigitem(
1116 1119 b'server', b'streamunbundle', default=False,
1117 1120 )
1118 1121 coreconfigitem(
1119 1122 b'server', b'uncompressed', default=True,
1120 1123 )
1121 1124 coreconfigitem(
1122 1125 b'server', b'uncompressedallowsecret', default=False,
1123 1126 )
1124 1127 coreconfigitem(
1125 1128 b'server', b'view', default=b'served',
1126 1129 )
1127 1130 coreconfigitem(
1128 1131 b'server', b'validate', default=False,
1129 1132 )
1130 1133 coreconfigitem(
1131 1134 b'server', b'zliblevel', default=-1,
1132 1135 )
1133 1136 coreconfigitem(
1134 1137 b'server', b'zstdlevel', default=3,
1135 1138 )
1136 1139 coreconfigitem(
1137 1140 b'share', b'pool', default=None,
1138 1141 )
1139 1142 coreconfigitem(
1140 1143 b'share', b'poolnaming', default=b'identity',
1141 1144 )
1142 1145 coreconfigitem(
1143 1146 b'shelve', b'maxbackups', default=10,
1144 1147 )
1145 1148 coreconfigitem(
1146 1149 b'smtp', b'host', default=None,
1147 1150 )
1148 1151 coreconfigitem(
1149 1152 b'smtp', b'local_hostname', default=None,
1150 1153 )
1151 1154 coreconfigitem(
1152 1155 b'smtp', b'password', default=None,
1153 1156 )
1154 1157 coreconfigitem(
1155 1158 b'smtp', b'port', default=dynamicdefault,
1156 1159 )
1157 1160 coreconfigitem(
1158 1161 b'smtp', b'tls', default=b'none',
1159 1162 )
1160 1163 coreconfigitem(
1161 1164 b'smtp', b'username', default=None,
1162 1165 )
1163 1166 coreconfigitem(
1164 1167 b'sparse', b'missingwarning', default=True, experimental=True,
1165 1168 )
1166 1169 coreconfigitem(
1167 1170 b'subrepos',
1168 1171 b'allowed',
1169 1172 default=dynamicdefault, # to make backporting simpler
1170 1173 )
1171 1174 coreconfigitem(
1172 1175 b'subrepos', b'hg:allowed', default=dynamicdefault,
1173 1176 )
1174 1177 coreconfigitem(
1175 1178 b'subrepos', b'git:allowed', default=dynamicdefault,
1176 1179 )
1177 1180 coreconfigitem(
1178 1181 b'subrepos', b'svn:allowed', default=dynamicdefault,
1179 1182 )
1180 1183 coreconfigitem(
1181 1184 b'templates', b'.*', default=None, generic=True,
1182 1185 )
1183 1186 coreconfigitem(
1184 1187 b'templateconfig', b'.*', default=dynamicdefault, generic=True,
1185 1188 )
1186 1189 coreconfigitem(
1187 1190 b'trusted', b'groups', default=list,
1188 1191 )
1189 1192 coreconfigitem(
1190 1193 b'trusted', b'users', default=list,
1191 1194 )
1192 1195 coreconfigitem(
1193 1196 b'ui', b'_usedassubrepo', default=False,
1194 1197 )
1195 1198 coreconfigitem(
1196 1199 b'ui', b'allowemptycommit', default=False,
1197 1200 )
1198 1201 coreconfigitem(
1199 1202 b'ui', b'archivemeta', default=True,
1200 1203 )
1201 1204 coreconfigitem(
1202 1205 b'ui', b'askusername', default=False,
1203 1206 )
1204 1207 coreconfigitem(
1205 1208 b'ui', b'clonebundlefallback', default=False,
1206 1209 )
1207 1210 coreconfigitem(
1208 1211 b'ui', b'clonebundleprefers', default=list,
1209 1212 )
1210 1213 coreconfigitem(
1211 1214 b'ui', b'clonebundles', default=True,
1212 1215 )
1213 1216 coreconfigitem(
1214 1217 b'ui', b'color', default=b'auto',
1215 1218 )
1216 1219 coreconfigitem(
1217 1220 b'ui', b'commitsubrepos', default=False,
1218 1221 )
1219 1222 coreconfigitem(
1220 1223 b'ui', b'debug', default=False,
1221 1224 )
1222 1225 coreconfigitem(
1223 1226 b'ui', b'debugger', default=None,
1224 1227 )
1225 1228 coreconfigitem(
1226 1229 b'ui', b'editor', default=dynamicdefault,
1227 1230 )
1228 1231 coreconfigitem(
1229 1232 b'ui', b'fallbackencoding', default=None,
1230 1233 )
1231 1234 coreconfigitem(
1232 1235 b'ui', b'forcecwd', default=None,
1233 1236 )
1234 1237 coreconfigitem(
1235 1238 b'ui', b'forcemerge', default=None,
1236 1239 )
1237 1240 coreconfigitem(
1238 1241 b'ui', b'formatdebug', default=False,
1239 1242 )
1240 1243 coreconfigitem(
1241 1244 b'ui', b'formatjson', default=False,
1242 1245 )
1243 1246 coreconfigitem(
1244 1247 b'ui', b'formatted', default=None,
1245 1248 )
1246 1249 coreconfigitem(
1247 1250 b'ui', b'graphnodetemplate', default=None,
1248 1251 )
1249 1252 coreconfigitem(
1250 1253 b'ui', b'interactive', default=None,
1251 1254 )
1252 1255 coreconfigitem(
1253 1256 b'ui', b'interface', default=None,
1254 1257 )
1255 1258 coreconfigitem(
1256 1259 b'ui', b'interface.chunkselector', default=None,
1257 1260 )
1258 1261 coreconfigitem(
1259 1262 b'ui', b'large-file-limit', default=10000000,
1260 1263 )
1261 1264 coreconfigitem(
1262 1265 b'ui', b'logblockedtimes', default=False,
1263 1266 )
1264 1267 coreconfigitem(
1265 1268 b'ui', b'logtemplate', default=None,
1266 1269 )
1267 1270 coreconfigitem(
1268 1271 b'ui', b'merge', default=None,
1269 1272 )
1270 1273 coreconfigitem(
1271 1274 b'ui', b'mergemarkers', default=b'basic',
1272 1275 )
1273 1276 coreconfigitem(
1274 1277 b'ui',
1275 1278 b'mergemarkertemplate',
1276 1279 default=(
1277 1280 b'{node|short} '
1278 1281 b'{ifeq(tags, "tip", "", '
1279 1282 b'ifeq(tags, "", "", "{tags} "))}'
1280 1283 b'{if(bookmarks, "{bookmarks} ")}'
1281 1284 b'{ifeq(branch, "default", "", "{branch} ")}'
1282 1285 b'- {author|user}: {desc|firstline}'
1283 1286 ),
1284 1287 )
1285 1288 coreconfigitem(
1286 1289 b'ui', b'message-output', default=b'stdio',
1287 1290 )
1288 1291 coreconfigitem(
1289 1292 b'ui', b'nontty', default=False,
1290 1293 )
1291 1294 coreconfigitem(
1292 1295 b'ui', b'origbackuppath', default=None,
1293 1296 )
1294 1297 coreconfigitem(
1295 1298 b'ui', b'paginate', default=True,
1296 1299 )
1297 1300 coreconfigitem(
1298 1301 b'ui', b'patch', default=None,
1299 1302 )
1300 1303 coreconfigitem(
1301 1304 b'ui', b'pre-merge-tool-output-template', default=None,
1302 1305 )
1303 1306 coreconfigitem(
1304 1307 b'ui', b'portablefilenames', default=b'warn',
1305 1308 )
1306 1309 coreconfigitem(
1307 1310 b'ui', b'promptecho', default=False,
1308 1311 )
1309 1312 coreconfigitem(
1310 1313 b'ui', b'quiet', default=False,
1311 1314 )
1312 1315 coreconfigitem(
1313 1316 b'ui', b'quietbookmarkmove', default=False,
1314 1317 )
1315 1318 coreconfigitem(
1316 1319 b'ui', b'relative-paths', default=b'legacy',
1317 1320 )
1318 1321 coreconfigitem(
1319 1322 b'ui', b'remotecmd', default=b'hg',
1320 1323 )
1321 1324 coreconfigitem(
1322 1325 b'ui', b'report_untrusted', default=True,
1323 1326 )
1324 1327 coreconfigitem(
1325 1328 b'ui', b'rollback', default=True,
1326 1329 )
1327 1330 coreconfigitem(
1328 1331 b'ui', b'signal-safe-lock', default=True,
1329 1332 )
1330 1333 coreconfigitem(
1331 1334 b'ui', b'slash', default=False,
1332 1335 )
1333 1336 coreconfigitem(
1334 1337 b'ui', b'ssh', default=b'ssh',
1335 1338 )
1336 1339 coreconfigitem(
1337 1340 b'ui', b'ssherrorhint', default=None,
1338 1341 )
1339 1342 coreconfigitem(
1340 1343 b'ui', b'statuscopies', default=False,
1341 1344 )
1342 1345 coreconfigitem(
1343 1346 b'ui', b'strict', default=False,
1344 1347 )
1345 1348 coreconfigitem(
1346 1349 b'ui', b'style', default=b'',
1347 1350 )
1348 1351 coreconfigitem(
1349 1352 b'ui', b'supportcontact', default=None,
1350 1353 )
1351 1354 coreconfigitem(
1352 1355 b'ui', b'textwidth', default=78,
1353 1356 )
1354 1357 coreconfigitem(
1355 1358 b'ui', b'timeout', default=b'600',
1356 1359 )
1357 1360 coreconfigitem(
1358 1361 b'ui', b'timeout.warn', default=0,
1359 1362 )
1360 1363 coreconfigitem(
1361 1364 b'ui', b'traceback', default=False,
1362 1365 )
1363 1366 coreconfigitem(
1364 1367 b'ui', b'tweakdefaults', default=False,
1365 1368 )
1366 1369 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
1367 1370 coreconfigitem(
1368 1371 b'ui', b'verbose', default=False,
1369 1372 )
1370 1373 coreconfigitem(
1371 1374 b'verify', b'skipflags', default=None,
1372 1375 )
1373 1376 coreconfigitem(
1374 1377 b'web', b'allowbz2', default=False,
1375 1378 )
1376 1379 coreconfigitem(
1377 1380 b'web', b'allowgz', default=False,
1378 1381 )
1379 1382 coreconfigitem(
1380 1383 b'web', b'allow-pull', alias=[(b'web', b'allowpull')], default=True,
1381 1384 )
1382 1385 coreconfigitem(
1383 1386 b'web', b'allow-push', alias=[(b'web', b'allow_push')], default=list,
1384 1387 )
1385 1388 coreconfigitem(
1386 1389 b'web', b'allowzip', default=False,
1387 1390 )
1388 1391 coreconfigitem(
1389 1392 b'web', b'archivesubrepos', default=False,
1390 1393 )
1391 1394 coreconfigitem(
1392 1395 b'web', b'cache', default=True,
1393 1396 )
1394 1397 coreconfigitem(
1395 1398 b'web', b'comparisoncontext', default=5,
1396 1399 )
1397 1400 coreconfigitem(
1398 1401 b'web', b'contact', default=None,
1399 1402 )
1400 1403 coreconfigitem(
1401 1404 b'web', b'deny_push', default=list,
1402 1405 )
1403 1406 coreconfigitem(
1404 1407 b'web', b'guessmime', default=False,
1405 1408 )
1406 1409 coreconfigitem(
1407 1410 b'web', b'hidden', default=False,
1408 1411 )
1409 1412 coreconfigitem(
1410 1413 b'web', b'labels', default=list,
1411 1414 )
1412 1415 coreconfigitem(
1413 1416 b'web', b'logoimg', default=b'hglogo.png',
1414 1417 )
1415 1418 coreconfigitem(
1416 1419 b'web', b'logourl', default=b'https://mercurial-scm.org/',
1417 1420 )
1418 1421 coreconfigitem(
1419 1422 b'web', b'accesslog', default=b'-',
1420 1423 )
1421 1424 coreconfigitem(
1422 1425 b'web', b'address', default=b'',
1423 1426 )
1424 1427 coreconfigitem(
1425 1428 b'web', b'allow-archive', alias=[(b'web', b'allow_archive')], default=list,
1426 1429 )
1427 1430 coreconfigitem(
1428 1431 b'web', b'allow_read', default=list,
1429 1432 )
1430 1433 coreconfigitem(
1431 1434 b'web', b'baseurl', default=None,
1432 1435 )
1433 1436 coreconfigitem(
1434 1437 b'web', b'cacerts', default=None,
1435 1438 )
1436 1439 coreconfigitem(
1437 1440 b'web', b'certificate', default=None,
1438 1441 )
1439 1442 coreconfigitem(
1440 1443 b'web', b'collapse', default=False,
1441 1444 )
1442 1445 coreconfigitem(
1443 1446 b'web', b'csp', default=None,
1444 1447 )
1445 1448 coreconfigitem(
1446 1449 b'web', b'deny_read', default=list,
1447 1450 )
1448 1451 coreconfigitem(
1449 1452 b'web', b'descend', default=True,
1450 1453 )
1451 1454 coreconfigitem(
1452 1455 b'web', b'description', default=b"",
1453 1456 )
1454 1457 coreconfigitem(
1455 1458 b'web', b'encoding', default=lambda: encoding.encoding,
1456 1459 )
1457 1460 coreconfigitem(
1458 1461 b'web', b'errorlog', default=b'-',
1459 1462 )
1460 1463 coreconfigitem(
1461 1464 b'web', b'ipv6', default=False,
1462 1465 )
1463 1466 coreconfigitem(
1464 1467 b'web', b'maxchanges', default=10,
1465 1468 )
1466 1469 coreconfigitem(
1467 1470 b'web', b'maxfiles', default=10,
1468 1471 )
1469 1472 coreconfigitem(
1470 1473 b'web', b'maxshortchanges', default=60,
1471 1474 )
1472 1475 coreconfigitem(
1473 1476 b'web', b'motd', default=b'',
1474 1477 )
1475 1478 coreconfigitem(
1476 1479 b'web', b'name', default=dynamicdefault,
1477 1480 )
1478 1481 coreconfigitem(
1479 1482 b'web', b'port', default=8000,
1480 1483 )
1481 1484 coreconfigitem(
1482 1485 b'web', b'prefix', default=b'',
1483 1486 )
1484 1487 coreconfigitem(
1485 1488 b'web', b'push_ssl', default=True,
1486 1489 )
1487 1490 coreconfigitem(
1488 1491 b'web', b'refreshinterval', default=20,
1489 1492 )
1490 1493 coreconfigitem(
1491 1494 b'web', b'server-header', default=None,
1492 1495 )
1493 1496 coreconfigitem(
1494 1497 b'web', b'static', default=None,
1495 1498 )
1496 1499 coreconfigitem(
1497 1500 b'web', b'staticurl', default=None,
1498 1501 )
1499 1502 coreconfigitem(
1500 1503 b'web', b'stripes', default=1,
1501 1504 )
1502 1505 coreconfigitem(
1503 1506 b'web', b'style', default=b'paper',
1504 1507 )
1505 1508 coreconfigitem(
1506 1509 b'web', b'templates', default=None,
1507 1510 )
1508 1511 coreconfigitem(
1509 1512 b'web', b'view', default=b'served', experimental=True,
1510 1513 )
1511 1514 coreconfigitem(
1512 1515 b'worker', b'backgroundclose', default=dynamicdefault,
1513 1516 )
1514 1517 # Windows defaults to a limit of 512 open files. A buffer of 128
1515 1518 # should give us enough headway.
1516 1519 coreconfigitem(
1517 1520 b'worker', b'backgroundclosemaxqueue', default=384,
1518 1521 )
1519 1522 coreconfigitem(
1520 1523 b'worker', b'backgroundcloseminfilecount', default=2048,
1521 1524 )
1522 1525 coreconfigitem(
1523 1526 b'worker', b'backgroundclosethreadcount', default=4,
1524 1527 )
1525 1528 coreconfigitem(
1526 1529 b'worker', b'enabled', default=True,
1527 1530 )
1528 1531 coreconfigitem(
1529 1532 b'worker', b'numcpus', default=None,
1530 1533 )
1531 1534
1532 1535 # Rebase related configuration moved to core because other extension are doing
1533 1536 # strange things. For example, shelve import the extensions to reuse some bit
1534 1537 # without formally loading it.
1535 1538 coreconfigitem(
1536 1539 b'commands', b'rebase.requiredest', default=False,
1537 1540 )
1538 1541 coreconfigitem(
1539 1542 b'experimental', b'rebaseskipobsolete', default=True,
1540 1543 )
1541 1544 coreconfigitem(
1542 1545 b'rebase', b'singletransaction', default=False,
1543 1546 )
1544 1547 coreconfigitem(
1545 1548 b'rebase', b'experimental.inmemory', default=False,
1546 1549 )
@@ -1,1032 +1,1129 b''
1 1 # copies.py - copy detection for Mercurial
2 2 #
3 3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import collections
11 import multiprocessing
11 12 import os
12 13
13 14 from .i18n import _
14 15
15 16
16 17 from .revlogutils.flagutil import REVIDX_SIDEDATA
17 18
18 19 from . import (
19 20 error,
20 21 match as matchmod,
21 22 node,
22 23 pathutil,
23 24 pycompat,
24 25 util,
25 26 )
26 27
27 28 from .revlogutils import sidedata as sidedatamod
28 29
29 30 from .utils import stringutil
30 31
31 32
32 33 def _filter(src, dst, t):
33 34 """filters out invalid copies after chaining"""
34 35
35 36 # When _chain()'ing copies in 'a' (from 'src' via some other commit 'mid')
36 37 # with copies in 'b' (from 'mid' to 'dst'), we can get the different cases
37 38 # in the following table (not including trivial cases). For example, case 2
38 39 # is where a file existed in 'src' and remained under that name in 'mid' and
39 40 # then was renamed between 'mid' and 'dst'.
40 41 #
41 42 # case src mid dst result
42 43 # 1 x y - -
43 44 # 2 x y y x->y
44 45 # 3 x y x -
45 46 # 4 x y z x->z
46 47 # 5 - x y -
47 48 # 6 x x y x->y
48 49 #
49 50 # _chain() takes care of chaining the copies in 'a' and 'b', but it
50 51 # cannot tell the difference between cases 1 and 2, between 3 and 4, or
51 52 # between 5 and 6, so it includes all cases in its result.
52 53 # Cases 1, 3, and 5 are then removed by _filter().
53 54
54 55 for k, v in list(t.items()):
55 56 # remove copies from files that didn't exist
56 57 if v not in src:
57 58 del t[k]
58 59 # remove criss-crossed copies
59 60 elif k in src and v in dst:
60 61 del t[k]
61 62 # remove copies to files that were then removed
62 63 elif k not in dst:
63 64 del t[k]
64 65
65 66
66 67 def _chain(prefix, suffix):
67 68 """chain two sets of copies 'prefix' and 'suffix'"""
68 69 result = prefix.copy()
69 70 for key, value in pycompat.iteritems(suffix):
70 71 result[key] = prefix.get(value, value)
71 72 return result
72 73
73 74
74 75 def _tracefile(fctx, am, basemf):
75 76 """return file context that is the ancestor of fctx present in ancestor
76 77 manifest am
77 78
78 79 Note: we used to try and stop after a given limit, however checking if that
79 80 limit is reached turned out to be very expensive. we are better off
80 81 disabling that feature."""
81 82
82 83 for f in fctx.ancestors():
83 84 path = f.path()
84 85 if am.get(path, None) == f.filenode():
85 86 return path
86 87 if basemf and basemf.get(path, None) == f.filenode():
87 88 return path
88 89
89 90
90 91 def _dirstatecopies(repo, match=None):
91 92 ds = repo.dirstate
92 93 c = ds.copies().copy()
93 94 for k in list(c):
94 95 if ds[k] not in b'anm' or (match and not match(k)):
95 96 del c[k]
96 97 return c
97 98
98 99
99 100 def _computeforwardmissing(a, b, match=None):
100 101 """Computes which files are in b but not a.
101 102 This is its own function so extensions can easily wrap this call to see what
102 103 files _forwardcopies is about to process.
103 104 """
104 105 ma = a.manifest()
105 106 mb = b.manifest()
106 107 return mb.filesnotin(ma, match=match)
107 108
108 109
109 110 def usechangesetcentricalgo(repo):
110 111 """Checks if we should use changeset-centric copy algorithms"""
111 112 if repo.filecopiesmode == b'changeset-sidedata':
112 113 return True
113 114 readfrom = repo.ui.config(b'experimental', b'copies.read-from')
114 115 changesetsource = (b'changeset-only', b'compatibility')
115 116 return readfrom in changesetsource
116 117
117 118
118 119 def _committedforwardcopies(a, b, base, match):
119 120 """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
120 121 # files might have to be traced back to the fctx parent of the last
121 122 # one-side-only changeset, but not further back than that
122 123 repo = a._repo
123 124
124 125 if usechangesetcentricalgo(repo):
125 126 return _changesetforwardcopies(a, b, match)
126 127
127 128 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
128 129 dbg = repo.ui.debug
129 130 if debug:
130 131 dbg(b'debug.copies: looking into rename from %s to %s\n' % (a, b))
131 132 am = a.manifest()
132 133 basemf = None if base is None else base.manifest()
133 134
134 135 # find where new files came from
135 136 # we currently don't try to find where old files went, too expensive
136 137 # this means we can miss a case like 'hg rm b; hg cp a b'
137 138 cm = {}
138 139
139 140 # Computing the forward missing is quite expensive on large manifests, since
140 141 # it compares the entire manifests. We can optimize it in the common use
141 142 # case of computing what copies are in a commit versus its parent (like
142 143 # during a rebase or histedit). Note, we exclude merge commits from this
143 144 # optimization, since the ctx.files() for a merge commit is not correct for
144 145 # this comparison.
145 146 forwardmissingmatch = match
146 147 if b.p1() == a and b.p2().node() == node.nullid:
147 148 filesmatcher = matchmod.exact(b.files())
148 149 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
149 150 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
150 151
151 152 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
152 153
153 154 if debug:
154 155 dbg(b'debug.copies: missing files to search: %d\n' % len(missing))
155 156
156 157 for f in sorted(missing):
157 158 if debug:
158 159 dbg(b'debug.copies: tracing file: %s\n' % f)
159 160 fctx = b[f]
160 161 fctx._ancestrycontext = ancestrycontext
161 162
162 163 if debug:
163 164 start = util.timer()
164 165 opath = _tracefile(fctx, am, basemf)
165 166 if opath:
166 167 if debug:
167 168 dbg(b'debug.copies: rename of: %s\n' % opath)
168 169 cm[f] = opath
169 170 if debug:
170 171 dbg(
171 172 b'debug.copies: time: %f seconds\n'
172 173 % (util.timer() - start)
173 174 )
174 175 return cm
175 176
176 177
177 178 def _revinfogetter(repo):
178 179 """return a function that return multiple data given a <rev>"i
179 180
180 181 * p1: revision number of first parent
181 182 * p2: revision number of first parent
182 183 * p1copies: mapping of copies from p1
183 184 * p2copies: mapping of copies from p2
184 185 * removed: a list of removed files
185 186 """
186 187 cl = repo.changelog
187 188 parents = cl.parentrevs
188 189
189 190 if repo.filecopiesmode == b'changeset-sidedata':
190 191 changelogrevision = cl.changelogrevision
191 192 flags = cl.flags
192 193
193 194 # A small cache to avoid doing the work twice for merges
194 195 #
195 196 # In the vast majority of cases, if we ask information for a revision
196 197 # about 1 parent, we'll later ask it for the other. So it make sense to
197 198 # keep the information around when reaching the first parent of a merge
198 199 # and dropping it after it was provided for the second parents.
199 200 #
200 201 # It exists cases were only one parent of the merge will be walked. It
201 202 # happens when the "destination" the copy tracing is descendant from a
202 203 # new root, not common with the "source". In that case, we will only walk
203 204 # through merge parents that are descendant of changesets common
204 205 # between "source" and "destination".
205 206 #
206 207 # With the current case implementation if such changesets have a copy
207 208 # information, we'll keep them in memory until the end of
208 209 # _changesetforwardcopies. We don't expect the case to be frequent
209 210 # enough to matters.
210 211 #
211 212 # In addition, it would be possible to reach pathological case, were
212 213 # many first parent are met before any second parent is reached. In
213 214 # that case the cache could grow. If this even become an issue one can
214 215 # safely introduce a maximum cache size. This would trade extra CPU/IO
215 216 # time to save memory.
216 217 merge_caches = {}
217 218
218 219 def revinfo(rev):
219 220 p1, p2 = parents(rev)
220 221 if flags(rev) & REVIDX_SIDEDATA:
221 222 e = merge_caches.pop(rev, None)
222 223 if e is not None:
223 224 return e
224 225 c = changelogrevision(rev)
225 226 p1copies = c.p1copies
226 227 p2copies = c.p2copies
227 228 removed = c.filesremoved
228 229 if p1 != node.nullrev and p2 != node.nullrev:
229 230 # XXX some case we over cache, IGNORE
230 231 merge_caches[rev] = (p1, p2, p1copies, p2copies, removed)
231 232 else:
232 233 p1copies = {}
233 234 p2copies = {}
234 235 removed = []
235 236 return p1, p2, p1copies, p2copies, removed
236 237
237 238 else:
238 239
239 240 def revinfo(rev):
240 241 p1, p2 = parents(rev)
241 242 ctx = repo[rev]
242 243 p1copies, p2copies = ctx._copies
243 244 removed = ctx.filesremoved()
244 245 return p1, p2, p1copies, p2copies, removed
245 246
246 247 return revinfo
247 248
248 249
249 250 def _changesetforwardcopies(a, b, match):
250 251 if a.rev() in (node.nullrev, b.rev()):
251 252 return {}
252 253
253 254 repo = a.repo().unfiltered()
254 255 children = {}
255 256 revinfo = _revinfogetter(repo)
256 257
257 258 cl = repo.changelog
258 259 missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()])
259 260 mrset = set(missingrevs)
260 261 roots = set()
261 262 for r in missingrevs:
262 263 for p in cl.parentrevs(r):
263 264 if p == node.nullrev:
264 265 continue
265 266 if p not in children:
266 267 children[p] = [r]
267 268 else:
268 269 children[p].append(r)
269 270 if p not in mrset:
270 271 roots.add(p)
271 272 if not roots:
272 273 # no common revision to track copies from
273 274 return {}
274 275 min_root = min(roots)
275 276
276 277 from_head = set(
277 278 cl.reachableroots(min_root, [b.rev()], list(roots), includepath=True)
278 279 )
279 280
280 281 iterrevs = set(from_head)
281 282 iterrevs &= mrset
282 283 iterrevs.update(roots)
283 284 iterrevs.remove(b.rev())
284 285 revs = sorted(iterrevs)
285 286 return _combinechangesetcopies(revs, children, b.rev(), revinfo, match)
286 287
287 288
288 289 def _combinechangesetcopies(revs, children, targetrev, revinfo, match):
289 290 """combine the copies information for each item of iterrevs
290 291
291 292 revs: sorted iterable of revision to visit
292 293 children: a {parent: [children]} mapping.
293 294 targetrev: the final copies destination revision (not in iterrevs)
294 295 revinfo(rev): a function that return (p1, p2, p1copies, p2copies, removed)
295 296 match: a matcher
296 297
297 298 It returns the aggregated copies information for `targetrev`.
298 299 """
299 300 all_copies = {}
300 301 alwaysmatch = match.always()
301 302 for r in revs:
302 303 copies = all_copies.pop(r, None)
303 304 if copies is None:
304 305 # this is a root
305 306 copies = {}
306 307 for i, c in enumerate(children[r]):
307 308 p1, p2, p1copies, p2copies, removed = revinfo(c)
308 309 if r == p1:
309 310 parent = 1
310 311 childcopies = p1copies
311 312 else:
312 313 assert r == p2
313 314 parent = 2
314 315 childcopies = p2copies
315 316 if not alwaysmatch:
316 317 childcopies = {
317 318 dst: src for dst, src in childcopies.items() if match(dst)
318 319 }
319 320 newcopies = copies
320 321 if childcopies:
321 322 newcopies = _chain(newcopies, childcopies)
322 323 # _chain makes a copies, we can avoid doing so in some
323 324 # simple/linear cases.
324 325 assert newcopies is not copies
325 326 for f in removed:
326 327 if f in newcopies:
327 328 if newcopies is copies:
328 329 # copy on write to avoid affecting potential other
329 330 # branches. when there are no other branches, this
330 331 # could be avoided.
331 332 newcopies = copies.copy()
332 333 del newcopies[f]
333 334 othercopies = all_copies.get(c)
334 335 if othercopies is None:
335 336 all_copies[c] = newcopies
336 337 else:
337 338 # we are the second parent to work on c, we need to merge our
338 339 # work with the other.
339 340 #
340 341 # Unlike when copies are stored in the filelog, we consider
341 342 # it a copy even if the destination already existed on the
342 343 # other branch. It's simply too expensive to check if the
343 344 # file existed in the manifest.
344 345 #
345 346 # In case of conflict, parent 1 take precedence over parent 2.
346 347 # This is an arbitrary choice made anew when implementing
347 348 # changeset based copies. It was made without regards with
348 349 # potential filelog related behavior.
349 350 if parent == 1:
350 351 othercopies.update(newcopies)
351 352 else:
352 353 newcopies.update(othercopies)
353 354 all_copies[c] = newcopies
354 355 return all_copies[targetrev]
355 356
356 357
357 358 def _forwardcopies(a, b, base=None, match=None):
358 359 """find {dst@b: src@a} copy mapping where a is an ancestor of b"""
359 360
360 361 if base is None:
361 362 base = a
362 363 match = a.repo().narrowmatch(match)
363 364 # check for working copy
364 365 if b.rev() is None:
365 366 cm = _committedforwardcopies(a, b.p1(), base, match)
366 367 # combine copies from dirstate if necessary
367 368 copies = _chain(cm, _dirstatecopies(b._repo, match))
368 369 else:
369 370 copies = _committedforwardcopies(a, b, base, match)
370 371 return copies
371 372
372 373
373 374 def _backwardrenames(a, b, match):
374 375 if a._repo.ui.config(b'experimental', b'copytrace') == b'off':
375 376 return {}
376 377
377 378 # Even though we're not taking copies into account, 1:n rename situations
378 379 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
379 380 # arbitrarily pick one of the renames.
380 381 # We don't want to pass in "match" here, since that would filter
381 382 # the destination by it. Since we're reversing the copies, we want
382 383 # to filter the source instead.
383 384 f = _forwardcopies(b, a)
384 385 r = {}
385 386 for k, v in sorted(pycompat.iteritems(f)):
386 387 if match and not match(v):
387 388 continue
388 389 # remove copies
389 390 if v in a:
390 391 continue
391 392 r[v] = k
392 393 return r
393 394
394 395
395 396 def pathcopies(x, y, match=None):
396 397 """find {dst@y: src@x} copy mapping for directed compare"""
397 398 repo = x._repo
398 399 debug = repo.ui.debugflag and repo.ui.configbool(b'devel', b'debug.copies')
399 400 if debug:
400 401 repo.ui.debug(
401 402 b'debug.copies: searching copies from %s to %s\n' % (x, y)
402 403 )
403 404 if x == y or not x or not y:
404 405 return {}
405 406 a = y.ancestor(x)
406 407 if a == x:
407 408 if debug:
408 409 repo.ui.debug(b'debug.copies: search mode: forward\n')
409 410 if y.rev() is None and x == y.p1():
410 411 # short-circuit to avoid issues with merge states
411 412 return _dirstatecopies(repo, match)
412 413 copies = _forwardcopies(x, y, match=match)
413 414 elif a == y:
414 415 if debug:
415 416 repo.ui.debug(b'debug.copies: search mode: backward\n')
416 417 copies = _backwardrenames(x, y, match=match)
417 418 else:
418 419 if debug:
419 420 repo.ui.debug(b'debug.copies: search mode: combined\n')
420 421 base = None
421 422 if a.rev() != node.nullrev:
422 423 base = x
423 424 copies = _chain(
424 425 _backwardrenames(x, a, match=match),
425 426 _forwardcopies(a, y, base, match=match),
426 427 )
427 428 _filter(x, y, copies)
428 429 return copies
429 430
430 431
431 432 def mergecopies(repo, c1, c2, base):
432 433 """
433 434 Finds moves and copies between context c1 and c2 that are relevant for
434 435 merging. 'base' will be used as the merge base.
435 436
436 437 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
437 438 files that were moved/ copied in one merge parent and modified in another.
438 439 For example:
439 440
440 441 o ---> 4 another commit
441 442 |
442 443 | o ---> 3 commit that modifies a.txt
443 444 | /
444 445 o / ---> 2 commit that moves a.txt to b.txt
445 446 |/
446 447 o ---> 1 merge base
447 448
448 449 If we try to rebase revision 3 on revision 4, since there is no a.txt in
449 450 revision 4, and if user have copytrace disabled, we prints the following
450 451 message:
451 452
452 453 ```other changed <file> which local deleted```
453 454
454 455 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
455 456 "dirmove".
456 457
457 458 "copy" is a mapping from destination name -> source name,
458 459 where source is in c1 and destination is in c2 or vice-versa.
459 460
460 461 "movewithdir" is a mapping from source name -> destination name,
461 462 where the file at source present in one context but not the other
462 463 needs to be moved to destination by the merge process, because the
463 464 other context moved the directory it is in.
464 465
465 466 "diverge" is a mapping of source name -> list of destination names
466 467 for divergent renames.
467 468
468 469 "renamedelete" is a mapping of source name -> list of destination
469 470 names for files deleted in c1 that were renamed in c2 or vice-versa.
470 471
471 472 "dirmove" is a mapping of detected source dir -> destination dir renames.
472 473 This is needed for handling changes to new files previously grafted into
473 474 renamed directories.
474 475
475 476 This function calls different copytracing algorithms based on config.
476 477 """
477 478 # avoid silly behavior for update from empty dir
478 479 if not c1 or not c2 or c1 == c2:
479 480 return {}, {}, {}, {}, {}
480 481
481 482 narrowmatch = c1.repo().narrowmatch()
482 483
483 484 # avoid silly behavior for parent -> working dir
484 485 if c2.node() is None and c1.node() == repo.dirstate.p1():
485 486 return _dirstatecopies(repo, narrowmatch), {}, {}, {}, {}
486 487
487 488 copytracing = repo.ui.config(b'experimental', b'copytrace')
488 489 if stringutil.parsebool(copytracing) is False:
489 490 # stringutil.parsebool() returns None when it is unable to parse the
490 491 # value, so we should rely on making sure copytracing is on such cases
491 492 return {}, {}, {}, {}, {}
492 493
493 494 if usechangesetcentricalgo(repo):
494 495 # The heuristics don't make sense when we need changeset-centric algos
495 496 return _fullcopytracing(repo, c1, c2, base)
496 497
497 498 # Copy trace disabling is explicitly below the node == p1 logic above
498 499 # because the logic above is required for a simple copy to be kept across a
499 500 # rebase.
500 501 if copytracing == b'heuristics':
501 502 # Do full copytracing if only non-public revisions are involved as
502 503 # that will be fast enough and will also cover the copies which could
503 504 # be missed by heuristics
504 505 if _isfullcopytraceable(repo, c1, base):
505 506 return _fullcopytracing(repo, c1, c2, base)
506 507 return _heuristicscopytracing(repo, c1, c2, base)
507 508 else:
508 509 return _fullcopytracing(repo, c1, c2, base)
509 510
510 511
511 512 def _isfullcopytraceable(repo, c1, base):
512 513 """ Checks that if base, source and destination are all no-public branches,
513 514 if yes let's use the full copytrace algorithm for increased capabilities
514 515 since it will be fast enough.
515 516
516 517 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
517 518 number of changesets from c1 to base such that if number of changesets are
518 519 more than the limit, full copytracing algorithm won't be used.
519 520 """
520 521 if c1.rev() is None:
521 522 c1 = c1.p1()
522 523 if c1.mutable() and base.mutable():
523 524 sourcecommitlimit = repo.ui.configint(
524 525 b'experimental', b'copytrace.sourcecommitlimit'
525 526 )
526 527 commits = len(repo.revs(b'%d::%d', base.rev(), c1.rev()))
527 528 return commits < sourcecommitlimit
528 529 return False
529 530
530 531
531 532 def _checksinglesidecopies(
532 533 src, dsts1, m1, m2, mb, c2, base, copy, renamedelete
533 534 ):
534 535 if src not in m2:
535 536 # deleted on side 2
536 537 if src not in m1:
537 538 # renamed on side 1, deleted on side 2
538 539 renamedelete[src] = dsts1
539 540 elif m2[src] != mb[src]:
540 541 if not _related(c2[src], base[src]):
541 542 return
542 543 # modified on side 2
543 544 for dst in dsts1:
544 545 if dst not in m2:
545 546 # dst not added on side 2 (handle as regular
546 547 # "both created" case in manifestmerge otherwise)
547 548 copy[dst] = src
548 549
549 550
550 551 def _fullcopytracing(repo, c1, c2, base):
551 552 """ The full copytracing algorithm which finds all the new files that were
552 553 added from merge base up to the top commit and for each file it checks if
553 554 this file was copied from another file.
554 555
555 556 This is pretty slow when a lot of changesets are involved but will track all
556 557 the copies.
557 558 """
558 559 m1 = c1.manifest()
559 560 m2 = c2.manifest()
560 561 mb = base.manifest()
561 562
562 563 copies1 = pathcopies(base, c1)
563 564 copies2 = pathcopies(base, c2)
564 565
565 566 inversecopies1 = {}
566 567 inversecopies2 = {}
567 568 for dst, src in copies1.items():
568 569 inversecopies1.setdefault(src, []).append(dst)
569 570 for dst, src in copies2.items():
570 571 inversecopies2.setdefault(src, []).append(dst)
571 572
572 573 copy = {}
573 574 diverge = {}
574 575 renamedelete = {}
575 576 allsources = set(inversecopies1) | set(inversecopies2)
576 577 for src in allsources:
577 578 dsts1 = inversecopies1.get(src)
578 579 dsts2 = inversecopies2.get(src)
579 580 if dsts1 and dsts2:
580 581 # copied/renamed on both sides
581 582 if src not in m1 and src not in m2:
582 583 # renamed on both sides
583 584 dsts1 = set(dsts1)
584 585 dsts2 = set(dsts2)
585 586 # If there's some overlap in the rename destinations, we
586 587 # consider it not divergent. For example, if side 1 copies 'a'
587 588 # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c'
588 589 # and 'd' and deletes 'a'.
589 590 if dsts1 & dsts2:
590 591 for dst in dsts1 & dsts2:
591 592 copy[dst] = src
592 593 else:
593 594 diverge[src] = sorted(dsts1 | dsts2)
594 595 elif src in m1 and src in m2:
595 596 # copied on both sides
596 597 dsts1 = set(dsts1)
597 598 dsts2 = set(dsts2)
598 599 for dst in dsts1 & dsts2:
599 600 copy[dst] = src
600 601 # TODO: Handle cases where it was renamed on one side and copied
601 602 # on the other side
602 603 elif dsts1:
603 604 # copied/renamed only on side 1
604 605 _checksinglesidecopies(
605 606 src, dsts1, m1, m2, mb, c2, base, copy, renamedelete
606 607 )
607 608 elif dsts2:
608 609 # copied/renamed only on side 2
609 610 _checksinglesidecopies(
610 611 src, dsts2, m2, m1, mb, c1, base, copy, renamedelete
611 612 )
612 613
613 614 renamedeleteset = set()
614 615 divergeset = set()
615 616 for dsts in diverge.values():
616 617 divergeset.update(dsts)
617 618 for dsts in renamedelete.values():
618 619 renamedeleteset.update(dsts)
619 620
620 621 # find interesting file sets from manifests
621 622 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
622 623 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
623 624 u1 = sorted(addedinm1 - addedinm2)
624 625 u2 = sorted(addedinm2 - addedinm1)
625 626
626 627 header = b" unmatched files in %s"
627 628 if u1:
628 629 repo.ui.debug(b"%s:\n %s\n" % (header % b'local', b"\n ".join(u1)))
629 630 if u2:
630 631 repo.ui.debug(b"%s:\n %s\n" % (header % b'other', b"\n ".join(u2)))
631 632
632 633 fullcopy = copies1.copy()
633 634 fullcopy.update(copies2)
634 635 if not fullcopy:
635 636 return copy, {}, diverge, renamedelete, {}
636 637
637 638 if repo.ui.debugflag:
638 639 repo.ui.debug(
639 640 b" all copies found (* = to merge, ! = divergent, "
640 641 b"% = renamed and deleted):\n"
641 642 )
642 643 for f in sorted(fullcopy):
643 644 note = b""
644 645 if f in copy:
645 646 note += b"*"
646 647 if f in divergeset:
647 648 note += b"!"
648 649 if f in renamedeleteset:
649 650 note += b"%"
650 651 repo.ui.debug(
651 652 b" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f, note)
652 653 )
653 654 del divergeset
654 655
655 656 repo.ui.debug(b" checking for directory renames\n")
656 657
657 658 # generate a directory move map
658 659 d1, d2 = c1.dirs(), c2.dirs()
659 660 invalid = set()
660 661 dirmove = {}
661 662
662 663 # examine each file copy for a potential directory move, which is
663 664 # when all the files in a directory are moved to a new directory
664 665 for dst, src in pycompat.iteritems(fullcopy):
665 666 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
666 667 if dsrc in invalid:
667 668 # already seen to be uninteresting
668 669 continue
669 670 elif dsrc in d1 and ddst in d1:
670 671 # directory wasn't entirely moved locally
671 672 invalid.add(dsrc)
672 673 elif dsrc in d2 and ddst in d2:
673 674 # directory wasn't entirely moved remotely
674 675 invalid.add(dsrc)
675 676 elif dsrc in dirmove and dirmove[dsrc] != ddst:
676 677 # files from the same directory moved to two different places
677 678 invalid.add(dsrc)
678 679 else:
679 680 # looks good so far
680 681 dirmove[dsrc] = ddst
681 682
682 683 for i in invalid:
683 684 if i in dirmove:
684 685 del dirmove[i]
685 686 del d1, d2, invalid
686 687
687 688 if not dirmove:
688 689 return copy, {}, diverge, renamedelete, {}
689 690
690 691 dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}
691 692
692 693 for d in dirmove:
693 694 repo.ui.debug(
694 695 b" discovered dir src: '%s' -> dst: '%s'\n" % (d, dirmove[d])
695 696 )
696 697
697 698 movewithdir = {}
698 699 # check unaccounted nonoverlapping files against directory moves
699 700 for f in u1 + u2:
700 701 if f not in fullcopy:
701 702 for d in dirmove:
702 703 if f.startswith(d):
703 704 # new file added in a directory that was moved, move it
704 705 df = dirmove[d] + f[len(d) :]
705 706 if df not in copy:
706 707 movewithdir[f] = df
707 708 repo.ui.debug(
708 709 b" pending file src: '%s' -> dst: '%s'\n"
709 710 % (f, df)
710 711 )
711 712 break
712 713
713 714 return copy, movewithdir, diverge, renamedelete, dirmove
714 715
715 716
716 717 def _heuristicscopytracing(repo, c1, c2, base):
717 718 """ Fast copytracing using filename heuristics
718 719
719 720 Assumes that moves or renames are of following two types:
720 721
721 722 1) Inside a directory only (same directory name but different filenames)
722 723 2) Move from one directory to another
723 724 (same filenames but different directory names)
724 725
725 726 Works only when there are no merge commits in the "source branch".
726 727 Source branch is commits from base up to c2 not including base.
727 728
728 729 If merge is involved it fallbacks to _fullcopytracing().
729 730
730 731 Can be used by setting the following config:
731 732
732 733 [experimental]
733 734 copytrace = heuristics
734 735
735 736 In some cases the copy/move candidates found by heuristics can be very large
736 737 in number and that will make the algorithm slow. The number of possible
737 738 candidates to check can be limited by using the config
738 739 `experimental.copytrace.movecandidateslimit` which defaults to 100.
739 740 """
740 741
741 742 if c1.rev() is None:
742 743 c1 = c1.p1()
743 744 if c2.rev() is None:
744 745 c2 = c2.p1()
745 746
746 747 copies = {}
747 748
748 749 changedfiles = set()
749 750 m1 = c1.manifest()
750 751 if not repo.revs(b'%d::%d', base.rev(), c2.rev()):
751 752 # If base is not in c2 branch, we switch to fullcopytracing
752 753 repo.ui.debug(
753 754 b"switching to full copytracing as base is not "
754 755 b"an ancestor of c2\n"
755 756 )
756 757 return _fullcopytracing(repo, c1, c2, base)
757 758
758 759 ctx = c2
759 760 while ctx != base:
760 761 if len(ctx.parents()) == 2:
761 762 # To keep things simple let's not handle merges
762 763 repo.ui.debug(b"switching to full copytracing because of merges\n")
763 764 return _fullcopytracing(repo, c1, c2, base)
764 765 changedfiles.update(ctx.files())
765 766 ctx = ctx.p1()
766 767
767 768 cp = _forwardcopies(base, c2)
768 769 for dst, src in pycompat.iteritems(cp):
769 770 if src in m1:
770 771 copies[dst] = src
771 772
772 773 # file is missing if it isn't present in the destination, but is present in
773 774 # the base and present in the source.
774 775 # Presence in the base is important to exclude added files, presence in the
775 776 # source is important to exclude removed files.
776 777 filt = lambda f: f not in m1 and f in base and f in c2
777 778 missingfiles = [f for f in changedfiles if filt(f)]
778 779
779 780 if missingfiles:
780 781 basenametofilename = collections.defaultdict(list)
781 782 dirnametofilename = collections.defaultdict(list)
782 783
783 784 for f in m1.filesnotin(base.manifest()):
784 785 basename = os.path.basename(f)
785 786 dirname = os.path.dirname(f)
786 787 basenametofilename[basename].append(f)
787 788 dirnametofilename[dirname].append(f)
788 789
789 790 for f in missingfiles:
790 791 basename = os.path.basename(f)
791 792 dirname = os.path.dirname(f)
792 793 samebasename = basenametofilename[basename]
793 794 samedirname = dirnametofilename[dirname]
794 795 movecandidates = samebasename + samedirname
795 796 # f is guaranteed to be present in c2, that's why
796 797 # c2.filectx(f) won't fail
797 798 f2 = c2.filectx(f)
798 799 # we can have a lot of candidates which can slow down the heuristics
799 800 # config value to limit the number of candidates moves to check
800 801 maxcandidates = repo.ui.configint(
801 802 b'experimental', b'copytrace.movecandidateslimit'
802 803 )
803 804
804 805 if len(movecandidates) > maxcandidates:
805 806 repo.ui.status(
806 807 _(
807 808 b"skipping copytracing for '%s', more "
808 809 b"candidates than the limit: %d\n"
809 810 )
810 811 % (f, len(movecandidates))
811 812 )
812 813 continue
813 814
814 815 for candidate in movecandidates:
815 816 f1 = c1.filectx(candidate)
816 817 if _related(f1, f2):
817 818 # if there are a few related copies then we'll merge
818 819 # changes into all of them. This matches the behaviour
819 820 # of upstream copytracing
820 821 copies[candidate] = f
821 822
822 823 return copies, {}, {}, {}, {}
823 824
824 825
825 826 def _related(f1, f2):
826 827 """return True if f1 and f2 filectx have a common ancestor
827 828
828 829 Walk back to common ancestor to see if the two files originate
829 830 from the same file. Since workingfilectx's rev() is None it messes
830 831 up the integer comparison logic, hence the pre-step check for
831 832 None (f1 and f2 can only be workingfilectx's initially).
832 833 """
833 834
834 835 if f1 == f2:
835 836 return True # a match
836 837
837 838 g1, g2 = f1.ancestors(), f2.ancestors()
838 839 try:
839 840 f1r, f2r = f1.linkrev(), f2.linkrev()
840 841
841 842 if f1r is None:
842 843 f1 = next(g1)
843 844 if f2r is None:
844 845 f2 = next(g2)
845 846
846 847 while True:
847 848 f1r, f2r = f1.linkrev(), f2.linkrev()
848 849 if f1r > f2r:
849 850 f1 = next(g1)
850 851 elif f2r > f1r:
851 852 f2 = next(g2)
852 853 else: # f1 and f2 point to files in the same linkrev
853 854 return f1 == f2 # true if they point to the same file
854 855 except StopIteration:
855 856 return False
856 857
857 858
858 859 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
859 860 """reproduce copies from fromrev to rev in the dirstate
860 861
861 862 If skiprev is specified, it's a revision that should be used to
862 863 filter copy records. Any copies that occur between fromrev and
863 864 skiprev will not be duplicated, even if they appear in the set of
864 865 copies between fromrev and rev.
865 866 """
866 867 exclude = {}
867 868 ctraceconfig = repo.ui.config(b'experimental', b'copytrace')
868 869 bctrace = stringutil.parsebool(ctraceconfig)
869 870 if skiprev is not None and (
870 871 ctraceconfig == b'heuristics' or bctrace or bctrace is None
871 872 ):
872 873 # copytrace='off' skips this line, but not the entire function because
873 874 # the line below is O(size of the repo) during a rebase, while the rest
874 875 # of the function is much faster (and is required for carrying copy
875 876 # metadata across the rebase anyway).
876 877 exclude = pathcopies(repo[fromrev], repo[skiprev])
877 878 for dst, src in pycompat.iteritems(pathcopies(repo[fromrev], repo[rev])):
878 879 if dst in exclude:
879 880 continue
880 881 if dst in wctx:
881 882 wctx[dst].markcopied(src)
882 883
883 884
884 885 def computechangesetfilesadded(ctx):
885 886 """return the list of files added in a changeset
886 887 """
887 888 added = []
888 889 for f in ctx.files():
889 890 if not any(f in p for p in ctx.parents()):
890 891 added.append(f)
891 892 return added
892 893
893 894
894 895 def computechangesetfilesremoved(ctx):
895 896 """return the list of files removed in a changeset
896 897 """
897 898 removed = []
898 899 for f in ctx.files():
899 900 if f not in ctx:
900 901 removed.append(f)
901 902 return removed
902 903
903 904
904 905 def computechangesetcopies(ctx):
905 906 """return the copies data for a changeset
906 907
907 908 The copies data are returned as a pair of dictionnary (p1copies, p2copies).
908 909
909 910 Each dictionnary are in the form: `{newname: oldname}`
910 911 """
911 912 p1copies = {}
912 913 p2copies = {}
913 914 p1 = ctx.p1()
914 915 p2 = ctx.p2()
915 916 narrowmatch = ctx._repo.narrowmatch()
916 917 for dst in ctx.files():
917 918 if not narrowmatch(dst) or dst not in ctx:
918 919 continue
919 920 copied = ctx[dst].renamed()
920 921 if not copied:
921 922 continue
922 923 src, srcnode = copied
923 924 if src in p1 and p1[src].filenode() == srcnode:
924 925 p1copies[dst] = src
925 926 elif src in p2 and p2[src].filenode() == srcnode:
926 927 p2copies[dst] = src
927 928 return p1copies, p2copies
928 929
929 930
930 931 def encodecopies(files, copies):
931 932 items = []
932 933 for i, dst in enumerate(files):
933 934 if dst in copies:
934 935 items.append(b'%d\0%s' % (i, copies[dst]))
935 936 if len(items) != len(copies):
936 937 raise error.ProgrammingError(
937 938 b'some copy targets missing from file list'
938 939 )
939 940 return b"\n".join(items)
940 941
941 942
942 943 def decodecopies(files, data):
943 944 try:
944 945 copies = {}
945 946 if not data:
946 947 return copies
947 948 for l in data.split(b'\n'):
948 949 strindex, src = l.split(b'\0')
949 950 i = int(strindex)
950 951 dst = files[i]
951 952 copies[dst] = src
952 953 return copies
953 954 except (ValueError, IndexError):
954 955 # Perhaps someone had chosen the same key name (e.g. "p1copies") and
955 956 # used different syntax for the value.
956 957 return None
957 958
958 959
959 960 def encodefileindices(files, subset):
960 961 subset = set(subset)
961 962 indices = []
962 963 for i, f in enumerate(files):
963 964 if f in subset:
964 965 indices.append(b'%d' % i)
965 966 return b'\n'.join(indices)
966 967
967 968
968 969 def decodefileindices(files, data):
969 970 try:
970 971 subset = []
971 972 if not data:
972 973 return subset
973 974 for strindex in data.split(b'\n'):
974 975 i = int(strindex)
975 976 if i < 0 or i >= len(files):
976 977 return None
977 978 subset.append(files[i])
978 979 return subset
979 980 except (ValueError, IndexError):
980 981 # Perhaps someone had chosen the same key name (e.g. "added") and
981 982 # used different syntax for the value.
982 983 return None
983 984
984 985
985 986 def _getsidedata(srcrepo, rev):
986 987 ctx = srcrepo[rev]
987 988 filescopies = computechangesetcopies(ctx)
988 989 filesadded = computechangesetfilesadded(ctx)
989 990 filesremoved = computechangesetfilesremoved(ctx)
990 991 sidedata = {}
991 992 if any([filescopies, filesadded, filesremoved]):
992 993 sortedfiles = sorted(ctx.files())
993 994 p1copies, p2copies = filescopies
994 995 p1copies = encodecopies(sortedfiles, p1copies)
995 996 p2copies = encodecopies(sortedfiles, p2copies)
996 997 filesadded = encodefileindices(sortedfiles, filesadded)
997 998 filesremoved = encodefileindices(sortedfiles, filesremoved)
998 999 if p1copies:
999 1000 sidedata[sidedatamod.SD_P1COPIES] = p1copies
1000 1001 if p2copies:
1001 1002 sidedata[sidedatamod.SD_P2COPIES] = p2copies
1002 1003 if filesadded:
1003 1004 sidedata[sidedatamod.SD_FILESADDED] = filesadded
1004 1005 if filesremoved:
1005 1006 sidedata[sidedatamod.SD_FILESREMOVED] = filesremoved
1006 1007 return sidedata
1007 1008
1008 1009
1009 1010 def getsidedataadder(srcrepo, destrepo):
1011 use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade')
1012 if pycompat.iswindows or not use_w:
1013 return _get_simple_sidedata_adder(srcrepo, destrepo)
1014 else:
1015 return _get_worker_sidedata_adder(srcrepo, destrepo)
1016
1017
1018 def _sidedata_worker(srcrepo, revs_queue, sidedata_queue, tokens):
1019 """The function used by worker precomputing sidedata
1020
1021 It read an input queue containing revision numbers
1022 It write in an output queue containing (rev, <sidedata-map>)
1023
1024 The `None` input value is used as a stop signal.
1025
1026 The `tokens` semaphore is user to avoid having too many unprocessed
1027 entries. The workers needs to acquire one token before fetching a task.
1028 They will be released by the consumer of the produced data.
1029 """
1030 tokens.acquire()
1031 rev = revs_queue.get()
1032 while rev is not None:
1033 data = _getsidedata(srcrepo, rev)
1034 sidedata_queue.put((rev, data))
1035 tokens.acquire()
1036 rev = revs_queue.get()
1037 # processing of `None` is completed, release the token.
1038 tokens.release()
1039
1040
1041 BUFF_PER_WORKER = 50
1042
1043
1044 def _get_worker_sidedata_adder(srcrepo, destrepo):
1045 """The parallel version of the sidedata computation
1046
1047 This code spawn a pool of worker that precompute a buffer of sidedata
1048 before we actually need them"""
1049 # avoid circular import copies -> scmutil -> worker -> copies
1050 from . import worker
1051
1052 nbworkers = worker._numworkers(srcrepo.ui)
1053
1054 tokens = multiprocessing.BoundedSemaphore(nbworkers * BUFF_PER_WORKER)
1055 revsq = multiprocessing.Queue()
1056 sidedataq = multiprocessing.Queue()
1057
1058 assert srcrepo.filtername is None
1059 # queue all tasks beforehand, revision numbers are small and it make
1060 # synchronisation simpler
1061 #
1062 # Since the computation for each node can be quite expensive, the overhead
1063 # of using a single queue is not revelant. In practice, most computation
1064 # are fast but some are very expensive and dominate all the other smaller
1065 # cost.
1066 for r in srcrepo.changelog.revs():
1067 revsq.put(r)
1068 # queue the "no more tasks" markers
1069 for i in range(nbworkers):
1070 revsq.put(None)
1071
1072 allworkers = []
1073 for i in range(nbworkers):
1074 args = (srcrepo, revsq, sidedataq, tokens)
1075 w = multiprocessing.Process(target=_sidedata_worker, args=args)
1076 allworkers.append(w)
1077 w.start()
1078
1079 # dictionnary to store results for revision higher than we one we are
1080 # looking for. For example, if we need the sidedatamap for 42, and 43 is
1081 # received, when shelve 43 for later use.
1082 staging = {}
1083
1084 def sidedata_companion(revlog, rev):
1085 sidedata = {}
1086 if util.safehasattr(revlog, b'filteredrevs'): # this is a changelog
1087 # Is the data previously shelved ?
1088 sidedata = staging.pop(rev, None)
1089 if sidedata is None:
1090 # look at the queued result until we find the one we are lookig
1091 # for (shelve the other ones)
1092 r, sidedata = sidedataq.get()
1093 while r != rev:
1094 staging[r] = sidedata
1095 r, sidedata = sidedataq.get()
1096 tokens.release()
1097 return False, (), sidedata
1098
1099 return sidedata_companion
1100
1101
1102 def _get_simple_sidedata_adder(srcrepo, destrepo):
1103 """The simple version of the sidedata computation
1104
1105 It just compute it in the same thread on request"""
1106
1010 1107 def sidedatacompanion(revlog, rev):
1011 1108 sidedata = {}
1012 1109 if util.safehasattr(revlog, 'filteredrevs'): # this is a changelog
1013 1110 sidedata = _getsidedata(srcrepo, rev)
1014 1111 return False, (), sidedata
1015 1112
1016 1113 return sidedatacompanion
1017 1114
1018 1115
1019 1116 def getsidedataremover(srcrepo, destrepo):
1020 1117 def sidedatacompanion(revlog, rev):
1021 1118 f = ()
1022 1119 if util.safehasattr(revlog, 'filteredrevs'): # this is a changelog
1023 1120 if revlog.flags(rev) & REVIDX_SIDEDATA:
1024 1121 f = (
1025 1122 sidedatamod.SD_P1COPIES,
1026 1123 sidedatamod.SD_P2COPIES,
1027 1124 sidedatamod.SD_FILESADDED,
1028 1125 sidedatamod.SD_FILESREMOVED,
1029 1126 )
1030 1127 return False, f, {}
1031 1128
1032 1129 return sidedatacompanion
General Comments 0
You need to be logged in to leave comments. Login now