##// END OF EJS Templates
log: add config for making `hg log -G` always topo-sorted...
Martin von Zweigbergk -
r42496:a39f8aa6 default draft
parent child Browse files
Show More
@@ -1,1487 +1,1490
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 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in sorted(configtable.items()):
20 for section, items in sorted(configtable.items()):
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 baseitem = super(itemregister, self).get(key)
70 baseitem = super(itemregister, self).get(key)
71 if baseitem is not None and not baseitem.generic:
71 if baseitem is not None and not baseitem.generic:
72 return baseitem
72 return baseitem
73
73
74 # search for a matching generic item
74 # search for a matching generic item
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 for item in generics:
76 for item in generics:
77 # we use 'match' instead of 'search' to make the matching simpler
77 # we use 'match' instead of 'search' to make the matching simpler
78 # for people unfamiliar with regular expression. Having the match
78 # for people unfamiliar with regular expression. Having the match
79 # rooted to the start of the string will produce less surprising
79 # rooted to the start of the string will produce less surprising
80 # result for user writing simple regex for sub-attribute.
80 # result for user writing simple regex for sub-attribute.
81 #
81 #
82 # For example using "color\..*" match produces an unsurprising
82 # For example using "color\..*" match produces an unsurprising
83 # result, while using search could suddenly match apparently
83 # result, while using search could suddenly match apparently
84 # unrelated configuration that happens to contains "color."
84 # unrelated configuration that happens to contains "color."
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 # some match to avoid the need to prefix most pattern with "^".
86 # some match to avoid the need to prefix most pattern with "^".
87 # The "^" seems more error prone.
87 # The "^" seems more error prone.
88 if item._re.match(key):
88 if item._re.match(key):
89 return item
89 return item
90
90
91 return None
91 return None
92
92
93 coreitems = {}
93 coreitems = {}
94
94
95 def _register(configtable, *args, **kwargs):
95 def _register(configtable, *args, **kwargs):
96 item = configitem(*args, **kwargs)
96 item = configitem(*args, **kwargs)
97 section = configtable.setdefault(item.section, itemregister())
97 section = configtable.setdefault(item.section, itemregister())
98 if item.name in section:
98 if item.name in section:
99 msg = "duplicated config item registration for '%s.%s'"
99 msg = "duplicated config item registration for '%s.%s'"
100 raise error.ProgrammingError(msg % (item.section, item.name))
100 raise error.ProgrammingError(msg % (item.section, item.name))
101 section[item.name] = item
101 section[item.name] = item
102
102
103 # special value for case where the default is derived from other values
103 # special value for case where the default is derived from other values
104 dynamicdefault = object()
104 dynamicdefault = object()
105
105
106 # Registering actual config items
106 # Registering actual config items
107
107
108 def getitemregister(configtable):
108 def getitemregister(configtable):
109 f = functools.partial(_register, configtable)
109 f = functools.partial(_register, configtable)
110 # export pseudo enum as configitem.*
110 # export pseudo enum as configitem.*
111 f.dynamicdefault = dynamicdefault
111 f.dynamicdefault = dynamicdefault
112 return f
112 return f
113
113
114 coreconfigitem = getitemregister(coreitems)
114 coreconfigitem = getitemregister(coreitems)
115
115
116 def _registerdiffopts(section, configprefix=''):
116 def _registerdiffopts(section, configprefix=''):
117 coreconfigitem(section, configprefix + 'nodates',
117 coreconfigitem(section, configprefix + 'nodates',
118 default=False,
118 default=False,
119 )
119 )
120 coreconfigitem(section, configprefix + 'showfunc',
120 coreconfigitem(section, configprefix + 'showfunc',
121 default=False,
121 default=False,
122 )
122 )
123 coreconfigitem(section, configprefix + 'unified',
123 coreconfigitem(section, configprefix + 'unified',
124 default=None,
124 default=None,
125 )
125 )
126 coreconfigitem(section, configprefix + 'git',
126 coreconfigitem(section, configprefix + 'git',
127 default=False,
127 default=False,
128 )
128 )
129 coreconfigitem(section, configprefix + 'ignorews',
129 coreconfigitem(section, configprefix + 'ignorews',
130 default=False,
130 default=False,
131 )
131 )
132 coreconfigitem(section, configprefix + 'ignorewsamount',
132 coreconfigitem(section, configprefix + 'ignorewsamount',
133 default=False,
133 default=False,
134 )
134 )
135 coreconfigitem(section, configprefix + 'ignoreblanklines',
135 coreconfigitem(section, configprefix + 'ignoreblanklines',
136 default=False,
136 default=False,
137 )
137 )
138 coreconfigitem(section, configprefix + 'ignorewseol',
138 coreconfigitem(section, configprefix + 'ignorewseol',
139 default=False,
139 default=False,
140 )
140 )
141 coreconfigitem(section, configprefix + 'nobinary',
141 coreconfigitem(section, configprefix + 'nobinary',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem(section, configprefix + 'noprefix',
144 coreconfigitem(section, configprefix + 'noprefix',
145 default=False,
145 default=False,
146 )
146 )
147 coreconfigitem(section, configprefix + 'word-diff',
147 coreconfigitem(section, configprefix + 'word-diff',
148 default=False,
148 default=False,
149 )
149 )
150
150
151 coreconfigitem('alias', '.*',
151 coreconfigitem('alias', '.*',
152 default=dynamicdefault,
152 default=dynamicdefault,
153 generic=True,
153 generic=True,
154 )
154 )
155 coreconfigitem('auth', 'cookiefile',
155 coreconfigitem('auth', 'cookiefile',
156 default=None,
156 default=None,
157 )
157 )
158 _registerdiffopts(section='annotate')
158 _registerdiffopts(section='annotate')
159 # bookmarks.pushing: internal hack for discovery
159 # bookmarks.pushing: internal hack for discovery
160 coreconfigitem('bookmarks', 'pushing',
160 coreconfigitem('bookmarks', 'pushing',
161 default=list,
161 default=list,
162 )
162 )
163 # bundle.mainreporoot: internal hack for bundlerepo
163 # bundle.mainreporoot: internal hack for bundlerepo
164 coreconfigitem('bundle', 'mainreporoot',
164 coreconfigitem('bundle', 'mainreporoot',
165 default='',
165 default='',
166 )
166 )
167 coreconfigitem('censor', 'policy',
167 coreconfigitem('censor', 'policy',
168 default='abort',
168 default='abort',
169 )
169 )
170 coreconfigitem('chgserver', 'idletimeout',
170 coreconfigitem('chgserver', 'idletimeout',
171 default=3600,
171 default=3600,
172 )
172 )
173 coreconfigitem('chgserver', 'skiphash',
173 coreconfigitem('chgserver', 'skiphash',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('cmdserver', 'log',
176 coreconfigitem('cmdserver', 'log',
177 default=None,
177 default=None,
178 )
178 )
179 coreconfigitem('cmdserver', 'max-log-files',
179 coreconfigitem('cmdserver', 'max-log-files',
180 default=7,
180 default=7,
181 )
181 )
182 coreconfigitem('cmdserver', 'max-log-size',
182 coreconfigitem('cmdserver', 'max-log-size',
183 default='1 MB',
183 default='1 MB',
184 )
184 )
185 coreconfigitem('cmdserver', 'max-repo-cache',
185 coreconfigitem('cmdserver', 'max-repo-cache',
186 default=0,
186 default=0,
187 )
187 )
188 coreconfigitem('cmdserver', 'message-encodings',
188 coreconfigitem('cmdserver', 'message-encodings',
189 default=list,
189 default=list,
190 )
190 )
191 coreconfigitem('cmdserver', 'track-log',
191 coreconfigitem('cmdserver', 'track-log',
192 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
192 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
193 )
193 )
194 coreconfigitem('color', '.*',
194 coreconfigitem('color', '.*',
195 default=None,
195 default=None,
196 generic=True,
196 generic=True,
197 )
197 )
198 coreconfigitem('color', 'mode',
198 coreconfigitem('color', 'mode',
199 default='auto',
199 default='auto',
200 )
200 )
201 coreconfigitem('color', 'pagermode',
201 coreconfigitem('color', 'pagermode',
202 default=dynamicdefault,
202 default=dynamicdefault,
203 )
203 )
204 _registerdiffopts(section='commands', configprefix='commit.interactive.')
204 _registerdiffopts(section='commands', configprefix='commit.interactive.')
205 coreconfigitem('commands', 'commit.post-status',
205 coreconfigitem('commands', 'commit.post-status',
206 default=False,
206 default=False,
207 )
207 )
208 coreconfigitem('commands', 'grep.all-files',
208 coreconfigitem('commands', 'grep.all-files',
209 default=False,
209 default=False,
210 )
210 )
211 coreconfigitem('commands', 'resolve.confirm',
211 coreconfigitem('commands', 'resolve.confirm',
212 default=False,
212 default=False,
213 )
213 )
214 coreconfigitem('commands', 'resolve.explicit-re-merge',
214 coreconfigitem('commands', 'resolve.explicit-re-merge',
215 default=False,
215 default=False,
216 )
216 )
217 coreconfigitem('commands', 'resolve.mark-check',
217 coreconfigitem('commands', 'resolve.mark-check',
218 default='none',
218 default='none',
219 )
219 )
220 _registerdiffopts(section='commands', configprefix='revert.interactive.')
220 _registerdiffopts(section='commands', configprefix='revert.interactive.')
221 coreconfigitem('commands', 'show.aliasprefix',
221 coreconfigitem('commands', 'show.aliasprefix',
222 default=list,
222 default=list,
223 )
223 )
224 coreconfigitem('commands', 'status.relative',
224 coreconfigitem('commands', 'status.relative',
225 default=False,
225 default=False,
226 )
226 )
227 coreconfigitem('commands', 'status.skipstates',
227 coreconfigitem('commands', 'status.skipstates',
228 default=[],
228 default=[],
229 )
229 )
230 coreconfigitem('commands', 'status.terse',
230 coreconfigitem('commands', 'status.terse',
231 default='',
231 default='',
232 )
232 )
233 coreconfigitem('commands', 'status.verbose',
233 coreconfigitem('commands', 'status.verbose',
234 default=False,
234 default=False,
235 )
235 )
236 coreconfigitem('commands', 'update.check',
236 coreconfigitem('commands', 'update.check',
237 default=None,
237 default=None,
238 )
238 )
239 coreconfigitem('commands', 'update.requiredest',
239 coreconfigitem('commands', 'update.requiredest',
240 default=False,
240 default=False,
241 )
241 )
242 coreconfigitem('committemplate', '.*',
242 coreconfigitem('committemplate', '.*',
243 default=None,
243 default=None,
244 generic=True,
244 generic=True,
245 )
245 )
246 coreconfigitem('convert', 'bzr.saverev',
246 coreconfigitem('convert', 'bzr.saverev',
247 default=True,
247 default=True,
248 )
248 )
249 coreconfigitem('convert', 'cvsps.cache',
249 coreconfigitem('convert', 'cvsps.cache',
250 default=True,
250 default=True,
251 )
251 )
252 coreconfigitem('convert', 'cvsps.fuzz',
252 coreconfigitem('convert', 'cvsps.fuzz',
253 default=60,
253 default=60,
254 )
254 )
255 coreconfigitem('convert', 'cvsps.logencoding',
255 coreconfigitem('convert', 'cvsps.logencoding',
256 default=None,
256 default=None,
257 )
257 )
258 coreconfigitem('convert', 'cvsps.mergefrom',
258 coreconfigitem('convert', 'cvsps.mergefrom',
259 default=None,
259 default=None,
260 )
260 )
261 coreconfigitem('convert', 'cvsps.mergeto',
261 coreconfigitem('convert', 'cvsps.mergeto',
262 default=None,
262 default=None,
263 )
263 )
264 coreconfigitem('convert', 'git.committeractions',
264 coreconfigitem('convert', 'git.committeractions',
265 default=lambda: ['messagedifferent'],
265 default=lambda: ['messagedifferent'],
266 )
266 )
267 coreconfigitem('convert', 'git.extrakeys',
267 coreconfigitem('convert', 'git.extrakeys',
268 default=list,
268 default=list,
269 )
269 )
270 coreconfigitem('convert', 'git.findcopiesharder',
270 coreconfigitem('convert', 'git.findcopiesharder',
271 default=False,
271 default=False,
272 )
272 )
273 coreconfigitem('convert', 'git.remoteprefix',
273 coreconfigitem('convert', 'git.remoteprefix',
274 default='remote',
274 default='remote',
275 )
275 )
276 coreconfigitem('convert', 'git.renamelimit',
276 coreconfigitem('convert', 'git.renamelimit',
277 default=400,
277 default=400,
278 )
278 )
279 coreconfigitem('convert', 'git.saverev',
279 coreconfigitem('convert', 'git.saverev',
280 default=True,
280 default=True,
281 )
281 )
282 coreconfigitem('convert', 'git.similarity',
282 coreconfigitem('convert', 'git.similarity',
283 default=50,
283 default=50,
284 )
284 )
285 coreconfigitem('convert', 'git.skipsubmodules',
285 coreconfigitem('convert', 'git.skipsubmodules',
286 default=False,
286 default=False,
287 )
287 )
288 coreconfigitem('convert', 'hg.clonebranches',
288 coreconfigitem('convert', 'hg.clonebranches',
289 default=False,
289 default=False,
290 )
290 )
291 coreconfigitem('convert', 'hg.ignoreerrors',
291 coreconfigitem('convert', 'hg.ignoreerrors',
292 default=False,
292 default=False,
293 )
293 )
294 coreconfigitem('convert', 'hg.revs',
294 coreconfigitem('convert', 'hg.revs',
295 default=None,
295 default=None,
296 )
296 )
297 coreconfigitem('convert', 'hg.saverev',
297 coreconfigitem('convert', 'hg.saverev',
298 default=False,
298 default=False,
299 )
299 )
300 coreconfigitem('convert', 'hg.sourcename',
300 coreconfigitem('convert', 'hg.sourcename',
301 default=None,
301 default=None,
302 )
302 )
303 coreconfigitem('convert', 'hg.startrev',
303 coreconfigitem('convert', 'hg.startrev',
304 default=None,
304 default=None,
305 )
305 )
306 coreconfigitem('convert', 'hg.tagsbranch',
306 coreconfigitem('convert', 'hg.tagsbranch',
307 default='default',
307 default='default',
308 )
308 )
309 coreconfigitem('convert', 'hg.usebranchnames',
309 coreconfigitem('convert', 'hg.usebranchnames',
310 default=True,
310 default=True,
311 )
311 )
312 coreconfigitem('convert', 'ignoreancestorcheck',
312 coreconfigitem('convert', 'ignoreancestorcheck',
313 default=False,
313 default=False,
314 )
314 )
315 coreconfigitem('convert', 'localtimezone',
315 coreconfigitem('convert', 'localtimezone',
316 default=False,
316 default=False,
317 )
317 )
318 coreconfigitem('convert', 'p4.encoding',
318 coreconfigitem('convert', 'p4.encoding',
319 default=dynamicdefault,
319 default=dynamicdefault,
320 )
320 )
321 coreconfigitem('convert', 'p4.startrev',
321 coreconfigitem('convert', 'p4.startrev',
322 default=0,
322 default=0,
323 )
323 )
324 coreconfigitem('convert', 'skiptags',
324 coreconfigitem('convert', 'skiptags',
325 default=False,
325 default=False,
326 )
326 )
327 coreconfigitem('convert', 'svn.debugsvnlog',
327 coreconfigitem('convert', 'svn.debugsvnlog',
328 default=True,
328 default=True,
329 )
329 )
330 coreconfigitem('convert', 'svn.trunk',
330 coreconfigitem('convert', 'svn.trunk',
331 default=None,
331 default=None,
332 )
332 )
333 coreconfigitem('convert', 'svn.tags',
333 coreconfigitem('convert', 'svn.tags',
334 default=None,
334 default=None,
335 )
335 )
336 coreconfigitem('convert', 'svn.branches',
336 coreconfigitem('convert', 'svn.branches',
337 default=None,
337 default=None,
338 )
338 )
339 coreconfigitem('convert', 'svn.startrev',
339 coreconfigitem('convert', 'svn.startrev',
340 default=0,
340 default=0,
341 )
341 )
342 coreconfigitem('debug', 'dirstate.delaywrite',
342 coreconfigitem('debug', 'dirstate.delaywrite',
343 default=0,
343 default=0,
344 )
344 )
345 coreconfigitem('defaults', '.*',
345 coreconfigitem('defaults', '.*',
346 default=None,
346 default=None,
347 generic=True,
347 generic=True,
348 )
348 )
349 coreconfigitem('devel', 'all-warnings',
349 coreconfigitem('devel', 'all-warnings',
350 default=False,
350 default=False,
351 )
351 )
352 coreconfigitem('devel', 'bundle2.debug',
352 coreconfigitem('devel', 'bundle2.debug',
353 default=False,
353 default=False,
354 )
354 )
355 coreconfigitem('devel', 'bundle.delta',
355 coreconfigitem('devel', 'bundle.delta',
356 default='',
356 default='',
357 )
357 )
358 coreconfigitem('devel', 'cache-vfs',
358 coreconfigitem('devel', 'cache-vfs',
359 default=None,
359 default=None,
360 )
360 )
361 coreconfigitem('devel', 'check-locks',
361 coreconfigitem('devel', 'check-locks',
362 default=False,
362 default=False,
363 )
363 )
364 coreconfigitem('devel', 'check-relroot',
364 coreconfigitem('devel', 'check-relroot',
365 default=False,
365 default=False,
366 )
366 )
367 coreconfigitem('devel', 'default-date',
367 coreconfigitem('devel', 'default-date',
368 default=None,
368 default=None,
369 )
369 )
370 coreconfigitem('devel', 'deprec-warn',
370 coreconfigitem('devel', 'deprec-warn',
371 default=False,
371 default=False,
372 )
372 )
373 coreconfigitem('devel', 'disableloaddefaultcerts',
373 coreconfigitem('devel', 'disableloaddefaultcerts',
374 default=False,
374 default=False,
375 )
375 )
376 coreconfigitem('devel', 'warn-empty-changegroup',
376 coreconfigitem('devel', 'warn-empty-changegroup',
377 default=False,
377 default=False,
378 )
378 )
379 coreconfigitem('devel', 'legacy.exchange',
379 coreconfigitem('devel', 'legacy.exchange',
380 default=list,
380 default=list,
381 )
381 )
382 coreconfigitem('devel', 'servercafile',
382 coreconfigitem('devel', 'servercafile',
383 default='',
383 default='',
384 )
384 )
385 coreconfigitem('devel', 'serverexactprotocol',
385 coreconfigitem('devel', 'serverexactprotocol',
386 default='',
386 default='',
387 )
387 )
388 coreconfigitem('devel', 'serverrequirecert',
388 coreconfigitem('devel', 'serverrequirecert',
389 default=False,
389 default=False,
390 )
390 )
391 coreconfigitem('devel', 'strip-obsmarkers',
391 coreconfigitem('devel', 'strip-obsmarkers',
392 default=True,
392 default=True,
393 )
393 )
394 coreconfigitem('devel', 'warn-config',
394 coreconfigitem('devel', 'warn-config',
395 default=None,
395 default=None,
396 )
396 )
397 coreconfigitem('devel', 'warn-config-default',
397 coreconfigitem('devel', 'warn-config-default',
398 default=None,
398 default=None,
399 )
399 )
400 coreconfigitem('devel', 'user.obsmarker',
400 coreconfigitem('devel', 'user.obsmarker',
401 default=None,
401 default=None,
402 )
402 )
403 coreconfigitem('devel', 'warn-config-unknown',
403 coreconfigitem('devel', 'warn-config-unknown',
404 default=None,
404 default=None,
405 )
405 )
406 coreconfigitem('devel', 'debug.copies',
406 coreconfigitem('devel', 'debug.copies',
407 default=False,
407 default=False,
408 )
408 )
409 coreconfigitem('devel', 'debug.extensions',
409 coreconfigitem('devel', 'debug.extensions',
410 default=False,
410 default=False,
411 )
411 )
412 coreconfigitem('devel', 'debug.peer-request',
412 coreconfigitem('devel', 'debug.peer-request',
413 default=False,
413 default=False,
414 )
414 )
415 _registerdiffopts(section='diff')
415 _registerdiffopts(section='diff')
416 coreconfigitem('email', 'bcc',
416 coreconfigitem('email', 'bcc',
417 default=None,
417 default=None,
418 )
418 )
419 coreconfigitem('email', 'cc',
419 coreconfigitem('email', 'cc',
420 default=None,
420 default=None,
421 )
421 )
422 coreconfigitem('email', 'charsets',
422 coreconfigitem('email', 'charsets',
423 default=list,
423 default=list,
424 )
424 )
425 coreconfigitem('email', 'from',
425 coreconfigitem('email', 'from',
426 default=None,
426 default=None,
427 )
427 )
428 coreconfigitem('email', 'method',
428 coreconfigitem('email', 'method',
429 default='smtp',
429 default='smtp',
430 )
430 )
431 coreconfigitem('email', 'reply-to',
431 coreconfigitem('email', 'reply-to',
432 default=None,
432 default=None,
433 )
433 )
434 coreconfigitem('email', 'to',
434 coreconfigitem('email', 'to',
435 default=None,
435 default=None,
436 )
436 )
437 coreconfigitem('experimental', 'archivemetatemplate',
437 coreconfigitem('experimental', 'archivemetatemplate',
438 default=dynamicdefault,
438 default=dynamicdefault,
439 )
439 )
440 coreconfigitem('experimental', 'auto-publish',
440 coreconfigitem('experimental', 'auto-publish',
441 default='publish',
441 default='publish',
442 )
442 )
443 coreconfigitem('experimental', 'bundle-phases',
443 coreconfigitem('experimental', 'bundle-phases',
444 default=False,
444 default=False,
445 )
445 )
446 coreconfigitem('experimental', 'bundle2-advertise',
446 coreconfigitem('experimental', 'bundle2-advertise',
447 default=True,
447 default=True,
448 )
448 )
449 coreconfigitem('experimental', 'bundle2-output-capture',
449 coreconfigitem('experimental', 'bundle2-output-capture',
450 default=False,
450 default=False,
451 )
451 )
452 coreconfigitem('experimental', 'bundle2.pushback',
452 coreconfigitem('experimental', 'bundle2.pushback',
453 default=False,
453 default=False,
454 )
454 )
455 coreconfigitem('experimental', 'bundle2lazylocking',
455 coreconfigitem('experimental', 'bundle2lazylocking',
456 default=False,
456 default=False,
457 )
457 )
458 coreconfigitem('experimental', 'bundlecomplevel',
458 coreconfigitem('experimental', 'bundlecomplevel',
459 default=None,
459 default=None,
460 )
460 )
461 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
461 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
462 default=None,
462 default=None,
463 )
463 )
464 coreconfigitem('experimental', 'bundlecomplevel.gzip',
464 coreconfigitem('experimental', 'bundlecomplevel.gzip',
465 default=None,
465 default=None,
466 )
466 )
467 coreconfigitem('experimental', 'bundlecomplevel.none',
467 coreconfigitem('experimental', 'bundlecomplevel.none',
468 default=None,
468 default=None,
469 )
469 )
470 coreconfigitem('experimental', 'bundlecomplevel.zstd',
470 coreconfigitem('experimental', 'bundlecomplevel.zstd',
471 default=None,
471 default=None,
472 )
472 )
473 coreconfigitem('experimental', 'changegroup3',
473 coreconfigitem('experimental', 'changegroup3',
474 default=False,
474 default=False,
475 )
475 )
476 coreconfigitem('experimental', 'cleanup-as-archived',
476 coreconfigitem('experimental', 'cleanup-as-archived',
477 default=False,
477 default=False,
478 )
478 )
479 coreconfigitem('experimental', 'clientcompressionengines',
479 coreconfigitem('experimental', 'clientcompressionengines',
480 default=list,
480 default=list,
481 )
481 )
482 coreconfigitem('experimental', 'copytrace',
482 coreconfigitem('experimental', 'copytrace',
483 default='on',
483 default='on',
484 )
484 )
485 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
485 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
486 default=100,
486 default=100,
487 )
487 )
488 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
488 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
489 default=100,
489 default=100,
490 )
490 )
491 coreconfigitem('experimental', 'copies.read-from',
491 coreconfigitem('experimental', 'copies.read-from',
492 default="filelog-only",
492 default="filelog-only",
493 )
493 )
494 coreconfigitem('experimental', 'copies.write-to',
494 coreconfigitem('experimental', 'copies.write-to',
495 default='filelog-only',
495 default='filelog-only',
496 )
496 )
497 coreconfigitem('experimental', 'crecordtest',
497 coreconfigitem('experimental', 'crecordtest',
498 default=None,
498 default=None,
499 )
499 )
500 coreconfigitem('experimental', 'directaccess',
500 coreconfigitem('experimental', 'directaccess',
501 default=False,
501 default=False,
502 )
502 )
503 coreconfigitem('experimental', 'directaccess.revnums',
503 coreconfigitem('experimental', 'directaccess.revnums',
504 default=False,
504 default=False,
505 )
505 )
506 coreconfigitem('experimental', 'editortmpinhg',
506 coreconfigitem('experimental', 'editortmpinhg',
507 default=False,
507 default=False,
508 )
508 )
509 coreconfigitem('experimental', 'evolution',
509 coreconfigitem('experimental', 'evolution',
510 default=list,
510 default=list,
511 )
511 )
512 coreconfigitem('experimental', 'evolution.allowdivergence',
512 coreconfigitem('experimental', 'evolution.allowdivergence',
513 default=False,
513 default=False,
514 alias=[('experimental', 'allowdivergence')]
514 alias=[('experimental', 'allowdivergence')]
515 )
515 )
516 coreconfigitem('experimental', 'evolution.allowunstable',
516 coreconfigitem('experimental', 'evolution.allowunstable',
517 default=None,
517 default=None,
518 )
518 )
519 coreconfigitem('experimental', 'evolution.createmarkers',
519 coreconfigitem('experimental', 'evolution.createmarkers',
520 default=None,
520 default=None,
521 )
521 )
522 coreconfigitem('experimental', 'evolution.effect-flags',
522 coreconfigitem('experimental', 'evolution.effect-flags',
523 default=True,
523 default=True,
524 alias=[('experimental', 'effect-flags')]
524 alias=[('experimental', 'effect-flags')]
525 )
525 )
526 coreconfigitem('experimental', 'evolution.exchange',
526 coreconfigitem('experimental', 'evolution.exchange',
527 default=None,
527 default=None,
528 )
528 )
529 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
529 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
530 default=False,
530 default=False,
531 )
531 )
532 coreconfigitem('experimental', 'log.topo',
533 default=False,
534 )
532 coreconfigitem('experimental', 'evolution.report-instabilities',
535 coreconfigitem('experimental', 'evolution.report-instabilities',
533 default=True,
536 default=True,
534 )
537 )
535 coreconfigitem('experimental', 'evolution.track-operation',
538 coreconfigitem('experimental', 'evolution.track-operation',
536 default=True,
539 default=True,
537 )
540 )
538 # repo-level config to exclude a revset visibility
541 # repo-level config to exclude a revset visibility
539 #
542 #
540 # The target use case is to use `share` to expose different subset of the same
543 # The target use case is to use `share` to expose different subset of the same
541 # repository, especially server side. See also `server.view`.
544 # repository, especially server side. See also `server.view`.
542 coreconfigitem('experimental', 'extra-filter-revs',
545 coreconfigitem('experimental', 'extra-filter-revs',
543 default=None,
546 default=None,
544 )
547 )
545 coreconfigitem('experimental', 'maxdeltachainspan',
548 coreconfigitem('experimental', 'maxdeltachainspan',
546 default=-1,
549 default=-1,
547 )
550 )
548 coreconfigitem('experimental', 'mergetempdirprefix',
551 coreconfigitem('experimental', 'mergetempdirprefix',
549 default=None,
552 default=None,
550 )
553 )
551 coreconfigitem('experimental', 'mmapindexthreshold',
554 coreconfigitem('experimental', 'mmapindexthreshold',
552 default=None,
555 default=None,
553 )
556 )
554 coreconfigitem('experimental', 'narrow',
557 coreconfigitem('experimental', 'narrow',
555 default=False,
558 default=False,
556 )
559 )
557 coreconfigitem('experimental', 'nonnormalparanoidcheck',
560 coreconfigitem('experimental', 'nonnormalparanoidcheck',
558 default=False,
561 default=False,
559 )
562 )
560 coreconfigitem('experimental', 'exportableenviron',
563 coreconfigitem('experimental', 'exportableenviron',
561 default=list,
564 default=list,
562 )
565 )
563 coreconfigitem('experimental', 'extendedheader.index',
566 coreconfigitem('experimental', 'extendedheader.index',
564 default=None,
567 default=None,
565 )
568 )
566 coreconfigitem('experimental', 'extendedheader.similarity',
569 coreconfigitem('experimental', 'extendedheader.similarity',
567 default=False,
570 default=False,
568 )
571 )
569 coreconfigitem('experimental', 'graphshorten',
572 coreconfigitem('experimental', 'graphshorten',
570 default=False,
573 default=False,
571 )
574 )
572 coreconfigitem('experimental', 'graphstyle.parent',
575 coreconfigitem('experimental', 'graphstyle.parent',
573 default=dynamicdefault,
576 default=dynamicdefault,
574 )
577 )
575 coreconfigitem('experimental', 'graphstyle.missing',
578 coreconfigitem('experimental', 'graphstyle.missing',
576 default=dynamicdefault,
579 default=dynamicdefault,
577 )
580 )
578 coreconfigitem('experimental', 'graphstyle.grandparent',
581 coreconfigitem('experimental', 'graphstyle.grandparent',
579 default=dynamicdefault,
582 default=dynamicdefault,
580 )
583 )
581 coreconfigitem('experimental', 'hook-track-tags',
584 coreconfigitem('experimental', 'hook-track-tags',
582 default=False,
585 default=False,
583 )
586 )
584 coreconfigitem('experimental', 'httppeer.advertise-v2',
587 coreconfigitem('experimental', 'httppeer.advertise-v2',
585 default=False,
588 default=False,
586 )
589 )
587 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
590 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
588 default=None,
591 default=None,
589 )
592 )
590 coreconfigitem('experimental', 'httppostargs',
593 coreconfigitem('experimental', 'httppostargs',
591 default=False,
594 default=False,
592 )
595 )
593 coreconfigitem('experimental', 'mergedriver',
596 coreconfigitem('experimental', 'mergedriver',
594 default=None,
597 default=None,
595 )
598 )
596 coreconfigitem('experimental', 'nointerrupt', default=False)
599 coreconfigitem('experimental', 'nointerrupt', default=False)
597 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
600 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
598
601
599 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
602 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
600 default=False,
603 default=False,
601 )
604 )
602 coreconfigitem('experimental', 'remotenames',
605 coreconfigitem('experimental', 'remotenames',
603 default=False,
606 default=False,
604 )
607 )
605 coreconfigitem('experimental', 'removeemptydirs',
608 coreconfigitem('experimental', 'removeemptydirs',
606 default=True,
609 default=True,
607 )
610 )
608 coreconfigitem('experimental', 'revert.interactive.select-to-keep',
611 coreconfigitem('experimental', 'revert.interactive.select-to-keep',
609 default=False,
612 default=False,
610 )
613 )
611 coreconfigitem('experimental', 'revisions.prefixhexnode',
614 coreconfigitem('experimental', 'revisions.prefixhexnode',
612 default=False,
615 default=False,
613 )
616 )
614 coreconfigitem('experimental', 'revlogv2',
617 coreconfigitem('experimental', 'revlogv2',
615 default=None,
618 default=None,
616 )
619 )
617 coreconfigitem('experimental', 'revisions.disambiguatewithin',
620 coreconfigitem('experimental', 'revisions.disambiguatewithin',
618 default=None,
621 default=None,
619 )
622 )
620 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
623 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
621 default=50000,
624 default=50000,
622 )
625 )
623 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
626 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
624 default=100000,
627 default=100000,
625 )
628 )
626 coreconfigitem('experimental', 'server.stream-narrow-clones',
629 coreconfigitem('experimental', 'server.stream-narrow-clones',
627 default=False,
630 default=False,
628 )
631 )
629 coreconfigitem('experimental', 'single-head-per-branch',
632 coreconfigitem('experimental', 'single-head-per-branch',
630 default=False,
633 default=False,
631 )
634 )
632 coreconfigitem('experimental', 'sshserver.support-v2',
635 coreconfigitem('experimental', 'sshserver.support-v2',
633 default=False,
636 default=False,
634 )
637 )
635 coreconfigitem('experimental', 'sparse-read',
638 coreconfigitem('experimental', 'sparse-read',
636 default=False,
639 default=False,
637 )
640 )
638 coreconfigitem('experimental', 'sparse-read.density-threshold',
641 coreconfigitem('experimental', 'sparse-read.density-threshold',
639 default=0.50,
642 default=0.50,
640 )
643 )
641 coreconfigitem('experimental', 'sparse-read.min-gap-size',
644 coreconfigitem('experimental', 'sparse-read.min-gap-size',
642 default='65K',
645 default='65K',
643 )
646 )
644 coreconfigitem('experimental', 'treemanifest',
647 coreconfigitem('experimental', 'treemanifest',
645 default=False,
648 default=False,
646 )
649 )
647 coreconfigitem('experimental', 'update.atomic-file',
650 coreconfigitem('experimental', 'update.atomic-file',
648 default=False,
651 default=False,
649 )
652 )
650 coreconfigitem('experimental', 'sshpeer.advertise-v2',
653 coreconfigitem('experimental', 'sshpeer.advertise-v2',
651 default=False,
654 default=False,
652 )
655 )
653 coreconfigitem('experimental', 'web.apiserver',
656 coreconfigitem('experimental', 'web.apiserver',
654 default=False,
657 default=False,
655 )
658 )
656 coreconfigitem('experimental', 'web.api.http-v2',
659 coreconfigitem('experimental', 'web.api.http-v2',
657 default=False,
660 default=False,
658 )
661 )
659 coreconfigitem('experimental', 'web.api.debugreflect',
662 coreconfigitem('experimental', 'web.api.debugreflect',
660 default=False,
663 default=False,
661 )
664 )
662 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
665 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
663 default=False,
666 default=False,
664 )
667 )
665 coreconfigitem('experimental', 'xdiff',
668 coreconfigitem('experimental', 'xdiff',
666 default=False,
669 default=False,
667 )
670 )
668 coreconfigitem('extensions', '.*',
671 coreconfigitem('extensions', '.*',
669 default=None,
672 default=None,
670 generic=True,
673 generic=True,
671 )
674 )
672 coreconfigitem('extdata', '.*',
675 coreconfigitem('extdata', '.*',
673 default=None,
676 default=None,
674 generic=True,
677 generic=True,
675 )
678 )
676 coreconfigitem('format', 'chunkcachesize',
679 coreconfigitem('format', 'chunkcachesize',
677 default=None,
680 default=None,
678 )
681 )
679 coreconfigitem('format', 'dotencode',
682 coreconfigitem('format', 'dotencode',
680 default=True,
683 default=True,
681 )
684 )
682 coreconfigitem('format', 'generaldelta',
685 coreconfigitem('format', 'generaldelta',
683 default=False,
686 default=False,
684 )
687 )
685 coreconfigitem('format', 'manifestcachesize',
688 coreconfigitem('format', 'manifestcachesize',
686 default=None,
689 default=None,
687 )
690 )
688 coreconfigitem('format', 'maxchainlen',
691 coreconfigitem('format', 'maxchainlen',
689 default=dynamicdefault,
692 default=dynamicdefault,
690 )
693 )
691 coreconfigitem('format', 'obsstore-version',
694 coreconfigitem('format', 'obsstore-version',
692 default=None,
695 default=None,
693 )
696 )
694 coreconfigitem('format', 'sparse-revlog',
697 coreconfigitem('format', 'sparse-revlog',
695 default=True,
698 default=True,
696 )
699 )
697 coreconfigitem('format', 'revlog-compression',
700 coreconfigitem('format', 'revlog-compression',
698 default='zlib',
701 default='zlib',
699 alias=[('experimental', 'format.compression')]
702 alias=[('experimental', 'format.compression')]
700 )
703 )
701 coreconfigitem('format', 'usefncache',
704 coreconfigitem('format', 'usefncache',
702 default=True,
705 default=True,
703 )
706 )
704 coreconfigitem('format', 'usegeneraldelta',
707 coreconfigitem('format', 'usegeneraldelta',
705 default=True,
708 default=True,
706 )
709 )
707 coreconfigitem('format', 'usestore',
710 coreconfigitem('format', 'usestore',
708 default=True,
711 default=True,
709 )
712 )
710 coreconfigitem('format', 'internal-phase',
713 coreconfigitem('format', 'internal-phase',
711 default=False,
714 default=False,
712 )
715 )
713 coreconfigitem('fsmonitor', 'warn_when_unused',
716 coreconfigitem('fsmonitor', 'warn_when_unused',
714 default=True,
717 default=True,
715 )
718 )
716 coreconfigitem('fsmonitor', 'warn_update_file_count',
719 coreconfigitem('fsmonitor', 'warn_update_file_count',
717 default=50000,
720 default=50000,
718 )
721 )
719 coreconfigitem('help', br'hidden-command\..*',
722 coreconfigitem('help', br'hidden-command\..*',
720 default=False,
723 default=False,
721 generic=True,
724 generic=True,
722 )
725 )
723 coreconfigitem('help', br'hidden-topic\..*',
726 coreconfigitem('help', br'hidden-topic\..*',
724 default=False,
727 default=False,
725 generic=True,
728 generic=True,
726 )
729 )
727 coreconfigitem('hooks', '.*',
730 coreconfigitem('hooks', '.*',
728 default=dynamicdefault,
731 default=dynamicdefault,
729 generic=True,
732 generic=True,
730 )
733 )
731 coreconfigitem('hgweb-paths', '.*',
734 coreconfigitem('hgweb-paths', '.*',
732 default=list,
735 default=list,
733 generic=True,
736 generic=True,
734 )
737 )
735 coreconfigitem('hostfingerprints', '.*',
738 coreconfigitem('hostfingerprints', '.*',
736 default=list,
739 default=list,
737 generic=True,
740 generic=True,
738 )
741 )
739 coreconfigitem('hostsecurity', 'ciphers',
742 coreconfigitem('hostsecurity', 'ciphers',
740 default=None,
743 default=None,
741 )
744 )
742 coreconfigitem('hostsecurity', 'disabletls10warning',
745 coreconfigitem('hostsecurity', 'disabletls10warning',
743 default=False,
746 default=False,
744 )
747 )
745 coreconfigitem('hostsecurity', 'minimumprotocol',
748 coreconfigitem('hostsecurity', 'minimumprotocol',
746 default=dynamicdefault,
749 default=dynamicdefault,
747 )
750 )
748 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
751 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
749 default=dynamicdefault,
752 default=dynamicdefault,
750 generic=True,
753 generic=True,
751 )
754 )
752 coreconfigitem('hostsecurity', '.*:ciphers$',
755 coreconfigitem('hostsecurity', '.*:ciphers$',
753 default=dynamicdefault,
756 default=dynamicdefault,
754 generic=True,
757 generic=True,
755 )
758 )
756 coreconfigitem('hostsecurity', '.*:fingerprints$',
759 coreconfigitem('hostsecurity', '.*:fingerprints$',
757 default=list,
760 default=list,
758 generic=True,
761 generic=True,
759 )
762 )
760 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
763 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
761 default=None,
764 default=None,
762 generic=True,
765 generic=True,
763 )
766 )
764
767
765 coreconfigitem('http_proxy', 'always',
768 coreconfigitem('http_proxy', 'always',
766 default=False,
769 default=False,
767 )
770 )
768 coreconfigitem('http_proxy', 'host',
771 coreconfigitem('http_proxy', 'host',
769 default=None,
772 default=None,
770 )
773 )
771 coreconfigitem('http_proxy', 'no',
774 coreconfigitem('http_proxy', 'no',
772 default=list,
775 default=list,
773 )
776 )
774 coreconfigitem('http_proxy', 'passwd',
777 coreconfigitem('http_proxy', 'passwd',
775 default=None,
778 default=None,
776 )
779 )
777 coreconfigitem('http_proxy', 'user',
780 coreconfigitem('http_proxy', 'user',
778 default=None,
781 default=None,
779 )
782 )
780
783
781 coreconfigitem('http', 'timeout',
784 coreconfigitem('http', 'timeout',
782 default=None,
785 default=None,
783 )
786 )
784
787
785 coreconfigitem('logtoprocess', 'commandexception',
788 coreconfigitem('logtoprocess', 'commandexception',
786 default=None,
789 default=None,
787 )
790 )
788 coreconfigitem('logtoprocess', 'commandfinish',
791 coreconfigitem('logtoprocess', 'commandfinish',
789 default=None,
792 default=None,
790 )
793 )
791 coreconfigitem('logtoprocess', 'command',
794 coreconfigitem('logtoprocess', 'command',
792 default=None,
795 default=None,
793 )
796 )
794 coreconfigitem('logtoprocess', 'develwarn',
797 coreconfigitem('logtoprocess', 'develwarn',
795 default=None,
798 default=None,
796 )
799 )
797 coreconfigitem('logtoprocess', 'uiblocked',
800 coreconfigitem('logtoprocess', 'uiblocked',
798 default=None,
801 default=None,
799 )
802 )
800 coreconfigitem('merge', 'checkunknown',
803 coreconfigitem('merge', 'checkunknown',
801 default='abort',
804 default='abort',
802 )
805 )
803 coreconfigitem('merge', 'checkignored',
806 coreconfigitem('merge', 'checkignored',
804 default='abort',
807 default='abort',
805 )
808 )
806 coreconfigitem('experimental', 'merge.checkpathconflicts',
809 coreconfigitem('experimental', 'merge.checkpathconflicts',
807 default=False,
810 default=False,
808 )
811 )
809 coreconfigitem('merge', 'followcopies',
812 coreconfigitem('merge', 'followcopies',
810 default=True,
813 default=True,
811 )
814 )
812 coreconfigitem('merge', 'on-failure',
815 coreconfigitem('merge', 'on-failure',
813 default='continue',
816 default='continue',
814 )
817 )
815 coreconfigitem('merge', 'preferancestor',
818 coreconfigitem('merge', 'preferancestor',
816 default=lambda: ['*'],
819 default=lambda: ['*'],
817 )
820 )
818 coreconfigitem('merge', 'strict-capability-check',
821 coreconfigitem('merge', 'strict-capability-check',
819 default=False,
822 default=False,
820 )
823 )
821 coreconfigitem('merge-tools', '.*',
824 coreconfigitem('merge-tools', '.*',
822 default=None,
825 default=None,
823 generic=True,
826 generic=True,
824 )
827 )
825 coreconfigitem('merge-tools', br'.*\.args$',
828 coreconfigitem('merge-tools', br'.*\.args$',
826 default="$local $base $other",
829 default="$local $base $other",
827 generic=True,
830 generic=True,
828 priority=-1,
831 priority=-1,
829 )
832 )
830 coreconfigitem('merge-tools', br'.*\.binary$',
833 coreconfigitem('merge-tools', br'.*\.binary$',
831 default=False,
834 default=False,
832 generic=True,
835 generic=True,
833 priority=-1,
836 priority=-1,
834 )
837 )
835 coreconfigitem('merge-tools', br'.*\.check$',
838 coreconfigitem('merge-tools', br'.*\.check$',
836 default=list,
839 default=list,
837 generic=True,
840 generic=True,
838 priority=-1,
841 priority=-1,
839 )
842 )
840 coreconfigitem('merge-tools', br'.*\.checkchanged$',
843 coreconfigitem('merge-tools', br'.*\.checkchanged$',
841 default=False,
844 default=False,
842 generic=True,
845 generic=True,
843 priority=-1,
846 priority=-1,
844 )
847 )
845 coreconfigitem('merge-tools', br'.*\.executable$',
848 coreconfigitem('merge-tools', br'.*\.executable$',
846 default=dynamicdefault,
849 default=dynamicdefault,
847 generic=True,
850 generic=True,
848 priority=-1,
851 priority=-1,
849 )
852 )
850 coreconfigitem('merge-tools', br'.*\.fixeol$',
853 coreconfigitem('merge-tools', br'.*\.fixeol$',
851 default=False,
854 default=False,
852 generic=True,
855 generic=True,
853 priority=-1,
856 priority=-1,
854 )
857 )
855 coreconfigitem('merge-tools', br'.*\.gui$',
858 coreconfigitem('merge-tools', br'.*\.gui$',
856 default=False,
859 default=False,
857 generic=True,
860 generic=True,
858 priority=-1,
861 priority=-1,
859 )
862 )
860 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
863 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
861 default='basic',
864 default='basic',
862 generic=True,
865 generic=True,
863 priority=-1,
866 priority=-1,
864 )
867 )
865 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
868 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
866 default=dynamicdefault, # take from ui.mergemarkertemplate
869 default=dynamicdefault, # take from ui.mergemarkertemplate
867 generic=True,
870 generic=True,
868 priority=-1,
871 priority=-1,
869 )
872 )
870 coreconfigitem('merge-tools', br'.*\.priority$',
873 coreconfigitem('merge-tools', br'.*\.priority$',
871 default=0,
874 default=0,
872 generic=True,
875 generic=True,
873 priority=-1,
876 priority=-1,
874 )
877 )
875 coreconfigitem('merge-tools', br'.*\.premerge$',
878 coreconfigitem('merge-tools', br'.*\.premerge$',
876 default=dynamicdefault,
879 default=dynamicdefault,
877 generic=True,
880 generic=True,
878 priority=-1,
881 priority=-1,
879 )
882 )
880 coreconfigitem('merge-tools', br'.*\.symlink$',
883 coreconfigitem('merge-tools', br'.*\.symlink$',
881 default=False,
884 default=False,
882 generic=True,
885 generic=True,
883 priority=-1,
886 priority=-1,
884 )
887 )
885 coreconfigitem('pager', 'attend-.*',
888 coreconfigitem('pager', 'attend-.*',
886 default=dynamicdefault,
889 default=dynamicdefault,
887 generic=True,
890 generic=True,
888 )
891 )
889 coreconfigitem('pager', 'ignore',
892 coreconfigitem('pager', 'ignore',
890 default=list,
893 default=list,
891 )
894 )
892 coreconfigitem('pager', 'pager',
895 coreconfigitem('pager', 'pager',
893 default=dynamicdefault,
896 default=dynamicdefault,
894 )
897 )
895 coreconfigitem('patch', 'eol',
898 coreconfigitem('patch', 'eol',
896 default='strict',
899 default='strict',
897 )
900 )
898 coreconfigitem('patch', 'fuzz',
901 coreconfigitem('patch', 'fuzz',
899 default=2,
902 default=2,
900 )
903 )
901 coreconfigitem('paths', 'default',
904 coreconfigitem('paths', 'default',
902 default=None,
905 default=None,
903 )
906 )
904 coreconfigitem('paths', 'default-push',
907 coreconfigitem('paths', 'default-push',
905 default=None,
908 default=None,
906 )
909 )
907 coreconfigitem('paths', '.*',
910 coreconfigitem('paths', '.*',
908 default=None,
911 default=None,
909 generic=True,
912 generic=True,
910 )
913 )
911 coreconfigitem('phases', 'checksubrepos',
914 coreconfigitem('phases', 'checksubrepos',
912 default='follow',
915 default='follow',
913 )
916 )
914 coreconfigitem('phases', 'new-commit',
917 coreconfigitem('phases', 'new-commit',
915 default='draft',
918 default='draft',
916 )
919 )
917 coreconfigitem('phases', 'publish',
920 coreconfigitem('phases', 'publish',
918 default=True,
921 default=True,
919 )
922 )
920 coreconfigitem('profiling', 'enabled',
923 coreconfigitem('profiling', 'enabled',
921 default=False,
924 default=False,
922 )
925 )
923 coreconfigitem('profiling', 'format',
926 coreconfigitem('profiling', 'format',
924 default='text',
927 default='text',
925 )
928 )
926 coreconfigitem('profiling', 'freq',
929 coreconfigitem('profiling', 'freq',
927 default=1000,
930 default=1000,
928 )
931 )
929 coreconfigitem('profiling', 'limit',
932 coreconfigitem('profiling', 'limit',
930 default=30,
933 default=30,
931 )
934 )
932 coreconfigitem('profiling', 'nested',
935 coreconfigitem('profiling', 'nested',
933 default=0,
936 default=0,
934 )
937 )
935 coreconfigitem('profiling', 'output',
938 coreconfigitem('profiling', 'output',
936 default=None,
939 default=None,
937 )
940 )
938 coreconfigitem('profiling', 'showmax',
941 coreconfigitem('profiling', 'showmax',
939 default=0.999,
942 default=0.999,
940 )
943 )
941 coreconfigitem('profiling', 'showmin',
944 coreconfigitem('profiling', 'showmin',
942 default=dynamicdefault,
945 default=dynamicdefault,
943 )
946 )
944 coreconfigitem('profiling', 'sort',
947 coreconfigitem('profiling', 'sort',
945 default='inlinetime',
948 default='inlinetime',
946 )
949 )
947 coreconfigitem('profiling', 'statformat',
950 coreconfigitem('profiling', 'statformat',
948 default='hotpath',
951 default='hotpath',
949 )
952 )
950 coreconfigitem('profiling', 'time-track',
953 coreconfigitem('profiling', 'time-track',
951 default=dynamicdefault,
954 default=dynamicdefault,
952 )
955 )
953 coreconfigitem('profiling', 'type',
956 coreconfigitem('profiling', 'type',
954 default='stat',
957 default='stat',
955 )
958 )
956 coreconfigitem('progress', 'assume-tty',
959 coreconfigitem('progress', 'assume-tty',
957 default=False,
960 default=False,
958 )
961 )
959 coreconfigitem('progress', 'changedelay',
962 coreconfigitem('progress', 'changedelay',
960 default=1,
963 default=1,
961 )
964 )
962 coreconfigitem('progress', 'clear-complete',
965 coreconfigitem('progress', 'clear-complete',
963 default=True,
966 default=True,
964 )
967 )
965 coreconfigitem('progress', 'debug',
968 coreconfigitem('progress', 'debug',
966 default=False,
969 default=False,
967 )
970 )
968 coreconfigitem('progress', 'delay',
971 coreconfigitem('progress', 'delay',
969 default=3,
972 default=3,
970 )
973 )
971 coreconfigitem('progress', 'disable',
974 coreconfigitem('progress', 'disable',
972 default=False,
975 default=False,
973 )
976 )
974 coreconfigitem('progress', 'estimateinterval',
977 coreconfigitem('progress', 'estimateinterval',
975 default=60.0,
978 default=60.0,
976 )
979 )
977 coreconfigitem('progress', 'format',
980 coreconfigitem('progress', 'format',
978 default=lambda: ['topic', 'bar', 'number', 'estimate'],
981 default=lambda: ['topic', 'bar', 'number', 'estimate'],
979 )
982 )
980 coreconfigitem('progress', 'refresh',
983 coreconfigitem('progress', 'refresh',
981 default=0.1,
984 default=0.1,
982 )
985 )
983 coreconfigitem('progress', 'width',
986 coreconfigitem('progress', 'width',
984 default=dynamicdefault,
987 default=dynamicdefault,
985 )
988 )
986 coreconfigitem('push', 'pushvars.server',
989 coreconfigitem('push', 'pushvars.server',
987 default=False,
990 default=False,
988 )
991 )
989 coreconfigitem('rewrite', 'backup-bundle',
992 coreconfigitem('rewrite', 'backup-bundle',
990 default=True,
993 default=True,
991 alias=[('ui', 'history-editing-backup')],
994 alias=[('ui', 'history-editing-backup')],
992 )
995 )
993 coreconfigitem('rewrite', 'update-timestamp',
996 coreconfigitem('rewrite', 'update-timestamp',
994 default=False,
997 default=False,
995 )
998 )
996 coreconfigitem('storage', 'new-repo-backend',
999 coreconfigitem('storage', 'new-repo-backend',
997 default='revlogv1',
1000 default='revlogv1',
998 )
1001 )
999 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
1002 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
1000 default=True,
1003 default=True,
1001 alias=[('format', 'aggressivemergedeltas')],
1004 alias=[('format', 'aggressivemergedeltas')],
1002 )
1005 )
1003 coreconfigitem('storage', 'revlog.reuse-external-delta',
1006 coreconfigitem('storage', 'revlog.reuse-external-delta',
1004 default=True,
1007 default=True,
1005 )
1008 )
1006 coreconfigitem('storage', 'revlog.reuse-external-delta-parent',
1009 coreconfigitem('storage', 'revlog.reuse-external-delta-parent',
1007 default=None,
1010 default=None,
1008 )
1011 )
1009 coreconfigitem('storage', 'revlog.zlib.level',
1012 coreconfigitem('storage', 'revlog.zlib.level',
1010 default=None,
1013 default=None,
1011 )
1014 )
1012 coreconfigitem('storage', 'revlog.zstd.level',
1015 coreconfigitem('storage', 'revlog.zstd.level',
1013 default=None,
1016 default=None,
1014 )
1017 )
1015 coreconfigitem('server', 'bookmarks-pushkey-compat',
1018 coreconfigitem('server', 'bookmarks-pushkey-compat',
1016 default=True,
1019 default=True,
1017 )
1020 )
1018 coreconfigitem('server', 'bundle1',
1021 coreconfigitem('server', 'bundle1',
1019 default=True,
1022 default=True,
1020 )
1023 )
1021 coreconfigitem('server', 'bundle1gd',
1024 coreconfigitem('server', 'bundle1gd',
1022 default=None,
1025 default=None,
1023 )
1026 )
1024 coreconfigitem('server', 'bundle1.pull',
1027 coreconfigitem('server', 'bundle1.pull',
1025 default=None,
1028 default=None,
1026 )
1029 )
1027 coreconfigitem('server', 'bundle1gd.pull',
1030 coreconfigitem('server', 'bundle1gd.pull',
1028 default=None,
1031 default=None,
1029 )
1032 )
1030 coreconfigitem('server', 'bundle1.push',
1033 coreconfigitem('server', 'bundle1.push',
1031 default=None,
1034 default=None,
1032 )
1035 )
1033 coreconfigitem('server', 'bundle1gd.push',
1036 coreconfigitem('server', 'bundle1gd.push',
1034 default=None,
1037 default=None,
1035 )
1038 )
1036 coreconfigitem('server', 'bundle2.stream',
1039 coreconfigitem('server', 'bundle2.stream',
1037 default=True,
1040 default=True,
1038 alias=[('experimental', 'bundle2.stream')]
1041 alias=[('experimental', 'bundle2.stream')]
1039 )
1042 )
1040 coreconfigitem('server', 'compressionengines',
1043 coreconfigitem('server', 'compressionengines',
1041 default=list,
1044 default=list,
1042 )
1045 )
1043 coreconfigitem('server', 'concurrent-push-mode',
1046 coreconfigitem('server', 'concurrent-push-mode',
1044 default='strict',
1047 default='strict',
1045 )
1048 )
1046 coreconfigitem('server', 'disablefullbundle',
1049 coreconfigitem('server', 'disablefullbundle',
1047 default=False,
1050 default=False,
1048 )
1051 )
1049 coreconfigitem('server', 'maxhttpheaderlen',
1052 coreconfigitem('server', 'maxhttpheaderlen',
1050 default=1024,
1053 default=1024,
1051 )
1054 )
1052 coreconfigitem('server', 'pullbundle',
1055 coreconfigitem('server', 'pullbundle',
1053 default=False,
1056 default=False,
1054 )
1057 )
1055 coreconfigitem('server', 'preferuncompressed',
1058 coreconfigitem('server', 'preferuncompressed',
1056 default=False,
1059 default=False,
1057 )
1060 )
1058 coreconfigitem('server', 'streamunbundle',
1061 coreconfigitem('server', 'streamunbundle',
1059 default=False,
1062 default=False,
1060 )
1063 )
1061 coreconfigitem('server', 'uncompressed',
1064 coreconfigitem('server', 'uncompressed',
1062 default=True,
1065 default=True,
1063 )
1066 )
1064 coreconfigitem('server', 'uncompressedallowsecret',
1067 coreconfigitem('server', 'uncompressedallowsecret',
1065 default=False,
1068 default=False,
1066 )
1069 )
1067 coreconfigitem('server', 'view',
1070 coreconfigitem('server', 'view',
1068 default='served',
1071 default='served',
1069 )
1072 )
1070 coreconfigitem('server', 'validate',
1073 coreconfigitem('server', 'validate',
1071 default=False,
1074 default=False,
1072 )
1075 )
1073 coreconfigitem('server', 'zliblevel',
1076 coreconfigitem('server', 'zliblevel',
1074 default=-1,
1077 default=-1,
1075 )
1078 )
1076 coreconfigitem('server', 'zstdlevel',
1079 coreconfigitem('server', 'zstdlevel',
1077 default=3,
1080 default=3,
1078 )
1081 )
1079 coreconfigitem('share', 'pool',
1082 coreconfigitem('share', 'pool',
1080 default=None,
1083 default=None,
1081 )
1084 )
1082 coreconfigitem('share', 'poolnaming',
1085 coreconfigitem('share', 'poolnaming',
1083 default='identity',
1086 default='identity',
1084 )
1087 )
1085 coreconfigitem('smtp', 'host',
1088 coreconfigitem('smtp', 'host',
1086 default=None,
1089 default=None,
1087 )
1090 )
1088 coreconfigitem('smtp', 'local_hostname',
1091 coreconfigitem('smtp', 'local_hostname',
1089 default=None,
1092 default=None,
1090 )
1093 )
1091 coreconfigitem('smtp', 'password',
1094 coreconfigitem('smtp', 'password',
1092 default=None,
1095 default=None,
1093 )
1096 )
1094 coreconfigitem('smtp', 'port',
1097 coreconfigitem('smtp', 'port',
1095 default=dynamicdefault,
1098 default=dynamicdefault,
1096 )
1099 )
1097 coreconfigitem('smtp', 'tls',
1100 coreconfigitem('smtp', 'tls',
1098 default='none',
1101 default='none',
1099 )
1102 )
1100 coreconfigitem('smtp', 'username',
1103 coreconfigitem('smtp', 'username',
1101 default=None,
1104 default=None,
1102 )
1105 )
1103 coreconfigitem('sparse', 'missingwarning',
1106 coreconfigitem('sparse', 'missingwarning',
1104 default=True,
1107 default=True,
1105 )
1108 )
1106 coreconfigitem('subrepos', 'allowed',
1109 coreconfigitem('subrepos', 'allowed',
1107 default=dynamicdefault, # to make backporting simpler
1110 default=dynamicdefault, # to make backporting simpler
1108 )
1111 )
1109 coreconfigitem('subrepos', 'hg:allowed',
1112 coreconfigitem('subrepos', 'hg:allowed',
1110 default=dynamicdefault,
1113 default=dynamicdefault,
1111 )
1114 )
1112 coreconfigitem('subrepos', 'git:allowed',
1115 coreconfigitem('subrepos', 'git:allowed',
1113 default=dynamicdefault,
1116 default=dynamicdefault,
1114 )
1117 )
1115 coreconfigitem('subrepos', 'svn:allowed',
1118 coreconfigitem('subrepos', 'svn:allowed',
1116 default=dynamicdefault,
1119 default=dynamicdefault,
1117 )
1120 )
1118 coreconfigitem('templates', '.*',
1121 coreconfigitem('templates', '.*',
1119 default=None,
1122 default=None,
1120 generic=True,
1123 generic=True,
1121 )
1124 )
1122 coreconfigitem('templateconfig', '.*',
1125 coreconfigitem('templateconfig', '.*',
1123 default=dynamicdefault,
1126 default=dynamicdefault,
1124 generic=True,
1127 generic=True,
1125 )
1128 )
1126 coreconfigitem('trusted', 'groups',
1129 coreconfigitem('trusted', 'groups',
1127 default=list,
1130 default=list,
1128 )
1131 )
1129 coreconfigitem('trusted', 'users',
1132 coreconfigitem('trusted', 'users',
1130 default=list,
1133 default=list,
1131 )
1134 )
1132 coreconfigitem('ui', '_usedassubrepo',
1135 coreconfigitem('ui', '_usedassubrepo',
1133 default=False,
1136 default=False,
1134 )
1137 )
1135 coreconfigitem('ui', 'allowemptycommit',
1138 coreconfigitem('ui', 'allowemptycommit',
1136 default=False,
1139 default=False,
1137 )
1140 )
1138 coreconfigitem('ui', 'archivemeta',
1141 coreconfigitem('ui', 'archivemeta',
1139 default=True,
1142 default=True,
1140 )
1143 )
1141 coreconfigitem('ui', 'askusername',
1144 coreconfigitem('ui', 'askusername',
1142 default=False,
1145 default=False,
1143 )
1146 )
1144 coreconfigitem('ui', 'clonebundlefallback',
1147 coreconfigitem('ui', 'clonebundlefallback',
1145 default=False,
1148 default=False,
1146 )
1149 )
1147 coreconfigitem('ui', 'clonebundleprefers',
1150 coreconfigitem('ui', 'clonebundleprefers',
1148 default=list,
1151 default=list,
1149 )
1152 )
1150 coreconfigitem('ui', 'clonebundles',
1153 coreconfigitem('ui', 'clonebundles',
1151 default=True,
1154 default=True,
1152 )
1155 )
1153 coreconfigitem('ui', 'color',
1156 coreconfigitem('ui', 'color',
1154 default='auto',
1157 default='auto',
1155 )
1158 )
1156 coreconfigitem('ui', 'commitsubrepos',
1159 coreconfigitem('ui', 'commitsubrepos',
1157 default=False,
1160 default=False,
1158 )
1161 )
1159 coreconfigitem('ui', 'debug',
1162 coreconfigitem('ui', 'debug',
1160 default=False,
1163 default=False,
1161 )
1164 )
1162 coreconfigitem('ui', 'debugger',
1165 coreconfigitem('ui', 'debugger',
1163 default=None,
1166 default=None,
1164 )
1167 )
1165 coreconfigitem('ui', 'editor',
1168 coreconfigitem('ui', 'editor',
1166 default=dynamicdefault,
1169 default=dynamicdefault,
1167 )
1170 )
1168 coreconfigitem('ui', 'fallbackencoding',
1171 coreconfigitem('ui', 'fallbackencoding',
1169 default=None,
1172 default=None,
1170 )
1173 )
1171 coreconfigitem('ui', 'forcecwd',
1174 coreconfigitem('ui', 'forcecwd',
1172 default=None,
1175 default=None,
1173 )
1176 )
1174 coreconfigitem('ui', 'forcemerge',
1177 coreconfigitem('ui', 'forcemerge',
1175 default=None,
1178 default=None,
1176 )
1179 )
1177 coreconfigitem('ui', 'formatdebug',
1180 coreconfigitem('ui', 'formatdebug',
1178 default=False,
1181 default=False,
1179 )
1182 )
1180 coreconfigitem('ui', 'formatjson',
1183 coreconfigitem('ui', 'formatjson',
1181 default=False,
1184 default=False,
1182 )
1185 )
1183 coreconfigitem('ui', 'formatted',
1186 coreconfigitem('ui', 'formatted',
1184 default=None,
1187 default=None,
1185 )
1188 )
1186 coreconfigitem('ui', 'graphnodetemplate',
1189 coreconfigitem('ui', 'graphnodetemplate',
1187 default=None,
1190 default=None,
1188 )
1191 )
1189 coreconfigitem('ui', 'interactive',
1192 coreconfigitem('ui', 'interactive',
1190 default=None,
1193 default=None,
1191 )
1194 )
1192 coreconfigitem('ui', 'interface',
1195 coreconfigitem('ui', 'interface',
1193 default=None,
1196 default=None,
1194 )
1197 )
1195 coreconfigitem('ui', 'interface.chunkselector',
1198 coreconfigitem('ui', 'interface.chunkselector',
1196 default=None,
1199 default=None,
1197 )
1200 )
1198 coreconfigitem('ui', 'large-file-limit',
1201 coreconfigitem('ui', 'large-file-limit',
1199 default=10000000,
1202 default=10000000,
1200 )
1203 )
1201 coreconfigitem('ui', 'logblockedtimes',
1204 coreconfigitem('ui', 'logblockedtimes',
1202 default=False,
1205 default=False,
1203 )
1206 )
1204 coreconfigitem('ui', 'logtemplate',
1207 coreconfigitem('ui', 'logtemplate',
1205 default=None,
1208 default=None,
1206 )
1209 )
1207 coreconfigitem('ui', 'merge',
1210 coreconfigitem('ui', 'merge',
1208 default=None,
1211 default=None,
1209 )
1212 )
1210 coreconfigitem('ui', 'mergemarkers',
1213 coreconfigitem('ui', 'mergemarkers',
1211 default='basic',
1214 default='basic',
1212 )
1215 )
1213 coreconfigitem('ui', 'mergemarkertemplate',
1216 coreconfigitem('ui', 'mergemarkertemplate',
1214 default=('{node|short} '
1217 default=('{node|short} '
1215 '{ifeq(tags, "tip", "", '
1218 '{ifeq(tags, "tip", "", '
1216 'ifeq(tags, "", "", "{tags} "))}'
1219 'ifeq(tags, "", "", "{tags} "))}'
1217 '{if(bookmarks, "{bookmarks} ")}'
1220 '{if(bookmarks, "{bookmarks} ")}'
1218 '{ifeq(branch, "default", "", "{branch} ")}'
1221 '{ifeq(branch, "default", "", "{branch} ")}'
1219 '- {author|user}: {desc|firstline}')
1222 '- {author|user}: {desc|firstline}')
1220 )
1223 )
1221 coreconfigitem('ui', 'message-output',
1224 coreconfigitem('ui', 'message-output',
1222 default='stdio',
1225 default='stdio',
1223 )
1226 )
1224 coreconfigitem('ui', 'nontty',
1227 coreconfigitem('ui', 'nontty',
1225 default=False,
1228 default=False,
1226 )
1229 )
1227 coreconfigitem('ui', 'origbackuppath',
1230 coreconfigitem('ui', 'origbackuppath',
1228 default=None,
1231 default=None,
1229 )
1232 )
1230 coreconfigitem('ui', 'paginate',
1233 coreconfigitem('ui', 'paginate',
1231 default=True,
1234 default=True,
1232 )
1235 )
1233 coreconfigitem('ui', 'patch',
1236 coreconfigitem('ui', 'patch',
1234 default=None,
1237 default=None,
1235 )
1238 )
1236 coreconfigitem('ui', 'pre-merge-tool-output-template',
1239 coreconfigitem('ui', 'pre-merge-tool-output-template',
1237 default=None,
1240 default=None,
1238 )
1241 )
1239 coreconfigitem('ui', 'portablefilenames',
1242 coreconfigitem('ui', 'portablefilenames',
1240 default='warn',
1243 default='warn',
1241 )
1244 )
1242 coreconfigitem('ui', 'promptecho',
1245 coreconfigitem('ui', 'promptecho',
1243 default=False,
1246 default=False,
1244 )
1247 )
1245 coreconfigitem('ui', 'quiet',
1248 coreconfigitem('ui', 'quiet',
1246 default=False,
1249 default=False,
1247 )
1250 )
1248 coreconfigitem('ui', 'quietbookmarkmove',
1251 coreconfigitem('ui', 'quietbookmarkmove',
1249 default=False,
1252 default=False,
1250 )
1253 )
1251 coreconfigitem('ui', 'relative-paths',
1254 coreconfigitem('ui', 'relative-paths',
1252 default='legacy',
1255 default='legacy',
1253 )
1256 )
1254 coreconfigitem('ui', 'remotecmd',
1257 coreconfigitem('ui', 'remotecmd',
1255 default='hg',
1258 default='hg',
1256 )
1259 )
1257 coreconfigitem('ui', 'report_untrusted',
1260 coreconfigitem('ui', 'report_untrusted',
1258 default=True,
1261 default=True,
1259 )
1262 )
1260 coreconfigitem('ui', 'rollback',
1263 coreconfigitem('ui', 'rollback',
1261 default=True,
1264 default=True,
1262 )
1265 )
1263 coreconfigitem('ui', 'signal-safe-lock',
1266 coreconfigitem('ui', 'signal-safe-lock',
1264 default=True,
1267 default=True,
1265 )
1268 )
1266 coreconfigitem('ui', 'slash',
1269 coreconfigitem('ui', 'slash',
1267 default=False,
1270 default=False,
1268 )
1271 )
1269 coreconfigitem('ui', 'ssh',
1272 coreconfigitem('ui', 'ssh',
1270 default='ssh',
1273 default='ssh',
1271 )
1274 )
1272 coreconfigitem('ui', 'ssherrorhint',
1275 coreconfigitem('ui', 'ssherrorhint',
1273 default=None,
1276 default=None,
1274 )
1277 )
1275 coreconfigitem('ui', 'statuscopies',
1278 coreconfigitem('ui', 'statuscopies',
1276 default=False,
1279 default=False,
1277 )
1280 )
1278 coreconfigitem('ui', 'strict',
1281 coreconfigitem('ui', 'strict',
1279 default=False,
1282 default=False,
1280 )
1283 )
1281 coreconfigitem('ui', 'style',
1284 coreconfigitem('ui', 'style',
1282 default='',
1285 default='',
1283 )
1286 )
1284 coreconfigitem('ui', 'supportcontact',
1287 coreconfigitem('ui', 'supportcontact',
1285 default=None,
1288 default=None,
1286 )
1289 )
1287 coreconfigitem('ui', 'textwidth',
1290 coreconfigitem('ui', 'textwidth',
1288 default=78,
1291 default=78,
1289 )
1292 )
1290 coreconfigitem('ui', 'timeout',
1293 coreconfigitem('ui', 'timeout',
1291 default='600',
1294 default='600',
1292 )
1295 )
1293 coreconfigitem('ui', 'timeout.warn',
1296 coreconfigitem('ui', 'timeout.warn',
1294 default=0,
1297 default=0,
1295 )
1298 )
1296 coreconfigitem('ui', 'traceback',
1299 coreconfigitem('ui', 'traceback',
1297 default=False,
1300 default=False,
1298 )
1301 )
1299 coreconfigitem('ui', 'tweakdefaults',
1302 coreconfigitem('ui', 'tweakdefaults',
1300 default=False,
1303 default=False,
1301 )
1304 )
1302 coreconfigitem('ui', 'username',
1305 coreconfigitem('ui', 'username',
1303 alias=[('ui', 'user')]
1306 alias=[('ui', 'user')]
1304 )
1307 )
1305 coreconfigitem('ui', 'verbose',
1308 coreconfigitem('ui', 'verbose',
1306 default=False,
1309 default=False,
1307 )
1310 )
1308 coreconfigitem('verify', 'skipflags',
1311 coreconfigitem('verify', 'skipflags',
1309 default=None,
1312 default=None,
1310 )
1313 )
1311 coreconfigitem('web', 'allowbz2',
1314 coreconfigitem('web', 'allowbz2',
1312 default=False,
1315 default=False,
1313 )
1316 )
1314 coreconfigitem('web', 'allowgz',
1317 coreconfigitem('web', 'allowgz',
1315 default=False,
1318 default=False,
1316 )
1319 )
1317 coreconfigitem('web', 'allow-pull',
1320 coreconfigitem('web', 'allow-pull',
1318 alias=[('web', 'allowpull')],
1321 alias=[('web', 'allowpull')],
1319 default=True,
1322 default=True,
1320 )
1323 )
1321 coreconfigitem('web', 'allow-push',
1324 coreconfigitem('web', 'allow-push',
1322 alias=[('web', 'allow_push')],
1325 alias=[('web', 'allow_push')],
1323 default=list,
1326 default=list,
1324 )
1327 )
1325 coreconfigitem('web', 'allowzip',
1328 coreconfigitem('web', 'allowzip',
1326 default=False,
1329 default=False,
1327 )
1330 )
1328 coreconfigitem('web', 'archivesubrepos',
1331 coreconfigitem('web', 'archivesubrepos',
1329 default=False,
1332 default=False,
1330 )
1333 )
1331 coreconfigitem('web', 'cache',
1334 coreconfigitem('web', 'cache',
1332 default=True,
1335 default=True,
1333 )
1336 )
1334 coreconfigitem('web', 'comparisoncontext',
1337 coreconfigitem('web', 'comparisoncontext',
1335 default=5,
1338 default=5,
1336 )
1339 )
1337 coreconfigitem('web', 'contact',
1340 coreconfigitem('web', 'contact',
1338 default=None,
1341 default=None,
1339 )
1342 )
1340 coreconfigitem('web', 'deny_push',
1343 coreconfigitem('web', 'deny_push',
1341 default=list,
1344 default=list,
1342 )
1345 )
1343 coreconfigitem('web', 'guessmime',
1346 coreconfigitem('web', 'guessmime',
1344 default=False,
1347 default=False,
1345 )
1348 )
1346 coreconfigitem('web', 'hidden',
1349 coreconfigitem('web', 'hidden',
1347 default=False,
1350 default=False,
1348 )
1351 )
1349 coreconfigitem('web', 'labels',
1352 coreconfigitem('web', 'labels',
1350 default=list,
1353 default=list,
1351 )
1354 )
1352 coreconfigitem('web', 'logoimg',
1355 coreconfigitem('web', 'logoimg',
1353 default='hglogo.png',
1356 default='hglogo.png',
1354 )
1357 )
1355 coreconfigitem('web', 'logourl',
1358 coreconfigitem('web', 'logourl',
1356 default='https://mercurial-scm.org/',
1359 default='https://mercurial-scm.org/',
1357 )
1360 )
1358 coreconfigitem('web', 'accesslog',
1361 coreconfigitem('web', 'accesslog',
1359 default='-',
1362 default='-',
1360 )
1363 )
1361 coreconfigitem('web', 'address',
1364 coreconfigitem('web', 'address',
1362 default='',
1365 default='',
1363 )
1366 )
1364 coreconfigitem('web', 'allow-archive',
1367 coreconfigitem('web', 'allow-archive',
1365 alias=[('web', 'allow_archive')],
1368 alias=[('web', 'allow_archive')],
1366 default=list,
1369 default=list,
1367 )
1370 )
1368 coreconfigitem('web', 'allow_read',
1371 coreconfigitem('web', 'allow_read',
1369 default=list,
1372 default=list,
1370 )
1373 )
1371 coreconfigitem('web', 'baseurl',
1374 coreconfigitem('web', 'baseurl',
1372 default=None,
1375 default=None,
1373 )
1376 )
1374 coreconfigitem('web', 'cacerts',
1377 coreconfigitem('web', 'cacerts',
1375 default=None,
1378 default=None,
1376 )
1379 )
1377 coreconfigitem('web', 'certificate',
1380 coreconfigitem('web', 'certificate',
1378 default=None,
1381 default=None,
1379 )
1382 )
1380 coreconfigitem('web', 'collapse',
1383 coreconfigitem('web', 'collapse',
1381 default=False,
1384 default=False,
1382 )
1385 )
1383 coreconfigitem('web', 'csp',
1386 coreconfigitem('web', 'csp',
1384 default=None,
1387 default=None,
1385 )
1388 )
1386 coreconfigitem('web', 'deny_read',
1389 coreconfigitem('web', 'deny_read',
1387 default=list,
1390 default=list,
1388 )
1391 )
1389 coreconfigitem('web', 'descend',
1392 coreconfigitem('web', 'descend',
1390 default=True,
1393 default=True,
1391 )
1394 )
1392 coreconfigitem('web', 'description',
1395 coreconfigitem('web', 'description',
1393 default="",
1396 default="",
1394 )
1397 )
1395 coreconfigitem('web', 'encoding',
1398 coreconfigitem('web', 'encoding',
1396 default=lambda: encoding.encoding,
1399 default=lambda: encoding.encoding,
1397 )
1400 )
1398 coreconfigitem('web', 'errorlog',
1401 coreconfigitem('web', 'errorlog',
1399 default='-',
1402 default='-',
1400 )
1403 )
1401 coreconfigitem('web', 'ipv6',
1404 coreconfigitem('web', 'ipv6',
1402 default=False,
1405 default=False,
1403 )
1406 )
1404 coreconfigitem('web', 'maxchanges',
1407 coreconfigitem('web', 'maxchanges',
1405 default=10,
1408 default=10,
1406 )
1409 )
1407 coreconfigitem('web', 'maxfiles',
1410 coreconfigitem('web', 'maxfiles',
1408 default=10,
1411 default=10,
1409 )
1412 )
1410 coreconfigitem('web', 'maxshortchanges',
1413 coreconfigitem('web', 'maxshortchanges',
1411 default=60,
1414 default=60,
1412 )
1415 )
1413 coreconfigitem('web', 'motd',
1416 coreconfigitem('web', 'motd',
1414 default='',
1417 default='',
1415 )
1418 )
1416 coreconfigitem('web', 'name',
1419 coreconfigitem('web', 'name',
1417 default=dynamicdefault,
1420 default=dynamicdefault,
1418 )
1421 )
1419 coreconfigitem('web', 'port',
1422 coreconfigitem('web', 'port',
1420 default=8000,
1423 default=8000,
1421 )
1424 )
1422 coreconfigitem('web', 'prefix',
1425 coreconfigitem('web', 'prefix',
1423 default='',
1426 default='',
1424 )
1427 )
1425 coreconfigitem('web', 'push_ssl',
1428 coreconfigitem('web', 'push_ssl',
1426 default=True,
1429 default=True,
1427 )
1430 )
1428 coreconfigitem('web', 'refreshinterval',
1431 coreconfigitem('web', 'refreshinterval',
1429 default=20,
1432 default=20,
1430 )
1433 )
1431 coreconfigitem('web', 'server-header',
1434 coreconfigitem('web', 'server-header',
1432 default=None,
1435 default=None,
1433 )
1436 )
1434 coreconfigitem('web', 'static',
1437 coreconfigitem('web', 'static',
1435 default=None,
1438 default=None,
1436 )
1439 )
1437 coreconfigitem('web', 'staticurl',
1440 coreconfigitem('web', 'staticurl',
1438 default=None,
1441 default=None,
1439 )
1442 )
1440 coreconfigitem('web', 'stripes',
1443 coreconfigitem('web', 'stripes',
1441 default=1,
1444 default=1,
1442 )
1445 )
1443 coreconfigitem('web', 'style',
1446 coreconfigitem('web', 'style',
1444 default='paper',
1447 default='paper',
1445 )
1448 )
1446 coreconfigitem('web', 'templates',
1449 coreconfigitem('web', 'templates',
1447 default=None,
1450 default=None,
1448 )
1451 )
1449 coreconfigitem('web', 'view',
1452 coreconfigitem('web', 'view',
1450 default='served',
1453 default='served',
1451 )
1454 )
1452 coreconfigitem('worker', 'backgroundclose',
1455 coreconfigitem('worker', 'backgroundclose',
1453 default=dynamicdefault,
1456 default=dynamicdefault,
1454 )
1457 )
1455 # Windows defaults to a limit of 512 open files. A buffer of 128
1458 # Windows defaults to a limit of 512 open files. A buffer of 128
1456 # should give us enough headway.
1459 # should give us enough headway.
1457 coreconfigitem('worker', 'backgroundclosemaxqueue',
1460 coreconfigitem('worker', 'backgroundclosemaxqueue',
1458 default=384,
1461 default=384,
1459 )
1462 )
1460 coreconfigitem('worker', 'backgroundcloseminfilecount',
1463 coreconfigitem('worker', 'backgroundcloseminfilecount',
1461 default=2048,
1464 default=2048,
1462 )
1465 )
1463 coreconfigitem('worker', 'backgroundclosethreadcount',
1466 coreconfigitem('worker', 'backgroundclosethreadcount',
1464 default=4,
1467 default=4,
1465 )
1468 )
1466 coreconfigitem('worker', 'enabled',
1469 coreconfigitem('worker', 'enabled',
1467 default=True,
1470 default=True,
1468 )
1471 )
1469 coreconfigitem('worker', 'numcpus',
1472 coreconfigitem('worker', 'numcpus',
1470 default=None,
1473 default=None,
1471 )
1474 )
1472
1475
1473 # Rebase related configuration moved to core because other extension are doing
1476 # Rebase related configuration moved to core because other extension are doing
1474 # strange things. For example, shelve import the extensions to reuse some bit
1477 # strange things. For example, shelve import the extensions to reuse some bit
1475 # without formally loading it.
1478 # without formally loading it.
1476 coreconfigitem('commands', 'rebase.requiredest',
1479 coreconfigitem('commands', 'rebase.requiredest',
1477 default=False,
1480 default=False,
1478 )
1481 )
1479 coreconfigitem('experimental', 'rebaseskipobsolete',
1482 coreconfigitem('experimental', 'rebaseskipobsolete',
1480 default=True,
1483 default=True,
1481 )
1484 )
1482 coreconfigitem('rebase', 'singletransaction',
1485 coreconfigitem('rebase', 'singletransaction',
1483 default=False,
1486 default=False,
1484 )
1487 )
1485 coreconfigitem('rebase', 'experimental.inmemory',
1488 coreconfigitem('rebase', 'experimental.inmemory',
1486 default=False,
1489 default=False,
1487 )
1490 )
@@ -1,938 +1,943
1 # logcmdutil.py - utility for log-like commands
1 # logcmdutil.py - utility for log-like commands
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 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 itertools
10 import itertools
11 import os
11 import os
12 import posixpath
12 import posixpath
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 nullid,
16 nullid,
17 wdirid,
17 wdirid,
18 wdirrev,
18 wdirrev,
19 )
19 )
20
20
21 from . import (
21 from . import (
22 dagop,
22 dagop,
23 error,
23 error,
24 formatter,
24 formatter,
25 graphmod,
25 graphmod,
26 match as matchmod,
26 match as matchmod,
27 mdiff,
27 mdiff,
28 patch,
28 patch,
29 pathutil,
29 pathutil,
30 pycompat,
30 pycompat,
31 revset,
31 revset,
32 revsetlang,
32 revsetlang,
33 scmutil,
33 scmutil,
34 smartset,
34 smartset,
35 templatekw,
35 templatekw,
36 templater,
36 templater,
37 util,
37 util,
38 )
38 )
39 from .utils import (
39 from .utils import (
40 dateutil,
40 dateutil,
41 stringutil,
41 stringutil,
42 )
42 )
43
43
44 def getlimit(opts):
44 def getlimit(opts):
45 """get the log limit according to option -l/--limit"""
45 """get the log limit according to option -l/--limit"""
46 limit = opts.get('limit')
46 limit = opts.get('limit')
47 if limit:
47 if limit:
48 try:
48 try:
49 limit = int(limit)
49 limit = int(limit)
50 except ValueError:
50 except ValueError:
51 raise error.Abort(_('limit must be a positive integer'))
51 raise error.Abort(_('limit must be a positive integer'))
52 if limit <= 0:
52 if limit <= 0:
53 raise error.Abort(_('limit must be positive'))
53 raise error.Abort(_('limit must be positive'))
54 else:
54 else:
55 limit = None
55 limit = None
56 return limit
56 return limit
57
57
58 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
58 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
59 changes=None, stat=False, fp=None, graphwidth=0,
59 changes=None, stat=False, fp=None, graphwidth=0,
60 prefix='', root='', listsubrepos=False, hunksfilterfn=None):
60 prefix='', root='', listsubrepos=False, hunksfilterfn=None):
61 '''show diff or diffstat.'''
61 '''show diff or diffstat.'''
62 ctx1 = repo[node1]
62 ctx1 = repo[node1]
63 ctx2 = repo[node2]
63 ctx2 = repo[node2]
64 if root:
64 if root:
65 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
65 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
66 else:
66 else:
67 relroot = ''
67 relroot = ''
68 copysourcematch = None
68 copysourcematch = None
69 def compose(f, g):
69 def compose(f, g):
70 return lambda x: f(g(x))
70 return lambda x: f(g(x))
71 def pathfn(f):
71 def pathfn(f):
72 return posixpath.join(prefix, f)
72 return posixpath.join(prefix, f)
73 if relroot != '':
73 if relroot != '':
74 # XXX relative roots currently don't work if the root is within a
74 # XXX relative roots currently don't work if the root is within a
75 # subrepo
75 # subrepo
76 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
76 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
77 uirelroot = uipathfn(pathfn(relroot))
77 uirelroot = uipathfn(pathfn(relroot))
78 relroot += '/'
78 relroot += '/'
79 for matchroot in match.files():
79 for matchroot in match.files():
80 if not matchroot.startswith(relroot):
80 if not matchroot.startswith(relroot):
81 ui.warn(_('warning: %s not inside relative root %s\n') %
81 ui.warn(_('warning: %s not inside relative root %s\n') %
82 (uipathfn(pathfn(matchroot)), uirelroot))
82 (uipathfn(pathfn(matchroot)), uirelroot))
83
83
84 relrootmatch = scmutil.match(ctx2, pats=[relroot], default='path')
84 relrootmatch = scmutil.match(ctx2, pats=[relroot], default='path')
85 match = matchmod.intersectmatchers(match, relrootmatch)
85 match = matchmod.intersectmatchers(match, relrootmatch)
86 copysourcematch = relrootmatch
86 copysourcematch = relrootmatch
87
87
88 checkroot = (repo.ui.configbool('devel', 'all-warnings') or
88 checkroot = (repo.ui.configbool('devel', 'all-warnings') or
89 repo.ui.configbool('devel', 'check-relroot'))
89 repo.ui.configbool('devel', 'check-relroot'))
90 def relrootpathfn(f):
90 def relrootpathfn(f):
91 if checkroot and not f.startswith(relroot):
91 if checkroot and not f.startswith(relroot):
92 raise AssertionError(
92 raise AssertionError(
93 "file %s doesn't start with relroot %s" % (f, relroot))
93 "file %s doesn't start with relroot %s" % (f, relroot))
94 return f[len(relroot):]
94 return f[len(relroot):]
95 pathfn = compose(relrootpathfn, pathfn)
95 pathfn = compose(relrootpathfn, pathfn)
96
96
97 if stat:
97 if stat:
98 diffopts = diffopts.copy(context=0, noprefix=False)
98 diffopts = diffopts.copy(context=0, noprefix=False)
99 width = 80
99 width = 80
100 if not ui.plain():
100 if not ui.plain():
101 width = ui.termwidth() - graphwidth
101 width = ui.termwidth() - graphwidth
102 # If an explicit --root was given, don't respect ui.relative-paths
102 # If an explicit --root was given, don't respect ui.relative-paths
103 if not relroot:
103 if not relroot:
104 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
104 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
105
105
106 chunks = ctx2.diff(ctx1, match, changes, opts=diffopts, pathfn=pathfn,
106 chunks = ctx2.diff(ctx1, match, changes, opts=diffopts, pathfn=pathfn,
107 copysourcematch=copysourcematch,
107 copysourcematch=copysourcematch,
108 hunksfilterfn=hunksfilterfn)
108 hunksfilterfn=hunksfilterfn)
109
109
110 if fp is not None or ui.canwritewithoutlabels():
110 if fp is not None or ui.canwritewithoutlabels():
111 out = fp or ui
111 out = fp or ui
112 if stat:
112 if stat:
113 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
113 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
114 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
114 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
115 out.write(chunk)
115 out.write(chunk)
116 else:
116 else:
117 if stat:
117 if stat:
118 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
118 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
119 else:
119 else:
120 chunks = patch.difflabel(lambda chunks, **kwargs: chunks, chunks,
120 chunks = patch.difflabel(lambda chunks, **kwargs: chunks, chunks,
121 opts=diffopts)
121 opts=diffopts)
122 if ui.canbatchlabeledwrites():
122 if ui.canbatchlabeledwrites():
123 def gen():
123 def gen():
124 for chunk, label in chunks:
124 for chunk, label in chunks:
125 yield ui.label(chunk, label=label)
125 yield ui.label(chunk, label=label)
126 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
126 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
127 ui.write(chunk)
127 ui.write(chunk)
128 else:
128 else:
129 for chunk, label in chunks:
129 for chunk, label in chunks:
130 ui.write(chunk, label=label)
130 ui.write(chunk, label=label)
131
131
132 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
132 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
133 tempnode2 = node2
133 tempnode2 = node2
134 try:
134 try:
135 if node2 is not None:
135 if node2 is not None:
136 tempnode2 = ctx2.substate[subpath][1]
136 tempnode2 = ctx2.substate[subpath][1]
137 except KeyError:
137 except KeyError:
138 # A subrepo that existed in node1 was deleted between node1 and
138 # A subrepo that existed in node1 was deleted between node1 and
139 # node2 (inclusive). Thus, ctx2's substate won't contain that
139 # node2 (inclusive). Thus, ctx2's substate won't contain that
140 # subpath. The best we can do is to ignore it.
140 # subpath. The best we can do is to ignore it.
141 tempnode2 = None
141 tempnode2 = None
142 submatch = matchmod.subdirmatcher(subpath, match)
142 submatch = matchmod.subdirmatcher(subpath, match)
143 subprefix = repo.wvfs.reljoin(prefix, subpath)
143 subprefix = repo.wvfs.reljoin(prefix, subpath)
144 if listsubrepos or match.exact(subpath) or any(submatch.files()):
144 if listsubrepos or match.exact(subpath) or any(submatch.files()):
145 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
145 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
146 stat=stat, fp=fp, prefix=subprefix)
146 stat=stat, fp=fp, prefix=subprefix)
147
147
148 class changesetdiffer(object):
148 class changesetdiffer(object):
149 """Generate diff of changeset with pre-configured filtering functions"""
149 """Generate diff of changeset with pre-configured filtering functions"""
150
150
151 def _makefilematcher(self, ctx):
151 def _makefilematcher(self, ctx):
152 return scmutil.matchall(ctx.repo())
152 return scmutil.matchall(ctx.repo())
153
153
154 def _makehunksfilter(self, ctx):
154 def _makehunksfilter(self, ctx):
155 return None
155 return None
156
156
157 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
157 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
158 repo = ctx.repo()
158 repo = ctx.repo()
159 node = ctx.node()
159 node = ctx.node()
160 prev = ctx.p1().node()
160 prev = ctx.p1().node()
161 diffordiffstat(ui, repo, diffopts, prev, node,
161 diffordiffstat(ui, repo, diffopts, prev, node,
162 match=self._makefilematcher(ctx), stat=stat,
162 match=self._makefilematcher(ctx), stat=stat,
163 graphwidth=graphwidth,
163 graphwidth=graphwidth,
164 hunksfilterfn=self._makehunksfilter(ctx))
164 hunksfilterfn=self._makehunksfilter(ctx))
165
165
166 def changesetlabels(ctx):
166 def changesetlabels(ctx):
167 labels = ['log.changeset', 'changeset.%s' % ctx.phasestr()]
167 labels = ['log.changeset', 'changeset.%s' % ctx.phasestr()]
168 if ctx.obsolete():
168 if ctx.obsolete():
169 labels.append('changeset.obsolete')
169 labels.append('changeset.obsolete')
170 if ctx.isunstable():
170 if ctx.isunstable():
171 labels.append('changeset.unstable')
171 labels.append('changeset.unstable')
172 for instability in ctx.instabilities():
172 for instability in ctx.instabilities():
173 labels.append('instability.%s' % instability)
173 labels.append('instability.%s' % instability)
174 return ' '.join(labels)
174 return ' '.join(labels)
175
175
176 class changesetprinter(object):
176 class changesetprinter(object):
177 '''show changeset information when templating not requested.'''
177 '''show changeset information when templating not requested.'''
178
178
179 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
179 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
180 self.ui = ui
180 self.ui = ui
181 self.repo = repo
181 self.repo = repo
182 self.buffered = buffered
182 self.buffered = buffered
183 self._differ = differ or changesetdiffer()
183 self._differ = differ or changesetdiffer()
184 self._diffopts = patch.diffallopts(ui, diffopts)
184 self._diffopts = patch.diffallopts(ui, diffopts)
185 self._includestat = diffopts and diffopts.get('stat')
185 self._includestat = diffopts and diffopts.get('stat')
186 self._includediff = diffopts and diffopts.get('patch')
186 self._includediff = diffopts and diffopts.get('patch')
187 self.header = {}
187 self.header = {}
188 self.hunk = {}
188 self.hunk = {}
189 self.lastheader = None
189 self.lastheader = None
190 self.footer = None
190 self.footer = None
191 self._columns = templatekw.getlogcolumns()
191 self._columns = templatekw.getlogcolumns()
192
192
193 def flush(self, ctx):
193 def flush(self, ctx):
194 rev = ctx.rev()
194 rev = ctx.rev()
195 if rev in self.header:
195 if rev in self.header:
196 h = self.header[rev]
196 h = self.header[rev]
197 if h != self.lastheader:
197 if h != self.lastheader:
198 self.lastheader = h
198 self.lastheader = h
199 self.ui.write(h)
199 self.ui.write(h)
200 del self.header[rev]
200 del self.header[rev]
201 if rev in self.hunk:
201 if rev in self.hunk:
202 self.ui.write(self.hunk[rev])
202 self.ui.write(self.hunk[rev])
203 del self.hunk[rev]
203 del self.hunk[rev]
204
204
205 def close(self):
205 def close(self):
206 if self.footer:
206 if self.footer:
207 self.ui.write(self.footer)
207 self.ui.write(self.footer)
208
208
209 def show(self, ctx, copies=None, **props):
209 def show(self, ctx, copies=None, **props):
210 props = pycompat.byteskwargs(props)
210 props = pycompat.byteskwargs(props)
211 if self.buffered:
211 if self.buffered:
212 self.ui.pushbuffer(labeled=True)
212 self.ui.pushbuffer(labeled=True)
213 self._show(ctx, copies, props)
213 self._show(ctx, copies, props)
214 self.hunk[ctx.rev()] = self.ui.popbuffer()
214 self.hunk[ctx.rev()] = self.ui.popbuffer()
215 else:
215 else:
216 self._show(ctx, copies, props)
216 self._show(ctx, copies, props)
217
217
218 def _show(self, ctx, copies, props):
218 def _show(self, ctx, copies, props):
219 '''show a single changeset or file revision'''
219 '''show a single changeset or file revision'''
220 changenode = ctx.node()
220 changenode = ctx.node()
221 graphwidth = props.get('graphwidth', 0)
221 graphwidth = props.get('graphwidth', 0)
222
222
223 if self.ui.quiet:
223 if self.ui.quiet:
224 self.ui.write("%s\n" % scmutil.formatchangeid(ctx),
224 self.ui.write("%s\n" % scmutil.formatchangeid(ctx),
225 label='log.node')
225 label='log.node')
226 return
226 return
227
227
228 columns = self._columns
228 columns = self._columns
229 self.ui.write(columns['changeset'] % scmutil.formatchangeid(ctx),
229 self.ui.write(columns['changeset'] % scmutil.formatchangeid(ctx),
230 label=changesetlabels(ctx))
230 label=changesetlabels(ctx))
231
231
232 # branches are shown first before any other names due to backwards
232 # branches are shown first before any other names due to backwards
233 # compatibility
233 # compatibility
234 branch = ctx.branch()
234 branch = ctx.branch()
235 # don't show the default branch name
235 # don't show the default branch name
236 if branch != 'default':
236 if branch != 'default':
237 self.ui.write(columns['branch'] % branch, label='log.branch')
237 self.ui.write(columns['branch'] % branch, label='log.branch')
238
238
239 for nsname, ns in self.repo.names.iteritems():
239 for nsname, ns in self.repo.names.iteritems():
240 # branches has special logic already handled above, so here we just
240 # branches has special logic already handled above, so here we just
241 # skip it
241 # skip it
242 if nsname == 'branches':
242 if nsname == 'branches':
243 continue
243 continue
244 # we will use the templatename as the color name since those two
244 # we will use the templatename as the color name since those two
245 # should be the same
245 # should be the same
246 for name in ns.names(self.repo, changenode):
246 for name in ns.names(self.repo, changenode):
247 self.ui.write(ns.logfmt % name,
247 self.ui.write(ns.logfmt % name,
248 label='log.%s' % ns.colorname)
248 label='log.%s' % ns.colorname)
249 if self.ui.debugflag:
249 if self.ui.debugflag:
250 self.ui.write(columns['phase'] % ctx.phasestr(), label='log.phase')
250 self.ui.write(columns['phase'] % ctx.phasestr(), label='log.phase')
251 for pctx in scmutil.meaningfulparents(self.repo, ctx):
251 for pctx in scmutil.meaningfulparents(self.repo, ctx):
252 label = 'log.parent changeset.%s' % pctx.phasestr()
252 label = 'log.parent changeset.%s' % pctx.phasestr()
253 self.ui.write(columns['parent'] % scmutil.formatchangeid(pctx),
253 self.ui.write(columns['parent'] % scmutil.formatchangeid(pctx),
254 label=label)
254 label=label)
255
255
256 if self.ui.debugflag:
256 if self.ui.debugflag:
257 mnode = ctx.manifestnode()
257 mnode = ctx.manifestnode()
258 if mnode is None:
258 if mnode is None:
259 mnode = wdirid
259 mnode = wdirid
260 mrev = wdirrev
260 mrev = wdirrev
261 else:
261 else:
262 mrev = self.repo.manifestlog.rev(mnode)
262 mrev = self.repo.manifestlog.rev(mnode)
263 self.ui.write(columns['manifest']
263 self.ui.write(columns['manifest']
264 % scmutil.formatrevnode(self.ui, mrev, mnode),
264 % scmutil.formatrevnode(self.ui, mrev, mnode),
265 label='ui.debug log.manifest')
265 label='ui.debug log.manifest')
266 self.ui.write(columns['user'] % ctx.user(), label='log.user')
266 self.ui.write(columns['user'] % ctx.user(), label='log.user')
267 self.ui.write(columns['date'] % dateutil.datestr(ctx.date()),
267 self.ui.write(columns['date'] % dateutil.datestr(ctx.date()),
268 label='log.date')
268 label='log.date')
269
269
270 if ctx.isunstable():
270 if ctx.isunstable():
271 instabilities = ctx.instabilities()
271 instabilities = ctx.instabilities()
272 self.ui.write(columns['instability'] % ', '.join(instabilities),
272 self.ui.write(columns['instability'] % ', '.join(instabilities),
273 label='log.instability')
273 label='log.instability')
274
274
275 elif ctx.obsolete():
275 elif ctx.obsolete():
276 self._showobsfate(ctx)
276 self._showobsfate(ctx)
277
277
278 self._exthook(ctx)
278 self._exthook(ctx)
279
279
280 if self.ui.debugflag:
280 if self.ui.debugflag:
281 files = ctx.p1().status(ctx)[:3]
281 files = ctx.p1().status(ctx)[:3]
282 for key, value in zip(['files', 'files+', 'files-'], files):
282 for key, value in zip(['files', 'files+', 'files-'], files):
283 if value:
283 if value:
284 self.ui.write(columns[key] % " ".join(value),
284 self.ui.write(columns[key] % " ".join(value),
285 label='ui.debug log.files')
285 label='ui.debug log.files')
286 elif ctx.files() and self.ui.verbose:
286 elif ctx.files() and self.ui.verbose:
287 self.ui.write(columns['files'] % " ".join(ctx.files()),
287 self.ui.write(columns['files'] % " ".join(ctx.files()),
288 label='ui.note log.files')
288 label='ui.note log.files')
289 if copies and self.ui.verbose:
289 if copies and self.ui.verbose:
290 copies = ['%s (%s)' % c for c in copies]
290 copies = ['%s (%s)' % c for c in copies]
291 self.ui.write(columns['copies'] % ' '.join(copies),
291 self.ui.write(columns['copies'] % ' '.join(copies),
292 label='ui.note log.copies')
292 label='ui.note log.copies')
293
293
294 extra = ctx.extra()
294 extra = ctx.extra()
295 if extra and self.ui.debugflag:
295 if extra and self.ui.debugflag:
296 for key, value in sorted(extra.items()):
296 for key, value in sorted(extra.items()):
297 self.ui.write(columns['extra']
297 self.ui.write(columns['extra']
298 % (key, stringutil.escapestr(value)),
298 % (key, stringutil.escapestr(value)),
299 label='ui.debug log.extra')
299 label='ui.debug log.extra')
300
300
301 description = ctx.description().strip()
301 description = ctx.description().strip()
302 if description:
302 if description:
303 if self.ui.verbose:
303 if self.ui.verbose:
304 self.ui.write(_("description:\n"),
304 self.ui.write(_("description:\n"),
305 label='ui.note log.description')
305 label='ui.note log.description')
306 self.ui.write(description,
306 self.ui.write(description,
307 label='ui.note log.description')
307 label='ui.note log.description')
308 self.ui.write("\n\n")
308 self.ui.write("\n\n")
309 else:
309 else:
310 self.ui.write(columns['summary'] % description.splitlines()[0],
310 self.ui.write(columns['summary'] % description.splitlines()[0],
311 label='log.summary')
311 label='log.summary')
312 self.ui.write("\n")
312 self.ui.write("\n")
313
313
314 self._showpatch(ctx, graphwidth)
314 self._showpatch(ctx, graphwidth)
315
315
316 def _showobsfate(self, ctx):
316 def _showobsfate(self, ctx):
317 # TODO: do not depend on templater
317 # TODO: do not depend on templater
318 tres = formatter.templateresources(self.repo.ui, self.repo)
318 tres = formatter.templateresources(self.repo.ui, self.repo)
319 t = formatter.maketemplater(self.repo.ui, '{join(obsfate, "\n")}',
319 t = formatter.maketemplater(self.repo.ui, '{join(obsfate, "\n")}',
320 defaults=templatekw.keywords,
320 defaults=templatekw.keywords,
321 resources=tres)
321 resources=tres)
322 obsfate = t.renderdefault({'ctx': ctx}).splitlines()
322 obsfate = t.renderdefault({'ctx': ctx}).splitlines()
323
323
324 if obsfate:
324 if obsfate:
325 for obsfateline in obsfate:
325 for obsfateline in obsfate:
326 self.ui.write(self._columns['obsolete'] % obsfateline,
326 self.ui.write(self._columns['obsolete'] % obsfateline,
327 label='log.obsfate')
327 label='log.obsfate')
328
328
329 def _exthook(self, ctx):
329 def _exthook(self, ctx):
330 '''empty method used by extension as a hook point
330 '''empty method used by extension as a hook point
331 '''
331 '''
332
332
333 def _showpatch(self, ctx, graphwidth=0):
333 def _showpatch(self, ctx, graphwidth=0):
334 if self._includestat:
334 if self._includestat:
335 self._differ.showdiff(self.ui, ctx, self._diffopts,
335 self._differ.showdiff(self.ui, ctx, self._diffopts,
336 graphwidth, stat=True)
336 graphwidth, stat=True)
337 if self._includestat and self._includediff:
337 if self._includestat and self._includediff:
338 self.ui.write("\n")
338 self.ui.write("\n")
339 if self._includediff:
339 if self._includediff:
340 self._differ.showdiff(self.ui, ctx, self._diffopts,
340 self._differ.showdiff(self.ui, ctx, self._diffopts,
341 graphwidth, stat=False)
341 graphwidth, stat=False)
342 if self._includestat or self._includediff:
342 if self._includestat or self._includediff:
343 self.ui.write("\n")
343 self.ui.write("\n")
344
344
345 class changesetformatter(changesetprinter):
345 class changesetformatter(changesetprinter):
346 """Format changeset information by generic formatter"""
346 """Format changeset information by generic formatter"""
347
347
348 def __init__(self, ui, repo, fm, differ=None, diffopts=None,
348 def __init__(self, ui, repo, fm, differ=None, diffopts=None,
349 buffered=False):
349 buffered=False):
350 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
350 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
351 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
351 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
352 self._fm = fm
352 self._fm = fm
353
353
354 def close(self):
354 def close(self):
355 self._fm.end()
355 self._fm.end()
356
356
357 def _show(self, ctx, copies, props):
357 def _show(self, ctx, copies, props):
358 '''show a single changeset or file revision'''
358 '''show a single changeset or file revision'''
359 fm = self._fm
359 fm = self._fm
360 fm.startitem()
360 fm.startitem()
361 fm.context(ctx=ctx)
361 fm.context(ctx=ctx)
362 fm.data(rev=scmutil.intrev(ctx),
362 fm.data(rev=scmutil.intrev(ctx),
363 node=fm.hexfunc(scmutil.binnode(ctx)))
363 node=fm.hexfunc(scmutil.binnode(ctx)))
364
364
365 if self.ui.quiet:
365 if self.ui.quiet:
366 return
366 return
367
367
368 fm.data(branch=ctx.branch(),
368 fm.data(branch=ctx.branch(),
369 phase=ctx.phasestr(),
369 phase=ctx.phasestr(),
370 user=ctx.user(),
370 user=ctx.user(),
371 date=fm.formatdate(ctx.date()),
371 date=fm.formatdate(ctx.date()),
372 desc=ctx.description(),
372 desc=ctx.description(),
373 bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'),
373 bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'),
374 tags=fm.formatlist(ctx.tags(), name='tag'),
374 tags=fm.formatlist(ctx.tags(), name='tag'),
375 parents=fm.formatlist([fm.hexfunc(c.node())
375 parents=fm.formatlist([fm.hexfunc(c.node())
376 for c in ctx.parents()], name='node'))
376 for c in ctx.parents()], name='node'))
377
377
378 if self.ui.debugflag:
378 if self.ui.debugflag:
379 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid),
379 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid),
380 extra=fm.formatdict(ctx.extra()))
380 extra=fm.formatdict(ctx.extra()))
381
381
382 files = ctx.p1().status(ctx)
382 files = ctx.p1().status(ctx)
383 fm.data(modified=fm.formatlist(files[0], name='file'),
383 fm.data(modified=fm.formatlist(files[0], name='file'),
384 added=fm.formatlist(files[1], name='file'),
384 added=fm.formatlist(files[1], name='file'),
385 removed=fm.formatlist(files[2], name='file'))
385 removed=fm.formatlist(files[2], name='file'))
386
386
387 elif self.ui.verbose:
387 elif self.ui.verbose:
388 fm.data(files=fm.formatlist(ctx.files(), name='file'))
388 fm.data(files=fm.formatlist(ctx.files(), name='file'))
389 if copies:
389 if copies:
390 fm.data(copies=fm.formatdict(copies,
390 fm.data(copies=fm.formatdict(copies,
391 key='name', value='source'))
391 key='name', value='source'))
392
392
393 if self._includestat:
393 if self._includestat:
394 self.ui.pushbuffer()
394 self.ui.pushbuffer()
395 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
395 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
396 fm.data(diffstat=self.ui.popbuffer())
396 fm.data(diffstat=self.ui.popbuffer())
397 if self._includediff:
397 if self._includediff:
398 self.ui.pushbuffer()
398 self.ui.pushbuffer()
399 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
399 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
400 fm.data(diff=self.ui.popbuffer())
400 fm.data(diff=self.ui.popbuffer())
401
401
402 class changesettemplater(changesetprinter):
402 class changesettemplater(changesetprinter):
403 '''format changeset information.
403 '''format changeset information.
404
404
405 Note: there are a variety of convenience functions to build a
405 Note: there are a variety of convenience functions to build a
406 changesettemplater for common cases. See functions such as:
406 changesettemplater for common cases. See functions such as:
407 maketemplater, changesetdisplayer, buildcommittemplate, or other
407 maketemplater, changesetdisplayer, buildcommittemplate, or other
408 functions that use changesest_templater.
408 functions that use changesest_templater.
409 '''
409 '''
410
410
411 # Arguments before "buffered" used to be positional. Consider not
411 # Arguments before "buffered" used to be positional. Consider not
412 # adding/removing arguments before "buffered" to not break callers.
412 # adding/removing arguments before "buffered" to not break callers.
413 def __init__(self, ui, repo, tmplspec, differ=None, diffopts=None,
413 def __init__(self, ui, repo, tmplspec, differ=None, diffopts=None,
414 buffered=False):
414 buffered=False):
415 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
415 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
416 # tres is shared with _graphnodeformatter()
416 # tres is shared with _graphnodeformatter()
417 self._tresources = tres = formatter.templateresources(ui, repo)
417 self._tresources = tres = formatter.templateresources(ui, repo)
418 self.t = formatter.loadtemplater(ui, tmplspec,
418 self.t = formatter.loadtemplater(ui, tmplspec,
419 defaults=templatekw.keywords,
419 defaults=templatekw.keywords,
420 resources=tres,
420 resources=tres,
421 cache=templatekw.defaulttempl)
421 cache=templatekw.defaulttempl)
422 self._counter = itertools.count()
422 self._counter = itertools.count()
423
423
424 self._tref = tmplspec.ref
424 self._tref = tmplspec.ref
425 self._parts = {'header': '', 'footer': '',
425 self._parts = {'header': '', 'footer': '',
426 tmplspec.ref: tmplspec.ref,
426 tmplspec.ref: tmplspec.ref,
427 'docheader': '', 'docfooter': '',
427 'docheader': '', 'docfooter': '',
428 'separator': ''}
428 'separator': ''}
429 if tmplspec.mapfile:
429 if tmplspec.mapfile:
430 # find correct templates for current mode, for backward
430 # find correct templates for current mode, for backward
431 # compatibility with 'log -v/-q/--debug' using a mapfile
431 # compatibility with 'log -v/-q/--debug' using a mapfile
432 tmplmodes = [
432 tmplmodes = [
433 (True, ''),
433 (True, ''),
434 (self.ui.verbose, '_verbose'),
434 (self.ui.verbose, '_verbose'),
435 (self.ui.quiet, '_quiet'),
435 (self.ui.quiet, '_quiet'),
436 (self.ui.debugflag, '_debug'),
436 (self.ui.debugflag, '_debug'),
437 ]
437 ]
438 for mode, postfix in tmplmodes:
438 for mode, postfix in tmplmodes:
439 for t in self._parts:
439 for t in self._parts:
440 cur = t + postfix
440 cur = t + postfix
441 if mode and cur in self.t:
441 if mode and cur in self.t:
442 self._parts[t] = cur
442 self._parts[t] = cur
443 else:
443 else:
444 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
444 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
445 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
445 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
446 self._parts.update(m)
446 self._parts.update(m)
447
447
448 if self._parts['docheader']:
448 if self._parts['docheader']:
449 self.ui.write(self.t.render(self._parts['docheader'], {}))
449 self.ui.write(self.t.render(self._parts['docheader'], {}))
450
450
451 def close(self):
451 def close(self):
452 if self._parts['docfooter']:
452 if self._parts['docfooter']:
453 if not self.footer:
453 if not self.footer:
454 self.footer = ""
454 self.footer = ""
455 self.footer += self.t.render(self._parts['docfooter'], {})
455 self.footer += self.t.render(self._parts['docfooter'], {})
456 return super(changesettemplater, self).close()
456 return super(changesettemplater, self).close()
457
457
458 def _show(self, ctx, copies, props):
458 def _show(self, ctx, copies, props):
459 '''show a single changeset or file revision'''
459 '''show a single changeset or file revision'''
460 props = props.copy()
460 props = props.copy()
461 props['ctx'] = ctx
461 props['ctx'] = ctx
462 props['index'] = index = next(self._counter)
462 props['index'] = index = next(self._counter)
463 props['revcache'] = {'copies': copies}
463 props['revcache'] = {'copies': copies}
464 graphwidth = props.get('graphwidth', 0)
464 graphwidth = props.get('graphwidth', 0)
465
465
466 # write separator, which wouldn't work well with the header part below
466 # write separator, which wouldn't work well with the header part below
467 # since there's inherently a conflict between header (across items) and
467 # since there's inherently a conflict between header (across items) and
468 # separator (per item)
468 # separator (per item)
469 if self._parts['separator'] and index > 0:
469 if self._parts['separator'] and index > 0:
470 self.ui.write(self.t.render(self._parts['separator'], {}))
470 self.ui.write(self.t.render(self._parts['separator'], {}))
471
471
472 # write header
472 # write header
473 if self._parts['header']:
473 if self._parts['header']:
474 h = self.t.render(self._parts['header'], props)
474 h = self.t.render(self._parts['header'], props)
475 if self.buffered:
475 if self.buffered:
476 self.header[ctx.rev()] = h
476 self.header[ctx.rev()] = h
477 else:
477 else:
478 if self.lastheader != h:
478 if self.lastheader != h:
479 self.lastheader = h
479 self.lastheader = h
480 self.ui.write(h)
480 self.ui.write(h)
481
481
482 # write changeset metadata, then patch if requested
482 # write changeset metadata, then patch if requested
483 key = self._parts[self._tref]
483 key = self._parts[self._tref]
484 self.ui.write(self.t.render(key, props))
484 self.ui.write(self.t.render(key, props))
485 self._showpatch(ctx, graphwidth)
485 self._showpatch(ctx, graphwidth)
486
486
487 if self._parts['footer']:
487 if self._parts['footer']:
488 if not self.footer:
488 if not self.footer:
489 self.footer = self.t.render(self._parts['footer'], props)
489 self.footer = self.t.render(self._parts['footer'], props)
490
490
491 def templatespec(tmpl, mapfile):
491 def templatespec(tmpl, mapfile):
492 if pycompat.ispy3:
492 if pycompat.ispy3:
493 assert not isinstance(tmpl, str), 'tmpl must not be a str'
493 assert not isinstance(tmpl, str), 'tmpl must not be a str'
494 if mapfile:
494 if mapfile:
495 return formatter.templatespec('changeset', tmpl, mapfile)
495 return formatter.templatespec('changeset', tmpl, mapfile)
496 else:
496 else:
497 return formatter.templatespec('', tmpl, None)
497 return formatter.templatespec('', tmpl, None)
498
498
499 def _lookuptemplate(ui, tmpl, style):
499 def _lookuptemplate(ui, tmpl, style):
500 """Find the template matching the given template spec or style
500 """Find the template matching the given template spec or style
501
501
502 See formatter.lookuptemplate() for details.
502 See formatter.lookuptemplate() for details.
503 """
503 """
504
504
505 # ui settings
505 # ui settings
506 if not tmpl and not style: # template are stronger than style
506 if not tmpl and not style: # template are stronger than style
507 tmpl = ui.config('ui', 'logtemplate')
507 tmpl = ui.config('ui', 'logtemplate')
508 if tmpl:
508 if tmpl:
509 return templatespec(templater.unquotestring(tmpl), None)
509 return templatespec(templater.unquotestring(tmpl), None)
510 else:
510 else:
511 style = util.expandpath(ui.config('ui', 'style'))
511 style = util.expandpath(ui.config('ui', 'style'))
512
512
513 if not tmpl and style:
513 if not tmpl and style:
514 mapfile = style
514 mapfile = style
515 if not os.path.split(mapfile)[0]:
515 if not os.path.split(mapfile)[0]:
516 mapname = (templater.templatepath('map-cmdline.' + mapfile)
516 mapname = (templater.templatepath('map-cmdline.' + mapfile)
517 or templater.templatepath(mapfile))
517 or templater.templatepath(mapfile))
518 if mapname:
518 if mapname:
519 mapfile = mapname
519 mapfile = mapname
520 return templatespec(None, mapfile)
520 return templatespec(None, mapfile)
521
521
522 if not tmpl:
522 if not tmpl:
523 return templatespec(None, None)
523 return templatespec(None, None)
524
524
525 return formatter.lookuptemplate(ui, 'changeset', tmpl)
525 return formatter.lookuptemplate(ui, 'changeset', tmpl)
526
526
527 def maketemplater(ui, repo, tmpl, buffered=False):
527 def maketemplater(ui, repo, tmpl, buffered=False):
528 """Create a changesettemplater from a literal template 'tmpl'
528 """Create a changesettemplater from a literal template 'tmpl'
529 byte-string."""
529 byte-string."""
530 spec = templatespec(tmpl, None)
530 spec = templatespec(tmpl, None)
531 return changesettemplater(ui, repo, spec, buffered=buffered)
531 return changesettemplater(ui, repo, spec, buffered=buffered)
532
532
533 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
533 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
534 """show one changeset using template or regular display.
534 """show one changeset using template or regular display.
535
535
536 Display format will be the first non-empty hit of:
536 Display format will be the first non-empty hit of:
537 1. option 'template'
537 1. option 'template'
538 2. option 'style'
538 2. option 'style'
539 3. [ui] setting 'logtemplate'
539 3. [ui] setting 'logtemplate'
540 4. [ui] setting 'style'
540 4. [ui] setting 'style'
541 If all of these values are either the unset or the empty string,
541 If all of these values are either the unset or the empty string,
542 regular display via changesetprinter() is done.
542 regular display via changesetprinter() is done.
543 """
543 """
544 postargs = (differ, opts, buffered)
544 postargs = (differ, opts, buffered)
545 if opts.get('template') in {'cbor', 'json'}:
545 if opts.get('template') in {'cbor', 'json'}:
546 fm = ui.formatter('log', opts)
546 fm = ui.formatter('log', opts)
547 return changesetformatter(ui, repo, fm, *postargs)
547 return changesetformatter(ui, repo, fm, *postargs)
548
548
549 spec = _lookuptemplate(ui, opts.get('template'), opts.get('style'))
549 spec = _lookuptemplate(ui, opts.get('template'), opts.get('style'))
550
550
551 if not spec.ref and not spec.tmpl and not spec.mapfile:
551 if not spec.ref and not spec.tmpl and not spec.mapfile:
552 return changesetprinter(ui, repo, *postargs)
552 return changesetprinter(ui, repo, *postargs)
553
553
554 return changesettemplater(ui, repo, spec, *postargs)
554 return changesettemplater(ui, repo, spec, *postargs)
555
555
556 def _makematcher(repo, revs, pats, opts):
556 def _makematcher(repo, revs, pats, opts):
557 """Build matcher and expanded patterns from log options
557 """Build matcher and expanded patterns from log options
558
558
559 If --follow, revs are the revisions to follow from.
559 If --follow, revs are the revisions to follow from.
560
560
561 Returns (match, pats, slowpath) where
561 Returns (match, pats, slowpath) where
562 - match: a matcher built from the given pats and -I/-X opts
562 - match: a matcher built from the given pats and -I/-X opts
563 - pats: patterns used (globs are expanded on Windows)
563 - pats: patterns used (globs are expanded on Windows)
564 - slowpath: True if patterns aren't as simple as scanning filelogs
564 - slowpath: True if patterns aren't as simple as scanning filelogs
565 """
565 """
566 # pats/include/exclude are passed to match.match() directly in
566 # pats/include/exclude are passed to match.match() directly in
567 # _matchfiles() revset but walkchangerevs() builds its matcher with
567 # _matchfiles() revset but walkchangerevs() builds its matcher with
568 # scmutil.match(). The difference is input pats are globbed on
568 # scmutil.match(). The difference is input pats are globbed on
569 # platforms without shell expansion (windows).
569 # platforms without shell expansion (windows).
570 wctx = repo[None]
570 wctx = repo[None]
571 match, pats = scmutil.matchandpats(wctx, pats, opts)
571 match, pats = scmutil.matchandpats(wctx, pats, opts)
572 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
572 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
573 if not slowpath:
573 if not slowpath:
574 follow = opts.get('follow') or opts.get('follow_first')
574 follow = opts.get('follow') or opts.get('follow_first')
575 startctxs = []
575 startctxs = []
576 if follow and opts.get('rev'):
576 if follow and opts.get('rev'):
577 startctxs = [repo[r] for r in revs]
577 startctxs = [repo[r] for r in revs]
578 for f in match.files():
578 for f in match.files():
579 if follow and startctxs:
579 if follow and startctxs:
580 # No idea if the path was a directory at that revision, so
580 # No idea if the path was a directory at that revision, so
581 # take the slow path.
581 # take the slow path.
582 if any(f not in c for c in startctxs):
582 if any(f not in c for c in startctxs):
583 slowpath = True
583 slowpath = True
584 continue
584 continue
585 elif follow and f not in wctx:
585 elif follow and f not in wctx:
586 # If the file exists, it may be a directory, so let it
586 # If the file exists, it may be a directory, so let it
587 # take the slow path.
587 # take the slow path.
588 if os.path.exists(repo.wjoin(f)):
588 if os.path.exists(repo.wjoin(f)):
589 slowpath = True
589 slowpath = True
590 continue
590 continue
591 else:
591 else:
592 raise error.Abort(_('cannot follow file not in parent '
592 raise error.Abort(_('cannot follow file not in parent '
593 'revision: "%s"') % f)
593 'revision: "%s"') % f)
594 filelog = repo.file(f)
594 filelog = repo.file(f)
595 if not filelog:
595 if not filelog:
596 # A zero count may be a directory or deleted file, so
596 # A zero count may be a directory or deleted file, so
597 # try to find matching entries on the slow path.
597 # try to find matching entries on the slow path.
598 if follow:
598 if follow:
599 raise error.Abort(
599 raise error.Abort(
600 _('cannot follow nonexistent file: "%s"') % f)
600 _('cannot follow nonexistent file: "%s"') % f)
601 slowpath = True
601 slowpath = True
602
602
603 # We decided to fall back to the slowpath because at least one
603 # We decided to fall back to the slowpath because at least one
604 # of the paths was not a file. Check to see if at least one of them
604 # of the paths was not a file. Check to see if at least one of them
605 # existed in history - in that case, we'll continue down the
605 # existed in history - in that case, we'll continue down the
606 # slowpath; otherwise, we can turn off the slowpath
606 # slowpath; otherwise, we can turn off the slowpath
607 if slowpath:
607 if slowpath:
608 for path in match.files():
608 for path in match.files():
609 if path == '.' or path in repo.store:
609 if path == '.' or path in repo.store:
610 break
610 break
611 else:
611 else:
612 slowpath = False
612 slowpath = False
613
613
614 return match, pats, slowpath
614 return match, pats, slowpath
615
615
616 def _fileancestors(repo, revs, match, followfirst):
616 def _fileancestors(repo, revs, match, followfirst):
617 fctxs = []
617 fctxs = []
618 for r in revs:
618 for r in revs:
619 ctx = repo[r]
619 ctx = repo[r]
620 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
620 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
621
621
622 # When displaying a revision with --patch --follow FILE, we have
622 # When displaying a revision with --patch --follow FILE, we have
623 # to know which file of the revision must be diffed. With
623 # to know which file of the revision must be diffed. With
624 # --follow, we want the names of the ancestors of FILE in the
624 # --follow, we want the names of the ancestors of FILE in the
625 # revision, stored in "fcache". "fcache" is populated as a side effect
625 # revision, stored in "fcache". "fcache" is populated as a side effect
626 # of the graph traversal.
626 # of the graph traversal.
627 fcache = {}
627 fcache = {}
628 def filematcher(ctx):
628 def filematcher(ctx):
629 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
629 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
630
630
631 def revgen():
631 def revgen():
632 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
632 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
633 fcache[rev] = [c.path() for c in cs]
633 fcache[rev] = [c.path() for c in cs]
634 yield rev
634 yield rev
635 return smartset.generatorset(revgen(), iterasc=False), filematcher
635 return smartset.generatorset(revgen(), iterasc=False), filematcher
636
636
637 def _makenofollowfilematcher(repo, pats, opts):
637 def _makenofollowfilematcher(repo, pats, opts):
638 '''hook for extensions to override the filematcher for non-follow cases'''
638 '''hook for extensions to override the filematcher for non-follow cases'''
639 return None
639 return None
640
640
641 _opt2logrevset = {
641 _opt2logrevset = {
642 'no_merges': ('not merge()', None),
642 'no_merges': ('not merge()', None),
643 'only_merges': ('merge()', None),
643 'only_merges': ('merge()', None),
644 '_matchfiles': (None, '_matchfiles(%ps)'),
644 '_matchfiles': (None, '_matchfiles(%ps)'),
645 'date': ('date(%s)', None),
645 'date': ('date(%s)', None),
646 'branch': ('branch(%s)', '%lr'),
646 'branch': ('branch(%s)', '%lr'),
647 '_patslog': ('filelog(%s)', '%lr'),
647 '_patslog': ('filelog(%s)', '%lr'),
648 'keyword': ('keyword(%s)', '%lr'),
648 'keyword': ('keyword(%s)', '%lr'),
649 'prune': ('ancestors(%s)', 'not %lr'),
649 'prune': ('ancestors(%s)', 'not %lr'),
650 'user': ('user(%s)', '%lr'),
650 'user': ('user(%s)', '%lr'),
651 }
651 }
652
652
653 def _makerevset(repo, match, pats, slowpath, opts):
653 def _makerevset(repo, match, pats, slowpath, opts):
654 """Return a revset string built from log options and file patterns"""
654 """Return a revset string built from log options and file patterns"""
655 opts = dict(opts)
655 opts = dict(opts)
656 # follow or not follow?
656 # follow or not follow?
657 follow = opts.get('follow') or opts.get('follow_first')
657 follow = opts.get('follow') or opts.get('follow_first')
658
658
659 # branch and only_branch are really aliases and must be handled at
659 # branch and only_branch are really aliases and must be handled at
660 # the same time
660 # the same time
661 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
661 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
662 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
662 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
663
663
664 if slowpath:
664 if slowpath:
665 # See walkchangerevs() slow path.
665 # See walkchangerevs() slow path.
666 #
666 #
667 # pats/include/exclude cannot be represented as separate
667 # pats/include/exclude cannot be represented as separate
668 # revset expressions as their filtering logic applies at file
668 # revset expressions as their filtering logic applies at file
669 # level. For instance "-I a -X b" matches a revision touching
669 # level. For instance "-I a -X b" matches a revision touching
670 # "a" and "b" while "file(a) and not file(b)" does
670 # "a" and "b" while "file(a) and not file(b)" does
671 # not. Besides, filesets are evaluated against the working
671 # not. Besides, filesets are evaluated against the working
672 # directory.
672 # directory.
673 matchargs = ['r:', 'd:relpath']
673 matchargs = ['r:', 'd:relpath']
674 for p in pats:
674 for p in pats:
675 matchargs.append('p:' + p)
675 matchargs.append('p:' + p)
676 for p in opts.get('include', []):
676 for p in opts.get('include', []):
677 matchargs.append('i:' + p)
677 matchargs.append('i:' + p)
678 for p in opts.get('exclude', []):
678 for p in opts.get('exclude', []):
679 matchargs.append('x:' + p)
679 matchargs.append('x:' + p)
680 opts['_matchfiles'] = matchargs
680 opts['_matchfiles'] = matchargs
681 elif not follow:
681 elif not follow:
682 opts['_patslog'] = list(pats)
682 opts['_patslog'] = list(pats)
683
683
684 expr = []
684 expr = []
685 for op, val in sorted(opts.iteritems()):
685 for op, val in sorted(opts.iteritems()):
686 if not val:
686 if not val:
687 continue
687 continue
688 if op not in _opt2logrevset:
688 if op not in _opt2logrevset:
689 continue
689 continue
690 revop, listop = _opt2logrevset[op]
690 revop, listop = _opt2logrevset[op]
691 if revop and '%' not in revop:
691 if revop and '%' not in revop:
692 expr.append(revop)
692 expr.append(revop)
693 elif not listop:
693 elif not listop:
694 expr.append(revsetlang.formatspec(revop, val))
694 expr.append(revsetlang.formatspec(revop, val))
695 else:
695 else:
696 if revop:
696 if revop:
697 val = [revsetlang.formatspec(revop, v) for v in val]
697 val = [revsetlang.formatspec(revop, v) for v in val]
698 expr.append(revsetlang.formatspec(listop, val))
698 expr.append(revsetlang.formatspec(listop, val))
699
699
700 if expr:
700 if expr:
701 expr = '(' + ' and '.join(expr) + ')'
701 expr = '(' + ' and '.join(expr) + ')'
702 else:
702 else:
703 expr = None
703 expr = None
704 return expr
704 return expr
705
705
706 def _initialrevs(repo, opts):
706 def _initialrevs(repo, opts):
707 """Return the initial set of revisions to be filtered or followed"""
707 """Return the initial set of revisions to be filtered or followed"""
708 follow = opts.get('follow') or opts.get('follow_first')
708 follow = opts.get('follow') or opts.get('follow_first')
709 if opts.get('rev'):
709 if opts.get('rev'):
710 revs = scmutil.revrange(repo, opts['rev'])
710 revs = scmutil.revrange(repo, opts['rev'])
711 elif follow and repo.dirstate.p1() == nullid:
711 elif follow and repo.dirstate.p1() == nullid:
712 revs = smartset.baseset()
712 revs = smartset.baseset()
713 elif follow:
713 elif follow:
714 revs = repo.revs('.')
714 revs = repo.revs('.')
715 else:
715 else:
716 revs = smartset.spanset(repo)
716 revs = smartset.spanset(repo)
717 revs.reverse()
717 revs.reverse()
718 return revs
718 return revs
719
719
720 def getrevs(repo, pats, opts):
720 def getrevs(repo, pats, opts):
721 """Return (revs, differ) where revs is a smartset
721 """Return (revs, differ) where revs is a smartset
722
722
723 differ is a changesetdiffer with pre-configured file matcher.
723 differ is a changesetdiffer with pre-configured file matcher.
724 """
724 """
725 follow = opts.get('follow') or opts.get('follow_first')
725 follow = opts.get('follow') or opts.get('follow_first')
726 followfirst = opts.get('follow_first')
726 followfirst = opts.get('follow_first')
727 limit = getlimit(opts)
727 limit = getlimit(opts)
728 revs = _initialrevs(repo, opts)
728 revs = _initialrevs(repo, opts)
729 if not revs:
729 if not revs:
730 return smartset.baseset(), None
730 return smartset.baseset(), None
731 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
731 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
732 filematcher = None
732 filematcher = None
733 if follow:
733 if follow:
734 if slowpath or match.always():
734 if slowpath or match.always():
735 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
735 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
736 else:
736 else:
737 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
737 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
738 revs.reverse()
738 revs.reverse()
739 if filematcher is None:
739 if filematcher is None:
740 filematcher = _makenofollowfilematcher(repo, pats, opts)
740 filematcher = _makenofollowfilematcher(repo, pats, opts)
741 if filematcher is None:
741 if filematcher is None:
742 def filematcher(ctx):
742 def filematcher(ctx):
743 return match
743 return match
744
744
745 expr = _makerevset(repo, match, pats, slowpath, opts)
745 expr = _makerevset(repo, match, pats, slowpath, opts)
746 if opts.get('graph'):
746 if opts.get('graph'):
747 # User-specified revs might be unsorted, but don't sort before
747 # User-specified revs might be unsorted, but don't sort before
748 # _makerevset because it might depend on the order of revs
748 # _makerevset because it might depend on the order of revs
749 if not (revs.isdescending() or revs.istopo()):
749 if repo.ui.configbool('experimental', 'log.topo'):
750 if not revs.istopo():
751 revs = dagop.toposort(revs, repo.changelog.parentrevs)
752 # TODO: try to iterate the set lazily
753 revs = revset.baseset(list(revs))
754 elif not (revs.isdescending() or revs.istopo()):
750 revs.sort(reverse=True)
755 revs.sort(reverse=True)
751 if expr:
756 if expr:
752 matcher = revset.match(None, expr)
757 matcher = revset.match(None, expr)
753 revs = matcher(repo, revs)
758 revs = matcher(repo, revs)
754 if limit is not None:
759 if limit is not None:
755 revs = revs.slice(0, limit)
760 revs = revs.slice(0, limit)
756
761
757 differ = changesetdiffer()
762 differ = changesetdiffer()
758 differ._makefilematcher = filematcher
763 differ._makefilematcher = filematcher
759 return revs, differ
764 return revs, differ
760
765
761 def _parselinerangeopt(repo, opts):
766 def _parselinerangeopt(repo, opts):
762 """Parse --line-range log option and return a list of tuples (filename,
767 """Parse --line-range log option and return a list of tuples (filename,
763 (fromline, toline)).
768 (fromline, toline)).
764 """
769 """
765 linerangebyfname = []
770 linerangebyfname = []
766 for pat in opts.get('line_range', []):
771 for pat in opts.get('line_range', []):
767 try:
772 try:
768 pat, linerange = pat.rsplit(',', 1)
773 pat, linerange = pat.rsplit(',', 1)
769 except ValueError:
774 except ValueError:
770 raise error.Abort(_('malformatted line-range pattern %s') % pat)
775 raise error.Abort(_('malformatted line-range pattern %s') % pat)
771 try:
776 try:
772 fromline, toline = map(int, linerange.split(':'))
777 fromline, toline = map(int, linerange.split(':'))
773 except ValueError:
778 except ValueError:
774 raise error.Abort(_("invalid line range for %s") % pat)
779 raise error.Abort(_("invalid line range for %s") % pat)
775 msg = _("line range pattern '%s' must match exactly one file") % pat
780 msg = _("line range pattern '%s' must match exactly one file") % pat
776 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
781 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
777 linerangebyfname.append(
782 linerangebyfname.append(
778 (fname, util.processlinerange(fromline, toline)))
783 (fname, util.processlinerange(fromline, toline)))
779 return linerangebyfname
784 return linerangebyfname
780
785
781 def getlinerangerevs(repo, userrevs, opts):
786 def getlinerangerevs(repo, userrevs, opts):
782 """Return (revs, differ).
787 """Return (revs, differ).
783
788
784 "revs" are revisions obtained by processing "line-range" log options and
789 "revs" are revisions obtained by processing "line-range" log options and
785 walking block ancestors of each specified file/line-range.
790 walking block ancestors of each specified file/line-range.
786
791
787 "differ" is a changesetdiffer with pre-configured file matcher and hunks
792 "differ" is a changesetdiffer with pre-configured file matcher and hunks
788 filter.
793 filter.
789 """
794 """
790 wctx = repo[None]
795 wctx = repo[None]
791
796
792 # Two-levels map of "rev -> file ctx -> [line range]".
797 # Two-levels map of "rev -> file ctx -> [line range]".
793 linerangesbyrev = {}
798 linerangesbyrev = {}
794 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
799 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
795 if fname not in wctx:
800 if fname not in wctx:
796 raise error.Abort(_('cannot follow file not in parent '
801 raise error.Abort(_('cannot follow file not in parent '
797 'revision: "%s"') % fname)
802 'revision: "%s"') % fname)
798 fctx = wctx.filectx(fname)
803 fctx = wctx.filectx(fname)
799 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
804 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
800 rev = fctx.introrev()
805 rev = fctx.introrev()
801 if rev not in userrevs:
806 if rev not in userrevs:
802 continue
807 continue
803 linerangesbyrev.setdefault(
808 linerangesbyrev.setdefault(
804 rev, {}).setdefault(
809 rev, {}).setdefault(
805 fctx.path(), []).append(linerange)
810 fctx.path(), []).append(linerange)
806
811
807 def nofilterhunksfn(fctx, hunks):
812 def nofilterhunksfn(fctx, hunks):
808 return hunks
813 return hunks
809
814
810 def hunksfilter(ctx):
815 def hunksfilter(ctx):
811 fctxlineranges = linerangesbyrev.get(ctx.rev())
816 fctxlineranges = linerangesbyrev.get(ctx.rev())
812 if fctxlineranges is None:
817 if fctxlineranges is None:
813 return nofilterhunksfn
818 return nofilterhunksfn
814
819
815 def filterfn(fctx, hunks):
820 def filterfn(fctx, hunks):
816 lineranges = fctxlineranges.get(fctx.path())
821 lineranges = fctxlineranges.get(fctx.path())
817 if lineranges is not None:
822 if lineranges is not None:
818 for hr, lines in hunks:
823 for hr, lines in hunks:
819 if hr is None: # binary
824 if hr is None: # binary
820 yield hr, lines
825 yield hr, lines
821 continue
826 continue
822 if any(mdiff.hunkinrange(hr[2:], lr)
827 if any(mdiff.hunkinrange(hr[2:], lr)
823 for lr in lineranges):
828 for lr in lineranges):
824 yield hr, lines
829 yield hr, lines
825 else:
830 else:
826 for hunk in hunks:
831 for hunk in hunks:
827 yield hunk
832 yield hunk
828
833
829 return filterfn
834 return filterfn
830
835
831 def filematcher(ctx):
836 def filematcher(ctx):
832 files = list(linerangesbyrev.get(ctx.rev(), []))
837 files = list(linerangesbyrev.get(ctx.rev(), []))
833 return scmutil.matchfiles(repo, files)
838 return scmutil.matchfiles(repo, files)
834
839
835 revs = sorted(linerangesbyrev, reverse=True)
840 revs = sorted(linerangesbyrev, reverse=True)
836
841
837 differ = changesetdiffer()
842 differ = changesetdiffer()
838 differ._makefilematcher = filematcher
843 differ._makefilematcher = filematcher
839 differ._makehunksfilter = hunksfilter
844 differ._makehunksfilter = hunksfilter
840 return revs, differ
845 return revs, differ
841
846
842 def _graphnodeformatter(ui, displayer):
847 def _graphnodeformatter(ui, displayer):
843 spec = ui.config('ui', 'graphnodetemplate')
848 spec = ui.config('ui', 'graphnodetemplate')
844 if not spec:
849 if not spec:
845 return templatekw.getgraphnode # fast path for "{graphnode}"
850 return templatekw.getgraphnode # fast path for "{graphnode}"
846
851
847 spec = templater.unquotestring(spec)
852 spec = templater.unquotestring(spec)
848 if isinstance(displayer, changesettemplater):
853 if isinstance(displayer, changesettemplater):
849 # reuse cache of slow templates
854 # reuse cache of slow templates
850 tres = displayer._tresources
855 tres = displayer._tresources
851 else:
856 else:
852 tres = formatter.templateresources(ui)
857 tres = formatter.templateresources(ui)
853 templ = formatter.maketemplater(ui, spec, defaults=templatekw.keywords,
858 templ = formatter.maketemplater(ui, spec, defaults=templatekw.keywords,
854 resources=tres)
859 resources=tres)
855 def formatnode(repo, ctx):
860 def formatnode(repo, ctx):
856 props = {'ctx': ctx, 'repo': repo}
861 props = {'ctx': ctx, 'repo': repo}
857 return templ.renderdefault(props)
862 return templ.renderdefault(props)
858 return formatnode
863 return formatnode
859
864
860 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, props=None):
865 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, props=None):
861 props = props or {}
866 props = props or {}
862 formatnode = _graphnodeformatter(ui, displayer)
867 formatnode = _graphnodeformatter(ui, displayer)
863 state = graphmod.asciistate()
868 state = graphmod.asciistate()
864 styles = state['styles']
869 styles = state['styles']
865
870
866 # only set graph styling if HGPLAIN is not set.
871 # only set graph styling if HGPLAIN is not set.
867 if ui.plain('graph'):
872 if ui.plain('graph'):
868 # set all edge styles to |, the default pre-3.8 behaviour
873 # set all edge styles to |, the default pre-3.8 behaviour
869 styles.update(dict.fromkeys(styles, '|'))
874 styles.update(dict.fromkeys(styles, '|'))
870 else:
875 else:
871 edgetypes = {
876 edgetypes = {
872 'parent': graphmod.PARENT,
877 'parent': graphmod.PARENT,
873 'grandparent': graphmod.GRANDPARENT,
878 'grandparent': graphmod.GRANDPARENT,
874 'missing': graphmod.MISSINGPARENT
879 'missing': graphmod.MISSINGPARENT
875 }
880 }
876 for name, key in edgetypes.items():
881 for name, key in edgetypes.items():
877 # experimental config: experimental.graphstyle.*
882 # experimental config: experimental.graphstyle.*
878 styles[key] = ui.config('experimental', 'graphstyle.%s' % name,
883 styles[key] = ui.config('experimental', 'graphstyle.%s' % name,
879 styles[key])
884 styles[key])
880 if not styles[key]:
885 if not styles[key]:
881 styles[key] = None
886 styles[key] = None
882
887
883 # experimental config: experimental.graphshorten
888 # experimental config: experimental.graphshorten
884 state['graphshorten'] = ui.configbool('experimental', 'graphshorten')
889 state['graphshorten'] = ui.configbool('experimental', 'graphshorten')
885
890
886 for rev, type, ctx, parents in dag:
891 for rev, type, ctx, parents in dag:
887 char = formatnode(repo, ctx)
892 char = formatnode(repo, ctx)
888 copies = None
893 copies = None
889 if getrenamed and ctx.rev():
894 if getrenamed and ctx.rev():
890 copies = []
895 copies = []
891 for fn in ctx.files():
896 for fn in ctx.files():
892 rename = getrenamed(fn, ctx.rev())
897 rename = getrenamed(fn, ctx.rev())
893 if rename:
898 if rename:
894 copies.append((fn, rename))
899 copies.append((fn, rename))
895 edges = edgefn(type, char, state, rev, parents)
900 edges = edgefn(type, char, state, rev, parents)
896 firstedge = next(edges)
901 firstedge = next(edges)
897 width = firstedge[2]
902 width = firstedge[2]
898 displayer.show(ctx, copies=copies,
903 displayer.show(ctx, copies=copies,
899 graphwidth=width, **pycompat.strkwargs(props))
904 graphwidth=width, **pycompat.strkwargs(props))
900 lines = displayer.hunk.pop(rev).split('\n')
905 lines = displayer.hunk.pop(rev).split('\n')
901 if not lines[-1]:
906 if not lines[-1]:
902 del lines[-1]
907 del lines[-1]
903 displayer.flush(ctx)
908 displayer.flush(ctx)
904 for type, char, width, coldata in itertools.chain([firstedge], edges):
909 for type, char, width, coldata in itertools.chain([firstedge], edges):
905 graphmod.ascii(ui, state, type, char, lines, coldata)
910 graphmod.ascii(ui, state, type, char, lines, coldata)
906 lines = []
911 lines = []
907 displayer.close()
912 displayer.close()
908
913
909 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
914 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
910 revdag = graphmod.dagwalker(repo, revs)
915 revdag = graphmod.dagwalker(repo, revs)
911 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
916 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
912
917
913 def displayrevs(ui, repo, revs, displayer, getrenamed):
918 def displayrevs(ui, repo, revs, displayer, getrenamed):
914 for rev in revs:
919 for rev in revs:
915 ctx = repo[rev]
920 ctx = repo[rev]
916 copies = None
921 copies = None
917 if getrenamed is not None and rev:
922 if getrenamed is not None and rev:
918 copies = []
923 copies = []
919 for fn in ctx.files():
924 for fn in ctx.files():
920 rename = getrenamed(fn, rev)
925 rename = getrenamed(fn, rev)
921 if rename:
926 if rename:
922 copies.append((fn, rename))
927 copies.append((fn, rename))
923 displayer.show(ctx, copies=copies)
928 displayer.show(ctx, copies=copies)
924 displayer.flush(ctx)
929 displayer.flush(ctx)
925 displayer.close()
930 displayer.close()
926
931
927 def checkunsupportedgraphflags(pats, opts):
932 def checkunsupportedgraphflags(pats, opts):
928 for op in ["newest_first"]:
933 for op in ["newest_first"]:
929 if op in opts and opts[op]:
934 if op in opts and opts[op]:
930 raise error.Abort(_("-G/--graph option is incompatible with --%s")
935 raise error.Abort(_("-G/--graph option is incompatible with --%s")
931 % op.replace("_", "-"))
936 % op.replace("_", "-"))
932
937
933 def graphrevs(repo, nodes, opts):
938 def graphrevs(repo, nodes, opts):
934 limit = getlimit(opts)
939 limit = getlimit(opts)
935 nodes.reverse()
940 nodes.reverse()
936 if limit is not None:
941 if limit is not None:
937 nodes = nodes[:limit]
942 nodes = nodes[:limit]
938 return graphmod.nodes(repo, nodes)
943 return graphmod.nodes(repo, nodes)
@@ -1,14 +1,24
1 == New Features ==
1 == New Features ==
2
2
3 * New config `commands.commit.post-status` shows status after successful
3 * New config `commands.commit.post-status` shows status after successful
4 commit.
4 commit.
5
5
6
7 == New Experimental Features ==
8
9 * New config `experimental.log.topo` makes `hg log -G` use
10 topological sorting. This is especially useful for aliases since it
11 lets the alias accept an `-r` option while still using topological
12 sorting with or without the `-r` (unlike if you use the `sort(...,
13 topo)` revset).
14
15
6 == Bug Fixes ==
16 == Bug Fixes ==
7
17
8
18
9 == Backwards Compatibility Changes ==
19 == Backwards Compatibility Changes ==
10
20
11
21
12 == Internal API Changes ==
22 == Internal API Changes ==
13
23
14 * Matchers are no longer iterable. Use `match.files()` instead.
24 * Matchers are no longer iterable. Use `match.files()` instead.
@@ -1,116 +1,154
1 This test file aims at test topological iteration and the various configuration it can has.
1 This test file aims at test topological iteration and the various configuration it can has.
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [ui]
4 > [ui]
5 > logtemplate={rev}\n
5 > logtemplate={rev}\n
6 > EOF
6 > EOF
7
7
8 On this simple example, all topological branch are displayed in turn until we
8 On this simple example, all topological branch are displayed in turn until we
9 can finally display 0. this implies skipping from 8 to 3 and coming back to 7
9 can finally display 0. this implies skipping from 8 to 3 and coming back to 7
10 later.
10 later.
11
11
12 $ hg init test01
12 $ hg init test01
13 $ cd test01
13 $ cd test01
14 $ hg unbundle $TESTDIR/bundles/remote.hg
14 $ hg unbundle $TESTDIR/bundles/remote.hg
15 adding changesets
15 adding changesets
16 adding manifests
16 adding manifests
17 adding file changes
17 adding file changes
18 added 9 changesets with 7 changes to 4 files (+1 heads)
18 added 9 changesets with 7 changes to 4 files (+1 heads)
19 new changesets bfaf4b5cbf01:916f1afdef90 (9 drafts)
19 new changesets bfaf4b5cbf01:916f1afdef90 (9 drafts)
20 (run 'hg heads' to see heads, 'hg merge' to merge)
20 (run 'hg heads' to see heads, 'hg merge' to merge)
21
21
22 $ hg log -G
22 $ hg log -G
23 o 8
23 o 8
24 |
24 |
25 | o 7
25 | o 7
26 | |
26 | |
27 | o 6
27 | o 6
28 | |
28 | |
29 | o 5
29 | o 5
30 | |
30 | |
31 | o 4
31 | o 4
32 | |
32 | |
33 o | 3
33 o | 3
34 | |
34 | |
35 o | 2
35 o | 2
36 | |
36 | |
37 o | 1
37 o | 1
38 |/
38 |/
39 o 0
39 o 0
40
40
41
41
42 (display all nodes)
42 (display all nodes)
43
43
44 $ hg log -G -r 'sort(all(), topo)'
44 $ hg log -G -r 'sort(all(), topo)'
45 o 8
45 o 8
46 |
46 |
47 o 3
47 o 3
48 |
48 |
49 o 2
49 o 2
50 |
50 |
51 o 1
51 o 1
52 |
52 |
53 | o 7
53 | o 7
54 | |
54 | |
55 | o 6
55 | o 6
56 | |
56 | |
57 | o 5
57 | o 5
58 | |
58 | |
59 | o 4
59 | o 4
60 |/
60 |/
61 o 0
61 o 0
62
62
63
63
64 (display nodes filtered by log options)
64 (display nodes filtered by log options)
65
65
66 $ hg log -G -r 'sort(all(), topo)' -k '.3'
66 $ hg log -G -r 'sort(all(), topo)' -k '.3'
67 o 8
67 o 8
68 |
68 |
69 o 3
69 o 3
70 |
70 |
71 ~
71 ~
72 o 7
72 o 7
73 |
73 |
74 o 6
74 o 6
75 |
75 |
76 ~
76 ~
77
77
78 (revset skipping nodes)
78 (revset skipping nodes)
79
79
80 $ hg log -G --rev 'sort(not (2+6), topo)'
80 $ hg log -G --rev 'sort(not (2+6), topo)'
81 o 8
81 o 8
82 |
82 |
83 o 3
83 o 3
84 :
84 :
85 o 1
85 o 1
86 |
86 |
87 | o 7
87 | o 7
88 | :
88 | :
89 | o 5
89 | o 5
90 | |
90 | |
91 | o 4
91 | o 4
92 |/
92 |/
93 o 0
93 o 0
94
94
95
95
96 (begin) from the other branch
96 (begin) from the other branch
97
97
98 $ hg log -G -r 'sort(all(), topo, topo.firstbranch=5)'
98 $ hg log -G -r 'sort(all(), topo, topo.firstbranch=5)'
99 o 7
99 o 7
100 |
100 |
101 o 6
101 o 6
102 |
102 |
103 o 5
103 o 5
104 |
104 |
105 o 4
105 o 4
106 |
106 |
107 | o 8
107 | o 8
108 | |
108 | |
109 | o 3
109 | o 3
110 | |
110 | |
111 | o 2
111 | o 2
112 | |
112 | |
113 | o 1
113 | o 1
114 |/
114 |/
115 o 0
115 o 0
116
116
117
118 Topological sort can be turned on via config
119
120 $ cat >> $HGRCPATH << EOF
121 > [experimental]
122 > log.topo=true
123 > EOF
124
125 $ hg log -G
126 o 8
127 |
128 o 3
129 |
130 o 2
131 |
132 o 1
133 |
134 | o 7
135 | |
136 | o 6
137 | |
138 | o 5
139 | |
140 | o 4
141 |/
142 o 0
143
144 Does not affect non-graph log
145 $ hg log -T '{rev}\n'
146 8
147 7
148 6
149 5
150 4
151 3
152 2
153 1
154 0
General Comments 0
You need to be logged in to leave comments. Login now