##// END OF EJS Templates
reuse-delta-base: improves some documentation...
marmoute -
r50561:4bd12c0f default
parent child Browse files
Show More
@@ -1,2908 +1,2909 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import functools
9 import functools
10 import re
10 import re
11
11
12 from . import (
12 from . import (
13 encoding,
13 encoding,
14 error,
14 error,
15 )
15 )
16
16
17
17
18 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in sorted(configtable.items()):
20 for section, items in sorted(configtable.items()):
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = b"extension '%s' overwrite config item '%s.%s'"
25 msg = b"extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config=b'warn-config')
27 ui.develwarn(msg, config=b'warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31
31
32 class configitem:
32 class configitem:
33 """represent a known config item
33 """represent a known config item
34
34
35 :section: the official config section where to find this item,
35 :section: the official config section where to find this item,
36 :name: the official name within the section,
36 :name: the official name within the section,
37 :default: default value for this item,
37 :default: default value for this item,
38 :alias: optional list of tuples as alternatives,
38 :alias: optional list of tuples as alternatives,
39 :generic: this is a generic definition, match name using regular expression.
39 :generic: this is a generic definition, match name using regular expression.
40 """
40 """
41
41
42 def __init__(
42 def __init__(
43 self,
43 self,
44 section,
44 section,
45 name,
45 name,
46 default=None,
46 default=None,
47 alias=(),
47 alias=(),
48 generic=False,
48 generic=False,
49 priority=0,
49 priority=0,
50 experimental=False,
50 experimental=False,
51 ):
51 ):
52 self.section = section
52 self.section = section
53 self.name = name
53 self.name = name
54 self.default = default
54 self.default = default
55 self.alias = list(alias)
55 self.alias = list(alias)
56 self.generic = generic
56 self.generic = generic
57 self.priority = priority
57 self.priority = priority
58 self.experimental = experimental
58 self.experimental = experimental
59 self._re = None
59 self._re = None
60 if generic:
60 if generic:
61 self._re = re.compile(self.name)
61 self._re = re.compile(self.name)
62
62
63
63
64 class itemregister(dict):
64 class itemregister(dict):
65 """A specialized dictionary that can handle wild-card selection"""
65 """A specialized dictionary that can handle wild-card selection"""
66
66
67 def __init__(self):
67 def __init__(self):
68 super(itemregister, self).__init__()
68 super(itemregister, self).__init__()
69 self._generics = set()
69 self._generics = set()
70
70
71 def update(self, other):
71 def update(self, other):
72 super(itemregister, self).update(other)
72 super(itemregister, self).update(other)
73 self._generics.update(other._generics)
73 self._generics.update(other._generics)
74
74
75 def __setitem__(self, key, item):
75 def __setitem__(self, key, item):
76 super(itemregister, self).__setitem__(key, item)
76 super(itemregister, self).__setitem__(key, item)
77 if item.generic:
77 if item.generic:
78 self._generics.add(item)
78 self._generics.add(item)
79
79
80 def get(self, key):
80 def get(self, key):
81 baseitem = super(itemregister, self).get(key)
81 baseitem = super(itemregister, self).get(key)
82 if baseitem is not None and not baseitem.generic:
82 if baseitem is not None and not baseitem.generic:
83 return baseitem
83 return baseitem
84
84
85 # search for a matching generic item
85 # search for a matching generic item
86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 for item in generics:
87 for item in generics:
88 # we use 'match' instead of 'search' to make the matching simpler
88 # we use 'match' instead of 'search' to make the matching simpler
89 # for people unfamiliar with regular expression. Having the match
89 # for people unfamiliar with regular expression. Having the match
90 # rooted to the start of the string will produce less surprising
90 # rooted to the start of the string will produce less surprising
91 # result for user writing simple regex for sub-attribute.
91 # result for user writing simple regex for sub-attribute.
92 #
92 #
93 # For example using "color\..*" match produces an unsurprising
93 # For example using "color\..*" match produces an unsurprising
94 # result, while using search could suddenly match apparently
94 # result, while using search could suddenly match apparently
95 # unrelated configuration that happens to contains "color."
95 # unrelated configuration that happens to contains "color."
96 # anywhere. This is a tradeoff where we favor requiring ".*" on
96 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 # some match to avoid the need to prefix most pattern with "^".
97 # some match to avoid the need to prefix most pattern with "^".
98 # The "^" seems more error prone.
98 # The "^" seems more error prone.
99 if item._re.match(key):
99 if item._re.match(key):
100 return item
100 return item
101
101
102 return None
102 return None
103
103
104
104
105 coreitems = {}
105 coreitems = {}
106
106
107
107
108 def _register(configtable, *args, **kwargs):
108 def _register(configtable, *args, **kwargs):
109 item = configitem(*args, **kwargs)
109 item = configitem(*args, **kwargs)
110 section = configtable.setdefault(item.section, itemregister())
110 section = configtable.setdefault(item.section, itemregister())
111 if item.name in section:
111 if item.name in section:
112 msg = b"duplicated config item registration for '%s.%s'"
112 msg = b"duplicated config item registration for '%s.%s'"
113 raise error.ProgrammingError(msg % (item.section, item.name))
113 raise error.ProgrammingError(msg % (item.section, item.name))
114 section[item.name] = item
114 section[item.name] = item
115
115
116
116
117 # special value for case where the default is derived from other values
117 # special value for case where the default is derived from other values
118 dynamicdefault = object()
118 dynamicdefault = object()
119
119
120 # Registering actual config items
120 # Registering actual config items
121
121
122
122
123 def getitemregister(configtable):
123 def getitemregister(configtable):
124 f = functools.partial(_register, configtable)
124 f = functools.partial(_register, configtable)
125 # export pseudo enum as configitem.*
125 # export pseudo enum as configitem.*
126 f.dynamicdefault = dynamicdefault
126 f.dynamicdefault = dynamicdefault
127 return f
127 return f
128
128
129
129
130 coreconfigitem = getitemregister(coreitems)
130 coreconfigitem = getitemregister(coreitems)
131
131
132
132
133 def _registerdiffopts(section, configprefix=b''):
133 def _registerdiffopts(section, configprefix=b''):
134 coreconfigitem(
134 coreconfigitem(
135 section,
135 section,
136 configprefix + b'nodates',
136 configprefix + b'nodates',
137 default=False,
137 default=False,
138 )
138 )
139 coreconfigitem(
139 coreconfigitem(
140 section,
140 section,
141 configprefix + b'showfunc',
141 configprefix + b'showfunc',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem(
144 coreconfigitem(
145 section,
145 section,
146 configprefix + b'unified',
146 configprefix + b'unified',
147 default=None,
147 default=None,
148 )
148 )
149 coreconfigitem(
149 coreconfigitem(
150 section,
150 section,
151 configprefix + b'git',
151 configprefix + b'git',
152 default=False,
152 default=False,
153 )
153 )
154 coreconfigitem(
154 coreconfigitem(
155 section,
155 section,
156 configprefix + b'ignorews',
156 configprefix + b'ignorews',
157 default=False,
157 default=False,
158 )
158 )
159 coreconfigitem(
159 coreconfigitem(
160 section,
160 section,
161 configprefix + b'ignorewsamount',
161 configprefix + b'ignorewsamount',
162 default=False,
162 default=False,
163 )
163 )
164 coreconfigitem(
164 coreconfigitem(
165 section,
165 section,
166 configprefix + b'ignoreblanklines',
166 configprefix + b'ignoreblanklines',
167 default=False,
167 default=False,
168 )
168 )
169 coreconfigitem(
169 coreconfigitem(
170 section,
170 section,
171 configprefix + b'ignorewseol',
171 configprefix + b'ignorewseol',
172 default=False,
172 default=False,
173 )
173 )
174 coreconfigitem(
174 coreconfigitem(
175 section,
175 section,
176 configprefix + b'nobinary',
176 configprefix + b'nobinary',
177 default=False,
177 default=False,
178 )
178 )
179 coreconfigitem(
179 coreconfigitem(
180 section,
180 section,
181 configprefix + b'noprefix',
181 configprefix + b'noprefix',
182 default=False,
182 default=False,
183 )
183 )
184 coreconfigitem(
184 coreconfigitem(
185 section,
185 section,
186 configprefix + b'word-diff',
186 configprefix + b'word-diff',
187 default=False,
187 default=False,
188 )
188 )
189
189
190
190
191 coreconfigitem(
191 coreconfigitem(
192 b'alias',
192 b'alias',
193 b'.*',
193 b'.*',
194 default=dynamicdefault,
194 default=dynamicdefault,
195 generic=True,
195 generic=True,
196 )
196 )
197 coreconfigitem(
197 coreconfigitem(
198 b'auth',
198 b'auth',
199 b'cookiefile',
199 b'cookiefile',
200 default=None,
200 default=None,
201 )
201 )
202 _registerdiffopts(section=b'annotate')
202 _registerdiffopts(section=b'annotate')
203 # bookmarks.pushing: internal hack for discovery
203 # bookmarks.pushing: internal hack for discovery
204 coreconfigitem(
204 coreconfigitem(
205 b'bookmarks',
205 b'bookmarks',
206 b'pushing',
206 b'pushing',
207 default=list,
207 default=list,
208 )
208 )
209 # bundle.mainreporoot: internal hack for bundlerepo
209 # bundle.mainreporoot: internal hack for bundlerepo
210 coreconfigitem(
210 coreconfigitem(
211 b'bundle',
211 b'bundle',
212 b'mainreporoot',
212 b'mainreporoot',
213 default=b'',
213 default=b'',
214 )
214 )
215 coreconfigitem(
215 coreconfigitem(
216 b'censor',
216 b'censor',
217 b'policy',
217 b'policy',
218 default=b'abort',
218 default=b'abort',
219 experimental=True,
219 experimental=True,
220 )
220 )
221 coreconfigitem(
221 coreconfigitem(
222 b'chgserver',
222 b'chgserver',
223 b'idletimeout',
223 b'idletimeout',
224 default=3600,
224 default=3600,
225 )
225 )
226 coreconfigitem(
226 coreconfigitem(
227 b'chgserver',
227 b'chgserver',
228 b'skiphash',
228 b'skiphash',
229 default=False,
229 default=False,
230 )
230 )
231 coreconfigitem(
231 coreconfigitem(
232 b'cmdserver',
232 b'cmdserver',
233 b'log',
233 b'log',
234 default=None,
234 default=None,
235 )
235 )
236 coreconfigitem(
236 coreconfigitem(
237 b'cmdserver',
237 b'cmdserver',
238 b'max-log-files',
238 b'max-log-files',
239 default=7,
239 default=7,
240 )
240 )
241 coreconfigitem(
241 coreconfigitem(
242 b'cmdserver',
242 b'cmdserver',
243 b'max-log-size',
243 b'max-log-size',
244 default=b'1 MB',
244 default=b'1 MB',
245 )
245 )
246 coreconfigitem(
246 coreconfigitem(
247 b'cmdserver',
247 b'cmdserver',
248 b'max-repo-cache',
248 b'max-repo-cache',
249 default=0,
249 default=0,
250 experimental=True,
250 experimental=True,
251 )
251 )
252 coreconfigitem(
252 coreconfigitem(
253 b'cmdserver',
253 b'cmdserver',
254 b'message-encodings',
254 b'message-encodings',
255 default=list,
255 default=list,
256 )
256 )
257 coreconfigitem(
257 coreconfigitem(
258 b'cmdserver',
258 b'cmdserver',
259 b'track-log',
259 b'track-log',
260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 )
261 )
262 coreconfigitem(
262 coreconfigitem(
263 b'cmdserver',
263 b'cmdserver',
264 b'shutdown-on-interrupt',
264 b'shutdown-on-interrupt',
265 default=True,
265 default=True,
266 )
266 )
267 coreconfigitem(
267 coreconfigitem(
268 b'color',
268 b'color',
269 b'.*',
269 b'.*',
270 default=None,
270 default=None,
271 generic=True,
271 generic=True,
272 )
272 )
273 coreconfigitem(
273 coreconfigitem(
274 b'color',
274 b'color',
275 b'mode',
275 b'mode',
276 default=b'auto',
276 default=b'auto',
277 )
277 )
278 coreconfigitem(
278 coreconfigitem(
279 b'color',
279 b'color',
280 b'pagermode',
280 b'pagermode',
281 default=dynamicdefault,
281 default=dynamicdefault,
282 )
282 )
283 coreconfigitem(
283 coreconfigitem(
284 b'command-templates',
284 b'command-templates',
285 b'graphnode',
285 b'graphnode',
286 default=None,
286 default=None,
287 alias=[(b'ui', b'graphnodetemplate')],
287 alias=[(b'ui', b'graphnodetemplate')],
288 )
288 )
289 coreconfigitem(
289 coreconfigitem(
290 b'command-templates',
290 b'command-templates',
291 b'log',
291 b'log',
292 default=None,
292 default=None,
293 alias=[(b'ui', b'logtemplate')],
293 alias=[(b'ui', b'logtemplate')],
294 )
294 )
295 coreconfigitem(
295 coreconfigitem(
296 b'command-templates',
296 b'command-templates',
297 b'mergemarker',
297 b'mergemarker',
298 default=(
298 default=(
299 b'{node|short} '
299 b'{node|short} '
300 b'{ifeq(tags, "tip", "", '
300 b'{ifeq(tags, "tip", "", '
301 b'ifeq(tags, "", "", "{tags} "))}'
301 b'ifeq(tags, "", "", "{tags} "))}'
302 b'{if(bookmarks, "{bookmarks} ")}'
302 b'{if(bookmarks, "{bookmarks} ")}'
303 b'{ifeq(branch, "default", "", "{branch} ")}'
303 b'{ifeq(branch, "default", "", "{branch} ")}'
304 b'- {author|user}: {desc|firstline}'
304 b'- {author|user}: {desc|firstline}'
305 ),
305 ),
306 alias=[(b'ui', b'mergemarkertemplate')],
306 alias=[(b'ui', b'mergemarkertemplate')],
307 )
307 )
308 coreconfigitem(
308 coreconfigitem(
309 b'command-templates',
309 b'command-templates',
310 b'pre-merge-tool-output',
310 b'pre-merge-tool-output',
311 default=None,
311 default=None,
312 alias=[(b'ui', b'pre-merge-tool-output-template')],
312 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 )
313 )
314 coreconfigitem(
314 coreconfigitem(
315 b'command-templates',
315 b'command-templates',
316 b'oneline-summary',
316 b'oneline-summary',
317 default=None,
317 default=None,
318 )
318 )
319 coreconfigitem(
319 coreconfigitem(
320 b'command-templates',
320 b'command-templates',
321 b'oneline-summary.*',
321 b'oneline-summary.*',
322 default=dynamicdefault,
322 default=dynamicdefault,
323 generic=True,
323 generic=True,
324 )
324 )
325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 coreconfigitem(
326 coreconfigitem(
327 b'commands',
327 b'commands',
328 b'commit.post-status',
328 b'commit.post-status',
329 default=False,
329 default=False,
330 )
330 )
331 coreconfigitem(
331 coreconfigitem(
332 b'commands',
332 b'commands',
333 b'grep.all-files',
333 b'grep.all-files',
334 default=False,
334 default=False,
335 experimental=True,
335 experimental=True,
336 )
336 )
337 coreconfigitem(
337 coreconfigitem(
338 b'commands',
338 b'commands',
339 b'merge.require-rev',
339 b'merge.require-rev',
340 default=False,
340 default=False,
341 )
341 )
342 coreconfigitem(
342 coreconfigitem(
343 b'commands',
343 b'commands',
344 b'push.require-revs',
344 b'push.require-revs',
345 default=False,
345 default=False,
346 )
346 )
347 coreconfigitem(
347 coreconfigitem(
348 b'commands',
348 b'commands',
349 b'resolve.confirm',
349 b'resolve.confirm',
350 default=False,
350 default=False,
351 )
351 )
352 coreconfigitem(
352 coreconfigitem(
353 b'commands',
353 b'commands',
354 b'resolve.explicit-re-merge',
354 b'resolve.explicit-re-merge',
355 default=False,
355 default=False,
356 )
356 )
357 coreconfigitem(
357 coreconfigitem(
358 b'commands',
358 b'commands',
359 b'resolve.mark-check',
359 b'resolve.mark-check',
360 default=b'none',
360 default=b'none',
361 )
361 )
362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 coreconfigitem(
363 coreconfigitem(
364 b'commands',
364 b'commands',
365 b'show.aliasprefix',
365 b'show.aliasprefix',
366 default=list,
366 default=list,
367 )
367 )
368 coreconfigitem(
368 coreconfigitem(
369 b'commands',
369 b'commands',
370 b'status.relative',
370 b'status.relative',
371 default=False,
371 default=False,
372 )
372 )
373 coreconfigitem(
373 coreconfigitem(
374 b'commands',
374 b'commands',
375 b'status.skipstates',
375 b'status.skipstates',
376 default=[],
376 default=[],
377 experimental=True,
377 experimental=True,
378 )
378 )
379 coreconfigitem(
379 coreconfigitem(
380 b'commands',
380 b'commands',
381 b'status.terse',
381 b'status.terse',
382 default=b'',
382 default=b'',
383 )
383 )
384 coreconfigitem(
384 coreconfigitem(
385 b'commands',
385 b'commands',
386 b'status.verbose',
386 b'status.verbose',
387 default=False,
387 default=False,
388 )
388 )
389 coreconfigitem(
389 coreconfigitem(
390 b'commands',
390 b'commands',
391 b'update.check',
391 b'update.check',
392 default=None,
392 default=None,
393 )
393 )
394 coreconfigitem(
394 coreconfigitem(
395 b'commands',
395 b'commands',
396 b'update.requiredest',
396 b'update.requiredest',
397 default=False,
397 default=False,
398 )
398 )
399 coreconfigitem(
399 coreconfigitem(
400 b'committemplate',
400 b'committemplate',
401 b'.*',
401 b'.*',
402 default=None,
402 default=None,
403 generic=True,
403 generic=True,
404 )
404 )
405 coreconfigitem(
405 coreconfigitem(
406 b'convert',
406 b'convert',
407 b'bzr.saverev',
407 b'bzr.saverev',
408 default=True,
408 default=True,
409 )
409 )
410 coreconfigitem(
410 coreconfigitem(
411 b'convert',
411 b'convert',
412 b'cvsps.cache',
412 b'cvsps.cache',
413 default=True,
413 default=True,
414 )
414 )
415 coreconfigitem(
415 coreconfigitem(
416 b'convert',
416 b'convert',
417 b'cvsps.fuzz',
417 b'cvsps.fuzz',
418 default=60,
418 default=60,
419 )
419 )
420 coreconfigitem(
420 coreconfigitem(
421 b'convert',
421 b'convert',
422 b'cvsps.logencoding',
422 b'cvsps.logencoding',
423 default=None,
423 default=None,
424 )
424 )
425 coreconfigitem(
425 coreconfigitem(
426 b'convert',
426 b'convert',
427 b'cvsps.mergefrom',
427 b'cvsps.mergefrom',
428 default=None,
428 default=None,
429 )
429 )
430 coreconfigitem(
430 coreconfigitem(
431 b'convert',
431 b'convert',
432 b'cvsps.mergeto',
432 b'cvsps.mergeto',
433 default=None,
433 default=None,
434 )
434 )
435 coreconfigitem(
435 coreconfigitem(
436 b'convert',
436 b'convert',
437 b'git.committeractions',
437 b'git.committeractions',
438 default=lambda: [b'messagedifferent'],
438 default=lambda: [b'messagedifferent'],
439 )
439 )
440 coreconfigitem(
440 coreconfigitem(
441 b'convert',
441 b'convert',
442 b'git.extrakeys',
442 b'git.extrakeys',
443 default=list,
443 default=list,
444 )
444 )
445 coreconfigitem(
445 coreconfigitem(
446 b'convert',
446 b'convert',
447 b'git.findcopiesharder',
447 b'git.findcopiesharder',
448 default=False,
448 default=False,
449 )
449 )
450 coreconfigitem(
450 coreconfigitem(
451 b'convert',
451 b'convert',
452 b'git.remoteprefix',
452 b'git.remoteprefix',
453 default=b'remote',
453 default=b'remote',
454 )
454 )
455 coreconfigitem(
455 coreconfigitem(
456 b'convert',
456 b'convert',
457 b'git.renamelimit',
457 b'git.renamelimit',
458 default=400,
458 default=400,
459 )
459 )
460 coreconfigitem(
460 coreconfigitem(
461 b'convert',
461 b'convert',
462 b'git.saverev',
462 b'git.saverev',
463 default=True,
463 default=True,
464 )
464 )
465 coreconfigitem(
465 coreconfigitem(
466 b'convert',
466 b'convert',
467 b'git.similarity',
467 b'git.similarity',
468 default=50,
468 default=50,
469 )
469 )
470 coreconfigitem(
470 coreconfigitem(
471 b'convert',
471 b'convert',
472 b'git.skipsubmodules',
472 b'git.skipsubmodules',
473 default=False,
473 default=False,
474 )
474 )
475 coreconfigitem(
475 coreconfigitem(
476 b'convert',
476 b'convert',
477 b'hg.clonebranches',
477 b'hg.clonebranches',
478 default=False,
478 default=False,
479 )
479 )
480 coreconfigitem(
480 coreconfigitem(
481 b'convert',
481 b'convert',
482 b'hg.ignoreerrors',
482 b'hg.ignoreerrors',
483 default=False,
483 default=False,
484 )
484 )
485 coreconfigitem(
485 coreconfigitem(
486 b'convert',
486 b'convert',
487 b'hg.preserve-hash',
487 b'hg.preserve-hash',
488 default=False,
488 default=False,
489 )
489 )
490 coreconfigitem(
490 coreconfigitem(
491 b'convert',
491 b'convert',
492 b'hg.revs',
492 b'hg.revs',
493 default=None,
493 default=None,
494 )
494 )
495 coreconfigitem(
495 coreconfigitem(
496 b'convert',
496 b'convert',
497 b'hg.saverev',
497 b'hg.saverev',
498 default=False,
498 default=False,
499 )
499 )
500 coreconfigitem(
500 coreconfigitem(
501 b'convert',
501 b'convert',
502 b'hg.sourcename',
502 b'hg.sourcename',
503 default=None,
503 default=None,
504 )
504 )
505 coreconfigitem(
505 coreconfigitem(
506 b'convert',
506 b'convert',
507 b'hg.startrev',
507 b'hg.startrev',
508 default=None,
508 default=None,
509 )
509 )
510 coreconfigitem(
510 coreconfigitem(
511 b'convert',
511 b'convert',
512 b'hg.tagsbranch',
512 b'hg.tagsbranch',
513 default=b'default',
513 default=b'default',
514 )
514 )
515 coreconfigitem(
515 coreconfigitem(
516 b'convert',
516 b'convert',
517 b'hg.usebranchnames',
517 b'hg.usebranchnames',
518 default=True,
518 default=True,
519 )
519 )
520 coreconfigitem(
520 coreconfigitem(
521 b'convert',
521 b'convert',
522 b'ignoreancestorcheck',
522 b'ignoreancestorcheck',
523 default=False,
523 default=False,
524 experimental=True,
524 experimental=True,
525 )
525 )
526 coreconfigitem(
526 coreconfigitem(
527 b'convert',
527 b'convert',
528 b'localtimezone',
528 b'localtimezone',
529 default=False,
529 default=False,
530 )
530 )
531 coreconfigitem(
531 coreconfigitem(
532 b'convert',
532 b'convert',
533 b'p4.encoding',
533 b'p4.encoding',
534 default=dynamicdefault,
534 default=dynamicdefault,
535 )
535 )
536 coreconfigitem(
536 coreconfigitem(
537 b'convert',
537 b'convert',
538 b'p4.startrev',
538 b'p4.startrev',
539 default=0,
539 default=0,
540 )
540 )
541 coreconfigitem(
541 coreconfigitem(
542 b'convert',
542 b'convert',
543 b'skiptags',
543 b'skiptags',
544 default=False,
544 default=False,
545 )
545 )
546 coreconfigitem(
546 coreconfigitem(
547 b'convert',
547 b'convert',
548 b'svn.debugsvnlog',
548 b'svn.debugsvnlog',
549 default=True,
549 default=True,
550 )
550 )
551 coreconfigitem(
551 coreconfigitem(
552 b'convert',
552 b'convert',
553 b'svn.trunk',
553 b'svn.trunk',
554 default=None,
554 default=None,
555 )
555 )
556 coreconfigitem(
556 coreconfigitem(
557 b'convert',
557 b'convert',
558 b'svn.tags',
558 b'svn.tags',
559 default=None,
559 default=None,
560 )
560 )
561 coreconfigitem(
561 coreconfigitem(
562 b'convert',
562 b'convert',
563 b'svn.branches',
563 b'svn.branches',
564 default=None,
564 default=None,
565 )
565 )
566 coreconfigitem(
566 coreconfigitem(
567 b'convert',
567 b'convert',
568 b'svn.startrev',
568 b'svn.startrev',
569 default=0,
569 default=0,
570 )
570 )
571 coreconfigitem(
571 coreconfigitem(
572 b'convert',
572 b'convert',
573 b'svn.dangerous-set-commit-dates',
573 b'svn.dangerous-set-commit-dates',
574 default=False,
574 default=False,
575 )
575 )
576 coreconfigitem(
576 coreconfigitem(
577 b'debug',
577 b'debug',
578 b'dirstate.delaywrite',
578 b'dirstate.delaywrite',
579 default=0,
579 default=0,
580 )
580 )
581 coreconfigitem(
581 coreconfigitem(
582 b'debug',
582 b'debug',
583 b'revlog.verifyposition.changelog',
583 b'revlog.verifyposition.changelog',
584 default=b'',
584 default=b'',
585 )
585 )
586 coreconfigitem(
586 coreconfigitem(
587 b'debug',
587 b'debug',
588 b'revlog.debug-delta',
588 b'revlog.debug-delta',
589 default=False,
589 default=False,
590 )
590 )
591 # display extra information about the bundling process
591 # display extra information about the bundling process
592 coreconfigitem(
592 coreconfigitem(
593 b'debug',
593 b'debug',
594 b'bundling-stats',
594 b'bundling-stats',
595 default=False,
595 default=False,
596 )
596 )
597 # display extra information about the unbundling process
597 # display extra information about the unbundling process
598 coreconfigitem(
598 coreconfigitem(
599 b'debug',
599 b'debug',
600 b'unbundling-stats',
600 b'unbundling-stats',
601 default=False,
601 default=False,
602 )
602 )
603 coreconfigitem(
603 coreconfigitem(
604 b'defaults',
604 b'defaults',
605 b'.*',
605 b'.*',
606 default=None,
606 default=None,
607 generic=True,
607 generic=True,
608 )
608 )
609 coreconfigitem(
609 coreconfigitem(
610 b'devel',
610 b'devel',
611 b'all-warnings',
611 b'all-warnings',
612 default=False,
612 default=False,
613 )
613 )
614 coreconfigitem(
614 coreconfigitem(
615 b'devel',
615 b'devel',
616 b'bundle2.debug',
616 b'bundle2.debug',
617 default=False,
617 default=False,
618 )
618 )
619 coreconfigitem(
619 coreconfigitem(
620 b'devel',
620 b'devel',
621 b'bundle.delta',
621 b'bundle.delta',
622 default=b'',
622 default=b'',
623 )
623 )
624 coreconfigitem(
624 coreconfigitem(
625 b'devel',
625 b'devel',
626 b'cache-vfs',
626 b'cache-vfs',
627 default=None,
627 default=None,
628 )
628 )
629 coreconfigitem(
629 coreconfigitem(
630 b'devel',
630 b'devel',
631 b'check-locks',
631 b'check-locks',
632 default=False,
632 default=False,
633 )
633 )
634 coreconfigitem(
634 coreconfigitem(
635 b'devel',
635 b'devel',
636 b'check-relroot',
636 b'check-relroot',
637 default=False,
637 default=False,
638 )
638 )
639 # Track copy information for all file, not just "added" one (very slow)
639 # Track copy information for all file, not just "added" one (very slow)
640 coreconfigitem(
640 coreconfigitem(
641 b'devel',
641 b'devel',
642 b'copy-tracing.trace-all-files',
642 b'copy-tracing.trace-all-files',
643 default=False,
643 default=False,
644 )
644 )
645 coreconfigitem(
645 coreconfigitem(
646 b'devel',
646 b'devel',
647 b'default-date',
647 b'default-date',
648 default=None,
648 default=None,
649 )
649 )
650 coreconfigitem(
650 coreconfigitem(
651 b'devel',
651 b'devel',
652 b'deprec-warn',
652 b'deprec-warn',
653 default=False,
653 default=False,
654 )
654 )
655 coreconfigitem(
655 coreconfigitem(
656 b'devel',
656 b'devel',
657 b'disableloaddefaultcerts',
657 b'disableloaddefaultcerts',
658 default=False,
658 default=False,
659 )
659 )
660 coreconfigitem(
660 coreconfigitem(
661 b'devel',
661 b'devel',
662 b'warn-empty-changegroup',
662 b'warn-empty-changegroup',
663 default=False,
663 default=False,
664 )
664 )
665 coreconfigitem(
665 coreconfigitem(
666 b'devel',
666 b'devel',
667 b'legacy.exchange',
667 b'legacy.exchange',
668 default=list,
668 default=list,
669 )
669 )
670 # When True, revlogs use a special reference version of the nodemap, that is not
670 # When True, revlogs use a special reference version of the nodemap, that is not
671 # performant but is "known" to behave properly.
671 # performant but is "known" to behave properly.
672 coreconfigitem(
672 coreconfigitem(
673 b'devel',
673 b'devel',
674 b'persistent-nodemap',
674 b'persistent-nodemap',
675 default=False,
675 default=False,
676 )
676 )
677 coreconfigitem(
677 coreconfigitem(
678 b'devel',
678 b'devel',
679 b'servercafile',
679 b'servercafile',
680 default=b'',
680 default=b'',
681 )
681 )
682 coreconfigitem(
682 coreconfigitem(
683 b'devel',
683 b'devel',
684 b'serverexactprotocol',
684 b'serverexactprotocol',
685 default=b'',
685 default=b'',
686 )
686 )
687 coreconfigitem(
687 coreconfigitem(
688 b'devel',
688 b'devel',
689 b'serverrequirecert',
689 b'serverrequirecert',
690 default=False,
690 default=False,
691 )
691 )
692 coreconfigitem(
692 coreconfigitem(
693 b'devel',
693 b'devel',
694 b'strip-obsmarkers',
694 b'strip-obsmarkers',
695 default=True,
695 default=True,
696 )
696 )
697 coreconfigitem(
697 coreconfigitem(
698 b'devel',
698 b'devel',
699 b'warn-config',
699 b'warn-config',
700 default=None,
700 default=None,
701 )
701 )
702 coreconfigitem(
702 coreconfigitem(
703 b'devel',
703 b'devel',
704 b'warn-config-default',
704 b'warn-config-default',
705 default=None,
705 default=None,
706 )
706 )
707 coreconfigitem(
707 coreconfigitem(
708 b'devel',
708 b'devel',
709 b'user.obsmarker',
709 b'user.obsmarker',
710 default=None,
710 default=None,
711 )
711 )
712 coreconfigitem(
712 coreconfigitem(
713 b'devel',
713 b'devel',
714 b'warn-config-unknown',
714 b'warn-config-unknown',
715 default=None,
715 default=None,
716 )
716 )
717 coreconfigitem(
717 coreconfigitem(
718 b'devel',
718 b'devel',
719 b'debug.copies',
719 b'debug.copies',
720 default=False,
720 default=False,
721 )
721 )
722 coreconfigitem(
722 coreconfigitem(
723 b'devel',
723 b'devel',
724 b'copy-tracing.multi-thread',
724 b'copy-tracing.multi-thread',
725 default=True,
725 default=True,
726 )
726 )
727 coreconfigitem(
727 coreconfigitem(
728 b'devel',
728 b'devel',
729 b'debug.extensions',
729 b'debug.extensions',
730 default=False,
730 default=False,
731 )
731 )
732 coreconfigitem(
732 coreconfigitem(
733 b'devel',
733 b'devel',
734 b'debug.repo-filters',
734 b'debug.repo-filters',
735 default=False,
735 default=False,
736 )
736 )
737 coreconfigitem(
737 coreconfigitem(
738 b'devel',
738 b'devel',
739 b'debug.peer-request',
739 b'debug.peer-request',
740 default=False,
740 default=False,
741 )
741 )
742 # If discovery.exchange-heads is False, the discovery will not start with
742 # If discovery.exchange-heads is False, the discovery will not start with
743 # remote head fetching and local head querying.
743 # remote head fetching and local head querying.
744 coreconfigitem(
744 coreconfigitem(
745 b'devel',
745 b'devel',
746 b'discovery.exchange-heads',
746 b'discovery.exchange-heads',
747 default=True,
747 default=True,
748 )
748 )
749 # If discovery.grow-sample is False, the sample size used in set discovery will
749 # If discovery.grow-sample is False, the sample size used in set discovery will
750 # not be increased through the process
750 # not be increased through the process
751 coreconfigitem(
751 coreconfigitem(
752 b'devel',
752 b'devel',
753 b'discovery.grow-sample',
753 b'discovery.grow-sample',
754 default=True,
754 default=True,
755 )
755 )
756 # When discovery.grow-sample.dynamic is True, the default, the sample size is
756 # When discovery.grow-sample.dynamic is True, the default, the sample size is
757 # adapted to the shape of the undecided set (it is set to the max of:
757 # adapted to the shape of the undecided set (it is set to the max of:
758 # <target-size>, len(roots(undecided)), len(heads(undecided)
758 # <target-size>, len(roots(undecided)), len(heads(undecided)
759 coreconfigitem(
759 coreconfigitem(
760 b'devel',
760 b'devel',
761 b'discovery.grow-sample.dynamic',
761 b'discovery.grow-sample.dynamic',
762 default=True,
762 default=True,
763 )
763 )
764 # discovery.grow-sample.rate control the rate at which the sample grow
764 # discovery.grow-sample.rate control the rate at which the sample grow
765 coreconfigitem(
765 coreconfigitem(
766 b'devel',
766 b'devel',
767 b'discovery.grow-sample.rate',
767 b'discovery.grow-sample.rate',
768 default=1.05,
768 default=1.05,
769 )
769 )
770 # If discovery.randomize is False, random sampling during discovery are
770 # If discovery.randomize is False, random sampling during discovery are
771 # deterministic. It is meant for integration tests.
771 # deterministic. It is meant for integration tests.
772 coreconfigitem(
772 coreconfigitem(
773 b'devel',
773 b'devel',
774 b'discovery.randomize',
774 b'discovery.randomize',
775 default=True,
775 default=True,
776 )
776 )
777 # Control the initial size of the discovery sample
777 # Control the initial size of the discovery sample
778 coreconfigitem(
778 coreconfigitem(
779 b'devel',
779 b'devel',
780 b'discovery.sample-size',
780 b'discovery.sample-size',
781 default=200,
781 default=200,
782 )
782 )
783 # Control the initial size of the discovery for initial change
783 # Control the initial size of the discovery for initial change
784 coreconfigitem(
784 coreconfigitem(
785 b'devel',
785 b'devel',
786 b'discovery.sample-size.initial',
786 b'discovery.sample-size.initial',
787 default=100,
787 default=100,
788 )
788 )
789 _registerdiffopts(section=b'diff')
789 _registerdiffopts(section=b'diff')
790 coreconfigitem(
790 coreconfigitem(
791 b'diff',
791 b'diff',
792 b'merge',
792 b'merge',
793 default=False,
793 default=False,
794 experimental=True,
794 experimental=True,
795 )
795 )
796 coreconfigitem(
796 coreconfigitem(
797 b'email',
797 b'email',
798 b'bcc',
798 b'bcc',
799 default=None,
799 default=None,
800 )
800 )
801 coreconfigitem(
801 coreconfigitem(
802 b'email',
802 b'email',
803 b'cc',
803 b'cc',
804 default=None,
804 default=None,
805 )
805 )
806 coreconfigitem(
806 coreconfigitem(
807 b'email',
807 b'email',
808 b'charsets',
808 b'charsets',
809 default=list,
809 default=list,
810 )
810 )
811 coreconfigitem(
811 coreconfigitem(
812 b'email',
812 b'email',
813 b'from',
813 b'from',
814 default=None,
814 default=None,
815 )
815 )
816 coreconfigitem(
816 coreconfigitem(
817 b'email',
817 b'email',
818 b'method',
818 b'method',
819 default=b'smtp',
819 default=b'smtp',
820 )
820 )
821 coreconfigitem(
821 coreconfigitem(
822 b'email',
822 b'email',
823 b'reply-to',
823 b'reply-to',
824 default=None,
824 default=None,
825 )
825 )
826 coreconfigitem(
826 coreconfigitem(
827 b'email',
827 b'email',
828 b'to',
828 b'to',
829 default=None,
829 default=None,
830 )
830 )
831 coreconfigitem(
831 coreconfigitem(
832 b'experimental',
832 b'experimental',
833 b'archivemetatemplate',
833 b'archivemetatemplate',
834 default=dynamicdefault,
834 default=dynamicdefault,
835 )
835 )
836 coreconfigitem(
836 coreconfigitem(
837 b'experimental',
837 b'experimental',
838 b'auto-publish',
838 b'auto-publish',
839 default=b'publish',
839 default=b'publish',
840 )
840 )
841 coreconfigitem(
841 coreconfigitem(
842 b'experimental',
842 b'experimental',
843 b'bundle-phases',
843 b'bundle-phases',
844 default=False,
844 default=False,
845 )
845 )
846 coreconfigitem(
846 coreconfigitem(
847 b'experimental',
847 b'experimental',
848 b'bundle2-advertise',
848 b'bundle2-advertise',
849 default=True,
849 default=True,
850 )
850 )
851 coreconfigitem(
851 coreconfigitem(
852 b'experimental',
852 b'experimental',
853 b'bundle2-output-capture',
853 b'bundle2-output-capture',
854 default=False,
854 default=False,
855 )
855 )
856 coreconfigitem(
856 coreconfigitem(
857 b'experimental',
857 b'experimental',
858 b'bundle2.pushback',
858 b'bundle2.pushback',
859 default=False,
859 default=False,
860 )
860 )
861 coreconfigitem(
861 coreconfigitem(
862 b'experimental',
862 b'experimental',
863 b'bundle2lazylocking',
863 b'bundle2lazylocking',
864 default=False,
864 default=False,
865 )
865 )
866 coreconfigitem(
866 coreconfigitem(
867 b'experimental',
867 b'experimental',
868 b'bundlecomplevel',
868 b'bundlecomplevel',
869 default=None,
869 default=None,
870 )
870 )
871 coreconfigitem(
871 coreconfigitem(
872 b'experimental',
872 b'experimental',
873 b'bundlecomplevel.bzip2',
873 b'bundlecomplevel.bzip2',
874 default=None,
874 default=None,
875 )
875 )
876 coreconfigitem(
876 coreconfigitem(
877 b'experimental',
877 b'experimental',
878 b'bundlecomplevel.gzip',
878 b'bundlecomplevel.gzip',
879 default=None,
879 default=None,
880 )
880 )
881 coreconfigitem(
881 coreconfigitem(
882 b'experimental',
882 b'experimental',
883 b'bundlecomplevel.none',
883 b'bundlecomplevel.none',
884 default=None,
884 default=None,
885 )
885 )
886 coreconfigitem(
886 coreconfigitem(
887 b'experimental',
887 b'experimental',
888 b'bundlecomplevel.zstd',
888 b'bundlecomplevel.zstd',
889 default=None,
889 default=None,
890 )
890 )
891 coreconfigitem(
891 coreconfigitem(
892 b'experimental',
892 b'experimental',
893 b'bundlecompthreads',
893 b'bundlecompthreads',
894 default=None,
894 default=None,
895 )
895 )
896 coreconfigitem(
896 coreconfigitem(
897 b'experimental',
897 b'experimental',
898 b'bundlecompthreads.bzip2',
898 b'bundlecompthreads.bzip2',
899 default=None,
899 default=None,
900 )
900 )
901 coreconfigitem(
901 coreconfigitem(
902 b'experimental',
902 b'experimental',
903 b'bundlecompthreads.gzip',
903 b'bundlecompthreads.gzip',
904 default=None,
904 default=None,
905 )
905 )
906 coreconfigitem(
906 coreconfigitem(
907 b'experimental',
907 b'experimental',
908 b'bundlecompthreads.none',
908 b'bundlecompthreads.none',
909 default=None,
909 default=None,
910 )
910 )
911 coreconfigitem(
911 coreconfigitem(
912 b'experimental',
912 b'experimental',
913 b'bundlecompthreads.zstd',
913 b'bundlecompthreads.zstd',
914 default=None,
914 default=None,
915 )
915 )
916 coreconfigitem(
916 coreconfigitem(
917 b'experimental',
917 b'experimental',
918 b'changegroup3',
918 b'changegroup3',
919 default=False,
919 default=False,
920 )
920 )
921 coreconfigitem(
921 coreconfigitem(
922 b'experimental',
922 b'experimental',
923 b'changegroup4',
923 b'changegroup4',
924 default=False,
924 default=False,
925 )
925 )
926
926
927 # might remove rank configuration once the computation has no impact
927 # might remove rank configuration once the computation has no impact
928 coreconfigitem(
928 coreconfigitem(
929 b'experimental',
929 b'experimental',
930 b'changelog-v2.compute-rank',
930 b'changelog-v2.compute-rank',
931 default=True,
931 default=True,
932 )
932 )
933 coreconfigitem(
933 coreconfigitem(
934 b'experimental',
934 b'experimental',
935 b'cleanup-as-archived',
935 b'cleanup-as-archived',
936 default=False,
936 default=False,
937 )
937 )
938 coreconfigitem(
938 coreconfigitem(
939 b'experimental',
939 b'experimental',
940 b'clientcompressionengines',
940 b'clientcompressionengines',
941 default=list,
941 default=list,
942 )
942 )
943 coreconfigitem(
943 coreconfigitem(
944 b'experimental',
944 b'experimental',
945 b'copytrace',
945 b'copytrace',
946 default=b'on',
946 default=b'on',
947 )
947 )
948 coreconfigitem(
948 coreconfigitem(
949 b'experimental',
949 b'experimental',
950 b'copytrace.movecandidateslimit',
950 b'copytrace.movecandidateslimit',
951 default=100,
951 default=100,
952 )
952 )
953 coreconfigitem(
953 coreconfigitem(
954 b'experimental',
954 b'experimental',
955 b'copytrace.sourcecommitlimit',
955 b'copytrace.sourcecommitlimit',
956 default=100,
956 default=100,
957 )
957 )
958 coreconfigitem(
958 coreconfigitem(
959 b'experimental',
959 b'experimental',
960 b'copies.read-from',
960 b'copies.read-from',
961 default=b"filelog-only",
961 default=b"filelog-only",
962 )
962 )
963 coreconfigitem(
963 coreconfigitem(
964 b'experimental',
964 b'experimental',
965 b'copies.write-to',
965 b'copies.write-to',
966 default=b'filelog-only',
966 default=b'filelog-only',
967 )
967 )
968 coreconfigitem(
968 coreconfigitem(
969 b'experimental',
969 b'experimental',
970 b'crecordtest',
970 b'crecordtest',
971 default=None,
971 default=None,
972 )
972 )
973 coreconfigitem(
973 coreconfigitem(
974 b'experimental',
974 b'experimental',
975 b'directaccess',
975 b'directaccess',
976 default=False,
976 default=False,
977 )
977 )
978 coreconfigitem(
978 coreconfigitem(
979 b'experimental',
979 b'experimental',
980 b'directaccess.revnums',
980 b'directaccess.revnums',
981 default=False,
981 default=False,
982 )
982 )
983 coreconfigitem(
983 coreconfigitem(
984 b'experimental',
984 b'experimental',
985 b'editortmpinhg',
985 b'editortmpinhg',
986 default=False,
986 default=False,
987 )
987 )
988 coreconfigitem(
988 coreconfigitem(
989 b'experimental',
989 b'experimental',
990 b'evolution',
990 b'evolution',
991 default=list,
991 default=list,
992 )
992 )
993 coreconfigitem(
993 coreconfigitem(
994 b'experimental',
994 b'experimental',
995 b'evolution.allowdivergence',
995 b'evolution.allowdivergence',
996 default=False,
996 default=False,
997 alias=[(b'experimental', b'allowdivergence')],
997 alias=[(b'experimental', b'allowdivergence')],
998 )
998 )
999 coreconfigitem(
999 coreconfigitem(
1000 b'experimental',
1000 b'experimental',
1001 b'evolution.allowunstable',
1001 b'evolution.allowunstable',
1002 default=None,
1002 default=None,
1003 )
1003 )
1004 coreconfigitem(
1004 coreconfigitem(
1005 b'experimental',
1005 b'experimental',
1006 b'evolution.createmarkers',
1006 b'evolution.createmarkers',
1007 default=None,
1007 default=None,
1008 )
1008 )
1009 coreconfigitem(
1009 coreconfigitem(
1010 b'experimental',
1010 b'experimental',
1011 b'evolution.effect-flags',
1011 b'evolution.effect-flags',
1012 default=True,
1012 default=True,
1013 alias=[(b'experimental', b'effect-flags')],
1013 alias=[(b'experimental', b'effect-flags')],
1014 )
1014 )
1015 coreconfigitem(
1015 coreconfigitem(
1016 b'experimental',
1016 b'experimental',
1017 b'evolution.exchange',
1017 b'evolution.exchange',
1018 default=None,
1018 default=None,
1019 )
1019 )
1020 coreconfigitem(
1020 coreconfigitem(
1021 b'experimental',
1021 b'experimental',
1022 b'evolution.bundle-obsmarker',
1022 b'evolution.bundle-obsmarker',
1023 default=False,
1023 default=False,
1024 )
1024 )
1025 coreconfigitem(
1025 coreconfigitem(
1026 b'experimental',
1026 b'experimental',
1027 b'evolution.bundle-obsmarker:mandatory',
1027 b'evolution.bundle-obsmarker:mandatory',
1028 default=True,
1028 default=True,
1029 )
1029 )
1030 coreconfigitem(
1030 coreconfigitem(
1031 b'experimental',
1031 b'experimental',
1032 b'log.topo',
1032 b'log.topo',
1033 default=False,
1033 default=False,
1034 )
1034 )
1035 coreconfigitem(
1035 coreconfigitem(
1036 b'experimental',
1036 b'experimental',
1037 b'evolution.report-instabilities',
1037 b'evolution.report-instabilities',
1038 default=True,
1038 default=True,
1039 )
1039 )
1040 coreconfigitem(
1040 coreconfigitem(
1041 b'experimental',
1041 b'experimental',
1042 b'evolution.track-operation',
1042 b'evolution.track-operation',
1043 default=True,
1043 default=True,
1044 )
1044 )
1045 # repo-level config to exclude a revset visibility
1045 # repo-level config to exclude a revset visibility
1046 #
1046 #
1047 # The target use case is to use `share` to expose different subset of the same
1047 # The target use case is to use `share` to expose different subset of the same
1048 # repository, especially server side. See also `server.view`.
1048 # repository, especially server side. See also `server.view`.
1049 coreconfigitem(
1049 coreconfigitem(
1050 b'experimental',
1050 b'experimental',
1051 b'extra-filter-revs',
1051 b'extra-filter-revs',
1052 default=None,
1052 default=None,
1053 )
1053 )
1054 coreconfigitem(
1054 coreconfigitem(
1055 b'experimental',
1055 b'experimental',
1056 b'maxdeltachainspan',
1056 b'maxdeltachainspan',
1057 default=-1,
1057 default=-1,
1058 )
1058 )
1059 # tracks files which were undeleted (merge might delete them but we explicitly
1059 # tracks files which were undeleted (merge might delete them but we explicitly
1060 # kept/undeleted them) and creates new filenodes for them
1060 # kept/undeleted them) and creates new filenodes for them
1061 coreconfigitem(
1061 coreconfigitem(
1062 b'experimental',
1062 b'experimental',
1063 b'merge-track-salvaged',
1063 b'merge-track-salvaged',
1064 default=False,
1064 default=False,
1065 )
1065 )
1066 coreconfigitem(
1066 coreconfigitem(
1067 b'experimental',
1067 b'experimental',
1068 b'mmapindexthreshold',
1068 b'mmapindexthreshold',
1069 default=None,
1069 default=None,
1070 )
1070 )
1071 coreconfigitem(
1071 coreconfigitem(
1072 b'experimental',
1072 b'experimental',
1073 b'narrow',
1073 b'narrow',
1074 default=False,
1074 default=False,
1075 )
1075 )
1076 coreconfigitem(
1076 coreconfigitem(
1077 b'experimental',
1077 b'experimental',
1078 b'nonnormalparanoidcheck',
1078 b'nonnormalparanoidcheck',
1079 default=False,
1079 default=False,
1080 )
1080 )
1081 coreconfigitem(
1081 coreconfigitem(
1082 b'experimental',
1082 b'experimental',
1083 b'exportableenviron',
1083 b'exportableenviron',
1084 default=list,
1084 default=list,
1085 )
1085 )
1086 coreconfigitem(
1086 coreconfigitem(
1087 b'experimental',
1087 b'experimental',
1088 b'extendedheader.index',
1088 b'extendedheader.index',
1089 default=None,
1089 default=None,
1090 )
1090 )
1091 coreconfigitem(
1091 coreconfigitem(
1092 b'experimental',
1092 b'experimental',
1093 b'extendedheader.similarity',
1093 b'extendedheader.similarity',
1094 default=False,
1094 default=False,
1095 )
1095 )
1096 coreconfigitem(
1096 coreconfigitem(
1097 b'experimental',
1097 b'experimental',
1098 b'graphshorten',
1098 b'graphshorten',
1099 default=False,
1099 default=False,
1100 )
1100 )
1101 coreconfigitem(
1101 coreconfigitem(
1102 b'experimental',
1102 b'experimental',
1103 b'graphstyle.parent',
1103 b'graphstyle.parent',
1104 default=dynamicdefault,
1104 default=dynamicdefault,
1105 )
1105 )
1106 coreconfigitem(
1106 coreconfigitem(
1107 b'experimental',
1107 b'experimental',
1108 b'graphstyle.missing',
1108 b'graphstyle.missing',
1109 default=dynamicdefault,
1109 default=dynamicdefault,
1110 )
1110 )
1111 coreconfigitem(
1111 coreconfigitem(
1112 b'experimental',
1112 b'experimental',
1113 b'graphstyle.grandparent',
1113 b'graphstyle.grandparent',
1114 default=dynamicdefault,
1114 default=dynamicdefault,
1115 )
1115 )
1116 coreconfigitem(
1116 coreconfigitem(
1117 b'experimental',
1117 b'experimental',
1118 b'hook-track-tags',
1118 b'hook-track-tags',
1119 default=False,
1119 default=False,
1120 )
1120 )
1121 coreconfigitem(
1121 coreconfigitem(
1122 b'experimental',
1122 b'experimental',
1123 b'httppostargs',
1123 b'httppostargs',
1124 default=False,
1124 default=False,
1125 )
1125 )
1126 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1126 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1127 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1127 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1128
1128
1129 coreconfigitem(
1129 coreconfigitem(
1130 b'experimental',
1130 b'experimental',
1131 b'obsmarkers-exchange-debug',
1131 b'obsmarkers-exchange-debug',
1132 default=False,
1132 default=False,
1133 )
1133 )
1134 coreconfigitem(
1134 coreconfigitem(
1135 b'experimental',
1135 b'experimental',
1136 b'remotenames',
1136 b'remotenames',
1137 default=False,
1137 default=False,
1138 )
1138 )
1139 coreconfigitem(
1139 coreconfigitem(
1140 b'experimental',
1140 b'experimental',
1141 b'removeemptydirs',
1141 b'removeemptydirs',
1142 default=True,
1142 default=True,
1143 )
1143 )
1144 coreconfigitem(
1144 coreconfigitem(
1145 b'experimental',
1145 b'experimental',
1146 b'revert.interactive.select-to-keep',
1146 b'revert.interactive.select-to-keep',
1147 default=False,
1147 default=False,
1148 )
1148 )
1149 coreconfigitem(
1149 coreconfigitem(
1150 b'experimental',
1150 b'experimental',
1151 b'revisions.prefixhexnode',
1151 b'revisions.prefixhexnode',
1152 default=False,
1152 default=False,
1153 )
1153 )
1154 # "out of experimental" todo list.
1154 # "out of experimental" todo list.
1155 #
1155 #
1156 # * include management of a persistent nodemap in the main docket
1156 # * include management of a persistent nodemap in the main docket
1157 # * enforce a "no-truncate" policy for mmap safety
1157 # * enforce a "no-truncate" policy for mmap safety
1158 # - for censoring operation
1158 # - for censoring operation
1159 # - for stripping operation
1159 # - for stripping operation
1160 # - for rollback operation
1160 # - for rollback operation
1161 # * proper streaming (race free) of the docket file
1161 # * proper streaming (race free) of the docket file
1162 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1162 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1163 # * Exchange-wise, we will also need to do something more efficient than
1163 # * Exchange-wise, we will also need to do something more efficient than
1164 # keeping references to the affected revlogs, especially memory-wise when
1164 # keeping references to the affected revlogs, especially memory-wise when
1165 # rewriting sidedata.
1165 # rewriting sidedata.
1166 # * introduce a proper solution to reduce the number of filelog related files.
1166 # * introduce a proper solution to reduce the number of filelog related files.
1167 # * use caching for reading sidedata (similar to what we do for data).
1167 # * use caching for reading sidedata (similar to what we do for data).
1168 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1168 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1169 # * Improvement to consider
1169 # * Improvement to consider
1170 # - avoid compression header in chunk using the default compression?
1170 # - avoid compression header in chunk using the default compression?
1171 # - forbid "inline" compression mode entirely?
1171 # - forbid "inline" compression mode entirely?
1172 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1172 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1173 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1173 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1174 # - keep track of chain base or size (probably not that useful anymore)
1174 # - keep track of chain base or size (probably not that useful anymore)
1175 coreconfigitem(
1175 coreconfigitem(
1176 b'experimental',
1176 b'experimental',
1177 b'revlogv2',
1177 b'revlogv2',
1178 default=None,
1178 default=None,
1179 )
1179 )
1180 coreconfigitem(
1180 coreconfigitem(
1181 b'experimental',
1181 b'experimental',
1182 b'revisions.disambiguatewithin',
1182 b'revisions.disambiguatewithin',
1183 default=None,
1183 default=None,
1184 )
1184 )
1185 coreconfigitem(
1185 coreconfigitem(
1186 b'experimental',
1186 b'experimental',
1187 b'rust.index',
1187 b'rust.index',
1188 default=False,
1188 default=False,
1189 )
1189 )
1190 coreconfigitem(
1190 coreconfigitem(
1191 b'experimental',
1191 b'experimental',
1192 b'server.filesdata.recommended-batch-size',
1192 b'server.filesdata.recommended-batch-size',
1193 default=50000,
1193 default=50000,
1194 )
1194 )
1195 coreconfigitem(
1195 coreconfigitem(
1196 b'experimental',
1196 b'experimental',
1197 b'server.manifestdata.recommended-batch-size',
1197 b'server.manifestdata.recommended-batch-size',
1198 default=100000,
1198 default=100000,
1199 )
1199 )
1200 coreconfigitem(
1200 coreconfigitem(
1201 b'experimental',
1201 b'experimental',
1202 b'server.stream-narrow-clones',
1202 b'server.stream-narrow-clones',
1203 default=False,
1203 default=False,
1204 )
1204 )
1205 coreconfigitem(
1205 coreconfigitem(
1206 b'experimental',
1206 b'experimental',
1207 b'single-head-per-branch',
1207 b'single-head-per-branch',
1208 default=False,
1208 default=False,
1209 )
1209 )
1210 coreconfigitem(
1210 coreconfigitem(
1211 b'experimental',
1211 b'experimental',
1212 b'single-head-per-branch:account-closed-heads',
1212 b'single-head-per-branch:account-closed-heads',
1213 default=False,
1213 default=False,
1214 )
1214 )
1215 coreconfigitem(
1215 coreconfigitem(
1216 b'experimental',
1216 b'experimental',
1217 b'single-head-per-branch:public-changes-only',
1217 b'single-head-per-branch:public-changes-only',
1218 default=False,
1218 default=False,
1219 )
1219 )
1220 coreconfigitem(
1220 coreconfigitem(
1221 b'experimental',
1221 b'experimental',
1222 b'sparse-read',
1222 b'sparse-read',
1223 default=False,
1223 default=False,
1224 )
1224 )
1225 coreconfigitem(
1225 coreconfigitem(
1226 b'experimental',
1226 b'experimental',
1227 b'sparse-read.density-threshold',
1227 b'sparse-read.density-threshold',
1228 default=0.50,
1228 default=0.50,
1229 )
1229 )
1230 coreconfigitem(
1230 coreconfigitem(
1231 b'experimental',
1231 b'experimental',
1232 b'sparse-read.min-gap-size',
1232 b'sparse-read.min-gap-size',
1233 default=b'65K',
1233 default=b'65K',
1234 )
1234 )
1235 coreconfigitem(
1235 coreconfigitem(
1236 b'experimental',
1236 b'experimental',
1237 b'treemanifest',
1237 b'treemanifest',
1238 default=False,
1238 default=False,
1239 )
1239 )
1240 coreconfigitem(
1240 coreconfigitem(
1241 b'experimental',
1241 b'experimental',
1242 b'update.atomic-file',
1242 b'update.atomic-file',
1243 default=False,
1243 default=False,
1244 )
1244 )
1245 coreconfigitem(
1245 coreconfigitem(
1246 b'experimental',
1246 b'experimental',
1247 b'web.full-garbage-collection-rate',
1247 b'web.full-garbage-collection-rate',
1248 default=1, # still forcing a full collection on each request
1248 default=1, # still forcing a full collection on each request
1249 )
1249 )
1250 coreconfigitem(
1250 coreconfigitem(
1251 b'experimental',
1251 b'experimental',
1252 b'worker.wdir-get-thread-safe',
1252 b'worker.wdir-get-thread-safe',
1253 default=False,
1253 default=False,
1254 )
1254 )
1255 coreconfigitem(
1255 coreconfigitem(
1256 b'experimental',
1256 b'experimental',
1257 b'worker.repository-upgrade',
1257 b'worker.repository-upgrade',
1258 default=False,
1258 default=False,
1259 )
1259 )
1260 coreconfigitem(
1260 coreconfigitem(
1261 b'experimental',
1261 b'experimental',
1262 b'xdiff',
1262 b'xdiff',
1263 default=False,
1263 default=False,
1264 )
1264 )
1265 coreconfigitem(
1265 coreconfigitem(
1266 b'extensions',
1266 b'extensions',
1267 b'[^:]*',
1267 b'[^:]*',
1268 default=None,
1268 default=None,
1269 generic=True,
1269 generic=True,
1270 )
1270 )
1271 coreconfigitem(
1271 coreconfigitem(
1272 b'extensions',
1272 b'extensions',
1273 b'[^:]*:required',
1273 b'[^:]*:required',
1274 default=False,
1274 default=False,
1275 generic=True,
1275 generic=True,
1276 )
1276 )
1277 coreconfigitem(
1277 coreconfigitem(
1278 b'extdata',
1278 b'extdata',
1279 b'.*',
1279 b'.*',
1280 default=None,
1280 default=None,
1281 generic=True,
1281 generic=True,
1282 )
1282 )
1283 coreconfigitem(
1283 coreconfigitem(
1284 b'format',
1284 b'format',
1285 b'bookmarks-in-store',
1285 b'bookmarks-in-store',
1286 default=False,
1286 default=False,
1287 )
1287 )
1288 coreconfigitem(
1288 coreconfigitem(
1289 b'format',
1289 b'format',
1290 b'chunkcachesize',
1290 b'chunkcachesize',
1291 default=None,
1291 default=None,
1292 experimental=True,
1292 experimental=True,
1293 )
1293 )
1294 coreconfigitem(
1294 coreconfigitem(
1295 # Enable this dirstate format *when creating a new repository*.
1295 # Enable this dirstate format *when creating a new repository*.
1296 # Which format to use for existing repos is controlled by .hg/requires
1296 # Which format to use for existing repos is controlled by .hg/requires
1297 b'format',
1297 b'format',
1298 b'use-dirstate-v2',
1298 b'use-dirstate-v2',
1299 default=False,
1299 default=False,
1300 experimental=True,
1300 experimental=True,
1301 alias=[(b'format', b'exp-rc-dirstate-v2')],
1301 alias=[(b'format', b'exp-rc-dirstate-v2')],
1302 )
1302 )
1303 coreconfigitem(
1303 coreconfigitem(
1304 b'format',
1304 b'format',
1305 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories',
1305 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories',
1306 default=False,
1306 default=False,
1307 experimental=True,
1307 experimental=True,
1308 )
1308 )
1309 coreconfigitem(
1309 coreconfigitem(
1310 b'format',
1310 b'format',
1311 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet',
1311 b'use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet',
1312 default=False,
1312 default=False,
1313 experimental=True,
1313 experimental=True,
1314 )
1314 )
1315 coreconfigitem(
1315 coreconfigitem(
1316 b'format',
1316 b'format',
1317 b'use-dirstate-tracked-hint',
1317 b'use-dirstate-tracked-hint',
1318 default=False,
1318 default=False,
1319 experimental=True,
1319 experimental=True,
1320 )
1320 )
1321 coreconfigitem(
1321 coreconfigitem(
1322 b'format',
1322 b'format',
1323 b'use-dirstate-tracked-hint.version',
1323 b'use-dirstate-tracked-hint.version',
1324 default=1,
1324 default=1,
1325 experimental=True,
1325 experimental=True,
1326 )
1326 )
1327 coreconfigitem(
1327 coreconfigitem(
1328 b'format',
1328 b'format',
1329 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories',
1329 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories',
1330 default=False,
1330 default=False,
1331 experimental=True,
1331 experimental=True,
1332 )
1332 )
1333 coreconfigitem(
1333 coreconfigitem(
1334 b'format',
1334 b'format',
1335 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet',
1335 b'use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet',
1336 default=False,
1336 default=False,
1337 experimental=True,
1337 experimental=True,
1338 )
1338 )
1339 coreconfigitem(
1339 coreconfigitem(
1340 b'format',
1340 b'format',
1341 b'dotencode',
1341 b'dotencode',
1342 default=True,
1342 default=True,
1343 )
1343 )
1344 coreconfigitem(
1344 coreconfigitem(
1345 b'format',
1345 b'format',
1346 b'generaldelta',
1346 b'generaldelta',
1347 default=False,
1347 default=False,
1348 experimental=True,
1348 experimental=True,
1349 )
1349 )
1350 coreconfigitem(
1350 coreconfigitem(
1351 b'format',
1351 b'format',
1352 b'manifestcachesize',
1352 b'manifestcachesize',
1353 default=None,
1353 default=None,
1354 experimental=True,
1354 experimental=True,
1355 )
1355 )
1356 coreconfigitem(
1356 coreconfigitem(
1357 b'format',
1357 b'format',
1358 b'maxchainlen',
1358 b'maxchainlen',
1359 default=dynamicdefault,
1359 default=dynamicdefault,
1360 experimental=True,
1360 experimental=True,
1361 )
1361 )
1362 coreconfigitem(
1362 coreconfigitem(
1363 b'format',
1363 b'format',
1364 b'obsstore-version',
1364 b'obsstore-version',
1365 default=None,
1365 default=None,
1366 )
1366 )
1367 coreconfigitem(
1367 coreconfigitem(
1368 b'format',
1368 b'format',
1369 b'sparse-revlog',
1369 b'sparse-revlog',
1370 default=True,
1370 default=True,
1371 )
1371 )
1372 coreconfigitem(
1372 coreconfigitem(
1373 b'format',
1373 b'format',
1374 b'revlog-compression',
1374 b'revlog-compression',
1375 default=lambda: [b'zstd', b'zlib'],
1375 default=lambda: [b'zstd', b'zlib'],
1376 alias=[(b'experimental', b'format.compression')],
1376 alias=[(b'experimental', b'format.compression')],
1377 )
1377 )
1378 # Experimental TODOs:
1378 # Experimental TODOs:
1379 #
1379 #
1380 # * Same as for revlogv2 (but for the reduction of the number of files)
1380 # * Same as for revlogv2 (but for the reduction of the number of files)
1381 # * Actually computing the rank of changesets
1381 # * Actually computing the rank of changesets
1382 # * Improvement to investigate
1382 # * Improvement to investigate
1383 # - storing .hgtags fnode
1383 # - storing .hgtags fnode
1384 # - storing branch related identifier
1384 # - storing branch related identifier
1385
1385
1386 coreconfigitem(
1386 coreconfigitem(
1387 b'format',
1387 b'format',
1388 b'exp-use-changelog-v2',
1388 b'exp-use-changelog-v2',
1389 default=None,
1389 default=None,
1390 experimental=True,
1390 experimental=True,
1391 )
1391 )
1392 coreconfigitem(
1392 coreconfigitem(
1393 b'format',
1393 b'format',
1394 b'usefncache',
1394 b'usefncache',
1395 default=True,
1395 default=True,
1396 )
1396 )
1397 coreconfigitem(
1397 coreconfigitem(
1398 b'format',
1398 b'format',
1399 b'usegeneraldelta',
1399 b'usegeneraldelta',
1400 default=True,
1400 default=True,
1401 )
1401 )
1402 coreconfigitem(
1402 coreconfigitem(
1403 b'format',
1403 b'format',
1404 b'usestore',
1404 b'usestore',
1405 default=True,
1405 default=True,
1406 )
1406 )
1407
1407
1408
1408
1409 def _persistent_nodemap_default():
1409 def _persistent_nodemap_default():
1410 """compute `use-persistent-nodemap` default value
1410 """compute `use-persistent-nodemap` default value
1411
1411
1412 The feature is disabled unless a fast implementation is available.
1412 The feature is disabled unless a fast implementation is available.
1413 """
1413 """
1414 from . import policy
1414 from . import policy
1415
1415
1416 return policy.importrust('revlog') is not None
1416 return policy.importrust('revlog') is not None
1417
1417
1418
1418
1419 coreconfigitem(
1419 coreconfigitem(
1420 b'format',
1420 b'format',
1421 b'use-persistent-nodemap',
1421 b'use-persistent-nodemap',
1422 default=_persistent_nodemap_default,
1422 default=_persistent_nodemap_default,
1423 )
1423 )
1424 coreconfigitem(
1424 coreconfigitem(
1425 b'format',
1425 b'format',
1426 b'exp-use-copies-side-data-changeset',
1426 b'exp-use-copies-side-data-changeset',
1427 default=False,
1427 default=False,
1428 experimental=True,
1428 experimental=True,
1429 )
1429 )
1430 coreconfigitem(
1430 coreconfigitem(
1431 b'format',
1431 b'format',
1432 b'use-share-safe',
1432 b'use-share-safe',
1433 default=True,
1433 default=True,
1434 )
1434 )
1435 coreconfigitem(
1435 coreconfigitem(
1436 b'format',
1436 b'format',
1437 b'use-share-safe.automatic-upgrade-of-mismatching-repositories',
1437 b'use-share-safe.automatic-upgrade-of-mismatching-repositories',
1438 default=False,
1438 default=False,
1439 experimental=True,
1439 experimental=True,
1440 )
1440 )
1441 coreconfigitem(
1441 coreconfigitem(
1442 b'format',
1442 b'format',
1443 b'use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet',
1443 b'use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet',
1444 default=False,
1444 default=False,
1445 experimental=True,
1445 experimental=True,
1446 )
1446 )
1447
1447
1448 # Moving this on by default means we are confident about the scaling of phases.
1448 # Moving this on by default means we are confident about the scaling of phases.
1449 # This is not garanteed to be the case at the time this message is written.
1449 # This is not garanteed to be the case at the time this message is written.
1450 coreconfigitem(
1450 coreconfigitem(
1451 b'format',
1451 b'format',
1452 b'use-internal-phase',
1452 b'use-internal-phase',
1453 default=False,
1453 default=False,
1454 experimental=True,
1454 experimental=True,
1455 )
1455 )
1456 # The interaction between the archived phase and obsolescence markers needs to
1456 # The interaction between the archived phase and obsolescence markers needs to
1457 # be sorted out before wider usage of this are to be considered.
1457 # be sorted out before wider usage of this are to be considered.
1458 #
1458 #
1459 # At the time this message is written, behavior when archiving obsolete
1459 # At the time this message is written, behavior when archiving obsolete
1460 # changeset differ significantly from stripping. As part of stripping, we also
1460 # changeset differ significantly from stripping. As part of stripping, we also
1461 # remove the obsolescence marker associated to the stripped changesets,
1461 # remove the obsolescence marker associated to the stripped changesets,
1462 # revealing the precedecessors changesets when applicable. When archiving, we
1462 # revealing the precedecessors changesets when applicable. When archiving, we
1463 # don't touch the obsolescence markers, keeping everything hidden. This can
1463 # don't touch the obsolescence markers, keeping everything hidden. This can
1464 # result in quite confusing situation for people combining exchanging draft
1464 # result in quite confusing situation for people combining exchanging draft
1465 # with the archived phases. As some markers needed by others may be skipped
1465 # with the archived phases. As some markers needed by others may be skipped
1466 # during exchange.
1466 # during exchange.
1467 coreconfigitem(
1467 coreconfigitem(
1468 b'format',
1468 b'format',
1469 b'exp-archived-phase',
1469 b'exp-archived-phase',
1470 default=False,
1470 default=False,
1471 experimental=True,
1471 experimental=True,
1472 )
1472 )
1473 coreconfigitem(
1473 coreconfigitem(
1474 b'shelve',
1474 b'shelve',
1475 b'store',
1475 b'store',
1476 default=b'internal',
1476 default=b'internal',
1477 experimental=True,
1477 experimental=True,
1478 )
1478 )
1479 coreconfigitem(
1479 coreconfigitem(
1480 b'fsmonitor',
1480 b'fsmonitor',
1481 b'warn_when_unused',
1481 b'warn_when_unused',
1482 default=True,
1482 default=True,
1483 )
1483 )
1484 coreconfigitem(
1484 coreconfigitem(
1485 b'fsmonitor',
1485 b'fsmonitor',
1486 b'warn_update_file_count',
1486 b'warn_update_file_count',
1487 default=50000,
1487 default=50000,
1488 )
1488 )
1489 coreconfigitem(
1489 coreconfigitem(
1490 b'fsmonitor',
1490 b'fsmonitor',
1491 b'warn_update_file_count_rust',
1491 b'warn_update_file_count_rust',
1492 default=400000,
1492 default=400000,
1493 )
1493 )
1494 coreconfigitem(
1494 coreconfigitem(
1495 b'help',
1495 b'help',
1496 br'hidden-command\..*',
1496 br'hidden-command\..*',
1497 default=False,
1497 default=False,
1498 generic=True,
1498 generic=True,
1499 )
1499 )
1500 coreconfigitem(
1500 coreconfigitem(
1501 b'help',
1501 b'help',
1502 br'hidden-topic\..*',
1502 br'hidden-topic\..*',
1503 default=False,
1503 default=False,
1504 generic=True,
1504 generic=True,
1505 )
1505 )
1506 coreconfigitem(
1506 coreconfigitem(
1507 b'hooks',
1507 b'hooks',
1508 b'[^:]*',
1508 b'[^:]*',
1509 default=dynamicdefault,
1509 default=dynamicdefault,
1510 generic=True,
1510 generic=True,
1511 )
1511 )
1512 coreconfigitem(
1512 coreconfigitem(
1513 b'hooks',
1513 b'hooks',
1514 b'.*:run-with-plain',
1514 b'.*:run-with-plain',
1515 default=True,
1515 default=True,
1516 generic=True,
1516 generic=True,
1517 )
1517 )
1518 coreconfigitem(
1518 coreconfigitem(
1519 b'hgweb-paths',
1519 b'hgweb-paths',
1520 b'.*',
1520 b'.*',
1521 default=list,
1521 default=list,
1522 generic=True,
1522 generic=True,
1523 )
1523 )
1524 coreconfigitem(
1524 coreconfigitem(
1525 b'hostfingerprints',
1525 b'hostfingerprints',
1526 b'.*',
1526 b'.*',
1527 default=list,
1527 default=list,
1528 generic=True,
1528 generic=True,
1529 )
1529 )
1530 coreconfigitem(
1530 coreconfigitem(
1531 b'hostsecurity',
1531 b'hostsecurity',
1532 b'ciphers',
1532 b'ciphers',
1533 default=None,
1533 default=None,
1534 )
1534 )
1535 coreconfigitem(
1535 coreconfigitem(
1536 b'hostsecurity',
1536 b'hostsecurity',
1537 b'minimumprotocol',
1537 b'minimumprotocol',
1538 default=dynamicdefault,
1538 default=dynamicdefault,
1539 )
1539 )
1540 coreconfigitem(
1540 coreconfigitem(
1541 b'hostsecurity',
1541 b'hostsecurity',
1542 b'.*:minimumprotocol$',
1542 b'.*:minimumprotocol$',
1543 default=dynamicdefault,
1543 default=dynamicdefault,
1544 generic=True,
1544 generic=True,
1545 )
1545 )
1546 coreconfigitem(
1546 coreconfigitem(
1547 b'hostsecurity',
1547 b'hostsecurity',
1548 b'.*:ciphers$',
1548 b'.*:ciphers$',
1549 default=dynamicdefault,
1549 default=dynamicdefault,
1550 generic=True,
1550 generic=True,
1551 )
1551 )
1552 coreconfigitem(
1552 coreconfigitem(
1553 b'hostsecurity',
1553 b'hostsecurity',
1554 b'.*:fingerprints$',
1554 b'.*:fingerprints$',
1555 default=list,
1555 default=list,
1556 generic=True,
1556 generic=True,
1557 )
1557 )
1558 coreconfigitem(
1558 coreconfigitem(
1559 b'hostsecurity',
1559 b'hostsecurity',
1560 b'.*:verifycertsfile$',
1560 b'.*:verifycertsfile$',
1561 default=None,
1561 default=None,
1562 generic=True,
1562 generic=True,
1563 )
1563 )
1564
1564
1565 coreconfigitem(
1565 coreconfigitem(
1566 b'http_proxy',
1566 b'http_proxy',
1567 b'always',
1567 b'always',
1568 default=False,
1568 default=False,
1569 )
1569 )
1570 coreconfigitem(
1570 coreconfigitem(
1571 b'http_proxy',
1571 b'http_proxy',
1572 b'host',
1572 b'host',
1573 default=None,
1573 default=None,
1574 )
1574 )
1575 coreconfigitem(
1575 coreconfigitem(
1576 b'http_proxy',
1576 b'http_proxy',
1577 b'no',
1577 b'no',
1578 default=list,
1578 default=list,
1579 )
1579 )
1580 coreconfigitem(
1580 coreconfigitem(
1581 b'http_proxy',
1581 b'http_proxy',
1582 b'passwd',
1582 b'passwd',
1583 default=None,
1583 default=None,
1584 )
1584 )
1585 coreconfigitem(
1585 coreconfigitem(
1586 b'http_proxy',
1586 b'http_proxy',
1587 b'user',
1587 b'user',
1588 default=None,
1588 default=None,
1589 )
1589 )
1590
1590
1591 coreconfigitem(
1591 coreconfigitem(
1592 b'http',
1592 b'http',
1593 b'timeout',
1593 b'timeout',
1594 default=None,
1594 default=None,
1595 )
1595 )
1596
1596
1597 coreconfigitem(
1597 coreconfigitem(
1598 b'logtoprocess',
1598 b'logtoprocess',
1599 b'commandexception',
1599 b'commandexception',
1600 default=None,
1600 default=None,
1601 )
1601 )
1602 coreconfigitem(
1602 coreconfigitem(
1603 b'logtoprocess',
1603 b'logtoprocess',
1604 b'commandfinish',
1604 b'commandfinish',
1605 default=None,
1605 default=None,
1606 )
1606 )
1607 coreconfigitem(
1607 coreconfigitem(
1608 b'logtoprocess',
1608 b'logtoprocess',
1609 b'command',
1609 b'command',
1610 default=None,
1610 default=None,
1611 )
1611 )
1612 coreconfigitem(
1612 coreconfigitem(
1613 b'logtoprocess',
1613 b'logtoprocess',
1614 b'develwarn',
1614 b'develwarn',
1615 default=None,
1615 default=None,
1616 )
1616 )
1617 coreconfigitem(
1617 coreconfigitem(
1618 b'logtoprocess',
1618 b'logtoprocess',
1619 b'uiblocked',
1619 b'uiblocked',
1620 default=None,
1620 default=None,
1621 )
1621 )
1622 coreconfigitem(
1622 coreconfigitem(
1623 b'merge',
1623 b'merge',
1624 b'checkunknown',
1624 b'checkunknown',
1625 default=b'abort',
1625 default=b'abort',
1626 )
1626 )
1627 coreconfigitem(
1627 coreconfigitem(
1628 b'merge',
1628 b'merge',
1629 b'checkignored',
1629 b'checkignored',
1630 default=b'abort',
1630 default=b'abort',
1631 )
1631 )
1632 coreconfigitem(
1632 coreconfigitem(
1633 b'experimental',
1633 b'experimental',
1634 b'merge.checkpathconflicts',
1634 b'merge.checkpathconflicts',
1635 default=False,
1635 default=False,
1636 )
1636 )
1637 coreconfigitem(
1637 coreconfigitem(
1638 b'merge',
1638 b'merge',
1639 b'followcopies',
1639 b'followcopies',
1640 default=True,
1640 default=True,
1641 )
1641 )
1642 coreconfigitem(
1642 coreconfigitem(
1643 b'merge',
1643 b'merge',
1644 b'on-failure',
1644 b'on-failure',
1645 default=b'continue',
1645 default=b'continue',
1646 )
1646 )
1647 coreconfigitem(
1647 coreconfigitem(
1648 b'merge',
1648 b'merge',
1649 b'preferancestor',
1649 b'preferancestor',
1650 default=lambda: [b'*'],
1650 default=lambda: [b'*'],
1651 experimental=True,
1651 experimental=True,
1652 )
1652 )
1653 coreconfigitem(
1653 coreconfigitem(
1654 b'merge',
1654 b'merge',
1655 b'strict-capability-check',
1655 b'strict-capability-check',
1656 default=False,
1656 default=False,
1657 )
1657 )
1658 coreconfigitem(
1658 coreconfigitem(
1659 b'merge',
1659 b'merge',
1660 b'disable-partial-tools',
1660 b'disable-partial-tools',
1661 default=False,
1661 default=False,
1662 experimental=True,
1662 experimental=True,
1663 )
1663 )
1664 coreconfigitem(
1664 coreconfigitem(
1665 b'partial-merge-tools',
1665 b'partial-merge-tools',
1666 b'.*',
1666 b'.*',
1667 default=None,
1667 default=None,
1668 generic=True,
1668 generic=True,
1669 experimental=True,
1669 experimental=True,
1670 )
1670 )
1671 coreconfigitem(
1671 coreconfigitem(
1672 b'partial-merge-tools',
1672 b'partial-merge-tools',
1673 br'.*\.patterns',
1673 br'.*\.patterns',
1674 default=dynamicdefault,
1674 default=dynamicdefault,
1675 generic=True,
1675 generic=True,
1676 priority=-1,
1676 priority=-1,
1677 experimental=True,
1677 experimental=True,
1678 )
1678 )
1679 coreconfigitem(
1679 coreconfigitem(
1680 b'partial-merge-tools',
1680 b'partial-merge-tools',
1681 br'.*\.executable$',
1681 br'.*\.executable$',
1682 default=dynamicdefault,
1682 default=dynamicdefault,
1683 generic=True,
1683 generic=True,
1684 priority=-1,
1684 priority=-1,
1685 experimental=True,
1685 experimental=True,
1686 )
1686 )
1687 coreconfigitem(
1687 coreconfigitem(
1688 b'partial-merge-tools',
1688 b'partial-merge-tools',
1689 br'.*\.order',
1689 br'.*\.order',
1690 default=0,
1690 default=0,
1691 generic=True,
1691 generic=True,
1692 priority=-1,
1692 priority=-1,
1693 experimental=True,
1693 experimental=True,
1694 )
1694 )
1695 coreconfigitem(
1695 coreconfigitem(
1696 b'partial-merge-tools',
1696 b'partial-merge-tools',
1697 br'.*\.args',
1697 br'.*\.args',
1698 default=b"$local $base $other",
1698 default=b"$local $base $other",
1699 generic=True,
1699 generic=True,
1700 priority=-1,
1700 priority=-1,
1701 experimental=True,
1701 experimental=True,
1702 )
1702 )
1703 coreconfigitem(
1703 coreconfigitem(
1704 b'partial-merge-tools',
1704 b'partial-merge-tools',
1705 br'.*\.disable',
1705 br'.*\.disable',
1706 default=False,
1706 default=False,
1707 generic=True,
1707 generic=True,
1708 priority=-1,
1708 priority=-1,
1709 experimental=True,
1709 experimental=True,
1710 )
1710 )
1711 coreconfigitem(
1711 coreconfigitem(
1712 b'merge-tools',
1712 b'merge-tools',
1713 b'.*',
1713 b'.*',
1714 default=None,
1714 default=None,
1715 generic=True,
1715 generic=True,
1716 )
1716 )
1717 coreconfigitem(
1717 coreconfigitem(
1718 b'merge-tools',
1718 b'merge-tools',
1719 br'.*\.args$',
1719 br'.*\.args$',
1720 default=b"$local $base $other",
1720 default=b"$local $base $other",
1721 generic=True,
1721 generic=True,
1722 priority=-1,
1722 priority=-1,
1723 )
1723 )
1724 coreconfigitem(
1724 coreconfigitem(
1725 b'merge-tools',
1725 b'merge-tools',
1726 br'.*\.binary$',
1726 br'.*\.binary$',
1727 default=False,
1727 default=False,
1728 generic=True,
1728 generic=True,
1729 priority=-1,
1729 priority=-1,
1730 )
1730 )
1731 coreconfigitem(
1731 coreconfigitem(
1732 b'merge-tools',
1732 b'merge-tools',
1733 br'.*\.check$',
1733 br'.*\.check$',
1734 default=list,
1734 default=list,
1735 generic=True,
1735 generic=True,
1736 priority=-1,
1736 priority=-1,
1737 )
1737 )
1738 coreconfigitem(
1738 coreconfigitem(
1739 b'merge-tools',
1739 b'merge-tools',
1740 br'.*\.checkchanged$',
1740 br'.*\.checkchanged$',
1741 default=False,
1741 default=False,
1742 generic=True,
1742 generic=True,
1743 priority=-1,
1743 priority=-1,
1744 )
1744 )
1745 coreconfigitem(
1745 coreconfigitem(
1746 b'merge-tools',
1746 b'merge-tools',
1747 br'.*\.executable$',
1747 br'.*\.executable$',
1748 default=dynamicdefault,
1748 default=dynamicdefault,
1749 generic=True,
1749 generic=True,
1750 priority=-1,
1750 priority=-1,
1751 )
1751 )
1752 coreconfigitem(
1752 coreconfigitem(
1753 b'merge-tools',
1753 b'merge-tools',
1754 br'.*\.fixeol$',
1754 br'.*\.fixeol$',
1755 default=False,
1755 default=False,
1756 generic=True,
1756 generic=True,
1757 priority=-1,
1757 priority=-1,
1758 )
1758 )
1759 coreconfigitem(
1759 coreconfigitem(
1760 b'merge-tools',
1760 b'merge-tools',
1761 br'.*\.gui$',
1761 br'.*\.gui$',
1762 default=False,
1762 default=False,
1763 generic=True,
1763 generic=True,
1764 priority=-1,
1764 priority=-1,
1765 )
1765 )
1766 coreconfigitem(
1766 coreconfigitem(
1767 b'merge-tools',
1767 b'merge-tools',
1768 br'.*\.mergemarkers$',
1768 br'.*\.mergemarkers$',
1769 default=b'basic',
1769 default=b'basic',
1770 generic=True,
1770 generic=True,
1771 priority=-1,
1771 priority=-1,
1772 )
1772 )
1773 coreconfigitem(
1773 coreconfigitem(
1774 b'merge-tools',
1774 b'merge-tools',
1775 br'.*\.mergemarkertemplate$',
1775 br'.*\.mergemarkertemplate$',
1776 default=dynamicdefault, # take from command-templates.mergemarker
1776 default=dynamicdefault, # take from command-templates.mergemarker
1777 generic=True,
1777 generic=True,
1778 priority=-1,
1778 priority=-1,
1779 )
1779 )
1780 coreconfigitem(
1780 coreconfigitem(
1781 b'merge-tools',
1781 b'merge-tools',
1782 br'.*\.priority$',
1782 br'.*\.priority$',
1783 default=0,
1783 default=0,
1784 generic=True,
1784 generic=True,
1785 priority=-1,
1785 priority=-1,
1786 )
1786 )
1787 coreconfigitem(
1787 coreconfigitem(
1788 b'merge-tools',
1788 b'merge-tools',
1789 br'.*\.premerge$',
1789 br'.*\.premerge$',
1790 default=dynamicdefault,
1790 default=dynamicdefault,
1791 generic=True,
1791 generic=True,
1792 priority=-1,
1792 priority=-1,
1793 )
1793 )
1794 coreconfigitem(
1794 coreconfigitem(
1795 b'merge-tools',
1795 b'merge-tools',
1796 br'.*\.regappend$',
1796 br'.*\.regappend$',
1797 default=b"",
1797 default=b"",
1798 generic=True,
1798 generic=True,
1799 priority=-1,
1799 priority=-1,
1800 )
1800 )
1801 coreconfigitem(
1801 coreconfigitem(
1802 b'merge-tools',
1802 b'merge-tools',
1803 br'.*\.symlink$',
1803 br'.*\.symlink$',
1804 default=False,
1804 default=False,
1805 generic=True,
1805 generic=True,
1806 priority=-1,
1806 priority=-1,
1807 )
1807 )
1808 coreconfigitem(
1808 coreconfigitem(
1809 b'pager',
1809 b'pager',
1810 b'attend-.*',
1810 b'attend-.*',
1811 default=dynamicdefault,
1811 default=dynamicdefault,
1812 generic=True,
1812 generic=True,
1813 )
1813 )
1814 coreconfigitem(
1814 coreconfigitem(
1815 b'pager',
1815 b'pager',
1816 b'ignore',
1816 b'ignore',
1817 default=list,
1817 default=list,
1818 )
1818 )
1819 coreconfigitem(
1819 coreconfigitem(
1820 b'pager',
1820 b'pager',
1821 b'pager',
1821 b'pager',
1822 default=dynamicdefault,
1822 default=dynamicdefault,
1823 )
1823 )
1824 coreconfigitem(
1824 coreconfigitem(
1825 b'patch',
1825 b'patch',
1826 b'eol',
1826 b'eol',
1827 default=b'strict',
1827 default=b'strict',
1828 )
1828 )
1829 coreconfigitem(
1829 coreconfigitem(
1830 b'patch',
1830 b'patch',
1831 b'fuzz',
1831 b'fuzz',
1832 default=2,
1832 default=2,
1833 )
1833 )
1834 coreconfigitem(
1834 coreconfigitem(
1835 b'paths',
1835 b'paths',
1836 b'default',
1836 b'default',
1837 default=None,
1837 default=None,
1838 )
1838 )
1839 coreconfigitem(
1839 coreconfigitem(
1840 b'paths',
1840 b'paths',
1841 b'default-push',
1841 b'default-push',
1842 default=None,
1842 default=None,
1843 )
1843 )
1844 coreconfigitem(
1844 coreconfigitem(
1845 b'paths',
1845 b'paths',
1846 b'.*',
1846 b'.*',
1847 default=None,
1847 default=None,
1848 generic=True,
1848 generic=True,
1849 )
1849 )
1850 coreconfigitem(
1850 coreconfigitem(
1851 b'paths',
1851 b'paths',
1852 b'.*:bookmarks.mode',
1852 b'.*:bookmarks.mode',
1853 default='default',
1853 default='default',
1854 generic=True,
1854 generic=True,
1855 )
1855 )
1856 coreconfigitem(
1856 coreconfigitem(
1857 b'paths',
1857 b'paths',
1858 b'.*:multi-urls',
1858 b'.*:multi-urls',
1859 default=False,
1859 default=False,
1860 generic=True,
1860 generic=True,
1861 )
1861 )
1862 coreconfigitem(
1862 coreconfigitem(
1863 b'paths',
1863 b'paths',
1864 b'.*:pushrev',
1864 b'.*:pushrev',
1865 default=None,
1865 default=None,
1866 generic=True,
1866 generic=True,
1867 )
1867 )
1868 coreconfigitem(
1868 coreconfigitem(
1869 b'paths',
1869 b'paths',
1870 b'.*:pushurl',
1870 b'.*:pushurl',
1871 default=None,
1871 default=None,
1872 generic=True,
1872 generic=True,
1873 )
1873 )
1874 coreconfigitem(
1874 coreconfigitem(
1875 b'phases',
1875 b'phases',
1876 b'checksubrepos',
1876 b'checksubrepos',
1877 default=b'follow',
1877 default=b'follow',
1878 )
1878 )
1879 coreconfigitem(
1879 coreconfigitem(
1880 b'phases',
1880 b'phases',
1881 b'new-commit',
1881 b'new-commit',
1882 default=b'draft',
1882 default=b'draft',
1883 )
1883 )
1884 coreconfigitem(
1884 coreconfigitem(
1885 b'phases',
1885 b'phases',
1886 b'publish',
1886 b'publish',
1887 default=True,
1887 default=True,
1888 )
1888 )
1889 coreconfigitem(
1889 coreconfigitem(
1890 b'profiling',
1890 b'profiling',
1891 b'enabled',
1891 b'enabled',
1892 default=False,
1892 default=False,
1893 )
1893 )
1894 coreconfigitem(
1894 coreconfigitem(
1895 b'profiling',
1895 b'profiling',
1896 b'format',
1896 b'format',
1897 default=b'text',
1897 default=b'text',
1898 )
1898 )
1899 coreconfigitem(
1899 coreconfigitem(
1900 b'profiling',
1900 b'profiling',
1901 b'freq',
1901 b'freq',
1902 default=1000,
1902 default=1000,
1903 )
1903 )
1904 coreconfigitem(
1904 coreconfigitem(
1905 b'profiling',
1905 b'profiling',
1906 b'limit',
1906 b'limit',
1907 default=30,
1907 default=30,
1908 )
1908 )
1909 coreconfigitem(
1909 coreconfigitem(
1910 b'profiling',
1910 b'profiling',
1911 b'nested',
1911 b'nested',
1912 default=0,
1912 default=0,
1913 )
1913 )
1914 coreconfigitem(
1914 coreconfigitem(
1915 b'profiling',
1915 b'profiling',
1916 b'output',
1916 b'output',
1917 default=None,
1917 default=None,
1918 )
1918 )
1919 coreconfigitem(
1919 coreconfigitem(
1920 b'profiling',
1920 b'profiling',
1921 b'showmax',
1921 b'showmax',
1922 default=0.999,
1922 default=0.999,
1923 )
1923 )
1924 coreconfigitem(
1924 coreconfigitem(
1925 b'profiling',
1925 b'profiling',
1926 b'showmin',
1926 b'showmin',
1927 default=dynamicdefault,
1927 default=dynamicdefault,
1928 )
1928 )
1929 coreconfigitem(
1929 coreconfigitem(
1930 b'profiling',
1930 b'profiling',
1931 b'showtime',
1931 b'showtime',
1932 default=True,
1932 default=True,
1933 )
1933 )
1934 coreconfigitem(
1934 coreconfigitem(
1935 b'profiling',
1935 b'profiling',
1936 b'sort',
1936 b'sort',
1937 default=b'inlinetime',
1937 default=b'inlinetime',
1938 )
1938 )
1939 coreconfigitem(
1939 coreconfigitem(
1940 b'profiling',
1940 b'profiling',
1941 b'statformat',
1941 b'statformat',
1942 default=b'hotpath',
1942 default=b'hotpath',
1943 )
1943 )
1944 coreconfigitem(
1944 coreconfigitem(
1945 b'profiling',
1945 b'profiling',
1946 b'time-track',
1946 b'time-track',
1947 default=dynamicdefault,
1947 default=dynamicdefault,
1948 )
1948 )
1949 coreconfigitem(
1949 coreconfigitem(
1950 b'profiling',
1950 b'profiling',
1951 b'type',
1951 b'type',
1952 default=b'stat',
1952 default=b'stat',
1953 )
1953 )
1954 coreconfigitem(
1954 coreconfigitem(
1955 b'progress',
1955 b'progress',
1956 b'assume-tty',
1956 b'assume-tty',
1957 default=False,
1957 default=False,
1958 )
1958 )
1959 coreconfigitem(
1959 coreconfigitem(
1960 b'progress',
1960 b'progress',
1961 b'changedelay',
1961 b'changedelay',
1962 default=1,
1962 default=1,
1963 )
1963 )
1964 coreconfigitem(
1964 coreconfigitem(
1965 b'progress',
1965 b'progress',
1966 b'clear-complete',
1966 b'clear-complete',
1967 default=True,
1967 default=True,
1968 )
1968 )
1969 coreconfigitem(
1969 coreconfigitem(
1970 b'progress',
1970 b'progress',
1971 b'debug',
1971 b'debug',
1972 default=False,
1972 default=False,
1973 )
1973 )
1974 coreconfigitem(
1974 coreconfigitem(
1975 b'progress',
1975 b'progress',
1976 b'delay',
1976 b'delay',
1977 default=3,
1977 default=3,
1978 )
1978 )
1979 coreconfigitem(
1979 coreconfigitem(
1980 b'progress',
1980 b'progress',
1981 b'disable',
1981 b'disable',
1982 default=False,
1982 default=False,
1983 )
1983 )
1984 coreconfigitem(
1984 coreconfigitem(
1985 b'progress',
1985 b'progress',
1986 b'estimateinterval',
1986 b'estimateinterval',
1987 default=60.0,
1987 default=60.0,
1988 )
1988 )
1989 coreconfigitem(
1989 coreconfigitem(
1990 b'progress',
1990 b'progress',
1991 b'format',
1991 b'format',
1992 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1992 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1993 )
1993 )
1994 coreconfigitem(
1994 coreconfigitem(
1995 b'progress',
1995 b'progress',
1996 b'refresh',
1996 b'refresh',
1997 default=0.1,
1997 default=0.1,
1998 )
1998 )
1999 coreconfigitem(
1999 coreconfigitem(
2000 b'progress',
2000 b'progress',
2001 b'width',
2001 b'width',
2002 default=dynamicdefault,
2002 default=dynamicdefault,
2003 )
2003 )
2004 coreconfigitem(
2004 coreconfigitem(
2005 b'pull',
2005 b'pull',
2006 b'confirm',
2006 b'confirm',
2007 default=False,
2007 default=False,
2008 )
2008 )
2009 coreconfigitem(
2009 coreconfigitem(
2010 b'push',
2010 b'push',
2011 b'pushvars.server',
2011 b'pushvars.server',
2012 default=False,
2012 default=False,
2013 )
2013 )
2014 coreconfigitem(
2014 coreconfigitem(
2015 b'rewrite',
2015 b'rewrite',
2016 b'backup-bundle',
2016 b'backup-bundle',
2017 default=True,
2017 default=True,
2018 alias=[(b'ui', b'history-editing-backup')],
2018 alias=[(b'ui', b'history-editing-backup')],
2019 )
2019 )
2020 coreconfigitem(
2020 coreconfigitem(
2021 b'rewrite',
2021 b'rewrite',
2022 b'update-timestamp',
2022 b'update-timestamp',
2023 default=False,
2023 default=False,
2024 )
2024 )
2025 coreconfigitem(
2025 coreconfigitem(
2026 b'rewrite',
2026 b'rewrite',
2027 b'empty-successor',
2027 b'empty-successor',
2028 default=b'skip',
2028 default=b'skip',
2029 experimental=True,
2029 experimental=True,
2030 )
2030 )
2031 # experimental as long as format.use-dirstate-v2 is.
2031 # experimental as long as format.use-dirstate-v2 is.
2032 coreconfigitem(
2032 coreconfigitem(
2033 b'storage',
2033 b'storage',
2034 b'dirstate-v2.slow-path',
2034 b'dirstate-v2.slow-path',
2035 default=b"abort",
2035 default=b"abort",
2036 experimental=True,
2036 experimental=True,
2037 )
2037 )
2038 coreconfigitem(
2038 coreconfigitem(
2039 b'storage',
2039 b'storage',
2040 b'new-repo-backend',
2040 b'new-repo-backend',
2041 default=b'revlogv1',
2041 default=b'revlogv1',
2042 experimental=True,
2042 experimental=True,
2043 )
2043 )
2044 coreconfigitem(
2044 coreconfigitem(
2045 b'storage',
2045 b'storage',
2046 b'revlog.optimize-delta-parent-choice',
2046 b'revlog.optimize-delta-parent-choice',
2047 default=True,
2047 default=True,
2048 alias=[(b'format', b'aggressivemergedeltas')],
2048 alias=[(b'format', b'aggressivemergedeltas')],
2049 )
2049 )
2050 coreconfigitem(
2050 coreconfigitem(
2051 b'storage',
2051 b'storage',
2052 b'revlog.delta-parent-search.candidate-group-chunk-size',
2052 b'revlog.delta-parent-search.candidate-group-chunk-size',
2053 default=10,
2053 default=10,
2054 )
2054 )
2055 coreconfigitem(
2055 coreconfigitem(
2056 b'storage',
2056 b'storage',
2057 b'revlog.issue6528.fix-incoming',
2057 b'revlog.issue6528.fix-incoming',
2058 default=True,
2058 default=True,
2059 )
2059 )
2060 # experimental as long as rust is experimental (or a C version is implemented)
2060 # experimental as long as rust is experimental (or a C version is implemented)
2061 coreconfigitem(
2061 coreconfigitem(
2062 b'storage',
2062 b'storage',
2063 b'revlog.persistent-nodemap.mmap',
2063 b'revlog.persistent-nodemap.mmap',
2064 default=True,
2064 default=True,
2065 )
2065 )
2066 # experimental as long as format.use-persistent-nodemap is.
2066 # experimental as long as format.use-persistent-nodemap is.
2067 coreconfigitem(
2067 coreconfigitem(
2068 b'storage',
2068 b'storage',
2069 b'revlog.persistent-nodemap.slow-path',
2069 b'revlog.persistent-nodemap.slow-path',
2070 default=b"abort",
2070 default=b"abort",
2071 )
2071 )
2072
2072
2073 coreconfigitem(
2073 coreconfigitem(
2074 b'storage',
2074 b'storage',
2075 b'revlog.reuse-external-delta',
2075 b'revlog.reuse-external-delta',
2076 default=True,
2076 default=True,
2077 )
2077 )
2078 # This option is True unless `format.generaldelta` is set.
2078 coreconfigitem(
2079 coreconfigitem(
2079 b'storage',
2080 b'storage',
2080 b'revlog.reuse-external-delta-parent',
2081 b'revlog.reuse-external-delta-parent',
2081 default=None,
2082 default=None,
2082 )
2083 )
2083 coreconfigitem(
2084 coreconfigitem(
2084 b'storage',
2085 b'storage',
2085 b'revlog.zlib.level',
2086 b'revlog.zlib.level',
2086 default=None,
2087 default=None,
2087 )
2088 )
2088 coreconfigitem(
2089 coreconfigitem(
2089 b'storage',
2090 b'storage',
2090 b'revlog.zstd.level',
2091 b'revlog.zstd.level',
2091 default=None,
2092 default=None,
2092 )
2093 )
2093 coreconfigitem(
2094 coreconfigitem(
2094 b'server',
2095 b'server',
2095 b'bookmarks-pushkey-compat',
2096 b'bookmarks-pushkey-compat',
2096 default=True,
2097 default=True,
2097 )
2098 )
2098 coreconfigitem(
2099 coreconfigitem(
2099 b'server',
2100 b'server',
2100 b'bundle1',
2101 b'bundle1',
2101 default=True,
2102 default=True,
2102 )
2103 )
2103 coreconfigitem(
2104 coreconfigitem(
2104 b'server',
2105 b'server',
2105 b'bundle1gd',
2106 b'bundle1gd',
2106 default=None,
2107 default=None,
2107 )
2108 )
2108 coreconfigitem(
2109 coreconfigitem(
2109 b'server',
2110 b'server',
2110 b'bundle1.pull',
2111 b'bundle1.pull',
2111 default=None,
2112 default=None,
2112 )
2113 )
2113 coreconfigitem(
2114 coreconfigitem(
2114 b'server',
2115 b'server',
2115 b'bundle1gd.pull',
2116 b'bundle1gd.pull',
2116 default=None,
2117 default=None,
2117 )
2118 )
2118 coreconfigitem(
2119 coreconfigitem(
2119 b'server',
2120 b'server',
2120 b'bundle1.push',
2121 b'bundle1.push',
2121 default=None,
2122 default=None,
2122 )
2123 )
2123 coreconfigitem(
2124 coreconfigitem(
2124 b'server',
2125 b'server',
2125 b'bundle1gd.push',
2126 b'bundle1gd.push',
2126 default=None,
2127 default=None,
2127 )
2128 )
2128 coreconfigitem(
2129 coreconfigitem(
2129 b'server',
2130 b'server',
2130 b'bundle2.stream',
2131 b'bundle2.stream',
2131 default=True,
2132 default=True,
2132 alias=[(b'experimental', b'bundle2.stream')],
2133 alias=[(b'experimental', b'bundle2.stream')],
2133 )
2134 )
2134 coreconfigitem(
2135 coreconfigitem(
2135 b'server',
2136 b'server',
2136 b'compressionengines',
2137 b'compressionengines',
2137 default=list,
2138 default=list,
2138 )
2139 )
2139 coreconfigitem(
2140 coreconfigitem(
2140 b'server',
2141 b'server',
2141 b'concurrent-push-mode',
2142 b'concurrent-push-mode',
2142 default=b'check-related',
2143 default=b'check-related',
2143 )
2144 )
2144 coreconfigitem(
2145 coreconfigitem(
2145 b'server',
2146 b'server',
2146 b'disablefullbundle',
2147 b'disablefullbundle',
2147 default=False,
2148 default=False,
2148 )
2149 )
2149 coreconfigitem(
2150 coreconfigitem(
2150 b'server',
2151 b'server',
2151 b'maxhttpheaderlen',
2152 b'maxhttpheaderlen',
2152 default=1024,
2153 default=1024,
2153 )
2154 )
2154 coreconfigitem(
2155 coreconfigitem(
2155 b'server',
2156 b'server',
2156 b'pullbundle',
2157 b'pullbundle',
2157 default=True,
2158 default=True,
2158 )
2159 )
2159 coreconfigitem(
2160 coreconfigitem(
2160 b'server',
2161 b'server',
2161 b'preferuncompressed',
2162 b'preferuncompressed',
2162 default=False,
2163 default=False,
2163 )
2164 )
2164 coreconfigitem(
2165 coreconfigitem(
2165 b'server',
2166 b'server',
2166 b'streamunbundle',
2167 b'streamunbundle',
2167 default=False,
2168 default=False,
2168 )
2169 )
2169 coreconfigitem(
2170 coreconfigitem(
2170 b'server',
2171 b'server',
2171 b'uncompressed',
2172 b'uncompressed',
2172 default=True,
2173 default=True,
2173 )
2174 )
2174 coreconfigitem(
2175 coreconfigitem(
2175 b'server',
2176 b'server',
2176 b'uncompressedallowsecret',
2177 b'uncompressedallowsecret',
2177 default=False,
2178 default=False,
2178 )
2179 )
2179 coreconfigitem(
2180 coreconfigitem(
2180 b'server',
2181 b'server',
2181 b'view',
2182 b'view',
2182 default=b'served',
2183 default=b'served',
2183 )
2184 )
2184 coreconfigitem(
2185 coreconfigitem(
2185 b'server',
2186 b'server',
2186 b'validate',
2187 b'validate',
2187 default=False,
2188 default=False,
2188 )
2189 )
2189 coreconfigitem(
2190 coreconfigitem(
2190 b'server',
2191 b'server',
2191 b'zliblevel',
2192 b'zliblevel',
2192 default=-1,
2193 default=-1,
2193 )
2194 )
2194 coreconfigitem(
2195 coreconfigitem(
2195 b'server',
2196 b'server',
2196 b'zstdlevel',
2197 b'zstdlevel',
2197 default=3,
2198 default=3,
2198 )
2199 )
2199 coreconfigitem(
2200 coreconfigitem(
2200 b'share',
2201 b'share',
2201 b'pool',
2202 b'pool',
2202 default=None,
2203 default=None,
2203 )
2204 )
2204 coreconfigitem(
2205 coreconfigitem(
2205 b'share',
2206 b'share',
2206 b'poolnaming',
2207 b'poolnaming',
2207 default=b'identity',
2208 default=b'identity',
2208 )
2209 )
2209 coreconfigitem(
2210 coreconfigitem(
2210 b'share',
2211 b'share',
2211 b'safe-mismatch.source-not-safe',
2212 b'safe-mismatch.source-not-safe',
2212 default=b'abort',
2213 default=b'abort',
2213 )
2214 )
2214 coreconfigitem(
2215 coreconfigitem(
2215 b'share',
2216 b'share',
2216 b'safe-mismatch.source-safe',
2217 b'safe-mismatch.source-safe',
2217 default=b'abort',
2218 default=b'abort',
2218 )
2219 )
2219 coreconfigitem(
2220 coreconfigitem(
2220 b'share',
2221 b'share',
2221 b'safe-mismatch.source-not-safe.warn',
2222 b'safe-mismatch.source-not-safe.warn',
2222 default=True,
2223 default=True,
2223 )
2224 )
2224 coreconfigitem(
2225 coreconfigitem(
2225 b'share',
2226 b'share',
2226 b'safe-mismatch.source-safe.warn',
2227 b'safe-mismatch.source-safe.warn',
2227 default=True,
2228 default=True,
2228 )
2229 )
2229 coreconfigitem(
2230 coreconfigitem(
2230 b'share',
2231 b'share',
2231 b'safe-mismatch.source-not-safe:verbose-upgrade',
2232 b'safe-mismatch.source-not-safe:verbose-upgrade',
2232 default=True,
2233 default=True,
2233 )
2234 )
2234 coreconfigitem(
2235 coreconfigitem(
2235 b'share',
2236 b'share',
2236 b'safe-mismatch.source-safe:verbose-upgrade',
2237 b'safe-mismatch.source-safe:verbose-upgrade',
2237 default=True,
2238 default=True,
2238 )
2239 )
2239 coreconfigitem(
2240 coreconfigitem(
2240 b'shelve',
2241 b'shelve',
2241 b'maxbackups',
2242 b'maxbackups',
2242 default=10,
2243 default=10,
2243 )
2244 )
2244 coreconfigitem(
2245 coreconfigitem(
2245 b'smtp',
2246 b'smtp',
2246 b'host',
2247 b'host',
2247 default=None,
2248 default=None,
2248 )
2249 )
2249 coreconfigitem(
2250 coreconfigitem(
2250 b'smtp',
2251 b'smtp',
2251 b'local_hostname',
2252 b'local_hostname',
2252 default=None,
2253 default=None,
2253 )
2254 )
2254 coreconfigitem(
2255 coreconfigitem(
2255 b'smtp',
2256 b'smtp',
2256 b'password',
2257 b'password',
2257 default=None,
2258 default=None,
2258 )
2259 )
2259 coreconfigitem(
2260 coreconfigitem(
2260 b'smtp',
2261 b'smtp',
2261 b'port',
2262 b'port',
2262 default=dynamicdefault,
2263 default=dynamicdefault,
2263 )
2264 )
2264 coreconfigitem(
2265 coreconfigitem(
2265 b'smtp',
2266 b'smtp',
2266 b'tls',
2267 b'tls',
2267 default=b'none',
2268 default=b'none',
2268 )
2269 )
2269 coreconfigitem(
2270 coreconfigitem(
2270 b'smtp',
2271 b'smtp',
2271 b'username',
2272 b'username',
2272 default=None,
2273 default=None,
2273 )
2274 )
2274 coreconfigitem(
2275 coreconfigitem(
2275 b'sparse',
2276 b'sparse',
2276 b'missingwarning',
2277 b'missingwarning',
2277 default=True,
2278 default=True,
2278 experimental=True,
2279 experimental=True,
2279 )
2280 )
2280 coreconfigitem(
2281 coreconfigitem(
2281 b'subrepos',
2282 b'subrepos',
2282 b'allowed',
2283 b'allowed',
2283 default=dynamicdefault, # to make backporting simpler
2284 default=dynamicdefault, # to make backporting simpler
2284 )
2285 )
2285 coreconfigitem(
2286 coreconfigitem(
2286 b'subrepos',
2287 b'subrepos',
2287 b'hg:allowed',
2288 b'hg:allowed',
2288 default=dynamicdefault,
2289 default=dynamicdefault,
2289 )
2290 )
2290 coreconfigitem(
2291 coreconfigitem(
2291 b'subrepos',
2292 b'subrepos',
2292 b'git:allowed',
2293 b'git:allowed',
2293 default=dynamicdefault,
2294 default=dynamicdefault,
2294 )
2295 )
2295 coreconfigitem(
2296 coreconfigitem(
2296 b'subrepos',
2297 b'subrepos',
2297 b'svn:allowed',
2298 b'svn:allowed',
2298 default=dynamicdefault,
2299 default=dynamicdefault,
2299 )
2300 )
2300 coreconfigitem(
2301 coreconfigitem(
2301 b'templates',
2302 b'templates',
2302 b'.*',
2303 b'.*',
2303 default=None,
2304 default=None,
2304 generic=True,
2305 generic=True,
2305 )
2306 )
2306 coreconfigitem(
2307 coreconfigitem(
2307 b'templateconfig',
2308 b'templateconfig',
2308 b'.*',
2309 b'.*',
2309 default=dynamicdefault,
2310 default=dynamicdefault,
2310 generic=True,
2311 generic=True,
2311 )
2312 )
2312 coreconfigitem(
2313 coreconfigitem(
2313 b'trusted',
2314 b'trusted',
2314 b'groups',
2315 b'groups',
2315 default=list,
2316 default=list,
2316 )
2317 )
2317 coreconfigitem(
2318 coreconfigitem(
2318 b'trusted',
2319 b'trusted',
2319 b'users',
2320 b'users',
2320 default=list,
2321 default=list,
2321 )
2322 )
2322 coreconfigitem(
2323 coreconfigitem(
2323 b'ui',
2324 b'ui',
2324 b'_usedassubrepo',
2325 b'_usedassubrepo',
2325 default=False,
2326 default=False,
2326 )
2327 )
2327 coreconfigitem(
2328 coreconfigitem(
2328 b'ui',
2329 b'ui',
2329 b'allowemptycommit',
2330 b'allowemptycommit',
2330 default=False,
2331 default=False,
2331 )
2332 )
2332 coreconfigitem(
2333 coreconfigitem(
2333 b'ui',
2334 b'ui',
2334 b'archivemeta',
2335 b'archivemeta',
2335 default=True,
2336 default=True,
2336 )
2337 )
2337 coreconfigitem(
2338 coreconfigitem(
2338 b'ui',
2339 b'ui',
2339 b'askusername',
2340 b'askusername',
2340 default=False,
2341 default=False,
2341 )
2342 )
2342 coreconfigitem(
2343 coreconfigitem(
2343 b'ui',
2344 b'ui',
2344 b'available-memory',
2345 b'available-memory',
2345 default=None,
2346 default=None,
2346 )
2347 )
2347
2348
2348 coreconfigitem(
2349 coreconfigitem(
2349 b'ui',
2350 b'ui',
2350 b'clonebundlefallback',
2351 b'clonebundlefallback',
2351 default=False,
2352 default=False,
2352 )
2353 )
2353 coreconfigitem(
2354 coreconfigitem(
2354 b'ui',
2355 b'ui',
2355 b'clonebundleprefers',
2356 b'clonebundleprefers',
2356 default=list,
2357 default=list,
2357 )
2358 )
2358 coreconfigitem(
2359 coreconfigitem(
2359 b'ui',
2360 b'ui',
2360 b'clonebundles',
2361 b'clonebundles',
2361 default=True,
2362 default=True,
2362 )
2363 )
2363 coreconfigitem(
2364 coreconfigitem(
2364 b'ui',
2365 b'ui',
2365 b'color',
2366 b'color',
2366 default=b'auto',
2367 default=b'auto',
2367 )
2368 )
2368 coreconfigitem(
2369 coreconfigitem(
2369 b'ui',
2370 b'ui',
2370 b'commitsubrepos',
2371 b'commitsubrepos',
2371 default=False,
2372 default=False,
2372 )
2373 )
2373 coreconfigitem(
2374 coreconfigitem(
2374 b'ui',
2375 b'ui',
2375 b'debug',
2376 b'debug',
2376 default=False,
2377 default=False,
2377 )
2378 )
2378 coreconfigitem(
2379 coreconfigitem(
2379 b'ui',
2380 b'ui',
2380 b'debugger',
2381 b'debugger',
2381 default=None,
2382 default=None,
2382 )
2383 )
2383 coreconfigitem(
2384 coreconfigitem(
2384 b'ui',
2385 b'ui',
2385 b'editor',
2386 b'editor',
2386 default=dynamicdefault,
2387 default=dynamicdefault,
2387 )
2388 )
2388 coreconfigitem(
2389 coreconfigitem(
2389 b'ui',
2390 b'ui',
2390 b'detailed-exit-code',
2391 b'detailed-exit-code',
2391 default=False,
2392 default=False,
2392 experimental=True,
2393 experimental=True,
2393 )
2394 )
2394 coreconfigitem(
2395 coreconfigitem(
2395 b'ui',
2396 b'ui',
2396 b'fallbackencoding',
2397 b'fallbackencoding',
2397 default=None,
2398 default=None,
2398 )
2399 )
2399 coreconfigitem(
2400 coreconfigitem(
2400 b'ui',
2401 b'ui',
2401 b'forcecwd',
2402 b'forcecwd',
2402 default=None,
2403 default=None,
2403 )
2404 )
2404 coreconfigitem(
2405 coreconfigitem(
2405 b'ui',
2406 b'ui',
2406 b'forcemerge',
2407 b'forcemerge',
2407 default=None,
2408 default=None,
2408 )
2409 )
2409 coreconfigitem(
2410 coreconfigitem(
2410 b'ui',
2411 b'ui',
2411 b'formatdebug',
2412 b'formatdebug',
2412 default=False,
2413 default=False,
2413 )
2414 )
2414 coreconfigitem(
2415 coreconfigitem(
2415 b'ui',
2416 b'ui',
2416 b'formatjson',
2417 b'formatjson',
2417 default=False,
2418 default=False,
2418 )
2419 )
2419 coreconfigitem(
2420 coreconfigitem(
2420 b'ui',
2421 b'ui',
2421 b'formatted',
2422 b'formatted',
2422 default=None,
2423 default=None,
2423 )
2424 )
2424 coreconfigitem(
2425 coreconfigitem(
2425 b'ui',
2426 b'ui',
2426 b'interactive',
2427 b'interactive',
2427 default=None,
2428 default=None,
2428 )
2429 )
2429 coreconfigitem(
2430 coreconfigitem(
2430 b'ui',
2431 b'ui',
2431 b'interface',
2432 b'interface',
2432 default=None,
2433 default=None,
2433 )
2434 )
2434 coreconfigitem(
2435 coreconfigitem(
2435 b'ui',
2436 b'ui',
2436 b'interface.chunkselector',
2437 b'interface.chunkselector',
2437 default=None,
2438 default=None,
2438 )
2439 )
2439 coreconfigitem(
2440 coreconfigitem(
2440 b'ui',
2441 b'ui',
2441 b'large-file-limit',
2442 b'large-file-limit',
2442 default=10 * (2 ** 20),
2443 default=10 * (2 ** 20),
2443 )
2444 )
2444 coreconfigitem(
2445 coreconfigitem(
2445 b'ui',
2446 b'ui',
2446 b'logblockedtimes',
2447 b'logblockedtimes',
2447 default=False,
2448 default=False,
2448 )
2449 )
2449 coreconfigitem(
2450 coreconfigitem(
2450 b'ui',
2451 b'ui',
2451 b'merge',
2452 b'merge',
2452 default=None,
2453 default=None,
2453 )
2454 )
2454 coreconfigitem(
2455 coreconfigitem(
2455 b'ui',
2456 b'ui',
2456 b'mergemarkers',
2457 b'mergemarkers',
2457 default=b'basic',
2458 default=b'basic',
2458 )
2459 )
2459 coreconfigitem(
2460 coreconfigitem(
2460 b'ui',
2461 b'ui',
2461 b'message-output',
2462 b'message-output',
2462 default=b'stdio',
2463 default=b'stdio',
2463 )
2464 )
2464 coreconfigitem(
2465 coreconfigitem(
2465 b'ui',
2466 b'ui',
2466 b'nontty',
2467 b'nontty',
2467 default=False,
2468 default=False,
2468 )
2469 )
2469 coreconfigitem(
2470 coreconfigitem(
2470 b'ui',
2471 b'ui',
2471 b'origbackuppath',
2472 b'origbackuppath',
2472 default=None,
2473 default=None,
2473 )
2474 )
2474 coreconfigitem(
2475 coreconfigitem(
2475 b'ui',
2476 b'ui',
2476 b'paginate',
2477 b'paginate',
2477 default=True,
2478 default=True,
2478 )
2479 )
2479 coreconfigitem(
2480 coreconfigitem(
2480 b'ui',
2481 b'ui',
2481 b'patch',
2482 b'patch',
2482 default=None,
2483 default=None,
2483 )
2484 )
2484 coreconfigitem(
2485 coreconfigitem(
2485 b'ui',
2486 b'ui',
2486 b'portablefilenames',
2487 b'portablefilenames',
2487 default=b'warn',
2488 default=b'warn',
2488 )
2489 )
2489 coreconfigitem(
2490 coreconfigitem(
2490 b'ui',
2491 b'ui',
2491 b'promptecho',
2492 b'promptecho',
2492 default=False,
2493 default=False,
2493 )
2494 )
2494 coreconfigitem(
2495 coreconfigitem(
2495 b'ui',
2496 b'ui',
2496 b'quiet',
2497 b'quiet',
2497 default=False,
2498 default=False,
2498 )
2499 )
2499 coreconfigitem(
2500 coreconfigitem(
2500 b'ui',
2501 b'ui',
2501 b'quietbookmarkmove',
2502 b'quietbookmarkmove',
2502 default=False,
2503 default=False,
2503 )
2504 )
2504 coreconfigitem(
2505 coreconfigitem(
2505 b'ui',
2506 b'ui',
2506 b'relative-paths',
2507 b'relative-paths',
2507 default=b'legacy',
2508 default=b'legacy',
2508 )
2509 )
2509 coreconfigitem(
2510 coreconfigitem(
2510 b'ui',
2511 b'ui',
2511 b'remotecmd',
2512 b'remotecmd',
2512 default=b'hg',
2513 default=b'hg',
2513 )
2514 )
2514 coreconfigitem(
2515 coreconfigitem(
2515 b'ui',
2516 b'ui',
2516 b'report_untrusted',
2517 b'report_untrusted',
2517 default=True,
2518 default=True,
2518 )
2519 )
2519 coreconfigitem(
2520 coreconfigitem(
2520 b'ui',
2521 b'ui',
2521 b'rollback',
2522 b'rollback',
2522 default=True,
2523 default=True,
2523 )
2524 )
2524 coreconfigitem(
2525 coreconfigitem(
2525 b'ui',
2526 b'ui',
2526 b'signal-safe-lock',
2527 b'signal-safe-lock',
2527 default=True,
2528 default=True,
2528 )
2529 )
2529 coreconfigitem(
2530 coreconfigitem(
2530 b'ui',
2531 b'ui',
2531 b'slash',
2532 b'slash',
2532 default=False,
2533 default=False,
2533 )
2534 )
2534 coreconfigitem(
2535 coreconfigitem(
2535 b'ui',
2536 b'ui',
2536 b'ssh',
2537 b'ssh',
2537 default=b'ssh',
2538 default=b'ssh',
2538 )
2539 )
2539 coreconfigitem(
2540 coreconfigitem(
2540 b'ui',
2541 b'ui',
2541 b'ssherrorhint',
2542 b'ssherrorhint',
2542 default=None,
2543 default=None,
2543 )
2544 )
2544 coreconfigitem(
2545 coreconfigitem(
2545 b'ui',
2546 b'ui',
2546 b'statuscopies',
2547 b'statuscopies',
2547 default=False,
2548 default=False,
2548 )
2549 )
2549 coreconfigitem(
2550 coreconfigitem(
2550 b'ui',
2551 b'ui',
2551 b'strict',
2552 b'strict',
2552 default=False,
2553 default=False,
2553 )
2554 )
2554 coreconfigitem(
2555 coreconfigitem(
2555 b'ui',
2556 b'ui',
2556 b'style',
2557 b'style',
2557 default=b'',
2558 default=b'',
2558 )
2559 )
2559 coreconfigitem(
2560 coreconfigitem(
2560 b'ui',
2561 b'ui',
2561 b'supportcontact',
2562 b'supportcontact',
2562 default=None,
2563 default=None,
2563 )
2564 )
2564 coreconfigitem(
2565 coreconfigitem(
2565 b'ui',
2566 b'ui',
2566 b'textwidth',
2567 b'textwidth',
2567 default=78,
2568 default=78,
2568 )
2569 )
2569 coreconfigitem(
2570 coreconfigitem(
2570 b'ui',
2571 b'ui',
2571 b'timeout',
2572 b'timeout',
2572 default=b'600',
2573 default=b'600',
2573 )
2574 )
2574 coreconfigitem(
2575 coreconfigitem(
2575 b'ui',
2576 b'ui',
2576 b'timeout.warn',
2577 b'timeout.warn',
2577 default=0,
2578 default=0,
2578 )
2579 )
2579 coreconfigitem(
2580 coreconfigitem(
2580 b'ui',
2581 b'ui',
2581 b'timestamp-output',
2582 b'timestamp-output',
2582 default=False,
2583 default=False,
2583 )
2584 )
2584 coreconfigitem(
2585 coreconfigitem(
2585 b'ui',
2586 b'ui',
2586 b'traceback',
2587 b'traceback',
2587 default=False,
2588 default=False,
2588 )
2589 )
2589 coreconfigitem(
2590 coreconfigitem(
2590 b'ui',
2591 b'ui',
2591 b'tweakdefaults',
2592 b'tweakdefaults',
2592 default=False,
2593 default=False,
2593 )
2594 )
2594 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2595 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2595 coreconfigitem(
2596 coreconfigitem(
2596 b'ui',
2597 b'ui',
2597 b'verbose',
2598 b'verbose',
2598 default=False,
2599 default=False,
2599 )
2600 )
2600 coreconfigitem(
2601 coreconfigitem(
2601 b'verify',
2602 b'verify',
2602 b'skipflags',
2603 b'skipflags',
2603 default=0,
2604 default=0,
2604 )
2605 )
2605 coreconfigitem(
2606 coreconfigitem(
2606 b'web',
2607 b'web',
2607 b'allowbz2',
2608 b'allowbz2',
2608 default=False,
2609 default=False,
2609 )
2610 )
2610 coreconfigitem(
2611 coreconfigitem(
2611 b'web',
2612 b'web',
2612 b'allowgz',
2613 b'allowgz',
2613 default=False,
2614 default=False,
2614 )
2615 )
2615 coreconfigitem(
2616 coreconfigitem(
2616 b'web',
2617 b'web',
2617 b'allow-pull',
2618 b'allow-pull',
2618 alias=[(b'web', b'allowpull')],
2619 alias=[(b'web', b'allowpull')],
2619 default=True,
2620 default=True,
2620 )
2621 )
2621 coreconfigitem(
2622 coreconfigitem(
2622 b'web',
2623 b'web',
2623 b'allow-push',
2624 b'allow-push',
2624 alias=[(b'web', b'allow_push')],
2625 alias=[(b'web', b'allow_push')],
2625 default=list,
2626 default=list,
2626 )
2627 )
2627 coreconfigitem(
2628 coreconfigitem(
2628 b'web',
2629 b'web',
2629 b'allowzip',
2630 b'allowzip',
2630 default=False,
2631 default=False,
2631 )
2632 )
2632 coreconfigitem(
2633 coreconfigitem(
2633 b'web',
2634 b'web',
2634 b'archivesubrepos',
2635 b'archivesubrepos',
2635 default=False,
2636 default=False,
2636 )
2637 )
2637 coreconfigitem(
2638 coreconfigitem(
2638 b'web',
2639 b'web',
2639 b'cache',
2640 b'cache',
2640 default=True,
2641 default=True,
2641 )
2642 )
2642 coreconfigitem(
2643 coreconfigitem(
2643 b'web',
2644 b'web',
2644 b'comparisoncontext',
2645 b'comparisoncontext',
2645 default=5,
2646 default=5,
2646 )
2647 )
2647 coreconfigitem(
2648 coreconfigitem(
2648 b'web',
2649 b'web',
2649 b'contact',
2650 b'contact',
2650 default=None,
2651 default=None,
2651 )
2652 )
2652 coreconfigitem(
2653 coreconfigitem(
2653 b'web',
2654 b'web',
2654 b'deny_push',
2655 b'deny_push',
2655 default=list,
2656 default=list,
2656 )
2657 )
2657 coreconfigitem(
2658 coreconfigitem(
2658 b'web',
2659 b'web',
2659 b'guessmime',
2660 b'guessmime',
2660 default=False,
2661 default=False,
2661 )
2662 )
2662 coreconfigitem(
2663 coreconfigitem(
2663 b'web',
2664 b'web',
2664 b'hidden',
2665 b'hidden',
2665 default=False,
2666 default=False,
2666 )
2667 )
2667 coreconfigitem(
2668 coreconfigitem(
2668 b'web',
2669 b'web',
2669 b'labels',
2670 b'labels',
2670 default=list,
2671 default=list,
2671 )
2672 )
2672 coreconfigitem(
2673 coreconfigitem(
2673 b'web',
2674 b'web',
2674 b'logoimg',
2675 b'logoimg',
2675 default=b'hglogo.png',
2676 default=b'hglogo.png',
2676 )
2677 )
2677 coreconfigitem(
2678 coreconfigitem(
2678 b'web',
2679 b'web',
2679 b'logourl',
2680 b'logourl',
2680 default=b'https://mercurial-scm.org/',
2681 default=b'https://mercurial-scm.org/',
2681 )
2682 )
2682 coreconfigitem(
2683 coreconfigitem(
2683 b'web',
2684 b'web',
2684 b'accesslog',
2685 b'accesslog',
2685 default=b'-',
2686 default=b'-',
2686 )
2687 )
2687 coreconfigitem(
2688 coreconfigitem(
2688 b'web',
2689 b'web',
2689 b'address',
2690 b'address',
2690 default=b'',
2691 default=b'',
2691 )
2692 )
2692 coreconfigitem(
2693 coreconfigitem(
2693 b'web',
2694 b'web',
2694 b'allow-archive',
2695 b'allow-archive',
2695 alias=[(b'web', b'allow_archive')],
2696 alias=[(b'web', b'allow_archive')],
2696 default=list,
2697 default=list,
2697 )
2698 )
2698 coreconfigitem(
2699 coreconfigitem(
2699 b'web',
2700 b'web',
2700 b'allow_read',
2701 b'allow_read',
2701 default=list,
2702 default=list,
2702 )
2703 )
2703 coreconfigitem(
2704 coreconfigitem(
2704 b'web',
2705 b'web',
2705 b'baseurl',
2706 b'baseurl',
2706 default=None,
2707 default=None,
2707 )
2708 )
2708 coreconfigitem(
2709 coreconfigitem(
2709 b'web',
2710 b'web',
2710 b'cacerts',
2711 b'cacerts',
2711 default=None,
2712 default=None,
2712 )
2713 )
2713 coreconfigitem(
2714 coreconfigitem(
2714 b'web',
2715 b'web',
2715 b'certificate',
2716 b'certificate',
2716 default=None,
2717 default=None,
2717 )
2718 )
2718 coreconfigitem(
2719 coreconfigitem(
2719 b'web',
2720 b'web',
2720 b'collapse',
2721 b'collapse',
2721 default=False,
2722 default=False,
2722 )
2723 )
2723 coreconfigitem(
2724 coreconfigitem(
2724 b'web',
2725 b'web',
2725 b'csp',
2726 b'csp',
2726 default=None,
2727 default=None,
2727 )
2728 )
2728 coreconfigitem(
2729 coreconfigitem(
2729 b'web',
2730 b'web',
2730 b'deny_read',
2731 b'deny_read',
2731 default=list,
2732 default=list,
2732 )
2733 )
2733 coreconfigitem(
2734 coreconfigitem(
2734 b'web',
2735 b'web',
2735 b'descend',
2736 b'descend',
2736 default=True,
2737 default=True,
2737 )
2738 )
2738 coreconfigitem(
2739 coreconfigitem(
2739 b'web',
2740 b'web',
2740 b'description',
2741 b'description',
2741 default=b"",
2742 default=b"",
2742 )
2743 )
2743 coreconfigitem(
2744 coreconfigitem(
2744 b'web',
2745 b'web',
2745 b'encoding',
2746 b'encoding',
2746 default=lambda: encoding.encoding,
2747 default=lambda: encoding.encoding,
2747 )
2748 )
2748 coreconfigitem(
2749 coreconfigitem(
2749 b'web',
2750 b'web',
2750 b'errorlog',
2751 b'errorlog',
2751 default=b'-',
2752 default=b'-',
2752 )
2753 )
2753 coreconfigitem(
2754 coreconfigitem(
2754 b'web',
2755 b'web',
2755 b'ipv6',
2756 b'ipv6',
2756 default=False,
2757 default=False,
2757 )
2758 )
2758 coreconfigitem(
2759 coreconfigitem(
2759 b'web',
2760 b'web',
2760 b'maxchanges',
2761 b'maxchanges',
2761 default=10,
2762 default=10,
2762 )
2763 )
2763 coreconfigitem(
2764 coreconfigitem(
2764 b'web',
2765 b'web',
2765 b'maxfiles',
2766 b'maxfiles',
2766 default=10,
2767 default=10,
2767 )
2768 )
2768 coreconfigitem(
2769 coreconfigitem(
2769 b'web',
2770 b'web',
2770 b'maxshortchanges',
2771 b'maxshortchanges',
2771 default=60,
2772 default=60,
2772 )
2773 )
2773 coreconfigitem(
2774 coreconfigitem(
2774 b'web',
2775 b'web',
2775 b'motd',
2776 b'motd',
2776 default=b'',
2777 default=b'',
2777 )
2778 )
2778 coreconfigitem(
2779 coreconfigitem(
2779 b'web',
2780 b'web',
2780 b'name',
2781 b'name',
2781 default=dynamicdefault,
2782 default=dynamicdefault,
2782 )
2783 )
2783 coreconfigitem(
2784 coreconfigitem(
2784 b'web',
2785 b'web',
2785 b'port',
2786 b'port',
2786 default=8000,
2787 default=8000,
2787 )
2788 )
2788 coreconfigitem(
2789 coreconfigitem(
2789 b'web',
2790 b'web',
2790 b'prefix',
2791 b'prefix',
2791 default=b'',
2792 default=b'',
2792 )
2793 )
2793 coreconfigitem(
2794 coreconfigitem(
2794 b'web',
2795 b'web',
2795 b'push_ssl',
2796 b'push_ssl',
2796 default=True,
2797 default=True,
2797 )
2798 )
2798 coreconfigitem(
2799 coreconfigitem(
2799 b'web',
2800 b'web',
2800 b'refreshinterval',
2801 b'refreshinterval',
2801 default=20,
2802 default=20,
2802 )
2803 )
2803 coreconfigitem(
2804 coreconfigitem(
2804 b'web',
2805 b'web',
2805 b'server-header',
2806 b'server-header',
2806 default=None,
2807 default=None,
2807 )
2808 )
2808 coreconfigitem(
2809 coreconfigitem(
2809 b'web',
2810 b'web',
2810 b'static',
2811 b'static',
2811 default=None,
2812 default=None,
2812 )
2813 )
2813 coreconfigitem(
2814 coreconfigitem(
2814 b'web',
2815 b'web',
2815 b'staticurl',
2816 b'staticurl',
2816 default=None,
2817 default=None,
2817 )
2818 )
2818 coreconfigitem(
2819 coreconfigitem(
2819 b'web',
2820 b'web',
2820 b'stripes',
2821 b'stripes',
2821 default=1,
2822 default=1,
2822 )
2823 )
2823 coreconfigitem(
2824 coreconfigitem(
2824 b'web',
2825 b'web',
2825 b'style',
2826 b'style',
2826 default=b'paper',
2827 default=b'paper',
2827 )
2828 )
2828 coreconfigitem(
2829 coreconfigitem(
2829 b'web',
2830 b'web',
2830 b'templates',
2831 b'templates',
2831 default=None,
2832 default=None,
2832 )
2833 )
2833 coreconfigitem(
2834 coreconfigitem(
2834 b'web',
2835 b'web',
2835 b'view',
2836 b'view',
2836 default=b'served',
2837 default=b'served',
2837 experimental=True,
2838 experimental=True,
2838 )
2839 )
2839 coreconfigitem(
2840 coreconfigitem(
2840 b'worker',
2841 b'worker',
2841 b'backgroundclose',
2842 b'backgroundclose',
2842 default=dynamicdefault,
2843 default=dynamicdefault,
2843 )
2844 )
2844 # Windows defaults to a limit of 512 open files. A buffer of 128
2845 # Windows defaults to a limit of 512 open files. A buffer of 128
2845 # should give us enough headway.
2846 # should give us enough headway.
2846 coreconfigitem(
2847 coreconfigitem(
2847 b'worker',
2848 b'worker',
2848 b'backgroundclosemaxqueue',
2849 b'backgroundclosemaxqueue',
2849 default=384,
2850 default=384,
2850 )
2851 )
2851 coreconfigitem(
2852 coreconfigitem(
2852 b'worker',
2853 b'worker',
2853 b'backgroundcloseminfilecount',
2854 b'backgroundcloseminfilecount',
2854 default=2048,
2855 default=2048,
2855 )
2856 )
2856 coreconfigitem(
2857 coreconfigitem(
2857 b'worker',
2858 b'worker',
2858 b'backgroundclosethreadcount',
2859 b'backgroundclosethreadcount',
2859 default=4,
2860 default=4,
2860 )
2861 )
2861 coreconfigitem(
2862 coreconfigitem(
2862 b'worker',
2863 b'worker',
2863 b'enabled',
2864 b'enabled',
2864 default=True,
2865 default=True,
2865 )
2866 )
2866 coreconfigitem(
2867 coreconfigitem(
2867 b'worker',
2868 b'worker',
2868 b'numcpus',
2869 b'numcpus',
2869 default=None,
2870 default=None,
2870 )
2871 )
2871
2872
2872 # Rebase related configuration moved to core because other extension are doing
2873 # Rebase related configuration moved to core because other extension are doing
2873 # strange things. For example, shelve import the extensions to reuse some bit
2874 # strange things. For example, shelve import the extensions to reuse some bit
2874 # without formally loading it.
2875 # without formally loading it.
2875 coreconfigitem(
2876 coreconfigitem(
2876 b'commands',
2877 b'commands',
2877 b'rebase.requiredest',
2878 b'rebase.requiredest',
2878 default=False,
2879 default=False,
2879 )
2880 )
2880 coreconfigitem(
2881 coreconfigitem(
2881 b'experimental',
2882 b'experimental',
2882 b'rebaseskipobsolete',
2883 b'rebaseskipobsolete',
2883 default=True,
2884 default=True,
2884 )
2885 )
2885 coreconfigitem(
2886 coreconfigitem(
2886 b'rebase',
2887 b'rebase',
2887 b'singletransaction',
2888 b'singletransaction',
2888 default=False,
2889 default=False,
2889 )
2890 )
2890 coreconfigitem(
2891 coreconfigitem(
2891 b'rebase',
2892 b'rebase',
2892 b'experimental.inmemory',
2893 b'experimental.inmemory',
2893 default=False,
2894 default=False,
2894 )
2895 )
2895
2896
2896 # This setting controls creation of a rebase_source extra field
2897 # This setting controls creation of a rebase_source extra field
2897 # during rebase. When False, no such field is created. This is
2898 # during rebase. When False, no such field is created. This is
2898 # useful eg for incrementally converting changesets and then
2899 # useful eg for incrementally converting changesets and then
2899 # rebasing them onto an existing repo.
2900 # rebasing them onto an existing repo.
2900 # WARNING: this is an advanced setting reserved for people who know
2901 # WARNING: this is an advanced setting reserved for people who know
2901 # exactly what they are doing. Misuse of this setting can easily
2902 # exactly what they are doing. Misuse of this setting can easily
2902 # result in obsmarker cycles and a vivid headache.
2903 # result in obsmarker cycles and a vivid headache.
2903 coreconfigitem(
2904 coreconfigitem(
2904 b'rebase',
2905 b'rebase',
2905 b'store-source',
2906 b'store-source',
2906 default=True,
2907 default=True,
2907 experimental=True,
2908 experimental=True,
2908 )
2909 )
@@ -1,2303 +1,2308 b''
1 # scmutil.py - Mercurial core utility functions
1 # scmutil.py - Mercurial core utility functions
2 #
2 #
3 # Copyright Olivia Mackall <olivia@selenic.com>
3 # Copyright Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import binascii
9 import binascii
10 import errno
10 import errno
11 import glob
11 import glob
12 import os
12 import os
13 import posixpath
13 import posixpath
14 import re
14 import re
15 import subprocess
15 import subprocess
16 import weakref
16 import weakref
17
17
18 from .i18n import _
18 from .i18n import _
19 from .node import (
19 from .node import (
20 bin,
20 bin,
21 hex,
21 hex,
22 nullrev,
22 nullrev,
23 short,
23 short,
24 wdirrev,
24 wdirrev,
25 )
25 )
26 from .pycompat import getattr
26 from .pycompat import getattr
27 from .thirdparty import attr
27 from .thirdparty import attr
28 from . import (
28 from . import (
29 copies as copiesmod,
29 copies as copiesmod,
30 encoding,
30 encoding,
31 error,
31 error,
32 match as matchmod,
32 match as matchmod,
33 obsolete,
33 obsolete,
34 obsutil,
34 obsutil,
35 pathutil,
35 pathutil,
36 phases,
36 phases,
37 policy,
37 policy,
38 pycompat,
38 pycompat,
39 requirements as requirementsmod,
39 requirements as requirementsmod,
40 revsetlang,
40 revsetlang,
41 similar,
41 similar,
42 smartset,
42 smartset,
43 url,
43 url,
44 util,
44 util,
45 vfs,
45 vfs,
46 )
46 )
47
47
48 from .utils import (
48 from .utils import (
49 hashutil,
49 hashutil,
50 procutil,
50 procutil,
51 stringutil,
51 stringutil,
52 )
52 )
53
53
54 if pycompat.iswindows:
54 if pycompat.iswindows:
55 from . import scmwindows as scmplatform
55 from . import scmwindows as scmplatform
56 else:
56 else:
57 from . import scmposix as scmplatform
57 from . import scmposix as scmplatform
58
58
59 parsers = policy.importmod('parsers')
59 parsers = policy.importmod('parsers')
60 rustrevlog = policy.importrust('revlog')
60 rustrevlog = policy.importrust('revlog')
61
61
62 termsize = scmplatform.termsize
62 termsize = scmplatform.termsize
63
63
64
64
65 @attr.s(slots=True, repr=False)
65 @attr.s(slots=True, repr=False)
66 class status:
66 class status:
67 """Struct with a list of files per status.
67 """Struct with a list of files per status.
68
68
69 The 'deleted', 'unknown' and 'ignored' properties are only
69 The 'deleted', 'unknown' and 'ignored' properties are only
70 relevant to the working copy.
70 relevant to the working copy.
71 """
71 """
72
72
73 modified = attr.ib(default=attr.Factory(list))
73 modified = attr.ib(default=attr.Factory(list))
74 added = attr.ib(default=attr.Factory(list))
74 added = attr.ib(default=attr.Factory(list))
75 removed = attr.ib(default=attr.Factory(list))
75 removed = attr.ib(default=attr.Factory(list))
76 deleted = attr.ib(default=attr.Factory(list))
76 deleted = attr.ib(default=attr.Factory(list))
77 unknown = attr.ib(default=attr.Factory(list))
77 unknown = attr.ib(default=attr.Factory(list))
78 ignored = attr.ib(default=attr.Factory(list))
78 ignored = attr.ib(default=attr.Factory(list))
79 clean = attr.ib(default=attr.Factory(list))
79 clean = attr.ib(default=attr.Factory(list))
80
80
81 def __iter__(self):
81 def __iter__(self):
82 yield self.modified
82 yield self.modified
83 yield self.added
83 yield self.added
84 yield self.removed
84 yield self.removed
85 yield self.deleted
85 yield self.deleted
86 yield self.unknown
86 yield self.unknown
87 yield self.ignored
87 yield self.ignored
88 yield self.clean
88 yield self.clean
89
89
90 def __repr__(self):
90 def __repr__(self):
91 return (
91 return (
92 r'<status modified=%s, added=%s, removed=%s, deleted=%s, '
92 r'<status modified=%s, added=%s, removed=%s, deleted=%s, '
93 r'unknown=%s, ignored=%s, clean=%s>'
93 r'unknown=%s, ignored=%s, clean=%s>'
94 ) % tuple(pycompat.sysstr(stringutil.pprint(v)) for v in self)
94 ) % tuple(pycompat.sysstr(stringutil.pprint(v)) for v in self)
95
95
96
96
97 def itersubrepos(ctx1, ctx2):
97 def itersubrepos(ctx1, ctx2):
98 """find subrepos in ctx1 or ctx2"""
98 """find subrepos in ctx1 or ctx2"""
99 # Create a (subpath, ctx) mapping where we prefer subpaths from
99 # Create a (subpath, ctx) mapping where we prefer subpaths from
100 # ctx1. The subpaths from ctx2 are important when the .hgsub file
100 # ctx1. The subpaths from ctx2 are important when the .hgsub file
101 # has been modified (in ctx2) but not yet committed (in ctx1).
101 # has been modified (in ctx2) but not yet committed (in ctx1).
102 subpaths = dict.fromkeys(ctx2.substate, ctx2)
102 subpaths = dict.fromkeys(ctx2.substate, ctx2)
103 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
103 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
104
104
105 missing = set()
105 missing = set()
106
106
107 for subpath in ctx2.substate:
107 for subpath in ctx2.substate:
108 if subpath not in ctx1.substate:
108 if subpath not in ctx1.substate:
109 del subpaths[subpath]
109 del subpaths[subpath]
110 missing.add(subpath)
110 missing.add(subpath)
111
111
112 for subpath, ctx in sorted(subpaths.items()):
112 for subpath, ctx in sorted(subpaths.items()):
113 yield subpath, ctx.sub(subpath)
113 yield subpath, ctx.sub(subpath)
114
114
115 # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
115 # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
116 # status and diff will have an accurate result when it does
116 # status and diff will have an accurate result when it does
117 # 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
117 # 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
118 # against itself.
118 # against itself.
119 for subpath in missing:
119 for subpath in missing:
120 yield subpath, ctx2.nullsub(subpath, ctx1)
120 yield subpath, ctx2.nullsub(subpath, ctx1)
121
121
122
122
123 def nochangesfound(ui, repo, excluded=None):
123 def nochangesfound(ui, repo, excluded=None):
124 """Report no changes for push/pull, excluded is None or a list of
124 """Report no changes for push/pull, excluded is None or a list of
125 nodes excluded from the push/pull.
125 nodes excluded from the push/pull.
126 """
126 """
127 secretlist = []
127 secretlist = []
128 if excluded:
128 if excluded:
129 for n in excluded:
129 for n in excluded:
130 ctx = repo[n]
130 ctx = repo[n]
131 if ctx.phase() >= phases.secret and not ctx.extinct():
131 if ctx.phase() >= phases.secret and not ctx.extinct():
132 secretlist.append(n)
132 secretlist.append(n)
133
133
134 if secretlist:
134 if secretlist:
135 ui.status(
135 ui.status(
136 _(b"no changes found (ignored %d secret changesets)\n")
136 _(b"no changes found (ignored %d secret changesets)\n")
137 % len(secretlist)
137 % len(secretlist)
138 )
138 )
139 else:
139 else:
140 ui.status(_(b"no changes found\n"))
140 ui.status(_(b"no changes found\n"))
141
141
142
142
143 def callcatch(ui, func):
143 def callcatch(ui, func):
144 """call func() with global exception handling
144 """call func() with global exception handling
145
145
146 return func() if no exception happens. otherwise do some error handling
146 return func() if no exception happens. otherwise do some error handling
147 and return an exit code accordingly. does not handle all exceptions.
147 and return an exit code accordingly. does not handle all exceptions.
148 """
148 """
149 coarse_exit_code = -1
149 coarse_exit_code = -1
150 detailed_exit_code = -1
150 detailed_exit_code = -1
151 try:
151 try:
152 try:
152 try:
153 return func()
153 return func()
154 except: # re-raises
154 except: # re-raises
155 ui.traceback()
155 ui.traceback()
156 raise
156 raise
157 # Global exception handling, alphabetically
157 # Global exception handling, alphabetically
158 # Mercurial-specific first, followed by built-in and library exceptions
158 # Mercurial-specific first, followed by built-in and library exceptions
159 except error.LockHeld as inst:
159 except error.LockHeld as inst:
160 detailed_exit_code = 20
160 detailed_exit_code = 20
161 if inst.errno == errno.ETIMEDOUT:
161 if inst.errno == errno.ETIMEDOUT:
162 reason = _(b'timed out waiting for lock held by %r') % (
162 reason = _(b'timed out waiting for lock held by %r') % (
163 pycompat.bytestr(inst.locker)
163 pycompat.bytestr(inst.locker)
164 )
164 )
165 else:
165 else:
166 reason = _(b'lock held by %r') % inst.locker
166 reason = _(b'lock held by %r') % inst.locker
167 ui.error(
167 ui.error(
168 _(b"abort: %s: %s\n")
168 _(b"abort: %s: %s\n")
169 % (inst.desc or stringutil.forcebytestr(inst.filename), reason)
169 % (inst.desc or stringutil.forcebytestr(inst.filename), reason)
170 )
170 )
171 if not inst.locker:
171 if not inst.locker:
172 ui.error(_(b"(lock might be very busy)\n"))
172 ui.error(_(b"(lock might be very busy)\n"))
173 except error.LockUnavailable as inst:
173 except error.LockUnavailable as inst:
174 detailed_exit_code = 20
174 detailed_exit_code = 20
175 ui.error(
175 ui.error(
176 _(b"abort: could not lock %s: %s\n")
176 _(b"abort: could not lock %s: %s\n")
177 % (
177 % (
178 inst.desc or stringutil.forcebytestr(inst.filename),
178 inst.desc or stringutil.forcebytestr(inst.filename),
179 encoding.strtolocal(inst.strerror),
179 encoding.strtolocal(inst.strerror),
180 )
180 )
181 )
181 )
182 except error.RepoError as inst:
182 except error.RepoError as inst:
183 if isinstance(inst, error.RepoLookupError):
183 if isinstance(inst, error.RepoLookupError):
184 detailed_exit_code = 10
184 detailed_exit_code = 10
185 ui.error(_(b"abort: %s\n") % inst)
185 ui.error(_(b"abort: %s\n") % inst)
186 if inst.hint:
186 if inst.hint:
187 ui.error(_(b"(%s)\n") % inst.hint)
187 ui.error(_(b"(%s)\n") % inst.hint)
188 except error.ResponseError as inst:
188 except error.ResponseError as inst:
189 ui.error(_(b"abort: %s") % inst.args[0])
189 ui.error(_(b"abort: %s") % inst.args[0])
190 msg = inst.args[1]
190 msg = inst.args[1]
191 if isinstance(msg, type(u'')):
191 if isinstance(msg, type(u'')):
192 msg = pycompat.sysbytes(msg)
192 msg = pycompat.sysbytes(msg)
193 if msg is None:
193 if msg is None:
194 ui.error(b"\n")
194 ui.error(b"\n")
195 elif not isinstance(msg, bytes):
195 elif not isinstance(msg, bytes):
196 ui.error(b" %r\n" % (msg,))
196 ui.error(b" %r\n" % (msg,))
197 elif not msg:
197 elif not msg:
198 ui.error(_(b" empty string\n"))
198 ui.error(_(b" empty string\n"))
199 else:
199 else:
200 ui.error(b"\n%r\n" % pycompat.bytestr(stringutil.ellipsis(msg)))
200 ui.error(b"\n%r\n" % pycompat.bytestr(stringutil.ellipsis(msg)))
201 except error.CensoredNodeError as inst:
201 except error.CensoredNodeError as inst:
202 ui.error(_(b"abort: file censored %s\n") % inst)
202 ui.error(_(b"abort: file censored %s\n") % inst)
203 except error.WdirUnsupported:
203 except error.WdirUnsupported:
204 ui.error(_(b"abort: working directory revision cannot be specified\n"))
204 ui.error(_(b"abort: working directory revision cannot be specified\n"))
205 except error.Error as inst:
205 except error.Error as inst:
206 if inst.detailed_exit_code is not None:
206 if inst.detailed_exit_code is not None:
207 detailed_exit_code = inst.detailed_exit_code
207 detailed_exit_code = inst.detailed_exit_code
208 if inst.coarse_exit_code is not None:
208 if inst.coarse_exit_code is not None:
209 coarse_exit_code = inst.coarse_exit_code
209 coarse_exit_code = inst.coarse_exit_code
210 ui.error(inst.format())
210 ui.error(inst.format())
211 except error.WorkerError as inst:
211 except error.WorkerError as inst:
212 # Don't print a message -- the worker already should have
212 # Don't print a message -- the worker already should have
213 return inst.status_code
213 return inst.status_code
214 except ImportError as inst:
214 except ImportError as inst:
215 ui.error(_(b"abort: %s\n") % stringutil.forcebytestr(inst))
215 ui.error(_(b"abort: %s\n") % stringutil.forcebytestr(inst))
216 m = stringutil.forcebytestr(inst).split()[-1]
216 m = stringutil.forcebytestr(inst).split()[-1]
217 if m in b"mpatch bdiff".split():
217 if m in b"mpatch bdiff".split():
218 ui.error(_(b"(did you forget to compile extensions?)\n"))
218 ui.error(_(b"(did you forget to compile extensions?)\n"))
219 elif m in b"zlib".split():
219 elif m in b"zlib".split():
220 ui.error(_(b"(is your Python install correct?)\n"))
220 ui.error(_(b"(is your Python install correct?)\n"))
221 except util.urlerr.httperror as inst:
221 except util.urlerr.httperror as inst:
222 detailed_exit_code = 100
222 detailed_exit_code = 100
223 ui.error(_(b"abort: %s\n") % stringutil.forcebytestr(inst))
223 ui.error(_(b"abort: %s\n") % stringutil.forcebytestr(inst))
224 except util.urlerr.urlerror as inst:
224 except util.urlerr.urlerror as inst:
225 detailed_exit_code = 100
225 detailed_exit_code = 100
226 try: # usually it is in the form (errno, strerror)
226 try: # usually it is in the form (errno, strerror)
227 reason = inst.reason.args[1]
227 reason = inst.reason.args[1]
228 except (AttributeError, IndexError):
228 except (AttributeError, IndexError):
229 # it might be anything, for example a string
229 # it might be anything, for example a string
230 reason = inst.reason
230 reason = inst.reason
231 if isinstance(reason, str):
231 if isinstance(reason, str):
232 # SSLError of Python 2.7.9 contains a unicode
232 # SSLError of Python 2.7.9 contains a unicode
233 reason = encoding.unitolocal(reason)
233 reason = encoding.unitolocal(reason)
234 ui.error(_(b"abort: error: %s\n") % stringutil.forcebytestr(reason))
234 ui.error(_(b"abort: error: %s\n") % stringutil.forcebytestr(reason))
235 except (IOError, OSError) as inst:
235 except (IOError, OSError) as inst:
236 if (
236 if (
237 util.safehasattr(inst, b"args")
237 util.safehasattr(inst, b"args")
238 and inst.args
238 and inst.args
239 and inst.args[0] == errno.EPIPE
239 and inst.args[0] == errno.EPIPE
240 ):
240 ):
241 pass
241 pass
242 elif getattr(inst, "strerror", None): # common IOError or OSError
242 elif getattr(inst, "strerror", None): # common IOError or OSError
243 if getattr(inst, "filename", None) is not None:
243 if getattr(inst, "filename", None) is not None:
244 ui.error(
244 ui.error(
245 _(b"abort: %s: '%s'\n")
245 _(b"abort: %s: '%s'\n")
246 % (
246 % (
247 encoding.strtolocal(inst.strerror),
247 encoding.strtolocal(inst.strerror),
248 stringutil.forcebytestr(inst.filename),
248 stringutil.forcebytestr(inst.filename),
249 )
249 )
250 )
250 )
251 else:
251 else:
252 ui.error(_(b"abort: %s\n") % encoding.strtolocal(inst.strerror))
252 ui.error(_(b"abort: %s\n") % encoding.strtolocal(inst.strerror))
253 else: # suspicious IOError
253 else: # suspicious IOError
254 raise
254 raise
255 except MemoryError:
255 except MemoryError:
256 ui.error(_(b"abort: out of memory\n"))
256 ui.error(_(b"abort: out of memory\n"))
257 except SystemExit as inst:
257 except SystemExit as inst:
258 # Commands shouldn't sys.exit directly, but give a return code.
258 # Commands shouldn't sys.exit directly, but give a return code.
259 # Just in case catch this and and pass exit code to caller.
259 # Just in case catch this and and pass exit code to caller.
260 detailed_exit_code = 254
260 detailed_exit_code = 254
261 coarse_exit_code = inst.code
261 coarse_exit_code = inst.code
262
262
263 if ui.configbool(b'ui', b'detailed-exit-code'):
263 if ui.configbool(b'ui', b'detailed-exit-code'):
264 return detailed_exit_code
264 return detailed_exit_code
265 else:
265 else:
266 return coarse_exit_code
266 return coarse_exit_code
267
267
268
268
269 def checknewlabel(repo, lbl, kind):
269 def checknewlabel(repo, lbl, kind):
270 # Do not use the "kind" parameter in ui output.
270 # Do not use the "kind" parameter in ui output.
271 # It makes strings difficult to translate.
271 # It makes strings difficult to translate.
272 if lbl in [b'tip', b'.', b'null']:
272 if lbl in [b'tip', b'.', b'null']:
273 raise error.InputError(_(b"the name '%s' is reserved") % lbl)
273 raise error.InputError(_(b"the name '%s' is reserved") % lbl)
274 for c in (b':', b'\0', b'\n', b'\r'):
274 for c in (b':', b'\0', b'\n', b'\r'):
275 if c in lbl:
275 if c in lbl:
276 raise error.InputError(
276 raise error.InputError(
277 _(b"%r cannot be used in a name") % pycompat.bytestr(c)
277 _(b"%r cannot be used in a name") % pycompat.bytestr(c)
278 )
278 )
279 try:
279 try:
280 int(lbl)
280 int(lbl)
281 raise error.InputError(_(b"cannot use an integer as a name"))
281 raise error.InputError(_(b"cannot use an integer as a name"))
282 except ValueError:
282 except ValueError:
283 pass
283 pass
284 if lbl.strip() != lbl:
284 if lbl.strip() != lbl:
285 raise error.InputError(
285 raise error.InputError(
286 _(b"leading or trailing whitespace in name %r") % lbl
286 _(b"leading or trailing whitespace in name %r") % lbl
287 )
287 )
288
288
289
289
290 def checkfilename(f):
290 def checkfilename(f):
291 '''Check that the filename f is an acceptable filename for a tracked file'''
291 '''Check that the filename f is an acceptable filename for a tracked file'''
292 if b'\r' in f or b'\n' in f:
292 if b'\r' in f or b'\n' in f:
293 raise error.InputError(
293 raise error.InputError(
294 _(b"'\\n' and '\\r' disallowed in filenames: %r")
294 _(b"'\\n' and '\\r' disallowed in filenames: %r")
295 % pycompat.bytestr(f)
295 % pycompat.bytestr(f)
296 )
296 )
297
297
298
298
299 def checkportable(ui, f):
299 def checkportable(ui, f):
300 '''Check if filename f is portable and warn or abort depending on config'''
300 '''Check if filename f is portable and warn or abort depending on config'''
301 checkfilename(f)
301 checkfilename(f)
302 abort, warn = checkportabilityalert(ui)
302 abort, warn = checkportabilityalert(ui)
303 if abort or warn:
303 if abort or warn:
304 msg = util.checkwinfilename(f)
304 msg = util.checkwinfilename(f)
305 if msg:
305 if msg:
306 msg = b"%s: %s" % (msg, procutil.shellquote(f))
306 msg = b"%s: %s" % (msg, procutil.shellquote(f))
307 if abort:
307 if abort:
308 raise error.InputError(msg)
308 raise error.InputError(msg)
309 ui.warn(_(b"warning: %s\n") % msg)
309 ui.warn(_(b"warning: %s\n") % msg)
310
310
311
311
312 def checkportabilityalert(ui):
312 def checkportabilityalert(ui):
313 """check if the user's config requests nothing, a warning, or abort for
313 """check if the user's config requests nothing, a warning, or abort for
314 non-portable filenames"""
314 non-portable filenames"""
315 val = ui.config(b'ui', b'portablefilenames')
315 val = ui.config(b'ui', b'portablefilenames')
316 lval = val.lower()
316 lval = val.lower()
317 bval = stringutil.parsebool(val)
317 bval = stringutil.parsebool(val)
318 abort = pycompat.iswindows or lval == b'abort'
318 abort = pycompat.iswindows or lval == b'abort'
319 warn = bval or lval == b'warn'
319 warn = bval or lval == b'warn'
320 if bval is None and not (warn or abort or lval == b'ignore'):
320 if bval is None and not (warn or abort or lval == b'ignore'):
321 raise error.ConfigError(
321 raise error.ConfigError(
322 _(b"ui.portablefilenames value is invalid ('%s')") % val
322 _(b"ui.portablefilenames value is invalid ('%s')") % val
323 )
323 )
324 return abort, warn
324 return abort, warn
325
325
326
326
327 class casecollisionauditor:
327 class casecollisionauditor:
328 def __init__(self, ui, abort, dirstate):
328 def __init__(self, ui, abort, dirstate):
329 self._ui = ui
329 self._ui = ui
330 self._abort = abort
330 self._abort = abort
331 allfiles = b'\0'.join(dirstate)
331 allfiles = b'\0'.join(dirstate)
332 self._loweredfiles = set(encoding.lower(allfiles).split(b'\0'))
332 self._loweredfiles = set(encoding.lower(allfiles).split(b'\0'))
333 self._dirstate = dirstate
333 self._dirstate = dirstate
334 # The purpose of _newfiles is so that we don't complain about
334 # The purpose of _newfiles is so that we don't complain about
335 # case collisions if someone were to call this object with the
335 # case collisions if someone were to call this object with the
336 # same filename twice.
336 # same filename twice.
337 self._newfiles = set()
337 self._newfiles = set()
338
338
339 def __call__(self, f):
339 def __call__(self, f):
340 if f in self._newfiles:
340 if f in self._newfiles:
341 return
341 return
342 fl = encoding.lower(f)
342 fl = encoding.lower(f)
343 if fl in self._loweredfiles and f not in self._dirstate:
343 if fl in self._loweredfiles and f not in self._dirstate:
344 msg = _(b'possible case-folding collision for %s') % f
344 msg = _(b'possible case-folding collision for %s') % f
345 if self._abort:
345 if self._abort:
346 raise error.StateError(msg)
346 raise error.StateError(msg)
347 self._ui.warn(_(b"warning: %s\n") % msg)
347 self._ui.warn(_(b"warning: %s\n") % msg)
348 self._loweredfiles.add(fl)
348 self._loweredfiles.add(fl)
349 self._newfiles.add(f)
349 self._newfiles.add(f)
350
350
351
351
352 def filteredhash(repo, maxrev, needobsolete=False):
352 def filteredhash(repo, maxrev, needobsolete=False):
353 """build hash of filtered revisions in the current repoview.
353 """build hash of filtered revisions in the current repoview.
354
354
355 Multiple caches perform up-to-date validation by checking that the
355 Multiple caches perform up-to-date validation by checking that the
356 tiprev and tipnode stored in the cache file match the current repository.
356 tiprev and tipnode stored in the cache file match the current repository.
357 However, this is not sufficient for validating repoviews because the set
357 However, this is not sufficient for validating repoviews because the set
358 of revisions in the view may change without the repository tiprev and
358 of revisions in the view may change without the repository tiprev and
359 tipnode changing.
359 tipnode changing.
360
360
361 This function hashes all the revs filtered from the view (and, optionally,
361 This function hashes all the revs filtered from the view (and, optionally,
362 all obsolete revs) up to maxrev and returns that SHA-1 digest.
362 all obsolete revs) up to maxrev and returns that SHA-1 digest.
363 """
363 """
364 cl = repo.changelog
364 cl = repo.changelog
365 if needobsolete:
365 if needobsolete:
366 obsrevs = obsolete.getrevs(repo, b'obsolete')
366 obsrevs = obsolete.getrevs(repo, b'obsolete')
367 if not cl.filteredrevs and not obsrevs:
367 if not cl.filteredrevs and not obsrevs:
368 return None
368 return None
369 key = (maxrev, hash(cl.filteredrevs), hash(obsrevs))
369 key = (maxrev, hash(cl.filteredrevs), hash(obsrevs))
370 else:
370 else:
371 if not cl.filteredrevs:
371 if not cl.filteredrevs:
372 return None
372 return None
373 key = maxrev
373 key = maxrev
374 obsrevs = frozenset()
374 obsrevs = frozenset()
375
375
376 result = cl._filteredrevs_hashcache.get(key)
376 result = cl._filteredrevs_hashcache.get(key)
377 if not result:
377 if not result:
378 revs = sorted(r for r in cl.filteredrevs | obsrevs if r <= maxrev)
378 revs = sorted(r for r in cl.filteredrevs | obsrevs if r <= maxrev)
379 if revs:
379 if revs:
380 s = hashutil.sha1()
380 s = hashutil.sha1()
381 for rev in revs:
381 for rev in revs:
382 s.update(b'%d;' % rev)
382 s.update(b'%d;' % rev)
383 result = s.digest()
383 result = s.digest()
384 cl._filteredrevs_hashcache[key] = result
384 cl._filteredrevs_hashcache[key] = result
385 return result
385 return result
386
386
387
387
388 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
388 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
389 """yield every hg repository under path, always recursively.
389 """yield every hg repository under path, always recursively.
390 The recurse flag will only control recursion into repo working dirs"""
390 The recurse flag will only control recursion into repo working dirs"""
391
391
392 def errhandler(err):
392 def errhandler(err):
393 if err.filename == path:
393 if err.filename == path:
394 raise err
394 raise err
395
395
396 samestat = getattr(os.path, 'samestat', None)
396 samestat = getattr(os.path, 'samestat', None)
397 if followsym and samestat is not None:
397 if followsym and samestat is not None:
398
398
399 def adddir(dirlst, dirname):
399 def adddir(dirlst, dirname):
400 dirstat = os.stat(dirname)
400 dirstat = os.stat(dirname)
401 match = any(samestat(dirstat, lstdirstat) for lstdirstat in dirlst)
401 match = any(samestat(dirstat, lstdirstat) for lstdirstat in dirlst)
402 if not match:
402 if not match:
403 dirlst.append(dirstat)
403 dirlst.append(dirstat)
404 return not match
404 return not match
405
405
406 else:
406 else:
407 followsym = False
407 followsym = False
408
408
409 if (seen_dirs is None) and followsym:
409 if (seen_dirs is None) and followsym:
410 seen_dirs = []
410 seen_dirs = []
411 adddir(seen_dirs, path)
411 adddir(seen_dirs, path)
412 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
412 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
413 dirs.sort()
413 dirs.sort()
414 if b'.hg' in dirs:
414 if b'.hg' in dirs:
415 yield root # found a repository
415 yield root # found a repository
416 qroot = os.path.join(root, b'.hg', b'patches')
416 qroot = os.path.join(root, b'.hg', b'patches')
417 if os.path.isdir(os.path.join(qroot, b'.hg')):
417 if os.path.isdir(os.path.join(qroot, b'.hg')):
418 yield qroot # we have a patch queue repo here
418 yield qroot # we have a patch queue repo here
419 if recurse:
419 if recurse:
420 # avoid recursing inside the .hg directory
420 # avoid recursing inside the .hg directory
421 dirs.remove(b'.hg')
421 dirs.remove(b'.hg')
422 else:
422 else:
423 dirs[:] = [] # don't descend further
423 dirs[:] = [] # don't descend further
424 elif followsym:
424 elif followsym:
425 newdirs = []
425 newdirs = []
426 for d in dirs:
426 for d in dirs:
427 fname = os.path.join(root, d)
427 fname = os.path.join(root, d)
428 if adddir(seen_dirs, fname):
428 if adddir(seen_dirs, fname):
429 if os.path.islink(fname):
429 if os.path.islink(fname):
430 for hgname in walkrepos(fname, True, seen_dirs):
430 for hgname in walkrepos(fname, True, seen_dirs):
431 yield hgname
431 yield hgname
432 else:
432 else:
433 newdirs.append(d)
433 newdirs.append(d)
434 dirs[:] = newdirs
434 dirs[:] = newdirs
435
435
436
436
437 def binnode(ctx):
437 def binnode(ctx):
438 """Return binary node id for a given basectx"""
438 """Return binary node id for a given basectx"""
439 node = ctx.node()
439 node = ctx.node()
440 if node is None:
440 if node is None:
441 return ctx.repo().nodeconstants.wdirid
441 return ctx.repo().nodeconstants.wdirid
442 return node
442 return node
443
443
444
444
445 def intrev(ctx):
445 def intrev(ctx):
446 """Return integer for a given basectx that can be used in comparison or
446 """Return integer for a given basectx that can be used in comparison or
447 arithmetic operation"""
447 arithmetic operation"""
448 rev = ctx.rev()
448 rev = ctx.rev()
449 if rev is None:
449 if rev is None:
450 return wdirrev
450 return wdirrev
451 return rev
451 return rev
452
452
453
453
454 def formatchangeid(ctx):
454 def formatchangeid(ctx):
455 """Format changectx as '{rev}:{node|formatnode}', which is the default
455 """Format changectx as '{rev}:{node|formatnode}', which is the default
456 template provided by logcmdutil.changesettemplater"""
456 template provided by logcmdutil.changesettemplater"""
457 repo = ctx.repo()
457 repo = ctx.repo()
458 return formatrevnode(repo.ui, intrev(ctx), binnode(ctx))
458 return formatrevnode(repo.ui, intrev(ctx), binnode(ctx))
459
459
460
460
461 def formatrevnode(ui, rev, node):
461 def formatrevnode(ui, rev, node):
462 """Format given revision and node depending on the current verbosity"""
462 """Format given revision and node depending on the current verbosity"""
463 if ui.debugflag:
463 if ui.debugflag:
464 hexfunc = hex
464 hexfunc = hex
465 else:
465 else:
466 hexfunc = short
466 hexfunc = short
467 return b'%d:%s' % (rev, hexfunc(node))
467 return b'%d:%s' % (rev, hexfunc(node))
468
468
469
469
470 def resolvehexnodeidprefix(repo, prefix):
470 def resolvehexnodeidprefix(repo, prefix):
471 if prefix.startswith(b'x'):
471 if prefix.startswith(b'x'):
472 prefix = prefix[1:]
472 prefix = prefix[1:]
473 try:
473 try:
474 # Uses unfiltered repo because it's faster when prefix is ambiguous/
474 # Uses unfiltered repo because it's faster when prefix is ambiguous/
475 # This matches the shortesthexnodeidprefix() function below.
475 # This matches the shortesthexnodeidprefix() function below.
476 node = repo.unfiltered().changelog._partialmatch(prefix)
476 node = repo.unfiltered().changelog._partialmatch(prefix)
477 except error.AmbiguousPrefixLookupError:
477 except error.AmbiguousPrefixLookupError:
478 revset = repo.ui.config(
478 revset = repo.ui.config(
479 b'experimental', b'revisions.disambiguatewithin'
479 b'experimental', b'revisions.disambiguatewithin'
480 )
480 )
481 if revset:
481 if revset:
482 # Clear config to avoid infinite recursion
482 # Clear config to avoid infinite recursion
483 configoverrides = {
483 configoverrides = {
484 (b'experimental', b'revisions.disambiguatewithin'): None
484 (b'experimental', b'revisions.disambiguatewithin'): None
485 }
485 }
486 with repo.ui.configoverride(configoverrides):
486 with repo.ui.configoverride(configoverrides):
487 revs = repo.anyrevs([revset], user=True)
487 revs = repo.anyrevs([revset], user=True)
488 matches = []
488 matches = []
489 for rev in revs:
489 for rev in revs:
490 node = repo.changelog.node(rev)
490 node = repo.changelog.node(rev)
491 if hex(node).startswith(prefix):
491 if hex(node).startswith(prefix):
492 matches.append(node)
492 matches.append(node)
493 if len(matches) == 1:
493 if len(matches) == 1:
494 return matches[0]
494 return matches[0]
495 raise
495 raise
496 if node is None:
496 if node is None:
497 return
497 return
498 repo.changelog.rev(node) # make sure node isn't filtered
498 repo.changelog.rev(node) # make sure node isn't filtered
499 return node
499 return node
500
500
501
501
502 def mayberevnum(repo, prefix):
502 def mayberevnum(repo, prefix):
503 """Checks if the given prefix may be mistaken for a revision number"""
503 """Checks if the given prefix may be mistaken for a revision number"""
504 try:
504 try:
505 i = int(prefix)
505 i = int(prefix)
506 # if we are a pure int, then starting with zero will not be
506 # if we are a pure int, then starting with zero will not be
507 # confused as a rev; or, obviously, if the int is larger
507 # confused as a rev; or, obviously, if the int is larger
508 # than the value of the tip rev. We still need to disambiguate if
508 # than the value of the tip rev. We still need to disambiguate if
509 # prefix == '0', since that *is* a valid revnum.
509 # prefix == '0', since that *is* a valid revnum.
510 if (prefix != b'0' and prefix[0:1] == b'0') or i >= len(repo):
510 if (prefix != b'0' and prefix[0:1] == b'0') or i >= len(repo):
511 return False
511 return False
512 return True
512 return True
513 except ValueError:
513 except ValueError:
514 return False
514 return False
515
515
516
516
517 def shortesthexnodeidprefix(repo, node, minlength=1, cache=None):
517 def shortesthexnodeidprefix(repo, node, minlength=1, cache=None):
518 """Find the shortest unambiguous prefix that matches hexnode.
518 """Find the shortest unambiguous prefix that matches hexnode.
519
519
520 If "cache" is not None, it must be a dictionary that can be used for
520 If "cache" is not None, it must be a dictionary that can be used for
521 caching between calls to this method.
521 caching between calls to this method.
522 """
522 """
523 # _partialmatch() of filtered changelog could take O(len(repo)) time,
523 # _partialmatch() of filtered changelog could take O(len(repo)) time,
524 # which would be unacceptably slow. so we look for hash collision in
524 # which would be unacceptably slow. so we look for hash collision in
525 # unfiltered space, which means some hashes may be slightly longer.
525 # unfiltered space, which means some hashes may be slightly longer.
526
526
527 minlength = max(minlength, 1)
527 minlength = max(minlength, 1)
528
528
529 def disambiguate(prefix):
529 def disambiguate(prefix):
530 """Disambiguate against revnums."""
530 """Disambiguate against revnums."""
531 if repo.ui.configbool(b'experimental', b'revisions.prefixhexnode'):
531 if repo.ui.configbool(b'experimental', b'revisions.prefixhexnode'):
532 if mayberevnum(repo, prefix):
532 if mayberevnum(repo, prefix):
533 return b'x' + prefix
533 return b'x' + prefix
534 else:
534 else:
535 return prefix
535 return prefix
536
536
537 hexnode = hex(node)
537 hexnode = hex(node)
538 for length in range(len(prefix), len(hexnode) + 1):
538 for length in range(len(prefix), len(hexnode) + 1):
539 prefix = hexnode[:length]
539 prefix = hexnode[:length]
540 if not mayberevnum(repo, prefix):
540 if not mayberevnum(repo, prefix):
541 return prefix
541 return prefix
542
542
543 cl = repo.unfiltered().changelog
543 cl = repo.unfiltered().changelog
544 revset = repo.ui.config(b'experimental', b'revisions.disambiguatewithin')
544 revset = repo.ui.config(b'experimental', b'revisions.disambiguatewithin')
545 if revset:
545 if revset:
546 revs = None
546 revs = None
547 if cache is not None:
547 if cache is not None:
548 revs = cache.get(b'disambiguationrevset')
548 revs = cache.get(b'disambiguationrevset')
549 if revs is None:
549 if revs is None:
550 revs = repo.anyrevs([revset], user=True)
550 revs = repo.anyrevs([revset], user=True)
551 if cache is not None:
551 if cache is not None:
552 cache[b'disambiguationrevset'] = revs
552 cache[b'disambiguationrevset'] = revs
553 if cl.rev(node) in revs:
553 if cl.rev(node) in revs:
554 hexnode = hex(node)
554 hexnode = hex(node)
555 nodetree = None
555 nodetree = None
556 if cache is not None:
556 if cache is not None:
557 nodetree = cache.get(b'disambiguationnodetree')
557 nodetree = cache.get(b'disambiguationnodetree')
558 if not nodetree:
558 if not nodetree:
559 if util.safehasattr(parsers, 'nodetree'):
559 if util.safehasattr(parsers, 'nodetree'):
560 # The CExt is the only implementation to provide a nodetree
560 # The CExt is the only implementation to provide a nodetree
561 # class so far.
561 # class so far.
562 index = cl.index
562 index = cl.index
563 if util.safehasattr(index, 'get_cindex'):
563 if util.safehasattr(index, 'get_cindex'):
564 # the rust wrapped need to give access to its internal index
564 # the rust wrapped need to give access to its internal index
565 index = index.get_cindex()
565 index = index.get_cindex()
566 nodetree = parsers.nodetree(index, len(revs))
566 nodetree = parsers.nodetree(index, len(revs))
567 for r in revs:
567 for r in revs:
568 nodetree.insert(r)
568 nodetree.insert(r)
569 if cache is not None:
569 if cache is not None:
570 cache[b'disambiguationnodetree'] = nodetree
570 cache[b'disambiguationnodetree'] = nodetree
571 if nodetree is not None:
571 if nodetree is not None:
572 length = max(nodetree.shortest(node), minlength)
572 length = max(nodetree.shortest(node), minlength)
573 prefix = hexnode[:length]
573 prefix = hexnode[:length]
574 return disambiguate(prefix)
574 return disambiguate(prefix)
575 for length in range(minlength, len(hexnode) + 1):
575 for length in range(minlength, len(hexnode) + 1):
576 matches = []
576 matches = []
577 prefix = hexnode[:length]
577 prefix = hexnode[:length]
578 for rev in revs:
578 for rev in revs:
579 otherhexnode = repo[rev].hex()
579 otherhexnode = repo[rev].hex()
580 if prefix == otherhexnode[:length]:
580 if prefix == otherhexnode[:length]:
581 matches.append(otherhexnode)
581 matches.append(otherhexnode)
582 if len(matches) == 1:
582 if len(matches) == 1:
583 return disambiguate(prefix)
583 return disambiguate(prefix)
584
584
585 try:
585 try:
586 return disambiguate(cl.shortest(node, minlength))
586 return disambiguate(cl.shortest(node, minlength))
587 except error.LookupError:
587 except error.LookupError:
588 raise error.RepoLookupError()
588 raise error.RepoLookupError()
589
589
590
590
591 def isrevsymbol(repo, symbol):
591 def isrevsymbol(repo, symbol):
592 """Checks if a symbol exists in the repo.
592 """Checks if a symbol exists in the repo.
593
593
594 See revsymbol() for details. Raises error.AmbiguousPrefixLookupError if the
594 See revsymbol() for details. Raises error.AmbiguousPrefixLookupError if the
595 symbol is an ambiguous nodeid prefix.
595 symbol is an ambiguous nodeid prefix.
596 """
596 """
597 try:
597 try:
598 revsymbol(repo, symbol)
598 revsymbol(repo, symbol)
599 return True
599 return True
600 except error.RepoLookupError:
600 except error.RepoLookupError:
601 return False
601 return False
602
602
603
603
604 def revsymbol(repo, symbol):
604 def revsymbol(repo, symbol):
605 """Returns a context given a single revision symbol (as string).
605 """Returns a context given a single revision symbol (as string).
606
606
607 This is similar to revsingle(), but accepts only a single revision symbol,
607 This is similar to revsingle(), but accepts only a single revision symbol,
608 i.e. things like ".", "tip", "1234", "deadbeef", "my-bookmark" work, but
608 i.e. things like ".", "tip", "1234", "deadbeef", "my-bookmark" work, but
609 not "max(public())".
609 not "max(public())".
610 """
610 """
611 if not isinstance(symbol, bytes):
611 if not isinstance(symbol, bytes):
612 msg = (
612 msg = (
613 b"symbol (%s of type %s) was not a string, did you mean "
613 b"symbol (%s of type %s) was not a string, did you mean "
614 b"repo[symbol]?" % (symbol, type(symbol))
614 b"repo[symbol]?" % (symbol, type(symbol))
615 )
615 )
616 raise error.ProgrammingError(msg)
616 raise error.ProgrammingError(msg)
617 try:
617 try:
618 if symbol in (b'.', b'tip', b'null'):
618 if symbol in (b'.', b'tip', b'null'):
619 return repo[symbol]
619 return repo[symbol]
620
620
621 try:
621 try:
622 r = int(symbol)
622 r = int(symbol)
623 if b'%d' % r != symbol:
623 if b'%d' % r != symbol:
624 raise ValueError
624 raise ValueError
625 l = len(repo.changelog)
625 l = len(repo.changelog)
626 if r < 0:
626 if r < 0:
627 r += l
627 r += l
628 if r < 0 or r >= l and r != wdirrev:
628 if r < 0 or r >= l and r != wdirrev:
629 raise ValueError
629 raise ValueError
630 return repo[r]
630 return repo[r]
631 except error.FilteredIndexError:
631 except error.FilteredIndexError:
632 raise
632 raise
633 except (ValueError, OverflowError, IndexError):
633 except (ValueError, OverflowError, IndexError):
634 pass
634 pass
635
635
636 if len(symbol) == 2 * repo.nodeconstants.nodelen:
636 if len(symbol) == 2 * repo.nodeconstants.nodelen:
637 try:
637 try:
638 node = bin(symbol)
638 node = bin(symbol)
639 rev = repo.changelog.rev(node)
639 rev = repo.changelog.rev(node)
640 return repo[rev]
640 return repo[rev]
641 except error.FilteredLookupError:
641 except error.FilteredLookupError:
642 raise
642 raise
643 except (binascii.Error, LookupError):
643 except (binascii.Error, LookupError):
644 pass
644 pass
645
645
646 # look up bookmarks through the name interface
646 # look up bookmarks through the name interface
647 try:
647 try:
648 node = repo.names.singlenode(repo, symbol)
648 node = repo.names.singlenode(repo, symbol)
649 rev = repo.changelog.rev(node)
649 rev = repo.changelog.rev(node)
650 return repo[rev]
650 return repo[rev]
651 except KeyError:
651 except KeyError:
652 pass
652 pass
653
653
654 node = resolvehexnodeidprefix(repo, symbol)
654 node = resolvehexnodeidprefix(repo, symbol)
655 if node is not None:
655 if node is not None:
656 rev = repo.changelog.rev(node)
656 rev = repo.changelog.rev(node)
657 return repo[rev]
657 return repo[rev]
658
658
659 raise error.RepoLookupError(_(b"unknown revision '%s'") % symbol)
659 raise error.RepoLookupError(_(b"unknown revision '%s'") % symbol)
660
660
661 except error.WdirUnsupported:
661 except error.WdirUnsupported:
662 return repo[None]
662 return repo[None]
663 except (
663 except (
664 error.FilteredIndexError,
664 error.FilteredIndexError,
665 error.FilteredLookupError,
665 error.FilteredLookupError,
666 error.FilteredRepoLookupError,
666 error.FilteredRepoLookupError,
667 ):
667 ):
668 raise _filterederror(repo, symbol)
668 raise _filterederror(repo, symbol)
669
669
670
670
671 def _filterederror(repo, changeid):
671 def _filterederror(repo, changeid):
672 """build an exception to be raised about a filtered changeid
672 """build an exception to be raised about a filtered changeid
673
673
674 This is extracted in a function to help extensions (eg: evolve) to
674 This is extracted in a function to help extensions (eg: evolve) to
675 experiment with various message variants."""
675 experiment with various message variants."""
676 if repo.filtername.startswith(b'visible'):
676 if repo.filtername.startswith(b'visible'):
677
677
678 # Check if the changeset is obsolete
678 # Check if the changeset is obsolete
679 unfilteredrepo = repo.unfiltered()
679 unfilteredrepo = repo.unfiltered()
680 ctx = revsymbol(unfilteredrepo, changeid)
680 ctx = revsymbol(unfilteredrepo, changeid)
681
681
682 # If the changeset is obsolete, enrich the message with the reason
682 # If the changeset is obsolete, enrich the message with the reason
683 # that made this changeset not visible
683 # that made this changeset not visible
684 if ctx.obsolete():
684 if ctx.obsolete():
685 msg = obsutil._getfilteredreason(repo, changeid, ctx)
685 msg = obsutil._getfilteredreason(repo, changeid, ctx)
686 else:
686 else:
687 msg = _(b"hidden revision '%s'") % changeid
687 msg = _(b"hidden revision '%s'") % changeid
688
688
689 hint = _(b'use --hidden to access hidden revisions')
689 hint = _(b'use --hidden to access hidden revisions')
690
690
691 return error.FilteredRepoLookupError(msg, hint=hint)
691 return error.FilteredRepoLookupError(msg, hint=hint)
692 msg = _(b"filtered revision '%s' (not in '%s' subset)")
692 msg = _(b"filtered revision '%s' (not in '%s' subset)")
693 msg %= (changeid, repo.filtername)
693 msg %= (changeid, repo.filtername)
694 return error.FilteredRepoLookupError(msg)
694 return error.FilteredRepoLookupError(msg)
695
695
696
696
697 def revsingle(repo, revspec, default=b'.', localalias=None):
697 def revsingle(repo, revspec, default=b'.', localalias=None):
698 if not revspec and revspec != 0:
698 if not revspec and revspec != 0:
699 return repo[default]
699 return repo[default]
700
700
701 l = revrange(repo, [revspec], localalias=localalias)
701 l = revrange(repo, [revspec], localalias=localalias)
702 if not l:
702 if not l:
703 raise error.InputError(_(b'empty revision set'))
703 raise error.InputError(_(b'empty revision set'))
704 return repo[l.last()]
704 return repo[l.last()]
705
705
706
706
707 def _pairspec(revspec):
707 def _pairspec(revspec):
708 tree = revsetlang.parse(revspec)
708 tree = revsetlang.parse(revspec)
709 return tree and tree[0] in (
709 return tree and tree[0] in (
710 b'range',
710 b'range',
711 b'rangepre',
711 b'rangepre',
712 b'rangepost',
712 b'rangepost',
713 b'rangeall',
713 b'rangeall',
714 )
714 )
715
715
716
716
717 def revpair(repo, revs):
717 def revpair(repo, revs):
718 if not revs:
718 if not revs:
719 return repo[b'.'], repo[None]
719 return repo[b'.'], repo[None]
720
720
721 l = revrange(repo, revs)
721 l = revrange(repo, revs)
722
722
723 if not l:
723 if not l:
724 raise error.InputError(_(b'empty revision range'))
724 raise error.InputError(_(b'empty revision range'))
725
725
726 first = l.first()
726 first = l.first()
727 second = l.last()
727 second = l.last()
728
728
729 if (
729 if (
730 first == second
730 first == second
731 and len(revs) >= 2
731 and len(revs) >= 2
732 and not all(revrange(repo, [r]) for r in revs)
732 and not all(revrange(repo, [r]) for r in revs)
733 ):
733 ):
734 raise error.InputError(_(b'empty revision on one side of range'))
734 raise error.InputError(_(b'empty revision on one side of range'))
735
735
736 # if top-level is range expression, the result must always be a pair
736 # if top-level is range expression, the result must always be a pair
737 if first == second and len(revs) == 1 and not _pairspec(revs[0]):
737 if first == second and len(revs) == 1 and not _pairspec(revs[0]):
738 return repo[first], repo[None]
738 return repo[first], repo[None]
739
739
740 return repo[first], repo[second]
740 return repo[first], repo[second]
741
741
742
742
743 def revrange(repo, specs, localalias=None):
743 def revrange(repo, specs, localalias=None):
744 """Execute 1 to many revsets and return the union.
744 """Execute 1 to many revsets and return the union.
745
745
746 This is the preferred mechanism for executing revsets using user-specified
746 This is the preferred mechanism for executing revsets using user-specified
747 config options, such as revset aliases.
747 config options, such as revset aliases.
748
748
749 The revsets specified by ``specs`` will be executed via a chained ``OR``
749 The revsets specified by ``specs`` will be executed via a chained ``OR``
750 expression. If ``specs`` is empty, an empty result is returned.
750 expression. If ``specs`` is empty, an empty result is returned.
751
751
752 ``specs`` can contain integers, in which case they are assumed to be
752 ``specs`` can contain integers, in which case they are assumed to be
753 revision numbers.
753 revision numbers.
754
754
755 It is assumed the revsets are already formatted. If you have arguments
755 It is assumed the revsets are already formatted. If you have arguments
756 that need to be expanded in the revset, call ``revsetlang.formatspec()``
756 that need to be expanded in the revset, call ``revsetlang.formatspec()``
757 and pass the result as an element of ``specs``.
757 and pass the result as an element of ``specs``.
758
758
759 Specifying a single revset is allowed.
759 Specifying a single revset is allowed.
760
760
761 Returns a ``smartset.abstractsmartset`` which is a list-like interface over
761 Returns a ``smartset.abstractsmartset`` which is a list-like interface over
762 integer revisions.
762 integer revisions.
763 """
763 """
764 allspecs = []
764 allspecs = []
765 for spec in specs:
765 for spec in specs:
766 if isinstance(spec, int):
766 if isinstance(spec, int):
767 spec = revsetlang.formatspec(b'%d', spec)
767 spec = revsetlang.formatspec(b'%d', spec)
768 allspecs.append(spec)
768 allspecs.append(spec)
769 return repo.anyrevs(allspecs, user=True, localalias=localalias)
769 return repo.anyrevs(allspecs, user=True, localalias=localalias)
770
770
771
771
772 def increasingwindows(windowsize=8, sizelimit=512):
772 def increasingwindows(windowsize=8, sizelimit=512):
773 while True:
773 while True:
774 yield windowsize
774 yield windowsize
775 if windowsize < sizelimit:
775 if windowsize < sizelimit:
776 windowsize *= 2
776 windowsize *= 2
777
777
778
778
779 def walkchangerevs(repo, revs, makefilematcher, prepare):
779 def walkchangerevs(repo, revs, makefilematcher, prepare):
780 """Iterate over files and the revs in a "windowed" way.
780 """Iterate over files and the revs in a "windowed" way.
781
781
782 Callers most commonly need to iterate backwards over the history
782 Callers most commonly need to iterate backwards over the history
783 in which they are interested. Doing so has awful (quadratic-looking)
783 in which they are interested. Doing so has awful (quadratic-looking)
784 performance, so we use iterators in a "windowed" way.
784 performance, so we use iterators in a "windowed" way.
785
785
786 We walk a window of revisions in the desired order. Within the
786 We walk a window of revisions in the desired order. Within the
787 window, we first walk forwards to gather data, then in the desired
787 window, we first walk forwards to gather data, then in the desired
788 order (usually backwards) to display it.
788 order (usually backwards) to display it.
789
789
790 This function returns an iterator yielding contexts. Before
790 This function returns an iterator yielding contexts. Before
791 yielding each context, the iterator will first call the prepare
791 yielding each context, the iterator will first call the prepare
792 function on each context in the window in forward order."""
792 function on each context in the window in forward order."""
793
793
794 if not revs:
794 if not revs:
795 return []
795 return []
796 change = repo.__getitem__
796 change = repo.__getitem__
797
797
798 def iterate():
798 def iterate():
799 it = iter(revs)
799 it = iter(revs)
800 stopiteration = False
800 stopiteration = False
801 for windowsize in increasingwindows():
801 for windowsize in increasingwindows():
802 nrevs = []
802 nrevs = []
803 for i in range(windowsize):
803 for i in range(windowsize):
804 rev = next(it, None)
804 rev = next(it, None)
805 if rev is None:
805 if rev is None:
806 stopiteration = True
806 stopiteration = True
807 break
807 break
808 nrevs.append(rev)
808 nrevs.append(rev)
809 for rev in sorted(nrevs):
809 for rev in sorted(nrevs):
810 ctx = change(rev)
810 ctx = change(rev)
811 prepare(ctx, makefilematcher(ctx))
811 prepare(ctx, makefilematcher(ctx))
812 for rev in nrevs:
812 for rev in nrevs:
813 yield change(rev)
813 yield change(rev)
814
814
815 if stopiteration:
815 if stopiteration:
816 break
816 break
817
817
818 return iterate()
818 return iterate()
819
819
820
820
821 def meaningfulparents(repo, ctx):
821 def meaningfulparents(repo, ctx):
822 """Return list of meaningful (or all if debug) parentrevs for rev.
822 """Return list of meaningful (or all if debug) parentrevs for rev.
823
823
824 For merges (two non-nullrev revisions) both parents are meaningful.
824 For merges (two non-nullrev revisions) both parents are meaningful.
825 Otherwise the first parent revision is considered meaningful if it
825 Otherwise the first parent revision is considered meaningful if it
826 is not the preceding revision.
826 is not the preceding revision.
827 """
827 """
828 parents = ctx.parents()
828 parents = ctx.parents()
829 if len(parents) > 1:
829 if len(parents) > 1:
830 return parents
830 return parents
831 if repo.ui.debugflag:
831 if repo.ui.debugflag:
832 return [parents[0], repo[nullrev]]
832 return [parents[0], repo[nullrev]]
833 if parents[0].rev() >= intrev(ctx) - 1:
833 if parents[0].rev() >= intrev(ctx) - 1:
834 return []
834 return []
835 return parents
835 return parents
836
836
837
837
838 def getuipathfn(repo, legacyrelativevalue=False, forcerelativevalue=None):
838 def getuipathfn(repo, legacyrelativevalue=False, forcerelativevalue=None):
839 """Return a function that produced paths for presenting to the user.
839 """Return a function that produced paths for presenting to the user.
840
840
841 The returned function takes a repo-relative path and produces a path
841 The returned function takes a repo-relative path and produces a path
842 that can be presented in the UI.
842 that can be presented in the UI.
843
843
844 Depending on the value of ui.relative-paths, either a repo-relative or
844 Depending on the value of ui.relative-paths, either a repo-relative or
845 cwd-relative path will be produced.
845 cwd-relative path will be produced.
846
846
847 legacyrelativevalue is the value to use if ui.relative-paths=legacy
847 legacyrelativevalue is the value to use if ui.relative-paths=legacy
848
848
849 If forcerelativevalue is not None, then that value will be used regardless
849 If forcerelativevalue is not None, then that value will be used regardless
850 of what ui.relative-paths is set to.
850 of what ui.relative-paths is set to.
851 """
851 """
852 if forcerelativevalue is not None:
852 if forcerelativevalue is not None:
853 relative = forcerelativevalue
853 relative = forcerelativevalue
854 else:
854 else:
855 config = repo.ui.config(b'ui', b'relative-paths')
855 config = repo.ui.config(b'ui', b'relative-paths')
856 if config == b'legacy':
856 if config == b'legacy':
857 relative = legacyrelativevalue
857 relative = legacyrelativevalue
858 else:
858 else:
859 relative = stringutil.parsebool(config)
859 relative = stringutil.parsebool(config)
860 if relative is None:
860 if relative is None:
861 raise error.ConfigError(
861 raise error.ConfigError(
862 _(b"ui.relative-paths is not a boolean ('%s')") % config
862 _(b"ui.relative-paths is not a boolean ('%s')") % config
863 )
863 )
864
864
865 if relative:
865 if relative:
866 cwd = repo.getcwd()
866 cwd = repo.getcwd()
867 if cwd != b'':
867 if cwd != b'':
868 # this branch would work even if cwd == b'' (ie cwd = repo
868 # this branch would work even if cwd == b'' (ie cwd = repo
869 # root), but its generality makes the returned function slower
869 # root), but its generality makes the returned function slower
870 pathto = repo.pathto
870 pathto = repo.pathto
871 return lambda f: pathto(f, cwd)
871 return lambda f: pathto(f, cwd)
872 if repo.ui.configbool(b'ui', b'slash'):
872 if repo.ui.configbool(b'ui', b'slash'):
873 return lambda f: f
873 return lambda f: f
874 else:
874 else:
875 return util.localpath
875 return util.localpath
876
876
877
877
878 def subdiruipathfn(subpath, uipathfn):
878 def subdiruipathfn(subpath, uipathfn):
879 '''Create a new uipathfn that treats the file as relative to subpath.'''
879 '''Create a new uipathfn that treats the file as relative to subpath.'''
880 return lambda f: uipathfn(posixpath.join(subpath, f))
880 return lambda f: uipathfn(posixpath.join(subpath, f))
881
881
882
882
883 def anypats(pats, opts):
883 def anypats(pats, opts):
884 """Checks if any patterns, including --include and --exclude were given.
884 """Checks if any patterns, including --include and --exclude were given.
885
885
886 Some commands (e.g. addremove) use this condition for deciding whether to
886 Some commands (e.g. addremove) use this condition for deciding whether to
887 print absolute or relative paths.
887 print absolute or relative paths.
888 """
888 """
889 return bool(pats or opts.get(b'include') or opts.get(b'exclude'))
889 return bool(pats or opts.get(b'include') or opts.get(b'exclude'))
890
890
891
891
892 def expandpats(pats):
892 def expandpats(pats):
893 """Expand bare globs when running on windows.
893 """Expand bare globs when running on windows.
894 On posix we assume it already has already been done by sh."""
894 On posix we assume it already has already been done by sh."""
895 if not util.expandglobs:
895 if not util.expandglobs:
896 return list(pats)
896 return list(pats)
897 ret = []
897 ret = []
898 for kindpat in pats:
898 for kindpat in pats:
899 kind, pat = matchmod._patsplit(kindpat, None)
899 kind, pat = matchmod._patsplit(kindpat, None)
900 if kind is None:
900 if kind is None:
901 try:
901 try:
902 globbed = glob.glob(pat)
902 globbed = glob.glob(pat)
903 except re.error:
903 except re.error:
904 globbed = [pat]
904 globbed = [pat]
905 if globbed:
905 if globbed:
906 ret.extend(globbed)
906 ret.extend(globbed)
907 continue
907 continue
908 ret.append(kindpat)
908 ret.append(kindpat)
909 return ret
909 return ret
910
910
911
911
912 def matchandpats(
912 def matchandpats(
913 ctx, pats=(), opts=None, globbed=False, default=b'relpath', badfn=None
913 ctx, pats=(), opts=None, globbed=False, default=b'relpath', badfn=None
914 ):
914 ):
915 """Return a matcher and the patterns that were used.
915 """Return a matcher and the patterns that were used.
916 The matcher will warn about bad matches, unless an alternate badfn callback
916 The matcher will warn about bad matches, unless an alternate badfn callback
917 is provided."""
917 is provided."""
918 if opts is None:
918 if opts is None:
919 opts = {}
919 opts = {}
920 if not globbed and default == b'relpath':
920 if not globbed and default == b'relpath':
921 pats = expandpats(pats or [])
921 pats = expandpats(pats or [])
922
922
923 uipathfn = getuipathfn(ctx.repo(), legacyrelativevalue=True)
923 uipathfn = getuipathfn(ctx.repo(), legacyrelativevalue=True)
924
924
925 def bad(f, msg):
925 def bad(f, msg):
926 ctx.repo().ui.warn(b"%s: %s\n" % (uipathfn(f), msg))
926 ctx.repo().ui.warn(b"%s: %s\n" % (uipathfn(f), msg))
927
927
928 if badfn is None:
928 if badfn is None:
929 badfn = bad
929 badfn = bad
930
930
931 m = ctx.match(
931 m = ctx.match(
932 pats,
932 pats,
933 opts.get(b'include'),
933 opts.get(b'include'),
934 opts.get(b'exclude'),
934 opts.get(b'exclude'),
935 default,
935 default,
936 listsubrepos=opts.get(b'subrepos'),
936 listsubrepos=opts.get(b'subrepos'),
937 badfn=badfn,
937 badfn=badfn,
938 )
938 )
939
939
940 if m.always():
940 if m.always():
941 pats = []
941 pats = []
942 return m, pats
942 return m, pats
943
943
944
944
945 def match(
945 def match(
946 ctx, pats=(), opts=None, globbed=False, default=b'relpath', badfn=None
946 ctx, pats=(), opts=None, globbed=False, default=b'relpath', badfn=None
947 ):
947 ):
948 '''Return a matcher that will warn about bad matches.'''
948 '''Return a matcher that will warn about bad matches.'''
949 return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
949 return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
950
950
951
951
952 def matchall(repo):
952 def matchall(repo):
953 '''Return a matcher that will efficiently match everything.'''
953 '''Return a matcher that will efficiently match everything.'''
954 return matchmod.always()
954 return matchmod.always()
955
955
956
956
957 def matchfiles(repo, files, badfn=None):
957 def matchfiles(repo, files, badfn=None):
958 '''Return a matcher that will efficiently match exactly these files.'''
958 '''Return a matcher that will efficiently match exactly these files.'''
959 return matchmod.exact(files, badfn=badfn)
959 return matchmod.exact(files, badfn=badfn)
960
960
961
961
962 def parsefollowlinespattern(repo, rev, pat, msg):
962 def parsefollowlinespattern(repo, rev, pat, msg):
963 """Return a file name from `pat` pattern suitable for usage in followlines
963 """Return a file name from `pat` pattern suitable for usage in followlines
964 logic.
964 logic.
965 """
965 """
966 if not matchmod.patkind(pat):
966 if not matchmod.patkind(pat):
967 return pathutil.canonpath(repo.root, repo.getcwd(), pat)
967 return pathutil.canonpath(repo.root, repo.getcwd(), pat)
968 else:
968 else:
969 ctx = repo[rev]
969 ctx = repo[rev]
970 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=ctx)
970 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=ctx)
971 files = [f for f in ctx if m(f)]
971 files = [f for f in ctx if m(f)]
972 if len(files) != 1:
972 if len(files) != 1:
973 raise error.ParseError(msg)
973 raise error.ParseError(msg)
974 return files[0]
974 return files[0]
975
975
976
976
977 def getorigvfs(ui, repo):
977 def getorigvfs(ui, repo):
978 """return a vfs suitable to save 'orig' file
978 """return a vfs suitable to save 'orig' file
979
979
980 return None if no special directory is configured"""
980 return None if no special directory is configured"""
981 origbackuppath = ui.config(b'ui', b'origbackuppath')
981 origbackuppath = ui.config(b'ui', b'origbackuppath')
982 if not origbackuppath:
982 if not origbackuppath:
983 return None
983 return None
984 return vfs.vfs(repo.wvfs.join(origbackuppath))
984 return vfs.vfs(repo.wvfs.join(origbackuppath))
985
985
986
986
987 def backuppath(ui, repo, filepath):
987 def backuppath(ui, repo, filepath):
988 """customize where working copy backup files (.orig files) are created
988 """customize where working copy backup files (.orig files) are created
989
989
990 Fetch user defined path from config file: [ui] origbackuppath = <path>
990 Fetch user defined path from config file: [ui] origbackuppath = <path>
991 Fall back to default (filepath with .orig suffix) if not specified
991 Fall back to default (filepath with .orig suffix) if not specified
992
992
993 filepath is repo-relative
993 filepath is repo-relative
994
994
995 Returns an absolute path
995 Returns an absolute path
996 """
996 """
997 origvfs = getorigvfs(ui, repo)
997 origvfs = getorigvfs(ui, repo)
998 if origvfs is None:
998 if origvfs is None:
999 return repo.wjoin(filepath + b".orig")
999 return repo.wjoin(filepath + b".orig")
1000
1000
1001 origbackupdir = origvfs.dirname(filepath)
1001 origbackupdir = origvfs.dirname(filepath)
1002 if not origvfs.isdir(origbackupdir) or origvfs.islink(origbackupdir):
1002 if not origvfs.isdir(origbackupdir) or origvfs.islink(origbackupdir):
1003 ui.note(_(b'creating directory: %s\n') % origvfs.join(origbackupdir))
1003 ui.note(_(b'creating directory: %s\n') % origvfs.join(origbackupdir))
1004
1004
1005 # Remove any files that conflict with the backup file's path
1005 # Remove any files that conflict with the backup file's path
1006 for f in reversed(list(pathutil.finddirs(filepath))):
1006 for f in reversed(list(pathutil.finddirs(filepath))):
1007 if origvfs.isfileorlink(f):
1007 if origvfs.isfileorlink(f):
1008 ui.note(_(b'removing conflicting file: %s\n') % origvfs.join(f))
1008 ui.note(_(b'removing conflicting file: %s\n') % origvfs.join(f))
1009 origvfs.unlink(f)
1009 origvfs.unlink(f)
1010 break
1010 break
1011
1011
1012 origvfs.makedirs(origbackupdir)
1012 origvfs.makedirs(origbackupdir)
1013
1013
1014 if origvfs.isdir(filepath) and not origvfs.islink(filepath):
1014 if origvfs.isdir(filepath) and not origvfs.islink(filepath):
1015 ui.note(
1015 ui.note(
1016 _(b'removing conflicting directory: %s\n') % origvfs.join(filepath)
1016 _(b'removing conflicting directory: %s\n') % origvfs.join(filepath)
1017 )
1017 )
1018 origvfs.rmtree(filepath, forcibly=True)
1018 origvfs.rmtree(filepath, forcibly=True)
1019
1019
1020 return origvfs.join(filepath)
1020 return origvfs.join(filepath)
1021
1021
1022
1022
1023 class _containsnode:
1023 class _containsnode:
1024 """proxy __contains__(node) to container.__contains__ which accepts revs"""
1024 """proxy __contains__(node) to container.__contains__ which accepts revs"""
1025
1025
1026 def __init__(self, repo, revcontainer):
1026 def __init__(self, repo, revcontainer):
1027 self._torev = repo.changelog.rev
1027 self._torev = repo.changelog.rev
1028 self._revcontains = revcontainer.__contains__
1028 self._revcontains = revcontainer.__contains__
1029
1029
1030 def __contains__(self, node):
1030 def __contains__(self, node):
1031 return self._revcontains(self._torev(node))
1031 return self._revcontains(self._torev(node))
1032
1032
1033
1033
1034 def cleanupnodes(
1034 def cleanupnodes(
1035 repo,
1035 repo,
1036 replacements,
1036 replacements,
1037 operation,
1037 operation,
1038 moves=None,
1038 moves=None,
1039 metadata=None,
1039 metadata=None,
1040 fixphase=False,
1040 fixphase=False,
1041 targetphase=None,
1041 targetphase=None,
1042 backup=True,
1042 backup=True,
1043 ):
1043 ):
1044 """do common cleanups when old nodes are replaced by new nodes
1044 """do common cleanups when old nodes are replaced by new nodes
1045
1045
1046 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
1046 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
1047 (we might also want to move working directory parent in the future)
1047 (we might also want to move working directory parent in the future)
1048
1048
1049 By default, bookmark moves are calculated automatically from 'replacements',
1049 By default, bookmark moves are calculated automatically from 'replacements',
1050 but 'moves' can be used to override that. Also, 'moves' may include
1050 but 'moves' can be used to override that. Also, 'moves' may include
1051 additional bookmark moves that should not have associated obsmarkers.
1051 additional bookmark moves that should not have associated obsmarkers.
1052
1052
1053 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
1053 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
1054 have replacements. operation is a string, like "rebase".
1054 have replacements. operation is a string, like "rebase".
1055
1055
1056 metadata is dictionary containing metadata to be stored in obsmarker if
1056 metadata is dictionary containing metadata to be stored in obsmarker if
1057 obsolescence is enabled.
1057 obsolescence is enabled.
1058 """
1058 """
1059 assert fixphase or targetphase is None
1059 assert fixphase or targetphase is None
1060 if not replacements and not moves:
1060 if not replacements and not moves:
1061 return
1061 return
1062
1062
1063 # translate mapping's other forms
1063 # translate mapping's other forms
1064 if not util.safehasattr(replacements, b'items'):
1064 if not util.safehasattr(replacements, b'items'):
1065 replacements = {(n,): () for n in replacements}
1065 replacements = {(n,): () for n in replacements}
1066 else:
1066 else:
1067 # upgrading non tuple "source" to tuple ones for BC
1067 # upgrading non tuple "source" to tuple ones for BC
1068 repls = {}
1068 repls = {}
1069 for key, value in replacements.items():
1069 for key, value in replacements.items():
1070 if not isinstance(key, tuple):
1070 if not isinstance(key, tuple):
1071 key = (key,)
1071 key = (key,)
1072 repls[key] = value
1072 repls[key] = value
1073 replacements = repls
1073 replacements = repls
1074
1074
1075 # Unfiltered repo is needed since nodes in replacements might be hidden.
1075 # Unfiltered repo is needed since nodes in replacements might be hidden.
1076 unfi = repo.unfiltered()
1076 unfi = repo.unfiltered()
1077
1077
1078 # Calculate bookmark movements
1078 # Calculate bookmark movements
1079 if moves is None:
1079 if moves is None:
1080 moves = {}
1080 moves = {}
1081 for oldnodes, newnodes in replacements.items():
1081 for oldnodes, newnodes in replacements.items():
1082 for oldnode in oldnodes:
1082 for oldnode in oldnodes:
1083 if oldnode in moves:
1083 if oldnode in moves:
1084 continue
1084 continue
1085 if len(newnodes) > 1:
1085 if len(newnodes) > 1:
1086 # usually a split, take the one with biggest rev number
1086 # usually a split, take the one with biggest rev number
1087 newnode = next(unfi.set(b'max(%ln)', newnodes)).node()
1087 newnode = next(unfi.set(b'max(%ln)', newnodes)).node()
1088 elif len(newnodes) == 0:
1088 elif len(newnodes) == 0:
1089 # move bookmark backwards
1089 # move bookmark backwards
1090 allreplaced = []
1090 allreplaced = []
1091 for rep in replacements:
1091 for rep in replacements:
1092 allreplaced.extend(rep)
1092 allreplaced.extend(rep)
1093 roots = list(
1093 roots = list(
1094 unfi.set(b'max((::%n) - %ln)', oldnode, allreplaced)
1094 unfi.set(b'max((::%n) - %ln)', oldnode, allreplaced)
1095 )
1095 )
1096 if roots:
1096 if roots:
1097 newnode = roots[0].node()
1097 newnode = roots[0].node()
1098 else:
1098 else:
1099 newnode = repo.nullid
1099 newnode = repo.nullid
1100 else:
1100 else:
1101 newnode = newnodes[0]
1101 newnode = newnodes[0]
1102 moves[oldnode] = newnode
1102 moves[oldnode] = newnode
1103
1103
1104 allnewnodes = [n for ns in replacements.values() for n in ns]
1104 allnewnodes = [n for ns in replacements.values() for n in ns]
1105 toretract = {}
1105 toretract = {}
1106 toadvance = {}
1106 toadvance = {}
1107 if fixphase:
1107 if fixphase:
1108 precursors = {}
1108 precursors = {}
1109 for oldnodes, newnodes in replacements.items():
1109 for oldnodes, newnodes in replacements.items():
1110 for oldnode in oldnodes:
1110 for oldnode in oldnodes:
1111 for newnode in newnodes:
1111 for newnode in newnodes:
1112 precursors.setdefault(newnode, []).append(oldnode)
1112 precursors.setdefault(newnode, []).append(oldnode)
1113
1113
1114 allnewnodes.sort(key=lambda n: unfi[n].rev())
1114 allnewnodes.sort(key=lambda n: unfi[n].rev())
1115 newphases = {}
1115 newphases = {}
1116
1116
1117 def phase(ctx):
1117 def phase(ctx):
1118 return newphases.get(ctx.node(), ctx.phase())
1118 return newphases.get(ctx.node(), ctx.phase())
1119
1119
1120 for newnode in allnewnodes:
1120 for newnode in allnewnodes:
1121 ctx = unfi[newnode]
1121 ctx = unfi[newnode]
1122 parentphase = max(phase(p) for p in ctx.parents())
1122 parentphase = max(phase(p) for p in ctx.parents())
1123 if targetphase is None:
1123 if targetphase is None:
1124 oldphase = max(
1124 oldphase = max(
1125 unfi[oldnode].phase() for oldnode in precursors[newnode]
1125 unfi[oldnode].phase() for oldnode in precursors[newnode]
1126 )
1126 )
1127 newphase = max(oldphase, parentphase)
1127 newphase = max(oldphase, parentphase)
1128 else:
1128 else:
1129 newphase = max(targetphase, parentphase)
1129 newphase = max(targetphase, parentphase)
1130 newphases[newnode] = newphase
1130 newphases[newnode] = newphase
1131 if newphase > ctx.phase():
1131 if newphase > ctx.phase():
1132 toretract.setdefault(newphase, []).append(newnode)
1132 toretract.setdefault(newphase, []).append(newnode)
1133 elif newphase < ctx.phase():
1133 elif newphase < ctx.phase():
1134 toadvance.setdefault(newphase, []).append(newnode)
1134 toadvance.setdefault(newphase, []).append(newnode)
1135
1135
1136 with repo.transaction(b'cleanup') as tr:
1136 with repo.transaction(b'cleanup') as tr:
1137 # Move bookmarks
1137 # Move bookmarks
1138 bmarks = repo._bookmarks
1138 bmarks = repo._bookmarks
1139 bmarkchanges = []
1139 bmarkchanges = []
1140 for oldnode, newnode in moves.items():
1140 for oldnode, newnode in moves.items():
1141 oldbmarks = repo.nodebookmarks(oldnode)
1141 oldbmarks = repo.nodebookmarks(oldnode)
1142 if not oldbmarks:
1142 if not oldbmarks:
1143 continue
1143 continue
1144 from . import bookmarks # avoid import cycle
1144 from . import bookmarks # avoid import cycle
1145
1145
1146 repo.ui.debug(
1146 repo.ui.debug(
1147 b'moving bookmarks %r from %s to %s\n'
1147 b'moving bookmarks %r from %s to %s\n'
1148 % (
1148 % (
1149 pycompat.rapply(pycompat.maybebytestr, oldbmarks),
1149 pycompat.rapply(pycompat.maybebytestr, oldbmarks),
1150 hex(oldnode),
1150 hex(oldnode),
1151 hex(newnode),
1151 hex(newnode),
1152 )
1152 )
1153 )
1153 )
1154 # Delete divergent bookmarks being parents of related newnodes
1154 # Delete divergent bookmarks being parents of related newnodes
1155 deleterevs = repo.revs(
1155 deleterevs = repo.revs(
1156 b'parents(roots(%ln & (::%n))) - parents(%n)',
1156 b'parents(roots(%ln & (::%n))) - parents(%n)',
1157 allnewnodes,
1157 allnewnodes,
1158 newnode,
1158 newnode,
1159 oldnode,
1159 oldnode,
1160 )
1160 )
1161 deletenodes = _containsnode(repo, deleterevs)
1161 deletenodes = _containsnode(repo, deleterevs)
1162 for name in oldbmarks:
1162 for name in oldbmarks:
1163 bmarkchanges.append((name, newnode))
1163 bmarkchanges.append((name, newnode))
1164 for b in bookmarks.divergent2delete(repo, deletenodes, name):
1164 for b in bookmarks.divergent2delete(repo, deletenodes, name):
1165 bmarkchanges.append((b, None))
1165 bmarkchanges.append((b, None))
1166
1166
1167 if bmarkchanges:
1167 if bmarkchanges:
1168 bmarks.applychanges(repo, tr, bmarkchanges)
1168 bmarks.applychanges(repo, tr, bmarkchanges)
1169
1169
1170 for phase, nodes in toretract.items():
1170 for phase, nodes in toretract.items():
1171 phases.retractboundary(repo, tr, phase, nodes)
1171 phases.retractboundary(repo, tr, phase, nodes)
1172 for phase, nodes in toadvance.items():
1172 for phase, nodes in toadvance.items():
1173 phases.advanceboundary(repo, tr, phase, nodes)
1173 phases.advanceboundary(repo, tr, phase, nodes)
1174
1174
1175 mayusearchived = repo.ui.config(b'experimental', b'cleanup-as-archived')
1175 mayusearchived = repo.ui.config(b'experimental', b'cleanup-as-archived')
1176 # Obsolete or strip nodes
1176 # Obsolete or strip nodes
1177 if obsolete.isenabled(repo, obsolete.createmarkersopt):
1177 if obsolete.isenabled(repo, obsolete.createmarkersopt):
1178 # If a node is already obsoleted, and we want to obsolete it
1178 # If a node is already obsoleted, and we want to obsolete it
1179 # without a successor, skip that obssolete request since it's
1179 # without a successor, skip that obssolete request since it's
1180 # unnecessary. That's the "if s or not isobs(n)" check below.
1180 # unnecessary. That's the "if s or not isobs(n)" check below.
1181 # Also sort the node in topology order, that might be useful for
1181 # Also sort the node in topology order, that might be useful for
1182 # some obsstore logic.
1182 # some obsstore logic.
1183 # NOTE: the sorting might belong to createmarkers.
1183 # NOTE: the sorting might belong to createmarkers.
1184 torev = unfi.changelog.rev
1184 torev = unfi.changelog.rev
1185 sortfunc = lambda ns: torev(ns[0][0])
1185 sortfunc = lambda ns: torev(ns[0][0])
1186 rels = []
1186 rels = []
1187 for ns, s in sorted(replacements.items(), key=sortfunc):
1187 for ns, s in sorted(replacements.items(), key=sortfunc):
1188 rel = (tuple(unfi[n] for n in ns), tuple(unfi[m] for m in s))
1188 rel = (tuple(unfi[n] for n in ns), tuple(unfi[m] for m in s))
1189 rels.append(rel)
1189 rels.append(rel)
1190 if rels:
1190 if rels:
1191 obsolete.createmarkers(
1191 obsolete.createmarkers(
1192 repo, rels, operation=operation, metadata=metadata
1192 repo, rels, operation=operation, metadata=metadata
1193 )
1193 )
1194 elif phases.supportarchived(repo) and mayusearchived:
1194 elif phases.supportarchived(repo) and mayusearchived:
1195 # this assume we do not have "unstable" nodes above the cleaned ones
1195 # this assume we do not have "unstable" nodes above the cleaned ones
1196 allreplaced = set()
1196 allreplaced = set()
1197 for ns in replacements.keys():
1197 for ns in replacements.keys():
1198 allreplaced.update(ns)
1198 allreplaced.update(ns)
1199 if backup:
1199 if backup:
1200 from . import repair # avoid import cycle
1200 from . import repair # avoid import cycle
1201
1201
1202 node = min(allreplaced, key=repo.changelog.rev)
1202 node = min(allreplaced, key=repo.changelog.rev)
1203 repair.backupbundle(
1203 repair.backupbundle(
1204 repo, allreplaced, allreplaced, node, operation
1204 repo, allreplaced, allreplaced, node, operation
1205 )
1205 )
1206 phases.retractboundary(repo, tr, phases.archived, allreplaced)
1206 phases.retractboundary(repo, tr, phases.archived, allreplaced)
1207 else:
1207 else:
1208 from . import repair # avoid import cycle
1208 from . import repair # avoid import cycle
1209
1209
1210 tostrip = list(n for ns in replacements for n in ns)
1210 tostrip = list(n for ns in replacements for n in ns)
1211 if tostrip:
1211 if tostrip:
1212 repair.delayedstrip(
1212 repair.delayedstrip(
1213 repo.ui, repo, tostrip, operation, backup=backup
1213 repo.ui, repo, tostrip, operation, backup=backup
1214 )
1214 )
1215
1215
1216
1216
1217 def addremove(repo, matcher, prefix, uipathfn, opts=None):
1217 def addremove(repo, matcher, prefix, uipathfn, opts=None):
1218 if opts is None:
1218 if opts is None:
1219 opts = {}
1219 opts = {}
1220 m = matcher
1220 m = matcher
1221 dry_run = opts.get(b'dry_run')
1221 dry_run = opts.get(b'dry_run')
1222 try:
1222 try:
1223 similarity = float(opts.get(b'similarity') or 0)
1223 similarity = float(opts.get(b'similarity') or 0)
1224 except ValueError:
1224 except ValueError:
1225 raise error.InputError(_(b'similarity must be a number'))
1225 raise error.InputError(_(b'similarity must be a number'))
1226 if similarity < 0 or similarity > 100:
1226 if similarity < 0 or similarity > 100:
1227 raise error.InputError(_(b'similarity must be between 0 and 100'))
1227 raise error.InputError(_(b'similarity must be between 0 and 100'))
1228 similarity /= 100.0
1228 similarity /= 100.0
1229
1229
1230 ret = 0
1230 ret = 0
1231
1231
1232 wctx = repo[None]
1232 wctx = repo[None]
1233 for subpath in sorted(wctx.substate):
1233 for subpath in sorted(wctx.substate):
1234 submatch = matchmod.subdirmatcher(subpath, m)
1234 submatch = matchmod.subdirmatcher(subpath, m)
1235 if opts.get(b'subrepos') or m.exact(subpath) or any(submatch.files()):
1235 if opts.get(b'subrepos') or m.exact(subpath) or any(submatch.files()):
1236 sub = wctx.sub(subpath)
1236 sub = wctx.sub(subpath)
1237 subprefix = repo.wvfs.reljoin(prefix, subpath)
1237 subprefix = repo.wvfs.reljoin(prefix, subpath)
1238 subuipathfn = subdiruipathfn(subpath, uipathfn)
1238 subuipathfn = subdiruipathfn(subpath, uipathfn)
1239 try:
1239 try:
1240 if sub.addremove(submatch, subprefix, subuipathfn, opts):
1240 if sub.addremove(submatch, subprefix, subuipathfn, opts):
1241 ret = 1
1241 ret = 1
1242 except error.LookupError:
1242 except error.LookupError:
1243 repo.ui.status(
1243 repo.ui.status(
1244 _(b"skipping missing subrepository: %s\n")
1244 _(b"skipping missing subrepository: %s\n")
1245 % uipathfn(subpath)
1245 % uipathfn(subpath)
1246 )
1246 )
1247
1247
1248 rejected = []
1248 rejected = []
1249
1249
1250 def badfn(f, msg):
1250 def badfn(f, msg):
1251 if f in m.files():
1251 if f in m.files():
1252 m.bad(f, msg)
1252 m.bad(f, msg)
1253 rejected.append(f)
1253 rejected.append(f)
1254
1254
1255 badmatch = matchmod.badmatch(m, badfn)
1255 badmatch = matchmod.badmatch(m, badfn)
1256 added, unknown, deleted, removed, forgotten = _interestingfiles(
1256 added, unknown, deleted, removed, forgotten = _interestingfiles(
1257 repo, badmatch
1257 repo, badmatch
1258 )
1258 )
1259
1259
1260 unknownset = set(unknown + forgotten)
1260 unknownset = set(unknown + forgotten)
1261 toprint = unknownset.copy()
1261 toprint = unknownset.copy()
1262 toprint.update(deleted)
1262 toprint.update(deleted)
1263 for abs in sorted(toprint):
1263 for abs in sorted(toprint):
1264 if repo.ui.verbose or not m.exact(abs):
1264 if repo.ui.verbose or not m.exact(abs):
1265 if abs in unknownset:
1265 if abs in unknownset:
1266 status = _(b'adding %s\n') % uipathfn(abs)
1266 status = _(b'adding %s\n') % uipathfn(abs)
1267 label = b'ui.addremove.added'
1267 label = b'ui.addremove.added'
1268 else:
1268 else:
1269 status = _(b'removing %s\n') % uipathfn(abs)
1269 status = _(b'removing %s\n') % uipathfn(abs)
1270 label = b'ui.addremove.removed'
1270 label = b'ui.addremove.removed'
1271 repo.ui.status(status, label=label)
1271 repo.ui.status(status, label=label)
1272
1272
1273 renames = _findrenames(
1273 renames = _findrenames(
1274 repo, m, added + unknown, removed + deleted, similarity, uipathfn
1274 repo, m, added + unknown, removed + deleted, similarity, uipathfn
1275 )
1275 )
1276
1276
1277 if not dry_run:
1277 if not dry_run:
1278 _markchanges(repo, unknown + forgotten, deleted, renames)
1278 _markchanges(repo, unknown + forgotten, deleted, renames)
1279
1279
1280 for f in rejected:
1280 for f in rejected:
1281 if f in m.files():
1281 if f in m.files():
1282 return 1
1282 return 1
1283 return ret
1283 return ret
1284
1284
1285
1285
1286 def marktouched(repo, files, similarity=0.0):
1286 def marktouched(repo, files, similarity=0.0):
1287 """Assert that files have somehow been operated upon. files are relative to
1287 """Assert that files have somehow been operated upon. files are relative to
1288 the repo root."""
1288 the repo root."""
1289 m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
1289 m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
1290 rejected = []
1290 rejected = []
1291
1291
1292 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
1292 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
1293
1293
1294 if repo.ui.verbose:
1294 if repo.ui.verbose:
1295 unknownset = set(unknown + forgotten)
1295 unknownset = set(unknown + forgotten)
1296 toprint = unknownset.copy()
1296 toprint = unknownset.copy()
1297 toprint.update(deleted)
1297 toprint.update(deleted)
1298 for abs in sorted(toprint):
1298 for abs in sorted(toprint):
1299 if abs in unknownset:
1299 if abs in unknownset:
1300 status = _(b'adding %s\n') % abs
1300 status = _(b'adding %s\n') % abs
1301 else:
1301 else:
1302 status = _(b'removing %s\n') % abs
1302 status = _(b'removing %s\n') % abs
1303 repo.ui.status(status)
1303 repo.ui.status(status)
1304
1304
1305 # TODO: We should probably have the caller pass in uipathfn and apply it to
1305 # TODO: We should probably have the caller pass in uipathfn and apply it to
1306 # the messages above too. legacyrelativevalue=True is consistent with how
1306 # the messages above too. legacyrelativevalue=True is consistent with how
1307 # it used to work.
1307 # it used to work.
1308 uipathfn = getuipathfn(repo, legacyrelativevalue=True)
1308 uipathfn = getuipathfn(repo, legacyrelativevalue=True)
1309 renames = _findrenames(
1309 renames = _findrenames(
1310 repo, m, added + unknown, removed + deleted, similarity, uipathfn
1310 repo, m, added + unknown, removed + deleted, similarity, uipathfn
1311 )
1311 )
1312
1312
1313 _markchanges(repo, unknown + forgotten, deleted, renames)
1313 _markchanges(repo, unknown + forgotten, deleted, renames)
1314
1314
1315 for f in rejected:
1315 for f in rejected:
1316 if f in m.files():
1316 if f in m.files():
1317 return 1
1317 return 1
1318 return 0
1318 return 0
1319
1319
1320
1320
1321 def _interestingfiles(repo, matcher):
1321 def _interestingfiles(repo, matcher):
1322 """Walk dirstate with matcher, looking for files that addremove would care
1322 """Walk dirstate with matcher, looking for files that addremove would care
1323 about.
1323 about.
1324
1324
1325 This is different from dirstate.status because it doesn't care about
1325 This is different from dirstate.status because it doesn't care about
1326 whether files are modified or clean."""
1326 whether files are modified or clean."""
1327 added, unknown, deleted, removed, forgotten = [], [], [], [], []
1327 added, unknown, deleted, removed, forgotten = [], [], [], [], []
1328 audit_path = pathutil.pathauditor(repo.root, cached=True)
1328 audit_path = pathutil.pathauditor(repo.root, cached=True)
1329
1329
1330 ctx = repo[None]
1330 ctx = repo[None]
1331 dirstate = repo.dirstate
1331 dirstate = repo.dirstate
1332 matcher = repo.narrowmatch(matcher, includeexact=True)
1332 matcher = repo.narrowmatch(matcher, includeexact=True)
1333 walkresults = dirstate.walk(
1333 walkresults = dirstate.walk(
1334 matcher,
1334 matcher,
1335 subrepos=sorted(ctx.substate),
1335 subrepos=sorted(ctx.substate),
1336 unknown=True,
1336 unknown=True,
1337 ignored=False,
1337 ignored=False,
1338 full=False,
1338 full=False,
1339 )
1339 )
1340 for abs, st in walkresults.items():
1340 for abs, st in walkresults.items():
1341 entry = dirstate.get_entry(abs)
1341 entry = dirstate.get_entry(abs)
1342 if (not entry.any_tracked) and audit_path.check(abs):
1342 if (not entry.any_tracked) and audit_path.check(abs):
1343 unknown.append(abs)
1343 unknown.append(abs)
1344 elif (not entry.removed) and not st:
1344 elif (not entry.removed) and not st:
1345 deleted.append(abs)
1345 deleted.append(abs)
1346 elif entry.removed and st:
1346 elif entry.removed and st:
1347 forgotten.append(abs)
1347 forgotten.append(abs)
1348 # for finding renames
1348 # for finding renames
1349 elif entry.removed and not st:
1349 elif entry.removed and not st:
1350 removed.append(abs)
1350 removed.append(abs)
1351 elif entry.added:
1351 elif entry.added:
1352 added.append(abs)
1352 added.append(abs)
1353
1353
1354 return added, unknown, deleted, removed, forgotten
1354 return added, unknown, deleted, removed, forgotten
1355
1355
1356
1356
1357 def _findrenames(repo, matcher, added, removed, similarity, uipathfn):
1357 def _findrenames(repo, matcher, added, removed, similarity, uipathfn):
1358 '''Find renames from removed files to added ones.'''
1358 '''Find renames from removed files to added ones.'''
1359 renames = {}
1359 renames = {}
1360 if similarity > 0:
1360 if similarity > 0:
1361 for old, new, score in similar.findrenames(
1361 for old, new, score in similar.findrenames(
1362 repo, added, removed, similarity
1362 repo, added, removed, similarity
1363 ):
1363 ):
1364 if (
1364 if (
1365 repo.ui.verbose
1365 repo.ui.verbose
1366 or not matcher.exact(old)
1366 or not matcher.exact(old)
1367 or not matcher.exact(new)
1367 or not matcher.exact(new)
1368 ):
1368 ):
1369 repo.ui.status(
1369 repo.ui.status(
1370 _(
1370 _(
1371 b'recording removal of %s as rename to %s '
1371 b'recording removal of %s as rename to %s '
1372 b'(%d%% similar)\n'
1372 b'(%d%% similar)\n'
1373 )
1373 )
1374 % (uipathfn(old), uipathfn(new), score * 100)
1374 % (uipathfn(old), uipathfn(new), score * 100)
1375 )
1375 )
1376 renames[new] = old
1376 renames[new] = old
1377 return renames
1377 return renames
1378
1378
1379
1379
1380 def _markchanges(repo, unknown, deleted, renames):
1380 def _markchanges(repo, unknown, deleted, renames):
1381 """Marks the files in unknown as added, the files in deleted as removed,
1381 """Marks the files in unknown as added, the files in deleted as removed,
1382 and the files in renames as copied."""
1382 and the files in renames as copied."""
1383 wctx = repo[None]
1383 wctx = repo[None]
1384 with repo.wlock():
1384 with repo.wlock():
1385 wctx.forget(deleted)
1385 wctx.forget(deleted)
1386 wctx.add(unknown)
1386 wctx.add(unknown)
1387 for new, old in renames.items():
1387 for new, old in renames.items():
1388 wctx.copy(old, new)
1388 wctx.copy(old, new)
1389
1389
1390
1390
1391 def getrenamedfn(repo, endrev=None):
1391 def getrenamedfn(repo, endrev=None):
1392 if copiesmod.usechangesetcentricalgo(repo):
1392 if copiesmod.usechangesetcentricalgo(repo):
1393
1393
1394 def getrenamed(fn, rev):
1394 def getrenamed(fn, rev):
1395 ctx = repo[rev]
1395 ctx = repo[rev]
1396 p1copies = ctx.p1copies()
1396 p1copies = ctx.p1copies()
1397 if fn in p1copies:
1397 if fn in p1copies:
1398 return p1copies[fn]
1398 return p1copies[fn]
1399 p2copies = ctx.p2copies()
1399 p2copies = ctx.p2copies()
1400 if fn in p2copies:
1400 if fn in p2copies:
1401 return p2copies[fn]
1401 return p2copies[fn]
1402 return None
1402 return None
1403
1403
1404 return getrenamed
1404 return getrenamed
1405
1405
1406 rcache = {}
1406 rcache = {}
1407 if endrev is None:
1407 if endrev is None:
1408 endrev = len(repo)
1408 endrev = len(repo)
1409
1409
1410 def getrenamed(fn, rev):
1410 def getrenamed(fn, rev):
1411 """looks up all renames for a file (up to endrev) the first
1411 """looks up all renames for a file (up to endrev) the first
1412 time the file is given. It indexes on the changerev and only
1412 time the file is given. It indexes on the changerev and only
1413 parses the manifest if linkrev != changerev.
1413 parses the manifest if linkrev != changerev.
1414 Returns rename info for fn at changerev rev."""
1414 Returns rename info for fn at changerev rev."""
1415 if fn not in rcache:
1415 if fn not in rcache:
1416 rcache[fn] = {}
1416 rcache[fn] = {}
1417 fl = repo.file(fn)
1417 fl = repo.file(fn)
1418 for i in fl:
1418 for i in fl:
1419 lr = fl.linkrev(i)
1419 lr = fl.linkrev(i)
1420 renamed = fl.renamed(fl.node(i))
1420 renamed = fl.renamed(fl.node(i))
1421 rcache[fn][lr] = renamed and renamed[0]
1421 rcache[fn][lr] = renamed and renamed[0]
1422 if lr >= endrev:
1422 if lr >= endrev:
1423 break
1423 break
1424 if rev in rcache[fn]:
1424 if rev in rcache[fn]:
1425 return rcache[fn][rev]
1425 return rcache[fn][rev]
1426
1426
1427 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1427 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1428 # filectx logic.
1428 # filectx logic.
1429 try:
1429 try:
1430 return repo[rev][fn].copysource()
1430 return repo[rev][fn].copysource()
1431 except error.LookupError:
1431 except error.LookupError:
1432 return None
1432 return None
1433
1433
1434 return getrenamed
1434 return getrenamed
1435
1435
1436
1436
1437 def getcopiesfn(repo, endrev=None):
1437 def getcopiesfn(repo, endrev=None):
1438 if copiesmod.usechangesetcentricalgo(repo):
1438 if copiesmod.usechangesetcentricalgo(repo):
1439
1439
1440 def copiesfn(ctx):
1440 def copiesfn(ctx):
1441 if ctx.p2copies():
1441 if ctx.p2copies():
1442 allcopies = ctx.p1copies().copy()
1442 allcopies = ctx.p1copies().copy()
1443 # There should be no overlap
1443 # There should be no overlap
1444 allcopies.update(ctx.p2copies())
1444 allcopies.update(ctx.p2copies())
1445 return sorted(allcopies.items())
1445 return sorted(allcopies.items())
1446 else:
1446 else:
1447 return sorted(ctx.p1copies().items())
1447 return sorted(ctx.p1copies().items())
1448
1448
1449 else:
1449 else:
1450 getrenamed = getrenamedfn(repo, endrev)
1450 getrenamed = getrenamedfn(repo, endrev)
1451
1451
1452 def copiesfn(ctx):
1452 def copiesfn(ctx):
1453 copies = []
1453 copies = []
1454 for fn in ctx.files():
1454 for fn in ctx.files():
1455 rename = getrenamed(fn, ctx.rev())
1455 rename = getrenamed(fn, ctx.rev())
1456 if rename:
1456 if rename:
1457 copies.append((fn, rename))
1457 copies.append((fn, rename))
1458 return copies
1458 return copies
1459
1459
1460 return copiesfn
1460 return copiesfn
1461
1461
1462
1462
1463 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
1463 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
1464 """Update the dirstate to reflect the intent of copying src to dst. For
1464 """Update the dirstate to reflect the intent of copying src to dst. For
1465 different reasons it might not end with dst being marked as copied from src.
1465 different reasons it might not end with dst being marked as copied from src.
1466 """
1466 """
1467 origsrc = repo.dirstate.copied(src) or src
1467 origsrc = repo.dirstate.copied(src) or src
1468 if dst == origsrc: # copying back a copy?
1468 if dst == origsrc: # copying back a copy?
1469 entry = repo.dirstate.get_entry(dst)
1469 entry = repo.dirstate.get_entry(dst)
1470 if (entry.added or not entry.tracked) and not dryrun:
1470 if (entry.added or not entry.tracked) and not dryrun:
1471 repo.dirstate.set_tracked(dst)
1471 repo.dirstate.set_tracked(dst)
1472 else:
1472 else:
1473 if repo.dirstate.get_entry(origsrc).added and origsrc == src:
1473 if repo.dirstate.get_entry(origsrc).added and origsrc == src:
1474 if not ui.quiet:
1474 if not ui.quiet:
1475 ui.warn(
1475 ui.warn(
1476 _(
1476 _(
1477 b"%s has not been committed yet, so no copy "
1477 b"%s has not been committed yet, so no copy "
1478 b"data will be stored for %s.\n"
1478 b"data will be stored for %s.\n"
1479 )
1479 )
1480 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd))
1480 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd))
1481 )
1481 )
1482 if not repo.dirstate.get_entry(dst).tracked and not dryrun:
1482 if not repo.dirstate.get_entry(dst).tracked and not dryrun:
1483 wctx.add([dst])
1483 wctx.add([dst])
1484 elif not dryrun:
1484 elif not dryrun:
1485 wctx.copy(origsrc, dst)
1485 wctx.copy(origsrc, dst)
1486
1486
1487
1487
1488 def movedirstate(repo, newctx, match=None):
1488 def movedirstate(repo, newctx, match=None):
1489 """Move the dirstate to newctx and adjust it as necessary.
1489 """Move the dirstate to newctx and adjust it as necessary.
1490
1490
1491 A matcher can be provided as an optimization. It is probably a bug to pass
1491 A matcher can be provided as an optimization. It is probably a bug to pass
1492 a matcher that doesn't match all the differences between the parent of the
1492 a matcher that doesn't match all the differences between the parent of the
1493 working copy and newctx.
1493 working copy and newctx.
1494 """
1494 """
1495 oldctx = repo[b'.']
1495 oldctx = repo[b'.']
1496 ds = repo.dirstate
1496 ds = repo.dirstate
1497 copies = dict(ds.copies())
1497 copies = dict(ds.copies())
1498 ds.setparents(newctx.node(), repo.nullid)
1498 ds.setparents(newctx.node(), repo.nullid)
1499 s = newctx.status(oldctx, match=match)
1499 s = newctx.status(oldctx, match=match)
1500
1500
1501 for f in s.modified:
1501 for f in s.modified:
1502 ds.update_file_p1(f, p1_tracked=True)
1502 ds.update_file_p1(f, p1_tracked=True)
1503
1503
1504 for f in s.added:
1504 for f in s.added:
1505 ds.update_file_p1(f, p1_tracked=False)
1505 ds.update_file_p1(f, p1_tracked=False)
1506
1506
1507 for f in s.removed:
1507 for f in s.removed:
1508 ds.update_file_p1(f, p1_tracked=True)
1508 ds.update_file_p1(f, p1_tracked=True)
1509
1509
1510 # Merge old parent and old working dir copies
1510 # Merge old parent and old working dir copies
1511 oldcopies = copiesmod.pathcopies(newctx, oldctx, match)
1511 oldcopies = copiesmod.pathcopies(newctx, oldctx, match)
1512 oldcopies.update(copies)
1512 oldcopies.update(copies)
1513 copies = {dst: oldcopies.get(src, src) for dst, src in oldcopies.items()}
1513 copies = {dst: oldcopies.get(src, src) for dst, src in oldcopies.items()}
1514 # Adjust the dirstate copies
1514 # Adjust the dirstate copies
1515 for dst, src in copies.items():
1515 for dst, src in copies.items():
1516 if src not in newctx or dst in newctx or not ds.get_entry(dst).added:
1516 if src not in newctx or dst in newctx or not ds.get_entry(dst).added:
1517 src = None
1517 src = None
1518 ds.copy(src, dst)
1518 ds.copy(src, dst)
1519 repo._quick_access_changeid_invalidate()
1519 repo._quick_access_changeid_invalidate()
1520
1520
1521
1521
1522 def filterrequirements(requirements):
1522 def filterrequirements(requirements):
1523 """filters the requirements into two sets:
1523 """filters the requirements into two sets:
1524
1524
1525 wcreq: requirements which should be written in .hg/requires
1525 wcreq: requirements which should be written in .hg/requires
1526 storereq: which should be written in .hg/store/requires
1526 storereq: which should be written in .hg/store/requires
1527
1527
1528 Returns (wcreq, storereq)
1528 Returns (wcreq, storereq)
1529 """
1529 """
1530 if requirementsmod.SHARESAFE_REQUIREMENT in requirements:
1530 if requirementsmod.SHARESAFE_REQUIREMENT in requirements:
1531 wc, store = set(), set()
1531 wc, store = set(), set()
1532 for r in requirements:
1532 for r in requirements:
1533 if r in requirementsmod.WORKING_DIR_REQUIREMENTS:
1533 if r in requirementsmod.WORKING_DIR_REQUIREMENTS:
1534 wc.add(r)
1534 wc.add(r)
1535 else:
1535 else:
1536 store.add(r)
1536 store.add(r)
1537 return wc, store
1537 return wc, store
1538 return requirements, None
1538 return requirements, None
1539
1539
1540
1540
1541 def istreemanifest(repo):
1541 def istreemanifest(repo):
1542 """returns whether the repository is using treemanifest or not"""
1542 """returns whether the repository is using treemanifest or not"""
1543 return requirementsmod.TREEMANIFEST_REQUIREMENT in repo.requirements
1543 return requirementsmod.TREEMANIFEST_REQUIREMENT in repo.requirements
1544
1544
1545
1545
1546 def writereporequirements(repo, requirements=None):
1546 def writereporequirements(repo, requirements=None):
1547 """writes requirements for the repo
1547 """writes requirements for the repo
1548
1548
1549 Requirements are written to .hg/requires and .hg/store/requires based
1549 Requirements are written to .hg/requires and .hg/store/requires based
1550 on whether share-safe mode is enabled and which requirements are wdir
1550 on whether share-safe mode is enabled and which requirements are wdir
1551 requirements and which are store requirements
1551 requirements and which are store requirements
1552 """
1552 """
1553 if requirements:
1553 if requirements:
1554 repo.requirements = requirements
1554 repo.requirements = requirements
1555 wcreq, storereq = filterrequirements(repo.requirements)
1555 wcreq, storereq = filterrequirements(repo.requirements)
1556 if wcreq is not None:
1556 if wcreq is not None:
1557 writerequires(repo.vfs, wcreq)
1557 writerequires(repo.vfs, wcreq)
1558 if storereq is not None:
1558 if storereq is not None:
1559 writerequires(repo.svfs, storereq)
1559 writerequires(repo.svfs, storereq)
1560 elif repo.ui.configbool(b'format', b'usestore'):
1560 elif repo.ui.configbool(b'format', b'usestore'):
1561 # only remove store requires if we are using store
1561 # only remove store requires if we are using store
1562 repo.svfs.tryunlink(b'requires')
1562 repo.svfs.tryunlink(b'requires')
1563
1563
1564
1564
1565 def writerequires(opener, requirements):
1565 def writerequires(opener, requirements):
1566 with opener(b'requires', b'w', atomictemp=True) as fp:
1566 with opener(b'requires', b'w', atomictemp=True) as fp:
1567 for r in sorted(requirements):
1567 for r in sorted(requirements):
1568 fp.write(b"%s\n" % r)
1568 fp.write(b"%s\n" % r)
1569
1569
1570
1570
1571 class filecachesubentry:
1571 class filecachesubentry:
1572 def __init__(self, path, stat):
1572 def __init__(self, path, stat):
1573 self.path = path
1573 self.path = path
1574 self.cachestat = None
1574 self.cachestat = None
1575 self._cacheable = None
1575 self._cacheable = None
1576
1576
1577 if stat:
1577 if stat:
1578 self.cachestat = filecachesubentry.stat(self.path)
1578 self.cachestat = filecachesubentry.stat(self.path)
1579
1579
1580 if self.cachestat:
1580 if self.cachestat:
1581 self._cacheable = self.cachestat.cacheable()
1581 self._cacheable = self.cachestat.cacheable()
1582 else:
1582 else:
1583 # None means we don't know yet
1583 # None means we don't know yet
1584 self._cacheable = None
1584 self._cacheable = None
1585
1585
1586 def refresh(self):
1586 def refresh(self):
1587 if self.cacheable():
1587 if self.cacheable():
1588 self.cachestat = filecachesubentry.stat(self.path)
1588 self.cachestat = filecachesubentry.stat(self.path)
1589
1589
1590 def cacheable(self):
1590 def cacheable(self):
1591 if self._cacheable is not None:
1591 if self._cacheable is not None:
1592 return self._cacheable
1592 return self._cacheable
1593
1593
1594 # we don't know yet, assume it is for now
1594 # we don't know yet, assume it is for now
1595 return True
1595 return True
1596
1596
1597 def changed(self):
1597 def changed(self):
1598 # no point in going further if we can't cache it
1598 # no point in going further if we can't cache it
1599 if not self.cacheable():
1599 if not self.cacheable():
1600 return True
1600 return True
1601
1601
1602 newstat = filecachesubentry.stat(self.path)
1602 newstat = filecachesubentry.stat(self.path)
1603
1603
1604 # we may not know if it's cacheable yet, check again now
1604 # we may not know if it's cacheable yet, check again now
1605 if newstat and self._cacheable is None:
1605 if newstat and self._cacheable is None:
1606 self._cacheable = newstat.cacheable()
1606 self._cacheable = newstat.cacheable()
1607
1607
1608 # check again
1608 # check again
1609 if not self._cacheable:
1609 if not self._cacheable:
1610 return True
1610 return True
1611
1611
1612 if self.cachestat != newstat:
1612 if self.cachestat != newstat:
1613 self.cachestat = newstat
1613 self.cachestat = newstat
1614 return True
1614 return True
1615 else:
1615 else:
1616 return False
1616 return False
1617
1617
1618 @staticmethod
1618 @staticmethod
1619 def stat(path):
1619 def stat(path):
1620 try:
1620 try:
1621 return util.cachestat(path)
1621 return util.cachestat(path)
1622 except FileNotFoundError:
1622 except FileNotFoundError:
1623 pass
1623 pass
1624
1624
1625
1625
1626 class filecacheentry:
1626 class filecacheentry:
1627 def __init__(self, paths, stat=True):
1627 def __init__(self, paths, stat=True):
1628 self._entries = []
1628 self._entries = []
1629 for path in paths:
1629 for path in paths:
1630 self._entries.append(filecachesubentry(path, stat))
1630 self._entries.append(filecachesubentry(path, stat))
1631
1631
1632 def changed(self):
1632 def changed(self):
1633 '''true if any entry has changed'''
1633 '''true if any entry has changed'''
1634 for entry in self._entries:
1634 for entry in self._entries:
1635 if entry.changed():
1635 if entry.changed():
1636 return True
1636 return True
1637 return False
1637 return False
1638
1638
1639 def refresh(self):
1639 def refresh(self):
1640 for entry in self._entries:
1640 for entry in self._entries:
1641 entry.refresh()
1641 entry.refresh()
1642
1642
1643
1643
1644 class filecache:
1644 class filecache:
1645 """A property like decorator that tracks files under .hg/ for updates.
1645 """A property like decorator that tracks files under .hg/ for updates.
1646
1646
1647 On first access, the files defined as arguments are stat()ed and the
1647 On first access, the files defined as arguments are stat()ed and the
1648 results cached. The decorated function is called. The results are stashed
1648 results cached. The decorated function is called. The results are stashed
1649 away in a ``_filecache`` dict on the object whose method is decorated.
1649 away in a ``_filecache`` dict on the object whose method is decorated.
1650
1650
1651 On subsequent access, the cached result is used as it is set to the
1651 On subsequent access, the cached result is used as it is set to the
1652 instance dictionary.
1652 instance dictionary.
1653
1653
1654 On external property set/delete operations, the caller must update the
1654 On external property set/delete operations, the caller must update the
1655 corresponding _filecache entry appropriately. Use __class__.<attr>.set()
1655 corresponding _filecache entry appropriately. Use __class__.<attr>.set()
1656 instead of directly setting <attr>.
1656 instead of directly setting <attr>.
1657
1657
1658 When using the property API, the cached data is always used if available.
1658 When using the property API, the cached data is always used if available.
1659 No stat() is performed to check if the file has changed.
1659 No stat() is performed to check if the file has changed.
1660
1660
1661 Others can muck about with the state of the ``_filecache`` dict. e.g. they
1661 Others can muck about with the state of the ``_filecache`` dict. e.g. they
1662 can populate an entry before the property's getter is called. In this case,
1662 can populate an entry before the property's getter is called. In this case,
1663 entries in ``_filecache`` will be used during property operations,
1663 entries in ``_filecache`` will be used during property operations,
1664 if available. If the underlying file changes, it is up to external callers
1664 if available. If the underlying file changes, it is up to external callers
1665 to reflect this by e.g. calling ``delattr(obj, attr)`` to remove the cached
1665 to reflect this by e.g. calling ``delattr(obj, attr)`` to remove the cached
1666 method result as well as possibly calling ``del obj._filecache[attr]`` to
1666 method result as well as possibly calling ``del obj._filecache[attr]`` to
1667 remove the ``filecacheentry``.
1667 remove the ``filecacheentry``.
1668 """
1668 """
1669
1669
1670 def __init__(self, *paths):
1670 def __init__(self, *paths):
1671 self.paths = paths
1671 self.paths = paths
1672
1672
1673 def tracked_paths(self, obj):
1673 def tracked_paths(self, obj):
1674 return [self.join(obj, path) for path in self.paths]
1674 return [self.join(obj, path) for path in self.paths]
1675
1675
1676 def join(self, obj, fname):
1676 def join(self, obj, fname):
1677 """Used to compute the runtime path of a cached file.
1677 """Used to compute the runtime path of a cached file.
1678
1678
1679 Users should subclass filecache and provide their own version of this
1679 Users should subclass filecache and provide their own version of this
1680 function to call the appropriate join function on 'obj' (an instance
1680 function to call the appropriate join function on 'obj' (an instance
1681 of the class that its member function was decorated).
1681 of the class that its member function was decorated).
1682 """
1682 """
1683 raise NotImplementedError
1683 raise NotImplementedError
1684
1684
1685 def __call__(self, func):
1685 def __call__(self, func):
1686 self.func = func
1686 self.func = func
1687 self.sname = func.__name__
1687 self.sname = func.__name__
1688 self.name = pycompat.sysbytes(self.sname)
1688 self.name = pycompat.sysbytes(self.sname)
1689 return self
1689 return self
1690
1690
1691 def __get__(self, obj, type=None):
1691 def __get__(self, obj, type=None):
1692 # if accessed on the class, return the descriptor itself.
1692 # if accessed on the class, return the descriptor itself.
1693 if obj is None:
1693 if obj is None:
1694 return self
1694 return self
1695
1695
1696 assert self.sname not in obj.__dict__
1696 assert self.sname not in obj.__dict__
1697
1697
1698 entry = obj._filecache.get(self.name)
1698 entry = obj._filecache.get(self.name)
1699
1699
1700 if entry:
1700 if entry:
1701 if entry.changed():
1701 if entry.changed():
1702 entry.obj = self.func(obj)
1702 entry.obj = self.func(obj)
1703 else:
1703 else:
1704 paths = self.tracked_paths(obj)
1704 paths = self.tracked_paths(obj)
1705
1705
1706 # We stat -before- creating the object so our cache doesn't lie if
1706 # We stat -before- creating the object so our cache doesn't lie if
1707 # a writer modified between the time we read and stat
1707 # a writer modified between the time we read and stat
1708 entry = filecacheentry(paths, True)
1708 entry = filecacheentry(paths, True)
1709 entry.obj = self.func(obj)
1709 entry.obj = self.func(obj)
1710
1710
1711 obj._filecache[self.name] = entry
1711 obj._filecache[self.name] = entry
1712
1712
1713 obj.__dict__[self.sname] = entry.obj
1713 obj.__dict__[self.sname] = entry.obj
1714 return entry.obj
1714 return entry.obj
1715
1715
1716 # don't implement __set__(), which would make __dict__ lookup as slow as
1716 # don't implement __set__(), which would make __dict__ lookup as slow as
1717 # function call.
1717 # function call.
1718
1718
1719 def set(self, obj, value):
1719 def set(self, obj, value):
1720 if self.name not in obj._filecache:
1720 if self.name not in obj._filecache:
1721 # we add an entry for the missing value because X in __dict__
1721 # we add an entry for the missing value because X in __dict__
1722 # implies X in _filecache
1722 # implies X in _filecache
1723 paths = self.tracked_paths(obj)
1723 paths = self.tracked_paths(obj)
1724 ce = filecacheentry(paths, False)
1724 ce = filecacheentry(paths, False)
1725 obj._filecache[self.name] = ce
1725 obj._filecache[self.name] = ce
1726 else:
1726 else:
1727 ce = obj._filecache[self.name]
1727 ce = obj._filecache[self.name]
1728
1728
1729 ce.obj = value # update cached copy
1729 ce.obj = value # update cached copy
1730 obj.__dict__[self.sname] = value # update copy returned by obj.x
1730 obj.__dict__[self.sname] = value # update copy returned by obj.x
1731
1731
1732
1732
1733 def extdatasource(repo, source):
1733 def extdatasource(repo, source):
1734 """Gather a map of rev -> value dict from the specified source
1734 """Gather a map of rev -> value dict from the specified source
1735
1735
1736 A source spec is treated as a URL, with a special case shell: type
1736 A source spec is treated as a URL, with a special case shell: type
1737 for parsing the output from a shell command.
1737 for parsing the output from a shell command.
1738
1738
1739 The data is parsed as a series of newline-separated records where
1739 The data is parsed as a series of newline-separated records where
1740 each record is a revision specifier optionally followed by a space
1740 each record is a revision specifier optionally followed by a space
1741 and a freeform string value. If the revision is known locally, it
1741 and a freeform string value. If the revision is known locally, it
1742 is converted to a rev, otherwise the record is skipped.
1742 is converted to a rev, otherwise the record is skipped.
1743
1743
1744 Note that both key and value are treated as UTF-8 and converted to
1744 Note that both key and value are treated as UTF-8 and converted to
1745 the local encoding. This allows uniformity between local and
1745 the local encoding. This allows uniformity between local and
1746 remote data sources.
1746 remote data sources.
1747 """
1747 """
1748
1748
1749 spec = repo.ui.config(b"extdata", source)
1749 spec = repo.ui.config(b"extdata", source)
1750 if not spec:
1750 if not spec:
1751 raise error.Abort(_(b"unknown extdata source '%s'") % source)
1751 raise error.Abort(_(b"unknown extdata source '%s'") % source)
1752
1752
1753 data = {}
1753 data = {}
1754 src = proc = None
1754 src = proc = None
1755 try:
1755 try:
1756 if spec.startswith(b"shell:"):
1756 if spec.startswith(b"shell:"):
1757 # external commands should be run relative to the repo root
1757 # external commands should be run relative to the repo root
1758 cmd = spec[6:]
1758 cmd = spec[6:]
1759 proc = subprocess.Popen(
1759 proc = subprocess.Popen(
1760 procutil.tonativestr(cmd),
1760 procutil.tonativestr(cmd),
1761 shell=True,
1761 shell=True,
1762 bufsize=-1,
1762 bufsize=-1,
1763 close_fds=procutil.closefds,
1763 close_fds=procutil.closefds,
1764 stdout=subprocess.PIPE,
1764 stdout=subprocess.PIPE,
1765 cwd=procutil.tonativestr(repo.root),
1765 cwd=procutil.tonativestr(repo.root),
1766 )
1766 )
1767 src = proc.stdout
1767 src = proc.stdout
1768 else:
1768 else:
1769 # treat as a URL or file
1769 # treat as a URL or file
1770 src = url.open(repo.ui, spec)
1770 src = url.open(repo.ui, spec)
1771 for l in src:
1771 for l in src:
1772 if b" " in l:
1772 if b" " in l:
1773 k, v = l.strip().split(b" ", 1)
1773 k, v = l.strip().split(b" ", 1)
1774 else:
1774 else:
1775 k, v = l.strip(), b""
1775 k, v = l.strip(), b""
1776
1776
1777 k = encoding.tolocal(k)
1777 k = encoding.tolocal(k)
1778 try:
1778 try:
1779 data[revsingle(repo, k).rev()] = encoding.tolocal(v)
1779 data[revsingle(repo, k).rev()] = encoding.tolocal(v)
1780 except (error.LookupError, error.RepoLookupError, error.InputError):
1780 except (error.LookupError, error.RepoLookupError, error.InputError):
1781 pass # we ignore data for nodes that don't exist locally
1781 pass # we ignore data for nodes that don't exist locally
1782 finally:
1782 finally:
1783 if proc:
1783 if proc:
1784 try:
1784 try:
1785 proc.communicate()
1785 proc.communicate()
1786 except ValueError:
1786 except ValueError:
1787 # This happens if we started iterating src and then
1787 # This happens if we started iterating src and then
1788 # get a parse error on a line. It should be safe to ignore.
1788 # get a parse error on a line. It should be safe to ignore.
1789 pass
1789 pass
1790 if src:
1790 if src:
1791 src.close()
1791 src.close()
1792 if proc and proc.returncode != 0:
1792 if proc and proc.returncode != 0:
1793 raise error.Abort(
1793 raise error.Abort(
1794 _(b"extdata command '%s' failed: %s")
1794 _(b"extdata command '%s' failed: %s")
1795 % (cmd, procutil.explainexit(proc.returncode))
1795 % (cmd, procutil.explainexit(proc.returncode))
1796 )
1796 )
1797
1797
1798 return data
1798 return data
1799
1799
1800
1800
1801 class progress:
1801 class progress:
1802 def __init__(self, ui, updatebar, topic, unit=b"", total=None):
1802 def __init__(self, ui, updatebar, topic, unit=b"", total=None):
1803 self.ui = ui
1803 self.ui = ui
1804 self.pos = 0
1804 self.pos = 0
1805 self.topic = topic
1805 self.topic = topic
1806 self.unit = unit
1806 self.unit = unit
1807 self.total = total
1807 self.total = total
1808 self.debug = ui.configbool(b'progress', b'debug')
1808 self.debug = ui.configbool(b'progress', b'debug')
1809 self._updatebar = updatebar
1809 self._updatebar = updatebar
1810
1810
1811 def __enter__(self):
1811 def __enter__(self):
1812 return self
1812 return self
1813
1813
1814 def __exit__(self, exc_type, exc_value, exc_tb):
1814 def __exit__(self, exc_type, exc_value, exc_tb):
1815 self.complete()
1815 self.complete()
1816
1816
1817 def update(self, pos, item=b"", total=None):
1817 def update(self, pos, item=b"", total=None):
1818 assert pos is not None
1818 assert pos is not None
1819 if total:
1819 if total:
1820 self.total = total
1820 self.total = total
1821 self.pos = pos
1821 self.pos = pos
1822 self._updatebar(self.topic, self.pos, item, self.unit, self.total)
1822 self._updatebar(self.topic, self.pos, item, self.unit, self.total)
1823 if self.debug:
1823 if self.debug:
1824 self._printdebug(item)
1824 self._printdebug(item)
1825
1825
1826 def increment(self, step=1, item=b"", total=None):
1826 def increment(self, step=1, item=b"", total=None):
1827 self.update(self.pos + step, item, total)
1827 self.update(self.pos + step, item, total)
1828
1828
1829 def complete(self):
1829 def complete(self):
1830 self.pos = None
1830 self.pos = None
1831 self.unit = b""
1831 self.unit = b""
1832 self.total = None
1832 self.total = None
1833 self._updatebar(self.topic, self.pos, b"", self.unit, self.total)
1833 self._updatebar(self.topic, self.pos, b"", self.unit, self.total)
1834
1834
1835 def _printdebug(self, item):
1835 def _printdebug(self, item):
1836 unit = b''
1836 unit = b''
1837 if self.unit:
1837 if self.unit:
1838 unit = b' ' + self.unit
1838 unit = b' ' + self.unit
1839 if item:
1839 if item:
1840 item = b' ' + item
1840 item = b' ' + item
1841
1841
1842 if self.total:
1842 if self.total:
1843 pct = 100.0 * self.pos / self.total
1843 pct = 100.0 * self.pos / self.total
1844 self.ui.debug(
1844 self.ui.debug(
1845 b'%s:%s %d/%d%s (%4.2f%%)\n'
1845 b'%s:%s %d/%d%s (%4.2f%%)\n'
1846 % (self.topic, item, self.pos, self.total, unit, pct)
1846 % (self.topic, item, self.pos, self.total, unit, pct)
1847 )
1847 )
1848 else:
1848 else:
1849 self.ui.debug(b'%s:%s %d%s\n' % (self.topic, item, self.pos, unit))
1849 self.ui.debug(b'%s:%s %d%s\n' % (self.topic, item, self.pos, unit))
1850
1850
1851
1851
1852 def gdinitconfig(ui):
1852 def gdinitconfig(ui):
1853 """helper function to know if a repo should be created as general delta"""
1853 """helper function to know if a repo should be created as general delta"""
1854 # experimental config: format.generaldelta
1854 # experimental config: format.generaldelta
1855 return ui.configbool(b'format', b'generaldelta') or ui.configbool(
1855 return ui.configbool(b'format', b'generaldelta') or ui.configbool(
1856 b'format', b'usegeneraldelta'
1856 b'format', b'usegeneraldelta'
1857 )
1857 )
1858
1858
1859
1859
1860 def gddeltaconfig(ui):
1860 def gddeltaconfig(ui):
1861 """helper function to know if incoming delta should be optimised"""
1861 """helper function to know if incoming deltas should be optimized
1862
1863 The `format.generaldelta` config is an old form of the config that also
1864 implies that incoming delta-bases should be never be trusted. This function
1865 exists for this purpose.
1866 """
1862 # experimental config: format.generaldelta
1867 # experimental config: format.generaldelta
1863 return ui.configbool(b'format', b'generaldelta')
1868 return ui.configbool(b'format', b'generaldelta')
1864
1869
1865
1870
1866 class simplekeyvaluefile:
1871 class simplekeyvaluefile:
1867 """A simple file with key=value lines
1872 """A simple file with key=value lines
1868
1873
1869 Keys must be alphanumerics and start with a letter, values must not
1874 Keys must be alphanumerics and start with a letter, values must not
1870 contain '\n' characters"""
1875 contain '\n' characters"""
1871
1876
1872 firstlinekey = b'__firstline'
1877 firstlinekey = b'__firstline'
1873
1878
1874 def __init__(self, vfs, path, keys=None):
1879 def __init__(self, vfs, path, keys=None):
1875 self.vfs = vfs
1880 self.vfs = vfs
1876 self.path = path
1881 self.path = path
1877
1882
1878 def read(self, firstlinenonkeyval=False):
1883 def read(self, firstlinenonkeyval=False):
1879 """Read the contents of a simple key-value file
1884 """Read the contents of a simple key-value file
1880
1885
1881 'firstlinenonkeyval' indicates whether the first line of file should
1886 'firstlinenonkeyval' indicates whether the first line of file should
1882 be treated as a key-value pair or reuturned fully under the
1887 be treated as a key-value pair or reuturned fully under the
1883 __firstline key."""
1888 __firstline key."""
1884 lines = self.vfs.readlines(self.path)
1889 lines = self.vfs.readlines(self.path)
1885 d = {}
1890 d = {}
1886 if firstlinenonkeyval:
1891 if firstlinenonkeyval:
1887 if not lines:
1892 if not lines:
1888 e = _(b"empty simplekeyvalue file")
1893 e = _(b"empty simplekeyvalue file")
1889 raise error.CorruptedState(e)
1894 raise error.CorruptedState(e)
1890 # we don't want to include '\n' in the __firstline
1895 # we don't want to include '\n' in the __firstline
1891 d[self.firstlinekey] = lines[0][:-1]
1896 d[self.firstlinekey] = lines[0][:-1]
1892 del lines[0]
1897 del lines[0]
1893
1898
1894 try:
1899 try:
1895 # the 'if line.strip()' part prevents us from failing on empty
1900 # the 'if line.strip()' part prevents us from failing on empty
1896 # lines which only contain '\n' therefore are not skipped
1901 # lines which only contain '\n' therefore are not skipped
1897 # by 'if line'
1902 # by 'if line'
1898 updatedict = dict(
1903 updatedict = dict(
1899 line[:-1].split(b'=', 1) for line in lines if line.strip()
1904 line[:-1].split(b'=', 1) for line in lines if line.strip()
1900 )
1905 )
1901 if self.firstlinekey in updatedict:
1906 if self.firstlinekey in updatedict:
1902 e = _(b"%r can't be used as a key")
1907 e = _(b"%r can't be used as a key")
1903 raise error.CorruptedState(e % self.firstlinekey)
1908 raise error.CorruptedState(e % self.firstlinekey)
1904 d.update(updatedict)
1909 d.update(updatedict)
1905 except ValueError as e:
1910 except ValueError as e:
1906 raise error.CorruptedState(stringutil.forcebytestr(e))
1911 raise error.CorruptedState(stringutil.forcebytestr(e))
1907 return d
1912 return d
1908
1913
1909 def write(self, data, firstline=None):
1914 def write(self, data, firstline=None):
1910 """Write key=>value mapping to a file
1915 """Write key=>value mapping to a file
1911 data is a dict. Keys must be alphanumerical and start with a letter.
1916 data is a dict. Keys must be alphanumerical and start with a letter.
1912 Values must not contain newline characters.
1917 Values must not contain newline characters.
1913
1918
1914 If 'firstline' is not None, it is written to file before
1919 If 'firstline' is not None, it is written to file before
1915 everything else, as it is, not in a key=value form"""
1920 everything else, as it is, not in a key=value form"""
1916 lines = []
1921 lines = []
1917 if firstline is not None:
1922 if firstline is not None:
1918 lines.append(b'%s\n' % firstline)
1923 lines.append(b'%s\n' % firstline)
1919
1924
1920 for k, v in data.items():
1925 for k, v in data.items():
1921 if k == self.firstlinekey:
1926 if k == self.firstlinekey:
1922 e = b"key name '%s' is reserved" % self.firstlinekey
1927 e = b"key name '%s' is reserved" % self.firstlinekey
1923 raise error.ProgrammingError(e)
1928 raise error.ProgrammingError(e)
1924 if not k[0:1].isalpha():
1929 if not k[0:1].isalpha():
1925 e = b"keys must start with a letter in a key-value file"
1930 e = b"keys must start with a letter in a key-value file"
1926 raise error.ProgrammingError(e)
1931 raise error.ProgrammingError(e)
1927 if not k.isalnum():
1932 if not k.isalnum():
1928 e = b"invalid key name in a simple key-value file"
1933 e = b"invalid key name in a simple key-value file"
1929 raise error.ProgrammingError(e)
1934 raise error.ProgrammingError(e)
1930 if b'\n' in v:
1935 if b'\n' in v:
1931 e = b"invalid value in a simple key-value file"
1936 e = b"invalid value in a simple key-value file"
1932 raise error.ProgrammingError(e)
1937 raise error.ProgrammingError(e)
1933 lines.append(b"%s=%s\n" % (k, v))
1938 lines.append(b"%s=%s\n" % (k, v))
1934 with self.vfs(self.path, mode=b'wb', atomictemp=True) as fp:
1939 with self.vfs(self.path, mode=b'wb', atomictemp=True) as fp:
1935 fp.write(b''.join(lines))
1940 fp.write(b''.join(lines))
1936
1941
1937
1942
1938 _reportobsoletedsource = [
1943 _reportobsoletedsource = [
1939 b'debugobsolete',
1944 b'debugobsolete',
1940 b'pull',
1945 b'pull',
1941 b'push',
1946 b'push',
1942 b'serve',
1947 b'serve',
1943 b'unbundle',
1948 b'unbundle',
1944 ]
1949 ]
1945
1950
1946 _reportnewcssource = [
1951 _reportnewcssource = [
1947 b'pull',
1952 b'pull',
1948 b'unbundle',
1953 b'unbundle',
1949 ]
1954 ]
1950
1955
1951
1956
1952 def prefetchfiles(repo, revmatches):
1957 def prefetchfiles(repo, revmatches):
1953 """Invokes the registered file prefetch functions, allowing extensions to
1958 """Invokes the registered file prefetch functions, allowing extensions to
1954 ensure the corresponding files are available locally, before the command
1959 ensure the corresponding files are available locally, before the command
1955 uses them.
1960 uses them.
1956
1961
1957 Args:
1962 Args:
1958 revmatches: a list of (revision, match) tuples to indicate the files to
1963 revmatches: a list of (revision, match) tuples to indicate the files to
1959 fetch at each revision. If any of the match elements is None, it matches
1964 fetch at each revision. If any of the match elements is None, it matches
1960 all files.
1965 all files.
1961 """
1966 """
1962
1967
1963 def _matcher(m):
1968 def _matcher(m):
1964 if m:
1969 if m:
1965 assert isinstance(m, matchmod.basematcher)
1970 assert isinstance(m, matchmod.basematcher)
1966 # The command itself will complain about files that don't exist, so
1971 # The command itself will complain about files that don't exist, so
1967 # don't duplicate the message.
1972 # don't duplicate the message.
1968 return matchmod.badmatch(m, lambda fn, msg: None)
1973 return matchmod.badmatch(m, lambda fn, msg: None)
1969 else:
1974 else:
1970 return matchall(repo)
1975 return matchall(repo)
1971
1976
1972 revbadmatches = [(rev, _matcher(match)) for (rev, match) in revmatches]
1977 revbadmatches = [(rev, _matcher(match)) for (rev, match) in revmatches]
1973
1978
1974 fileprefetchhooks(repo, revbadmatches)
1979 fileprefetchhooks(repo, revbadmatches)
1975
1980
1976
1981
1977 # a list of (repo, revs, match) prefetch functions
1982 # a list of (repo, revs, match) prefetch functions
1978 fileprefetchhooks = util.hooks()
1983 fileprefetchhooks = util.hooks()
1979
1984
1980 # A marker that tells the evolve extension to suppress its own reporting
1985 # A marker that tells the evolve extension to suppress its own reporting
1981 _reportstroubledchangesets = True
1986 _reportstroubledchangesets = True
1982
1987
1983
1988
1984 def registersummarycallback(repo, otr, txnname=b'', as_validator=False):
1989 def registersummarycallback(repo, otr, txnname=b'', as_validator=False):
1985 """register a callback to issue a summary after the transaction is closed
1990 """register a callback to issue a summary after the transaction is closed
1986
1991
1987 If as_validator is true, then the callbacks are registered as transaction
1992 If as_validator is true, then the callbacks are registered as transaction
1988 validators instead
1993 validators instead
1989 """
1994 """
1990
1995
1991 def txmatch(sources):
1996 def txmatch(sources):
1992 return any(txnname.startswith(source) for source in sources)
1997 return any(txnname.startswith(source) for source in sources)
1993
1998
1994 categories = []
1999 categories = []
1995
2000
1996 def reportsummary(func):
2001 def reportsummary(func):
1997 """decorator for report callbacks."""
2002 """decorator for report callbacks."""
1998 # The repoview life cycle is shorter than the one of the actual
2003 # The repoview life cycle is shorter than the one of the actual
1999 # underlying repository. So the filtered object can die before the
2004 # underlying repository. So the filtered object can die before the
2000 # weakref is used leading to troubles. We keep a reference to the
2005 # weakref is used leading to troubles. We keep a reference to the
2001 # unfiltered object and restore the filtering when retrieving the
2006 # unfiltered object and restore the filtering when retrieving the
2002 # repository through the weakref.
2007 # repository through the weakref.
2003 filtername = repo.filtername
2008 filtername = repo.filtername
2004 reporef = weakref.ref(repo.unfiltered())
2009 reporef = weakref.ref(repo.unfiltered())
2005
2010
2006 def wrapped(tr):
2011 def wrapped(tr):
2007 repo = reporef()
2012 repo = reporef()
2008 if filtername:
2013 if filtername:
2009 assert repo is not None # help pytype
2014 assert repo is not None # help pytype
2010 repo = repo.filtered(filtername)
2015 repo = repo.filtered(filtername)
2011 func(repo, tr)
2016 func(repo, tr)
2012
2017
2013 newcat = b'%02i-txnreport' % len(categories)
2018 newcat = b'%02i-txnreport' % len(categories)
2014 if as_validator:
2019 if as_validator:
2015 otr.addvalidator(newcat, wrapped)
2020 otr.addvalidator(newcat, wrapped)
2016 else:
2021 else:
2017 otr.addpostclose(newcat, wrapped)
2022 otr.addpostclose(newcat, wrapped)
2018 categories.append(newcat)
2023 categories.append(newcat)
2019 return wrapped
2024 return wrapped
2020
2025
2021 @reportsummary
2026 @reportsummary
2022 def reportchangegroup(repo, tr):
2027 def reportchangegroup(repo, tr):
2023 cgchangesets = tr.changes.get(b'changegroup-count-changesets', 0)
2028 cgchangesets = tr.changes.get(b'changegroup-count-changesets', 0)
2024 cgrevisions = tr.changes.get(b'changegroup-count-revisions', 0)
2029 cgrevisions = tr.changes.get(b'changegroup-count-revisions', 0)
2025 cgfiles = tr.changes.get(b'changegroup-count-files', 0)
2030 cgfiles = tr.changes.get(b'changegroup-count-files', 0)
2026 cgheads = tr.changes.get(b'changegroup-count-heads', 0)
2031 cgheads = tr.changes.get(b'changegroup-count-heads', 0)
2027 if cgchangesets or cgrevisions or cgfiles:
2032 if cgchangesets or cgrevisions or cgfiles:
2028 htext = b""
2033 htext = b""
2029 if cgheads:
2034 if cgheads:
2030 htext = _(b" (%+d heads)") % cgheads
2035 htext = _(b" (%+d heads)") % cgheads
2031 msg = _(b"added %d changesets with %d changes to %d files%s\n")
2036 msg = _(b"added %d changesets with %d changes to %d files%s\n")
2032 if as_validator:
2037 if as_validator:
2033 msg = _(b"adding %d changesets with %d changes to %d files%s\n")
2038 msg = _(b"adding %d changesets with %d changes to %d files%s\n")
2034 assert repo is not None # help pytype
2039 assert repo is not None # help pytype
2035 repo.ui.status(msg % (cgchangesets, cgrevisions, cgfiles, htext))
2040 repo.ui.status(msg % (cgchangesets, cgrevisions, cgfiles, htext))
2036
2041
2037 if txmatch(_reportobsoletedsource):
2042 if txmatch(_reportobsoletedsource):
2038
2043
2039 @reportsummary
2044 @reportsummary
2040 def reportobsoleted(repo, tr):
2045 def reportobsoleted(repo, tr):
2041 obsoleted = obsutil.getobsoleted(repo, tr)
2046 obsoleted = obsutil.getobsoleted(repo, tr)
2042 newmarkers = len(tr.changes.get(b'obsmarkers', ()))
2047 newmarkers = len(tr.changes.get(b'obsmarkers', ()))
2043 if newmarkers:
2048 if newmarkers:
2044 repo.ui.status(_(b'%i new obsolescence markers\n') % newmarkers)
2049 repo.ui.status(_(b'%i new obsolescence markers\n') % newmarkers)
2045 if obsoleted:
2050 if obsoleted:
2046 msg = _(b'obsoleted %i changesets\n')
2051 msg = _(b'obsoleted %i changesets\n')
2047 if as_validator:
2052 if as_validator:
2048 msg = _(b'obsoleting %i changesets\n')
2053 msg = _(b'obsoleting %i changesets\n')
2049 repo.ui.status(msg % len(obsoleted))
2054 repo.ui.status(msg % len(obsoleted))
2050
2055
2051 if obsolete.isenabled(
2056 if obsolete.isenabled(
2052 repo, obsolete.createmarkersopt
2057 repo, obsolete.createmarkersopt
2053 ) and repo.ui.configbool(
2058 ) and repo.ui.configbool(
2054 b'experimental', b'evolution.report-instabilities'
2059 b'experimental', b'evolution.report-instabilities'
2055 ):
2060 ):
2056 instabilitytypes = [
2061 instabilitytypes = [
2057 (b'orphan', b'orphan'),
2062 (b'orphan', b'orphan'),
2058 (b'phase-divergent', b'phasedivergent'),
2063 (b'phase-divergent', b'phasedivergent'),
2059 (b'content-divergent', b'contentdivergent'),
2064 (b'content-divergent', b'contentdivergent'),
2060 ]
2065 ]
2061
2066
2062 def getinstabilitycounts(repo):
2067 def getinstabilitycounts(repo):
2063 filtered = repo.changelog.filteredrevs
2068 filtered = repo.changelog.filteredrevs
2064 counts = {}
2069 counts = {}
2065 for instability, revset in instabilitytypes:
2070 for instability, revset in instabilitytypes:
2066 counts[instability] = len(
2071 counts[instability] = len(
2067 set(obsolete.getrevs(repo, revset)) - filtered
2072 set(obsolete.getrevs(repo, revset)) - filtered
2068 )
2073 )
2069 return counts
2074 return counts
2070
2075
2071 oldinstabilitycounts = getinstabilitycounts(repo)
2076 oldinstabilitycounts = getinstabilitycounts(repo)
2072
2077
2073 @reportsummary
2078 @reportsummary
2074 def reportnewinstabilities(repo, tr):
2079 def reportnewinstabilities(repo, tr):
2075 newinstabilitycounts = getinstabilitycounts(repo)
2080 newinstabilitycounts = getinstabilitycounts(repo)
2076 for instability, revset in instabilitytypes:
2081 for instability, revset in instabilitytypes:
2077 delta = (
2082 delta = (
2078 newinstabilitycounts[instability]
2083 newinstabilitycounts[instability]
2079 - oldinstabilitycounts[instability]
2084 - oldinstabilitycounts[instability]
2080 )
2085 )
2081 msg = getinstabilitymessage(delta, instability)
2086 msg = getinstabilitymessage(delta, instability)
2082 if msg:
2087 if msg:
2083 repo.ui.warn(msg)
2088 repo.ui.warn(msg)
2084
2089
2085 if txmatch(_reportnewcssource):
2090 if txmatch(_reportnewcssource):
2086
2091
2087 @reportsummary
2092 @reportsummary
2088 def reportnewcs(repo, tr):
2093 def reportnewcs(repo, tr):
2089 """Report the range of new revisions pulled/unbundled."""
2094 """Report the range of new revisions pulled/unbundled."""
2090 origrepolen = tr.changes.get(b'origrepolen', len(repo))
2095 origrepolen = tr.changes.get(b'origrepolen', len(repo))
2091 unfi = repo.unfiltered()
2096 unfi = repo.unfiltered()
2092 if origrepolen >= len(unfi):
2097 if origrepolen >= len(unfi):
2093 return
2098 return
2094
2099
2095 # Compute the bounds of new visible revisions' range.
2100 # Compute the bounds of new visible revisions' range.
2096 revs = smartset.spanset(repo, start=origrepolen)
2101 revs = smartset.spanset(repo, start=origrepolen)
2097 if revs:
2102 if revs:
2098 minrev, maxrev = repo[revs.min()], repo[revs.max()]
2103 minrev, maxrev = repo[revs.min()], repo[revs.max()]
2099
2104
2100 if minrev == maxrev:
2105 if minrev == maxrev:
2101 revrange = minrev
2106 revrange = minrev
2102 else:
2107 else:
2103 revrange = b'%s:%s' % (minrev, maxrev)
2108 revrange = b'%s:%s' % (minrev, maxrev)
2104 draft = len(repo.revs(b'%ld and draft()', revs))
2109 draft = len(repo.revs(b'%ld and draft()', revs))
2105 secret = len(repo.revs(b'%ld and secret()', revs))
2110 secret = len(repo.revs(b'%ld and secret()', revs))
2106 if not (draft or secret):
2111 if not (draft or secret):
2107 msg = _(b'new changesets %s\n') % revrange
2112 msg = _(b'new changesets %s\n') % revrange
2108 elif draft and secret:
2113 elif draft and secret:
2109 msg = _(b'new changesets %s (%d drafts, %d secrets)\n')
2114 msg = _(b'new changesets %s (%d drafts, %d secrets)\n')
2110 msg %= (revrange, draft, secret)
2115 msg %= (revrange, draft, secret)
2111 elif draft:
2116 elif draft:
2112 msg = _(b'new changesets %s (%d drafts)\n')
2117 msg = _(b'new changesets %s (%d drafts)\n')
2113 msg %= (revrange, draft)
2118 msg %= (revrange, draft)
2114 elif secret:
2119 elif secret:
2115 msg = _(b'new changesets %s (%d secrets)\n')
2120 msg = _(b'new changesets %s (%d secrets)\n')
2116 msg %= (revrange, secret)
2121 msg %= (revrange, secret)
2117 else:
2122 else:
2118 errormsg = b'entered unreachable condition'
2123 errormsg = b'entered unreachable condition'
2119 raise error.ProgrammingError(errormsg)
2124 raise error.ProgrammingError(errormsg)
2120 repo.ui.status(msg)
2125 repo.ui.status(msg)
2121
2126
2122 # search new changesets directly pulled as obsolete
2127 # search new changesets directly pulled as obsolete
2123 duplicates = tr.changes.get(b'revduplicates', ())
2128 duplicates = tr.changes.get(b'revduplicates', ())
2124 obsadded = unfi.revs(
2129 obsadded = unfi.revs(
2125 b'(%d: + %ld) and obsolete()', origrepolen, duplicates
2130 b'(%d: + %ld) and obsolete()', origrepolen, duplicates
2126 )
2131 )
2127 cl = repo.changelog
2132 cl = repo.changelog
2128 extinctadded = [r for r in obsadded if r not in cl]
2133 extinctadded = [r for r in obsadded if r not in cl]
2129 if extinctadded:
2134 if extinctadded:
2130 # They are not just obsolete, but obsolete and invisible
2135 # They are not just obsolete, but obsolete and invisible
2131 # we call them "extinct" internally but the terms have not been
2136 # we call them "extinct" internally but the terms have not been
2132 # exposed to users.
2137 # exposed to users.
2133 msg = b'(%d other changesets obsolete on arrival)\n'
2138 msg = b'(%d other changesets obsolete on arrival)\n'
2134 repo.ui.status(msg % len(extinctadded))
2139 repo.ui.status(msg % len(extinctadded))
2135
2140
2136 @reportsummary
2141 @reportsummary
2137 def reportphasechanges(repo, tr):
2142 def reportphasechanges(repo, tr):
2138 """Report statistics of phase changes for changesets pre-existing
2143 """Report statistics of phase changes for changesets pre-existing
2139 pull/unbundle.
2144 pull/unbundle.
2140 """
2145 """
2141 origrepolen = tr.changes.get(b'origrepolen', len(repo))
2146 origrepolen = tr.changes.get(b'origrepolen', len(repo))
2142 published = []
2147 published = []
2143 for revs, (old, new) in tr.changes.get(b'phases', []):
2148 for revs, (old, new) in tr.changes.get(b'phases', []):
2144 if new != phases.public:
2149 if new != phases.public:
2145 continue
2150 continue
2146 published.extend(rev for rev in revs if rev < origrepolen)
2151 published.extend(rev for rev in revs if rev < origrepolen)
2147 if not published:
2152 if not published:
2148 return
2153 return
2149 msg = _(b'%d local changesets published\n')
2154 msg = _(b'%d local changesets published\n')
2150 if as_validator:
2155 if as_validator:
2151 msg = _(b'%d local changesets will be published\n')
2156 msg = _(b'%d local changesets will be published\n')
2152 repo.ui.status(msg % len(published))
2157 repo.ui.status(msg % len(published))
2153
2158
2154
2159
2155 def getinstabilitymessage(delta, instability):
2160 def getinstabilitymessage(delta, instability):
2156 """function to return the message to show warning about new instabilities
2161 """function to return the message to show warning about new instabilities
2157
2162
2158 exists as a separate function so that extension can wrap to show more
2163 exists as a separate function so that extension can wrap to show more
2159 information like how to fix instabilities"""
2164 information like how to fix instabilities"""
2160 if delta > 0:
2165 if delta > 0:
2161 return _(b'%i new %s changesets\n') % (delta, instability)
2166 return _(b'%i new %s changesets\n') % (delta, instability)
2162
2167
2163
2168
2164 def nodesummaries(repo, nodes, maxnumnodes=4):
2169 def nodesummaries(repo, nodes, maxnumnodes=4):
2165 if len(nodes) <= maxnumnodes or repo.ui.verbose:
2170 if len(nodes) <= maxnumnodes or repo.ui.verbose:
2166 return b' '.join(short(h) for h in nodes)
2171 return b' '.join(short(h) for h in nodes)
2167 first = b' '.join(short(h) for h in nodes[:maxnumnodes])
2172 first = b' '.join(short(h) for h in nodes[:maxnumnodes])
2168 return _(b"%s and %d others") % (first, len(nodes) - maxnumnodes)
2173 return _(b"%s and %d others") % (first, len(nodes) - maxnumnodes)
2169
2174
2170
2175
2171 def enforcesinglehead(repo, tr, desc, accountclosed, filtername):
2176 def enforcesinglehead(repo, tr, desc, accountclosed, filtername):
2172 """check that no named branch has multiple heads"""
2177 """check that no named branch has multiple heads"""
2173 if desc in (b'strip', b'repair'):
2178 if desc in (b'strip', b'repair'):
2174 # skip the logic during strip
2179 # skip the logic during strip
2175 return
2180 return
2176 visible = repo.filtered(filtername)
2181 visible = repo.filtered(filtername)
2177 # possible improvement: we could restrict the check to affected branch
2182 # possible improvement: we could restrict the check to affected branch
2178 bm = visible.branchmap()
2183 bm = visible.branchmap()
2179 for name in bm:
2184 for name in bm:
2180 heads = bm.branchheads(name, closed=accountclosed)
2185 heads = bm.branchheads(name, closed=accountclosed)
2181 if len(heads) > 1:
2186 if len(heads) > 1:
2182 msg = _(b'rejecting multiple heads on branch "%s"')
2187 msg = _(b'rejecting multiple heads on branch "%s"')
2183 msg %= name
2188 msg %= name
2184 hint = _(b'%d heads: %s')
2189 hint = _(b'%d heads: %s')
2185 hint %= (len(heads), nodesummaries(repo, heads))
2190 hint %= (len(heads), nodesummaries(repo, heads))
2186 raise error.Abort(msg, hint=hint)
2191 raise error.Abort(msg, hint=hint)
2187
2192
2188
2193
2189 def wrapconvertsink(sink):
2194 def wrapconvertsink(sink):
2190 """Allow extensions to wrap the sink returned by convcmd.convertsink()
2195 """Allow extensions to wrap the sink returned by convcmd.convertsink()
2191 before it is used, whether or not the convert extension was formally loaded.
2196 before it is used, whether or not the convert extension was formally loaded.
2192 """
2197 """
2193 return sink
2198 return sink
2194
2199
2195
2200
2196 def unhidehashlikerevs(repo, specs, hiddentype):
2201 def unhidehashlikerevs(repo, specs, hiddentype):
2197 """parse the user specs and unhide changesets whose hash or revision number
2202 """parse the user specs and unhide changesets whose hash or revision number
2198 is passed.
2203 is passed.
2199
2204
2200 hiddentype can be: 1) 'warn': warn while unhiding changesets
2205 hiddentype can be: 1) 'warn': warn while unhiding changesets
2201 2) 'nowarn': don't warn while unhiding changesets
2206 2) 'nowarn': don't warn while unhiding changesets
2202
2207
2203 returns a repo object with the required changesets unhidden
2208 returns a repo object with the required changesets unhidden
2204 """
2209 """
2205 if not specs:
2210 if not specs:
2206 return repo
2211 return repo
2207
2212
2208 if not repo.filtername or not repo.ui.configbool(
2213 if not repo.filtername or not repo.ui.configbool(
2209 b'experimental', b'directaccess'
2214 b'experimental', b'directaccess'
2210 ):
2215 ):
2211 return repo
2216 return repo
2212
2217
2213 if repo.filtername not in (b'visible', b'visible-hidden'):
2218 if repo.filtername not in (b'visible', b'visible-hidden'):
2214 return repo
2219 return repo
2215
2220
2216 symbols = set()
2221 symbols = set()
2217 for spec in specs:
2222 for spec in specs:
2218 try:
2223 try:
2219 tree = revsetlang.parse(spec)
2224 tree = revsetlang.parse(spec)
2220 except error.ParseError: # will be reported by scmutil.revrange()
2225 except error.ParseError: # will be reported by scmutil.revrange()
2221 continue
2226 continue
2222
2227
2223 symbols.update(revsetlang.gethashlikesymbols(tree))
2228 symbols.update(revsetlang.gethashlikesymbols(tree))
2224
2229
2225 if not symbols:
2230 if not symbols:
2226 return repo
2231 return repo
2227
2232
2228 revs = _getrevsfromsymbols(repo, symbols)
2233 revs = _getrevsfromsymbols(repo, symbols)
2229
2234
2230 if not revs:
2235 if not revs:
2231 return repo
2236 return repo
2232
2237
2233 if hiddentype == b'warn':
2238 if hiddentype == b'warn':
2234 unfi = repo.unfiltered()
2239 unfi = repo.unfiltered()
2235 revstr = b", ".join([pycompat.bytestr(unfi[l]) for l in revs])
2240 revstr = b", ".join([pycompat.bytestr(unfi[l]) for l in revs])
2236 repo.ui.warn(
2241 repo.ui.warn(
2237 _(
2242 _(
2238 b"warning: accessing hidden changesets for write "
2243 b"warning: accessing hidden changesets for write "
2239 b"operation: %s\n"
2244 b"operation: %s\n"
2240 )
2245 )
2241 % revstr
2246 % revstr
2242 )
2247 )
2243
2248
2244 # we have to use new filtername to separate branch/tags cache until we can
2249 # we have to use new filtername to separate branch/tags cache until we can
2245 # disbale these cache when revisions are dynamically pinned.
2250 # disbale these cache when revisions are dynamically pinned.
2246 return repo.filtered(b'visible-hidden', revs)
2251 return repo.filtered(b'visible-hidden', revs)
2247
2252
2248
2253
2249 def _getrevsfromsymbols(repo, symbols):
2254 def _getrevsfromsymbols(repo, symbols):
2250 """parse the list of symbols and returns a set of revision numbers of hidden
2255 """parse the list of symbols and returns a set of revision numbers of hidden
2251 changesets present in symbols"""
2256 changesets present in symbols"""
2252 revs = set()
2257 revs = set()
2253 unfi = repo.unfiltered()
2258 unfi = repo.unfiltered()
2254 unficl = unfi.changelog
2259 unficl = unfi.changelog
2255 cl = repo.changelog
2260 cl = repo.changelog
2256 tiprev = len(unficl)
2261 tiprev = len(unficl)
2257 allowrevnums = repo.ui.configbool(b'experimental', b'directaccess.revnums')
2262 allowrevnums = repo.ui.configbool(b'experimental', b'directaccess.revnums')
2258 for s in symbols:
2263 for s in symbols:
2259 try:
2264 try:
2260 n = int(s)
2265 n = int(s)
2261 if n <= tiprev:
2266 if n <= tiprev:
2262 if not allowrevnums:
2267 if not allowrevnums:
2263 continue
2268 continue
2264 else:
2269 else:
2265 if n not in cl:
2270 if n not in cl:
2266 revs.add(n)
2271 revs.add(n)
2267 continue
2272 continue
2268 except ValueError:
2273 except ValueError:
2269 pass
2274 pass
2270
2275
2271 try:
2276 try:
2272 s = resolvehexnodeidprefix(unfi, s)
2277 s = resolvehexnodeidprefix(unfi, s)
2273 except (error.LookupError, error.WdirUnsupported):
2278 except (error.LookupError, error.WdirUnsupported):
2274 s = None
2279 s = None
2275
2280
2276 if s is not None:
2281 if s is not None:
2277 rev = unficl.rev(s)
2282 rev = unficl.rev(s)
2278 if rev not in cl:
2283 if rev not in cl:
2279 revs.add(rev)
2284 revs.add(rev)
2280
2285
2281 return revs
2286 return revs
2282
2287
2283
2288
2284 def bookmarkrevs(repo, mark):
2289 def bookmarkrevs(repo, mark):
2285 """Select revisions reachable by a given bookmark
2290 """Select revisions reachable by a given bookmark
2286
2291
2287 If the bookmarked revision isn't a head, an empty set will be returned.
2292 If the bookmarked revision isn't a head, an empty set will be returned.
2288 """
2293 """
2289 return repo.revs(format_bookmark_revspec(mark))
2294 return repo.revs(format_bookmark_revspec(mark))
2290
2295
2291
2296
2292 def format_bookmark_revspec(mark):
2297 def format_bookmark_revspec(mark):
2293 """Build a revset expression to select revisions reachable by a given
2298 """Build a revset expression to select revisions reachable by a given
2294 bookmark"""
2299 bookmark"""
2295 mark = b'literal:' + mark
2300 mark = b'literal:' + mark
2296 return revsetlang.formatspec(
2301 return revsetlang.formatspec(
2297 b"ancestors(bookmark(%s)) - "
2302 b"ancestors(bookmark(%s)) - "
2298 b"ancestors(head() and not bookmark(%s)) - "
2303 b"ancestors(head() and not bookmark(%s)) - "
2299 b"ancestors(bookmark() and not bookmark(%s))",
2304 b"ancestors(bookmark() and not bookmark(%s))",
2300 mark,
2305 mark,
2301 mark,
2306 mark,
2302 mark,
2307 mark,
2303 )
2308 )
General Comments 0
You need to be logged in to leave comments. Login now