##// END OF EJS Templates
configitems: adds a developer warning when accessing undeclared configuration...
Boris Feld -
r34859:85a2db47 default
parent child Browse files
Show More
@@ -1,1103 +1,1106
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 configtable.items():
20 for section, items in 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 if key in self:
70 if key in self:
71 return self[key]
71 return self[key]
72
72
73 # search for a matching generic item
73 # search for a matching generic item
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 for item in generics:
75 for item in generics:
76 if item._re.match(key):
76 if item._re.match(key):
77 return item
77 return item
78
78
79 # fallback to dict get
79 # fallback to dict get
80 return super(itemregister, self).get(key)
80 return super(itemregister, self).get(key)
81
81
82 coreitems = {}
82 coreitems = {}
83
83
84 def _register(configtable, *args, **kwargs):
84 def _register(configtable, *args, **kwargs):
85 item = configitem(*args, **kwargs)
85 item = configitem(*args, **kwargs)
86 section = configtable.setdefault(item.section, itemregister())
86 section = configtable.setdefault(item.section, itemregister())
87 if item.name in section:
87 if item.name in section:
88 msg = "duplicated config item registration for '%s.%s'"
88 msg = "duplicated config item registration for '%s.%s'"
89 raise error.ProgrammingError(msg % (item.section, item.name))
89 raise error.ProgrammingError(msg % (item.section, item.name))
90 section[item.name] = item
90 section[item.name] = item
91
91
92 # special value for case where the default is derived from other values
92 # special value for case where the default is derived from other values
93 dynamicdefault = object()
93 dynamicdefault = object()
94
94
95 # Registering actual config items
95 # Registering actual config items
96
96
97 def getitemregister(configtable):
97 def getitemregister(configtable):
98 return functools.partial(_register, configtable)
98 return functools.partial(_register, configtable)
99
99
100 coreconfigitem = getitemregister(coreitems)
100 coreconfigitem = getitemregister(coreitems)
101
101
102 coreconfigitem('alias', '.*',
102 coreconfigitem('alias', '.*',
103 default=None,
103 default=None,
104 generic=True,
104 generic=True,
105 )
105 )
106 coreconfigitem('annotate', 'nodates',
106 coreconfigitem('annotate', 'nodates',
107 default=False,
107 default=False,
108 )
108 )
109 coreconfigitem('annotate', 'showfunc',
109 coreconfigitem('annotate', 'showfunc',
110 default=False,
110 default=False,
111 )
111 )
112 coreconfigitem('annotate', 'unified',
112 coreconfigitem('annotate', 'unified',
113 default=None,
113 default=None,
114 )
114 )
115 coreconfigitem('annotate', 'git',
115 coreconfigitem('annotate', 'git',
116 default=False,
116 default=False,
117 )
117 )
118 coreconfigitem('annotate', 'ignorews',
118 coreconfigitem('annotate', 'ignorews',
119 default=False,
119 default=False,
120 )
120 )
121 coreconfigitem('annotate', 'ignorewsamount',
121 coreconfigitem('annotate', 'ignorewsamount',
122 default=False,
122 default=False,
123 )
123 )
124 coreconfigitem('annotate', 'ignoreblanklines',
124 coreconfigitem('annotate', 'ignoreblanklines',
125 default=False,
125 default=False,
126 )
126 )
127 coreconfigitem('annotate', 'ignorewseol',
127 coreconfigitem('annotate', 'ignorewseol',
128 default=False,
128 default=False,
129 )
129 )
130 coreconfigitem('annotate', 'nobinary',
130 coreconfigitem('annotate', 'nobinary',
131 default=False,
131 default=False,
132 )
132 )
133 coreconfigitem('annotate', 'noprefix',
133 coreconfigitem('annotate', 'noprefix',
134 default=False,
134 default=False,
135 )
135 )
136 coreconfigitem('auth', 'cookiefile',
136 coreconfigitem('auth', 'cookiefile',
137 default=None,
137 default=None,
138 )
138 )
139 # bookmarks.pushing: internal hack for discovery
139 # bookmarks.pushing: internal hack for discovery
140 coreconfigitem('bookmarks', 'pushing',
140 coreconfigitem('bookmarks', 'pushing',
141 default=list,
141 default=list,
142 )
142 )
143 # bundle.mainreporoot: internal hack for bundlerepo
143 # bundle.mainreporoot: internal hack for bundlerepo
144 coreconfigitem('bundle', 'mainreporoot',
144 coreconfigitem('bundle', 'mainreporoot',
145 default='',
145 default='',
146 )
146 )
147 # bundle.reorder: experimental config
147 # bundle.reorder: experimental config
148 coreconfigitem('bundle', 'reorder',
148 coreconfigitem('bundle', 'reorder',
149 default='auto',
149 default='auto',
150 )
150 )
151 coreconfigitem('censor', 'policy',
151 coreconfigitem('censor', 'policy',
152 default='abort',
152 default='abort',
153 )
153 )
154 coreconfigitem('chgserver', 'idletimeout',
154 coreconfigitem('chgserver', 'idletimeout',
155 default=3600,
155 default=3600,
156 )
156 )
157 coreconfigitem('chgserver', 'skiphash',
157 coreconfigitem('chgserver', 'skiphash',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem('cmdserver', 'log',
160 coreconfigitem('cmdserver', 'log',
161 default=None,
161 default=None,
162 )
162 )
163 coreconfigitem('color', '.*',
163 coreconfigitem('color', '.*',
164 default=None,
164 default=None,
165 generic=True,
165 generic=True,
166 )
166 )
167 coreconfigitem('color', 'mode',
167 coreconfigitem('color', 'mode',
168 default='auto',
168 default='auto',
169 )
169 )
170 coreconfigitem('color', 'pagermode',
170 coreconfigitem('color', 'pagermode',
171 default=dynamicdefault,
171 default=dynamicdefault,
172 )
172 )
173 coreconfigitem('commands', 'status.relative',
173 coreconfigitem('commands', 'status.relative',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('commands', 'status.skipstates',
176 coreconfigitem('commands', 'status.skipstates',
177 default=[],
177 default=[],
178 )
178 )
179 coreconfigitem('commands', 'status.verbose',
179 coreconfigitem('commands', 'status.verbose',
180 default=False,
180 default=False,
181 )
181 )
182 coreconfigitem('commands', 'update.check',
182 coreconfigitem('commands', 'update.check',
183 default=None,
183 default=None,
184 # Deprecated, remove after 4.4 release
184 # Deprecated, remove after 4.4 release
185 alias=[('experimental', 'updatecheck')]
185 alias=[('experimental', 'updatecheck')]
186 )
186 )
187 coreconfigitem('commands', 'update.requiredest',
187 coreconfigitem('commands', 'update.requiredest',
188 default=False,
188 default=False,
189 )
189 )
190 coreconfigitem('committemplate', '.*',
190 coreconfigitem('committemplate', '.*',
191 default=None,
191 default=None,
192 generic=True,
192 generic=True,
193 )
193 )
194 coreconfigitem('debug', 'dirstate.delaywrite',
194 coreconfigitem('debug', 'dirstate.delaywrite',
195 default=0,
195 default=0,
196 )
196 )
197 coreconfigitem('defaults', '.*',
197 coreconfigitem('defaults', '.*',
198 default=None,
198 default=None,
199 generic=True,
199 generic=True,
200 )
200 )
201 coreconfigitem('devel', 'all-warnings',
201 coreconfigitem('devel', 'all-warnings',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('devel', 'bundle2.debug',
204 coreconfigitem('devel', 'bundle2.debug',
205 default=False,
205 default=False,
206 )
206 )
207 coreconfigitem('devel', 'cache-vfs',
207 coreconfigitem('devel', 'cache-vfs',
208 default=None,
208 default=None,
209 )
209 )
210 coreconfigitem('devel', 'check-locks',
210 coreconfigitem('devel', 'check-locks',
211 default=False,
211 default=False,
212 )
212 )
213 coreconfigitem('devel', 'check-relroot',
213 coreconfigitem('devel', 'check-relroot',
214 default=False,
214 default=False,
215 )
215 )
216 coreconfigitem('devel', 'default-date',
216 coreconfigitem('devel', 'default-date',
217 default=None,
217 default=None,
218 )
218 )
219 coreconfigitem('devel', 'deprec-warn',
219 coreconfigitem('devel', 'deprec-warn',
220 default=False,
220 default=False,
221 )
221 )
222 coreconfigitem('devel', 'disableloaddefaultcerts',
222 coreconfigitem('devel', 'disableloaddefaultcerts',
223 default=False,
223 default=False,
224 )
224 )
225 coreconfigitem('devel', 'warn-empty-changegroup',
225 coreconfigitem('devel', 'warn-empty-changegroup',
226 default=False,
226 default=False,
227 )
227 )
228 coreconfigitem('devel', 'legacy.exchange',
228 coreconfigitem('devel', 'legacy.exchange',
229 default=list,
229 default=list,
230 )
230 )
231 coreconfigitem('devel', 'servercafile',
231 coreconfigitem('devel', 'servercafile',
232 default='',
232 default='',
233 )
233 )
234 coreconfigitem('devel', 'serverexactprotocol',
234 coreconfigitem('devel', 'serverexactprotocol',
235 default='',
235 default='',
236 )
236 )
237 coreconfigitem('devel', 'serverrequirecert',
237 coreconfigitem('devel', 'serverrequirecert',
238 default=False,
238 default=False,
239 )
239 )
240 coreconfigitem('devel', 'strip-obsmarkers',
240 coreconfigitem('devel', 'strip-obsmarkers',
241 default=True,
241 default=True,
242 )
242 )
243 coreconfigitem('devel', 'warn-config',
243 coreconfigitem('devel', 'warn-config',
244 default=None,
244 default=None,
245 )
245 )
246 coreconfigitem('devel', 'warn-config-default',
246 coreconfigitem('devel', 'warn-config-default',
247 default=None,
247 default=None,
248 )
248 )
249 coreconfigitem('devel', 'user.obsmarker',
249 coreconfigitem('devel', 'user.obsmarker',
250 default=None,
250 default=None,
251 )
251 )
252 coreconfigitem('devel', 'warn-config-unknown',
253 default=None,
254 )
252 coreconfigitem('diff', 'nodates',
255 coreconfigitem('diff', 'nodates',
253 default=False,
256 default=False,
254 )
257 )
255 coreconfigitem('diff', 'showfunc',
258 coreconfigitem('diff', 'showfunc',
256 default=False,
259 default=False,
257 )
260 )
258 coreconfigitem('diff', 'unified',
261 coreconfigitem('diff', 'unified',
259 default=None,
262 default=None,
260 )
263 )
261 coreconfigitem('diff', 'git',
264 coreconfigitem('diff', 'git',
262 default=False,
265 default=False,
263 )
266 )
264 coreconfigitem('diff', 'ignorews',
267 coreconfigitem('diff', 'ignorews',
265 default=False,
268 default=False,
266 )
269 )
267 coreconfigitem('diff', 'ignorewsamount',
270 coreconfigitem('diff', 'ignorewsamount',
268 default=False,
271 default=False,
269 )
272 )
270 coreconfigitem('diff', 'ignoreblanklines',
273 coreconfigitem('diff', 'ignoreblanklines',
271 default=False,
274 default=False,
272 )
275 )
273 coreconfigitem('diff', 'ignorewseol',
276 coreconfigitem('diff', 'ignorewseol',
274 default=False,
277 default=False,
275 )
278 )
276 coreconfigitem('diff', 'nobinary',
279 coreconfigitem('diff', 'nobinary',
277 default=False,
280 default=False,
278 )
281 )
279 coreconfigitem('diff', 'noprefix',
282 coreconfigitem('diff', 'noprefix',
280 default=False,
283 default=False,
281 )
284 )
282 coreconfigitem('email', 'bcc',
285 coreconfigitem('email', 'bcc',
283 default=None,
286 default=None,
284 )
287 )
285 coreconfigitem('email', 'cc',
288 coreconfigitem('email', 'cc',
286 default=None,
289 default=None,
287 )
290 )
288 coreconfigitem('email', 'charsets',
291 coreconfigitem('email', 'charsets',
289 default=list,
292 default=list,
290 )
293 )
291 coreconfigitem('email', 'from',
294 coreconfigitem('email', 'from',
292 default=None,
295 default=None,
293 )
296 )
294 coreconfigitem('email', 'method',
297 coreconfigitem('email', 'method',
295 default='smtp',
298 default='smtp',
296 )
299 )
297 coreconfigitem('email', 'reply-to',
300 coreconfigitem('email', 'reply-to',
298 default=None,
301 default=None,
299 )
302 )
300 coreconfigitem('experimental', 'allowdivergence',
303 coreconfigitem('experimental', 'allowdivergence',
301 default=False,
304 default=False,
302 )
305 )
303 coreconfigitem('experimental', 'archivemetatemplate',
306 coreconfigitem('experimental', 'archivemetatemplate',
304 default=dynamicdefault,
307 default=dynamicdefault,
305 )
308 )
306 coreconfigitem('experimental', 'bundle-phases',
309 coreconfigitem('experimental', 'bundle-phases',
307 default=False,
310 default=False,
308 )
311 )
309 coreconfigitem('experimental', 'bundle2-advertise',
312 coreconfigitem('experimental', 'bundle2-advertise',
310 default=True,
313 default=True,
311 )
314 )
312 coreconfigitem('experimental', 'bundle2-output-capture',
315 coreconfigitem('experimental', 'bundle2-output-capture',
313 default=False,
316 default=False,
314 )
317 )
315 coreconfigitem('experimental', 'bundle2.pushback',
318 coreconfigitem('experimental', 'bundle2.pushback',
316 default=False,
319 default=False,
317 )
320 )
318 coreconfigitem('experimental', 'bundle2lazylocking',
321 coreconfigitem('experimental', 'bundle2lazylocking',
319 default=False,
322 default=False,
320 )
323 )
321 coreconfigitem('experimental', 'bundlecomplevel',
324 coreconfigitem('experimental', 'bundlecomplevel',
322 default=None,
325 default=None,
323 )
326 )
324 coreconfigitem('experimental', 'changegroup3',
327 coreconfigitem('experimental', 'changegroup3',
325 default=False,
328 default=False,
326 )
329 )
327 coreconfigitem('experimental', 'clientcompressionengines',
330 coreconfigitem('experimental', 'clientcompressionengines',
328 default=list,
331 default=list,
329 )
332 )
330 coreconfigitem('experimental', 'copytrace',
333 coreconfigitem('experimental', 'copytrace',
331 default='on',
334 default='on',
332 )
335 )
333 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
336 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
334 default=100,
337 default=100,
335 )
338 )
336 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
339 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
337 default=100,
340 default=100,
338 )
341 )
339 coreconfigitem('experimental', 'crecordtest',
342 coreconfigitem('experimental', 'crecordtest',
340 default=None,
343 default=None,
341 )
344 )
342 coreconfigitem('experimental', 'editortmpinhg',
345 coreconfigitem('experimental', 'editortmpinhg',
343 default=False,
346 default=False,
344 )
347 )
345 coreconfigitem('experimental', 'maxdeltachainspan',
348 coreconfigitem('experimental', 'maxdeltachainspan',
346 default=-1,
349 default=-1,
347 )
350 )
348 coreconfigitem('experimental', 'mmapindexthreshold',
351 coreconfigitem('experimental', 'mmapindexthreshold',
349 default=None,
352 default=None,
350 )
353 )
351 coreconfigitem('experimental', 'nonnormalparanoidcheck',
354 coreconfigitem('experimental', 'nonnormalparanoidcheck',
352 default=False,
355 default=False,
353 )
356 )
354 coreconfigitem('experimental', 'effect-flags',
357 coreconfigitem('experimental', 'effect-flags',
355 default=False,
358 default=False,
356 )
359 )
357 coreconfigitem('experimental', 'stabilization',
360 coreconfigitem('experimental', 'stabilization',
358 default=list,
361 default=list,
359 alias=[('experimental', 'evolution')],
362 alias=[('experimental', 'evolution')],
360 )
363 )
361 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
364 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
362 default=False,
365 default=False,
363 alias=[('experimental', 'evolution.bundle-obsmarker')],
366 alias=[('experimental', 'evolution.bundle-obsmarker')],
364 )
367 )
365 coreconfigitem('experimental', 'stabilization.track-operation',
368 coreconfigitem('experimental', 'stabilization.track-operation',
366 default=True,
369 default=True,
367 alias=[('experimental', 'evolution.track-operation')]
370 alias=[('experimental', 'evolution.track-operation')]
368 )
371 )
369 coreconfigitem('experimental', 'exportableenviron',
372 coreconfigitem('experimental', 'exportableenviron',
370 default=list,
373 default=list,
371 )
374 )
372 coreconfigitem('experimental', 'extendedheader.index',
375 coreconfigitem('experimental', 'extendedheader.index',
373 default=None,
376 default=None,
374 )
377 )
375 coreconfigitem('experimental', 'extendedheader.similarity',
378 coreconfigitem('experimental', 'extendedheader.similarity',
376 default=False,
379 default=False,
377 )
380 )
378 coreconfigitem('experimental', 'format.compression',
381 coreconfigitem('experimental', 'format.compression',
379 default='zlib',
382 default='zlib',
380 )
383 )
381 coreconfigitem('experimental', 'graphshorten',
384 coreconfigitem('experimental', 'graphshorten',
382 default=False,
385 default=False,
383 )
386 )
384 coreconfigitem('experimental', 'graphstyle.parent',
387 coreconfigitem('experimental', 'graphstyle.parent',
385 default=dynamicdefault,
388 default=dynamicdefault,
386 )
389 )
387 coreconfigitem('experimental', 'graphstyle.missing',
390 coreconfigitem('experimental', 'graphstyle.missing',
388 default=dynamicdefault,
391 default=dynamicdefault,
389 )
392 )
390 coreconfigitem('experimental', 'graphstyle.grandparent',
393 coreconfigitem('experimental', 'graphstyle.grandparent',
391 default=dynamicdefault,
394 default=dynamicdefault,
392 )
395 )
393 coreconfigitem('experimental', 'hook-track-tags',
396 coreconfigitem('experimental', 'hook-track-tags',
394 default=False,
397 default=False,
395 )
398 )
396 coreconfigitem('experimental', 'httppostargs',
399 coreconfigitem('experimental', 'httppostargs',
397 default=False,
400 default=False,
398 )
401 )
399 coreconfigitem('experimental', 'manifestv2',
402 coreconfigitem('experimental', 'manifestv2',
400 default=False,
403 default=False,
401 )
404 )
402 coreconfigitem('experimental', 'mergedriver',
405 coreconfigitem('experimental', 'mergedriver',
403 default=None,
406 default=None,
404 )
407 )
405 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
408 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
406 default=False,
409 default=False,
407 )
410 )
408 coreconfigitem('experimental', 'rebase.multidest',
411 coreconfigitem('experimental', 'rebase.multidest',
409 default=False,
412 default=False,
410 )
413 )
411 coreconfigitem('experimental', 'revertalternateinteractivemode',
414 coreconfigitem('experimental', 'revertalternateinteractivemode',
412 default=True,
415 default=True,
413 )
416 )
414 coreconfigitem('experimental', 'revlogv2',
417 coreconfigitem('experimental', 'revlogv2',
415 default=None,
418 default=None,
416 )
419 )
417 coreconfigitem('experimental', 'spacemovesdown',
420 coreconfigitem('experimental', 'spacemovesdown',
418 default=False,
421 default=False,
419 )
422 )
420 coreconfigitem('experimental', 'sparse-read',
423 coreconfigitem('experimental', 'sparse-read',
421 default=False,
424 default=False,
422 )
425 )
423 coreconfigitem('experimental', 'sparse-read.density-threshold',
426 coreconfigitem('experimental', 'sparse-read.density-threshold',
424 default=0.25,
427 default=0.25,
425 )
428 )
426 coreconfigitem('experimental', 'sparse-read.min-block-size',
429 coreconfigitem('experimental', 'sparse-read.min-block-size',
427 default='256K',
430 default='256K',
428 )
431 )
429 coreconfigitem('experimental', 'treemanifest',
432 coreconfigitem('experimental', 'treemanifest',
430 default=False,
433 default=False,
431 )
434 )
432 coreconfigitem('extensions', '.*',
435 coreconfigitem('extensions', '.*',
433 default=None,
436 default=None,
434 generic=True,
437 generic=True,
435 )
438 )
436 coreconfigitem('extdata', '.*',
439 coreconfigitem('extdata', '.*',
437 default=None,
440 default=None,
438 generic=True,
441 generic=True,
439 )
442 )
440 coreconfigitem('format', 'aggressivemergedeltas',
443 coreconfigitem('format', 'aggressivemergedeltas',
441 default=False,
444 default=False,
442 )
445 )
443 coreconfigitem('format', 'chunkcachesize',
446 coreconfigitem('format', 'chunkcachesize',
444 default=None,
447 default=None,
445 )
448 )
446 coreconfigitem('format', 'dotencode',
449 coreconfigitem('format', 'dotencode',
447 default=True,
450 default=True,
448 )
451 )
449 coreconfigitem('format', 'generaldelta',
452 coreconfigitem('format', 'generaldelta',
450 default=False,
453 default=False,
451 )
454 )
452 coreconfigitem('format', 'manifestcachesize',
455 coreconfigitem('format', 'manifestcachesize',
453 default=None,
456 default=None,
454 )
457 )
455 coreconfigitem('format', 'maxchainlen',
458 coreconfigitem('format', 'maxchainlen',
456 default=None,
459 default=None,
457 )
460 )
458 coreconfigitem('format', 'obsstore-version',
461 coreconfigitem('format', 'obsstore-version',
459 default=None,
462 default=None,
460 )
463 )
461 coreconfigitem('format', 'usefncache',
464 coreconfigitem('format', 'usefncache',
462 default=True,
465 default=True,
463 )
466 )
464 coreconfigitem('format', 'usegeneraldelta',
467 coreconfigitem('format', 'usegeneraldelta',
465 default=True,
468 default=True,
466 )
469 )
467 coreconfigitem('format', 'usestore',
470 coreconfigitem('format', 'usestore',
468 default=True,
471 default=True,
469 )
472 )
470 coreconfigitem('hooks', '.*',
473 coreconfigitem('hooks', '.*',
471 default=dynamicdefault,
474 default=dynamicdefault,
472 generic=True,
475 generic=True,
473 )
476 )
474 coreconfigitem('hgweb-paths', '.*',
477 coreconfigitem('hgweb-paths', '.*',
475 default=list,
478 default=list,
476 generic=True,
479 generic=True,
477 )
480 )
478 coreconfigitem('hostfingerprints', '.*',
481 coreconfigitem('hostfingerprints', '.*',
479 default=list,
482 default=list,
480 generic=True,
483 generic=True,
481 )
484 )
482 coreconfigitem('hostsecurity', 'ciphers',
485 coreconfigitem('hostsecurity', 'ciphers',
483 default=None,
486 default=None,
484 )
487 )
485 coreconfigitem('hostsecurity', 'disabletls10warning',
488 coreconfigitem('hostsecurity', 'disabletls10warning',
486 default=False,
489 default=False,
487 )
490 )
488 coreconfigitem('hostsecurity', 'minimumprotocol',
491 coreconfigitem('hostsecurity', 'minimumprotocol',
489 default=dynamicdefault,
492 default=dynamicdefault,
490 )
493 )
491 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
494 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
492 default=dynamicdefault,
495 default=dynamicdefault,
493 generic=True,
496 generic=True,
494 )
497 )
495 coreconfigitem('hostsecurity', '.*:ciphers$',
498 coreconfigitem('hostsecurity', '.*:ciphers$',
496 default=dynamicdefault,
499 default=dynamicdefault,
497 generic=True,
500 generic=True,
498 )
501 )
499 coreconfigitem('hostsecurity', '.*:fingerprints$',
502 coreconfigitem('hostsecurity', '.*:fingerprints$',
500 default=list,
503 default=list,
501 generic=True,
504 generic=True,
502 )
505 )
503 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
506 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
504 default=None,
507 default=None,
505 generic=True,
508 generic=True,
506 )
509 )
507
510
508 coreconfigitem('http_proxy', 'always',
511 coreconfigitem('http_proxy', 'always',
509 default=False,
512 default=False,
510 )
513 )
511 coreconfigitem('http_proxy', 'host',
514 coreconfigitem('http_proxy', 'host',
512 default=None,
515 default=None,
513 )
516 )
514 coreconfigitem('http_proxy', 'no',
517 coreconfigitem('http_proxy', 'no',
515 default=list,
518 default=list,
516 )
519 )
517 coreconfigitem('http_proxy', 'passwd',
520 coreconfigitem('http_proxy', 'passwd',
518 default=None,
521 default=None,
519 )
522 )
520 coreconfigitem('http_proxy', 'user',
523 coreconfigitem('http_proxy', 'user',
521 default=None,
524 default=None,
522 )
525 )
523 coreconfigitem('logtoprocess', 'commandexception',
526 coreconfigitem('logtoprocess', 'commandexception',
524 default=None,
527 default=None,
525 )
528 )
526 coreconfigitem('logtoprocess', 'commandfinish',
529 coreconfigitem('logtoprocess', 'commandfinish',
527 default=None,
530 default=None,
528 )
531 )
529 coreconfigitem('logtoprocess', 'command',
532 coreconfigitem('logtoprocess', 'command',
530 default=None,
533 default=None,
531 )
534 )
532 coreconfigitem('logtoprocess', 'develwarn',
535 coreconfigitem('logtoprocess', 'develwarn',
533 default=None,
536 default=None,
534 )
537 )
535 coreconfigitem('logtoprocess', 'uiblocked',
538 coreconfigitem('logtoprocess', 'uiblocked',
536 default=None,
539 default=None,
537 )
540 )
538 coreconfigitem('merge', 'checkunknown',
541 coreconfigitem('merge', 'checkunknown',
539 default='abort',
542 default='abort',
540 )
543 )
541 coreconfigitem('merge', 'checkignored',
544 coreconfigitem('merge', 'checkignored',
542 default='abort',
545 default='abort',
543 )
546 )
544 coreconfigitem('merge', 'followcopies',
547 coreconfigitem('merge', 'followcopies',
545 default=True,
548 default=True,
546 )
549 )
547 coreconfigitem('merge', 'on-failure',
550 coreconfigitem('merge', 'on-failure',
548 default='continue',
551 default='continue',
549 )
552 )
550 coreconfigitem('merge', 'preferancestor',
553 coreconfigitem('merge', 'preferancestor',
551 default=lambda: ['*'],
554 default=lambda: ['*'],
552 )
555 )
553 coreconfigitem('merge-tools', '.*',
556 coreconfigitem('merge-tools', '.*',
554 default=None,
557 default=None,
555 generic=True,
558 generic=True,
556 )
559 )
557 coreconfigitem('merge-tools', r'.*\.args$',
560 coreconfigitem('merge-tools', r'.*\.args$',
558 default="$local $base $other",
561 default="$local $base $other",
559 generic=True,
562 generic=True,
560 priority=-1,
563 priority=-1,
561 )
564 )
562 coreconfigitem('merge-tools', r'.*\.binary$',
565 coreconfigitem('merge-tools', r'.*\.binary$',
563 default=False,
566 default=False,
564 generic=True,
567 generic=True,
565 priority=-1,
568 priority=-1,
566 )
569 )
567 coreconfigitem('merge-tools', r'.*\.check$',
570 coreconfigitem('merge-tools', r'.*\.check$',
568 default=list,
571 default=list,
569 generic=True,
572 generic=True,
570 priority=-1,
573 priority=-1,
571 )
574 )
572 coreconfigitem('merge-tools', r'.*\.checkchanged$',
575 coreconfigitem('merge-tools', r'.*\.checkchanged$',
573 default=False,
576 default=False,
574 generic=True,
577 generic=True,
575 priority=-1,
578 priority=-1,
576 )
579 )
577 coreconfigitem('merge-tools', r'.*\.executable$',
580 coreconfigitem('merge-tools', r'.*\.executable$',
578 default=dynamicdefault,
581 default=dynamicdefault,
579 generic=True,
582 generic=True,
580 priority=-1,
583 priority=-1,
581 )
584 )
582 coreconfigitem('merge-tools', r'.*\.fixeol$',
585 coreconfigitem('merge-tools', r'.*\.fixeol$',
583 default=False,
586 default=False,
584 generic=True,
587 generic=True,
585 priority=-1,
588 priority=-1,
586 )
589 )
587 coreconfigitem('merge-tools', r'.*\.gui$',
590 coreconfigitem('merge-tools', r'.*\.gui$',
588 default=False,
591 default=False,
589 generic=True,
592 generic=True,
590 priority=-1,
593 priority=-1,
591 )
594 )
592 coreconfigitem('merge-tools', r'.*\.priority$',
595 coreconfigitem('merge-tools', r'.*\.priority$',
593 default=0,
596 default=0,
594 generic=True,
597 generic=True,
595 priority=-1,
598 priority=-1,
596 )
599 )
597 coreconfigitem('merge-tools', r'.*\.premerge$',
600 coreconfigitem('merge-tools', r'.*\.premerge$',
598 default=dynamicdefault,
601 default=dynamicdefault,
599 generic=True,
602 generic=True,
600 priority=-1,
603 priority=-1,
601 )
604 )
602 coreconfigitem('merge-tools', r'.*\.symlink$',
605 coreconfigitem('merge-tools', r'.*\.symlink$',
603 default=False,
606 default=False,
604 generic=True,
607 generic=True,
605 priority=-1,
608 priority=-1,
606 )
609 )
607 coreconfigitem('pager', 'attend-.*',
610 coreconfigitem('pager', 'attend-.*',
608 default=dynamicdefault,
611 default=dynamicdefault,
609 generic=True,
612 generic=True,
610 )
613 )
611 coreconfigitem('pager', 'ignore',
614 coreconfigitem('pager', 'ignore',
612 default=list,
615 default=list,
613 )
616 )
614 coreconfigitem('pager', 'pager',
617 coreconfigitem('pager', 'pager',
615 default=dynamicdefault,
618 default=dynamicdefault,
616 )
619 )
617 coreconfigitem('patch', 'eol',
620 coreconfigitem('patch', 'eol',
618 default='strict',
621 default='strict',
619 )
622 )
620 coreconfigitem('patch', 'fuzz',
623 coreconfigitem('patch', 'fuzz',
621 default=2,
624 default=2,
622 )
625 )
623 coreconfigitem('paths', 'default',
626 coreconfigitem('paths', 'default',
624 default=None,
627 default=None,
625 )
628 )
626 coreconfigitem('paths', 'default-push',
629 coreconfigitem('paths', 'default-push',
627 default=None,
630 default=None,
628 )
631 )
629 coreconfigitem('paths', '.*',
632 coreconfigitem('paths', '.*',
630 default=None,
633 default=None,
631 generic=True,
634 generic=True,
632 )
635 )
633 coreconfigitem('phases', 'checksubrepos',
636 coreconfigitem('phases', 'checksubrepos',
634 default='follow',
637 default='follow',
635 )
638 )
636 coreconfigitem('phases', 'new-commit',
639 coreconfigitem('phases', 'new-commit',
637 default='draft',
640 default='draft',
638 )
641 )
639 coreconfigitem('phases', 'publish',
642 coreconfigitem('phases', 'publish',
640 default=True,
643 default=True,
641 )
644 )
642 coreconfigitem('profiling', 'enabled',
645 coreconfigitem('profiling', 'enabled',
643 default=False,
646 default=False,
644 )
647 )
645 coreconfigitem('profiling', 'format',
648 coreconfigitem('profiling', 'format',
646 default='text',
649 default='text',
647 )
650 )
648 coreconfigitem('profiling', 'freq',
651 coreconfigitem('profiling', 'freq',
649 default=1000,
652 default=1000,
650 )
653 )
651 coreconfigitem('profiling', 'limit',
654 coreconfigitem('profiling', 'limit',
652 default=30,
655 default=30,
653 )
656 )
654 coreconfigitem('profiling', 'nested',
657 coreconfigitem('profiling', 'nested',
655 default=0,
658 default=0,
656 )
659 )
657 coreconfigitem('profiling', 'output',
660 coreconfigitem('profiling', 'output',
658 default=None,
661 default=None,
659 )
662 )
660 coreconfigitem('profiling', 'showmax',
663 coreconfigitem('profiling', 'showmax',
661 default=0.999,
664 default=0.999,
662 )
665 )
663 coreconfigitem('profiling', 'showmin',
666 coreconfigitem('profiling', 'showmin',
664 default=dynamicdefault,
667 default=dynamicdefault,
665 )
668 )
666 coreconfigitem('profiling', 'sort',
669 coreconfigitem('profiling', 'sort',
667 default='inlinetime',
670 default='inlinetime',
668 )
671 )
669 coreconfigitem('profiling', 'statformat',
672 coreconfigitem('profiling', 'statformat',
670 default='hotpath',
673 default='hotpath',
671 )
674 )
672 coreconfigitem('profiling', 'type',
675 coreconfigitem('profiling', 'type',
673 default='stat',
676 default='stat',
674 )
677 )
675 coreconfigitem('progress', 'assume-tty',
678 coreconfigitem('progress', 'assume-tty',
676 default=False,
679 default=False,
677 )
680 )
678 coreconfigitem('progress', 'changedelay',
681 coreconfigitem('progress', 'changedelay',
679 default=1,
682 default=1,
680 )
683 )
681 coreconfigitem('progress', 'clear-complete',
684 coreconfigitem('progress', 'clear-complete',
682 default=True,
685 default=True,
683 )
686 )
684 coreconfigitem('progress', 'debug',
687 coreconfigitem('progress', 'debug',
685 default=False,
688 default=False,
686 )
689 )
687 coreconfigitem('progress', 'delay',
690 coreconfigitem('progress', 'delay',
688 default=3,
691 default=3,
689 )
692 )
690 coreconfigitem('progress', 'disable',
693 coreconfigitem('progress', 'disable',
691 default=False,
694 default=False,
692 )
695 )
693 coreconfigitem('progress', 'estimateinterval',
696 coreconfigitem('progress', 'estimateinterval',
694 default=60.0,
697 default=60.0,
695 )
698 )
696 coreconfigitem('progress', 'format',
699 coreconfigitem('progress', 'format',
697 default=lambda: ['topic', 'bar', 'number', 'estimate'],
700 default=lambda: ['topic', 'bar', 'number', 'estimate'],
698 )
701 )
699 coreconfigitem('progress', 'refresh',
702 coreconfigitem('progress', 'refresh',
700 default=0.1,
703 default=0.1,
701 )
704 )
702 coreconfigitem('progress', 'width',
705 coreconfigitem('progress', 'width',
703 default=dynamicdefault,
706 default=dynamicdefault,
704 )
707 )
705 coreconfigitem('push', 'pushvars.server',
708 coreconfigitem('push', 'pushvars.server',
706 default=False,
709 default=False,
707 )
710 )
708 coreconfigitem('server', 'bundle1',
711 coreconfigitem('server', 'bundle1',
709 default=True,
712 default=True,
710 )
713 )
711 coreconfigitem('server', 'bundle1gd',
714 coreconfigitem('server', 'bundle1gd',
712 default=None,
715 default=None,
713 )
716 )
714 coreconfigitem('server', 'bundle1.pull',
717 coreconfigitem('server', 'bundle1.pull',
715 default=None,
718 default=None,
716 )
719 )
717 coreconfigitem('server', 'bundle1gd.pull',
720 coreconfigitem('server', 'bundle1gd.pull',
718 default=None,
721 default=None,
719 )
722 )
720 coreconfigitem('server', 'bundle1.push',
723 coreconfigitem('server', 'bundle1.push',
721 default=None,
724 default=None,
722 )
725 )
723 coreconfigitem('server', 'bundle1gd.push',
726 coreconfigitem('server', 'bundle1gd.push',
724 default=None,
727 default=None,
725 )
728 )
726 coreconfigitem('server', 'compressionengines',
729 coreconfigitem('server', 'compressionengines',
727 default=list,
730 default=list,
728 )
731 )
729 coreconfigitem('server', 'concurrent-push-mode',
732 coreconfigitem('server', 'concurrent-push-mode',
730 default='strict',
733 default='strict',
731 )
734 )
732 coreconfigitem('server', 'disablefullbundle',
735 coreconfigitem('server', 'disablefullbundle',
733 default=False,
736 default=False,
734 )
737 )
735 coreconfigitem('server', 'maxhttpheaderlen',
738 coreconfigitem('server', 'maxhttpheaderlen',
736 default=1024,
739 default=1024,
737 )
740 )
738 coreconfigitem('server', 'preferuncompressed',
741 coreconfigitem('server', 'preferuncompressed',
739 default=False,
742 default=False,
740 )
743 )
741 coreconfigitem('server', 'uncompressed',
744 coreconfigitem('server', 'uncompressed',
742 default=True,
745 default=True,
743 )
746 )
744 coreconfigitem('server', 'uncompressedallowsecret',
747 coreconfigitem('server', 'uncompressedallowsecret',
745 default=False,
748 default=False,
746 )
749 )
747 coreconfigitem('server', 'validate',
750 coreconfigitem('server', 'validate',
748 default=False,
751 default=False,
749 )
752 )
750 coreconfigitem('server', 'zliblevel',
753 coreconfigitem('server', 'zliblevel',
751 default=-1,
754 default=-1,
752 )
755 )
753 coreconfigitem('smtp', 'host',
756 coreconfigitem('smtp', 'host',
754 default=None,
757 default=None,
755 )
758 )
756 coreconfigitem('smtp', 'local_hostname',
759 coreconfigitem('smtp', 'local_hostname',
757 default=None,
760 default=None,
758 )
761 )
759 coreconfigitem('smtp', 'password',
762 coreconfigitem('smtp', 'password',
760 default=None,
763 default=None,
761 )
764 )
762 coreconfigitem('smtp', 'port',
765 coreconfigitem('smtp', 'port',
763 default=dynamicdefault,
766 default=dynamicdefault,
764 )
767 )
765 coreconfigitem('smtp', 'tls',
768 coreconfigitem('smtp', 'tls',
766 default='none',
769 default='none',
767 )
770 )
768 coreconfigitem('smtp', 'username',
771 coreconfigitem('smtp', 'username',
769 default=None,
772 default=None,
770 )
773 )
771 coreconfigitem('sparse', 'missingwarning',
774 coreconfigitem('sparse', 'missingwarning',
772 default=True,
775 default=True,
773 )
776 )
774 coreconfigitem('templates', '.*',
777 coreconfigitem('templates', '.*',
775 default=None,
778 default=None,
776 generic=True,
779 generic=True,
777 )
780 )
778 coreconfigitem('trusted', 'groups',
781 coreconfigitem('trusted', 'groups',
779 default=list,
782 default=list,
780 )
783 )
781 coreconfigitem('trusted', 'users',
784 coreconfigitem('trusted', 'users',
782 default=list,
785 default=list,
783 )
786 )
784 coreconfigitem('ui', '_usedassubrepo',
787 coreconfigitem('ui', '_usedassubrepo',
785 default=False,
788 default=False,
786 )
789 )
787 coreconfigitem('ui', 'allowemptycommit',
790 coreconfigitem('ui', 'allowemptycommit',
788 default=False,
791 default=False,
789 )
792 )
790 coreconfigitem('ui', 'archivemeta',
793 coreconfigitem('ui', 'archivemeta',
791 default=True,
794 default=True,
792 )
795 )
793 coreconfigitem('ui', 'askusername',
796 coreconfigitem('ui', 'askusername',
794 default=False,
797 default=False,
795 )
798 )
796 coreconfigitem('ui', 'clonebundlefallback',
799 coreconfigitem('ui', 'clonebundlefallback',
797 default=False,
800 default=False,
798 )
801 )
799 coreconfigitem('ui', 'clonebundleprefers',
802 coreconfigitem('ui', 'clonebundleprefers',
800 default=list,
803 default=list,
801 )
804 )
802 coreconfigitem('ui', 'clonebundles',
805 coreconfigitem('ui', 'clonebundles',
803 default=True,
806 default=True,
804 )
807 )
805 coreconfigitem('ui', 'color',
808 coreconfigitem('ui', 'color',
806 default='auto',
809 default='auto',
807 )
810 )
808 coreconfigitem('ui', 'commitsubrepos',
811 coreconfigitem('ui', 'commitsubrepos',
809 default=False,
812 default=False,
810 )
813 )
811 coreconfigitem('ui', 'debug',
814 coreconfigitem('ui', 'debug',
812 default=False,
815 default=False,
813 )
816 )
814 coreconfigitem('ui', 'debugger',
817 coreconfigitem('ui', 'debugger',
815 default=None,
818 default=None,
816 )
819 )
817 coreconfigitem('ui', 'fallbackencoding',
820 coreconfigitem('ui', 'fallbackencoding',
818 default=None,
821 default=None,
819 )
822 )
820 coreconfigitem('ui', 'forcecwd',
823 coreconfigitem('ui', 'forcecwd',
821 default=None,
824 default=None,
822 )
825 )
823 coreconfigitem('ui', 'forcemerge',
826 coreconfigitem('ui', 'forcemerge',
824 default=None,
827 default=None,
825 )
828 )
826 coreconfigitem('ui', 'formatdebug',
829 coreconfigitem('ui', 'formatdebug',
827 default=False,
830 default=False,
828 )
831 )
829 coreconfigitem('ui', 'formatjson',
832 coreconfigitem('ui', 'formatjson',
830 default=False,
833 default=False,
831 )
834 )
832 coreconfigitem('ui', 'formatted',
835 coreconfigitem('ui', 'formatted',
833 default=None,
836 default=None,
834 )
837 )
835 coreconfigitem('ui', 'graphnodetemplate',
838 coreconfigitem('ui', 'graphnodetemplate',
836 default=None,
839 default=None,
837 )
840 )
838 coreconfigitem('ui', 'http2debuglevel',
841 coreconfigitem('ui', 'http2debuglevel',
839 default=None,
842 default=None,
840 )
843 )
841 coreconfigitem('ui', 'interactive',
844 coreconfigitem('ui', 'interactive',
842 default=None,
845 default=None,
843 )
846 )
844 coreconfigitem('ui', 'interface',
847 coreconfigitem('ui', 'interface',
845 default=None,
848 default=None,
846 )
849 )
847 coreconfigitem('ui', 'interface.chunkselector',
850 coreconfigitem('ui', 'interface.chunkselector',
848 default=None,
851 default=None,
849 )
852 )
850 coreconfigitem('ui', 'logblockedtimes',
853 coreconfigitem('ui', 'logblockedtimes',
851 default=False,
854 default=False,
852 )
855 )
853 coreconfigitem('ui', 'logtemplate',
856 coreconfigitem('ui', 'logtemplate',
854 default=None,
857 default=None,
855 )
858 )
856 coreconfigitem('ui', 'merge',
859 coreconfigitem('ui', 'merge',
857 default=None,
860 default=None,
858 )
861 )
859 coreconfigitem('ui', 'mergemarkers',
862 coreconfigitem('ui', 'mergemarkers',
860 default='basic',
863 default='basic',
861 )
864 )
862 coreconfigitem('ui', 'mergemarkertemplate',
865 coreconfigitem('ui', 'mergemarkertemplate',
863 default=('{node|short} '
866 default=('{node|short} '
864 '{ifeq(tags, "tip", "", '
867 '{ifeq(tags, "tip", "", '
865 'ifeq(tags, "", "", "{tags} "))}'
868 'ifeq(tags, "", "", "{tags} "))}'
866 '{if(bookmarks, "{bookmarks} ")}'
869 '{if(bookmarks, "{bookmarks} ")}'
867 '{ifeq(branch, "default", "", "{branch} ")}'
870 '{ifeq(branch, "default", "", "{branch} ")}'
868 '- {author|user}: {desc|firstline}')
871 '- {author|user}: {desc|firstline}')
869 )
872 )
870 coreconfigitem('ui', 'nontty',
873 coreconfigitem('ui', 'nontty',
871 default=False,
874 default=False,
872 )
875 )
873 coreconfigitem('ui', 'origbackuppath',
876 coreconfigitem('ui', 'origbackuppath',
874 default=None,
877 default=None,
875 )
878 )
876 coreconfigitem('ui', 'paginate',
879 coreconfigitem('ui', 'paginate',
877 default=True,
880 default=True,
878 )
881 )
879 coreconfigitem('ui', 'patch',
882 coreconfigitem('ui', 'patch',
880 default=None,
883 default=None,
881 )
884 )
882 coreconfigitem('ui', 'portablefilenames',
885 coreconfigitem('ui', 'portablefilenames',
883 default='warn',
886 default='warn',
884 )
887 )
885 coreconfigitem('ui', 'promptecho',
888 coreconfigitem('ui', 'promptecho',
886 default=False,
889 default=False,
887 )
890 )
888 coreconfigitem('ui', 'quiet',
891 coreconfigitem('ui', 'quiet',
889 default=False,
892 default=False,
890 )
893 )
891 coreconfigitem('ui', 'quietbookmarkmove',
894 coreconfigitem('ui', 'quietbookmarkmove',
892 default=False,
895 default=False,
893 )
896 )
894 coreconfigitem('ui', 'remotecmd',
897 coreconfigitem('ui', 'remotecmd',
895 default='hg',
898 default='hg',
896 )
899 )
897 coreconfigitem('ui', 'report_untrusted',
900 coreconfigitem('ui', 'report_untrusted',
898 default=True,
901 default=True,
899 )
902 )
900 coreconfigitem('ui', 'rollback',
903 coreconfigitem('ui', 'rollback',
901 default=True,
904 default=True,
902 )
905 )
903 coreconfigitem('ui', 'slash',
906 coreconfigitem('ui', 'slash',
904 default=False,
907 default=False,
905 )
908 )
906 coreconfigitem('ui', 'ssh',
909 coreconfigitem('ui', 'ssh',
907 default='ssh',
910 default='ssh',
908 )
911 )
909 coreconfigitem('ui', 'statuscopies',
912 coreconfigitem('ui', 'statuscopies',
910 default=False,
913 default=False,
911 )
914 )
912 coreconfigitem('ui', 'strict',
915 coreconfigitem('ui', 'strict',
913 default=False,
916 default=False,
914 )
917 )
915 coreconfigitem('ui', 'style',
918 coreconfigitem('ui', 'style',
916 default='',
919 default='',
917 )
920 )
918 coreconfigitem('ui', 'supportcontact',
921 coreconfigitem('ui', 'supportcontact',
919 default=None,
922 default=None,
920 )
923 )
921 coreconfigitem('ui', 'textwidth',
924 coreconfigitem('ui', 'textwidth',
922 default=78,
925 default=78,
923 )
926 )
924 coreconfigitem('ui', 'timeout',
927 coreconfigitem('ui', 'timeout',
925 default='600',
928 default='600',
926 )
929 )
927 coreconfigitem('ui', 'traceback',
930 coreconfigitem('ui', 'traceback',
928 default=False,
931 default=False,
929 )
932 )
930 coreconfigitem('ui', 'tweakdefaults',
933 coreconfigitem('ui', 'tweakdefaults',
931 default=False,
934 default=False,
932 )
935 )
933 coreconfigitem('ui', 'usehttp2',
936 coreconfigitem('ui', 'usehttp2',
934 default=False,
937 default=False,
935 )
938 )
936 coreconfigitem('ui', 'username',
939 coreconfigitem('ui', 'username',
937 alias=[('ui', 'user')]
940 alias=[('ui', 'user')]
938 )
941 )
939 coreconfigitem('ui', 'verbose',
942 coreconfigitem('ui', 'verbose',
940 default=False,
943 default=False,
941 )
944 )
942 coreconfigitem('verify', 'skipflags',
945 coreconfigitem('verify', 'skipflags',
943 default=None,
946 default=None,
944 )
947 )
945 coreconfigitem('web', 'allowbz2',
948 coreconfigitem('web', 'allowbz2',
946 default=False,
949 default=False,
947 )
950 )
948 coreconfigitem('web', 'allowgz',
951 coreconfigitem('web', 'allowgz',
949 default=False,
952 default=False,
950 )
953 )
951 coreconfigitem('web', 'allowpull',
954 coreconfigitem('web', 'allowpull',
952 default=True,
955 default=True,
953 )
956 )
954 coreconfigitem('web', 'allow_push',
957 coreconfigitem('web', 'allow_push',
955 default=list,
958 default=list,
956 )
959 )
957 coreconfigitem('web', 'allowzip',
960 coreconfigitem('web', 'allowzip',
958 default=False,
961 default=False,
959 )
962 )
960 coreconfigitem('web', 'archivesubrepos',
963 coreconfigitem('web', 'archivesubrepos',
961 default=False,
964 default=False,
962 )
965 )
963 coreconfigitem('web', 'cache',
966 coreconfigitem('web', 'cache',
964 default=True,
967 default=True,
965 )
968 )
966 coreconfigitem('web', 'contact',
969 coreconfigitem('web', 'contact',
967 default=None,
970 default=None,
968 )
971 )
969 coreconfigitem('web', 'deny_push',
972 coreconfigitem('web', 'deny_push',
970 default=list,
973 default=list,
971 )
974 )
972 coreconfigitem('web', 'guessmime',
975 coreconfigitem('web', 'guessmime',
973 default=False,
976 default=False,
974 )
977 )
975 coreconfigitem('web', 'hidden',
978 coreconfigitem('web', 'hidden',
976 default=False,
979 default=False,
977 )
980 )
978 coreconfigitem('web', 'labels',
981 coreconfigitem('web', 'labels',
979 default=list,
982 default=list,
980 )
983 )
981 coreconfigitem('web', 'logoimg',
984 coreconfigitem('web', 'logoimg',
982 default='hglogo.png',
985 default='hglogo.png',
983 )
986 )
984 coreconfigitem('web', 'logourl',
987 coreconfigitem('web', 'logourl',
985 default='https://mercurial-scm.org/',
988 default='https://mercurial-scm.org/',
986 )
989 )
987 coreconfigitem('web', 'accesslog',
990 coreconfigitem('web', 'accesslog',
988 default='-',
991 default='-',
989 )
992 )
990 coreconfigitem('web', 'address',
993 coreconfigitem('web', 'address',
991 default='',
994 default='',
992 )
995 )
993 coreconfigitem('web', 'allow_archive',
996 coreconfigitem('web', 'allow_archive',
994 default=list,
997 default=list,
995 )
998 )
996 coreconfigitem('web', 'allow_read',
999 coreconfigitem('web', 'allow_read',
997 default=list,
1000 default=list,
998 )
1001 )
999 coreconfigitem('web', 'baseurl',
1002 coreconfigitem('web', 'baseurl',
1000 default=None,
1003 default=None,
1001 )
1004 )
1002 coreconfigitem('web', 'cacerts',
1005 coreconfigitem('web', 'cacerts',
1003 default=None,
1006 default=None,
1004 )
1007 )
1005 coreconfigitem('web', 'certificate',
1008 coreconfigitem('web', 'certificate',
1006 default=None,
1009 default=None,
1007 )
1010 )
1008 coreconfigitem('web', 'collapse',
1011 coreconfigitem('web', 'collapse',
1009 default=False,
1012 default=False,
1010 )
1013 )
1011 coreconfigitem('web', 'csp',
1014 coreconfigitem('web', 'csp',
1012 default=None,
1015 default=None,
1013 )
1016 )
1014 coreconfigitem('web', 'deny_read',
1017 coreconfigitem('web', 'deny_read',
1015 default=list,
1018 default=list,
1016 )
1019 )
1017 coreconfigitem('web', 'descend',
1020 coreconfigitem('web', 'descend',
1018 default=True,
1021 default=True,
1019 )
1022 )
1020 coreconfigitem('web', 'description',
1023 coreconfigitem('web', 'description',
1021 default="",
1024 default="",
1022 )
1025 )
1023 coreconfigitem('web', 'encoding',
1026 coreconfigitem('web', 'encoding',
1024 default=lambda: encoding.encoding,
1027 default=lambda: encoding.encoding,
1025 )
1028 )
1026 coreconfigitem('web', 'errorlog',
1029 coreconfigitem('web', 'errorlog',
1027 default='-',
1030 default='-',
1028 )
1031 )
1029 coreconfigitem('web', 'ipv6',
1032 coreconfigitem('web', 'ipv6',
1030 default=False,
1033 default=False,
1031 )
1034 )
1032 coreconfigitem('web', 'maxchanges',
1035 coreconfigitem('web', 'maxchanges',
1033 default=10,
1036 default=10,
1034 )
1037 )
1035 coreconfigitem('web', 'maxfiles',
1038 coreconfigitem('web', 'maxfiles',
1036 default=10,
1039 default=10,
1037 )
1040 )
1038 coreconfigitem('web', 'maxshortchanges',
1041 coreconfigitem('web', 'maxshortchanges',
1039 default=60,
1042 default=60,
1040 )
1043 )
1041 coreconfigitem('web', 'motd',
1044 coreconfigitem('web', 'motd',
1042 default='',
1045 default='',
1043 )
1046 )
1044 coreconfigitem('web', 'name',
1047 coreconfigitem('web', 'name',
1045 default=dynamicdefault,
1048 default=dynamicdefault,
1046 )
1049 )
1047 coreconfigitem('web', 'port',
1050 coreconfigitem('web', 'port',
1048 default=8000,
1051 default=8000,
1049 )
1052 )
1050 coreconfigitem('web', 'prefix',
1053 coreconfigitem('web', 'prefix',
1051 default='',
1054 default='',
1052 )
1055 )
1053 coreconfigitem('web', 'push_ssl',
1056 coreconfigitem('web', 'push_ssl',
1054 default=True,
1057 default=True,
1055 )
1058 )
1056 coreconfigitem('web', 'refreshinterval',
1059 coreconfigitem('web', 'refreshinterval',
1057 default=20,
1060 default=20,
1058 )
1061 )
1059 coreconfigitem('web', 'staticurl',
1062 coreconfigitem('web', 'staticurl',
1060 default=None,
1063 default=None,
1061 )
1064 )
1062 coreconfigitem('web', 'stripes',
1065 coreconfigitem('web', 'stripes',
1063 default=1,
1066 default=1,
1064 )
1067 )
1065 coreconfigitem('web', 'style',
1068 coreconfigitem('web', 'style',
1066 default='paper',
1069 default='paper',
1067 )
1070 )
1068 coreconfigitem('web', 'templates',
1071 coreconfigitem('web', 'templates',
1069 default=None,
1072 default=None,
1070 )
1073 )
1071 coreconfigitem('web', 'view',
1074 coreconfigitem('web', 'view',
1072 default='served',
1075 default='served',
1073 )
1076 )
1074 coreconfigitem('worker', 'backgroundclose',
1077 coreconfigitem('worker', 'backgroundclose',
1075 default=dynamicdefault,
1078 default=dynamicdefault,
1076 )
1079 )
1077 # Windows defaults to a limit of 512 open files. A buffer of 128
1080 # Windows defaults to a limit of 512 open files. A buffer of 128
1078 # should give us enough headway.
1081 # should give us enough headway.
1079 coreconfigitem('worker', 'backgroundclosemaxqueue',
1082 coreconfigitem('worker', 'backgroundclosemaxqueue',
1080 default=384,
1083 default=384,
1081 )
1084 )
1082 coreconfigitem('worker', 'backgroundcloseminfilecount',
1085 coreconfigitem('worker', 'backgroundcloseminfilecount',
1083 default=2048,
1086 default=2048,
1084 )
1087 )
1085 coreconfigitem('worker', 'backgroundclosethreadcount',
1088 coreconfigitem('worker', 'backgroundclosethreadcount',
1086 default=4,
1089 default=4,
1087 )
1090 )
1088 coreconfigitem('worker', 'numcpus',
1091 coreconfigitem('worker', 'numcpus',
1089 default=None,
1092 default=None,
1090 )
1093 )
1091
1094
1092 # Rebase related configuration moved to core because other extension are doing
1095 # Rebase related configuration moved to core because other extension are doing
1093 # strange things. For example, shelve import the extensions to reuse some bit
1096 # strange things. For example, shelve import the extensions to reuse some bit
1094 # without formally loading it.
1097 # without formally loading it.
1095 coreconfigitem('commands', 'rebase.requiredest',
1098 coreconfigitem('commands', 'rebase.requiredest',
1096 default=False,
1099 default=False,
1097 )
1100 )
1098 coreconfigitem('experimental', 'rebaseskipobsolete',
1101 coreconfigitem('experimental', 'rebaseskipobsolete',
1099 default=True,
1102 default=True,
1100 )
1103 )
1101 coreconfigitem('rebase', 'singletransaction',
1104 coreconfigitem('rebase', 'singletransaction',
1102 default=False,
1105 default=False,
1103 )
1106 )
@@ -1,1825 +1,1829
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
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 collections
10 import collections
11 import contextlib
11 import contextlib
12 import errno
12 import errno
13 import getpass
13 import getpass
14 import inspect
14 import inspect
15 import os
15 import os
16 import re
16 import re
17 import signal
17 import signal
18 import socket
18 import socket
19 import subprocess
19 import subprocess
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22 import traceback
22 import traceback
23
23
24 from .i18n import _
24 from .i18n import _
25 from .node import hex
25 from .node import hex
26
26
27 from . import (
27 from . import (
28 color,
28 color,
29 config,
29 config,
30 configitems,
30 configitems,
31 encoding,
31 encoding,
32 error,
32 error,
33 formatter,
33 formatter,
34 progress,
34 progress,
35 pycompat,
35 pycompat,
36 rcutil,
36 rcutil,
37 scmutil,
37 scmutil,
38 util,
38 util,
39 )
39 )
40
40
41 urlreq = util.urlreq
41 urlreq = util.urlreq
42
42
43 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
43 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
44 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
44 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
45 if not c.isalnum())
45 if not c.isalnum())
46
46
47 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
47 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
48 tweakrc = """
48 tweakrc = """
49 [ui]
49 [ui]
50 # The rollback command is dangerous. As a rule, don't use it.
50 # The rollback command is dangerous. As a rule, don't use it.
51 rollback = False
51 rollback = False
52
52
53 [commands]
53 [commands]
54 # Make `hg status` emit cwd-relative paths by default.
54 # Make `hg status` emit cwd-relative paths by default.
55 status.relative = yes
55 status.relative = yes
56 # Refuse to perform an `hg update` that would cause a file content merge
56 # Refuse to perform an `hg update` that would cause a file content merge
57 update.check = noconflict
57 update.check = noconflict
58
58
59 [diff]
59 [diff]
60 git = 1
60 git = 1
61 """
61 """
62
62
63 samplehgrcs = {
63 samplehgrcs = {
64 'user':
64 'user':
65 b"""# example user config (see 'hg help config' for more info)
65 b"""# example user config (see 'hg help config' for more info)
66 [ui]
66 [ui]
67 # name and email, e.g.
67 # name and email, e.g.
68 # username = Jane Doe <jdoe@example.com>
68 # username = Jane Doe <jdoe@example.com>
69 username =
69 username =
70
70
71 # We recommend enabling tweakdefaults to get slight improvements to
71 # We recommend enabling tweakdefaults to get slight improvements to
72 # the UI over time. Make sure to set HGPLAIN in the environment when
72 # the UI over time. Make sure to set HGPLAIN in the environment when
73 # writing scripts!
73 # writing scripts!
74 # tweakdefaults = True
74 # tweakdefaults = True
75
75
76 # uncomment to disable color in command output
76 # uncomment to disable color in command output
77 # (see 'hg help color' for details)
77 # (see 'hg help color' for details)
78 # color = never
78 # color = never
79
79
80 # uncomment to disable command output pagination
80 # uncomment to disable command output pagination
81 # (see 'hg help pager' for details)
81 # (see 'hg help pager' for details)
82 # paginate = never
82 # paginate = never
83
83
84 [extensions]
84 [extensions]
85 # uncomment these lines to enable some popular extensions
85 # uncomment these lines to enable some popular extensions
86 # (see 'hg help extensions' for more info)
86 # (see 'hg help extensions' for more info)
87 #
87 #
88 # churn =
88 # churn =
89 """,
89 """,
90
90
91 'cloned':
91 'cloned':
92 b"""# example repository config (see 'hg help config' for more info)
92 b"""# example repository config (see 'hg help config' for more info)
93 [paths]
93 [paths]
94 default = %s
94 default = %s
95
95
96 # path aliases to other clones of this repo in URLs or filesystem paths
96 # path aliases to other clones of this repo in URLs or filesystem paths
97 # (see 'hg help config.paths' for more info)
97 # (see 'hg help config.paths' for more info)
98 #
98 #
99 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
99 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
100 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
100 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
101 # my-clone = /home/jdoe/jdoes-clone
101 # my-clone = /home/jdoe/jdoes-clone
102
102
103 [ui]
103 [ui]
104 # name and email (local to this repository, optional), e.g.
104 # name and email (local to this repository, optional), e.g.
105 # username = Jane Doe <jdoe@example.com>
105 # username = Jane Doe <jdoe@example.com>
106 """,
106 """,
107
107
108 'local':
108 'local':
109 b"""# example repository config (see 'hg help config' for more info)
109 b"""# example repository config (see 'hg help config' for more info)
110 [paths]
110 [paths]
111 # path aliases to other clones of this repo in URLs or filesystem paths
111 # path aliases to other clones of this repo in URLs or filesystem paths
112 # (see 'hg help config.paths' for more info)
112 # (see 'hg help config.paths' for more info)
113 #
113 #
114 # default = http://example.com/hg/example-repo
114 # default = http://example.com/hg/example-repo
115 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
115 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
116 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
116 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
117 # my-clone = /home/jdoe/jdoes-clone
117 # my-clone = /home/jdoe/jdoes-clone
118
118
119 [ui]
119 [ui]
120 # name and email (local to this repository, optional), e.g.
120 # name and email (local to this repository, optional), e.g.
121 # username = Jane Doe <jdoe@example.com>
121 # username = Jane Doe <jdoe@example.com>
122 """,
122 """,
123
123
124 'global':
124 'global':
125 b"""# example system-wide hg config (see 'hg help config' for more info)
125 b"""# example system-wide hg config (see 'hg help config' for more info)
126
126
127 [ui]
127 [ui]
128 # uncomment to disable color in command output
128 # uncomment to disable color in command output
129 # (see 'hg help color' for details)
129 # (see 'hg help color' for details)
130 # color = never
130 # color = never
131
131
132 # uncomment to disable command output pagination
132 # uncomment to disable command output pagination
133 # (see 'hg help pager' for details)
133 # (see 'hg help pager' for details)
134 # paginate = never
134 # paginate = never
135
135
136 [extensions]
136 [extensions]
137 # uncomment these lines to enable some popular extensions
137 # uncomment these lines to enable some popular extensions
138 # (see 'hg help extensions' for more info)
138 # (see 'hg help extensions' for more info)
139 #
139 #
140 # blackbox =
140 # blackbox =
141 # churn =
141 # churn =
142 """,
142 """,
143 }
143 }
144
144
145 def _maybestrurl(maybebytes):
145 def _maybestrurl(maybebytes):
146 if maybebytes is None:
146 if maybebytes is None:
147 return None
147 return None
148 return pycompat.strurl(maybebytes)
148 return pycompat.strurl(maybebytes)
149
149
150 def _maybebytesurl(maybestr):
150 def _maybebytesurl(maybestr):
151 if maybestr is None:
151 if maybestr is None:
152 return None
152 return None
153 return pycompat.bytesurl(maybestr)
153 return pycompat.bytesurl(maybestr)
154
154
155 class httppasswordmgrdbproxy(object):
155 class httppasswordmgrdbproxy(object):
156 """Delays loading urllib2 until it's needed."""
156 """Delays loading urllib2 until it's needed."""
157 def __init__(self):
157 def __init__(self):
158 self._mgr = None
158 self._mgr = None
159
159
160 def _get_mgr(self):
160 def _get_mgr(self):
161 if self._mgr is None:
161 if self._mgr is None:
162 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
162 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
163 return self._mgr
163 return self._mgr
164
164
165 def add_password(self, realm, uris, user, passwd):
165 def add_password(self, realm, uris, user, passwd):
166 if isinstance(uris, tuple):
166 if isinstance(uris, tuple):
167 uris = tuple(_maybestrurl(u) for u in uris)
167 uris = tuple(_maybestrurl(u) for u in uris)
168 else:
168 else:
169 uris = _maybestrurl(uris)
169 uris = _maybestrurl(uris)
170 return self._get_mgr().add_password(
170 return self._get_mgr().add_password(
171 _maybestrurl(realm), uris,
171 _maybestrurl(realm), uris,
172 _maybestrurl(user), _maybestrurl(passwd))
172 _maybestrurl(user), _maybestrurl(passwd))
173
173
174 def find_user_password(self, realm, uri):
174 def find_user_password(self, realm, uri):
175 return tuple(_maybebytesurl(v) for v in
175 return tuple(_maybebytesurl(v) for v in
176 self._get_mgr().find_user_password(_maybestrurl(realm),
176 self._get_mgr().find_user_password(_maybestrurl(realm),
177 _maybestrurl(uri)))
177 _maybestrurl(uri)))
178
178
179 def _catchterm(*args):
179 def _catchterm(*args):
180 raise error.SignalInterrupt
180 raise error.SignalInterrupt
181
181
182 # unique object used to detect no default value has been provided when
182 # unique object used to detect no default value has been provided when
183 # retrieving configuration value.
183 # retrieving configuration value.
184 _unset = object()
184 _unset = object()
185
185
186 class ui(object):
186 class ui(object):
187 def __init__(self, src=None):
187 def __init__(self, src=None):
188 """Create a fresh new ui object if no src given
188 """Create a fresh new ui object if no src given
189
189
190 Use uimod.ui.load() to create a ui which knows global and user configs.
190 Use uimod.ui.load() to create a ui which knows global and user configs.
191 In most cases, you should use ui.copy() to create a copy of an existing
191 In most cases, you should use ui.copy() to create a copy of an existing
192 ui object.
192 ui object.
193 """
193 """
194 # _buffers: used for temporary capture of output
194 # _buffers: used for temporary capture of output
195 self._buffers = []
195 self._buffers = []
196 # _exithandlers: callbacks run at the end of a request
196 # _exithandlers: callbacks run at the end of a request
197 self._exithandlers = []
197 self._exithandlers = []
198 # 3-tuple describing how each buffer in the stack behaves.
198 # 3-tuple describing how each buffer in the stack behaves.
199 # Values are (capture stderr, capture subprocesses, apply labels).
199 # Values are (capture stderr, capture subprocesses, apply labels).
200 self._bufferstates = []
200 self._bufferstates = []
201 # When a buffer is active, defines whether we are expanding labels.
201 # When a buffer is active, defines whether we are expanding labels.
202 # This exists to prevent an extra list lookup.
202 # This exists to prevent an extra list lookup.
203 self._bufferapplylabels = None
203 self._bufferapplylabels = None
204 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
204 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
205 self._reportuntrusted = True
205 self._reportuntrusted = True
206 self._knownconfig = configitems.coreitems
206 self._knownconfig = configitems.coreitems
207 self._ocfg = config.config() # overlay
207 self._ocfg = config.config() # overlay
208 self._tcfg = config.config() # trusted
208 self._tcfg = config.config() # trusted
209 self._ucfg = config.config() # untrusted
209 self._ucfg = config.config() # untrusted
210 self._trustusers = set()
210 self._trustusers = set()
211 self._trustgroups = set()
211 self._trustgroups = set()
212 self.callhooks = True
212 self.callhooks = True
213 # Insecure server connections requested.
213 # Insecure server connections requested.
214 self.insecureconnections = False
214 self.insecureconnections = False
215 # Blocked time
215 # Blocked time
216 self.logblockedtimes = False
216 self.logblockedtimes = False
217 # color mode: see mercurial/color.py for possible value
217 # color mode: see mercurial/color.py for possible value
218 self._colormode = None
218 self._colormode = None
219 self._terminfoparams = {}
219 self._terminfoparams = {}
220 self._styles = {}
220 self._styles = {}
221
221
222 if src:
222 if src:
223 self._exithandlers = src._exithandlers
223 self._exithandlers = src._exithandlers
224 self.fout = src.fout
224 self.fout = src.fout
225 self.ferr = src.ferr
225 self.ferr = src.ferr
226 self.fin = src.fin
226 self.fin = src.fin
227 self.pageractive = src.pageractive
227 self.pageractive = src.pageractive
228 self._disablepager = src._disablepager
228 self._disablepager = src._disablepager
229 self._tweaked = src._tweaked
229 self._tweaked = src._tweaked
230
230
231 self._tcfg = src._tcfg.copy()
231 self._tcfg = src._tcfg.copy()
232 self._ucfg = src._ucfg.copy()
232 self._ucfg = src._ucfg.copy()
233 self._ocfg = src._ocfg.copy()
233 self._ocfg = src._ocfg.copy()
234 self._trustusers = src._trustusers.copy()
234 self._trustusers = src._trustusers.copy()
235 self._trustgroups = src._trustgroups.copy()
235 self._trustgroups = src._trustgroups.copy()
236 self.environ = src.environ
236 self.environ = src.environ
237 self.callhooks = src.callhooks
237 self.callhooks = src.callhooks
238 self.insecureconnections = src.insecureconnections
238 self.insecureconnections = src.insecureconnections
239 self._colormode = src._colormode
239 self._colormode = src._colormode
240 self._terminfoparams = src._terminfoparams.copy()
240 self._terminfoparams = src._terminfoparams.copy()
241 self._styles = src._styles.copy()
241 self._styles = src._styles.copy()
242
242
243 self.fixconfig()
243 self.fixconfig()
244
244
245 self.httppasswordmgrdb = src.httppasswordmgrdb
245 self.httppasswordmgrdb = src.httppasswordmgrdb
246 self._blockedtimes = src._blockedtimes
246 self._blockedtimes = src._blockedtimes
247 else:
247 else:
248 self.fout = util.stdout
248 self.fout = util.stdout
249 self.ferr = util.stderr
249 self.ferr = util.stderr
250 self.fin = util.stdin
250 self.fin = util.stdin
251 self.pageractive = False
251 self.pageractive = False
252 self._disablepager = False
252 self._disablepager = False
253 self._tweaked = False
253 self._tweaked = False
254
254
255 # shared read-only environment
255 # shared read-only environment
256 self.environ = encoding.environ
256 self.environ = encoding.environ
257
257
258 self.httppasswordmgrdb = httppasswordmgrdbproxy()
258 self.httppasswordmgrdb = httppasswordmgrdbproxy()
259 self._blockedtimes = collections.defaultdict(int)
259 self._blockedtimes = collections.defaultdict(int)
260
260
261 allowed = self.configlist('experimental', 'exportableenviron')
261 allowed = self.configlist('experimental', 'exportableenviron')
262 if '*' in allowed:
262 if '*' in allowed:
263 self._exportableenviron = self.environ
263 self._exportableenviron = self.environ
264 else:
264 else:
265 self._exportableenviron = {}
265 self._exportableenviron = {}
266 for k in allowed:
266 for k in allowed:
267 if k in self.environ:
267 if k in self.environ:
268 self._exportableenviron[k] = self.environ[k]
268 self._exportableenviron[k] = self.environ[k]
269
269
270 @classmethod
270 @classmethod
271 def load(cls):
271 def load(cls):
272 """Create a ui and load global and user configs"""
272 """Create a ui and load global and user configs"""
273 u = cls()
273 u = cls()
274 # we always trust global config files and environment variables
274 # we always trust global config files and environment variables
275 for t, f in rcutil.rccomponents():
275 for t, f in rcutil.rccomponents():
276 if t == 'path':
276 if t == 'path':
277 u.readconfig(f, trust=True)
277 u.readconfig(f, trust=True)
278 elif t == 'items':
278 elif t == 'items':
279 sections = set()
279 sections = set()
280 for section, name, value, source in f:
280 for section, name, value, source in f:
281 # do not set u._ocfg
281 # do not set u._ocfg
282 # XXX clean this up once immutable config object is a thing
282 # XXX clean this up once immutable config object is a thing
283 u._tcfg.set(section, name, value, source)
283 u._tcfg.set(section, name, value, source)
284 u._ucfg.set(section, name, value, source)
284 u._ucfg.set(section, name, value, source)
285 sections.add(section)
285 sections.add(section)
286 for section in sections:
286 for section in sections:
287 u.fixconfig(section=section)
287 u.fixconfig(section=section)
288 else:
288 else:
289 raise error.ProgrammingError('unknown rctype: %s' % t)
289 raise error.ProgrammingError('unknown rctype: %s' % t)
290 u._maybetweakdefaults()
290 u._maybetweakdefaults()
291 return u
291 return u
292
292
293 def _maybetweakdefaults(self):
293 def _maybetweakdefaults(self):
294 if not self.configbool('ui', 'tweakdefaults'):
294 if not self.configbool('ui', 'tweakdefaults'):
295 return
295 return
296 if self._tweaked or self.plain('tweakdefaults'):
296 if self._tweaked or self.plain('tweakdefaults'):
297 return
297 return
298
298
299 # Note: it is SUPER IMPORTANT that you set self._tweaked to
299 # Note: it is SUPER IMPORTANT that you set self._tweaked to
300 # True *before* any calls to setconfig(), otherwise you'll get
300 # True *before* any calls to setconfig(), otherwise you'll get
301 # infinite recursion between setconfig and this method.
301 # infinite recursion between setconfig and this method.
302 #
302 #
303 # TODO: We should extract an inner method in setconfig() to
303 # TODO: We should extract an inner method in setconfig() to
304 # avoid this weirdness.
304 # avoid this weirdness.
305 self._tweaked = True
305 self._tweaked = True
306 tmpcfg = config.config()
306 tmpcfg = config.config()
307 tmpcfg.parse('<tweakdefaults>', tweakrc)
307 tmpcfg.parse('<tweakdefaults>', tweakrc)
308 for section in tmpcfg:
308 for section in tmpcfg:
309 for name, value in tmpcfg.items(section):
309 for name, value in tmpcfg.items(section):
310 if not self.hasconfig(section, name):
310 if not self.hasconfig(section, name):
311 self.setconfig(section, name, value, "<tweakdefaults>")
311 self.setconfig(section, name, value, "<tweakdefaults>")
312
312
313 def copy(self):
313 def copy(self):
314 return self.__class__(self)
314 return self.__class__(self)
315
315
316 def resetstate(self):
316 def resetstate(self):
317 """Clear internal state that shouldn't persist across commands"""
317 """Clear internal state that shouldn't persist across commands"""
318 if self._progbar:
318 if self._progbar:
319 self._progbar.resetstate() # reset last-print time of progress bar
319 self._progbar.resetstate() # reset last-print time of progress bar
320 self.httppasswordmgrdb = httppasswordmgrdbproxy()
320 self.httppasswordmgrdb = httppasswordmgrdbproxy()
321
321
322 @contextlib.contextmanager
322 @contextlib.contextmanager
323 def timeblockedsection(self, key):
323 def timeblockedsection(self, key):
324 # this is open-coded below - search for timeblockedsection to find them
324 # this is open-coded below - search for timeblockedsection to find them
325 starttime = util.timer()
325 starttime = util.timer()
326 try:
326 try:
327 yield
327 yield
328 finally:
328 finally:
329 self._blockedtimes[key + '_blocked'] += \
329 self._blockedtimes[key + '_blocked'] += \
330 (util.timer() - starttime) * 1000
330 (util.timer() - starttime) * 1000
331
331
332 def formatter(self, topic, opts):
332 def formatter(self, topic, opts):
333 return formatter.formatter(self, self, topic, opts)
333 return formatter.formatter(self, self, topic, opts)
334
334
335 def _trusted(self, fp, f):
335 def _trusted(self, fp, f):
336 st = util.fstat(fp)
336 st = util.fstat(fp)
337 if util.isowner(st):
337 if util.isowner(st):
338 return True
338 return True
339
339
340 tusers, tgroups = self._trustusers, self._trustgroups
340 tusers, tgroups = self._trustusers, self._trustgroups
341 if '*' in tusers or '*' in tgroups:
341 if '*' in tusers or '*' in tgroups:
342 return True
342 return True
343
343
344 user = util.username(st.st_uid)
344 user = util.username(st.st_uid)
345 group = util.groupname(st.st_gid)
345 group = util.groupname(st.st_gid)
346 if user in tusers or group in tgroups or user == util.username():
346 if user in tusers or group in tgroups or user == util.username():
347 return True
347 return True
348
348
349 if self._reportuntrusted:
349 if self._reportuntrusted:
350 self.warn(_('not trusting file %s from untrusted '
350 self.warn(_('not trusting file %s from untrusted '
351 'user %s, group %s\n') % (f, user, group))
351 'user %s, group %s\n') % (f, user, group))
352 return False
352 return False
353
353
354 def readconfig(self, filename, root=None, trust=False,
354 def readconfig(self, filename, root=None, trust=False,
355 sections=None, remap=None):
355 sections=None, remap=None):
356 try:
356 try:
357 fp = open(filename, u'rb')
357 fp = open(filename, u'rb')
358 except IOError:
358 except IOError:
359 if not sections: # ignore unless we were looking for something
359 if not sections: # ignore unless we were looking for something
360 return
360 return
361 raise
361 raise
362
362
363 cfg = config.config()
363 cfg = config.config()
364 trusted = sections or trust or self._trusted(fp, filename)
364 trusted = sections or trust or self._trusted(fp, filename)
365
365
366 try:
366 try:
367 cfg.read(filename, fp, sections=sections, remap=remap)
367 cfg.read(filename, fp, sections=sections, remap=remap)
368 fp.close()
368 fp.close()
369 except error.ConfigError as inst:
369 except error.ConfigError as inst:
370 if trusted:
370 if trusted:
371 raise
371 raise
372 self.warn(_("ignored: %s\n") % str(inst))
372 self.warn(_("ignored: %s\n") % str(inst))
373
373
374 if self.plain():
374 if self.plain():
375 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
375 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
376 'logtemplate', 'statuscopies', 'style',
376 'logtemplate', 'statuscopies', 'style',
377 'traceback', 'verbose'):
377 'traceback', 'verbose'):
378 if k in cfg['ui']:
378 if k in cfg['ui']:
379 del cfg['ui'][k]
379 del cfg['ui'][k]
380 for k, v in cfg.items('defaults'):
380 for k, v in cfg.items('defaults'):
381 del cfg['defaults'][k]
381 del cfg['defaults'][k]
382 for k, v in cfg.items('commands'):
382 for k, v in cfg.items('commands'):
383 del cfg['commands'][k]
383 del cfg['commands'][k]
384 # Don't remove aliases from the configuration if in the exceptionlist
384 # Don't remove aliases from the configuration if in the exceptionlist
385 if self.plain('alias'):
385 if self.plain('alias'):
386 for k, v in cfg.items('alias'):
386 for k, v in cfg.items('alias'):
387 del cfg['alias'][k]
387 del cfg['alias'][k]
388 if self.plain('revsetalias'):
388 if self.plain('revsetalias'):
389 for k, v in cfg.items('revsetalias'):
389 for k, v in cfg.items('revsetalias'):
390 del cfg['revsetalias'][k]
390 del cfg['revsetalias'][k]
391 if self.plain('templatealias'):
391 if self.plain('templatealias'):
392 for k, v in cfg.items('templatealias'):
392 for k, v in cfg.items('templatealias'):
393 del cfg['templatealias'][k]
393 del cfg['templatealias'][k]
394
394
395 if trusted:
395 if trusted:
396 self._tcfg.update(cfg)
396 self._tcfg.update(cfg)
397 self._tcfg.update(self._ocfg)
397 self._tcfg.update(self._ocfg)
398 self._ucfg.update(cfg)
398 self._ucfg.update(cfg)
399 self._ucfg.update(self._ocfg)
399 self._ucfg.update(self._ocfg)
400
400
401 if root is None:
401 if root is None:
402 root = os.path.expanduser('~')
402 root = os.path.expanduser('~')
403 self.fixconfig(root=root)
403 self.fixconfig(root=root)
404
404
405 def fixconfig(self, root=None, section=None):
405 def fixconfig(self, root=None, section=None):
406 if section in (None, 'paths'):
406 if section in (None, 'paths'):
407 # expand vars and ~
407 # expand vars and ~
408 # translate paths relative to root (or home) into absolute paths
408 # translate paths relative to root (or home) into absolute paths
409 root = root or pycompat.getcwd()
409 root = root or pycompat.getcwd()
410 for c in self._tcfg, self._ucfg, self._ocfg:
410 for c in self._tcfg, self._ucfg, self._ocfg:
411 for n, p in c.items('paths'):
411 for n, p in c.items('paths'):
412 # Ignore sub-options.
412 # Ignore sub-options.
413 if ':' in n:
413 if ':' in n:
414 continue
414 continue
415 if not p:
415 if not p:
416 continue
416 continue
417 if '%%' in p:
417 if '%%' in p:
418 s = self.configsource('paths', n) or 'none'
418 s = self.configsource('paths', n) or 'none'
419 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
419 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
420 % (n, p, s))
420 % (n, p, s))
421 p = p.replace('%%', '%')
421 p = p.replace('%%', '%')
422 p = util.expandpath(p)
422 p = util.expandpath(p)
423 if not util.hasscheme(p) and not os.path.isabs(p):
423 if not util.hasscheme(p) and not os.path.isabs(p):
424 p = os.path.normpath(os.path.join(root, p))
424 p = os.path.normpath(os.path.join(root, p))
425 c.set("paths", n, p)
425 c.set("paths", n, p)
426
426
427 if section in (None, 'ui'):
427 if section in (None, 'ui'):
428 # update ui options
428 # update ui options
429 self.debugflag = self.configbool('ui', 'debug')
429 self.debugflag = self.configbool('ui', 'debug')
430 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
430 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
431 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
431 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
432 if self.verbose and self.quiet:
432 if self.verbose and self.quiet:
433 self.quiet = self.verbose = False
433 self.quiet = self.verbose = False
434 self._reportuntrusted = self.debugflag or self.configbool("ui",
434 self._reportuntrusted = self.debugflag or self.configbool("ui",
435 "report_untrusted")
435 "report_untrusted")
436 self.tracebackflag = self.configbool('ui', 'traceback')
436 self.tracebackflag = self.configbool('ui', 'traceback')
437 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
437 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
438
438
439 if section in (None, 'trusted'):
439 if section in (None, 'trusted'):
440 # update trust information
440 # update trust information
441 self._trustusers.update(self.configlist('trusted', 'users'))
441 self._trustusers.update(self.configlist('trusted', 'users'))
442 self._trustgroups.update(self.configlist('trusted', 'groups'))
442 self._trustgroups.update(self.configlist('trusted', 'groups'))
443
443
444 def backupconfig(self, section, item):
444 def backupconfig(self, section, item):
445 return (self._ocfg.backup(section, item),
445 return (self._ocfg.backup(section, item),
446 self._tcfg.backup(section, item),
446 self._tcfg.backup(section, item),
447 self._ucfg.backup(section, item),)
447 self._ucfg.backup(section, item),)
448 def restoreconfig(self, data):
448 def restoreconfig(self, data):
449 self._ocfg.restore(data[0])
449 self._ocfg.restore(data[0])
450 self._tcfg.restore(data[1])
450 self._tcfg.restore(data[1])
451 self._ucfg.restore(data[2])
451 self._ucfg.restore(data[2])
452
452
453 def setconfig(self, section, name, value, source=''):
453 def setconfig(self, section, name, value, source=''):
454 for cfg in (self._ocfg, self._tcfg, self._ucfg):
454 for cfg in (self._ocfg, self._tcfg, self._ucfg):
455 cfg.set(section, name, value, source)
455 cfg.set(section, name, value, source)
456 self.fixconfig(section=section)
456 self.fixconfig(section=section)
457 self._maybetweakdefaults()
457 self._maybetweakdefaults()
458
458
459 def _data(self, untrusted):
459 def _data(self, untrusted):
460 return untrusted and self._ucfg or self._tcfg
460 return untrusted and self._ucfg or self._tcfg
461
461
462 def configsource(self, section, name, untrusted=False):
462 def configsource(self, section, name, untrusted=False):
463 return self._data(untrusted).source(section, name)
463 return self._data(untrusted).source(section, name)
464
464
465 def config(self, section, name, default=_unset, untrusted=False):
465 def config(self, section, name, default=_unset, untrusted=False):
466 """return the plain string version of a config"""
466 """return the plain string version of a config"""
467 value = self._config(section, name, default=default,
467 value = self._config(section, name, default=default,
468 untrusted=untrusted)
468 untrusted=untrusted)
469 if value is _unset:
469 if value is _unset:
470 return None
470 return None
471 return value
471 return value
472
472
473 def _config(self, section, name, default=_unset, untrusted=False):
473 def _config(self, section, name, default=_unset, untrusted=False):
474 value = default
474 value = default
475 item = self._knownconfig.get(section, {}).get(name)
475 item = self._knownconfig.get(section, {}).get(name)
476 alternates = [(section, name)]
476 alternates = [(section, name)]
477
477
478 if item is not None:
478 if item is not None:
479 alternates.extend(item.alias)
479 alternates.extend(item.alias)
480 else:
481 msg = ("accessing unregistered config item: '%s.%s'")
482 msg %= (section, name)
483 self.develwarn(msg, 2, 'warn-config-unknown')
480
484
481 if default is _unset:
485 if default is _unset:
482 if item is None:
486 if item is None:
483 value = default
487 value = default
484 elif item.default is configitems.dynamicdefault:
488 elif item.default is configitems.dynamicdefault:
485 value = None
489 value = None
486 msg = "config item requires an explicit default value: '%s.%s'"
490 msg = "config item requires an explicit default value: '%s.%s'"
487 msg %= (section, name)
491 msg %= (section, name)
488 self.develwarn(msg, 2, 'warn-config-default')
492 self.develwarn(msg, 2, 'warn-config-default')
489 elif callable(item.default):
493 elif callable(item.default):
490 value = item.default()
494 value = item.default()
491 else:
495 else:
492 value = item.default
496 value = item.default
493 elif (item is not None
497 elif (item is not None
494 and item.default is not configitems.dynamicdefault):
498 and item.default is not configitems.dynamicdefault):
495 msg = ("specifying a default value for a registered "
499 msg = ("specifying a default value for a registered "
496 "config item: '%s.%s' '%s'")
500 "config item: '%s.%s' '%s'")
497 msg %= (section, name, default)
501 msg %= (section, name, default)
498 self.develwarn(msg, 2, 'warn-config-default')
502 self.develwarn(msg, 2, 'warn-config-default')
499
503
500 for s, n in alternates:
504 for s, n in alternates:
501 candidate = self._data(untrusted).get(s, n, None)
505 candidate = self._data(untrusted).get(s, n, None)
502 if candidate is not None:
506 if candidate is not None:
503 value = candidate
507 value = candidate
504 section = s
508 section = s
505 name = n
509 name = n
506 break
510 break
507
511
508 if self.debugflag and not untrusted and self._reportuntrusted:
512 if self.debugflag and not untrusted and self._reportuntrusted:
509 for s, n in alternates:
513 for s, n in alternates:
510 uvalue = self._ucfg.get(s, n)
514 uvalue = self._ucfg.get(s, n)
511 if uvalue is not None and uvalue != value:
515 if uvalue is not None and uvalue != value:
512 self.debug("ignoring untrusted configuration option "
516 self.debug("ignoring untrusted configuration option "
513 "%s.%s = %s\n" % (s, n, uvalue))
517 "%s.%s = %s\n" % (s, n, uvalue))
514 return value
518 return value
515
519
516 def configsuboptions(self, section, name, default=_unset, untrusted=False):
520 def configsuboptions(self, section, name, default=_unset, untrusted=False):
517 """Get a config option and all sub-options.
521 """Get a config option and all sub-options.
518
522
519 Some config options have sub-options that are declared with the
523 Some config options have sub-options that are declared with the
520 format "key:opt = value". This method is used to return the main
524 format "key:opt = value". This method is used to return the main
521 option and all its declared sub-options.
525 option and all its declared sub-options.
522
526
523 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
527 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
524 is a dict of defined sub-options where keys and values are strings.
528 is a dict of defined sub-options where keys and values are strings.
525 """
529 """
526 main = self.config(section, name, default, untrusted=untrusted)
530 main = self.config(section, name, default, untrusted=untrusted)
527 data = self._data(untrusted)
531 data = self._data(untrusted)
528 sub = {}
532 sub = {}
529 prefix = '%s:' % name
533 prefix = '%s:' % name
530 for k, v in data.items(section):
534 for k, v in data.items(section):
531 if k.startswith(prefix):
535 if k.startswith(prefix):
532 sub[k[len(prefix):]] = v
536 sub[k[len(prefix):]] = v
533
537
534 if self.debugflag and not untrusted and self._reportuntrusted:
538 if self.debugflag and not untrusted and self._reportuntrusted:
535 for k, v in sub.items():
539 for k, v in sub.items():
536 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
540 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
537 if uvalue is not None and uvalue != v:
541 if uvalue is not None and uvalue != v:
538 self.debug('ignoring untrusted configuration option '
542 self.debug('ignoring untrusted configuration option '
539 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
543 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
540
544
541 return main, sub
545 return main, sub
542
546
543 def configpath(self, section, name, default=_unset, untrusted=False):
547 def configpath(self, section, name, default=_unset, untrusted=False):
544 'get a path config item, expanded relative to repo root or config file'
548 'get a path config item, expanded relative to repo root or config file'
545 v = self.config(section, name, default, untrusted)
549 v = self.config(section, name, default, untrusted)
546 if v is None:
550 if v is None:
547 return None
551 return None
548 if not os.path.isabs(v) or "://" not in v:
552 if not os.path.isabs(v) or "://" not in v:
549 src = self.configsource(section, name, untrusted)
553 src = self.configsource(section, name, untrusted)
550 if ':' in src:
554 if ':' in src:
551 base = os.path.dirname(src.rsplit(':')[0])
555 base = os.path.dirname(src.rsplit(':')[0])
552 v = os.path.join(base, os.path.expanduser(v))
556 v = os.path.join(base, os.path.expanduser(v))
553 return v
557 return v
554
558
555 def configbool(self, section, name, default=_unset, untrusted=False):
559 def configbool(self, section, name, default=_unset, untrusted=False):
556 """parse a configuration element as a boolean
560 """parse a configuration element as a boolean
557
561
558 >>> u = ui(); s = b'foo'
562 >>> u = ui(); s = b'foo'
559 >>> u.setconfig(s, b'true', b'yes')
563 >>> u.setconfig(s, b'true', b'yes')
560 >>> u.configbool(s, b'true')
564 >>> u.configbool(s, b'true')
561 True
565 True
562 >>> u.setconfig(s, b'false', b'no')
566 >>> u.setconfig(s, b'false', b'no')
563 >>> u.configbool(s, b'false')
567 >>> u.configbool(s, b'false')
564 False
568 False
565 >>> u.configbool(s, b'unknown')
569 >>> u.configbool(s, b'unknown')
566 False
570 False
567 >>> u.configbool(s, b'unknown', True)
571 >>> u.configbool(s, b'unknown', True)
568 True
572 True
569 >>> u.setconfig(s, b'invalid', b'somevalue')
573 >>> u.setconfig(s, b'invalid', b'somevalue')
570 >>> u.configbool(s, b'invalid')
574 >>> u.configbool(s, b'invalid')
571 Traceback (most recent call last):
575 Traceback (most recent call last):
572 ...
576 ...
573 ConfigError: foo.invalid is not a boolean ('somevalue')
577 ConfigError: foo.invalid is not a boolean ('somevalue')
574 """
578 """
575
579
576 v = self._config(section, name, default, untrusted=untrusted)
580 v = self._config(section, name, default, untrusted=untrusted)
577 if v is None:
581 if v is None:
578 return v
582 return v
579 if v is _unset:
583 if v is _unset:
580 if default is _unset:
584 if default is _unset:
581 return False
585 return False
582 return default
586 return default
583 if isinstance(v, bool):
587 if isinstance(v, bool):
584 return v
588 return v
585 b = util.parsebool(v)
589 b = util.parsebool(v)
586 if b is None:
590 if b is None:
587 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
591 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
588 % (section, name, v))
592 % (section, name, v))
589 return b
593 return b
590
594
591 def configwith(self, convert, section, name, default=_unset,
595 def configwith(self, convert, section, name, default=_unset,
592 desc=None, untrusted=False):
596 desc=None, untrusted=False):
593 """parse a configuration element with a conversion function
597 """parse a configuration element with a conversion function
594
598
595 >>> u = ui(); s = b'foo'
599 >>> u = ui(); s = b'foo'
596 >>> u.setconfig(s, b'float1', b'42')
600 >>> u.setconfig(s, b'float1', b'42')
597 >>> u.configwith(float, s, b'float1')
601 >>> u.configwith(float, s, b'float1')
598 42.0
602 42.0
599 >>> u.setconfig(s, b'float2', b'-4.25')
603 >>> u.setconfig(s, b'float2', b'-4.25')
600 >>> u.configwith(float, s, b'float2')
604 >>> u.configwith(float, s, b'float2')
601 -4.25
605 -4.25
602 >>> u.configwith(float, s, b'unknown', 7)
606 >>> u.configwith(float, s, b'unknown', 7)
603 7.0
607 7.0
604 >>> u.setconfig(s, b'invalid', b'somevalue')
608 >>> u.setconfig(s, b'invalid', b'somevalue')
605 >>> u.configwith(float, s, b'invalid')
609 >>> u.configwith(float, s, b'invalid')
606 Traceback (most recent call last):
610 Traceback (most recent call last):
607 ...
611 ...
608 ConfigError: foo.invalid is not a valid float ('somevalue')
612 ConfigError: foo.invalid is not a valid float ('somevalue')
609 >>> u.configwith(float, s, b'invalid', desc=b'womble')
613 >>> u.configwith(float, s, b'invalid', desc=b'womble')
610 Traceback (most recent call last):
614 Traceback (most recent call last):
611 ...
615 ...
612 ConfigError: foo.invalid is not a valid womble ('somevalue')
616 ConfigError: foo.invalid is not a valid womble ('somevalue')
613 """
617 """
614
618
615 v = self.config(section, name, default, untrusted)
619 v = self.config(section, name, default, untrusted)
616 if v is None:
620 if v is None:
617 return v # do not attempt to convert None
621 return v # do not attempt to convert None
618 try:
622 try:
619 return convert(v)
623 return convert(v)
620 except (ValueError, error.ParseError):
624 except (ValueError, error.ParseError):
621 if desc is None:
625 if desc is None:
622 desc = pycompat.sysbytes(convert.__name__)
626 desc = pycompat.sysbytes(convert.__name__)
623 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
627 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
624 % (section, name, desc, v))
628 % (section, name, desc, v))
625
629
626 def configint(self, section, name, default=_unset, untrusted=False):
630 def configint(self, section, name, default=_unset, untrusted=False):
627 """parse a configuration element as an integer
631 """parse a configuration element as an integer
628
632
629 >>> u = ui(); s = b'foo'
633 >>> u = ui(); s = b'foo'
630 >>> u.setconfig(s, b'int1', b'42')
634 >>> u.setconfig(s, b'int1', b'42')
631 >>> u.configint(s, b'int1')
635 >>> u.configint(s, b'int1')
632 42
636 42
633 >>> u.setconfig(s, b'int2', b'-42')
637 >>> u.setconfig(s, b'int2', b'-42')
634 >>> u.configint(s, b'int2')
638 >>> u.configint(s, b'int2')
635 -42
639 -42
636 >>> u.configint(s, b'unknown', 7)
640 >>> u.configint(s, b'unknown', 7)
637 7
641 7
638 >>> u.setconfig(s, b'invalid', b'somevalue')
642 >>> u.setconfig(s, b'invalid', b'somevalue')
639 >>> u.configint(s, b'invalid')
643 >>> u.configint(s, b'invalid')
640 Traceback (most recent call last):
644 Traceback (most recent call last):
641 ...
645 ...
642 ConfigError: foo.invalid is not a valid integer ('somevalue')
646 ConfigError: foo.invalid is not a valid integer ('somevalue')
643 """
647 """
644
648
645 return self.configwith(int, section, name, default, 'integer',
649 return self.configwith(int, section, name, default, 'integer',
646 untrusted)
650 untrusted)
647
651
648 def configbytes(self, section, name, default=_unset, untrusted=False):
652 def configbytes(self, section, name, default=_unset, untrusted=False):
649 """parse a configuration element as a quantity in bytes
653 """parse a configuration element as a quantity in bytes
650
654
651 Units can be specified as b (bytes), k or kb (kilobytes), m or
655 Units can be specified as b (bytes), k or kb (kilobytes), m or
652 mb (megabytes), g or gb (gigabytes).
656 mb (megabytes), g or gb (gigabytes).
653
657
654 >>> u = ui(); s = b'foo'
658 >>> u = ui(); s = b'foo'
655 >>> u.setconfig(s, b'val1', b'42')
659 >>> u.setconfig(s, b'val1', b'42')
656 >>> u.configbytes(s, b'val1')
660 >>> u.configbytes(s, b'val1')
657 42
661 42
658 >>> u.setconfig(s, b'val2', b'42.5 kb')
662 >>> u.setconfig(s, b'val2', b'42.5 kb')
659 >>> u.configbytes(s, b'val2')
663 >>> u.configbytes(s, b'val2')
660 43520
664 43520
661 >>> u.configbytes(s, b'unknown', b'7 MB')
665 >>> u.configbytes(s, b'unknown', b'7 MB')
662 7340032
666 7340032
663 >>> u.setconfig(s, b'invalid', b'somevalue')
667 >>> u.setconfig(s, b'invalid', b'somevalue')
664 >>> u.configbytes(s, b'invalid')
668 >>> u.configbytes(s, b'invalid')
665 Traceback (most recent call last):
669 Traceback (most recent call last):
666 ...
670 ...
667 ConfigError: foo.invalid is not a byte quantity ('somevalue')
671 ConfigError: foo.invalid is not a byte quantity ('somevalue')
668 """
672 """
669
673
670 value = self._config(section, name, default, untrusted)
674 value = self._config(section, name, default, untrusted)
671 if value is _unset:
675 if value is _unset:
672 if default is _unset:
676 if default is _unset:
673 default = 0
677 default = 0
674 value = default
678 value = default
675 if not isinstance(value, bytes):
679 if not isinstance(value, bytes):
676 return value
680 return value
677 try:
681 try:
678 return util.sizetoint(value)
682 return util.sizetoint(value)
679 except error.ParseError:
683 except error.ParseError:
680 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
684 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
681 % (section, name, value))
685 % (section, name, value))
682
686
683 def configlist(self, section, name, default=_unset, untrusted=False):
687 def configlist(self, section, name, default=_unset, untrusted=False):
684 """parse a configuration element as a list of comma/space separated
688 """parse a configuration element as a list of comma/space separated
685 strings
689 strings
686
690
687 >>> u = ui(); s = b'foo'
691 >>> u = ui(); s = b'foo'
688 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
692 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
689 >>> u.configlist(s, b'list1')
693 >>> u.configlist(s, b'list1')
690 ['this', 'is', 'a small', 'test']
694 ['this', 'is', 'a small', 'test']
691 """
695 """
692 # default is not always a list
696 # default is not always a list
693 v = self.configwith(config.parselist, section, name, default,
697 v = self.configwith(config.parselist, section, name, default,
694 'list', untrusted)
698 'list', untrusted)
695 if isinstance(v, bytes):
699 if isinstance(v, bytes):
696 return config.parselist(v)
700 return config.parselist(v)
697 elif v is None:
701 elif v is None:
698 return []
702 return []
699 return v
703 return v
700
704
701 def configdate(self, section, name, default=_unset, untrusted=False):
705 def configdate(self, section, name, default=_unset, untrusted=False):
702 """parse a configuration element as a tuple of ints
706 """parse a configuration element as a tuple of ints
703
707
704 >>> u = ui(); s = b'foo'
708 >>> u = ui(); s = b'foo'
705 >>> u.setconfig(s, b'date', b'0 0')
709 >>> u.setconfig(s, b'date', b'0 0')
706 >>> u.configdate(s, b'date')
710 >>> u.configdate(s, b'date')
707 (0, 0)
711 (0, 0)
708 """
712 """
709 if self.config(section, name, default, untrusted):
713 if self.config(section, name, default, untrusted):
710 return self.configwith(util.parsedate, section, name, default,
714 return self.configwith(util.parsedate, section, name, default,
711 'date', untrusted)
715 'date', untrusted)
712 if default is _unset:
716 if default is _unset:
713 return None
717 return None
714 return default
718 return default
715
719
716 def hasconfig(self, section, name, untrusted=False):
720 def hasconfig(self, section, name, untrusted=False):
717 return self._data(untrusted).hasitem(section, name)
721 return self._data(untrusted).hasitem(section, name)
718
722
719 def has_section(self, section, untrusted=False):
723 def has_section(self, section, untrusted=False):
720 '''tell whether section exists in config.'''
724 '''tell whether section exists in config.'''
721 return section in self._data(untrusted)
725 return section in self._data(untrusted)
722
726
723 def configitems(self, section, untrusted=False, ignoresub=False):
727 def configitems(self, section, untrusted=False, ignoresub=False):
724 items = self._data(untrusted).items(section)
728 items = self._data(untrusted).items(section)
725 if ignoresub:
729 if ignoresub:
726 newitems = {}
730 newitems = {}
727 for k, v in items:
731 for k, v in items:
728 if ':' not in k:
732 if ':' not in k:
729 newitems[k] = v
733 newitems[k] = v
730 items = newitems.items()
734 items = newitems.items()
731 if self.debugflag and not untrusted and self._reportuntrusted:
735 if self.debugflag and not untrusted and self._reportuntrusted:
732 for k, v in self._ucfg.items(section):
736 for k, v in self._ucfg.items(section):
733 if self._tcfg.get(section, k) != v:
737 if self._tcfg.get(section, k) != v:
734 self.debug("ignoring untrusted configuration option "
738 self.debug("ignoring untrusted configuration option "
735 "%s.%s = %s\n" % (section, k, v))
739 "%s.%s = %s\n" % (section, k, v))
736 return items
740 return items
737
741
738 def walkconfig(self, untrusted=False):
742 def walkconfig(self, untrusted=False):
739 cfg = self._data(untrusted)
743 cfg = self._data(untrusted)
740 for section in cfg.sections():
744 for section in cfg.sections():
741 for name, value in self.configitems(section, untrusted):
745 for name, value in self.configitems(section, untrusted):
742 yield section, name, value
746 yield section, name, value
743
747
744 def plain(self, feature=None):
748 def plain(self, feature=None):
745 '''is plain mode active?
749 '''is plain mode active?
746
750
747 Plain mode means that all configuration variables which affect
751 Plain mode means that all configuration variables which affect
748 the behavior and output of Mercurial should be
752 the behavior and output of Mercurial should be
749 ignored. Additionally, the output should be stable,
753 ignored. Additionally, the output should be stable,
750 reproducible and suitable for use in scripts or applications.
754 reproducible and suitable for use in scripts or applications.
751
755
752 The only way to trigger plain mode is by setting either the
756 The only way to trigger plain mode is by setting either the
753 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
757 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
754
758
755 The return value can either be
759 The return value can either be
756 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
760 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
757 - True otherwise
761 - True otherwise
758 '''
762 '''
759 if ('HGPLAIN' not in encoding.environ and
763 if ('HGPLAIN' not in encoding.environ and
760 'HGPLAINEXCEPT' not in encoding.environ):
764 'HGPLAINEXCEPT' not in encoding.environ):
761 return False
765 return False
762 exceptions = encoding.environ.get('HGPLAINEXCEPT',
766 exceptions = encoding.environ.get('HGPLAINEXCEPT',
763 '').strip().split(',')
767 '').strip().split(',')
764 if feature and exceptions:
768 if feature and exceptions:
765 return feature not in exceptions
769 return feature not in exceptions
766 return True
770 return True
767
771
768 def username(self, acceptempty=False):
772 def username(self, acceptempty=False):
769 """Return default username to be used in commits.
773 """Return default username to be used in commits.
770
774
771 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
775 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
772 and stop searching if one of these is set.
776 and stop searching if one of these is set.
773 If not found and acceptempty is True, returns None.
777 If not found and acceptempty is True, returns None.
774 If not found and ui.askusername is True, ask the user, else use
778 If not found and ui.askusername is True, ask the user, else use
775 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
779 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
776 If no username could be found, raise an Abort error.
780 If no username could be found, raise an Abort error.
777 """
781 """
778 user = encoding.environ.get("HGUSER")
782 user = encoding.environ.get("HGUSER")
779 if user is None:
783 if user is None:
780 user = self.config("ui", "username")
784 user = self.config("ui", "username")
781 if user is not None:
785 if user is not None:
782 user = os.path.expandvars(user)
786 user = os.path.expandvars(user)
783 if user is None:
787 if user is None:
784 user = encoding.environ.get("EMAIL")
788 user = encoding.environ.get("EMAIL")
785 if user is None and acceptempty:
789 if user is None and acceptempty:
786 return user
790 return user
787 if user is None and self.configbool("ui", "askusername"):
791 if user is None and self.configbool("ui", "askusername"):
788 user = self.prompt(_("enter a commit username:"), default=None)
792 user = self.prompt(_("enter a commit username:"), default=None)
789 if user is None and not self.interactive():
793 if user is None and not self.interactive():
790 try:
794 try:
791 user = '%s@%s' % (util.getuser(), socket.getfqdn())
795 user = '%s@%s' % (util.getuser(), socket.getfqdn())
792 self.warn(_("no username found, using '%s' instead\n") % user)
796 self.warn(_("no username found, using '%s' instead\n") % user)
793 except KeyError:
797 except KeyError:
794 pass
798 pass
795 if not user:
799 if not user:
796 raise error.Abort(_('no username supplied'),
800 raise error.Abort(_('no username supplied'),
797 hint=_("use 'hg config --edit' "
801 hint=_("use 'hg config --edit' "
798 'to set your username'))
802 'to set your username'))
799 if "\n" in user:
803 if "\n" in user:
800 raise error.Abort(_("username %s contains a newline\n")
804 raise error.Abort(_("username %s contains a newline\n")
801 % repr(user))
805 % repr(user))
802 return user
806 return user
803
807
804 def shortuser(self, user):
808 def shortuser(self, user):
805 """Return a short representation of a user name or email address."""
809 """Return a short representation of a user name or email address."""
806 if not self.verbose:
810 if not self.verbose:
807 user = util.shortuser(user)
811 user = util.shortuser(user)
808 return user
812 return user
809
813
810 def expandpath(self, loc, default=None):
814 def expandpath(self, loc, default=None):
811 """Return repository location relative to cwd or from [paths]"""
815 """Return repository location relative to cwd or from [paths]"""
812 try:
816 try:
813 p = self.paths.getpath(loc)
817 p = self.paths.getpath(loc)
814 if p:
818 if p:
815 return p.rawloc
819 return p.rawloc
816 except error.RepoError:
820 except error.RepoError:
817 pass
821 pass
818
822
819 if default:
823 if default:
820 try:
824 try:
821 p = self.paths.getpath(default)
825 p = self.paths.getpath(default)
822 if p:
826 if p:
823 return p.rawloc
827 return p.rawloc
824 except error.RepoError:
828 except error.RepoError:
825 pass
829 pass
826
830
827 return loc
831 return loc
828
832
829 @util.propertycache
833 @util.propertycache
830 def paths(self):
834 def paths(self):
831 return paths(self)
835 return paths(self)
832
836
833 def pushbuffer(self, error=False, subproc=False, labeled=False):
837 def pushbuffer(self, error=False, subproc=False, labeled=False):
834 """install a buffer to capture standard output of the ui object
838 """install a buffer to capture standard output of the ui object
835
839
836 If error is True, the error output will be captured too.
840 If error is True, the error output will be captured too.
837
841
838 If subproc is True, output from subprocesses (typically hooks) will be
842 If subproc is True, output from subprocesses (typically hooks) will be
839 captured too.
843 captured too.
840
844
841 If labeled is True, any labels associated with buffered
845 If labeled is True, any labels associated with buffered
842 output will be handled. By default, this has no effect
846 output will be handled. By default, this has no effect
843 on the output returned, but extensions and GUI tools may
847 on the output returned, but extensions and GUI tools may
844 handle this argument and returned styled output. If output
848 handle this argument and returned styled output. If output
845 is being buffered so it can be captured and parsed or
849 is being buffered so it can be captured and parsed or
846 processed, labeled should not be set to True.
850 processed, labeled should not be set to True.
847 """
851 """
848 self._buffers.append([])
852 self._buffers.append([])
849 self._bufferstates.append((error, subproc, labeled))
853 self._bufferstates.append((error, subproc, labeled))
850 self._bufferapplylabels = labeled
854 self._bufferapplylabels = labeled
851
855
852 def popbuffer(self):
856 def popbuffer(self):
853 '''pop the last buffer and return the buffered output'''
857 '''pop the last buffer and return the buffered output'''
854 self._bufferstates.pop()
858 self._bufferstates.pop()
855 if self._bufferstates:
859 if self._bufferstates:
856 self._bufferapplylabels = self._bufferstates[-1][2]
860 self._bufferapplylabels = self._bufferstates[-1][2]
857 else:
861 else:
858 self._bufferapplylabels = None
862 self._bufferapplylabels = None
859
863
860 return "".join(self._buffers.pop())
864 return "".join(self._buffers.pop())
861
865
862 def write(self, *args, **opts):
866 def write(self, *args, **opts):
863 '''write args to output
867 '''write args to output
864
868
865 By default, this method simply writes to the buffer or stdout.
869 By default, this method simply writes to the buffer or stdout.
866 Color mode can be set on the UI class to have the output decorated
870 Color mode can be set on the UI class to have the output decorated
867 with color modifier before being written to stdout.
871 with color modifier before being written to stdout.
868
872
869 The color used is controlled by an optional keyword argument, "label".
873 The color used is controlled by an optional keyword argument, "label".
870 This should be a string containing label names separated by space.
874 This should be a string containing label names separated by space.
871 Label names take the form of "topic.type". For example, ui.debug()
875 Label names take the form of "topic.type". For example, ui.debug()
872 issues a label of "ui.debug".
876 issues a label of "ui.debug".
873
877
874 When labeling output for a specific command, a label of
878 When labeling output for a specific command, a label of
875 "cmdname.type" is recommended. For example, status issues
879 "cmdname.type" is recommended. For example, status issues
876 a label of "status.modified" for modified files.
880 a label of "status.modified" for modified files.
877 '''
881 '''
878 if self._buffers and not opts.get('prompt', False):
882 if self._buffers and not opts.get('prompt', False):
879 if self._bufferapplylabels:
883 if self._bufferapplylabels:
880 label = opts.get('label', '')
884 label = opts.get('label', '')
881 self._buffers[-1].extend(self.label(a, label) for a in args)
885 self._buffers[-1].extend(self.label(a, label) for a in args)
882 else:
886 else:
883 self._buffers[-1].extend(args)
887 self._buffers[-1].extend(args)
884 elif self._colormode == 'win32':
888 elif self._colormode == 'win32':
885 # windows color printing is its own can of crab, defer to
889 # windows color printing is its own can of crab, defer to
886 # the color module and that is it.
890 # the color module and that is it.
887 color.win32print(self, self._write, *args, **opts)
891 color.win32print(self, self._write, *args, **opts)
888 else:
892 else:
889 msgs = args
893 msgs = args
890 if self._colormode is not None:
894 if self._colormode is not None:
891 label = opts.get('label', '')
895 label = opts.get('label', '')
892 msgs = [self.label(a, label) for a in args]
896 msgs = [self.label(a, label) for a in args]
893 self._write(*msgs, **opts)
897 self._write(*msgs, **opts)
894
898
895 def _write(self, *msgs, **opts):
899 def _write(self, *msgs, **opts):
896 self._progclear()
900 self._progclear()
897 # opencode timeblockedsection because this is a critical path
901 # opencode timeblockedsection because this is a critical path
898 starttime = util.timer()
902 starttime = util.timer()
899 try:
903 try:
900 for a in msgs:
904 for a in msgs:
901 self.fout.write(a)
905 self.fout.write(a)
902 except IOError as err:
906 except IOError as err:
903 raise error.StdioError(err)
907 raise error.StdioError(err)
904 finally:
908 finally:
905 self._blockedtimes['stdio_blocked'] += \
909 self._blockedtimes['stdio_blocked'] += \
906 (util.timer() - starttime) * 1000
910 (util.timer() - starttime) * 1000
907
911
908 def write_err(self, *args, **opts):
912 def write_err(self, *args, **opts):
909 self._progclear()
913 self._progclear()
910 if self._bufferstates and self._bufferstates[-1][0]:
914 if self._bufferstates and self._bufferstates[-1][0]:
911 self.write(*args, **opts)
915 self.write(*args, **opts)
912 elif self._colormode == 'win32':
916 elif self._colormode == 'win32':
913 # windows color printing is its own can of crab, defer to
917 # windows color printing is its own can of crab, defer to
914 # the color module and that is it.
918 # the color module and that is it.
915 color.win32print(self, self._write_err, *args, **opts)
919 color.win32print(self, self._write_err, *args, **opts)
916 else:
920 else:
917 msgs = args
921 msgs = args
918 if self._colormode is not None:
922 if self._colormode is not None:
919 label = opts.get('label', '')
923 label = opts.get('label', '')
920 msgs = [self.label(a, label) for a in args]
924 msgs = [self.label(a, label) for a in args]
921 self._write_err(*msgs, **opts)
925 self._write_err(*msgs, **opts)
922
926
923 def _write_err(self, *msgs, **opts):
927 def _write_err(self, *msgs, **opts):
924 try:
928 try:
925 with self.timeblockedsection('stdio'):
929 with self.timeblockedsection('stdio'):
926 if not getattr(self.fout, 'closed', False):
930 if not getattr(self.fout, 'closed', False):
927 self.fout.flush()
931 self.fout.flush()
928 for a in msgs:
932 for a in msgs:
929 self.ferr.write(a)
933 self.ferr.write(a)
930 # stderr may be buffered under win32 when redirected to files,
934 # stderr may be buffered under win32 when redirected to files,
931 # including stdout.
935 # including stdout.
932 if not getattr(self.ferr, 'closed', False):
936 if not getattr(self.ferr, 'closed', False):
933 self.ferr.flush()
937 self.ferr.flush()
934 except IOError as inst:
938 except IOError as inst:
935 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
939 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
936 raise error.StdioError(inst)
940 raise error.StdioError(inst)
937
941
938 def flush(self):
942 def flush(self):
939 # opencode timeblockedsection because this is a critical path
943 # opencode timeblockedsection because this is a critical path
940 starttime = util.timer()
944 starttime = util.timer()
941 try:
945 try:
942 try:
946 try:
943 self.fout.flush()
947 self.fout.flush()
944 except IOError as err:
948 except IOError as err:
945 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
949 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
946 raise error.StdioError(err)
950 raise error.StdioError(err)
947 finally:
951 finally:
948 try:
952 try:
949 self.ferr.flush()
953 self.ferr.flush()
950 except IOError as err:
954 except IOError as err:
951 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
955 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
952 raise error.StdioError(err)
956 raise error.StdioError(err)
953 finally:
957 finally:
954 self._blockedtimes['stdio_blocked'] += \
958 self._blockedtimes['stdio_blocked'] += \
955 (util.timer() - starttime) * 1000
959 (util.timer() - starttime) * 1000
956
960
957 def _isatty(self, fh):
961 def _isatty(self, fh):
958 if self.configbool('ui', 'nontty'):
962 if self.configbool('ui', 'nontty'):
959 return False
963 return False
960 return util.isatty(fh)
964 return util.isatty(fh)
961
965
962 def disablepager(self):
966 def disablepager(self):
963 self._disablepager = True
967 self._disablepager = True
964
968
965 def pager(self, command):
969 def pager(self, command):
966 """Start a pager for subsequent command output.
970 """Start a pager for subsequent command output.
967
971
968 Commands which produce a long stream of output should call
972 Commands which produce a long stream of output should call
969 this function to activate the user's preferred pagination
973 this function to activate the user's preferred pagination
970 mechanism (which may be no pager). Calling this function
974 mechanism (which may be no pager). Calling this function
971 precludes any future use of interactive functionality, such as
975 precludes any future use of interactive functionality, such as
972 prompting the user or activating curses.
976 prompting the user or activating curses.
973
977
974 Args:
978 Args:
975 command: The full, non-aliased name of the command. That is, "log"
979 command: The full, non-aliased name of the command. That is, "log"
976 not "history, "summary" not "summ", etc.
980 not "history, "summary" not "summ", etc.
977 """
981 """
978 if (self._disablepager
982 if (self._disablepager
979 or self.pageractive):
983 or self.pageractive):
980 # how pager should do is already determined
984 # how pager should do is already determined
981 return
985 return
982
986
983 if not command.startswith('internal-always-') and (
987 if not command.startswith('internal-always-') and (
984 # explicit --pager=on (= 'internal-always-' prefix) should
988 # explicit --pager=on (= 'internal-always-' prefix) should
985 # take precedence over disabling factors below
989 # take precedence over disabling factors below
986 command in self.configlist('pager', 'ignore')
990 command in self.configlist('pager', 'ignore')
987 or not self.configbool('ui', 'paginate')
991 or not self.configbool('ui', 'paginate')
988 or not self.configbool('pager', 'attend-' + command, True)
992 or not self.configbool('pager', 'attend-' + command, True)
989 # TODO: if we want to allow HGPLAINEXCEPT=pager,
993 # TODO: if we want to allow HGPLAINEXCEPT=pager,
990 # formatted() will need some adjustment.
994 # formatted() will need some adjustment.
991 or not self.formatted()
995 or not self.formatted()
992 or self.plain()
996 or self.plain()
993 or self._buffers
997 or self._buffers
994 # TODO: expose debugger-enabled on the UI object
998 # TODO: expose debugger-enabled on the UI object
995 or '--debugger' in pycompat.sysargv):
999 or '--debugger' in pycompat.sysargv):
996 # We only want to paginate if the ui appears to be
1000 # We only want to paginate if the ui appears to be
997 # interactive, the user didn't say HGPLAIN or
1001 # interactive, the user didn't say HGPLAIN or
998 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1002 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
999 return
1003 return
1000
1004
1001 pagercmd = self.config('pager', 'pager', rcutil.fallbackpager)
1005 pagercmd = self.config('pager', 'pager', rcutil.fallbackpager)
1002 if not pagercmd:
1006 if not pagercmd:
1003 return
1007 return
1004
1008
1005 pagerenv = {}
1009 pagerenv = {}
1006 for name, value in rcutil.defaultpagerenv().items():
1010 for name, value in rcutil.defaultpagerenv().items():
1007 if name not in encoding.environ:
1011 if name not in encoding.environ:
1008 pagerenv[name] = value
1012 pagerenv[name] = value
1009
1013
1010 self.debug('starting pager for command %r\n' % command)
1014 self.debug('starting pager for command %r\n' % command)
1011 self.flush()
1015 self.flush()
1012
1016
1013 wasformatted = self.formatted()
1017 wasformatted = self.formatted()
1014 if util.safehasattr(signal, "SIGPIPE"):
1018 if util.safehasattr(signal, "SIGPIPE"):
1015 signal.signal(signal.SIGPIPE, _catchterm)
1019 signal.signal(signal.SIGPIPE, _catchterm)
1016 if self._runpager(pagercmd, pagerenv):
1020 if self._runpager(pagercmd, pagerenv):
1017 self.pageractive = True
1021 self.pageractive = True
1018 # Preserve the formatted-ness of the UI. This is important
1022 # Preserve the formatted-ness of the UI. This is important
1019 # because we mess with stdout, which might confuse
1023 # because we mess with stdout, which might confuse
1020 # auto-detection of things being formatted.
1024 # auto-detection of things being formatted.
1021 self.setconfig('ui', 'formatted', wasformatted, 'pager')
1025 self.setconfig('ui', 'formatted', wasformatted, 'pager')
1022 self.setconfig('ui', 'interactive', False, 'pager')
1026 self.setconfig('ui', 'interactive', False, 'pager')
1023
1027
1024 # If pagermode differs from color.mode, reconfigure color now that
1028 # If pagermode differs from color.mode, reconfigure color now that
1025 # pageractive is set.
1029 # pageractive is set.
1026 cm = self._colormode
1030 cm = self._colormode
1027 if cm != self.config('color', 'pagermode', cm):
1031 if cm != self.config('color', 'pagermode', cm):
1028 color.setup(self)
1032 color.setup(self)
1029 else:
1033 else:
1030 # If the pager can't be spawned in dispatch when --pager=on is
1034 # If the pager can't be spawned in dispatch when --pager=on is
1031 # given, don't try again when the command runs, to avoid a duplicate
1035 # given, don't try again when the command runs, to avoid a duplicate
1032 # warning about a missing pager command.
1036 # warning about a missing pager command.
1033 self.disablepager()
1037 self.disablepager()
1034
1038
1035 def _runpager(self, command, env=None):
1039 def _runpager(self, command, env=None):
1036 """Actually start the pager and set up file descriptors.
1040 """Actually start the pager and set up file descriptors.
1037
1041
1038 This is separate in part so that extensions (like chg) can
1042 This is separate in part so that extensions (like chg) can
1039 override how a pager is invoked.
1043 override how a pager is invoked.
1040 """
1044 """
1041 if command == 'cat':
1045 if command == 'cat':
1042 # Save ourselves some work.
1046 # Save ourselves some work.
1043 return False
1047 return False
1044 # If the command doesn't contain any of these characters, we
1048 # If the command doesn't contain any of these characters, we
1045 # assume it's a binary and exec it directly. This means for
1049 # assume it's a binary and exec it directly. This means for
1046 # simple pager command configurations, we can degrade
1050 # simple pager command configurations, we can degrade
1047 # gracefully and tell the user about their broken pager.
1051 # gracefully and tell the user about their broken pager.
1048 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
1052 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
1049
1053
1050 if pycompat.iswindows and not shell:
1054 if pycompat.iswindows and not shell:
1051 # Window's built-in `more` cannot be invoked with shell=False, but
1055 # Window's built-in `more` cannot be invoked with shell=False, but
1052 # its `more.com` can. Hide this implementation detail from the
1056 # its `more.com` can. Hide this implementation detail from the
1053 # user so we can also get sane bad PAGER behavior. MSYS has
1057 # user so we can also get sane bad PAGER behavior. MSYS has
1054 # `more.exe`, so do a cmd.exe style resolution of the executable to
1058 # `more.exe`, so do a cmd.exe style resolution of the executable to
1055 # determine which one to use.
1059 # determine which one to use.
1056 fullcmd = util.findexe(command)
1060 fullcmd = util.findexe(command)
1057 if not fullcmd:
1061 if not fullcmd:
1058 self.warn(_("missing pager command '%s', skipping pager\n")
1062 self.warn(_("missing pager command '%s', skipping pager\n")
1059 % command)
1063 % command)
1060 return False
1064 return False
1061
1065
1062 command = fullcmd
1066 command = fullcmd
1063
1067
1064 try:
1068 try:
1065 pager = subprocess.Popen(
1069 pager = subprocess.Popen(
1066 command, shell=shell, bufsize=-1,
1070 command, shell=shell, bufsize=-1,
1067 close_fds=util.closefds, stdin=subprocess.PIPE,
1071 close_fds=util.closefds, stdin=subprocess.PIPE,
1068 stdout=util.stdout, stderr=util.stderr,
1072 stdout=util.stdout, stderr=util.stderr,
1069 env=util.shellenviron(env))
1073 env=util.shellenviron(env))
1070 except OSError as e:
1074 except OSError as e:
1071 if e.errno == errno.ENOENT and not shell:
1075 if e.errno == errno.ENOENT and not shell:
1072 self.warn(_("missing pager command '%s', skipping pager\n")
1076 self.warn(_("missing pager command '%s', skipping pager\n")
1073 % command)
1077 % command)
1074 return False
1078 return False
1075 raise
1079 raise
1076
1080
1077 # back up original file descriptors
1081 # back up original file descriptors
1078 stdoutfd = os.dup(util.stdout.fileno())
1082 stdoutfd = os.dup(util.stdout.fileno())
1079 stderrfd = os.dup(util.stderr.fileno())
1083 stderrfd = os.dup(util.stderr.fileno())
1080
1084
1081 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
1085 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
1082 if self._isatty(util.stderr):
1086 if self._isatty(util.stderr):
1083 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
1087 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
1084
1088
1085 @self.atexit
1089 @self.atexit
1086 def killpager():
1090 def killpager():
1087 if util.safehasattr(signal, "SIGINT"):
1091 if util.safehasattr(signal, "SIGINT"):
1088 signal.signal(signal.SIGINT, signal.SIG_IGN)
1092 signal.signal(signal.SIGINT, signal.SIG_IGN)
1089 # restore original fds, closing pager.stdin copies in the process
1093 # restore original fds, closing pager.stdin copies in the process
1090 os.dup2(stdoutfd, util.stdout.fileno())
1094 os.dup2(stdoutfd, util.stdout.fileno())
1091 os.dup2(stderrfd, util.stderr.fileno())
1095 os.dup2(stderrfd, util.stderr.fileno())
1092 pager.stdin.close()
1096 pager.stdin.close()
1093 pager.wait()
1097 pager.wait()
1094
1098
1095 return True
1099 return True
1096
1100
1097 def atexit(self, func, *args, **kwargs):
1101 def atexit(self, func, *args, **kwargs):
1098 '''register a function to run after dispatching a request
1102 '''register a function to run after dispatching a request
1099
1103
1100 Handlers do not stay registered across request boundaries.'''
1104 Handlers do not stay registered across request boundaries.'''
1101 self._exithandlers.append((func, args, kwargs))
1105 self._exithandlers.append((func, args, kwargs))
1102 return func
1106 return func
1103
1107
1104 def interface(self, feature):
1108 def interface(self, feature):
1105 """what interface to use for interactive console features?
1109 """what interface to use for interactive console features?
1106
1110
1107 The interface is controlled by the value of `ui.interface` but also by
1111 The interface is controlled by the value of `ui.interface` but also by
1108 the value of feature-specific configuration. For example:
1112 the value of feature-specific configuration. For example:
1109
1113
1110 ui.interface.histedit = text
1114 ui.interface.histedit = text
1111 ui.interface.chunkselector = curses
1115 ui.interface.chunkselector = curses
1112
1116
1113 Here the features are "histedit" and "chunkselector".
1117 Here the features are "histedit" and "chunkselector".
1114
1118
1115 The configuration above means that the default interfaces for commands
1119 The configuration above means that the default interfaces for commands
1116 is curses, the interface for histedit is text and the interface for
1120 is curses, the interface for histedit is text and the interface for
1117 selecting chunk is crecord (the best curses interface available).
1121 selecting chunk is crecord (the best curses interface available).
1118
1122
1119 Consider the following example:
1123 Consider the following example:
1120 ui.interface = curses
1124 ui.interface = curses
1121 ui.interface.histedit = text
1125 ui.interface.histedit = text
1122
1126
1123 Then histedit will use the text interface and chunkselector will use
1127 Then histedit will use the text interface and chunkselector will use
1124 the default curses interface (crecord at the moment).
1128 the default curses interface (crecord at the moment).
1125 """
1129 """
1126 alldefaults = frozenset(["text", "curses"])
1130 alldefaults = frozenset(["text", "curses"])
1127
1131
1128 featureinterfaces = {
1132 featureinterfaces = {
1129 "chunkselector": [
1133 "chunkselector": [
1130 "text",
1134 "text",
1131 "curses",
1135 "curses",
1132 ]
1136 ]
1133 }
1137 }
1134
1138
1135 # Feature-specific interface
1139 # Feature-specific interface
1136 if feature not in featureinterfaces.keys():
1140 if feature not in featureinterfaces.keys():
1137 # Programming error, not user error
1141 # Programming error, not user error
1138 raise ValueError("Unknown feature requested %s" % feature)
1142 raise ValueError("Unknown feature requested %s" % feature)
1139
1143
1140 availableinterfaces = frozenset(featureinterfaces[feature])
1144 availableinterfaces = frozenset(featureinterfaces[feature])
1141 if alldefaults > availableinterfaces:
1145 if alldefaults > availableinterfaces:
1142 # Programming error, not user error. We need a use case to
1146 # Programming error, not user error. We need a use case to
1143 # define the right thing to do here.
1147 # define the right thing to do here.
1144 raise ValueError(
1148 raise ValueError(
1145 "Feature %s does not handle all default interfaces" %
1149 "Feature %s does not handle all default interfaces" %
1146 feature)
1150 feature)
1147
1151
1148 if self.plain():
1152 if self.plain():
1149 return "text"
1153 return "text"
1150
1154
1151 # Default interface for all the features
1155 # Default interface for all the features
1152 defaultinterface = "text"
1156 defaultinterface = "text"
1153 i = self.config("ui", "interface")
1157 i = self.config("ui", "interface")
1154 if i in alldefaults:
1158 if i in alldefaults:
1155 defaultinterface = i
1159 defaultinterface = i
1156
1160
1157 choseninterface = defaultinterface
1161 choseninterface = defaultinterface
1158 f = self.config("ui", "interface.%s" % feature)
1162 f = self.config("ui", "interface.%s" % feature)
1159 if f in availableinterfaces:
1163 if f in availableinterfaces:
1160 choseninterface = f
1164 choseninterface = f
1161
1165
1162 if i is not None and defaultinterface != i:
1166 if i is not None and defaultinterface != i:
1163 if f is not None:
1167 if f is not None:
1164 self.warn(_("invalid value for ui.interface: %s\n") %
1168 self.warn(_("invalid value for ui.interface: %s\n") %
1165 (i,))
1169 (i,))
1166 else:
1170 else:
1167 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1171 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1168 (i, choseninterface))
1172 (i, choseninterface))
1169 if f is not None and choseninterface != f:
1173 if f is not None and choseninterface != f:
1170 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1174 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1171 (feature, f, choseninterface))
1175 (feature, f, choseninterface))
1172
1176
1173 return choseninterface
1177 return choseninterface
1174
1178
1175 def interactive(self):
1179 def interactive(self):
1176 '''is interactive input allowed?
1180 '''is interactive input allowed?
1177
1181
1178 An interactive session is a session where input can be reasonably read
1182 An interactive session is a session where input can be reasonably read
1179 from `sys.stdin'. If this function returns false, any attempt to read
1183 from `sys.stdin'. If this function returns false, any attempt to read
1180 from stdin should fail with an error, unless a sensible default has been
1184 from stdin should fail with an error, unless a sensible default has been
1181 specified.
1185 specified.
1182
1186
1183 Interactiveness is triggered by the value of the `ui.interactive'
1187 Interactiveness is triggered by the value of the `ui.interactive'
1184 configuration variable or - if it is unset - when `sys.stdin' points
1188 configuration variable or - if it is unset - when `sys.stdin' points
1185 to a terminal device.
1189 to a terminal device.
1186
1190
1187 This function refers to input only; for output, see `ui.formatted()'.
1191 This function refers to input only; for output, see `ui.formatted()'.
1188 '''
1192 '''
1189 i = self.configbool("ui", "interactive")
1193 i = self.configbool("ui", "interactive")
1190 if i is None:
1194 if i is None:
1191 # some environments replace stdin without implementing isatty
1195 # some environments replace stdin without implementing isatty
1192 # usually those are non-interactive
1196 # usually those are non-interactive
1193 return self._isatty(self.fin)
1197 return self._isatty(self.fin)
1194
1198
1195 return i
1199 return i
1196
1200
1197 def termwidth(self):
1201 def termwidth(self):
1198 '''how wide is the terminal in columns?
1202 '''how wide is the terminal in columns?
1199 '''
1203 '''
1200 if 'COLUMNS' in encoding.environ:
1204 if 'COLUMNS' in encoding.environ:
1201 try:
1205 try:
1202 return int(encoding.environ['COLUMNS'])
1206 return int(encoding.environ['COLUMNS'])
1203 except ValueError:
1207 except ValueError:
1204 pass
1208 pass
1205 return scmutil.termsize(self)[0]
1209 return scmutil.termsize(self)[0]
1206
1210
1207 def formatted(self):
1211 def formatted(self):
1208 '''should formatted output be used?
1212 '''should formatted output be used?
1209
1213
1210 It is often desirable to format the output to suite the output medium.
1214 It is often desirable to format the output to suite the output medium.
1211 Examples of this are truncating long lines or colorizing messages.
1215 Examples of this are truncating long lines or colorizing messages.
1212 However, this is not often not desirable when piping output into other
1216 However, this is not often not desirable when piping output into other
1213 utilities, e.g. `grep'.
1217 utilities, e.g. `grep'.
1214
1218
1215 Formatted output is triggered by the value of the `ui.formatted'
1219 Formatted output is triggered by the value of the `ui.formatted'
1216 configuration variable or - if it is unset - when `sys.stdout' points
1220 configuration variable or - if it is unset - when `sys.stdout' points
1217 to a terminal device. Please note that `ui.formatted' should be
1221 to a terminal device. Please note that `ui.formatted' should be
1218 considered an implementation detail; it is not intended for use outside
1222 considered an implementation detail; it is not intended for use outside
1219 Mercurial or its extensions.
1223 Mercurial or its extensions.
1220
1224
1221 This function refers to output only; for input, see `ui.interactive()'.
1225 This function refers to output only; for input, see `ui.interactive()'.
1222 This function always returns false when in plain mode, see `ui.plain()'.
1226 This function always returns false when in plain mode, see `ui.plain()'.
1223 '''
1227 '''
1224 if self.plain():
1228 if self.plain():
1225 return False
1229 return False
1226
1230
1227 i = self.configbool("ui", "formatted")
1231 i = self.configbool("ui", "formatted")
1228 if i is None:
1232 if i is None:
1229 # some environments replace stdout without implementing isatty
1233 # some environments replace stdout without implementing isatty
1230 # usually those are non-interactive
1234 # usually those are non-interactive
1231 return self._isatty(self.fout)
1235 return self._isatty(self.fout)
1232
1236
1233 return i
1237 return i
1234
1238
1235 def _readline(self, prompt=''):
1239 def _readline(self, prompt=''):
1236 if self._isatty(self.fin):
1240 if self._isatty(self.fin):
1237 try:
1241 try:
1238 # magically add command line editing support, where
1242 # magically add command line editing support, where
1239 # available
1243 # available
1240 import readline
1244 import readline
1241 # force demandimport to really load the module
1245 # force demandimport to really load the module
1242 readline.read_history_file
1246 readline.read_history_file
1243 # windows sometimes raises something other than ImportError
1247 # windows sometimes raises something other than ImportError
1244 except Exception:
1248 except Exception:
1245 pass
1249 pass
1246
1250
1247 # call write() so output goes through subclassed implementation
1251 # call write() so output goes through subclassed implementation
1248 # e.g. color extension on Windows
1252 # e.g. color extension on Windows
1249 self.write(prompt, prompt=True)
1253 self.write(prompt, prompt=True)
1250 self.flush()
1254 self.flush()
1251
1255
1252 # prompt ' ' must exist; otherwise readline may delete entire line
1256 # prompt ' ' must exist; otherwise readline may delete entire line
1253 # - http://bugs.python.org/issue12833
1257 # - http://bugs.python.org/issue12833
1254 with self.timeblockedsection('stdio'):
1258 with self.timeblockedsection('stdio'):
1255 line = util.bytesinput(self.fin, self.fout, r' ')
1259 line = util.bytesinput(self.fin, self.fout, r' ')
1256
1260
1257 # When stdin is in binary mode on Windows, it can cause
1261 # When stdin is in binary mode on Windows, it can cause
1258 # raw_input() to emit an extra trailing carriage return
1262 # raw_input() to emit an extra trailing carriage return
1259 if pycompat.oslinesep == '\r\n' and line and line[-1] == '\r':
1263 if pycompat.oslinesep == '\r\n' and line and line[-1] == '\r':
1260 line = line[:-1]
1264 line = line[:-1]
1261 return line
1265 return line
1262
1266
1263 def prompt(self, msg, default="y"):
1267 def prompt(self, msg, default="y"):
1264 """Prompt user with msg, read response.
1268 """Prompt user with msg, read response.
1265 If ui is not interactive, the default is returned.
1269 If ui is not interactive, the default is returned.
1266 """
1270 """
1267 if not self.interactive():
1271 if not self.interactive():
1268 self.write(msg, ' ', default or '', "\n")
1272 self.write(msg, ' ', default or '', "\n")
1269 return default
1273 return default
1270 try:
1274 try:
1271 r = self._readline(self.label(msg, 'ui.prompt'))
1275 r = self._readline(self.label(msg, 'ui.prompt'))
1272 if not r:
1276 if not r:
1273 r = default
1277 r = default
1274 if self.configbool('ui', 'promptecho'):
1278 if self.configbool('ui', 'promptecho'):
1275 self.write(r, "\n")
1279 self.write(r, "\n")
1276 return r
1280 return r
1277 except EOFError:
1281 except EOFError:
1278 raise error.ResponseExpected()
1282 raise error.ResponseExpected()
1279
1283
1280 @staticmethod
1284 @staticmethod
1281 def extractchoices(prompt):
1285 def extractchoices(prompt):
1282 """Extract prompt message and list of choices from specified prompt.
1286 """Extract prompt message and list of choices from specified prompt.
1283
1287
1284 This returns tuple "(message, choices)", and "choices" is the
1288 This returns tuple "(message, choices)", and "choices" is the
1285 list of tuple "(response character, text without &)".
1289 list of tuple "(response character, text without &)".
1286
1290
1287 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1291 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1288 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1292 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1289 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1293 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1290 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1294 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1291 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1295 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1292 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1296 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1293 """
1297 """
1294
1298
1295 # Sadly, the prompt string may have been built with a filename
1299 # Sadly, the prompt string may have been built with a filename
1296 # containing "$$" so let's try to find the first valid-looking
1300 # containing "$$" so let's try to find the first valid-looking
1297 # prompt to start parsing. Sadly, we also can't rely on
1301 # prompt to start parsing. Sadly, we also can't rely on
1298 # choices containing spaces, ASCII, or basically anything
1302 # choices containing spaces, ASCII, or basically anything
1299 # except an ampersand followed by a character.
1303 # except an ampersand followed by a character.
1300 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1304 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1301 msg = m.group(1)
1305 msg = m.group(1)
1302 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1306 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1303 def choicetuple(s):
1307 def choicetuple(s):
1304 ampidx = s.index('&')
1308 ampidx = s.index('&')
1305 return s[ampidx + 1:ampidx + 2].lower(), s.replace('&', '', 1)
1309 return s[ampidx + 1:ampidx + 2].lower(), s.replace('&', '', 1)
1306 return (msg, [choicetuple(s) for s in choices])
1310 return (msg, [choicetuple(s) for s in choices])
1307
1311
1308 def promptchoice(self, prompt, default=0):
1312 def promptchoice(self, prompt, default=0):
1309 """Prompt user with a message, read response, and ensure it matches
1313 """Prompt user with a message, read response, and ensure it matches
1310 one of the provided choices. The prompt is formatted as follows:
1314 one of the provided choices. The prompt is formatted as follows:
1311
1315
1312 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1316 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1313
1317
1314 The index of the choice is returned. Responses are case
1318 The index of the choice is returned. Responses are case
1315 insensitive. If ui is not interactive, the default is
1319 insensitive. If ui is not interactive, the default is
1316 returned.
1320 returned.
1317 """
1321 """
1318
1322
1319 msg, choices = self.extractchoices(prompt)
1323 msg, choices = self.extractchoices(prompt)
1320 resps = [r for r, t in choices]
1324 resps = [r for r, t in choices]
1321 while True:
1325 while True:
1322 r = self.prompt(msg, resps[default])
1326 r = self.prompt(msg, resps[default])
1323 if r.lower() in resps:
1327 if r.lower() in resps:
1324 return resps.index(r.lower())
1328 return resps.index(r.lower())
1325 self.write(_("unrecognized response\n"))
1329 self.write(_("unrecognized response\n"))
1326
1330
1327 def getpass(self, prompt=None, default=None):
1331 def getpass(self, prompt=None, default=None):
1328 if not self.interactive():
1332 if not self.interactive():
1329 return default
1333 return default
1330 try:
1334 try:
1331 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1335 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1332 # disable getpass() only if explicitly specified. it's still valid
1336 # disable getpass() only if explicitly specified. it's still valid
1333 # to interact with tty even if fin is not a tty.
1337 # to interact with tty even if fin is not a tty.
1334 with self.timeblockedsection('stdio'):
1338 with self.timeblockedsection('stdio'):
1335 if self.configbool('ui', 'nontty'):
1339 if self.configbool('ui', 'nontty'):
1336 l = self.fin.readline()
1340 l = self.fin.readline()
1337 if not l:
1341 if not l:
1338 raise EOFError
1342 raise EOFError
1339 return l.rstrip('\n')
1343 return l.rstrip('\n')
1340 else:
1344 else:
1341 return getpass.getpass('')
1345 return getpass.getpass('')
1342 except EOFError:
1346 except EOFError:
1343 raise error.ResponseExpected()
1347 raise error.ResponseExpected()
1344 def status(self, *msg, **opts):
1348 def status(self, *msg, **opts):
1345 '''write status message to output (if ui.quiet is False)
1349 '''write status message to output (if ui.quiet is False)
1346
1350
1347 This adds an output label of "ui.status".
1351 This adds an output label of "ui.status".
1348 '''
1352 '''
1349 if not self.quiet:
1353 if not self.quiet:
1350 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1354 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1351 self.write(*msg, **opts)
1355 self.write(*msg, **opts)
1352 def warn(self, *msg, **opts):
1356 def warn(self, *msg, **opts):
1353 '''write warning message to output (stderr)
1357 '''write warning message to output (stderr)
1354
1358
1355 This adds an output label of "ui.warning".
1359 This adds an output label of "ui.warning".
1356 '''
1360 '''
1357 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1361 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1358 self.write_err(*msg, **opts)
1362 self.write_err(*msg, **opts)
1359 def note(self, *msg, **opts):
1363 def note(self, *msg, **opts):
1360 '''write note to output (if ui.verbose is True)
1364 '''write note to output (if ui.verbose is True)
1361
1365
1362 This adds an output label of "ui.note".
1366 This adds an output label of "ui.note".
1363 '''
1367 '''
1364 if self.verbose:
1368 if self.verbose:
1365 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1369 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1366 self.write(*msg, **opts)
1370 self.write(*msg, **opts)
1367 def debug(self, *msg, **opts):
1371 def debug(self, *msg, **opts):
1368 '''write debug message to output (if ui.debugflag is True)
1372 '''write debug message to output (if ui.debugflag is True)
1369
1373
1370 This adds an output label of "ui.debug".
1374 This adds an output label of "ui.debug".
1371 '''
1375 '''
1372 if self.debugflag:
1376 if self.debugflag:
1373 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1377 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1374 self.write(*msg, **opts)
1378 self.write(*msg, **opts)
1375
1379
1376 def edit(self, text, user, extra=None, editform=None, pending=None,
1380 def edit(self, text, user, extra=None, editform=None, pending=None,
1377 repopath=None, action=None):
1381 repopath=None, action=None):
1378 if action is None:
1382 if action is None:
1379 self.develwarn('action is None but will soon be a required '
1383 self.develwarn('action is None but will soon be a required '
1380 'parameter to ui.edit()')
1384 'parameter to ui.edit()')
1381 extra_defaults = {
1385 extra_defaults = {
1382 'prefix': 'editor',
1386 'prefix': 'editor',
1383 'suffix': '.txt',
1387 'suffix': '.txt',
1384 }
1388 }
1385 if extra is not None:
1389 if extra is not None:
1386 if extra.get('suffix') is not None:
1390 if extra.get('suffix') is not None:
1387 self.develwarn('extra.suffix is not None but will soon be '
1391 self.develwarn('extra.suffix is not None but will soon be '
1388 'ignored by ui.edit()')
1392 'ignored by ui.edit()')
1389 extra_defaults.update(extra)
1393 extra_defaults.update(extra)
1390 extra = extra_defaults
1394 extra = extra_defaults
1391
1395
1392 if action == 'diff':
1396 if action == 'diff':
1393 suffix = '.diff'
1397 suffix = '.diff'
1394 elif action:
1398 elif action:
1395 suffix = '.%s.hg.txt' % action
1399 suffix = '.%s.hg.txt' % action
1396 else:
1400 else:
1397 suffix = extra['suffix']
1401 suffix = extra['suffix']
1398
1402
1399 rdir = None
1403 rdir = None
1400 if self.configbool('experimental', 'editortmpinhg'):
1404 if self.configbool('experimental', 'editortmpinhg'):
1401 rdir = repopath
1405 rdir = repopath
1402 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1406 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1403 suffix=suffix,
1407 suffix=suffix,
1404 dir=rdir)
1408 dir=rdir)
1405 try:
1409 try:
1406 f = os.fdopen(fd, r'wb')
1410 f = os.fdopen(fd, r'wb')
1407 f.write(util.tonativeeol(text))
1411 f.write(util.tonativeeol(text))
1408 f.close()
1412 f.close()
1409
1413
1410 environ = {'HGUSER': user}
1414 environ = {'HGUSER': user}
1411 if 'transplant_source' in extra:
1415 if 'transplant_source' in extra:
1412 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1416 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1413 for label in ('intermediate-source', 'source', 'rebase_source'):
1417 for label in ('intermediate-source', 'source', 'rebase_source'):
1414 if label in extra:
1418 if label in extra:
1415 environ.update({'HGREVISION': extra[label]})
1419 environ.update({'HGREVISION': extra[label]})
1416 break
1420 break
1417 if editform:
1421 if editform:
1418 environ.update({'HGEDITFORM': editform})
1422 environ.update({'HGEDITFORM': editform})
1419 if pending:
1423 if pending:
1420 environ.update({'HG_PENDING': pending})
1424 environ.update({'HG_PENDING': pending})
1421
1425
1422 editor = self.geteditor()
1426 editor = self.geteditor()
1423
1427
1424 self.system("%s \"%s\"" % (editor, name),
1428 self.system("%s \"%s\"" % (editor, name),
1425 environ=environ,
1429 environ=environ,
1426 onerr=error.Abort, errprefix=_("edit failed"),
1430 onerr=error.Abort, errprefix=_("edit failed"),
1427 blockedtag='editor')
1431 blockedtag='editor')
1428
1432
1429 f = open(name, r'rb')
1433 f = open(name, r'rb')
1430 t = util.fromnativeeol(f.read())
1434 t = util.fromnativeeol(f.read())
1431 f.close()
1435 f.close()
1432 finally:
1436 finally:
1433 os.unlink(name)
1437 os.unlink(name)
1434
1438
1435 return t
1439 return t
1436
1440
1437 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1441 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1438 blockedtag=None):
1442 blockedtag=None):
1439 '''execute shell command with appropriate output stream. command
1443 '''execute shell command with appropriate output stream. command
1440 output will be redirected if fout is not stdout.
1444 output will be redirected if fout is not stdout.
1441
1445
1442 if command fails and onerr is None, return status, else raise onerr
1446 if command fails and onerr is None, return status, else raise onerr
1443 object as exception.
1447 object as exception.
1444 '''
1448 '''
1445 if blockedtag is None:
1449 if blockedtag is None:
1446 # Long cmds tend to be because of an absolute path on cmd. Keep
1450 # Long cmds tend to be because of an absolute path on cmd. Keep
1447 # the tail end instead
1451 # the tail end instead
1448 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1452 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1449 blockedtag = 'unknown_system_' + cmdsuffix
1453 blockedtag = 'unknown_system_' + cmdsuffix
1450 out = self.fout
1454 out = self.fout
1451 if any(s[1] for s in self._bufferstates):
1455 if any(s[1] for s in self._bufferstates):
1452 out = self
1456 out = self
1453 with self.timeblockedsection(blockedtag):
1457 with self.timeblockedsection(blockedtag):
1454 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1458 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1455 if rc and onerr:
1459 if rc and onerr:
1456 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1460 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1457 util.explainexit(rc)[0])
1461 util.explainexit(rc)[0])
1458 if errprefix:
1462 if errprefix:
1459 errmsg = '%s: %s' % (errprefix, errmsg)
1463 errmsg = '%s: %s' % (errprefix, errmsg)
1460 raise onerr(errmsg)
1464 raise onerr(errmsg)
1461 return rc
1465 return rc
1462
1466
1463 def _runsystem(self, cmd, environ, cwd, out):
1467 def _runsystem(self, cmd, environ, cwd, out):
1464 """actually execute the given shell command (can be overridden by
1468 """actually execute the given shell command (can be overridden by
1465 extensions like chg)"""
1469 extensions like chg)"""
1466 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1470 return util.system(cmd, environ=environ, cwd=cwd, out=out)
1467
1471
1468 def traceback(self, exc=None, force=False):
1472 def traceback(self, exc=None, force=False):
1469 '''print exception traceback if traceback printing enabled or forced.
1473 '''print exception traceback if traceback printing enabled or forced.
1470 only to call in exception handler. returns true if traceback
1474 only to call in exception handler. returns true if traceback
1471 printed.'''
1475 printed.'''
1472 if self.tracebackflag or force:
1476 if self.tracebackflag or force:
1473 if exc is None:
1477 if exc is None:
1474 exc = sys.exc_info()
1478 exc = sys.exc_info()
1475 cause = getattr(exc[1], 'cause', None)
1479 cause = getattr(exc[1], 'cause', None)
1476
1480
1477 if cause is not None:
1481 if cause is not None:
1478 causetb = traceback.format_tb(cause[2])
1482 causetb = traceback.format_tb(cause[2])
1479 exctb = traceback.format_tb(exc[2])
1483 exctb = traceback.format_tb(exc[2])
1480 exconly = traceback.format_exception_only(cause[0], cause[1])
1484 exconly = traceback.format_exception_only(cause[0], cause[1])
1481
1485
1482 # exclude frame where 'exc' was chained and rethrown from exctb
1486 # exclude frame where 'exc' was chained and rethrown from exctb
1483 self.write_err('Traceback (most recent call last):\n',
1487 self.write_err('Traceback (most recent call last):\n',
1484 ''.join(exctb[:-1]),
1488 ''.join(exctb[:-1]),
1485 ''.join(causetb),
1489 ''.join(causetb),
1486 ''.join(exconly))
1490 ''.join(exconly))
1487 else:
1491 else:
1488 output = traceback.format_exception(exc[0], exc[1], exc[2])
1492 output = traceback.format_exception(exc[0], exc[1], exc[2])
1489 data = r''.join(output)
1493 data = r''.join(output)
1490 if pycompat.ispy3:
1494 if pycompat.ispy3:
1491 enc = pycompat.sysstr(encoding.encoding)
1495 enc = pycompat.sysstr(encoding.encoding)
1492 data = data.encode(enc, errors=r'replace')
1496 data = data.encode(enc, errors=r'replace')
1493 self.write_err(data)
1497 self.write_err(data)
1494 return self.tracebackflag or force
1498 return self.tracebackflag or force
1495
1499
1496 def geteditor(self):
1500 def geteditor(self):
1497 '''return editor to use'''
1501 '''return editor to use'''
1498 if pycompat.sysplatform == 'plan9':
1502 if pycompat.sysplatform == 'plan9':
1499 # vi is the MIPS instruction simulator on Plan 9. We
1503 # vi is the MIPS instruction simulator on Plan 9. We
1500 # instead default to E to plumb commit messages to
1504 # instead default to E to plumb commit messages to
1501 # avoid confusion.
1505 # avoid confusion.
1502 editor = 'E'
1506 editor = 'E'
1503 else:
1507 else:
1504 editor = 'vi'
1508 editor = 'vi'
1505 return (encoding.environ.get("HGEDITOR") or
1509 return (encoding.environ.get("HGEDITOR") or
1506 self.config("ui", "editor", editor))
1510 self.config("ui", "editor", editor))
1507
1511
1508 @util.propertycache
1512 @util.propertycache
1509 def _progbar(self):
1513 def _progbar(self):
1510 """setup the progbar singleton to the ui object"""
1514 """setup the progbar singleton to the ui object"""
1511 if (self.quiet or self.debugflag
1515 if (self.quiet or self.debugflag
1512 or self.configbool('progress', 'disable')
1516 or self.configbool('progress', 'disable')
1513 or not progress.shouldprint(self)):
1517 or not progress.shouldprint(self)):
1514 return None
1518 return None
1515 return getprogbar(self)
1519 return getprogbar(self)
1516
1520
1517 def _progclear(self):
1521 def _progclear(self):
1518 """clear progress bar output if any. use it before any output"""
1522 """clear progress bar output if any. use it before any output"""
1519 if not haveprogbar(): # nothing loaded yet
1523 if not haveprogbar(): # nothing loaded yet
1520 return
1524 return
1521 if self._progbar is not None and self._progbar.printed:
1525 if self._progbar is not None and self._progbar.printed:
1522 self._progbar.clear()
1526 self._progbar.clear()
1523
1527
1524 def progress(self, topic, pos, item="", unit="", total=None):
1528 def progress(self, topic, pos, item="", unit="", total=None):
1525 '''show a progress message
1529 '''show a progress message
1526
1530
1527 By default a textual progress bar will be displayed if an operation
1531 By default a textual progress bar will be displayed if an operation
1528 takes too long. 'topic' is the current operation, 'item' is a
1532 takes too long. 'topic' is the current operation, 'item' is a
1529 non-numeric marker of the current position (i.e. the currently
1533 non-numeric marker of the current position (i.e. the currently
1530 in-process file), 'pos' is the current numeric position (i.e.
1534 in-process file), 'pos' is the current numeric position (i.e.
1531 revision, bytes, etc.), unit is a corresponding unit label,
1535 revision, bytes, etc.), unit is a corresponding unit label,
1532 and total is the highest expected pos.
1536 and total is the highest expected pos.
1533
1537
1534 Multiple nested topics may be active at a time.
1538 Multiple nested topics may be active at a time.
1535
1539
1536 All topics should be marked closed by setting pos to None at
1540 All topics should be marked closed by setting pos to None at
1537 termination.
1541 termination.
1538 '''
1542 '''
1539 if self._progbar is not None:
1543 if self._progbar is not None:
1540 self._progbar.progress(topic, pos, item=item, unit=unit,
1544 self._progbar.progress(topic, pos, item=item, unit=unit,
1541 total=total)
1545 total=total)
1542 if pos is None or not self.configbool('progress', 'debug'):
1546 if pos is None or not self.configbool('progress', 'debug'):
1543 return
1547 return
1544
1548
1545 if unit:
1549 if unit:
1546 unit = ' ' + unit
1550 unit = ' ' + unit
1547 if item:
1551 if item:
1548 item = ' ' + item
1552 item = ' ' + item
1549
1553
1550 if total:
1554 if total:
1551 pct = 100.0 * pos / total
1555 pct = 100.0 * pos / total
1552 self.debug('%s:%s %d/%d%s (%4.2f%%)\n'
1556 self.debug('%s:%s %d/%d%s (%4.2f%%)\n'
1553 % (topic, item, pos, total, unit, pct))
1557 % (topic, item, pos, total, unit, pct))
1554 else:
1558 else:
1555 self.debug('%s:%s %d%s\n' % (topic, item, pos, unit))
1559 self.debug('%s:%s %d%s\n' % (topic, item, pos, unit))
1556
1560
1557 def log(self, service, *msg, **opts):
1561 def log(self, service, *msg, **opts):
1558 '''hook for logging facility extensions
1562 '''hook for logging facility extensions
1559
1563
1560 service should be a readily-identifiable subsystem, which will
1564 service should be a readily-identifiable subsystem, which will
1561 allow filtering.
1565 allow filtering.
1562
1566
1563 *msg should be a newline-terminated format string to log, and
1567 *msg should be a newline-terminated format string to log, and
1564 then any values to %-format into that format string.
1568 then any values to %-format into that format string.
1565
1569
1566 **opts currently has no defined meanings.
1570 **opts currently has no defined meanings.
1567 '''
1571 '''
1568
1572
1569 def label(self, msg, label):
1573 def label(self, msg, label):
1570 '''style msg based on supplied label
1574 '''style msg based on supplied label
1571
1575
1572 If some color mode is enabled, this will add the necessary control
1576 If some color mode is enabled, this will add the necessary control
1573 characters to apply such color. In addition, 'debug' color mode adds
1577 characters to apply such color. In addition, 'debug' color mode adds
1574 markup showing which label affects a piece of text.
1578 markup showing which label affects a piece of text.
1575
1579
1576 ui.write(s, 'label') is equivalent to
1580 ui.write(s, 'label') is equivalent to
1577 ui.write(ui.label(s, 'label')).
1581 ui.write(ui.label(s, 'label')).
1578 '''
1582 '''
1579 if self._colormode is not None:
1583 if self._colormode is not None:
1580 return color.colorlabel(self, msg, label)
1584 return color.colorlabel(self, msg, label)
1581 return msg
1585 return msg
1582
1586
1583 def develwarn(self, msg, stacklevel=1, config=None):
1587 def develwarn(self, msg, stacklevel=1, config=None):
1584 """issue a developer warning message
1588 """issue a developer warning message
1585
1589
1586 Use 'stacklevel' to report the offender some layers further up in the
1590 Use 'stacklevel' to report the offender some layers further up in the
1587 stack.
1591 stack.
1588 """
1592 """
1589 if not self.configbool('devel', 'all-warnings'):
1593 if not self.configbool('devel', 'all-warnings'):
1590 if config is not None and not self.configbool('devel', config):
1594 if config is not None and not self.configbool('devel', config):
1591 return
1595 return
1592 msg = 'devel-warn: ' + msg
1596 msg = 'devel-warn: ' + msg
1593 stacklevel += 1 # get in develwarn
1597 stacklevel += 1 # get in develwarn
1594 if self.tracebackflag:
1598 if self.tracebackflag:
1595 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1599 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1596 self.log('develwarn', '%s at:\n%s' %
1600 self.log('develwarn', '%s at:\n%s' %
1597 (msg, ''.join(util.getstackframes(stacklevel))))
1601 (msg, ''.join(util.getstackframes(stacklevel))))
1598 else:
1602 else:
1599 curframe = inspect.currentframe()
1603 curframe = inspect.currentframe()
1600 calframe = inspect.getouterframes(curframe, 2)
1604 calframe = inspect.getouterframes(curframe, 2)
1601 self.write_err('%s at: %s:%s (%s)\n'
1605 self.write_err('%s at: %s:%s (%s)\n'
1602 % ((msg,) + calframe[stacklevel][1:4]))
1606 % ((msg,) + calframe[stacklevel][1:4]))
1603 self.log('develwarn', '%s at: %s:%s (%s)\n',
1607 self.log('develwarn', '%s at: %s:%s (%s)\n',
1604 msg, *calframe[stacklevel][1:4])
1608 msg, *calframe[stacklevel][1:4])
1605 curframe = calframe = None # avoid cycles
1609 curframe = calframe = None # avoid cycles
1606
1610
1607 def deprecwarn(self, msg, version):
1611 def deprecwarn(self, msg, version):
1608 """issue a deprecation warning
1612 """issue a deprecation warning
1609
1613
1610 - msg: message explaining what is deprecated and how to upgrade,
1614 - msg: message explaining what is deprecated and how to upgrade,
1611 - version: last version where the API will be supported,
1615 - version: last version where the API will be supported,
1612 """
1616 """
1613 if not (self.configbool('devel', 'all-warnings')
1617 if not (self.configbool('devel', 'all-warnings')
1614 or self.configbool('devel', 'deprec-warn')):
1618 or self.configbool('devel', 'deprec-warn')):
1615 return
1619 return
1616 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1620 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1617 " update your code.)") % version
1621 " update your code.)") % version
1618 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1622 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1619
1623
1620 def exportableenviron(self):
1624 def exportableenviron(self):
1621 """The environment variables that are safe to export, e.g. through
1625 """The environment variables that are safe to export, e.g. through
1622 hgweb.
1626 hgweb.
1623 """
1627 """
1624 return self._exportableenviron
1628 return self._exportableenviron
1625
1629
1626 @contextlib.contextmanager
1630 @contextlib.contextmanager
1627 def configoverride(self, overrides, source=""):
1631 def configoverride(self, overrides, source=""):
1628 """Context manager for temporary config overrides
1632 """Context manager for temporary config overrides
1629 `overrides` must be a dict of the following structure:
1633 `overrides` must be a dict of the following structure:
1630 {(section, name) : value}"""
1634 {(section, name) : value}"""
1631 backups = {}
1635 backups = {}
1632 try:
1636 try:
1633 for (section, name), value in overrides.items():
1637 for (section, name), value in overrides.items():
1634 backups[(section, name)] = self.backupconfig(section, name)
1638 backups[(section, name)] = self.backupconfig(section, name)
1635 self.setconfig(section, name, value, source)
1639 self.setconfig(section, name, value, source)
1636 yield
1640 yield
1637 finally:
1641 finally:
1638 for __, backup in backups.items():
1642 for __, backup in backups.items():
1639 self.restoreconfig(backup)
1643 self.restoreconfig(backup)
1640 # just restoring ui.quiet config to the previous value is not enough
1644 # just restoring ui.quiet config to the previous value is not enough
1641 # as it does not update ui.quiet class member
1645 # as it does not update ui.quiet class member
1642 if ('ui', 'quiet') in overrides:
1646 if ('ui', 'quiet') in overrides:
1643 self.fixconfig(section='ui')
1647 self.fixconfig(section='ui')
1644
1648
1645 class paths(dict):
1649 class paths(dict):
1646 """Represents a collection of paths and their configs.
1650 """Represents a collection of paths and their configs.
1647
1651
1648 Data is initially derived from ui instances and the config files they have
1652 Data is initially derived from ui instances and the config files they have
1649 loaded.
1653 loaded.
1650 """
1654 """
1651 def __init__(self, ui):
1655 def __init__(self, ui):
1652 dict.__init__(self)
1656 dict.__init__(self)
1653
1657
1654 for name, loc in ui.configitems('paths', ignoresub=True):
1658 for name, loc in ui.configitems('paths', ignoresub=True):
1655 # No location is the same as not existing.
1659 # No location is the same as not existing.
1656 if not loc:
1660 if not loc:
1657 continue
1661 continue
1658 loc, sub = ui.configsuboptions('paths', name)
1662 loc, sub = ui.configsuboptions('paths', name)
1659 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1663 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1660
1664
1661 def getpath(self, name, default=None):
1665 def getpath(self, name, default=None):
1662 """Return a ``path`` from a string, falling back to default.
1666 """Return a ``path`` from a string, falling back to default.
1663
1667
1664 ``name`` can be a named path or locations. Locations are filesystem
1668 ``name`` can be a named path or locations. Locations are filesystem
1665 paths or URIs.
1669 paths or URIs.
1666
1670
1667 Returns None if ``name`` is not a registered path, a URI, or a local
1671 Returns None if ``name`` is not a registered path, a URI, or a local
1668 path to a repo.
1672 path to a repo.
1669 """
1673 """
1670 # Only fall back to default if no path was requested.
1674 # Only fall back to default if no path was requested.
1671 if name is None:
1675 if name is None:
1672 if not default:
1676 if not default:
1673 default = ()
1677 default = ()
1674 elif not isinstance(default, (tuple, list)):
1678 elif not isinstance(default, (tuple, list)):
1675 default = (default,)
1679 default = (default,)
1676 for k in default:
1680 for k in default:
1677 try:
1681 try:
1678 return self[k]
1682 return self[k]
1679 except KeyError:
1683 except KeyError:
1680 continue
1684 continue
1681 return None
1685 return None
1682
1686
1683 # Most likely empty string.
1687 # Most likely empty string.
1684 # This may need to raise in the future.
1688 # This may need to raise in the future.
1685 if not name:
1689 if not name:
1686 return None
1690 return None
1687
1691
1688 try:
1692 try:
1689 return self[name]
1693 return self[name]
1690 except KeyError:
1694 except KeyError:
1691 # Try to resolve as a local path or URI.
1695 # Try to resolve as a local path or URI.
1692 try:
1696 try:
1693 # We don't pass sub-options in, so no need to pass ui instance.
1697 # We don't pass sub-options in, so no need to pass ui instance.
1694 return path(None, None, rawloc=name)
1698 return path(None, None, rawloc=name)
1695 except ValueError:
1699 except ValueError:
1696 raise error.RepoError(_('repository %s does not exist') %
1700 raise error.RepoError(_('repository %s does not exist') %
1697 name)
1701 name)
1698
1702
1699 _pathsuboptions = {}
1703 _pathsuboptions = {}
1700
1704
1701 def pathsuboption(option, attr):
1705 def pathsuboption(option, attr):
1702 """Decorator used to declare a path sub-option.
1706 """Decorator used to declare a path sub-option.
1703
1707
1704 Arguments are the sub-option name and the attribute it should set on
1708 Arguments are the sub-option name and the attribute it should set on
1705 ``path`` instances.
1709 ``path`` instances.
1706
1710
1707 The decorated function will receive as arguments a ``ui`` instance,
1711 The decorated function will receive as arguments a ``ui`` instance,
1708 ``path`` instance, and the string value of this option from the config.
1712 ``path`` instance, and the string value of this option from the config.
1709 The function should return the value that will be set on the ``path``
1713 The function should return the value that will be set on the ``path``
1710 instance.
1714 instance.
1711
1715
1712 This decorator can be used to perform additional verification of
1716 This decorator can be used to perform additional verification of
1713 sub-options and to change the type of sub-options.
1717 sub-options and to change the type of sub-options.
1714 """
1718 """
1715 def register(func):
1719 def register(func):
1716 _pathsuboptions[option] = (attr, func)
1720 _pathsuboptions[option] = (attr, func)
1717 return func
1721 return func
1718 return register
1722 return register
1719
1723
1720 @pathsuboption('pushurl', 'pushloc')
1724 @pathsuboption('pushurl', 'pushloc')
1721 def pushurlpathoption(ui, path, value):
1725 def pushurlpathoption(ui, path, value):
1722 u = util.url(value)
1726 u = util.url(value)
1723 # Actually require a URL.
1727 # Actually require a URL.
1724 if not u.scheme:
1728 if not u.scheme:
1725 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1729 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1726 return None
1730 return None
1727
1731
1728 # Don't support the #foo syntax in the push URL to declare branch to
1732 # Don't support the #foo syntax in the push URL to declare branch to
1729 # push.
1733 # push.
1730 if u.fragment:
1734 if u.fragment:
1731 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1735 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1732 'ignoring)\n') % path.name)
1736 'ignoring)\n') % path.name)
1733 u.fragment = None
1737 u.fragment = None
1734
1738
1735 return str(u)
1739 return str(u)
1736
1740
1737 @pathsuboption('pushrev', 'pushrev')
1741 @pathsuboption('pushrev', 'pushrev')
1738 def pushrevpathoption(ui, path, value):
1742 def pushrevpathoption(ui, path, value):
1739 return value
1743 return value
1740
1744
1741 class path(object):
1745 class path(object):
1742 """Represents an individual path and its configuration."""
1746 """Represents an individual path and its configuration."""
1743
1747
1744 def __init__(self, ui, name, rawloc=None, suboptions=None):
1748 def __init__(self, ui, name, rawloc=None, suboptions=None):
1745 """Construct a path from its config options.
1749 """Construct a path from its config options.
1746
1750
1747 ``ui`` is the ``ui`` instance the path is coming from.
1751 ``ui`` is the ``ui`` instance the path is coming from.
1748 ``name`` is the symbolic name of the path.
1752 ``name`` is the symbolic name of the path.
1749 ``rawloc`` is the raw location, as defined in the config.
1753 ``rawloc`` is the raw location, as defined in the config.
1750 ``pushloc`` is the raw locations pushes should be made to.
1754 ``pushloc`` is the raw locations pushes should be made to.
1751
1755
1752 If ``name`` is not defined, we require that the location be a) a local
1756 If ``name`` is not defined, we require that the location be a) a local
1753 filesystem path with a .hg directory or b) a URL. If not,
1757 filesystem path with a .hg directory or b) a URL. If not,
1754 ``ValueError`` is raised.
1758 ``ValueError`` is raised.
1755 """
1759 """
1756 if not rawloc:
1760 if not rawloc:
1757 raise ValueError('rawloc must be defined')
1761 raise ValueError('rawloc must be defined')
1758
1762
1759 # Locations may define branches via syntax <base>#<branch>.
1763 # Locations may define branches via syntax <base>#<branch>.
1760 u = util.url(rawloc)
1764 u = util.url(rawloc)
1761 branch = None
1765 branch = None
1762 if u.fragment:
1766 if u.fragment:
1763 branch = u.fragment
1767 branch = u.fragment
1764 u.fragment = None
1768 u.fragment = None
1765
1769
1766 self.url = u
1770 self.url = u
1767 self.branch = branch
1771 self.branch = branch
1768
1772
1769 self.name = name
1773 self.name = name
1770 self.rawloc = rawloc
1774 self.rawloc = rawloc
1771 self.loc = '%s' % u
1775 self.loc = '%s' % u
1772
1776
1773 # When given a raw location but not a symbolic name, validate the
1777 # When given a raw location but not a symbolic name, validate the
1774 # location is valid.
1778 # location is valid.
1775 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1779 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1776 raise ValueError('location is not a URL or path to a local '
1780 raise ValueError('location is not a URL or path to a local '
1777 'repo: %s' % rawloc)
1781 'repo: %s' % rawloc)
1778
1782
1779 suboptions = suboptions or {}
1783 suboptions = suboptions or {}
1780
1784
1781 # Now process the sub-options. If a sub-option is registered, its
1785 # Now process the sub-options. If a sub-option is registered, its
1782 # attribute will always be present. The value will be None if there
1786 # attribute will always be present. The value will be None if there
1783 # was no valid sub-option.
1787 # was no valid sub-option.
1784 for suboption, (attr, func) in _pathsuboptions.iteritems():
1788 for suboption, (attr, func) in _pathsuboptions.iteritems():
1785 if suboption not in suboptions:
1789 if suboption not in suboptions:
1786 setattr(self, attr, None)
1790 setattr(self, attr, None)
1787 continue
1791 continue
1788
1792
1789 value = func(ui, self, suboptions[suboption])
1793 value = func(ui, self, suboptions[suboption])
1790 setattr(self, attr, value)
1794 setattr(self, attr, value)
1791
1795
1792 def _isvalidlocalpath(self, path):
1796 def _isvalidlocalpath(self, path):
1793 """Returns True if the given path is a potentially valid repository.
1797 """Returns True if the given path is a potentially valid repository.
1794 This is its own function so that extensions can change the definition of
1798 This is its own function so that extensions can change the definition of
1795 'valid' in this case (like when pulling from a git repo into a hg
1799 'valid' in this case (like when pulling from a git repo into a hg
1796 one)."""
1800 one)."""
1797 return os.path.isdir(os.path.join(path, '.hg'))
1801 return os.path.isdir(os.path.join(path, '.hg'))
1798
1802
1799 @property
1803 @property
1800 def suboptions(self):
1804 def suboptions(self):
1801 """Return sub-options and their values for this path.
1805 """Return sub-options and their values for this path.
1802
1806
1803 This is intended to be used for presentation purposes.
1807 This is intended to be used for presentation purposes.
1804 """
1808 """
1805 d = {}
1809 d = {}
1806 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1810 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1807 value = getattr(self, attr)
1811 value = getattr(self, attr)
1808 if value is not None:
1812 if value is not None:
1809 d[subopt] = value
1813 d[subopt] = value
1810 return d
1814 return d
1811
1815
1812 # we instantiate one globally shared progress bar to avoid
1816 # we instantiate one globally shared progress bar to avoid
1813 # competing progress bars when multiple UI objects get created
1817 # competing progress bars when multiple UI objects get created
1814 _progresssingleton = None
1818 _progresssingleton = None
1815
1819
1816 def getprogbar(ui):
1820 def getprogbar(ui):
1817 global _progresssingleton
1821 global _progresssingleton
1818 if _progresssingleton is None:
1822 if _progresssingleton is None:
1819 # passing 'ui' object to the singleton is fishy,
1823 # passing 'ui' object to the singleton is fishy,
1820 # this is how the extension used to work but feel free to rework it.
1824 # this is how the extension used to work but feel free to rework it.
1821 _progresssingleton = progress.progbar(ui)
1825 _progresssingleton = progress.progbar(ui)
1822 return _progresssingleton
1826 return _progresssingleton
1823
1827
1824 def haveprogbar():
1828 def haveprogbar():
1825 return _progresssingleton is not None
1829 return _progresssingleton is not None
@@ -1,376 +1,380
1
1
2 $ cat << EOF > buggylocking.py
2 $ cat << EOF > buggylocking.py
3 > """A small extension that tests our developer warnings
3 > """A small extension that tests our developer warnings
4 > """
4 > """
5 >
5 >
6 > from mercurial import error, registrar, repair, util
6 > from mercurial import error, registrar, repair, util
7 >
7 >
8 > cmdtable = {}
8 > cmdtable = {}
9 > command = registrar.command(cmdtable)
9 > command = registrar.command(cmdtable)
10 >
10 >
11 > @command(b'buggylocking', [], '')
11 > @command(b'buggylocking', [], '')
12 > def buggylocking(ui, repo):
12 > def buggylocking(ui, repo):
13 > lo = repo.lock()
13 > lo = repo.lock()
14 > wl = repo.wlock()
14 > wl = repo.wlock()
15 > wl.release()
15 > wl.release()
16 > lo.release()
16 > lo.release()
17 >
17 >
18 > @command(b'buggytransaction', [], '')
18 > @command(b'buggytransaction', [], '')
19 > def buggylocking(ui, repo):
19 > def buggylocking(ui, repo):
20 > tr = repo.transaction('buggy')
20 > tr = repo.transaction('buggy')
21 > # make sure we rollback the transaction as we don't want to rely on the__del__
21 > # make sure we rollback the transaction as we don't want to rely on the__del__
22 > tr.release()
22 > tr.release()
23 >
23 >
24 > @command(b'properlocking', [], '')
24 > @command(b'properlocking', [], '')
25 > def properlocking(ui, repo):
25 > def properlocking(ui, repo):
26 > """check that reentrance is fine"""
26 > """check that reentrance is fine"""
27 > wl = repo.wlock()
27 > wl = repo.wlock()
28 > lo = repo.lock()
28 > lo = repo.lock()
29 > tr = repo.transaction('proper')
29 > tr = repo.transaction('proper')
30 > tr2 = repo.transaction('proper')
30 > tr2 = repo.transaction('proper')
31 > lo2 = repo.lock()
31 > lo2 = repo.lock()
32 > wl2 = repo.wlock()
32 > wl2 = repo.wlock()
33 > wl2.release()
33 > wl2.release()
34 > lo2.release()
34 > lo2.release()
35 > tr2.close()
35 > tr2.close()
36 > tr.close()
36 > tr.close()
37 > lo.release()
37 > lo.release()
38 > wl.release()
38 > wl.release()
39 >
39 >
40 > @command(b'nowaitlocking', [], '')
40 > @command(b'nowaitlocking', [], '')
41 > def nowaitlocking(ui, repo):
41 > def nowaitlocking(ui, repo):
42 > lo = repo.lock()
42 > lo = repo.lock()
43 > wl = repo.wlock(wait=False)
43 > wl = repo.wlock(wait=False)
44 > wl.release()
44 > wl.release()
45 > lo.release()
45 > lo.release()
46 >
46 >
47 > @command(b'no-wlock-write', [], '')
47 > @command(b'no-wlock-write', [], '')
48 > def nowlockwrite(ui, repo):
48 > def nowlockwrite(ui, repo):
49 > with repo.vfs(b'branch', 'a'):
49 > with repo.vfs(b'branch', 'a'):
50 > pass
50 > pass
51 >
51 >
52 > @command(b'no-lock-write', [], '')
52 > @command(b'no-lock-write', [], '')
53 > def nolockwrite(ui, repo):
53 > def nolockwrite(ui, repo):
54 > with repo.svfs(b'fncache', 'a'):
54 > with repo.svfs(b'fncache', 'a'):
55 > pass
55 > pass
56 >
56 >
57 > @command(b'stripintr', [], '')
57 > @command(b'stripintr', [], '')
58 > def stripintr(ui, repo):
58 > def stripintr(ui, repo):
59 > lo = repo.lock()
59 > lo = repo.lock()
60 > tr = repo.transaction('foobar')
60 > tr = repo.transaction('foobar')
61 > try:
61 > try:
62 > repair.strip(repo.ui, repo, [repo['.'].node()])
62 > repair.strip(repo.ui, repo, [repo['.'].node()])
63 > finally:
63 > finally:
64 > lo.release()
64 > lo.release()
65 > @command(b'oldanddeprecated', [], '')
65 > @command(b'oldanddeprecated', [], '')
66 > def oldanddeprecated(ui, repo):
66 > def oldanddeprecated(ui, repo):
67 > """test deprecation warning API"""
67 > """test deprecation warning API"""
68 > def foobar(ui):
68 > def foobar(ui):
69 > ui.deprecwarn('foorbar is deprecated, go shopping', '42.1337')
69 > ui.deprecwarn('foorbar is deprecated, go shopping', '42.1337')
70 > foobar(ui)
70 > foobar(ui)
71 > @command(b'nouiwarning', [], '')
71 > @command(b'nouiwarning', [], '')
72 > def nouiwarning(ui, repo):
72 > def nouiwarning(ui, repo):
73 > util.nouideprecwarn('this is a test', '13.37')
73 > util.nouideprecwarn('this is a test', '13.37')
74 > @command(b'programmingerror', [], '')
74 > @command(b'programmingerror', [], '')
75 > def programmingerror(ui, repo):
75 > def programmingerror(ui, repo):
76 > raise error.ProgrammingError('something went wrong', hint='try again')
76 > raise error.ProgrammingError('something went wrong', hint='try again')
77 > EOF
77 > EOF
78
78
79 $ cat << EOF >> $HGRCPATH
79 $ cat << EOF >> $HGRCPATH
80 > [extensions]
80 > [extensions]
81 > buggylocking=$TESTTMP/buggylocking.py
81 > buggylocking=$TESTTMP/buggylocking.py
82 > mock=$TESTDIR/mockblackbox.py
82 > mock=$TESTDIR/mockblackbox.py
83 > blackbox=
83 > blackbox=
84 > [devel]
84 > [devel]
85 > all-warnings=1
85 > all-warnings=1
86 > EOF
86 > EOF
87
87
88 $ hg init lock-checker
88 $ hg init lock-checker
89 $ cd lock-checker
89 $ cd lock-checker
90 $ hg buggylocking
90 $ hg buggylocking
91 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
91 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
92 $ cat << EOF >> $HGRCPATH
92 $ cat << EOF >> $HGRCPATH
93 > [devel]
93 > [devel]
94 > all=0
94 > all=0
95 > check-locks=1
95 > check-locks=1
96 > EOF
96 > EOF
97 $ hg buggylocking
97 $ hg buggylocking
98 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
98 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
99 #if no-chg
99 #if no-chg
100 $ hg buggylocking --traceback
100 $ hg buggylocking --traceback
101 devel-warn: "wlock" acquired after "lock" at:
101 devel-warn: "wlock" acquired after "lock" at:
102 */hg:* in <module> (glob)
102 */hg:* in <module> (glob)
103 */mercurial/dispatch.py:* in run (glob)
103 */mercurial/dispatch.py:* in run (glob)
104 */mercurial/dispatch.py:* in dispatch (glob)
104 */mercurial/dispatch.py:* in dispatch (glob)
105 */mercurial/dispatch.py:* in _runcatch (glob)
105 */mercurial/dispatch.py:* in _runcatch (glob)
106 */mercurial/dispatch.py:* in _callcatch (glob)
106 */mercurial/dispatch.py:* in _callcatch (glob)
107 */mercurial/scmutil.py* in callcatch (glob)
107 */mercurial/scmutil.py* in callcatch (glob)
108 */mercurial/dispatch.py:* in _runcatchfunc (glob)
108 */mercurial/dispatch.py:* in _runcatchfunc (glob)
109 */mercurial/dispatch.py:* in _dispatch (glob)
109 */mercurial/dispatch.py:* in _dispatch (glob)
110 */mercurial/dispatch.py:* in runcommand (glob)
110 */mercurial/dispatch.py:* in runcommand (glob)
111 */mercurial/dispatch.py:* in _runcommand (glob)
111 */mercurial/dispatch.py:* in _runcommand (glob)
112 */mercurial/dispatch.py:* in <lambda> (glob)
112 */mercurial/dispatch.py:* in <lambda> (glob)
113 */mercurial/util.py:* in check (glob)
113 */mercurial/util.py:* in check (glob)
114 $TESTTMP/buggylocking.py:* in buggylocking (glob)
114 $TESTTMP/buggylocking.py:* in buggylocking (glob)
115 #else
115 #else
116 $ hg buggylocking --traceback
116 $ hg buggylocking --traceback
117 devel-warn: "wlock" acquired after "lock" at:
117 devel-warn: "wlock" acquired after "lock" at:
118 */hg:* in <module> (glob)
118 */hg:* in <module> (glob)
119 */mercurial/dispatch.py:* in run (glob)
119 */mercurial/dispatch.py:* in run (glob)
120 */mercurial/dispatch.py:* in dispatch (glob)
120 */mercurial/dispatch.py:* in dispatch (glob)
121 */mercurial/dispatch.py:* in _runcatch (glob)
121 */mercurial/dispatch.py:* in _runcatch (glob)
122 */mercurial/dispatch.py:* in _callcatch (glob)
122 */mercurial/dispatch.py:* in _callcatch (glob)
123 */mercurial/scmutil.py:* in callcatch (glob)
123 */mercurial/scmutil.py:* in callcatch (glob)
124 */mercurial/dispatch.py:* in _runcatchfunc (glob)
124 */mercurial/dispatch.py:* in _runcatchfunc (glob)
125 */mercurial/dispatch.py:* in _dispatch (glob)
125 */mercurial/dispatch.py:* in _dispatch (glob)
126 */mercurial/dispatch.py:* in runcommand (glob)
126 */mercurial/dispatch.py:* in runcommand (glob)
127 */mercurial/dispatch.py:* in _runcommand (glob)
127 */mercurial/dispatch.py:* in _runcommand (glob)
128 */mercurial/dispatch.py:* in <lambda> (glob)
128 */mercurial/dispatch.py:* in <lambda> (glob)
129 */mercurial/util.py:* in check (glob)
129 */mercurial/util.py:* in check (glob)
130 */mercurial/commands.py:* in serve (glob)
130 */mercurial/commands.py:* in serve (glob)
131 */mercurial/server.py:* in runservice (glob)
131 */mercurial/server.py:* in runservice (glob)
132 */mercurial/commandserver.py:* in run (glob)
132 */mercurial/commandserver.py:* in run (glob)
133 */mercurial/commandserver.py:* in _mainloop (glob)
133 */mercurial/commandserver.py:* in _mainloop (glob)
134 */mercurial/commandserver.py:* in _runworker (glob)
134 */mercurial/commandserver.py:* in _runworker (glob)
135 */mercurial/commandserver.py:* in _serverequest (glob)
135 */mercurial/commandserver.py:* in _serverequest (glob)
136 */mercurial/commandserver.py:* in serve (glob)
136 */mercurial/commandserver.py:* in serve (glob)
137 */mercurial/commandserver.py:* in serveone (glob)
137 */mercurial/commandserver.py:* in serveone (glob)
138 */mercurial/chgserver.py:* in runcommand (glob)
138 */mercurial/chgserver.py:* in runcommand (glob)
139 */mercurial/commandserver.py:* in runcommand (glob)
139 */mercurial/commandserver.py:* in runcommand (glob)
140 */mercurial/dispatch.py:* in dispatch (glob)
140 */mercurial/dispatch.py:* in dispatch (glob)
141 */mercurial/dispatch.py:* in _runcatch (glob)
141 */mercurial/dispatch.py:* in _runcatch (glob)
142 */mercurial/dispatch.py:* in _callcatch (glob)
142 */mercurial/dispatch.py:* in _callcatch (glob)
143 */mercurial/scmutil.py:* in callcatch (glob)
143 */mercurial/scmutil.py:* in callcatch (glob)
144 */mercurial/dispatch.py:* in _runcatchfunc (glob)
144 */mercurial/dispatch.py:* in _runcatchfunc (glob)
145 */mercurial/dispatch.py:* in _dispatch (glob)
145 */mercurial/dispatch.py:* in _dispatch (glob)
146 */mercurial/dispatch.py:* in runcommand (glob)
146 */mercurial/dispatch.py:* in runcommand (glob)
147 */mercurial/dispatch.py:* in _runcommand (glob)
147 */mercurial/dispatch.py:* in _runcommand (glob)
148 */mercurial/dispatch.py:* in <lambda> (glob)
148 */mercurial/dispatch.py:* in <lambda> (glob)
149 */mercurial/util.py:* in check (glob)
149 */mercurial/util.py:* in check (glob)
150 $TESTTMP/buggylocking.py:* in buggylocking (glob)
150 $TESTTMP/buggylocking.py:* in buggylocking (glob)
151 #endif
151 #endif
152 $ hg properlocking
152 $ hg properlocking
153 $ hg nowaitlocking
153 $ hg nowaitlocking
154
154
155 Writing without lock
155 Writing without lock
156
156
157 $ hg no-wlock-write
157 $ hg no-wlock-write
158 devel-warn: write with no wlock: "branch" at: $TESTTMP/buggylocking.py:* (nowlockwrite) (glob)
158 devel-warn: write with no wlock: "branch" at: $TESTTMP/buggylocking.py:* (nowlockwrite) (glob)
159
159
160 $ hg no-lock-write
160 $ hg no-lock-write
161 devel-warn: write with no lock: "fncache" at: $TESTTMP/buggylocking.py:* (nolockwrite) (glob)
161 devel-warn: write with no lock: "fncache" at: $TESTTMP/buggylocking.py:* (nolockwrite) (glob)
162
162
163 Stripping from a transaction
163 Stripping from a transaction
164
164
165 $ echo a > a
165 $ echo a > a
166 $ hg add a
166 $ hg add a
167 $ hg commit -m a
167 $ hg commit -m a
168 $ hg stripintr 2>&1 | egrep -v '^(\*\*| )'
168 $ hg stripintr 2>&1 | egrep -v '^(\*\*| )'
169 Traceback (most recent call last):
169 Traceback (most recent call last):
170 *ProgrammingError: cannot strip from inside a transaction (glob)
170 *ProgrammingError: cannot strip from inside a transaction (glob)
171
171
172 $ hg oldanddeprecated
172 $ hg oldanddeprecated
173 devel-warn: foorbar is deprecated, go shopping
173 devel-warn: foorbar is deprecated, go shopping
174 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
174 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
175
175
176 #if no-chg
176 #if no-chg
177 $ hg oldanddeprecated --traceback
177 $ hg oldanddeprecated --traceback
178 devel-warn: foorbar is deprecated, go shopping
178 devel-warn: foorbar is deprecated, go shopping
179 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
179 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
180 */hg:* in <module> (glob)
180 */hg:* in <module> (glob)
181 */mercurial/dispatch.py:* in run (glob)
181 */mercurial/dispatch.py:* in run (glob)
182 */mercurial/dispatch.py:* in dispatch (glob)
182 */mercurial/dispatch.py:* in dispatch (glob)
183 */mercurial/dispatch.py:* in _runcatch (glob)
183 */mercurial/dispatch.py:* in _runcatch (glob)
184 */mercurial/dispatch.py:* in _callcatch (glob)
184 */mercurial/dispatch.py:* in _callcatch (glob)
185 */mercurial/scmutil.py* in callcatch (glob)
185 */mercurial/scmutil.py* in callcatch (glob)
186 */mercurial/dispatch.py:* in _runcatchfunc (glob)
186 */mercurial/dispatch.py:* in _runcatchfunc (glob)
187 */mercurial/dispatch.py:* in _dispatch (glob)
187 */mercurial/dispatch.py:* in _dispatch (glob)
188 */mercurial/dispatch.py:* in runcommand (glob)
188 */mercurial/dispatch.py:* in runcommand (glob)
189 */mercurial/dispatch.py:* in _runcommand (glob)
189 */mercurial/dispatch.py:* in _runcommand (glob)
190 */mercurial/dispatch.py:* in <lambda> (glob)
190 */mercurial/dispatch.py:* in <lambda> (glob)
191 */mercurial/util.py:* in check (glob)
191 */mercurial/util.py:* in check (glob)
192 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
192 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
193 #else
193 #else
194 $ hg oldanddeprecated --traceback
194 $ hg oldanddeprecated --traceback
195 devel-warn: foorbar is deprecated, go shopping
195 devel-warn: foorbar is deprecated, go shopping
196 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
196 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
197 */hg:* in <module> (glob)
197 */hg:* in <module> (glob)
198 */mercurial/dispatch.py:* in run (glob)
198 */mercurial/dispatch.py:* in run (glob)
199 */mercurial/dispatch.py:* in dispatch (glob)
199 */mercurial/dispatch.py:* in dispatch (glob)
200 */mercurial/dispatch.py:* in _runcatch (glob)
200 */mercurial/dispatch.py:* in _runcatch (glob)
201 */mercurial/dispatch.py:* in _callcatch (glob)
201 */mercurial/dispatch.py:* in _callcatch (glob)
202 */mercurial/scmutil.py:* in callcatch (glob)
202 */mercurial/scmutil.py:* in callcatch (glob)
203 */mercurial/dispatch.py:* in _runcatchfunc (glob)
203 */mercurial/dispatch.py:* in _runcatchfunc (glob)
204 */mercurial/dispatch.py:* in _dispatch (glob)
204 */mercurial/dispatch.py:* in _dispatch (glob)
205 */mercurial/dispatch.py:* in runcommand (glob)
205 */mercurial/dispatch.py:* in runcommand (glob)
206 */mercurial/dispatch.py:* in _runcommand (glob)
206 */mercurial/dispatch.py:* in _runcommand (glob)
207 */mercurial/dispatch.py:* in <lambda> (glob)
207 */mercurial/dispatch.py:* in <lambda> (glob)
208 */mercurial/util.py:* in check (glob)
208 */mercurial/util.py:* in check (glob)
209 */mercurial/commands.py:* in serve (glob)
209 */mercurial/commands.py:* in serve (glob)
210 */mercurial/server.py:* in runservice (glob)
210 */mercurial/server.py:* in runservice (glob)
211 */mercurial/commandserver.py:* in run (glob)
211 */mercurial/commandserver.py:* in run (glob)
212 */mercurial/commandserver.py:* in _mainloop (glob)
212 */mercurial/commandserver.py:* in _mainloop (glob)
213 */mercurial/commandserver.py:* in _runworker (glob)
213 */mercurial/commandserver.py:* in _runworker (glob)
214 */mercurial/commandserver.py:* in _serverequest (glob)
214 */mercurial/commandserver.py:* in _serverequest (glob)
215 */mercurial/commandserver.py:* in serve (glob)
215 */mercurial/commandserver.py:* in serve (glob)
216 */mercurial/commandserver.py:* in serveone (glob)
216 */mercurial/commandserver.py:* in serveone (glob)
217 */mercurial/chgserver.py:* in runcommand (glob)
217 */mercurial/chgserver.py:* in runcommand (glob)
218 */mercurial/commandserver.py:* in runcommand (glob)
218 */mercurial/commandserver.py:* in runcommand (glob)
219 */mercurial/dispatch.py:* in dispatch (glob)
219 */mercurial/dispatch.py:* in dispatch (glob)
220 */mercurial/dispatch.py:* in _runcatch (glob)
220 */mercurial/dispatch.py:* in _runcatch (glob)
221 */mercurial/dispatch.py:* in _callcatch (glob)
221 */mercurial/dispatch.py:* in _callcatch (glob)
222 */mercurial/scmutil.py:* in callcatch (glob)
222 */mercurial/scmutil.py:* in callcatch (glob)
223 */mercurial/dispatch.py:* in _runcatchfunc (glob)
223 */mercurial/dispatch.py:* in _runcatchfunc (glob)
224 */mercurial/dispatch.py:* in _dispatch (glob)
224 */mercurial/dispatch.py:* in _dispatch (glob)
225 */mercurial/dispatch.py:* in runcommand (glob)
225 */mercurial/dispatch.py:* in runcommand (glob)
226 */mercurial/dispatch.py:* in _runcommand (glob)
226 */mercurial/dispatch.py:* in _runcommand (glob)
227 */mercurial/dispatch.py:* in <lambda> (glob)
227 */mercurial/dispatch.py:* in <lambda> (glob)
228 */mercurial/util.py:* in check (glob)
228 */mercurial/util.py:* in check (glob)
229 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
229 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
230 #endif
230 #endif
231
231
232 #if no-chg
232 #if no-chg
233 $ hg blackbox -l 7
233 $ hg blackbox -l 7
234 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
234 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
235 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
235 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
236 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
236 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
237 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
237 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
238 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
238 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
239 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
239 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
240 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
240 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
241 */hg:* in <module> (glob)
241 */hg:* in <module> (glob)
242 */mercurial/dispatch.py:* in run (glob)
242 */mercurial/dispatch.py:* in run (glob)
243 */mercurial/dispatch.py:* in dispatch (glob)
243 */mercurial/dispatch.py:* in dispatch (glob)
244 */mercurial/dispatch.py:* in _runcatch (glob)
244 */mercurial/dispatch.py:* in _runcatch (glob)
245 */mercurial/dispatch.py:* in _callcatch (glob)
245 */mercurial/dispatch.py:* in _callcatch (glob)
246 */mercurial/scmutil.py* in callcatch (glob)
246 */mercurial/scmutil.py* in callcatch (glob)
247 */mercurial/dispatch.py:* in _runcatchfunc (glob)
247 */mercurial/dispatch.py:* in _runcatchfunc (glob)
248 */mercurial/dispatch.py:* in _dispatch (glob)
248 */mercurial/dispatch.py:* in _dispatch (glob)
249 */mercurial/dispatch.py:* in runcommand (glob)
249 */mercurial/dispatch.py:* in runcommand (glob)
250 */mercurial/dispatch.py:* in _runcommand (glob)
250 */mercurial/dispatch.py:* in _runcommand (glob)
251 */mercurial/dispatch.py:* in <lambda> (glob)
251 */mercurial/dispatch.py:* in <lambda> (glob)
252 */mercurial/util.py:* in check (glob)
252 */mercurial/util.py:* in check (glob)
253 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
253 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
254 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
254 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
255 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
255 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
256 #else
256 #else
257 $ hg blackbox -l 7
257 $ hg blackbox -l 7
258 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
258 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
259 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
259 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
260 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
260 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
261 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
261 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
262 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
262 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
263 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
263 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
264 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
264 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
265 */hg:* in <module> (glob)
265 */hg:* in <module> (glob)
266 */mercurial/dispatch.py:* in run (glob)
266 */mercurial/dispatch.py:* in run (glob)
267 */mercurial/dispatch.py:* in dispatch (glob)
267 */mercurial/dispatch.py:* in dispatch (glob)
268 */mercurial/dispatch.py:* in _runcatch (glob)
268 */mercurial/dispatch.py:* in _runcatch (glob)
269 */mercurial/dispatch.py:* in _callcatch (glob)
269 */mercurial/dispatch.py:* in _callcatch (glob)
270 */mercurial/scmutil.py:* in callcatch (glob)
270 */mercurial/scmutil.py:* in callcatch (glob)
271 */mercurial/dispatch.py:* in _runcatchfunc (glob)
271 */mercurial/dispatch.py:* in _runcatchfunc (glob)
272 */mercurial/dispatch.py:* in _dispatch (glob)
272 */mercurial/dispatch.py:* in _dispatch (glob)
273 */mercurial/dispatch.py:* in runcommand (glob)
273 */mercurial/dispatch.py:* in runcommand (glob)
274 */mercurial/dispatch.py:* in _runcommand (glob)
274 */mercurial/dispatch.py:* in _runcommand (glob)
275 */mercurial/dispatch.py:* in <lambda> (glob)
275 */mercurial/dispatch.py:* in <lambda> (glob)
276 */mercurial/util.py:* in check (glob)
276 */mercurial/util.py:* in check (glob)
277 */mercurial/commands.py:* in serve (glob)
277 */mercurial/commands.py:* in serve (glob)
278 */mercurial/server.py:* in runservice (glob)
278 */mercurial/server.py:* in runservice (glob)
279 */mercurial/commandserver.py:* in run (glob)
279 */mercurial/commandserver.py:* in run (glob)
280 */mercurial/commandserver.py:* in _mainloop (glob)
280 */mercurial/commandserver.py:* in _mainloop (glob)
281 */mercurial/commandserver.py:* in _runworker (glob)
281 */mercurial/commandserver.py:* in _runworker (glob)
282 */mercurial/commandserver.py:* in _serverequest (glob)
282 */mercurial/commandserver.py:* in _serverequest (glob)
283 */mercurial/commandserver.py:* in serve (glob)
283 */mercurial/commandserver.py:* in serve (glob)
284 */mercurial/commandserver.py:* in serveone (glob)
284 */mercurial/commandserver.py:* in serveone (glob)
285 */mercurial/chgserver.py:* in runcommand (glob)
285 */mercurial/chgserver.py:* in runcommand (glob)
286 */mercurial/commandserver.py:* in runcommand (glob)
286 */mercurial/commandserver.py:* in runcommand (glob)
287 */mercurial/dispatch.py:* in dispatch (glob)
287 */mercurial/dispatch.py:* in dispatch (glob)
288 */mercurial/dispatch.py:* in _runcatch (glob)
288 */mercurial/dispatch.py:* in _runcatch (glob)
289 */mercurial/dispatch.py:* in _callcatch (glob)
289 */mercurial/dispatch.py:* in _callcatch (glob)
290 */mercurial/scmutil.py:* in callcatch (glob)
290 */mercurial/scmutil.py:* in callcatch (glob)
291 */mercurial/dispatch.py:* in _runcatchfunc (glob)
291 */mercurial/dispatch.py:* in _runcatchfunc (glob)
292 */mercurial/dispatch.py:* in _dispatch (glob)
292 */mercurial/dispatch.py:* in _dispatch (glob)
293 */mercurial/dispatch.py:* in runcommand (glob)
293 */mercurial/dispatch.py:* in runcommand (glob)
294 */mercurial/dispatch.py:* in _runcommand (glob)
294 */mercurial/dispatch.py:* in _runcommand (glob)
295 */mercurial/dispatch.py:* in <lambda> (glob)
295 */mercurial/dispatch.py:* in <lambda> (glob)
296 */mercurial/util.py:* in check (glob)
296 */mercurial/util.py:* in check (glob)
297 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
297 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
298 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
298 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
299 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
299 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
300 #endif
300 #endif
301
301
302 Test programming error failure:
302 Test programming error failure:
303
303
304 $ hg buggytransaction 2>&1 | egrep -v '^ '
304 $ hg buggytransaction 2>&1 | egrep -v '^ '
305 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
305 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
306 ** which supports versions unknown of Mercurial.
306 ** which supports versions unknown of Mercurial.
307 ** Please disable buggylocking and try your action again.
307 ** Please disable buggylocking and try your action again.
308 ** If that fixes the bug please report it to the extension author.
308 ** If that fixes the bug please report it to the extension author.
309 ** Python * (glob)
309 ** Python * (glob)
310 ** Mercurial Distributed SCM (*) (glob)
310 ** Mercurial Distributed SCM (*) (glob)
311 ** Extensions loaded: * (glob)
311 ** Extensions loaded: * (glob)
312 ** ProgrammingError: transaction requires locking
312 ** ProgrammingError: transaction requires locking
313 Traceback (most recent call last):
313 Traceback (most recent call last):
314 *ProgrammingError: transaction requires locking (glob)
314 *ProgrammingError: transaction requires locking (glob)
315
315
316 $ hg programmingerror 2>&1 | egrep -v '^ '
316 $ hg programmingerror 2>&1 | egrep -v '^ '
317 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
317 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
318 ** which supports versions unknown of Mercurial.
318 ** which supports versions unknown of Mercurial.
319 ** Please disable buggylocking and try your action again.
319 ** Please disable buggylocking and try your action again.
320 ** If that fixes the bug please report it to the extension author.
320 ** If that fixes the bug please report it to the extension author.
321 ** Python * (glob)
321 ** Python * (glob)
322 ** Mercurial Distributed SCM (*) (glob)
322 ** Mercurial Distributed SCM (*) (glob)
323 ** Extensions loaded: * (glob)
323 ** Extensions loaded: * (glob)
324 ** ProgrammingError: something went wrong
324 ** ProgrammingError: something went wrong
325 ** (try again)
325 ** (try again)
326 Traceback (most recent call last):
326 Traceback (most recent call last):
327 *ProgrammingError: something went wrong (glob)
327 *ProgrammingError: something went wrong (glob)
328
328
329 Old style deprecation warning
329 Old style deprecation warning
330
330
331 $ hg nouiwarning
331 $ hg nouiwarning
332 $TESTTMP/buggylocking.py:*: DeprecationWarning: this is a test (glob)
332 $TESTTMP/buggylocking.py:*: DeprecationWarning: this is a test (glob)
333 (compatibility will be dropped after Mercurial-13.37, update your code.)
333 (compatibility will be dropped after Mercurial-13.37, update your code.)
334 util.nouideprecwarn('this is a test', '13.37')
334 util.nouideprecwarn('this is a test', '13.37')
335
335
336 (disabled outside of test run)
336 (disabled outside of test run)
337
337
338 $ HGEMITWARNINGS= hg nouiwarning
338 $ HGEMITWARNINGS= hg nouiwarning
339
339
340 Test warning on config option access and registration
340 Test warning on config option access and registration
341
341
342 $ cat << EOF > ${TESTTMP}/buggyconfig.py
342 $ cat << EOF > ${TESTTMP}/buggyconfig.py
343 > """A small extension that tests our developer warnings for config"""
343 > """A small extension that tests our developer warnings for config"""
344 >
344 >
345 > from mercurial import registrar, configitems
345 > from mercurial import registrar, configitems
346 >
346 >
347 > cmdtable = {}
347 > cmdtable = {}
348 > command = registrar.command(cmdtable)
348 > command = registrar.command(cmdtable)
349 >
349 >
350 > configtable = {}
350 > configtable = {}
351 > configitem = registrar.configitem(configtable)
351 > configitem = registrar.configitem(configtable)
352 >
352 >
353 > configitem('test', 'some', default='foo')
353 > configitem('test', 'some', default='foo')
354 > configitem('test', 'dynamic', default=configitems.dynamicdefault)
354 > configitem('test', 'dynamic', default=configitems.dynamicdefault)
355 > # overwrite a core config
355 > # overwrite a core config
356 > configitem('ui', 'quiet', default=False)
356 > configitem('ui', 'quiet', default=False)
357 > configitem('ui', 'interactive', default=None)
357 > configitem('ui', 'interactive', default=None)
358 >
358 >
359 > @command(b'buggyconfig')
359 > @command(b'buggyconfig')
360 > def cmdbuggyconfig(ui, repo):
360 > def cmdbuggyconfig(ui, repo):
361 > repo.ui.config('ui', 'quiet', False)
361 > repo.ui.config('ui', 'quiet', False)
362 > repo.ui.config('ui', 'interactive', None)
362 > repo.ui.config('ui', 'interactive', None)
363 > repo.ui.config('test', 'some', 'foo')
363 > repo.ui.config('test', 'some', 'foo')
364 > repo.ui.config('test', 'dynamic', 'some-required-default')
364 > repo.ui.config('test', 'dynamic', 'some-required-default')
365 > repo.ui.config('test', 'dynamic')
365 > repo.ui.config('test', 'dynamic')
366 > repo.ui.config('test', 'unregistered')
367 > repo.ui.config('unregistered', 'unregistered')
366 > EOF
368 > EOF
367
369
368 $ hg --config "extensions.buggyconfig=${TESTTMP}/buggyconfig.py" buggyconfig
370 $ hg --config "extensions.buggyconfig=${TESTTMP}/buggyconfig.py" buggyconfig
369 devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: */mercurial/extensions.py:* (_loadextra) (glob)
371 devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: */mercurial/extensions.py:* (_loadextra) (glob)
370 devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: */mercurial/extensions.py:* (_loadextra) (glob)
372 devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: */mercurial/extensions.py:* (_loadextra) (glob)
371 devel-warn: specifying a default value for a registered config item: 'ui.quiet' 'False' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
373 devel-warn: specifying a default value for a registered config item: 'ui.quiet' 'False' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
372 devel-warn: specifying a default value for a registered config item: 'ui.interactive' 'None' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
374 devel-warn: specifying a default value for a registered config item: 'ui.interactive' 'None' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
373 devel-warn: specifying a default value for a registered config item: 'test.some' 'foo' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
375 devel-warn: specifying a default value for a registered config item: 'test.some' 'foo' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
374 devel-warn: config item requires an explicit default value: 'test.dynamic' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
376 devel-warn: config item requires an explicit default value: 'test.dynamic' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
377 devel-warn: accessing unregistered config item: 'test.unregistered' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
378 devel-warn: accessing unregistered config item: 'unregistered.unregistered' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
375
379
376 $ cd ..
380 $ cd ..
@@ -1,247 +1,261
1 # Since it's not easy to write a test that portably deals
1 # Since it's not easy to write a test that portably deals
2 # with files from different users/groups, we cheat a bit by
2 # with files from different users/groups, we cheat a bit by
3 # monkey-patching some functions in the util module
3 # monkey-patching some functions in the util module
4
4
5 from __future__ import absolute_import, print_function
5 from __future__ import absolute_import, print_function
6
6
7 import os
7 import os
8 from mercurial import (
8 from mercurial import (
9 error,
9 error,
10 ui as uimod,
10 ui as uimod,
11 util,
11 util,
12 )
12 )
13
13
14 hgrc = os.environ['HGRCPATH']
14 hgrc = os.environ['HGRCPATH']
15 f = open(hgrc)
15 f = open(hgrc)
16 basehgrc = f.read()
16 basehgrc = f.read()
17 f.close()
17 f.close()
18
18
19 def testui(user='foo', group='bar', tusers=(), tgroups=(),
19 def testui(user='foo', group='bar', tusers=(), tgroups=(),
20 cuser='foo', cgroup='bar', debug=False, silent=False,
20 cuser='foo', cgroup='bar', debug=False, silent=False,
21 report=True):
21 report=True):
22 # user, group => owners of the file
22 # user, group => owners of the file
23 # tusers, tgroups => trusted users/groups
23 # tusers, tgroups => trusted users/groups
24 # cuser, cgroup => user/group of the current process
24 # cuser, cgroup => user/group of the current process
25
25
26 # write a global hgrc with the list of trusted users/groups and
26 # write a global hgrc with the list of trusted users/groups and
27 # some setting so that we can be sure it was read
27 # some setting so that we can be sure it was read
28 f = open(hgrc, 'w')
28 f = open(hgrc, 'w')
29 f.write(basehgrc)
29 f.write(basehgrc)
30 f.write('\n[paths]\n')
30 f.write('\n[paths]\n')
31 f.write('global = /some/path\n\n')
31 f.write('global = /some/path\n\n')
32
32
33 if tusers or tgroups:
33 if tusers or tgroups:
34 f.write('[trusted]\n')
34 f.write('[trusted]\n')
35 if tusers:
35 if tusers:
36 f.write('users = %s\n' % ', '.join(tusers))
36 f.write('users = %s\n' % ', '.join(tusers))
37 if tgroups:
37 if tgroups:
38 f.write('groups = %s\n' % ', '.join(tgroups))
38 f.write('groups = %s\n' % ', '.join(tgroups))
39 f.close()
39 f.close()
40
40
41 # override the functions that give names to uids and gids
41 # override the functions that give names to uids and gids
42 def username(uid=None):
42 def username(uid=None):
43 if uid is None:
43 if uid is None:
44 return cuser
44 return cuser
45 return user
45 return user
46 util.username = username
46 util.username = username
47
47
48 def groupname(gid=None):
48 def groupname(gid=None):
49 if gid is None:
49 if gid is None:
50 return 'bar'
50 return 'bar'
51 return group
51 return group
52 util.groupname = groupname
52 util.groupname = groupname
53
53
54 def isowner(st):
54 def isowner(st):
55 return user == cuser
55 return user == cuser
56 util.isowner = isowner
56 util.isowner = isowner
57
57
58 # try to read everything
58 # try to read everything
59 #print '# File belongs to user %s, group %s' % (user, group)
59 #print '# File belongs to user %s, group %s' % (user, group)
60 #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
60 #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
61 kind = ('different', 'same')
61 kind = ('different', 'same')
62 who = ('', 'user', 'group', 'user and the group')
62 who = ('', 'user', 'group', 'user and the group')
63 trusted = who[(user in tusers) + 2*(group in tgroups)]
63 trusted = who[(user in tusers) + 2*(group in tgroups)]
64 if trusted:
64 if trusted:
65 trusted = ', but we trust the ' + trusted
65 trusted = ', but we trust the ' + trusted
66 print('# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
66 print('# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
67 trusted))
67 trusted))
68
68
69 u = uimod.ui.load()
69 u = uimod.ui.load()
70 # disable the configuration registration warning
71 #
72 # the purpose of this test is to check the old behavior, not to validate the
73 # behavior from registered item. so we silent warning related to unregisted
74 # config.
75 u.setconfig('devel', 'warn-config-unknown', False, 'test')
76 u.setconfig('devel', 'all-warnings', False, 'test')
70 u.setconfig('ui', 'debug', str(bool(debug)))
77 u.setconfig('ui', 'debug', str(bool(debug)))
71 u.setconfig('ui', 'report_untrusted', str(bool(report)))
78 u.setconfig('ui', 'report_untrusted', str(bool(report)))
72 u.readconfig('.hg/hgrc')
79 u.readconfig('.hg/hgrc')
73 if silent:
80 if silent:
74 return u
81 return u
75 print('trusted')
82 print('trusted')
76 for name, path in u.configitems('paths'):
83 for name, path in u.configitems('paths'):
77 print(' ', name, '=', util.pconvert(path))
84 print(' ', name, '=', util.pconvert(path))
78 print('untrusted')
85 print('untrusted')
79 for name, path in u.configitems('paths', untrusted=True):
86 for name, path in u.configitems('paths', untrusted=True):
80 print('.', end=' ')
87 print('.', end=' ')
81 u.config('paths', name) # warning with debug=True
88 u.config('paths', name) # warning with debug=True
82 print('.', end=' ')
89 print('.', end=' ')
83 u.config('paths', name, untrusted=True) # no warnings
90 u.config('paths', name, untrusted=True) # no warnings
84 print(name, '=', util.pconvert(path))
91 print(name, '=', util.pconvert(path))
85 print()
92 print()
86
93
87 return u
94 return u
88
95
89 os.mkdir('repo')
96 os.mkdir('repo')
90 os.chdir('repo')
97 os.chdir('repo')
91 os.mkdir('.hg')
98 os.mkdir('.hg')
92 f = open('.hg/hgrc', 'w')
99 f = open('.hg/hgrc', 'w')
93 f.write('[paths]\n')
100 f.write('[paths]\n')
94 f.write('local = /another/path\n\n')
101 f.write('local = /another/path\n\n')
95 f.close()
102 f.close()
96
103
97 #print '# Everything is run by user foo, group bar\n'
104 #print '# Everything is run by user foo, group bar\n'
98
105
99 # same user, same group
106 # same user, same group
100 testui()
107 testui()
101 # same user, different group
108 # same user, different group
102 testui(group='def')
109 testui(group='def')
103 # different user, same group
110 # different user, same group
104 testui(user='abc')
111 testui(user='abc')
105 # ... but we trust the group
112 # ... but we trust the group
106 testui(user='abc', tgroups=['bar'])
113 testui(user='abc', tgroups=['bar'])
107 # different user, different group
114 # different user, different group
108 testui(user='abc', group='def')
115 testui(user='abc', group='def')
109 # ... but we trust the user
116 # ... but we trust the user
110 testui(user='abc', group='def', tusers=['abc'])
117 testui(user='abc', group='def', tusers=['abc'])
111 # ... but we trust the group
118 # ... but we trust the group
112 testui(user='abc', group='def', tgroups=['def'])
119 testui(user='abc', group='def', tgroups=['def'])
113 # ... but we trust the user and the group
120 # ... but we trust the user and the group
114 testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
121 testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
115 # ... but we trust all users
122 # ... but we trust all users
116 print('# we trust all users')
123 print('# we trust all users')
117 testui(user='abc', group='def', tusers=['*'])
124 testui(user='abc', group='def', tusers=['*'])
118 # ... but we trust all groups
125 # ... but we trust all groups
119 print('# we trust all groups')
126 print('# we trust all groups')
120 testui(user='abc', group='def', tgroups=['*'])
127 testui(user='abc', group='def', tgroups=['*'])
121 # ... but we trust the whole universe
128 # ... but we trust the whole universe
122 print('# we trust all users and groups')
129 print('# we trust all users and groups')
123 testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
130 testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
124 # ... check that users and groups are in different namespaces
131 # ... check that users and groups are in different namespaces
125 print("# we don't get confused by users and groups with the same name")
132 print("# we don't get confused by users and groups with the same name")
126 testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
133 testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
127 # ... lists of user names work
134 # ... lists of user names work
128 print("# list of user names")
135 print("# list of user names")
129 testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
136 testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
130 tgroups=['bar', 'baz', 'qux'])
137 tgroups=['bar', 'baz', 'qux'])
131 # ... lists of group names work
138 # ... lists of group names work
132 print("# list of group names")
139 print("# list of group names")
133 testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
140 testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
134 tgroups=['bar', 'def', 'baz', 'qux'])
141 tgroups=['bar', 'def', 'baz', 'qux'])
135
142
136 print("# Can't figure out the name of the user running this process")
143 print("# Can't figure out the name of the user running this process")
137 testui(user='abc', group='def', cuser=None)
144 testui(user='abc', group='def', cuser=None)
138
145
139 print("# prints debug warnings")
146 print("# prints debug warnings")
140 u = testui(user='abc', group='def', cuser='foo', debug=True)
147 u = testui(user='abc', group='def', cuser='foo', debug=True)
141
148
142 print("# report_untrusted enabled without debug hides warnings")
149 print("# report_untrusted enabled without debug hides warnings")
143 u = testui(user='abc', group='def', cuser='foo', report=False)
150 u = testui(user='abc', group='def', cuser='foo', report=False)
144
151
145 print("# report_untrusted enabled with debug shows warnings")
152 print("# report_untrusted enabled with debug shows warnings")
146 u = testui(user='abc', group='def', cuser='foo', debug=True, report=False)
153 u = testui(user='abc', group='def', cuser='foo', debug=True, report=False)
147
154
148 print("# ui.readconfig sections")
155 print("# ui.readconfig sections")
149 filename = 'foobar'
156 filename = 'foobar'
150 f = open(filename, 'w')
157 f = open(filename, 'w')
151 f.write('[foobar]\n')
158 f.write('[foobar]\n')
152 f.write('baz = quux\n')
159 f.write('baz = quux\n')
153 f.close()
160 f.close()
154 u.readconfig(filename, sections=['foobar'])
161 u.readconfig(filename, sections=['foobar'])
155 print(u.config('foobar', 'baz'))
162 print(u.config('foobar', 'baz'))
156
163
157 print()
164 print()
158 print("# read trusted, untrusted, new ui, trusted")
165 print("# read trusted, untrusted, new ui, trusted")
159 u = uimod.ui.load()
166 u = uimod.ui.load()
167 # disable the configuration registration warning
168 #
169 # the purpose of this test is to check the old behavior, not to validate the
170 # behavior from registered item. so we silent warning related to unregisted
171 # config.
172 u.setconfig('devel', 'warn-config-unknown', False, 'test')
173 u.setconfig('devel', 'all-warnings', False, 'test')
160 u.setconfig('ui', 'debug', 'on')
174 u.setconfig('ui', 'debug', 'on')
161 u.readconfig(filename)
175 u.readconfig(filename)
162 u2 = u.copy()
176 u2 = u.copy()
163 def username(uid=None):
177 def username(uid=None):
164 return 'foo'
178 return 'foo'
165 util.username = username
179 util.username = username
166 u2.readconfig('.hg/hgrc')
180 u2.readconfig('.hg/hgrc')
167 print('trusted:')
181 print('trusted:')
168 print(u2.config('foobar', 'baz'))
182 print(u2.config('foobar', 'baz'))
169 print('untrusted:')
183 print('untrusted:')
170 print(u2.config('foobar', 'baz', untrusted=True))
184 print(u2.config('foobar', 'baz', untrusted=True))
171
185
172 print()
186 print()
173 print("# error handling")
187 print("# error handling")
174
188
175 def assertraises(f, exc=error.Abort):
189 def assertraises(f, exc=error.Abort):
176 try:
190 try:
177 f()
191 f()
178 except exc as inst:
192 except exc as inst:
179 print('raised', inst.__class__.__name__)
193 print('raised', inst.__class__.__name__)
180 else:
194 else:
181 print('no exception?!')
195 print('no exception?!')
182
196
183 print("# file doesn't exist")
197 print("# file doesn't exist")
184 os.unlink('.hg/hgrc')
198 os.unlink('.hg/hgrc')
185 assert not os.path.exists('.hg/hgrc')
199 assert not os.path.exists('.hg/hgrc')
186 testui(debug=True, silent=True)
200 testui(debug=True, silent=True)
187 testui(user='abc', group='def', debug=True, silent=True)
201 testui(user='abc', group='def', debug=True, silent=True)
188
202
189 print()
203 print()
190 print("# parse error")
204 print("# parse error")
191 f = open('.hg/hgrc', 'w')
205 f = open('.hg/hgrc', 'w')
192 f.write('foo')
206 f.write('foo')
193 f.close()
207 f.close()
194
208
195 try:
209 try:
196 testui(user='abc', group='def', silent=True)
210 testui(user='abc', group='def', silent=True)
197 except error.ParseError as inst:
211 except error.ParseError as inst:
198 print(inst)
212 print(inst)
199
213
200 try:
214 try:
201 testui(debug=True, silent=True)
215 testui(debug=True, silent=True)
202 except error.ParseError as inst:
216 except error.ParseError as inst:
203 print(inst)
217 print(inst)
204
218
205 print()
219 print()
206 print('# access typed information')
220 print('# access typed information')
207 with open('.hg/hgrc', 'w') as f:
221 with open('.hg/hgrc', 'w') as f:
208 f.write('''\
222 f.write('''\
209 [foo]
223 [foo]
210 sub=main
224 sub=main
211 sub:one=one
225 sub:one=one
212 sub:two=two
226 sub:two=two
213 path=monty/python
227 path=monty/python
214 bool=true
228 bool=true
215 int=42
229 int=42
216 bytes=81mb
230 bytes=81mb
217 list=spam,ham,eggs
231 list=spam,ham,eggs
218 ''')
232 ''')
219 u = testui(user='abc', group='def', cuser='foo', silent=True)
233 u = testui(user='abc', group='def', cuser='foo', silent=True)
220 def configpath(section, name, default=None, untrusted=False):
234 def configpath(section, name, default=None, untrusted=False):
221 path = u.configpath(section, name, default, untrusted)
235 path = u.configpath(section, name, default, untrusted)
222 if path is None:
236 if path is None:
223 return None
237 return None
224 return util.pconvert(path)
238 return util.pconvert(path)
225
239
226 print('# suboptions, trusted and untrusted')
240 print('# suboptions, trusted and untrusted')
227 trusted = u.configsuboptions('foo', 'sub')
241 trusted = u.configsuboptions('foo', 'sub')
228 untrusted = u.configsuboptions('foo', 'sub', untrusted=True)
242 untrusted = u.configsuboptions('foo', 'sub', untrusted=True)
229 print(
243 print(
230 (trusted[0], sorted(trusted[1].items())),
244 (trusted[0], sorted(trusted[1].items())),
231 (untrusted[0], sorted(untrusted[1].items())))
245 (untrusted[0], sorted(untrusted[1].items())))
232 print('# path, trusted and untrusted')
246 print('# path, trusted and untrusted')
233 print(configpath('foo', 'path'), configpath('foo', 'path', untrusted=True))
247 print(configpath('foo', 'path'), configpath('foo', 'path', untrusted=True))
234 print('# bool, trusted and untrusted')
248 print('# bool, trusted and untrusted')
235 print(u.configbool('foo', 'bool'), u.configbool('foo', 'bool', untrusted=True))
249 print(u.configbool('foo', 'bool'), u.configbool('foo', 'bool', untrusted=True))
236 print('# int, trusted and untrusted')
250 print('# int, trusted and untrusted')
237 print(
251 print(
238 u.configint('foo', 'int', 0),
252 u.configint('foo', 'int', 0),
239 u.configint('foo', 'int', 0, untrusted=True))
253 u.configint('foo', 'int', 0, untrusted=True))
240 print('# bytes, trusted and untrusted')
254 print('# bytes, trusted and untrusted')
241 print(
255 print(
242 u.configbytes('foo', 'bytes', 0),
256 u.configbytes('foo', 'bytes', 0),
243 u.configbytes('foo', 'bytes', 0, untrusted=True))
257 u.configbytes('foo', 'bytes', 0, untrusted=True))
244 print('# list, trusted and untrusted')
258 print('# list, trusted and untrusted')
245 print(
259 print(
246 u.configlist('foo', 'list', []),
260 u.configlist('foo', 'list', []),
247 u.configlist('foo', 'list', [], untrusted=True))
261 u.configlist('foo', 'list', [], untrusted=True))
@@ -1,113 +1,122
1 from __future__ import absolute_import, print_function
1 from __future__ import absolute_import, print_function
2 from mercurial import (
2 from mercurial import (
3 dispatch,
3 dispatch,
4 error,
4 error,
5 ui as uimod,
5 ui as uimod,
6 )
6 )
7
7
8 testui = uimod.ui.load()
8 testui = uimod.ui.load()
9
10 # disable the configuration registration warning
11 #
12 # the purpose of this test is to check the old behavior, not to validate the
13 # behavior from registered item. so we silent warning related to unregisted
14 # config.
15 testui.setconfig('devel', 'warn-config-unknown', False, 'test')
16 testui.setconfig('devel', 'all-warnings', False, 'test')
17
9 parsed = dispatch._parseconfig(testui, [
18 parsed = dispatch._parseconfig(testui, [
10 'values.string=string value',
19 'values.string=string value',
11 'values.bool1=true',
20 'values.bool1=true',
12 'values.bool2=false',
21 'values.bool2=false',
13 'values.boolinvalid=foo',
22 'values.boolinvalid=foo',
14 'values.int1=42',
23 'values.int1=42',
15 'values.int2=-42',
24 'values.int2=-42',
16 'values.intinvalid=foo',
25 'values.intinvalid=foo',
17 'lists.list1=foo',
26 'lists.list1=foo',
18 'lists.list2=foo bar baz',
27 'lists.list2=foo bar baz',
19 'lists.list3=alice, bob',
28 'lists.list3=alice, bob',
20 'lists.list4=foo bar baz alice, bob',
29 'lists.list4=foo bar baz alice, bob',
21 'lists.list5=abc d"ef"g "hij def"',
30 'lists.list5=abc d"ef"g "hij def"',
22 'lists.list6="hello world", "how are you?"',
31 'lists.list6="hello world", "how are you?"',
23 'lists.list7=Do"Not"Separate',
32 'lists.list7=Do"Not"Separate',
24 'lists.list8="Do"Separate',
33 'lists.list8="Do"Separate',
25 'lists.list9="Do\\"NotSeparate"',
34 'lists.list9="Do\\"NotSeparate"',
26 'lists.list10=string "with extraneous" quotation mark"',
35 'lists.list10=string "with extraneous" quotation mark"',
27 'lists.list11=x, y',
36 'lists.list11=x, y',
28 'lists.list12="x", "y"',
37 'lists.list12="x", "y"',
29 'lists.list13=""" key = "x", "y" """',
38 'lists.list13=""" key = "x", "y" """',
30 'lists.list14=,,,, ',
39 'lists.list14=,,,, ',
31 'lists.list15=" just with starting quotation',
40 'lists.list15=" just with starting quotation',
32 'lists.list16="longer quotation" with "no ending quotation',
41 'lists.list16="longer quotation" with "no ending quotation',
33 'lists.list17=this is \\" "not a quotation mark"',
42 'lists.list17=this is \\" "not a quotation mark"',
34 'lists.list18=\n \n\nding\ndong',
43 'lists.list18=\n \n\nding\ndong',
35 'date.epoch=0 0',
44 'date.epoch=0 0',
36 'date.birth=2005-04-19T00:00:00',
45 'date.birth=2005-04-19T00:00:00',
37 'date.invalid=0'
46 'date.invalid=0'
38 ])
47 ])
39
48
40 print(repr(testui.configitems('values')))
49 print(repr(testui.configitems('values')))
41 print(repr(testui.configitems('lists')))
50 print(repr(testui.configitems('lists')))
42 print("---")
51 print("---")
43 print(repr(testui.config('values', 'string')))
52 print(repr(testui.config('values', 'string')))
44 print(repr(testui.config('values', 'bool1')))
53 print(repr(testui.config('values', 'bool1')))
45 print(repr(testui.config('values', 'bool2')))
54 print(repr(testui.config('values', 'bool2')))
46 print(repr(testui.config('values', 'unknown')))
55 print(repr(testui.config('values', 'unknown')))
47 print("---")
56 print("---")
48 try:
57 try:
49 print(repr(testui.configbool('values', 'string')))
58 print(repr(testui.configbool('values', 'string')))
50 except error.ConfigError as inst:
59 except error.ConfigError as inst:
51 print(inst)
60 print(inst)
52 print(repr(testui.configbool('values', 'bool1')))
61 print(repr(testui.configbool('values', 'bool1')))
53 print(repr(testui.configbool('values', 'bool2')))
62 print(repr(testui.configbool('values', 'bool2')))
54 print(repr(testui.configbool('values', 'bool2', True)))
63 print(repr(testui.configbool('values', 'bool2', True)))
55 print(repr(testui.configbool('values', 'unknown')))
64 print(repr(testui.configbool('values', 'unknown')))
56 print(repr(testui.configbool('values', 'unknown', True)))
65 print(repr(testui.configbool('values', 'unknown', True)))
57 print("---")
66 print("---")
58 print(repr(testui.configint('values', 'int1')))
67 print(repr(testui.configint('values', 'int1')))
59 print(repr(testui.configint('values', 'int2')))
68 print(repr(testui.configint('values', 'int2')))
60 print("---")
69 print("---")
61 print(repr(testui.configlist('lists', 'list1')))
70 print(repr(testui.configlist('lists', 'list1')))
62 print(repr(testui.configlist('lists', 'list2')))
71 print(repr(testui.configlist('lists', 'list2')))
63 print(repr(testui.configlist('lists', 'list3')))
72 print(repr(testui.configlist('lists', 'list3')))
64 print(repr(testui.configlist('lists', 'list4')))
73 print(repr(testui.configlist('lists', 'list4')))
65 print(repr(testui.configlist('lists', 'list4', ['foo'])))
74 print(repr(testui.configlist('lists', 'list4', ['foo'])))
66 print(repr(testui.configlist('lists', 'list5')))
75 print(repr(testui.configlist('lists', 'list5')))
67 print(repr(testui.configlist('lists', 'list6')))
76 print(repr(testui.configlist('lists', 'list6')))
68 print(repr(testui.configlist('lists', 'list7')))
77 print(repr(testui.configlist('lists', 'list7')))
69 print(repr(testui.configlist('lists', 'list8')))
78 print(repr(testui.configlist('lists', 'list8')))
70 print(repr(testui.configlist('lists', 'list9')))
79 print(repr(testui.configlist('lists', 'list9')))
71 print(repr(testui.configlist('lists', 'list10')))
80 print(repr(testui.configlist('lists', 'list10')))
72 print(repr(testui.configlist('lists', 'list11')))
81 print(repr(testui.configlist('lists', 'list11')))
73 print(repr(testui.configlist('lists', 'list12')))
82 print(repr(testui.configlist('lists', 'list12')))
74 print(repr(testui.configlist('lists', 'list13')))
83 print(repr(testui.configlist('lists', 'list13')))
75 print(repr(testui.configlist('lists', 'list14')))
84 print(repr(testui.configlist('lists', 'list14')))
76 print(repr(testui.configlist('lists', 'list15')))
85 print(repr(testui.configlist('lists', 'list15')))
77 print(repr(testui.configlist('lists', 'list16')))
86 print(repr(testui.configlist('lists', 'list16')))
78 print(repr(testui.configlist('lists', 'list17')))
87 print(repr(testui.configlist('lists', 'list17')))
79 print(repr(testui.configlist('lists', 'list18')))
88 print(repr(testui.configlist('lists', 'list18')))
80 print(repr(testui.configlist('lists', 'unknown')))
89 print(repr(testui.configlist('lists', 'unknown')))
81 print(repr(testui.configlist('lists', 'unknown', '')))
90 print(repr(testui.configlist('lists', 'unknown', '')))
82 print(repr(testui.configlist('lists', 'unknown', 'foo')))
91 print(repr(testui.configlist('lists', 'unknown', 'foo')))
83 print(repr(testui.configlist('lists', 'unknown', ['foo'])))
92 print(repr(testui.configlist('lists', 'unknown', ['foo'])))
84 print(repr(testui.configlist('lists', 'unknown', 'foo bar')))
93 print(repr(testui.configlist('lists', 'unknown', 'foo bar')))
85 print(repr(testui.configlist('lists', 'unknown', 'foo, bar')))
94 print(repr(testui.configlist('lists', 'unknown', 'foo, bar')))
86 print(repr(testui.configlist('lists', 'unknown', ['foo bar'])))
95 print(repr(testui.configlist('lists', 'unknown', ['foo bar'])))
87 print(repr(testui.configlist('lists', 'unknown', ['foo', 'bar'])))
96 print(repr(testui.configlist('lists', 'unknown', ['foo', 'bar'])))
88 print("---")
97 print("---")
89 print(repr(testui.configdate('date', 'epoch')))
98 print(repr(testui.configdate('date', 'epoch')))
90 print(repr(testui.configdate('date', 'birth')))
99 print(repr(testui.configdate('date', 'birth')))
91
100
92 print(repr(testui.config('values', 'String')))
101 print(repr(testui.config('values', 'String')))
93
102
94 def function():
103 def function():
95 pass
104 pass
96
105
97 # values that aren't strings should work
106 # values that aren't strings should work
98 testui.setconfig('hook', 'commit', function)
107 testui.setconfig('hook', 'commit', function)
99 print(function == testui.config('hook', 'commit'))
108 print(function == testui.config('hook', 'commit'))
100
109
101 # invalid values
110 # invalid values
102 try:
111 try:
103 testui.configbool('values', 'boolinvalid')
112 testui.configbool('values', 'boolinvalid')
104 except error.ConfigError:
113 except error.ConfigError:
105 print('boolinvalid')
114 print('boolinvalid')
106 try:
115 try:
107 testui.configint('values', 'intinvalid')
116 testui.configint('values', 'intinvalid')
108 except error.ConfigError:
117 except error.ConfigError:
109 print('intinvalid')
118 print('intinvalid')
110 try:
119 try:
111 testui.configdate('date', 'invalid')
120 testui.configdate('date', 'invalid')
112 except error.ConfigError:
121 except error.ConfigError:
113 print('dateinvalid')
122 print('dateinvalid')
General Comments 0
You need to be logged in to leave comments. Login now