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