##// END OF EJS Templates
ui: add option to timestamp status and diagnostic messages...
Joerg Sonnenberger -
r45564:24b1a8eb default
parent child Browse files
Show More
@@ -1,1572 +1,1575 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18
18
19 def loadconfigtable(ui, extname, configtable):
19 def loadconfigtable(ui, extname, configtable):
20 """update config item known to the ui with the extension ones"""
20 """update config item known to the ui with the extension ones"""
21 for section, items in sorted(configtable.items()):
21 for section, items in sorted(configtable.items()):
22 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownitems = ui._knownconfig.setdefault(section, itemregister())
23 knownkeys = set(knownitems)
23 knownkeys = set(knownitems)
24 newkeys = set(items)
24 newkeys = set(items)
25 for key in sorted(knownkeys & newkeys):
25 for key in sorted(knownkeys & newkeys):
26 msg = b"extension '%s' overwrite config item '%s.%s'"
26 msg = b"extension '%s' overwrite config item '%s.%s'"
27 msg %= (extname, section, key)
27 msg %= (extname, section, key)
28 ui.develwarn(msg, config=b'warn-config')
28 ui.develwarn(msg, config=b'warn-config')
29
29
30 knownitems.update(items)
30 knownitems.update(items)
31
31
32
32
33 class configitem(object):
33 class configitem(object):
34 """represent a known config item
34 """represent a known config item
35
35
36 :section: the official config section where to find this item,
36 :section: the official config section where to find this item,
37 :name: the official name within the section,
37 :name: the official name within the section,
38 :default: default value for this item,
38 :default: default value for this item,
39 :alias: optional list of tuples as alternatives,
39 :alias: optional list of tuples as alternatives,
40 :generic: this is a generic definition, match name using regular expression.
40 :generic: this is a generic definition, match name using regular expression.
41 """
41 """
42
42
43 def __init__(
43 def __init__(
44 self,
44 self,
45 section,
45 section,
46 name,
46 name,
47 default=None,
47 default=None,
48 alias=(),
48 alias=(),
49 generic=False,
49 generic=False,
50 priority=0,
50 priority=0,
51 experimental=False,
51 experimental=False,
52 ):
52 ):
53 self.section = section
53 self.section = section
54 self.name = name
54 self.name = name
55 self.default = default
55 self.default = default
56 self.alias = list(alias)
56 self.alias = list(alias)
57 self.generic = generic
57 self.generic = generic
58 self.priority = priority
58 self.priority = priority
59 self.experimental = experimental
59 self.experimental = experimental
60 self._re = None
60 self._re = None
61 if generic:
61 if generic:
62 self._re = re.compile(self.name)
62 self._re = re.compile(self.name)
63
63
64
64
65 class itemregister(dict):
65 class itemregister(dict):
66 """A specialized dictionary that can handle wild-card selection"""
66 """A specialized dictionary that can handle wild-card selection"""
67
67
68 def __init__(self):
68 def __init__(self):
69 super(itemregister, self).__init__()
69 super(itemregister, self).__init__()
70 self._generics = set()
70 self._generics = set()
71
71
72 def update(self, other):
72 def update(self, other):
73 super(itemregister, self).update(other)
73 super(itemregister, self).update(other)
74 self._generics.update(other._generics)
74 self._generics.update(other._generics)
75
75
76 def __setitem__(self, key, item):
76 def __setitem__(self, key, item):
77 super(itemregister, self).__setitem__(key, item)
77 super(itemregister, self).__setitem__(key, item)
78 if item.generic:
78 if item.generic:
79 self._generics.add(item)
79 self._generics.add(item)
80
80
81 def get(self, key):
81 def get(self, key):
82 baseitem = super(itemregister, self).get(key)
82 baseitem = super(itemregister, self).get(key)
83 if baseitem is not None and not baseitem.generic:
83 if baseitem is not None and not baseitem.generic:
84 return baseitem
84 return baseitem
85
85
86 # search for a matching generic item
86 # search for a matching generic item
87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
88 for item in generics:
88 for item in generics:
89 # we use 'match' instead of 'search' to make the matching simpler
89 # we use 'match' instead of 'search' to make the matching simpler
90 # for people unfamiliar with regular expression. Having the match
90 # for people unfamiliar with regular expression. Having the match
91 # rooted to the start of the string will produce less surprising
91 # rooted to the start of the string will produce less surprising
92 # result for user writing simple regex for sub-attribute.
92 # result for user writing simple regex for sub-attribute.
93 #
93 #
94 # For example using "color\..*" match produces an unsurprising
94 # For example using "color\..*" match produces an unsurprising
95 # result, while using search could suddenly match apparently
95 # result, while using search could suddenly match apparently
96 # unrelated configuration that happens to contains "color."
96 # unrelated configuration that happens to contains "color."
97 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 # anywhere. This is a tradeoff where we favor requiring ".*" on
98 # some match to avoid the need to prefix most pattern with "^".
98 # some match to avoid the need to prefix most pattern with "^".
99 # The "^" seems more error prone.
99 # The "^" seems more error prone.
100 if item._re.match(key):
100 if item._re.match(key):
101 return item
101 return item
102
102
103 return None
103 return None
104
104
105
105
106 coreitems = {}
106 coreitems = {}
107
107
108
108
109 def _register(configtable, *args, **kwargs):
109 def _register(configtable, *args, **kwargs):
110 item = configitem(*args, **kwargs)
110 item = configitem(*args, **kwargs)
111 section = configtable.setdefault(item.section, itemregister())
111 section = configtable.setdefault(item.section, itemregister())
112 if item.name in section:
112 if item.name in section:
113 msg = b"duplicated config item registration for '%s.%s'"
113 msg = b"duplicated config item registration for '%s.%s'"
114 raise error.ProgrammingError(msg % (item.section, item.name))
114 raise error.ProgrammingError(msg % (item.section, item.name))
115 section[item.name] = item
115 section[item.name] = item
116
116
117
117
118 # special value for case where the default is derived from other values
118 # special value for case where the default is derived from other values
119 dynamicdefault = object()
119 dynamicdefault = object()
120
120
121 # Registering actual config items
121 # Registering actual config items
122
122
123
123
124 def getitemregister(configtable):
124 def getitemregister(configtable):
125 f = functools.partial(_register, configtable)
125 f = functools.partial(_register, configtable)
126 # export pseudo enum as configitem.*
126 # export pseudo enum as configitem.*
127 f.dynamicdefault = dynamicdefault
127 f.dynamicdefault = dynamicdefault
128 return f
128 return f
129
129
130
130
131 coreconfigitem = getitemregister(coreitems)
131 coreconfigitem = getitemregister(coreitems)
132
132
133
133
134 def _registerdiffopts(section, configprefix=b''):
134 def _registerdiffopts(section, configprefix=b''):
135 coreconfigitem(
135 coreconfigitem(
136 section, configprefix + b'nodates', default=False,
136 section, configprefix + b'nodates', default=False,
137 )
137 )
138 coreconfigitem(
138 coreconfigitem(
139 section, configprefix + b'showfunc', default=False,
139 section, configprefix + b'showfunc', default=False,
140 )
140 )
141 coreconfigitem(
141 coreconfigitem(
142 section, configprefix + b'unified', default=None,
142 section, configprefix + b'unified', default=None,
143 )
143 )
144 coreconfigitem(
144 coreconfigitem(
145 section, configprefix + b'git', default=False,
145 section, configprefix + b'git', default=False,
146 )
146 )
147 coreconfigitem(
147 coreconfigitem(
148 section, configprefix + b'ignorews', default=False,
148 section, configprefix + b'ignorews', default=False,
149 )
149 )
150 coreconfigitem(
150 coreconfigitem(
151 section, configprefix + b'ignorewsamount', default=False,
151 section, configprefix + b'ignorewsamount', default=False,
152 )
152 )
153 coreconfigitem(
153 coreconfigitem(
154 section, configprefix + b'ignoreblanklines', default=False,
154 section, configprefix + b'ignoreblanklines', default=False,
155 )
155 )
156 coreconfigitem(
156 coreconfigitem(
157 section, configprefix + b'ignorewseol', default=False,
157 section, configprefix + b'ignorewseol', default=False,
158 )
158 )
159 coreconfigitem(
159 coreconfigitem(
160 section, configprefix + b'nobinary', default=False,
160 section, configprefix + b'nobinary', default=False,
161 )
161 )
162 coreconfigitem(
162 coreconfigitem(
163 section, configprefix + b'noprefix', default=False,
163 section, configprefix + b'noprefix', default=False,
164 )
164 )
165 coreconfigitem(
165 coreconfigitem(
166 section, configprefix + b'word-diff', default=False,
166 section, configprefix + b'word-diff', default=False,
167 )
167 )
168
168
169
169
170 coreconfigitem(
170 coreconfigitem(
171 b'alias', b'.*', default=dynamicdefault, generic=True,
171 b'alias', b'.*', default=dynamicdefault, generic=True,
172 )
172 )
173 coreconfigitem(
173 coreconfigitem(
174 b'auth', b'cookiefile', default=None,
174 b'auth', b'cookiefile', default=None,
175 )
175 )
176 _registerdiffopts(section=b'annotate')
176 _registerdiffopts(section=b'annotate')
177 # bookmarks.pushing: internal hack for discovery
177 # bookmarks.pushing: internal hack for discovery
178 coreconfigitem(
178 coreconfigitem(
179 b'bookmarks', b'pushing', default=list,
179 b'bookmarks', b'pushing', default=list,
180 )
180 )
181 # bundle.mainreporoot: internal hack for bundlerepo
181 # bundle.mainreporoot: internal hack for bundlerepo
182 coreconfigitem(
182 coreconfigitem(
183 b'bundle', b'mainreporoot', default=b'',
183 b'bundle', b'mainreporoot', default=b'',
184 )
184 )
185 coreconfigitem(
185 coreconfigitem(
186 b'censor', b'policy', default=b'abort', experimental=True,
186 b'censor', b'policy', default=b'abort', experimental=True,
187 )
187 )
188 coreconfigitem(
188 coreconfigitem(
189 b'chgserver', b'idletimeout', default=3600,
189 b'chgserver', b'idletimeout', default=3600,
190 )
190 )
191 coreconfigitem(
191 coreconfigitem(
192 b'chgserver', b'skiphash', default=False,
192 b'chgserver', b'skiphash', default=False,
193 )
193 )
194 coreconfigitem(
194 coreconfigitem(
195 b'cmdserver', b'log', default=None,
195 b'cmdserver', b'log', default=None,
196 )
196 )
197 coreconfigitem(
197 coreconfigitem(
198 b'cmdserver', b'max-log-files', default=7,
198 b'cmdserver', b'max-log-files', default=7,
199 )
199 )
200 coreconfigitem(
200 coreconfigitem(
201 b'cmdserver', b'max-log-size', default=b'1 MB',
201 b'cmdserver', b'max-log-size', default=b'1 MB',
202 )
202 )
203 coreconfigitem(
203 coreconfigitem(
204 b'cmdserver', b'max-repo-cache', default=0, experimental=True,
204 b'cmdserver', b'max-repo-cache', default=0, experimental=True,
205 )
205 )
206 coreconfigitem(
206 coreconfigitem(
207 b'cmdserver', b'message-encodings', default=list, experimental=True,
207 b'cmdserver', b'message-encodings', default=list, experimental=True,
208 )
208 )
209 coreconfigitem(
209 coreconfigitem(
210 b'cmdserver',
210 b'cmdserver',
211 b'track-log',
211 b'track-log',
212 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
212 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
213 )
213 )
214 coreconfigitem(
214 coreconfigitem(
215 b'color', b'.*', default=None, generic=True,
215 b'color', b'.*', default=None, generic=True,
216 )
216 )
217 coreconfigitem(
217 coreconfigitem(
218 b'color', b'mode', default=b'auto',
218 b'color', b'mode', default=b'auto',
219 )
219 )
220 coreconfigitem(
220 coreconfigitem(
221 b'color', b'pagermode', default=dynamicdefault,
221 b'color', b'pagermode', default=dynamicdefault,
222 )
222 )
223 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
223 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
224 coreconfigitem(
224 coreconfigitem(
225 b'commands', b'commit.post-status', default=False,
225 b'commands', b'commit.post-status', default=False,
226 )
226 )
227 coreconfigitem(
227 coreconfigitem(
228 b'commands', b'grep.all-files', default=False, experimental=True,
228 b'commands', b'grep.all-files', default=False, experimental=True,
229 )
229 )
230 coreconfigitem(
230 coreconfigitem(
231 b'commands', b'merge.require-rev', default=False,
231 b'commands', b'merge.require-rev', default=False,
232 )
232 )
233 coreconfigitem(
233 coreconfigitem(
234 b'commands', b'push.require-revs', default=False,
234 b'commands', b'push.require-revs', default=False,
235 )
235 )
236 coreconfigitem(
236 coreconfigitem(
237 b'commands', b'resolve.confirm', default=False,
237 b'commands', b'resolve.confirm', default=False,
238 )
238 )
239 coreconfigitem(
239 coreconfigitem(
240 b'commands', b'resolve.explicit-re-merge', default=False,
240 b'commands', b'resolve.explicit-re-merge', default=False,
241 )
241 )
242 coreconfigitem(
242 coreconfigitem(
243 b'commands', b'resolve.mark-check', default=b'none',
243 b'commands', b'resolve.mark-check', default=b'none',
244 )
244 )
245 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
245 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
246 coreconfigitem(
246 coreconfigitem(
247 b'commands', b'show.aliasprefix', default=list,
247 b'commands', b'show.aliasprefix', default=list,
248 )
248 )
249 coreconfigitem(
249 coreconfigitem(
250 b'commands', b'status.relative', default=False,
250 b'commands', b'status.relative', default=False,
251 )
251 )
252 coreconfigitem(
252 coreconfigitem(
253 b'commands', b'status.skipstates', default=[], experimental=True,
253 b'commands', b'status.skipstates', default=[], experimental=True,
254 )
254 )
255 coreconfigitem(
255 coreconfigitem(
256 b'commands', b'status.terse', default=b'',
256 b'commands', b'status.terse', default=b'',
257 )
257 )
258 coreconfigitem(
258 coreconfigitem(
259 b'commands', b'status.verbose', default=False,
259 b'commands', b'status.verbose', default=False,
260 )
260 )
261 coreconfigitem(
261 coreconfigitem(
262 b'commands', b'update.check', default=None,
262 b'commands', b'update.check', default=None,
263 )
263 )
264 coreconfigitem(
264 coreconfigitem(
265 b'commands', b'update.requiredest', default=False,
265 b'commands', b'update.requiredest', default=False,
266 )
266 )
267 coreconfigitem(
267 coreconfigitem(
268 b'committemplate', b'.*', default=None, generic=True,
268 b'committemplate', b'.*', default=None, generic=True,
269 )
269 )
270 coreconfigitem(
270 coreconfigitem(
271 b'convert', b'bzr.saverev', default=True,
271 b'convert', b'bzr.saverev', default=True,
272 )
272 )
273 coreconfigitem(
273 coreconfigitem(
274 b'convert', b'cvsps.cache', default=True,
274 b'convert', b'cvsps.cache', default=True,
275 )
275 )
276 coreconfigitem(
276 coreconfigitem(
277 b'convert', b'cvsps.fuzz', default=60,
277 b'convert', b'cvsps.fuzz', default=60,
278 )
278 )
279 coreconfigitem(
279 coreconfigitem(
280 b'convert', b'cvsps.logencoding', default=None,
280 b'convert', b'cvsps.logencoding', default=None,
281 )
281 )
282 coreconfigitem(
282 coreconfigitem(
283 b'convert', b'cvsps.mergefrom', default=None,
283 b'convert', b'cvsps.mergefrom', default=None,
284 )
284 )
285 coreconfigitem(
285 coreconfigitem(
286 b'convert', b'cvsps.mergeto', default=None,
286 b'convert', b'cvsps.mergeto', default=None,
287 )
287 )
288 coreconfigitem(
288 coreconfigitem(
289 b'convert', b'git.committeractions', default=lambda: [b'messagedifferent'],
289 b'convert', b'git.committeractions', default=lambda: [b'messagedifferent'],
290 )
290 )
291 coreconfigitem(
291 coreconfigitem(
292 b'convert', b'git.extrakeys', default=list,
292 b'convert', b'git.extrakeys', default=list,
293 )
293 )
294 coreconfigitem(
294 coreconfigitem(
295 b'convert', b'git.findcopiesharder', default=False,
295 b'convert', b'git.findcopiesharder', default=False,
296 )
296 )
297 coreconfigitem(
297 coreconfigitem(
298 b'convert', b'git.remoteprefix', default=b'remote',
298 b'convert', b'git.remoteprefix', default=b'remote',
299 )
299 )
300 coreconfigitem(
300 coreconfigitem(
301 b'convert', b'git.renamelimit', default=400,
301 b'convert', b'git.renamelimit', default=400,
302 )
302 )
303 coreconfigitem(
303 coreconfigitem(
304 b'convert', b'git.saverev', default=True,
304 b'convert', b'git.saverev', default=True,
305 )
305 )
306 coreconfigitem(
306 coreconfigitem(
307 b'convert', b'git.similarity', default=50,
307 b'convert', b'git.similarity', default=50,
308 )
308 )
309 coreconfigitem(
309 coreconfigitem(
310 b'convert', b'git.skipsubmodules', default=False,
310 b'convert', b'git.skipsubmodules', default=False,
311 )
311 )
312 coreconfigitem(
312 coreconfigitem(
313 b'convert', b'hg.clonebranches', default=False,
313 b'convert', b'hg.clonebranches', default=False,
314 )
314 )
315 coreconfigitem(
315 coreconfigitem(
316 b'convert', b'hg.ignoreerrors', default=False,
316 b'convert', b'hg.ignoreerrors', default=False,
317 )
317 )
318 coreconfigitem(
318 coreconfigitem(
319 b'convert', b'hg.preserve-hash', default=False,
319 b'convert', b'hg.preserve-hash', default=False,
320 )
320 )
321 coreconfigitem(
321 coreconfigitem(
322 b'convert', b'hg.revs', default=None,
322 b'convert', b'hg.revs', default=None,
323 )
323 )
324 coreconfigitem(
324 coreconfigitem(
325 b'convert', b'hg.saverev', default=False,
325 b'convert', b'hg.saverev', default=False,
326 )
326 )
327 coreconfigitem(
327 coreconfigitem(
328 b'convert', b'hg.sourcename', default=None,
328 b'convert', b'hg.sourcename', default=None,
329 )
329 )
330 coreconfigitem(
330 coreconfigitem(
331 b'convert', b'hg.startrev', default=None,
331 b'convert', b'hg.startrev', default=None,
332 )
332 )
333 coreconfigitem(
333 coreconfigitem(
334 b'convert', b'hg.tagsbranch', default=b'default',
334 b'convert', b'hg.tagsbranch', default=b'default',
335 )
335 )
336 coreconfigitem(
336 coreconfigitem(
337 b'convert', b'hg.usebranchnames', default=True,
337 b'convert', b'hg.usebranchnames', default=True,
338 )
338 )
339 coreconfigitem(
339 coreconfigitem(
340 b'convert', b'ignoreancestorcheck', default=False, experimental=True,
340 b'convert', b'ignoreancestorcheck', default=False, experimental=True,
341 )
341 )
342 coreconfigitem(
342 coreconfigitem(
343 b'convert', b'localtimezone', default=False,
343 b'convert', b'localtimezone', default=False,
344 )
344 )
345 coreconfigitem(
345 coreconfigitem(
346 b'convert', b'p4.encoding', default=dynamicdefault,
346 b'convert', b'p4.encoding', default=dynamicdefault,
347 )
347 )
348 coreconfigitem(
348 coreconfigitem(
349 b'convert', b'p4.startrev', default=0,
349 b'convert', b'p4.startrev', default=0,
350 )
350 )
351 coreconfigitem(
351 coreconfigitem(
352 b'convert', b'skiptags', default=False,
352 b'convert', b'skiptags', default=False,
353 )
353 )
354 coreconfigitem(
354 coreconfigitem(
355 b'convert', b'svn.debugsvnlog', default=True,
355 b'convert', b'svn.debugsvnlog', default=True,
356 )
356 )
357 coreconfigitem(
357 coreconfigitem(
358 b'convert', b'svn.trunk', default=None,
358 b'convert', b'svn.trunk', default=None,
359 )
359 )
360 coreconfigitem(
360 coreconfigitem(
361 b'convert', b'svn.tags', default=None,
361 b'convert', b'svn.tags', default=None,
362 )
362 )
363 coreconfigitem(
363 coreconfigitem(
364 b'convert', b'svn.branches', default=None,
364 b'convert', b'svn.branches', default=None,
365 )
365 )
366 coreconfigitem(
366 coreconfigitem(
367 b'convert', b'svn.startrev', default=0,
367 b'convert', b'svn.startrev', default=0,
368 )
368 )
369 coreconfigitem(
369 coreconfigitem(
370 b'debug', b'dirstate.delaywrite', default=0,
370 b'debug', b'dirstate.delaywrite', default=0,
371 )
371 )
372 coreconfigitem(
372 coreconfigitem(
373 b'defaults', b'.*', default=None, generic=True,
373 b'defaults', b'.*', default=None, generic=True,
374 )
374 )
375 coreconfigitem(
375 coreconfigitem(
376 b'devel', b'all-warnings', default=False,
376 b'devel', b'all-warnings', default=False,
377 )
377 )
378 coreconfigitem(
378 coreconfigitem(
379 b'devel', b'bundle2.debug', default=False,
379 b'devel', b'bundle2.debug', default=False,
380 )
380 )
381 coreconfigitem(
381 coreconfigitem(
382 b'devel', b'bundle.delta', default=b'',
382 b'devel', b'bundle.delta', default=b'',
383 )
383 )
384 coreconfigitem(
384 coreconfigitem(
385 b'devel', b'cache-vfs', default=None,
385 b'devel', b'cache-vfs', default=None,
386 )
386 )
387 coreconfigitem(
387 coreconfigitem(
388 b'devel', b'check-locks', default=False,
388 b'devel', b'check-locks', default=False,
389 )
389 )
390 coreconfigitem(
390 coreconfigitem(
391 b'devel', b'check-relroot', default=False,
391 b'devel', b'check-relroot', default=False,
392 )
392 )
393 coreconfigitem(
393 coreconfigitem(
394 b'devel', b'default-date', default=None,
394 b'devel', b'default-date', default=None,
395 )
395 )
396 coreconfigitem(
396 coreconfigitem(
397 b'devel', b'deprec-warn', default=False,
397 b'devel', b'deprec-warn', default=False,
398 )
398 )
399 coreconfigitem(
399 coreconfigitem(
400 b'devel', b'disableloaddefaultcerts', default=False,
400 b'devel', b'disableloaddefaultcerts', default=False,
401 )
401 )
402 coreconfigitem(
402 coreconfigitem(
403 b'devel', b'warn-empty-changegroup', default=False,
403 b'devel', b'warn-empty-changegroup', default=False,
404 )
404 )
405 coreconfigitem(
405 coreconfigitem(
406 b'devel', b'legacy.exchange', default=list,
406 b'devel', b'legacy.exchange', default=list,
407 )
407 )
408 coreconfigitem(
408 coreconfigitem(
409 b'devel', b'persistent-nodemap', default=False,
409 b'devel', b'persistent-nodemap', default=False,
410 )
410 )
411 coreconfigitem(
411 coreconfigitem(
412 b'devel', b'servercafile', default=b'',
412 b'devel', b'servercafile', default=b'',
413 )
413 )
414 coreconfigitem(
414 coreconfigitem(
415 b'devel', b'serverexactprotocol', default=b'',
415 b'devel', b'serverexactprotocol', default=b'',
416 )
416 )
417 coreconfigitem(
417 coreconfigitem(
418 b'devel', b'serverrequirecert', default=False,
418 b'devel', b'serverrequirecert', default=False,
419 )
419 )
420 coreconfigitem(
420 coreconfigitem(
421 b'devel', b'strip-obsmarkers', default=True,
421 b'devel', b'strip-obsmarkers', default=True,
422 )
422 )
423 coreconfigitem(
423 coreconfigitem(
424 b'devel', b'warn-config', default=None,
424 b'devel', b'warn-config', default=None,
425 )
425 )
426 coreconfigitem(
426 coreconfigitem(
427 b'devel', b'warn-config-default', default=None,
427 b'devel', b'warn-config-default', default=None,
428 )
428 )
429 coreconfigitem(
429 coreconfigitem(
430 b'devel', b'user.obsmarker', default=None,
430 b'devel', b'user.obsmarker', default=None,
431 )
431 )
432 coreconfigitem(
432 coreconfigitem(
433 b'devel', b'warn-config-unknown', default=None,
433 b'devel', b'warn-config-unknown', default=None,
434 )
434 )
435 coreconfigitem(
435 coreconfigitem(
436 b'devel', b'debug.copies', default=False,
436 b'devel', b'debug.copies', default=False,
437 )
437 )
438 coreconfigitem(
438 coreconfigitem(
439 b'devel', b'debug.extensions', default=False,
439 b'devel', b'debug.extensions', default=False,
440 )
440 )
441 coreconfigitem(
441 coreconfigitem(
442 b'devel', b'debug.repo-filters', default=False,
442 b'devel', b'debug.repo-filters', default=False,
443 )
443 )
444 coreconfigitem(
444 coreconfigitem(
445 b'devel', b'debug.peer-request', default=False,
445 b'devel', b'debug.peer-request', default=False,
446 )
446 )
447 coreconfigitem(
447 coreconfigitem(
448 b'devel', b'discovery.randomize', default=True,
448 b'devel', b'discovery.randomize', default=True,
449 )
449 )
450 _registerdiffopts(section=b'diff')
450 _registerdiffopts(section=b'diff')
451 coreconfigitem(
451 coreconfigitem(
452 b'email', b'bcc', default=None,
452 b'email', b'bcc', default=None,
453 )
453 )
454 coreconfigitem(
454 coreconfigitem(
455 b'email', b'cc', default=None,
455 b'email', b'cc', default=None,
456 )
456 )
457 coreconfigitem(
457 coreconfigitem(
458 b'email', b'charsets', default=list,
458 b'email', b'charsets', default=list,
459 )
459 )
460 coreconfigitem(
460 coreconfigitem(
461 b'email', b'from', default=None,
461 b'email', b'from', default=None,
462 )
462 )
463 coreconfigitem(
463 coreconfigitem(
464 b'email', b'method', default=b'smtp',
464 b'email', b'method', default=b'smtp',
465 )
465 )
466 coreconfigitem(
466 coreconfigitem(
467 b'email', b'reply-to', default=None,
467 b'email', b'reply-to', default=None,
468 )
468 )
469 coreconfigitem(
469 coreconfigitem(
470 b'email', b'to', default=None,
470 b'email', b'to', default=None,
471 )
471 )
472 coreconfigitem(
472 coreconfigitem(
473 b'experimental', b'archivemetatemplate', default=dynamicdefault,
473 b'experimental', b'archivemetatemplate', default=dynamicdefault,
474 )
474 )
475 coreconfigitem(
475 coreconfigitem(
476 b'experimental', b'auto-publish', default=b'publish',
476 b'experimental', b'auto-publish', default=b'publish',
477 )
477 )
478 coreconfigitem(
478 coreconfigitem(
479 b'experimental', b'bundle-phases', default=False,
479 b'experimental', b'bundle-phases', default=False,
480 )
480 )
481 coreconfigitem(
481 coreconfigitem(
482 b'experimental', b'bundle2-advertise', default=True,
482 b'experimental', b'bundle2-advertise', default=True,
483 )
483 )
484 coreconfigitem(
484 coreconfigitem(
485 b'experimental', b'bundle2-output-capture', default=False,
485 b'experimental', b'bundle2-output-capture', default=False,
486 )
486 )
487 coreconfigitem(
487 coreconfigitem(
488 b'experimental', b'bundle2.pushback', default=False,
488 b'experimental', b'bundle2.pushback', default=False,
489 )
489 )
490 coreconfigitem(
490 coreconfigitem(
491 b'experimental', b'bundle2lazylocking', default=False,
491 b'experimental', b'bundle2lazylocking', default=False,
492 )
492 )
493 coreconfigitem(
493 coreconfigitem(
494 b'experimental', b'bundlecomplevel', default=None,
494 b'experimental', b'bundlecomplevel', default=None,
495 )
495 )
496 coreconfigitem(
496 coreconfigitem(
497 b'experimental', b'bundlecomplevel.bzip2', default=None,
497 b'experimental', b'bundlecomplevel.bzip2', default=None,
498 )
498 )
499 coreconfigitem(
499 coreconfigitem(
500 b'experimental', b'bundlecomplevel.gzip', default=None,
500 b'experimental', b'bundlecomplevel.gzip', default=None,
501 )
501 )
502 coreconfigitem(
502 coreconfigitem(
503 b'experimental', b'bundlecomplevel.none', default=None,
503 b'experimental', b'bundlecomplevel.none', default=None,
504 )
504 )
505 coreconfigitem(
505 coreconfigitem(
506 b'experimental', b'bundlecomplevel.zstd', default=None,
506 b'experimental', b'bundlecomplevel.zstd', default=None,
507 )
507 )
508 coreconfigitem(
508 coreconfigitem(
509 b'experimental', b'changegroup3', default=False,
509 b'experimental', b'changegroup3', default=False,
510 )
510 )
511 coreconfigitem(
511 coreconfigitem(
512 b'experimental', b'cleanup-as-archived', default=False,
512 b'experimental', b'cleanup-as-archived', default=False,
513 )
513 )
514 coreconfigitem(
514 coreconfigitem(
515 b'experimental', b'clientcompressionengines', default=list,
515 b'experimental', b'clientcompressionengines', default=list,
516 )
516 )
517 coreconfigitem(
517 coreconfigitem(
518 b'experimental', b'copytrace', default=b'on',
518 b'experimental', b'copytrace', default=b'on',
519 )
519 )
520 coreconfigitem(
520 coreconfigitem(
521 b'experimental', b'copytrace.movecandidateslimit', default=100,
521 b'experimental', b'copytrace.movecandidateslimit', default=100,
522 )
522 )
523 coreconfigitem(
523 coreconfigitem(
524 b'experimental', b'copytrace.sourcecommitlimit', default=100,
524 b'experimental', b'copytrace.sourcecommitlimit', default=100,
525 )
525 )
526 coreconfigitem(
526 coreconfigitem(
527 b'experimental', b'copies.read-from', default=b"filelog-only",
527 b'experimental', b'copies.read-from', default=b"filelog-only",
528 )
528 )
529 coreconfigitem(
529 coreconfigitem(
530 b'experimental', b'copies.write-to', default=b'filelog-only',
530 b'experimental', b'copies.write-to', default=b'filelog-only',
531 )
531 )
532 coreconfigitem(
532 coreconfigitem(
533 b'experimental', b'crecordtest', default=None,
533 b'experimental', b'crecordtest', default=None,
534 )
534 )
535 coreconfigitem(
535 coreconfigitem(
536 b'experimental', b'directaccess', default=False,
536 b'experimental', b'directaccess', default=False,
537 )
537 )
538 coreconfigitem(
538 coreconfigitem(
539 b'experimental', b'directaccess.revnums', default=False,
539 b'experimental', b'directaccess.revnums', default=False,
540 )
540 )
541 coreconfigitem(
541 coreconfigitem(
542 b'experimental', b'editortmpinhg', default=False,
542 b'experimental', b'editortmpinhg', default=False,
543 )
543 )
544 coreconfigitem(
544 coreconfigitem(
545 b'experimental', b'evolution', default=list,
545 b'experimental', b'evolution', default=list,
546 )
546 )
547 coreconfigitem(
547 coreconfigitem(
548 b'experimental',
548 b'experimental',
549 b'evolution.allowdivergence',
549 b'evolution.allowdivergence',
550 default=False,
550 default=False,
551 alias=[(b'experimental', b'allowdivergence')],
551 alias=[(b'experimental', b'allowdivergence')],
552 )
552 )
553 coreconfigitem(
553 coreconfigitem(
554 b'experimental', b'evolution.allowunstable', default=None,
554 b'experimental', b'evolution.allowunstable', default=None,
555 )
555 )
556 coreconfigitem(
556 coreconfigitem(
557 b'experimental', b'evolution.createmarkers', default=None,
557 b'experimental', b'evolution.createmarkers', default=None,
558 )
558 )
559 coreconfigitem(
559 coreconfigitem(
560 b'experimental',
560 b'experimental',
561 b'evolution.effect-flags',
561 b'evolution.effect-flags',
562 default=True,
562 default=True,
563 alias=[(b'experimental', b'effect-flags')],
563 alias=[(b'experimental', b'effect-flags')],
564 )
564 )
565 coreconfigitem(
565 coreconfigitem(
566 b'experimental', b'evolution.exchange', default=None,
566 b'experimental', b'evolution.exchange', default=None,
567 )
567 )
568 coreconfigitem(
568 coreconfigitem(
569 b'experimental', b'evolution.bundle-obsmarker', default=False,
569 b'experimental', b'evolution.bundle-obsmarker', default=False,
570 )
570 )
571 coreconfigitem(
571 coreconfigitem(
572 b'experimental', b'log.topo', default=False,
572 b'experimental', b'log.topo', default=False,
573 )
573 )
574 coreconfigitem(
574 coreconfigitem(
575 b'experimental', b'evolution.report-instabilities', default=True,
575 b'experimental', b'evolution.report-instabilities', default=True,
576 )
576 )
577 coreconfigitem(
577 coreconfigitem(
578 b'experimental', b'evolution.track-operation', default=True,
578 b'experimental', b'evolution.track-operation', default=True,
579 )
579 )
580 # repo-level config to exclude a revset visibility
580 # repo-level config to exclude a revset visibility
581 #
581 #
582 # The target use case is to use `share` to expose different subset of the same
582 # The target use case is to use `share` to expose different subset of the same
583 # repository, especially server side. See also `server.view`.
583 # repository, especially server side. See also `server.view`.
584 coreconfigitem(
584 coreconfigitem(
585 b'experimental', b'extra-filter-revs', default=None,
585 b'experimental', b'extra-filter-revs', default=None,
586 )
586 )
587 coreconfigitem(
587 coreconfigitem(
588 b'experimental', b'maxdeltachainspan', default=-1,
588 b'experimental', b'maxdeltachainspan', default=-1,
589 )
589 )
590 coreconfigitem(
590 coreconfigitem(
591 b'experimental', b'mergetempdirprefix', default=None,
591 b'experimental', b'mergetempdirprefix', default=None,
592 )
592 )
593 coreconfigitem(
593 coreconfigitem(
594 b'experimental', b'mmapindexthreshold', default=None,
594 b'experimental', b'mmapindexthreshold', default=None,
595 )
595 )
596 coreconfigitem(
596 coreconfigitem(
597 b'experimental', b'narrow', default=False,
597 b'experimental', b'narrow', default=False,
598 )
598 )
599 coreconfigitem(
599 coreconfigitem(
600 b'experimental', b'nonnormalparanoidcheck', default=False,
600 b'experimental', b'nonnormalparanoidcheck', default=False,
601 )
601 )
602 coreconfigitem(
602 coreconfigitem(
603 b'experimental', b'exportableenviron', default=list,
603 b'experimental', b'exportableenviron', default=list,
604 )
604 )
605 coreconfigitem(
605 coreconfigitem(
606 b'experimental', b'extendedheader.index', default=None,
606 b'experimental', b'extendedheader.index', default=None,
607 )
607 )
608 coreconfigitem(
608 coreconfigitem(
609 b'experimental', b'extendedheader.similarity', default=False,
609 b'experimental', b'extendedheader.similarity', default=False,
610 )
610 )
611 coreconfigitem(
611 coreconfigitem(
612 b'experimental', b'graphshorten', default=False,
612 b'experimental', b'graphshorten', default=False,
613 )
613 )
614 coreconfigitem(
614 coreconfigitem(
615 b'experimental', b'graphstyle.parent', default=dynamicdefault,
615 b'experimental', b'graphstyle.parent', default=dynamicdefault,
616 )
616 )
617 coreconfigitem(
617 coreconfigitem(
618 b'experimental', b'graphstyle.missing', default=dynamicdefault,
618 b'experimental', b'graphstyle.missing', default=dynamicdefault,
619 )
619 )
620 coreconfigitem(
620 coreconfigitem(
621 b'experimental', b'graphstyle.grandparent', default=dynamicdefault,
621 b'experimental', b'graphstyle.grandparent', default=dynamicdefault,
622 )
622 )
623 coreconfigitem(
623 coreconfigitem(
624 b'experimental', b'hook-track-tags', default=False,
624 b'experimental', b'hook-track-tags', default=False,
625 )
625 )
626 coreconfigitem(
626 coreconfigitem(
627 b'experimental', b'httppeer.advertise-v2', default=False,
627 b'experimental', b'httppeer.advertise-v2', default=False,
628 )
628 )
629 coreconfigitem(
629 coreconfigitem(
630 b'experimental', b'httppeer.v2-encoder-order', default=None,
630 b'experimental', b'httppeer.v2-encoder-order', default=None,
631 )
631 )
632 coreconfigitem(
632 coreconfigitem(
633 b'experimental', b'httppostargs', default=False,
633 b'experimental', b'httppostargs', default=False,
634 )
634 )
635 coreconfigitem(
635 coreconfigitem(
636 b'experimental', b'mergedriver', default=None,
636 b'experimental', b'mergedriver', default=None,
637 )
637 )
638 coreconfigitem(b'experimental', b'nointerrupt', default=False)
638 coreconfigitem(b'experimental', b'nointerrupt', default=False)
639 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
639 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
640
640
641 coreconfigitem(
641 coreconfigitem(
642 b'experimental', b'obsmarkers-exchange-debug', default=False,
642 b'experimental', b'obsmarkers-exchange-debug', default=False,
643 )
643 )
644 coreconfigitem(
644 coreconfigitem(
645 b'experimental', b'remotenames', default=False,
645 b'experimental', b'remotenames', default=False,
646 )
646 )
647 coreconfigitem(
647 coreconfigitem(
648 b'experimental', b'removeemptydirs', default=True,
648 b'experimental', b'removeemptydirs', default=True,
649 )
649 )
650 coreconfigitem(
650 coreconfigitem(
651 b'experimental', b'revert.interactive.select-to-keep', default=False,
651 b'experimental', b'revert.interactive.select-to-keep', default=False,
652 )
652 )
653 coreconfigitem(
653 coreconfigitem(
654 b'experimental', b'revisions.prefixhexnode', default=False,
654 b'experimental', b'revisions.prefixhexnode', default=False,
655 )
655 )
656 coreconfigitem(
656 coreconfigitem(
657 b'experimental', b'revlogv2', default=None,
657 b'experimental', b'revlogv2', default=None,
658 )
658 )
659 coreconfigitem(
659 coreconfigitem(
660 b'experimental', b'revisions.disambiguatewithin', default=None,
660 b'experimental', b'revisions.disambiguatewithin', default=None,
661 )
661 )
662 coreconfigitem(
662 coreconfigitem(
663 b'experimental', b'rust.index', default=False,
663 b'experimental', b'rust.index', default=False,
664 )
664 )
665 coreconfigitem(
665 coreconfigitem(
666 b'experimental', b'server.filesdata.recommended-batch-size', default=50000,
666 b'experimental', b'server.filesdata.recommended-batch-size', default=50000,
667 )
667 )
668 coreconfigitem(
668 coreconfigitem(
669 b'experimental',
669 b'experimental',
670 b'server.manifestdata.recommended-batch-size',
670 b'server.manifestdata.recommended-batch-size',
671 default=100000,
671 default=100000,
672 )
672 )
673 coreconfigitem(
673 coreconfigitem(
674 b'experimental', b'server.stream-narrow-clones', default=False,
674 b'experimental', b'server.stream-narrow-clones', default=False,
675 )
675 )
676 coreconfigitem(
676 coreconfigitem(
677 b'experimental', b'single-head-per-branch', default=False,
677 b'experimental', b'single-head-per-branch', default=False,
678 )
678 )
679 coreconfigitem(
679 coreconfigitem(
680 b'experimental',
680 b'experimental',
681 b'single-head-per-branch:account-closed-heads',
681 b'single-head-per-branch:account-closed-heads',
682 default=False,
682 default=False,
683 )
683 )
684 coreconfigitem(
684 coreconfigitem(
685 b'experimental', b'sshserver.support-v2', default=False,
685 b'experimental', b'sshserver.support-v2', default=False,
686 )
686 )
687 coreconfigitem(
687 coreconfigitem(
688 b'experimental', b'sparse-read', default=False,
688 b'experimental', b'sparse-read', default=False,
689 )
689 )
690 coreconfigitem(
690 coreconfigitem(
691 b'experimental', b'sparse-read.density-threshold', default=0.50,
691 b'experimental', b'sparse-read.density-threshold', default=0.50,
692 )
692 )
693 coreconfigitem(
693 coreconfigitem(
694 b'experimental', b'sparse-read.min-gap-size', default=b'65K',
694 b'experimental', b'sparse-read.min-gap-size', default=b'65K',
695 )
695 )
696 coreconfigitem(
696 coreconfigitem(
697 b'experimental', b'treemanifest', default=False,
697 b'experimental', b'treemanifest', default=False,
698 )
698 )
699 coreconfigitem(
699 coreconfigitem(
700 b'experimental', b'update.atomic-file', default=False,
700 b'experimental', b'update.atomic-file', default=False,
701 )
701 )
702 coreconfigitem(
702 coreconfigitem(
703 b'experimental', b'sshpeer.advertise-v2', default=False,
703 b'experimental', b'sshpeer.advertise-v2', default=False,
704 )
704 )
705 coreconfigitem(
705 coreconfigitem(
706 b'experimental', b'web.apiserver', default=False,
706 b'experimental', b'web.apiserver', default=False,
707 )
707 )
708 coreconfigitem(
708 coreconfigitem(
709 b'experimental', b'web.api.http-v2', default=False,
709 b'experimental', b'web.api.http-v2', default=False,
710 )
710 )
711 coreconfigitem(
711 coreconfigitem(
712 b'experimental', b'web.api.debugreflect', default=False,
712 b'experimental', b'web.api.debugreflect', default=False,
713 )
713 )
714 coreconfigitem(
714 coreconfigitem(
715 b'experimental', b'worker.wdir-get-thread-safe', default=False,
715 b'experimental', b'worker.wdir-get-thread-safe', default=False,
716 )
716 )
717 coreconfigitem(
717 coreconfigitem(
718 b'experimental', b'worker.repository-upgrade', default=False,
718 b'experimental', b'worker.repository-upgrade', default=False,
719 )
719 )
720 coreconfigitem(
720 coreconfigitem(
721 b'experimental', b'xdiff', default=False,
721 b'experimental', b'xdiff', default=False,
722 )
722 )
723 coreconfigitem(
723 coreconfigitem(
724 b'extensions', b'.*', default=None, generic=True,
724 b'extensions', b'.*', default=None, generic=True,
725 )
725 )
726 coreconfigitem(
726 coreconfigitem(
727 b'extdata', b'.*', default=None, generic=True,
727 b'extdata', b'.*', default=None, generic=True,
728 )
728 )
729 coreconfigitem(
729 coreconfigitem(
730 b'format', b'bookmarks-in-store', default=False,
730 b'format', b'bookmarks-in-store', default=False,
731 )
731 )
732 coreconfigitem(
732 coreconfigitem(
733 b'format', b'chunkcachesize', default=None, experimental=True,
733 b'format', b'chunkcachesize', default=None, experimental=True,
734 )
734 )
735 coreconfigitem(
735 coreconfigitem(
736 b'format', b'dotencode', default=True,
736 b'format', b'dotencode', default=True,
737 )
737 )
738 coreconfigitem(
738 coreconfigitem(
739 b'format', b'generaldelta', default=False, experimental=True,
739 b'format', b'generaldelta', default=False, experimental=True,
740 )
740 )
741 coreconfigitem(
741 coreconfigitem(
742 b'format', b'manifestcachesize', default=None, experimental=True,
742 b'format', b'manifestcachesize', default=None, experimental=True,
743 )
743 )
744 coreconfigitem(
744 coreconfigitem(
745 b'format', b'maxchainlen', default=dynamicdefault, experimental=True,
745 b'format', b'maxchainlen', default=dynamicdefault, experimental=True,
746 )
746 )
747 coreconfigitem(
747 coreconfigitem(
748 b'format', b'obsstore-version', default=None,
748 b'format', b'obsstore-version', default=None,
749 )
749 )
750 coreconfigitem(
750 coreconfigitem(
751 b'format', b'sparse-revlog', default=True,
751 b'format', b'sparse-revlog', default=True,
752 )
752 )
753 coreconfigitem(
753 coreconfigitem(
754 b'format',
754 b'format',
755 b'revlog-compression',
755 b'revlog-compression',
756 default=lambda: [b'zlib'],
756 default=lambda: [b'zlib'],
757 alias=[(b'experimental', b'format.compression')],
757 alias=[(b'experimental', b'format.compression')],
758 )
758 )
759 coreconfigitem(
759 coreconfigitem(
760 b'format', b'usefncache', default=True,
760 b'format', b'usefncache', default=True,
761 )
761 )
762 coreconfigitem(
762 coreconfigitem(
763 b'format', b'usegeneraldelta', default=True,
763 b'format', b'usegeneraldelta', default=True,
764 )
764 )
765 coreconfigitem(
765 coreconfigitem(
766 b'format', b'usestore', default=True,
766 b'format', b'usestore', default=True,
767 )
767 )
768 # Right now, the only efficient implement of the nodemap logic is in Rust, so
768 # Right now, the only efficient implement of the nodemap logic is in Rust, so
769 # the persistent nodemap feature needs to stay experimental as long as the Rust
769 # the persistent nodemap feature needs to stay experimental as long as the Rust
770 # extensions are an experimental feature.
770 # extensions are an experimental feature.
771 coreconfigitem(
771 coreconfigitem(
772 b'format', b'use-persistent-nodemap', default=False, experimental=True
772 b'format', b'use-persistent-nodemap', default=False, experimental=True
773 )
773 )
774 coreconfigitem(
774 coreconfigitem(
775 b'format',
775 b'format',
776 b'exp-use-copies-side-data-changeset',
776 b'exp-use-copies-side-data-changeset',
777 default=False,
777 default=False,
778 experimental=True,
778 experimental=True,
779 )
779 )
780 coreconfigitem(
780 coreconfigitem(
781 b'format', b'exp-use-side-data', default=False, experimental=True,
781 b'format', b'exp-use-side-data', default=False, experimental=True,
782 )
782 )
783 coreconfigitem(
783 coreconfigitem(
784 b'format', b'internal-phase', default=False, experimental=True,
784 b'format', b'internal-phase', default=False, experimental=True,
785 )
785 )
786 coreconfigitem(
786 coreconfigitem(
787 b'fsmonitor', b'warn_when_unused', default=True,
787 b'fsmonitor', b'warn_when_unused', default=True,
788 )
788 )
789 coreconfigitem(
789 coreconfigitem(
790 b'fsmonitor', b'warn_update_file_count', default=50000,
790 b'fsmonitor', b'warn_update_file_count', default=50000,
791 )
791 )
792 coreconfigitem(
792 coreconfigitem(
793 b'help', br'hidden-command\..*', default=False, generic=True,
793 b'help', br'hidden-command\..*', default=False, generic=True,
794 )
794 )
795 coreconfigitem(
795 coreconfigitem(
796 b'help', br'hidden-topic\..*', default=False, generic=True,
796 b'help', br'hidden-topic\..*', default=False, generic=True,
797 )
797 )
798 coreconfigitem(
798 coreconfigitem(
799 b'hooks', b'.*', default=dynamicdefault, generic=True,
799 b'hooks', b'.*', default=dynamicdefault, generic=True,
800 )
800 )
801 coreconfigitem(
801 coreconfigitem(
802 b'hgweb-paths', b'.*', default=list, generic=True,
802 b'hgweb-paths', b'.*', default=list, generic=True,
803 )
803 )
804 coreconfigitem(
804 coreconfigitem(
805 b'hostfingerprints', b'.*', default=list, generic=True,
805 b'hostfingerprints', b'.*', default=list, generic=True,
806 )
806 )
807 coreconfigitem(
807 coreconfigitem(
808 b'hostsecurity', b'ciphers', default=None,
808 b'hostsecurity', b'ciphers', default=None,
809 )
809 )
810 coreconfigitem(
810 coreconfigitem(
811 b'hostsecurity', b'minimumprotocol', default=dynamicdefault,
811 b'hostsecurity', b'minimumprotocol', default=dynamicdefault,
812 )
812 )
813 coreconfigitem(
813 coreconfigitem(
814 b'hostsecurity',
814 b'hostsecurity',
815 b'.*:minimumprotocol$',
815 b'.*:minimumprotocol$',
816 default=dynamicdefault,
816 default=dynamicdefault,
817 generic=True,
817 generic=True,
818 )
818 )
819 coreconfigitem(
819 coreconfigitem(
820 b'hostsecurity', b'.*:ciphers$', default=dynamicdefault, generic=True,
820 b'hostsecurity', b'.*:ciphers$', default=dynamicdefault, generic=True,
821 )
821 )
822 coreconfigitem(
822 coreconfigitem(
823 b'hostsecurity', b'.*:fingerprints$', default=list, generic=True,
823 b'hostsecurity', b'.*:fingerprints$', default=list, generic=True,
824 )
824 )
825 coreconfigitem(
825 coreconfigitem(
826 b'hostsecurity', b'.*:verifycertsfile$', default=None, generic=True,
826 b'hostsecurity', b'.*:verifycertsfile$', default=None, generic=True,
827 )
827 )
828
828
829 coreconfigitem(
829 coreconfigitem(
830 b'http_proxy', b'always', default=False,
830 b'http_proxy', b'always', default=False,
831 )
831 )
832 coreconfigitem(
832 coreconfigitem(
833 b'http_proxy', b'host', default=None,
833 b'http_proxy', b'host', default=None,
834 )
834 )
835 coreconfigitem(
835 coreconfigitem(
836 b'http_proxy', b'no', default=list,
836 b'http_proxy', b'no', default=list,
837 )
837 )
838 coreconfigitem(
838 coreconfigitem(
839 b'http_proxy', b'passwd', default=None,
839 b'http_proxy', b'passwd', default=None,
840 )
840 )
841 coreconfigitem(
841 coreconfigitem(
842 b'http_proxy', b'user', default=None,
842 b'http_proxy', b'user', default=None,
843 )
843 )
844
844
845 coreconfigitem(
845 coreconfigitem(
846 b'http', b'timeout', default=None,
846 b'http', b'timeout', default=None,
847 )
847 )
848
848
849 coreconfigitem(
849 coreconfigitem(
850 b'logtoprocess', b'commandexception', default=None,
850 b'logtoprocess', b'commandexception', default=None,
851 )
851 )
852 coreconfigitem(
852 coreconfigitem(
853 b'logtoprocess', b'commandfinish', default=None,
853 b'logtoprocess', b'commandfinish', default=None,
854 )
854 )
855 coreconfigitem(
855 coreconfigitem(
856 b'logtoprocess', b'command', default=None,
856 b'logtoprocess', b'command', default=None,
857 )
857 )
858 coreconfigitem(
858 coreconfigitem(
859 b'logtoprocess', b'develwarn', default=None,
859 b'logtoprocess', b'develwarn', default=None,
860 )
860 )
861 coreconfigitem(
861 coreconfigitem(
862 b'logtoprocess', b'uiblocked', default=None,
862 b'logtoprocess', b'uiblocked', default=None,
863 )
863 )
864 coreconfigitem(
864 coreconfigitem(
865 b'merge', b'checkunknown', default=b'abort',
865 b'merge', b'checkunknown', default=b'abort',
866 )
866 )
867 coreconfigitem(
867 coreconfigitem(
868 b'merge', b'checkignored', default=b'abort',
868 b'merge', b'checkignored', default=b'abort',
869 )
869 )
870 coreconfigitem(
870 coreconfigitem(
871 b'experimental', b'merge.checkpathconflicts', default=False,
871 b'experimental', b'merge.checkpathconflicts', default=False,
872 )
872 )
873 coreconfigitem(
873 coreconfigitem(
874 b'merge', b'followcopies', default=True,
874 b'merge', b'followcopies', default=True,
875 )
875 )
876 coreconfigitem(
876 coreconfigitem(
877 b'merge', b'on-failure', default=b'continue',
877 b'merge', b'on-failure', default=b'continue',
878 )
878 )
879 coreconfigitem(
879 coreconfigitem(
880 b'merge', b'preferancestor', default=lambda: [b'*'], experimental=True,
880 b'merge', b'preferancestor', default=lambda: [b'*'], experimental=True,
881 )
881 )
882 coreconfigitem(
882 coreconfigitem(
883 b'merge', b'strict-capability-check', default=False,
883 b'merge', b'strict-capability-check', default=False,
884 )
884 )
885 coreconfigitem(
885 coreconfigitem(
886 b'merge-tools', b'.*', default=None, generic=True,
886 b'merge-tools', b'.*', default=None, generic=True,
887 )
887 )
888 coreconfigitem(
888 coreconfigitem(
889 b'merge-tools',
889 b'merge-tools',
890 br'.*\.args$',
890 br'.*\.args$',
891 default=b"$local $base $other",
891 default=b"$local $base $other",
892 generic=True,
892 generic=True,
893 priority=-1,
893 priority=-1,
894 )
894 )
895 coreconfigitem(
895 coreconfigitem(
896 b'merge-tools', br'.*\.binary$', default=False, generic=True, priority=-1,
896 b'merge-tools', br'.*\.binary$', default=False, generic=True, priority=-1,
897 )
897 )
898 coreconfigitem(
898 coreconfigitem(
899 b'merge-tools', br'.*\.check$', default=list, generic=True, priority=-1,
899 b'merge-tools', br'.*\.check$', default=list, generic=True, priority=-1,
900 )
900 )
901 coreconfigitem(
901 coreconfigitem(
902 b'merge-tools',
902 b'merge-tools',
903 br'.*\.checkchanged$',
903 br'.*\.checkchanged$',
904 default=False,
904 default=False,
905 generic=True,
905 generic=True,
906 priority=-1,
906 priority=-1,
907 )
907 )
908 coreconfigitem(
908 coreconfigitem(
909 b'merge-tools',
909 b'merge-tools',
910 br'.*\.executable$',
910 br'.*\.executable$',
911 default=dynamicdefault,
911 default=dynamicdefault,
912 generic=True,
912 generic=True,
913 priority=-1,
913 priority=-1,
914 )
914 )
915 coreconfigitem(
915 coreconfigitem(
916 b'merge-tools', br'.*\.fixeol$', default=False, generic=True, priority=-1,
916 b'merge-tools', br'.*\.fixeol$', default=False, generic=True, priority=-1,
917 )
917 )
918 coreconfigitem(
918 coreconfigitem(
919 b'merge-tools', br'.*\.gui$', default=False, generic=True, priority=-1,
919 b'merge-tools', br'.*\.gui$', default=False, generic=True, priority=-1,
920 )
920 )
921 coreconfigitem(
921 coreconfigitem(
922 b'merge-tools',
922 b'merge-tools',
923 br'.*\.mergemarkers$',
923 br'.*\.mergemarkers$',
924 default=b'basic',
924 default=b'basic',
925 generic=True,
925 generic=True,
926 priority=-1,
926 priority=-1,
927 )
927 )
928 coreconfigitem(
928 coreconfigitem(
929 b'merge-tools',
929 b'merge-tools',
930 br'.*\.mergemarkertemplate$',
930 br'.*\.mergemarkertemplate$',
931 default=dynamicdefault, # take from ui.mergemarkertemplate
931 default=dynamicdefault, # take from ui.mergemarkertemplate
932 generic=True,
932 generic=True,
933 priority=-1,
933 priority=-1,
934 )
934 )
935 coreconfigitem(
935 coreconfigitem(
936 b'merge-tools', br'.*\.priority$', default=0, generic=True, priority=-1,
936 b'merge-tools', br'.*\.priority$', default=0, generic=True, priority=-1,
937 )
937 )
938 coreconfigitem(
938 coreconfigitem(
939 b'merge-tools',
939 b'merge-tools',
940 br'.*\.premerge$',
940 br'.*\.premerge$',
941 default=dynamicdefault,
941 default=dynamicdefault,
942 generic=True,
942 generic=True,
943 priority=-1,
943 priority=-1,
944 )
944 )
945 coreconfigitem(
945 coreconfigitem(
946 b'merge-tools', br'.*\.symlink$', default=False, generic=True, priority=-1,
946 b'merge-tools', br'.*\.symlink$', default=False, generic=True, priority=-1,
947 )
947 )
948 coreconfigitem(
948 coreconfigitem(
949 b'pager', b'attend-.*', default=dynamicdefault, generic=True,
949 b'pager', b'attend-.*', default=dynamicdefault, generic=True,
950 )
950 )
951 coreconfigitem(
951 coreconfigitem(
952 b'pager', b'ignore', default=list,
952 b'pager', b'ignore', default=list,
953 )
953 )
954 coreconfigitem(
954 coreconfigitem(
955 b'pager', b'pager', default=dynamicdefault,
955 b'pager', b'pager', default=dynamicdefault,
956 )
956 )
957 coreconfigitem(
957 coreconfigitem(
958 b'patch', b'eol', default=b'strict',
958 b'patch', b'eol', default=b'strict',
959 )
959 )
960 coreconfigitem(
960 coreconfigitem(
961 b'patch', b'fuzz', default=2,
961 b'patch', b'fuzz', default=2,
962 )
962 )
963 coreconfigitem(
963 coreconfigitem(
964 b'paths', b'default', default=None,
964 b'paths', b'default', default=None,
965 )
965 )
966 coreconfigitem(
966 coreconfigitem(
967 b'paths', b'default-push', default=None,
967 b'paths', b'default-push', default=None,
968 )
968 )
969 coreconfigitem(
969 coreconfigitem(
970 b'paths', b'.*', default=None, generic=True,
970 b'paths', b'.*', default=None, generic=True,
971 )
971 )
972 coreconfigitem(
972 coreconfigitem(
973 b'phases', b'checksubrepos', default=b'follow',
973 b'phases', b'checksubrepos', default=b'follow',
974 )
974 )
975 coreconfigitem(
975 coreconfigitem(
976 b'phases', b'new-commit', default=b'draft',
976 b'phases', b'new-commit', default=b'draft',
977 )
977 )
978 coreconfigitem(
978 coreconfigitem(
979 b'phases', b'publish', default=True,
979 b'phases', b'publish', default=True,
980 )
980 )
981 coreconfigitem(
981 coreconfigitem(
982 b'profiling', b'enabled', default=False,
982 b'profiling', b'enabled', default=False,
983 )
983 )
984 coreconfigitem(
984 coreconfigitem(
985 b'profiling', b'format', default=b'text',
985 b'profiling', b'format', default=b'text',
986 )
986 )
987 coreconfigitem(
987 coreconfigitem(
988 b'profiling', b'freq', default=1000,
988 b'profiling', b'freq', default=1000,
989 )
989 )
990 coreconfigitem(
990 coreconfigitem(
991 b'profiling', b'limit', default=30,
991 b'profiling', b'limit', default=30,
992 )
992 )
993 coreconfigitem(
993 coreconfigitem(
994 b'profiling', b'nested', default=0,
994 b'profiling', b'nested', default=0,
995 )
995 )
996 coreconfigitem(
996 coreconfigitem(
997 b'profiling', b'output', default=None,
997 b'profiling', b'output', default=None,
998 )
998 )
999 coreconfigitem(
999 coreconfigitem(
1000 b'profiling', b'showmax', default=0.999,
1000 b'profiling', b'showmax', default=0.999,
1001 )
1001 )
1002 coreconfigitem(
1002 coreconfigitem(
1003 b'profiling', b'showmin', default=dynamicdefault,
1003 b'profiling', b'showmin', default=dynamicdefault,
1004 )
1004 )
1005 coreconfigitem(
1005 coreconfigitem(
1006 b'profiling', b'showtime', default=True,
1006 b'profiling', b'showtime', default=True,
1007 )
1007 )
1008 coreconfigitem(
1008 coreconfigitem(
1009 b'profiling', b'sort', default=b'inlinetime',
1009 b'profiling', b'sort', default=b'inlinetime',
1010 )
1010 )
1011 coreconfigitem(
1011 coreconfigitem(
1012 b'profiling', b'statformat', default=b'hotpath',
1012 b'profiling', b'statformat', default=b'hotpath',
1013 )
1013 )
1014 coreconfigitem(
1014 coreconfigitem(
1015 b'profiling', b'time-track', default=dynamicdefault,
1015 b'profiling', b'time-track', default=dynamicdefault,
1016 )
1016 )
1017 coreconfigitem(
1017 coreconfigitem(
1018 b'profiling', b'type', default=b'stat',
1018 b'profiling', b'type', default=b'stat',
1019 )
1019 )
1020 coreconfigitem(
1020 coreconfigitem(
1021 b'progress', b'assume-tty', default=False,
1021 b'progress', b'assume-tty', default=False,
1022 )
1022 )
1023 coreconfigitem(
1023 coreconfigitem(
1024 b'progress', b'changedelay', default=1,
1024 b'progress', b'changedelay', default=1,
1025 )
1025 )
1026 coreconfigitem(
1026 coreconfigitem(
1027 b'progress', b'clear-complete', default=True,
1027 b'progress', b'clear-complete', default=True,
1028 )
1028 )
1029 coreconfigitem(
1029 coreconfigitem(
1030 b'progress', b'debug', default=False,
1030 b'progress', b'debug', default=False,
1031 )
1031 )
1032 coreconfigitem(
1032 coreconfigitem(
1033 b'progress', b'delay', default=3,
1033 b'progress', b'delay', default=3,
1034 )
1034 )
1035 coreconfigitem(
1035 coreconfigitem(
1036 b'progress', b'disable', default=False,
1036 b'progress', b'disable', default=False,
1037 )
1037 )
1038 coreconfigitem(
1038 coreconfigitem(
1039 b'progress', b'estimateinterval', default=60.0,
1039 b'progress', b'estimateinterval', default=60.0,
1040 )
1040 )
1041 coreconfigitem(
1041 coreconfigitem(
1042 b'progress',
1042 b'progress',
1043 b'format',
1043 b'format',
1044 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1044 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1045 )
1045 )
1046 coreconfigitem(
1046 coreconfigitem(
1047 b'progress', b'refresh', default=0.1,
1047 b'progress', b'refresh', default=0.1,
1048 )
1048 )
1049 coreconfigitem(
1049 coreconfigitem(
1050 b'progress', b'width', default=dynamicdefault,
1050 b'progress', b'width', default=dynamicdefault,
1051 )
1051 )
1052 coreconfigitem(
1052 coreconfigitem(
1053 b'pull', b'confirm', default=False,
1053 b'pull', b'confirm', default=False,
1054 )
1054 )
1055 coreconfigitem(
1055 coreconfigitem(
1056 b'push', b'pushvars.server', default=False,
1056 b'push', b'pushvars.server', default=False,
1057 )
1057 )
1058 coreconfigitem(
1058 coreconfigitem(
1059 b'rewrite',
1059 b'rewrite',
1060 b'backup-bundle',
1060 b'backup-bundle',
1061 default=True,
1061 default=True,
1062 alias=[(b'ui', b'history-editing-backup')],
1062 alias=[(b'ui', b'history-editing-backup')],
1063 )
1063 )
1064 coreconfigitem(
1064 coreconfigitem(
1065 b'rewrite', b'update-timestamp', default=False,
1065 b'rewrite', b'update-timestamp', default=False,
1066 )
1066 )
1067 coreconfigitem(
1067 coreconfigitem(
1068 b'storage', b'new-repo-backend', default=b'revlogv1', experimental=True,
1068 b'storage', b'new-repo-backend', default=b'revlogv1', experimental=True,
1069 )
1069 )
1070 coreconfigitem(
1070 coreconfigitem(
1071 b'storage',
1071 b'storage',
1072 b'revlog.optimize-delta-parent-choice',
1072 b'revlog.optimize-delta-parent-choice',
1073 default=True,
1073 default=True,
1074 alias=[(b'format', b'aggressivemergedeltas')],
1074 alias=[(b'format', b'aggressivemergedeltas')],
1075 )
1075 )
1076 # experimental as long as rust is experimental (or a C version is implemented)
1076 # experimental as long as rust is experimental (or a C version is implemented)
1077 coreconfigitem(
1077 coreconfigitem(
1078 b'storage', b'revlog.nodemap.mmap', default=True, experimental=True
1078 b'storage', b'revlog.nodemap.mmap', default=True, experimental=True
1079 )
1079 )
1080 # experimental as long as format.use-persistent-nodemap is.
1080 # experimental as long as format.use-persistent-nodemap is.
1081 coreconfigitem(
1081 coreconfigitem(
1082 b'storage', b'revlog.nodemap.mode', default=b'compat', experimental=True
1082 b'storage', b'revlog.nodemap.mode', default=b'compat', experimental=True
1083 )
1083 )
1084 coreconfigitem(
1084 coreconfigitem(
1085 b'storage', b'revlog.reuse-external-delta', default=True,
1085 b'storage', b'revlog.reuse-external-delta', default=True,
1086 )
1086 )
1087 coreconfigitem(
1087 coreconfigitem(
1088 b'storage', b'revlog.reuse-external-delta-parent', default=None,
1088 b'storage', b'revlog.reuse-external-delta-parent', default=None,
1089 )
1089 )
1090 coreconfigitem(
1090 coreconfigitem(
1091 b'storage', b'revlog.zlib.level', default=None,
1091 b'storage', b'revlog.zlib.level', default=None,
1092 )
1092 )
1093 coreconfigitem(
1093 coreconfigitem(
1094 b'storage', b'revlog.zstd.level', default=None,
1094 b'storage', b'revlog.zstd.level', default=None,
1095 )
1095 )
1096 coreconfigitem(
1096 coreconfigitem(
1097 b'server', b'bookmarks-pushkey-compat', default=True,
1097 b'server', b'bookmarks-pushkey-compat', default=True,
1098 )
1098 )
1099 coreconfigitem(
1099 coreconfigitem(
1100 b'server', b'bundle1', default=True,
1100 b'server', b'bundle1', default=True,
1101 )
1101 )
1102 coreconfigitem(
1102 coreconfigitem(
1103 b'server', b'bundle1gd', default=None,
1103 b'server', b'bundle1gd', default=None,
1104 )
1104 )
1105 coreconfigitem(
1105 coreconfigitem(
1106 b'server', b'bundle1.pull', default=None,
1106 b'server', b'bundle1.pull', default=None,
1107 )
1107 )
1108 coreconfigitem(
1108 coreconfigitem(
1109 b'server', b'bundle1gd.pull', default=None,
1109 b'server', b'bundle1gd.pull', default=None,
1110 )
1110 )
1111 coreconfigitem(
1111 coreconfigitem(
1112 b'server', b'bundle1.push', default=None,
1112 b'server', b'bundle1.push', default=None,
1113 )
1113 )
1114 coreconfigitem(
1114 coreconfigitem(
1115 b'server', b'bundle1gd.push', default=None,
1115 b'server', b'bundle1gd.push', default=None,
1116 )
1116 )
1117 coreconfigitem(
1117 coreconfigitem(
1118 b'server',
1118 b'server',
1119 b'bundle2.stream',
1119 b'bundle2.stream',
1120 default=True,
1120 default=True,
1121 alias=[(b'experimental', b'bundle2.stream')],
1121 alias=[(b'experimental', b'bundle2.stream')],
1122 )
1122 )
1123 coreconfigitem(
1123 coreconfigitem(
1124 b'server', b'compressionengines', default=list,
1124 b'server', b'compressionengines', default=list,
1125 )
1125 )
1126 coreconfigitem(
1126 coreconfigitem(
1127 b'server', b'concurrent-push-mode', default=b'check-related',
1127 b'server', b'concurrent-push-mode', default=b'check-related',
1128 )
1128 )
1129 coreconfigitem(
1129 coreconfigitem(
1130 b'server', b'disablefullbundle', default=False,
1130 b'server', b'disablefullbundle', default=False,
1131 )
1131 )
1132 coreconfigitem(
1132 coreconfigitem(
1133 b'server', b'maxhttpheaderlen', default=1024,
1133 b'server', b'maxhttpheaderlen', default=1024,
1134 )
1134 )
1135 coreconfigitem(
1135 coreconfigitem(
1136 b'server', b'pullbundle', default=False,
1136 b'server', b'pullbundle', default=False,
1137 )
1137 )
1138 coreconfigitem(
1138 coreconfigitem(
1139 b'server', b'preferuncompressed', default=False,
1139 b'server', b'preferuncompressed', default=False,
1140 )
1140 )
1141 coreconfigitem(
1141 coreconfigitem(
1142 b'server', b'streamunbundle', default=False,
1142 b'server', b'streamunbundle', default=False,
1143 )
1143 )
1144 coreconfigitem(
1144 coreconfigitem(
1145 b'server', b'uncompressed', default=True,
1145 b'server', b'uncompressed', default=True,
1146 )
1146 )
1147 coreconfigitem(
1147 coreconfigitem(
1148 b'server', b'uncompressedallowsecret', default=False,
1148 b'server', b'uncompressedallowsecret', default=False,
1149 )
1149 )
1150 coreconfigitem(
1150 coreconfigitem(
1151 b'server', b'view', default=b'served',
1151 b'server', b'view', default=b'served',
1152 )
1152 )
1153 coreconfigitem(
1153 coreconfigitem(
1154 b'server', b'validate', default=False,
1154 b'server', b'validate', default=False,
1155 )
1155 )
1156 coreconfigitem(
1156 coreconfigitem(
1157 b'server', b'zliblevel', default=-1,
1157 b'server', b'zliblevel', default=-1,
1158 )
1158 )
1159 coreconfigitem(
1159 coreconfigitem(
1160 b'server', b'zstdlevel', default=3,
1160 b'server', b'zstdlevel', default=3,
1161 )
1161 )
1162 coreconfigitem(
1162 coreconfigitem(
1163 b'share', b'pool', default=None,
1163 b'share', b'pool', default=None,
1164 )
1164 )
1165 coreconfigitem(
1165 coreconfigitem(
1166 b'share', b'poolnaming', default=b'identity',
1166 b'share', b'poolnaming', default=b'identity',
1167 )
1167 )
1168 coreconfigitem(
1168 coreconfigitem(
1169 b'shelve', b'maxbackups', default=10,
1169 b'shelve', b'maxbackups', default=10,
1170 )
1170 )
1171 coreconfigitem(
1171 coreconfigitem(
1172 b'smtp', b'host', default=None,
1172 b'smtp', b'host', default=None,
1173 )
1173 )
1174 coreconfigitem(
1174 coreconfigitem(
1175 b'smtp', b'local_hostname', default=None,
1175 b'smtp', b'local_hostname', default=None,
1176 )
1176 )
1177 coreconfigitem(
1177 coreconfigitem(
1178 b'smtp', b'password', default=None,
1178 b'smtp', b'password', default=None,
1179 )
1179 )
1180 coreconfigitem(
1180 coreconfigitem(
1181 b'smtp', b'port', default=dynamicdefault,
1181 b'smtp', b'port', default=dynamicdefault,
1182 )
1182 )
1183 coreconfigitem(
1183 coreconfigitem(
1184 b'smtp', b'tls', default=b'none',
1184 b'smtp', b'tls', default=b'none',
1185 )
1185 )
1186 coreconfigitem(
1186 coreconfigitem(
1187 b'smtp', b'username', default=None,
1187 b'smtp', b'username', default=None,
1188 )
1188 )
1189 coreconfigitem(
1189 coreconfigitem(
1190 b'sparse', b'missingwarning', default=True, experimental=True,
1190 b'sparse', b'missingwarning', default=True, experimental=True,
1191 )
1191 )
1192 coreconfigitem(
1192 coreconfigitem(
1193 b'subrepos',
1193 b'subrepos',
1194 b'allowed',
1194 b'allowed',
1195 default=dynamicdefault, # to make backporting simpler
1195 default=dynamicdefault, # to make backporting simpler
1196 )
1196 )
1197 coreconfigitem(
1197 coreconfigitem(
1198 b'subrepos', b'hg:allowed', default=dynamicdefault,
1198 b'subrepos', b'hg:allowed', default=dynamicdefault,
1199 )
1199 )
1200 coreconfigitem(
1200 coreconfigitem(
1201 b'subrepos', b'git:allowed', default=dynamicdefault,
1201 b'subrepos', b'git:allowed', default=dynamicdefault,
1202 )
1202 )
1203 coreconfigitem(
1203 coreconfigitem(
1204 b'subrepos', b'svn:allowed', default=dynamicdefault,
1204 b'subrepos', b'svn:allowed', default=dynamicdefault,
1205 )
1205 )
1206 coreconfigitem(
1206 coreconfigitem(
1207 b'templates', b'.*', default=None, generic=True,
1207 b'templates', b'.*', default=None, generic=True,
1208 )
1208 )
1209 coreconfigitem(
1209 coreconfigitem(
1210 b'templateconfig', b'.*', default=dynamicdefault, generic=True,
1210 b'templateconfig', b'.*', default=dynamicdefault, generic=True,
1211 )
1211 )
1212 coreconfigitem(
1212 coreconfigitem(
1213 b'trusted', b'groups', default=list,
1213 b'trusted', b'groups', default=list,
1214 )
1214 )
1215 coreconfigitem(
1215 coreconfigitem(
1216 b'trusted', b'users', default=list,
1216 b'trusted', b'users', default=list,
1217 )
1217 )
1218 coreconfigitem(
1218 coreconfigitem(
1219 b'ui', b'_usedassubrepo', default=False,
1219 b'ui', b'_usedassubrepo', default=False,
1220 )
1220 )
1221 coreconfigitem(
1221 coreconfigitem(
1222 b'ui', b'allowemptycommit', default=False,
1222 b'ui', b'allowemptycommit', default=False,
1223 )
1223 )
1224 coreconfigitem(
1224 coreconfigitem(
1225 b'ui', b'archivemeta', default=True,
1225 b'ui', b'archivemeta', default=True,
1226 )
1226 )
1227 coreconfigitem(
1227 coreconfigitem(
1228 b'ui', b'askusername', default=False,
1228 b'ui', b'askusername', default=False,
1229 )
1229 )
1230 coreconfigitem(
1230 coreconfigitem(
1231 b'ui', b'clonebundlefallback', default=False,
1231 b'ui', b'clonebundlefallback', default=False,
1232 )
1232 )
1233 coreconfigitem(
1233 coreconfigitem(
1234 b'ui', b'clonebundleprefers', default=list,
1234 b'ui', b'clonebundleprefers', default=list,
1235 )
1235 )
1236 coreconfigitem(
1236 coreconfigitem(
1237 b'ui', b'clonebundles', default=True,
1237 b'ui', b'clonebundles', default=True,
1238 )
1238 )
1239 coreconfigitem(
1239 coreconfigitem(
1240 b'ui', b'color', default=b'auto',
1240 b'ui', b'color', default=b'auto',
1241 )
1241 )
1242 coreconfigitem(
1242 coreconfigitem(
1243 b'ui', b'commitsubrepos', default=False,
1243 b'ui', b'commitsubrepos', default=False,
1244 )
1244 )
1245 coreconfigitem(
1245 coreconfigitem(
1246 b'ui', b'debug', default=False,
1246 b'ui', b'debug', default=False,
1247 )
1247 )
1248 coreconfigitem(
1248 coreconfigitem(
1249 b'ui', b'debugger', default=None,
1249 b'ui', b'debugger', default=None,
1250 )
1250 )
1251 coreconfigitem(
1251 coreconfigitem(
1252 b'ui', b'editor', default=dynamicdefault,
1252 b'ui', b'editor', default=dynamicdefault,
1253 )
1253 )
1254 coreconfigitem(
1254 coreconfigitem(
1255 b'ui', b'fallbackencoding', default=None,
1255 b'ui', b'fallbackencoding', default=None,
1256 )
1256 )
1257 coreconfigitem(
1257 coreconfigitem(
1258 b'ui', b'forcecwd', default=None,
1258 b'ui', b'forcecwd', default=None,
1259 )
1259 )
1260 coreconfigitem(
1260 coreconfigitem(
1261 b'ui', b'forcemerge', default=None,
1261 b'ui', b'forcemerge', default=None,
1262 )
1262 )
1263 coreconfigitem(
1263 coreconfigitem(
1264 b'ui', b'formatdebug', default=False,
1264 b'ui', b'formatdebug', default=False,
1265 )
1265 )
1266 coreconfigitem(
1266 coreconfigitem(
1267 b'ui', b'formatjson', default=False,
1267 b'ui', b'formatjson', default=False,
1268 )
1268 )
1269 coreconfigitem(
1269 coreconfigitem(
1270 b'ui', b'formatted', default=None,
1270 b'ui', b'formatted', default=None,
1271 )
1271 )
1272 coreconfigitem(
1272 coreconfigitem(
1273 b'ui', b'graphnodetemplate', default=None,
1273 b'ui', b'graphnodetemplate', default=None,
1274 )
1274 )
1275 coreconfigitem(
1275 coreconfigitem(
1276 b'ui', b'interactive', default=None,
1276 b'ui', b'interactive', default=None,
1277 )
1277 )
1278 coreconfigitem(
1278 coreconfigitem(
1279 b'ui', b'interface', default=None,
1279 b'ui', b'interface', default=None,
1280 )
1280 )
1281 coreconfigitem(
1281 coreconfigitem(
1282 b'ui', b'interface.chunkselector', default=None,
1282 b'ui', b'interface.chunkselector', default=None,
1283 )
1283 )
1284 coreconfigitem(
1284 coreconfigitem(
1285 b'ui', b'large-file-limit', default=10000000,
1285 b'ui', b'large-file-limit', default=10000000,
1286 )
1286 )
1287 coreconfigitem(
1287 coreconfigitem(
1288 b'ui', b'logblockedtimes', default=False,
1288 b'ui', b'logblockedtimes', default=False,
1289 )
1289 )
1290 coreconfigitem(
1290 coreconfigitem(
1291 b'ui', b'logtemplate', default=None,
1291 b'ui', b'logtemplate', default=None,
1292 )
1292 )
1293 coreconfigitem(
1293 coreconfigitem(
1294 b'ui', b'merge', default=None,
1294 b'ui', b'merge', default=None,
1295 )
1295 )
1296 coreconfigitem(
1296 coreconfigitem(
1297 b'ui', b'mergemarkers', default=b'basic',
1297 b'ui', b'mergemarkers', default=b'basic',
1298 )
1298 )
1299 coreconfigitem(
1299 coreconfigitem(
1300 b'ui',
1300 b'ui',
1301 b'mergemarkertemplate',
1301 b'mergemarkertemplate',
1302 default=(
1302 default=(
1303 b'{node|short} '
1303 b'{node|short} '
1304 b'{ifeq(tags, "tip", "", '
1304 b'{ifeq(tags, "tip", "", '
1305 b'ifeq(tags, "", "", "{tags} "))}'
1305 b'ifeq(tags, "", "", "{tags} "))}'
1306 b'{if(bookmarks, "{bookmarks} ")}'
1306 b'{if(bookmarks, "{bookmarks} ")}'
1307 b'{ifeq(branch, "default", "", "{branch} ")}'
1307 b'{ifeq(branch, "default", "", "{branch} ")}'
1308 b'- {author|user}: {desc|firstline}'
1308 b'- {author|user}: {desc|firstline}'
1309 ),
1309 ),
1310 )
1310 )
1311 coreconfigitem(
1311 coreconfigitem(
1312 b'ui', b'message-output', default=b'stdio',
1312 b'ui', b'message-output', default=b'stdio',
1313 )
1313 )
1314 coreconfigitem(
1314 coreconfigitem(
1315 b'ui', b'nontty', default=False,
1315 b'ui', b'nontty', default=False,
1316 )
1316 )
1317 coreconfigitem(
1317 coreconfigitem(
1318 b'ui', b'origbackuppath', default=None,
1318 b'ui', b'origbackuppath', default=None,
1319 )
1319 )
1320 coreconfigitem(
1320 coreconfigitem(
1321 b'ui', b'paginate', default=True,
1321 b'ui', b'paginate', default=True,
1322 )
1322 )
1323 coreconfigitem(
1323 coreconfigitem(
1324 b'ui', b'patch', default=None,
1324 b'ui', b'patch', default=None,
1325 )
1325 )
1326 coreconfigitem(
1326 coreconfigitem(
1327 b'ui', b'pre-merge-tool-output-template', default=None,
1327 b'ui', b'pre-merge-tool-output-template', default=None,
1328 )
1328 )
1329 coreconfigitem(
1329 coreconfigitem(
1330 b'ui', b'portablefilenames', default=b'warn',
1330 b'ui', b'portablefilenames', default=b'warn',
1331 )
1331 )
1332 coreconfigitem(
1332 coreconfigitem(
1333 b'ui', b'promptecho', default=False,
1333 b'ui', b'promptecho', default=False,
1334 )
1334 )
1335 coreconfigitem(
1335 coreconfigitem(
1336 b'ui', b'quiet', default=False,
1336 b'ui', b'quiet', default=False,
1337 )
1337 )
1338 coreconfigitem(
1338 coreconfigitem(
1339 b'ui', b'quietbookmarkmove', default=False,
1339 b'ui', b'quietbookmarkmove', default=False,
1340 )
1340 )
1341 coreconfigitem(
1341 coreconfigitem(
1342 b'ui', b'relative-paths', default=b'legacy',
1342 b'ui', b'relative-paths', default=b'legacy',
1343 )
1343 )
1344 coreconfigitem(
1344 coreconfigitem(
1345 b'ui', b'remotecmd', default=b'hg',
1345 b'ui', b'remotecmd', default=b'hg',
1346 )
1346 )
1347 coreconfigitem(
1347 coreconfigitem(
1348 b'ui', b'report_untrusted', default=True,
1348 b'ui', b'report_untrusted', default=True,
1349 )
1349 )
1350 coreconfigitem(
1350 coreconfigitem(
1351 b'ui', b'rollback', default=True,
1351 b'ui', b'rollback', default=True,
1352 )
1352 )
1353 coreconfigitem(
1353 coreconfigitem(
1354 b'ui', b'signal-safe-lock', default=True,
1354 b'ui', b'signal-safe-lock', default=True,
1355 )
1355 )
1356 coreconfigitem(
1356 coreconfigitem(
1357 b'ui', b'slash', default=False,
1357 b'ui', b'slash', default=False,
1358 )
1358 )
1359 coreconfigitem(
1359 coreconfigitem(
1360 b'ui', b'ssh', default=b'ssh',
1360 b'ui', b'ssh', default=b'ssh',
1361 )
1361 )
1362 coreconfigitem(
1362 coreconfigitem(
1363 b'ui', b'ssherrorhint', default=None,
1363 b'ui', b'ssherrorhint', default=None,
1364 )
1364 )
1365 coreconfigitem(
1365 coreconfigitem(
1366 b'ui', b'statuscopies', default=False,
1366 b'ui', b'statuscopies', default=False,
1367 )
1367 )
1368 coreconfigitem(
1368 coreconfigitem(
1369 b'ui', b'strict', default=False,
1369 b'ui', b'strict', default=False,
1370 )
1370 )
1371 coreconfigitem(
1371 coreconfigitem(
1372 b'ui', b'style', default=b'',
1372 b'ui', b'style', default=b'',
1373 )
1373 )
1374 coreconfigitem(
1374 coreconfigitem(
1375 b'ui', b'supportcontact', default=None,
1375 b'ui', b'supportcontact', default=None,
1376 )
1376 )
1377 coreconfigitem(
1377 coreconfigitem(
1378 b'ui', b'textwidth', default=78,
1378 b'ui', b'textwidth', default=78,
1379 )
1379 )
1380 coreconfigitem(
1380 coreconfigitem(
1381 b'ui', b'timeout', default=b'600',
1381 b'ui', b'timeout', default=b'600',
1382 )
1382 )
1383 coreconfigitem(
1383 coreconfigitem(
1384 b'ui', b'timeout.warn', default=0,
1384 b'ui', b'timeout.warn', default=0,
1385 )
1385 )
1386 coreconfigitem(
1386 coreconfigitem(
1387 b'ui', b'timestamp-output', default=False,
1388 )
1389 coreconfigitem(
1387 b'ui', b'traceback', default=False,
1390 b'ui', b'traceback', default=False,
1388 )
1391 )
1389 coreconfigitem(
1392 coreconfigitem(
1390 b'ui', b'tweakdefaults', default=False,
1393 b'ui', b'tweakdefaults', default=False,
1391 )
1394 )
1392 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
1395 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
1393 coreconfigitem(
1396 coreconfigitem(
1394 b'ui', b'verbose', default=False,
1397 b'ui', b'verbose', default=False,
1395 )
1398 )
1396 coreconfigitem(
1399 coreconfigitem(
1397 b'verify', b'skipflags', default=None,
1400 b'verify', b'skipflags', default=None,
1398 )
1401 )
1399 coreconfigitem(
1402 coreconfigitem(
1400 b'web', b'allowbz2', default=False,
1403 b'web', b'allowbz2', default=False,
1401 )
1404 )
1402 coreconfigitem(
1405 coreconfigitem(
1403 b'web', b'allowgz', default=False,
1406 b'web', b'allowgz', default=False,
1404 )
1407 )
1405 coreconfigitem(
1408 coreconfigitem(
1406 b'web', b'allow-pull', alias=[(b'web', b'allowpull')], default=True,
1409 b'web', b'allow-pull', alias=[(b'web', b'allowpull')], default=True,
1407 )
1410 )
1408 coreconfigitem(
1411 coreconfigitem(
1409 b'web', b'allow-push', alias=[(b'web', b'allow_push')], default=list,
1412 b'web', b'allow-push', alias=[(b'web', b'allow_push')], default=list,
1410 )
1413 )
1411 coreconfigitem(
1414 coreconfigitem(
1412 b'web', b'allowzip', default=False,
1415 b'web', b'allowzip', default=False,
1413 )
1416 )
1414 coreconfigitem(
1417 coreconfigitem(
1415 b'web', b'archivesubrepos', default=False,
1418 b'web', b'archivesubrepos', default=False,
1416 )
1419 )
1417 coreconfigitem(
1420 coreconfigitem(
1418 b'web', b'cache', default=True,
1421 b'web', b'cache', default=True,
1419 )
1422 )
1420 coreconfigitem(
1423 coreconfigitem(
1421 b'web', b'comparisoncontext', default=5,
1424 b'web', b'comparisoncontext', default=5,
1422 )
1425 )
1423 coreconfigitem(
1426 coreconfigitem(
1424 b'web', b'contact', default=None,
1427 b'web', b'contact', default=None,
1425 )
1428 )
1426 coreconfigitem(
1429 coreconfigitem(
1427 b'web', b'deny_push', default=list,
1430 b'web', b'deny_push', default=list,
1428 )
1431 )
1429 coreconfigitem(
1432 coreconfigitem(
1430 b'web', b'guessmime', default=False,
1433 b'web', b'guessmime', default=False,
1431 )
1434 )
1432 coreconfigitem(
1435 coreconfigitem(
1433 b'web', b'hidden', default=False,
1436 b'web', b'hidden', default=False,
1434 )
1437 )
1435 coreconfigitem(
1438 coreconfigitem(
1436 b'web', b'labels', default=list,
1439 b'web', b'labels', default=list,
1437 )
1440 )
1438 coreconfigitem(
1441 coreconfigitem(
1439 b'web', b'logoimg', default=b'hglogo.png',
1442 b'web', b'logoimg', default=b'hglogo.png',
1440 )
1443 )
1441 coreconfigitem(
1444 coreconfigitem(
1442 b'web', b'logourl', default=b'https://mercurial-scm.org/',
1445 b'web', b'logourl', default=b'https://mercurial-scm.org/',
1443 )
1446 )
1444 coreconfigitem(
1447 coreconfigitem(
1445 b'web', b'accesslog', default=b'-',
1448 b'web', b'accesslog', default=b'-',
1446 )
1449 )
1447 coreconfigitem(
1450 coreconfigitem(
1448 b'web', b'address', default=b'',
1451 b'web', b'address', default=b'',
1449 )
1452 )
1450 coreconfigitem(
1453 coreconfigitem(
1451 b'web', b'allow-archive', alias=[(b'web', b'allow_archive')], default=list,
1454 b'web', b'allow-archive', alias=[(b'web', b'allow_archive')], default=list,
1452 )
1455 )
1453 coreconfigitem(
1456 coreconfigitem(
1454 b'web', b'allow_read', default=list,
1457 b'web', b'allow_read', default=list,
1455 )
1458 )
1456 coreconfigitem(
1459 coreconfigitem(
1457 b'web', b'baseurl', default=None,
1460 b'web', b'baseurl', default=None,
1458 )
1461 )
1459 coreconfigitem(
1462 coreconfigitem(
1460 b'web', b'cacerts', default=None,
1463 b'web', b'cacerts', default=None,
1461 )
1464 )
1462 coreconfigitem(
1465 coreconfigitem(
1463 b'web', b'certificate', default=None,
1466 b'web', b'certificate', default=None,
1464 )
1467 )
1465 coreconfigitem(
1468 coreconfigitem(
1466 b'web', b'collapse', default=False,
1469 b'web', b'collapse', default=False,
1467 )
1470 )
1468 coreconfigitem(
1471 coreconfigitem(
1469 b'web', b'csp', default=None,
1472 b'web', b'csp', default=None,
1470 )
1473 )
1471 coreconfigitem(
1474 coreconfigitem(
1472 b'web', b'deny_read', default=list,
1475 b'web', b'deny_read', default=list,
1473 )
1476 )
1474 coreconfigitem(
1477 coreconfigitem(
1475 b'web', b'descend', default=True,
1478 b'web', b'descend', default=True,
1476 )
1479 )
1477 coreconfigitem(
1480 coreconfigitem(
1478 b'web', b'description', default=b"",
1481 b'web', b'description', default=b"",
1479 )
1482 )
1480 coreconfigitem(
1483 coreconfigitem(
1481 b'web', b'encoding', default=lambda: encoding.encoding,
1484 b'web', b'encoding', default=lambda: encoding.encoding,
1482 )
1485 )
1483 coreconfigitem(
1486 coreconfigitem(
1484 b'web', b'errorlog', default=b'-',
1487 b'web', b'errorlog', default=b'-',
1485 )
1488 )
1486 coreconfigitem(
1489 coreconfigitem(
1487 b'web', b'ipv6', default=False,
1490 b'web', b'ipv6', default=False,
1488 )
1491 )
1489 coreconfigitem(
1492 coreconfigitem(
1490 b'web', b'maxchanges', default=10,
1493 b'web', b'maxchanges', default=10,
1491 )
1494 )
1492 coreconfigitem(
1495 coreconfigitem(
1493 b'web', b'maxfiles', default=10,
1496 b'web', b'maxfiles', default=10,
1494 )
1497 )
1495 coreconfigitem(
1498 coreconfigitem(
1496 b'web', b'maxshortchanges', default=60,
1499 b'web', b'maxshortchanges', default=60,
1497 )
1500 )
1498 coreconfigitem(
1501 coreconfigitem(
1499 b'web', b'motd', default=b'',
1502 b'web', b'motd', default=b'',
1500 )
1503 )
1501 coreconfigitem(
1504 coreconfigitem(
1502 b'web', b'name', default=dynamicdefault,
1505 b'web', b'name', default=dynamicdefault,
1503 )
1506 )
1504 coreconfigitem(
1507 coreconfigitem(
1505 b'web', b'port', default=8000,
1508 b'web', b'port', default=8000,
1506 )
1509 )
1507 coreconfigitem(
1510 coreconfigitem(
1508 b'web', b'prefix', default=b'',
1511 b'web', b'prefix', default=b'',
1509 )
1512 )
1510 coreconfigitem(
1513 coreconfigitem(
1511 b'web', b'push_ssl', default=True,
1514 b'web', b'push_ssl', default=True,
1512 )
1515 )
1513 coreconfigitem(
1516 coreconfigitem(
1514 b'web', b'refreshinterval', default=20,
1517 b'web', b'refreshinterval', default=20,
1515 )
1518 )
1516 coreconfigitem(
1519 coreconfigitem(
1517 b'web', b'server-header', default=None,
1520 b'web', b'server-header', default=None,
1518 )
1521 )
1519 coreconfigitem(
1522 coreconfigitem(
1520 b'web', b'static', default=None,
1523 b'web', b'static', default=None,
1521 )
1524 )
1522 coreconfigitem(
1525 coreconfigitem(
1523 b'web', b'staticurl', default=None,
1526 b'web', b'staticurl', default=None,
1524 )
1527 )
1525 coreconfigitem(
1528 coreconfigitem(
1526 b'web', b'stripes', default=1,
1529 b'web', b'stripes', default=1,
1527 )
1530 )
1528 coreconfigitem(
1531 coreconfigitem(
1529 b'web', b'style', default=b'paper',
1532 b'web', b'style', default=b'paper',
1530 )
1533 )
1531 coreconfigitem(
1534 coreconfigitem(
1532 b'web', b'templates', default=None,
1535 b'web', b'templates', default=None,
1533 )
1536 )
1534 coreconfigitem(
1537 coreconfigitem(
1535 b'web', b'view', default=b'served', experimental=True,
1538 b'web', b'view', default=b'served', experimental=True,
1536 )
1539 )
1537 coreconfigitem(
1540 coreconfigitem(
1538 b'worker', b'backgroundclose', default=dynamicdefault,
1541 b'worker', b'backgroundclose', default=dynamicdefault,
1539 )
1542 )
1540 # Windows defaults to a limit of 512 open files. A buffer of 128
1543 # Windows defaults to a limit of 512 open files. A buffer of 128
1541 # should give us enough headway.
1544 # should give us enough headway.
1542 coreconfigitem(
1545 coreconfigitem(
1543 b'worker', b'backgroundclosemaxqueue', default=384,
1546 b'worker', b'backgroundclosemaxqueue', default=384,
1544 )
1547 )
1545 coreconfigitem(
1548 coreconfigitem(
1546 b'worker', b'backgroundcloseminfilecount', default=2048,
1549 b'worker', b'backgroundcloseminfilecount', default=2048,
1547 )
1550 )
1548 coreconfigitem(
1551 coreconfigitem(
1549 b'worker', b'backgroundclosethreadcount', default=4,
1552 b'worker', b'backgroundclosethreadcount', default=4,
1550 )
1553 )
1551 coreconfigitem(
1554 coreconfigitem(
1552 b'worker', b'enabled', default=True,
1555 b'worker', b'enabled', default=True,
1553 )
1556 )
1554 coreconfigitem(
1557 coreconfigitem(
1555 b'worker', b'numcpus', default=None,
1558 b'worker', b'numcpus', default=None,
1556 )
1559 )
1557
1560
1558 # Rebase related configuration moved to core because other extension are doing
1561 # Rebase related configuration moved to core because other extension are doing
1559 # strange things. For example, shelve import the extensions to reuse some bit
1562 # strange things. For example, shelve import the extensions to reuse some bit
1560 # without formally loading it.
1563 # without formally loading it.
1561 coreconfigitem(
1564 coreconfigitem(
1562 b'commands', b'rebase.requiredest', default=False,
1565 b'commands', b'rebase.requiredest', default=False,
1563 )
1566 )
1564 coreconfigitem(
1567 coreconfigitem(
1565 b'experimental', b'rebaseskipobsolete', default=True,
1568 b'experimental', b'rebaseskipobsolete', default=True,
1566 )
1569 )
1567 coreconfigitem(
1570 coreconfigitem(
1568 b'rebase', b'singletransaction', default=False,
1571 b'rebase', b'singletransaction', default=False,
1569 )
1572 )
1570 coreconfigitem(
1573 coreconfigitem(
1571 b'rebase', b'experimental.inmemory', default=False,
1574 b'rebase', b'experimental.inmemory', default=False,
1572 )
1575 )
@@ -1,2335 +1,2351 b''
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 datetime
12 import errno
13 import errno
13 import getpass
14 import getpass
14 import inspect
15 import inspect
15 import os
16 import os
16 import re
17 import re
17 import signal
18 import signal
18 import socket
19 import socket
19 import subprocess
20 import subprocess
20 import sys
21 import sys
21 import traceback
22 import traceback
22
23
23 from .i18n import _
24 from .i18n import _
24 from .node import hex
25 from .node import hex
25 from .pycompat import (
26 from .pycompat import (
26 getattr,
27 getattr,
27 open,
28 open,
28 setattr,
29 setattr,
29 )
30 )
30
31
31 from . import (
32 from . import (
32 color,
33 color,
33 config,
34 config,
34 configitems,
35 configitems,
35 encoding,
36 encoding,
36 error,
37 error,
37 formatter,
38 formatter,
38 loggingutil,
39 loggingutil,
39 progress,
40 progress,
40 pycompat,
41 pycompat,
41 rcutil,
42 rcutil,
42 scmutil,
43 scmutil,
43 util,
44 util,
44 )
45 )
45 from .utils import (
46 from .utils import (
46 dateutil,
47 dateutil,
47 procutil,
48 procutil,
48 resourceutil,
49 resourceutil,
49 stringutil,
50 stringutil,
50 )
51 )
51
52
52 urlreq = util.urlreq
53 urlreq = util.urlreq
53
54
54 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
55 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
55 _keepalnum = b''.join(
56 _keepalnum = b''.join(
56 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum()
57 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum()
57 )
58 )
58
59
59 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
60 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
60 tweakrc = b"""
61 tweakrc = b"""
61 [ui]
62 [ui]
62 # The rollback command is dangerous. As a rule, don't use it.
63 # The rollback command is dangerous. As a rule, don't use it.
63 rollback = False
64 rollback = False
64 # Make `hg status` report copy information
65 # Make `hg status` report copy information
65 statuscopies = yes
66 statuscopies = yes
66 # Prefer curses UIs when available. Revert to plain-text with `text`.
67 # Prefer curses UIs when available. Revert to plain-text with `text`.
67 interface = curses
68 interface = curses
68 # Make compatible commands emit cwd-relative paths by default.
69 # Make compatible commands emit cwd-relative paths by default.
69 relative-paths = yes
70 relative-paths = yes
70
71
71 [commands]
72 [commands]
72 # Grep working directory by default.
73 # Grep working directory by default.
73 grep.all-files = True
74 grep.all-files = True
74 # Refuse to perform an `hg update` that would cause a file content merge
75 # Refuse to perform an `hg update` that would cause a file content merge
75 update.check = noconflict
76 update.check = noconflict
76 # Show conflicts information in `hg status`
77 # Show conflicts information in `hg status`
77 status.verbose = True
78 status.verbose = True
78 # Make `hg resolve` with no action (like `-m`) fail instead of re-merging.
79 # Make `hg resolve` with no action (like `-m`) fail instead of re-merging.
79 resolve.explicit-re-merge = True
80 resolve.explicit-re-merge = True
80
81
81 [diff]
82 [diff]
82 git = 1
83 git = 1
83 showfunc = 1
84 showfunc = 1
84 word-diff = 1
85 word-diff = 1
85 """
86 """
86
87
87 samplehgrcs = {
88 samplehgrcs = {
88 b'user': b"""# example user config (see 'hg help config' for more info)
89 b'user': b"""# example user config (see 'hg help config' for more info)
89 [ui]
90 [ui]
90 # name and email, e.g.
91 # name and email, e.g.
91 # username = Jane Doe <jdoe@example.com>
92 # username = Jane Doe <jdoe@example.com>
92 username =
93 username =
93
94
94 # We recommend enabling tweakdefaults to get slight improvements to
95 # We recommend enabling tweakdefaults to get slight improvements to
95 # the UI over time. Make sure to set HGPLAIN in the environment when
96 # the UI over time. Make sure to set HGPLAIN in the environment when
96 # writing scripts!
97 # writing scripts!
97 # tweakdefaults = True
98 # tweakdefaults = True
98
99
99 # uncomment to disable color in command output
100 # uncomment to disable color in command output
100 # (see 'hg help color' for details)
101 # (see 'hg help color' for details)
101 # color = never
102 # color = never
102
103
103 # uncomment to disable command output pagination
104 # uncomment to disable command output pagination
104 # (see 'hg help pager' for details)
105 # (see 'hg help pager' for details)
105 # paginate = never
106 # paginate = never
106
107
107 [extensions]
108 [extensions]
108 # uncomment the lines below to enable some popular extensions
109 # uncomment the lines below to enable some popular extensions
109 # (see 'hg help extensions' for more info)
110 # (see 'hg help extensions' for more info)
110 #
111 #
111 # histedit =
112 # histedit =
112 # rebase =
113 # rebase =
113 # uncommit =
114 # uncommit =
114 """,
115 """,
115 b'cloned': b"""# example repository config (see 'hg help config' for more info)
116 b'cloned': b"""# example repository config (see 'hg help config' for more info)
116 [paths]
117 [paths]
117 default = %s
118 default = %s
118
119
119 # path aliases to other clones of this repo in URLs or filesystem paths
120 # path aliases to other clones of this repo in URLs or filesystem paths
120 # (see 'hg help config.paths' for more info)
121 # (see 'hg help config.paths' for more info)
121 #
122 #
122 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
123 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
123 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
124 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
124 # my-clone = /home/jdoe/jdoes-clone
125 # my-clone = /home/jdoe/jdoes-clone
125
126
126 [ui]
127 [ui]
127 # name and email (local to this repository, optional), e.g.
128 # name and email (local to this repository, optional), e.g.
128 # username = Jane Doe <jdoe@example.com>
129 # username = Jane Doe <jdoe@example.com>
129 """,
130 """,
130 b'local': b"""# example repository config (see 'hg help config' for more info)
131 b'local': b"""# example repository config (see 'hg help config' for more info)
131 [paths]
132 [paths]
132 # path aliases to other clones of this repo in URLs or filesystem paths
133 # path aliases to other clones of this repo in URLs or filesystem paths
133 # (see 'hg help config.paths' for more info)
134 # (see 'hg help config.paths' for more info)
134 #
135 #
135 # default = http://example.com/hg/example-repo
136 # default = http://example.com/hg/example-repo
136 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
137 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
137 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
138 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
138 # my-clone = /home/jdoe/jdoes-clone
139 # my-clone = /home/jdoe/jdoes-clone
139
140
140 [ui]
141 [ui]
141 # name and email (local to this repository, optional), e.g.
142 # name and email (local to this repository, optional), e.g.
142 # username = Jane Doe <jdoe@example.com>
143 # username = Jane Doe <jdoe@example.com>
143 """,
144 """,
144 b'global': b"""# example system-wide hg config (see 'hg help config' for more info)
145 b'global': b"""# example system-wide hg config (see 'hg help config' for more info)
145
146
146 [ui]
147 [ui]
147 # uncomment to disable color in command output
148 # uncomment to disable color in command output
148 # (see 'hg help color' for details)
149 # (see 'hg help color' for details)
149 # color = never
150 # color = never
150
151
151 # uncomment to disable command output pagination
152 # uncomment to disable command output pagination
152 # (see 'hg help pager' for details)
153 # (see 'hg help pager' for details)
153 # paginate = never
154 # paginate = never
154
155
155 [extensions]
156 [extensions]
156 # uncomment the lines below to enable some popular extensions
157 # uncomment the lines below to enable some popular extensions
157 # (see 'hg help extensions' for more info)
158 # (see 'hg help extensions' for more info)
158 #
159 #
159 # blackbox =
160 # blackbox =
160 # churn =
161 # churn =
161 """,
162 """,
162 }
163 }
163
164
164
165
165 def _maybestrurl(maybebytes):
166 def _maybestrurl(maybebytes):
166 return pycompat.rapply(pycompat.strurl, maybebytes)
167 return pycompat.rapply(pycompat.strurl, maybebytes)
167
168
168
169
169 def _maybebytesurl(maybestr):
170 def _maybebytesurl(maybestr):
170 return pycompat.rapply(pycompat.bytesurl, maybestr)
171 return pycompat.rapply(pycompat.bytesurl, maybestr)
171
172
172
173
173 class httppasswordmgrdbproxy(object):
174 class httppasswordmgrdbproxy(object):
174 """Delays loading urllib2 until it's needed."""
175 """Delays loading urllib2 until it's needed."""
175
176
176 def __init__(self):
177 def __init__(self):
177 self._mgr = None
178 self._mgr = None
178
179
179 def _get_mgr(self):
180 def _get_mgr(self):
180 if self._mgr is None:
181 if self._mgr is None:
181 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
182 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
182 return self._mgr
183 return self._mgr
183
184
184 def add_password(self, realm, uris, user, passwd):
185 def add_password(self, realm, uris, user, passwd):
185 return self._get_mgr().add_password(
186 return self._get_mgr().add_password(
186 _maybestrurl(realm),
187 _maybestrurl(realm),
187 _maybestrurl(uris),
188 _maybestrurl(uris),
188 _maybestrurl(user),
189 _maybestrurl(user),
189 _maybestrurl(passwd),
190 _maybestrurl(passwd),
190 )
191 )
191
192
192 def find_user_password(self, realm, uri):
193 def find_user_password(self, realm, uri):
193 mgr = self._get_mgr()
194 mgr = self._get_mgr()
194 return _maybebytesurl(
195 return _maybebytesurl(
195 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri))
196 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri))
196 )
197 )
197
198
198
199
199 def _catchterm(*args):
200 def _catchterm(*args):
200 raise error.SignalInterrupt
201 raise error.SignalInterrupt
201
202
202
203
203 # unique object used to detect no default value has been provided when
204 # unique object used to detect no default value has been provided when
204 # retrieving configuration value.
205 # retrieving configuration value.
205 _unset = object()
206 _unset = object()
206
207
207 # _reqexithandlers: callbacks run at the end of a request
208 # _reqexithandlers: callbacks run at the end of a request
208 _reqexithandlers = []
209 _reqexithandlers = []
209
210
210
211
211 class ui(object):
212 class ui(object):
212 def __init__(self, src=None):
213 def __init__(self, src=None):
213 """Create a fresh new ui object if no src given
214 """Create a fresh new ui object if no src given
214
215
215 Use uimod.ui.load() to create a ui which knows global and user configs.
216 Use uimod.ui.load() to create a ui which knows global and user configs.
216 In most cases, you should use ui.copy() to create a copy of an existing
217 In most cases, you should use ui.copy() to create a copy of an existing
217 ui object.
218 ui object.
218 """
219 """
219 # _buffers: used for temporary capture of output
220 # _buffers: used for temporary capture of output
220 self._buffers = []
221 self._buffers = []
221 # 3-tuple describing how each buffer in the stack behaves.
222 # 3-tuple describing how each buffer in the stack behaves.
222 # Values are (capture stderr, capture subprocesses, apply labels).
223 # Values are (capture stderr, capture subprocesses, apply labels).
223 self._bufferstates = []
224 self._bufferstates = []
224 # When a buffer is active, defines whether we are expanding labels.
225 # When a buffer is active, defines whether we are expanding labels.
225 # This exists to prevent an extra list lookup.
226 # This exists to prevent an extra list lookup.
226 self._bufferapplylabels = None
227 self._bufferapplylabels = None
227 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
228 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
228 self._reportuntrusted = True
229 self._reportuntrusted = True
229 self._knownconfig = configitems.coreitems
230 self._knownconfig = configitems.coreitems
230 self._ocfg = config.config() # overlay
231 self._ocfg = config.config() # overlay
231 self._tcfg = config.config() # trusted
232 self._tcfg = config.config() # trusted
232 self._ucfg = config.config() # untrusted
233 self._ucfg = config.config() # untrusted
233 self._trustusers = set()
234 self._trustusers = set()
234 self._trustgroups = set()
235 self._trustgroups = set()
235 self.callhooks = True
236 self.callhooks = True
236 # Insecure server connections requested.
237 # Insecure server connections requested.
237 self.insecureconnections = False
238 self.insecureconnections = False
238 # Blocked time
239 # Blocked time
239 self.logblockedtimes = False
240 self.logblockedtimes = False
240 # color mode: see mercurial/color.py for possible value
241 # color mode: see mercurial/color.py for possible value
241 self._colormode = None
242 self._colormode = None
242 self._terminfoparams = {}
243 self._terminfoparams = {}
243 self._styles = {}
244 self._styles = {}
244 self._uninterruptible = False
245 self._uninterruptible = False
246 self.showtimestamp = False
245
247
246 if src:
248 if src:
247 self._fout = src._fout
249 self._fout = src._fout
248 self._ferr = src._ferr
250 self._ferr = src._ferr
249 self._fin = src._fin
251 self._fin = src._fin
250 self._fmsg = src._fmsg
252 self._fmsg = src._fmsg
251 self._fmsgout = src._fmsgout
253 self._fmsgout = src._fmsgout
252 self._fmsgerr = src._fmsgerr
254 self._fmsgerr = src._fmsgerr
253 self._finoutredirected = src._finoutredirected
255 self._finoutredirected = src._finoutredirected
254 self._loggers = src._loggers.copy()
256 self._loggers = src._loggers.copy()
255 self.pageractive = src.pageractive
257 self.pageractive = src.pageractive
256 self._disablepager = src._disablepager
258 self._disablepager = src._disablepager
257 self._tweaked = src._tweaked
259 self._tweaked = src._tweaked
258
260
259 self._tcfg = src._tcfg.copy()
261 self._tcfg = src._tcfg.copy()
260 self._ucfg = src._ucfg.copy()
262 self._ucfg = src._ucfg.copy()
261 self._ocfg = src._ocfg.copy()
263 self._ocfg = src._ocfg.copy()
262 self._trustusers = src._trustusers.copy()
264 self._trustusers = src._trustusers.copy()
263 self._trustgroups = src._trustgroups.copy()
265 self._trustgroups = src._trustgroups.copy()
264 self.environ = src.environ
266 self.environ = src.environ
265 self.callhooks = src.callhooks
267 self.callhooks = src.callhooks
266 self.insecureconnections = src.insecureconnections
268 self.insecureconnections = src.insecureconnections
267 self._colormode = src._colormode
269 self._colormode = src._colormode
268 self._terminfoparams = src._terminfoparams.copy()
270 self._terminfoparams = src._terminfoparams.copy()
269 self._styles = src._styles.copy()
271 self._styles = src._styles.copy()
270
272
271 self.fixconfig()
273 self.fixconfig()
272
274
273 self.httppasswordmgrdb = src.httppasswordmgrdb
275 self.httppasswordmgrdb = src.httppasswordmgrdb
274 self._blockedtimes = src._blockedtimes
276 self._blockedtimes = src._blockedtimes
275 else:
277 else:
276 self._fout = procutil.stdout
278 self._fout = procutil.stdout
277 self._ferr = procutil.stderr
279 self._ferr = procutil.stderr
278 self._fin = procutil.stdin
280 self._fin = procutil.stdin
279 self._fmsg = None
281 self._fmsg = None
280 self._fmsgout = self.fout # configurable
282 self._fmsgout = self.fout # configurable
281 self._fmsgerr = self.ferr # configurable
283 self._fmsgerr = self.ferr # configurable
282 self._finoutredirected = False
284 self._finoutredirected = False
283 self._loggers = {}
285 self._loggers = {}
284 self.pageractive = False
286 self.pageractive = False
285 self._disablepager = False
287 self._disablepager = False
286 self._tweaked = False
288 self._tweaked = False
287
289
288 # shared read-only environment
290 # shared read-only environment
289 self.environ = encoding.environ
291 self.environ = encoding.environ
290
292
291 self.httppasswordmgrdb = httppasswordmgrdbproxy()
293 self.httppasswordmgrdb = httppasswordmgrdbproxy()
292 self._blockedtimes = collections.defaultdict(int)
294 self._blockedtimes = collections.defaultdict(int)
293
295
294 allowed = self.configlist(b'experimental', b'exportableenviron')
296 allowed = self.configlist(b'experimental', b'exportableenviron')
295 if b'*' in allowed:
297 if b'*' in allowed:
296 self._exportableenviron = self.environ
298 self._exportableenviron = self.environ
297 else:
299 else:
298 self._exportableenviron = {}
300 self._exportableenviron = {}
299 for k in allowed:
301 for k in allowed:
300 if k in self.environ:
302 if k in self.environ:
301 self._exportableenviron[k] = self.environ[k]
303 self._exportableenviron[k] = self.environ[k]
302
304
303 @classmethod
305 @classmethod
304 def load(cls):
306 def load(cls):
305 """Create a ui and load global and user configs"""
307 """Create a ui and load global and user configs"""
306 u = cls()
308 u = cls()
307 # we always trust global config files and environment variables
309 # we always trust global config files and environment variables
308 for t, f in rcutil.rccomponents():
310 for t, f in rcutil.rccomponents():
309 if t == b'path':
311 if t == b'path':
310 u.readconfig(f, trust=True)
312 u.readconfig(f, trust=True)
311 elif t == b'resource':
313 elif t == b'resource':
312 u.read_resource_config(f, trust=True)
314 u.read_resource_config(f, trust=True)
313 elif t == b'items':
315 elif t == b'items':
314 sections = set()
316 sections = set()
315 for section, name, value, source in f:
317 for section, name, value, source in f:
316 # do not set u._ocfg
318 # do not set u._ocfg
317 # XXX clean this up once immutable config object is a thing
319 # XXX clean this up once immutable config object is a thing
318 u._tcfg.set(section, name, value, source)
320 u._tcfg.set(section, name, value, source)
319 u._ucfg.set(section, name, value, source)
321 u._ucfg.set(section, name, value, source)
320 sections.add(section)
322 sections.add(section)
321 for section in sections:
323 for section in sections:
322 u.fixconfig(section=section)
324 u.fixconfig(section=section)
323 else:
325 else:
324 raise error.ProgrammingError(b'unknown rctype: %s' % t)
326 raise error.ProgrammingError(b'unknown rctype: %s' % t)
325 u._maybetweakdefaults()
327 u._maybetweakdefaults()
326 return u
328 return u
327
329
328 def _maybetweakdefaults(self):
330 def _maybetweakdefaults(self):
329 if not self.configbool(b'ui', b'tweakdefaults'):
331 if not self.configbool(b'ui', b'tweakdefaults'):
330 return
332 return
331 if self._tweaked or self.plain(b'tweakdefaults'):
333 if self._tweaked or self.plain(b'tweakdefaults'):
332 return
334 return
333
335
334 # Note: it is SUPER IMPORTANT that you set self._tweaked to
336 # Note: it is SUPER IMPORTANT that you set self._tweaked to
335 # True *before* any calls to setconfig(), otherwise you'll get
337 # True *before* any calls to setconfig(), otherwise you'll get
336 # infinite recursion between setconfig and this method.
338 # infinite recursion between setconfig and this method.
337 #
339 #
338 # TODO: We should extract an inner method in setconfig() to
340 # TODO: We should extract an inner method in setconfig() to
339 # avoid this weirdness.
341 # avoid this weirdness.
340 self._tweaked = True
342 self._tweaked = True
341 tmpcfg = config.config()
343 tmpcfg = config.config()
342 tmpcfg.parse(b'<tweakdefaults>', tweakrc)
344 tmpcfg.parse(b'<tweakdefaults>', tweakrc)
343 for section in tmpcfg:
345 for section in tmpcfg:
344 for name, value in tmpcfg.items(section):
346 for name, value in tmpcfg.items(section):
345 if not self.hasconfig(section, name):
347 if not self.hasconfig(section, name):
346 self.setconfig(section, name, value, b"<tweakdefaults>")
348 self.setconfig(section, name, value, b"<tweakdefaults>")
347
349
348 def copy(self):
350 def copy(self):
349 return self.__class__(self)
351 return self.__class__(self)
350
352
351 def resetstate(self):
353 def resetstate(self):
352 """Clear internal state that shouldn't persist across commands"""
354 """Clear internal state that shouldn't persist across commands"""
353 if self._progbar:
355 if self._progbar:
354 self._progbar.resetstate() # reset last-print time of progress bar
356 self._progbar.resetstate() # reset last-print time of progress bar
355 self.httppasswordmgrdb = httppasswordmgrdbproxy()
357 self.httppasswordmgrdb = httppasswordmgrdbproxy()
356
358
357 @contextlib.contextmanager
359 @contextlib.contextmanager
358 def timeblockedsection(self, key):
360 def timeblockedsection(self, key):
359 # this is open-coded below - search for timeblockedsection to find them
361 # this is open-coded below - search for timeblockedsection to find them
360 starttime = util.timer()
362 starttime = util.timer()
361 try:
363 try:
362 yield
364 yield
363 finally:
365 finally:
364 self._blockedtimes[key + b'_blocked'] += (
366 self._blockedtimes[key + b'_blocked'] += (
365 util.timer() - starttime
367 util.timer() - starttime
366 ) * 1000
368 ) * 1000
367
369
368 @contextlib.contextmanager
370 @contextlib.contextmanager
369 def uninterruptible(self):
371 def uninterruptible(self):
370 """Mark an operation as unsafe.
372 """Mark an operation as unsafe.
371
373
372 Most operations on a repository are safe to interrupt, but a
374 Most operations on a repository are safe to interrupt, but a
373 few are risky (for example repair.strip). This context manager
375 few are risky (for example repair.strip). This context manager
374 lets you advise Mercurial that something risky is happening so
376 lets you advise Mercurial that something risky is happening so
375 that control-C etc can be blocked if desired.
377 that control-C etc can be blocked if desired.
376 """
378 """
377 enabled = self.configbool(b'experimental', b'nointerrupt')
379 enabled = self.configbool(b'experimental', b'nointerrupt')
378 if enabled and self.configbool(
380 if enabled and self.configbool(
379 b'experimental', b'nointerrupt-interactiveonly'
381 b'experimental', b'nointerrupt-interactiveonly'
380 ):
382 ):
381 enabled = self.interactive()
383 enabled = self.interactive()
382 if self._uninterruptible or not enabled:
384 if self._uninterruptible or not enabled:
383 # if nointerrupt support is turned off, the process isn't
385 # if nointerrupt support is turned off, the process isn't
384 # interactive, or we're already in an uninterruptible
386 # interactive, or we're already in an uninterruptible
385 # block, do nothing.
387 # block, do nothing.
386 yield
388 yield
387 return
389 return
388
390
389 def warn():
391 def warn():
390 self.warn(_(b"shutting down cleanly\n"))
392 self.warn(_(b"shutting down cleanly\n"))
391 self.warn(
393 self.warn(
392 _(b"press ^C again to terminate immediately (dangerous)\n")
394 _(b"press ^C again to terminate immediately (dangerous)\n")
393 )
395 )
394 return True
396 return True
395
397
396 with procutil.uninterruptible(warn):
398 with procutil.uninterruptible(warn):
397 try:
399 try:
398 self._uninterruptible = True
400 self._uninterruptible = True
399 yield
401 yield
400 finally:
402 finally:
401 self._uninterruptible = False
403 self._uninterruptible = False
402
404
403 def formatter(self, topic, opts):
405 def formatter(self, topic, opts):
404 return formatter.formatter(self, self, topic, opts)
406 return formatter.formatter(self, self, topic, opts)
405
407
406 def _trusted(self, fp, f):
408 def _trusted(self, fp, f):
407 st = util.fstat(fp)
409 st = util.fstat(fp)
408 if util.isowner(st):
410 if util.isowner(st):
409 return True
411 return True
410
412
411 tusers, tgroups = self._trustusers, self._trustgroups
413 tusers, tgroups = self._trustusers, self._trustgroups
412 if b'*' in tusers or b'*' in tgroups:
414 if b'*' in tusers or b'*' in tgroups:
413 return True
415 return True
414
416
415 user = util.username(st.st_uid)
417 user = util.username(st.st_uid)
416 group = util.groupname(st.st_gid)
418 group = util.groupname(st.st_gid)
417 if user in tusers or group in tgroups or user == util.username():
419 if user in tusers or group in tgroups or user == util.username():
418 return True
420 return True
419
421
420 if self._reportuntrusted:
422 if self._reportuntrusted:
421 self.warn(
423 self.warn(
422 _(
424 _(
423 b'not trusting file %s from untrusted '
425 b'not trusting file %s from untrusted '
424 b'user %s, group %s\n'
426 b'user %s, group %s\n'
425 )
427 )
426 % (f, user, group)
428 % (f, user, group)
427 )
429 )
428 return False
430 return False
429
431
430 def read_resource_config(
432 def read_resource_config(
431 self, name, root=None, trust=False, sections=None, remap=None
433 self, name, root=None, trust=False, sections=None, remap=None
432 ):
434 ):
433 try:
435 try:
434 fp = resourceutil.open_resource(name[0], name[1])
436 fp = resourceutil.open_resource(name[0], name[1])
435 except IOError:
437 except IOError:
436 if not sections: # ignore unless we were looking for something
438 if not sections: # ignore unless we were looking for something
437 return
439 return
438 raise
440 raise
439
441
440 self._readconfig(
442 self._readconfig(
441 b'resource:%s.%s' % name, fp, root, trust, sections, remap
443 b'resource:%s.%s' % name, fp, root, trust, sections, remap
442 )
444 )
443
445
444 def readconfig(
446 def readconfig(
445 self, filename, root=None, trust=False, sections=None, remap=None
447 self, filename, root=None, trust=False, sections=None, remap=None
446 ):
448 ):
447 try:
449 try:
448 fp = open(filename, 'rb')
450 fp = open(filename, 'rb')
449 except IOError:
451 except IOError:
450 if not sections: # ignore unless we were looking for something
452 if not sections: # ignore unless we were looking for something
451 return
453 return
452 raise
454 raise
453
455
454 self._readconfig(filename, fp, root, trust, sections, remap)
456 self._readconfig(filename, fp, root, trust, sections, remap)
455
457
456 def _readconfig(
458 def _readconfig(
457 self, filename, fp, root=None, trust=False, sections=None, remap=None
459 self, filename, fp, root=None, trust=False, sections=None, remap=None
458 ):
460 ):
459 with fp:
461 with fp:
460 cfg = config.config()
462 cfg = config.config()
461 trusted = sections or trust or self._trusted(fp, filename)
463 trusted = sections or trust or self._trusted(fp, filename)
462
464
463 try:
465 try:
464 cfg.read(filename, fp, sections=sections, remap=remap)
466 cfg.read(filename, fp, sections=sections, remap=remap)
465 except error.ParseError as inst:
467 except error.ParseError as inst:
466 if trusted:
468 if trusted:
467 raise
469 raise
468 self.warn(_(b'ignored: %s\n') % stringutil.forcebytestr(inst))
470 self.warn(_(b'ignored: %s\n') % stringutil.forcebytestr(inst))
469
471
470 self._applyconfig(cfg, trusted, root)
472 self._applyconfig(cfg, trusted, root)
471
473
472 def applyconfig(self, configitems, source=b"", root=None):
474 def applyconfig(self, configitems, source=b"", root=None):
473 """Add configitems from a non-file source. Unlike with ``setconfig()``,
475 """Add configitems from a non-file source. Unlike with ``setconfig()``,
474 they can be overridden by subsequent config file reads. The items are
476 they can be overridden by subsequent config file reads. The items are
475 in the same format as ``configoverride()``, namely a dict of the
477 in the same format as ``configoverride()``, namely a dict of the
476 following structures: {(section, name) : value}
478 following structures: {(section, name) : value}
477
479
478 Typically this is used by extensions that inject themselves into the
480 Typically this is used by extensions that inject themselves into the
479 config file load procedure by monkeypatching ``localrepo.loadhgrc()``.
481 config file load procedure by monkeypatching ``localrepo.loadhgrc()``.
480 """
482 """
481 cfg = config.config()
483 cfg = config.config()
482
484
483 for (section, name), value in configitems.items():
485 for (section, name), value in configitems.items():
484 cfg.set(section, name, value, source)
486 cfg.set(section, name, value, source)
485
487
486 self._applyconfig(cfg, True, root)
488 self._applyconfig(cfg, True, root)
487
489
488 def _applyconfig(self, cfg, trusted, root):
490 def _applyconfig(self, cfg, trusted, root):
489 if self.plain():
491 if self.plain():
490 for k in (
492 for k in (
491 b'debug',
493 b'debug',
492 b'fallbackencoding',
494 b'fallbackencoding',
493 b'quiet',
495 b'quiet',
494 b'slash',
496 b'slash',
495 b'logtemplate',
497 b'logtemplate',
496 b'message-output',
498 b'message-output',
497 b'statuscopies',
499 b'statuscopies',
498 b'style',
500 b'style',
499 b'traceback',
501 b'traceback',
500 b'verbose',
502 b'verbose',
501 ):
503 ):
502 if k in cfg[b'ui']:
504 if k in cfg[b'ui']:
503 del cfg[b'ui'][k]
505 del cfg[b'ui'][k]
504 for k, v in cfg.items(b'defaults'):
506 for k, v in cfg.items(b'defaults'):
505 del cfg[b'defaults'][k]
507 del cfg[b'defaults'][k]
506 for k, v in cfg.items(b'commands'):
508 for k, v in cfg.items(b'commands'):
507 del cfg[b'commands'][k]
509 del cfg[b'commands'][k]
508 # Don't remove aliases from the configuration if in the exceptionlist
510 # Don't remove aliases from the configuration if in the exceptionlist
509 if self.plain(b'alias'):
511 if self.plain(b'alias'):
510 for k, v in cfg.items(b'alias'):
512 for k, v in cfg.items(b'alias'):
511 del cfg[b'alias'][k]
513 del cfg[b'alias'][k]
512 if self.plain(b'revsetalias'):
514 if self.plain(b'revsetalias'):
513 for k, v in cfg.items(b'revsetalias'):
515 for k, v in cfg.items(b'revsetalias'):
514 del cfg[b'revsetalias'][k]
516 del cfg[b'revsetalias'][k]
515 if self.plain(b'templatealias'):
517 if self.plain(b'templatealias'):
516 for k, v in cfg.items(b'templatealias'):
518 for k, v in cfg.items(b'templatealias'):
517 del cfg[b'templatealias'][k]
519 del cfg[b'templatealias'][k]
518
520
519 if trusted:
521 if trusted:
520 self._tcfg.update(cfg)
522 self._tcfg.update(cfg)
521 self._tcfg.update(self._ocfg)
523 self._tcfg.update(self._ocfg)
522 self._ucfg.update(cfg)
524 self._ucfg.update(cfg)
523 self._ucfg.update(self._ocfg)
525 self._ucfg.update(self._ocfg)
524
526
525 if root is None:
527 if root is None:
526 root = os.path.expanduser(b'~')
528 root = os.path.expanduser(b'~')
527 self.fixconfig(root=root)
529 self.fixconfig(root=root)
528
530
529 def fixconfig(self, root=None, section=None):
531 def fixconfig(self, root=None, section=None):
530 if section in (None, b'paths'):
532 if section in (None, b'paths'):
531 # expand vars and ~
533 # expand vars and ~
532 # translate paths relative to root (or home) into absolute paths
534 # translate paths relative to root (or home) into absolute paths
533 root = root or encoding.getcwd()
535 root = root or encoding.getcwd()
534 for c in self._tcfg, self._ucfg, self._ocfg:
536 for c in self._tcfg, self._ucfg, self._ocfg:
535 for n, p in c.items(b'paths'):
537 for n, p in c.items(b'paths'):
536 # Ignore sub-options.
538 # Ignore sub-options.
537 if b':' in n:
539 if b':' in n:
538 continue
540 continue
539 if not p:
541 if not p:
540 continue
542 continue
541 if b'%%' in p:
543 if b'%%' in p:
542 s = self.configsource(b'paths', n) or b'none'
544 s = self.configsource(b'paths', n) or b'none'
543 self.warn(
545 self.warn(
544 _(b"(deprecated '%%' in path %s=%s from %s)\n")
546 _(b"(deprecated '%%' in path %s=%s from %s)\n")
545 % (n, p, s)
547 % (n, p, s)
546 )
548 )
547 p = p.replace(b'%%', b'%')
549 p = p.replace(b'%%', b'%')
548 p = util.expandpath(p)
550 p = util.expandpath(p)
549 if not util.hasscheme(p) and not os.path.isabs(p):
551 if not util.hasscheme(p) and not os.path.isabs(p):
550 p = os.path.normpath(os.path.join(root, p))
552 p = os.path.normpath(os.path.join(root, p))
551 c.set(b"paths", n, p)
553 c.set(b"paths", n, p)
552
554
553 if section in (None, b'ui'):
555 if section in (None, b'ui'):
554 # update ui options
556 # update ui options
555 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
557 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
556 self.debugflag = self.configbool(b'ui', b'debug')
558 self.debugflag = self.configbool(b'ui', b'debug')
557 self.verbose = self.debugflag or self.configbool(b'ui', b'verbose')
559 self.verbose = self.debugflag or self.configbool(b'ui', b'verbose')
558 self.quiet = not self.debugflag and self.configbool(b'ui', b'quiet')
560 self.quiet = not self.debugflag and self.configbool(b'ui', b'quiet')
559 if self.verbose and self.quiet:
561 if self.verbose and self.quiet:
560 self.quiet = self.verbose = False
562 self.quiet = self.verbose = False
561 self._reportuntrusted = self.debugflag or self.configbool(
563 self._reportuntrusted = self.debugflag or self.configbool(
562 b"ui", b"report_untrusted"
564 b"ui", b"report_untrusted"
563 )
565 )
566 self.showtimestamp = self.configbool(b'ui', b'timestamp-output')
564 self.tracebackflag = self.configbool(b'ui', b'traceback')
567 self.tracebackflag = self.configbool(b'ui', b'traceback')
565 self.logblockedtimes = self.configbool(b'ui', b'logblockedtimes')
568 self.logblockedtimes = self.configbool(b'ui', b'logblockedtimes')
566
569
567 if section in (None, b'trusted'):
570 if section in (None, b'trusted'):
568 # update trust information
571 # update trust information
569 self._trustusers.update(self.configlist(b'trusted', b'users'))
572 self._trustusers.update(self.configlist(b'trusted', b'users'))
570 self._trustgroups.update(self.configlist(b'trusted', b'groups'))
573 self._trustgroups.update(self.configlist(b'trusted', b'groups'))
571
574
572 if section in (None, b'devel', b'ui') and self.debugflag:
575 if section in (None, b'devel', b'ui') and self.debugflag:
573 tracked = set()
576 tracked = set()
574 if self.configbool(b'devel', b'debug.extensions'):
577 if self.configbool(b'devel', b'debug.extensions'):
575 tracked.add(b'extension')
578 tracked.add(b'extension')
576 if tracked:
579 if tracked:
577 logger = loggingutil.fileobjectlogger(self._ferr, tracked)
580 logger = loggingutil.fileobjectlogger(self._ferr, tracked)
578 self.setlogger(b'debug', logger)
581 self.setlogger(b'debug', logger)
579
582
580 def backupconfig(self, section, item):
583 def backupconfig(self, section, item):
581 return (
584 return (
582 self._ocfg.backup(section, item),
585 self._ocfg.backup(section, item),
583 self._tcfg.backup(section, item),
586 self._tcfg.backup(section, item),
584 self._ucfg.backup(section, item),
587 self._ucfg.backup(section, item),
585 )
588 )
586
589
587 def restoreconfig(self, data):
590 def restoreconfig(self, data):
588 self._ocfg.restore(data[0])
591 self._ocfg.restore(data[0])
589 self._tcfg.restore(data[1])
592 self._tcfg.restore(data[1])
590 self._ucfg.restore(data[2])
593 self._ucfg.restore(data[2])
591
594
592 def setconfig(self, section, name, value, source=b''):
595 def setconfig(self, section, name, value, source=b''):
593 for cfg in (self._ocfg, self._tcfg, self._ucfg):
596 for cfg in (self._ocfg, self._tcfg, self._ucfg):
594 cfg.set(section, name, value, source)
597 cfg.set(section, name, value, source)
595 self.fixconfig(section=section)
598 self.fixconfig(section=section)
596 self._maybetweakdefaults()
599 self._maybetweakdefaults()
597
600
598 def _data(self, untrusted):
601 def _data(self, untrusted):
599 return untrusted and self._ucfg or self._tcfg
602 return untrusted and self._ucfg or self._tcfg
600
603
601 def configsource(self, section, name, untrusted=False):
604 def configsource(self, section, name, untrusted=False):
602 return self._data(untrusted).source(section, name)
605 return self._data(untrusted).source(section, name)
603
606
604 def config(self, section, name, default=_unset, untrusted=False):
607 def config(self, section, name, default=_unset, untrusted=False):
605 """return the plain string version of a config"""
608 """return the plain string version of a config"""
606 value = self._config(
609 value = self._config(
607 section, name, default=default, untrusted=untrusted
610 section, name, default=default, untrusted=untrusted
608 )
611 )
609 if value is _unset:
612 if value is _unset:
610 return None
613 return None
611 return value
614 return value
612
615
613 def _config(self, section, name, default=_unset, untrusted=False):
616 def _config(self, section, name, default=_unset, untrusted=False):
614 value = itemdefault = default
617 value = itemdefault = default
615 item = self._knownconfig.get(section, {}).get(name)
618 item = self._knownconfig.get(section, {}).get(name)
616 alternates = [(section, name)]
619 alternates = [(section, name)]
617
620
618 if item is not None:
621 if item is not None:
619 alternates.extend(item.alias)
622 alternates.extend(item.alias)
620 if callable(item.default):
623 if callable(item.default):
621 itemdefault = item.default()
624 itemdefault = item.default()
622 else:
625 else:
623 itemdefault = item.default
626 itemdefault = item.default
624 else:
627 else:
625 msg = b"accessing unregistered config item: '%s.%s'"
628 msg = b"accessing unregistered config item: '%s.%s'"
626 msg %= (section, name)
629 msg %= (section, name)
627 self.develwarn(msg, 2, b'warn-config-unknown')
630 self.develwarn(msg, 2, b'warn-config-unknown')
628
631
629 if default is _unset:
632 if default is _unset:
630 if item is None:
633 if item is None:
631 value = default
634 value = default
632 elif item.default is configitems.dynamicdefault:
635 elif item.default is configitems.dynamicdefault:
633 value = None
636 value = None
634 msg = b"config item requires an explicit default value: '%s.%s'"
637 msg = b"config item requires an explicit default value: '%s.%s'"
635 msg %= (section, name)
638 msg %= (section, name)
636 self.develwarn(msg, 2, b'warn-config-default')
639 self.develwarn(msg, 2, b'warn-config-default')
637 else:
640 else:
638 value = itemdefault
641 value = itemdefault
639 elif (
642 elif (
640 item is not None
643 item is not None
641 and item.default is not configitems.dynamicdefault
644 and item.default is not configitems.dynamicdefault
642 and default != itemdefault
645 and default != itemdefault
643 ):
646 ):
644 msg = (
647 msg = (
645 b"specifying a mismatched default value for a registered "
648 b"specifying a mismatched default value for a registered "
646 b"config item: '%s.%s' '%s'"
649 b"config item: '%s.%s' '%s'"
647 )
650 )
648 msg %= (section, name, pycompat.bytestr(default))
651 msg %= (section, name, pycompat.bytestr(default))
649 self.develwarn(msg, 2, b'warn-config-default')
652 self.develwarn(msg, 2, b'warn-config-default')
650
653
651 for s, n in alternates:
654 for s, n in alternates:
652 candidate = self._data(untrusted).get(s, n, None)
655 candidate = self._data(untrusted).get(s, n, None)
653 if candidate is not None:
656 if candidate is not None:
654 value = candidate
657 value = candidate
655 break
658 break
656
659
657 if self.debugflag and not untrusted and self._reportuntrusted:
660 if self.debugflag and not untrusted and self._reportuntrusted:
658 for s, n in alternates:
661 for s, n in alternates:
659 uvalue = self._ucfg.get(s, n)
662 uvalue = self._ucfg.get(s, n)
660 if uvalue is not None and uvalue != value:
663 if uvalue is not None and uvalue != value:
661 self.debug(
664 self.debug(
662 b"ignoring untrusted configuration option "
665 b"ignoring untrusted configuration option "
663 b"%s.%s = %s\n" % (s, n, uvalue)
666 b"%s.%s = %s\n" % (s, n, uvalue)
664 )
667 )
665 return value
668 return value
666
669
667 def configsuboptions(self, section, name, default=_unset, untrusted=False):
670 def configsuboptions(self, section, name, default=_unset, untrusted=False):
668 """Get a config option and all sub-options.
671 """Get a config option and all sub-options.
669
672
670 Some config options have sub-options that are declared with the
673 Some config options have sub-options that are declared with the
671 format "key:opt = value". This method is used to return the main
674 format "key:opt = value". This method is used to return the main
672 option and all its declared sub-options.
675 option and all its declared sub-options.
673
676
674 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
677 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
675 is a dict of defined sub-options where keys and values are strings.
678 is a dict of defined sub-options where keys and values are strings.
676 """
679 """
677 main = self.config(section, name, default, untrusted=untrusted)
680 main = self.config(section, name, default, untrusted=untrusted)
678 data = self._data(untrusted)
681 data = self._data(untrusted)
679 sub = {}
682 sub = {}
680 prefix = b'%s:' % name
683 prefix = b'%s:' % name
681 for k, v in data.items(section):
684 for k, v in data.items(section):
682 if k.startswith(prefix):
685 if k.startswith(prefix):
683 sub[k[len(prefix) :]] = v
686 sub[k[len(prefix) :]] = v
684
687
685 if self.debugflag and not untrusted and self._reportuntrusted:
688 if self.debugflag and not untrusted and self._reportuntrusted:
686 for k, v in sub.items():
689 for k, v in sub.items():
687 uvalue = self._ucfg.get(section, b'%s:%s' % (name, k))
690 uvalue = self._ucfg.get(section, b'%s:%s' % (name, k))
688 if uvalue is not None and uvalue != v:
691 if uvalue is not None and uvalue != v:
689 self.debug(
692 self.debug(
690 b'ignoring untrusted configuration option '
693 b'ignoring untrusted configuration option '
691 b'%s:%s.%s = %s\n' % (section, name, k, uvalue)
694 b'%s:%s.%s = %s\n' % (section, name, k, uvalue)
692 )
695 )
693
696
694 return main, sub
697 return main, sub
695
698
696 def configpath(self, section, name, default=_unset, untrusted=False):
699 def configpath(self, section, name, default=_unset, untrusted=False):
697 """get a path config item, expanded relative to repo root or config
700 """get a path config item, expanded relative to repo root or config
698 file"""
701 file"""
699 v = self.config(section, name, default, untrusted)
702 v = self.config(section, name, default, untrusted)
700 if v is None:
703 if v is None:
701 return None
704 return None
702 if not os.path.isabs(v) or b"://" not in v:
705 if not os.path.isabs(v) or b"://" not in v:
703 src = self.configsource(section, name, untrusted)
706 src = self.configsource(section, name, untrusted)
704 if b':' in src:
707 if b':' in src:
705 base = os.path.dirname(src.rsplit(b':')[0])
708 base = os.path.dirname(src.rsplit(b':')[0])
706 v = os.path.join(base, os.path.expanduser(v))
709 v = os.path.join(base, os.path.expanduser(v))
707 return v
710 return v
708
711
709 def configbool(self, section, name, default=_unset, untrusted=False):
712 def configbool(self, section, name, default=_unset, untrusted=False):
710 """parse a configuration element as a boolean
713 """parse a configuration element as a boolean
711
714
712 >>> u = ui(); s = b'foo'
715 >>> u = ui(); s = b'foo'
713 >>> u.setconfig(s, b'true', b'yes')
716 >>> u.setconfig(s, b'true', b'yes')
714 >>> u.configbool(s, b'true')
717 >>> u.configbool(s, b'true')
715 True
718 True
716 >>> u.setconfig(s, b'false', b'no')
719 >>> u.setconfig(s, b'false', b'no')
717 >>> u.configbool(s, b'false')
720 >>> u.configbool(s, b'false')
718 False
721 False
719 >>> u.configbool(s, b'unknown')
722 >>> u.configbool(s, b'unknown')
720 False
723 False
721 >>> u.configbool(s, b'unknown', True)
724 >>> u.configbool(s, b'unknown', True)
722 True
725 True
723 >>> u.setconfig(s, b'invalid', b'somevalue')
726 >>> u.setconfig(s, b'invalid', b'somevalue')
724 >>> u.configbool(s, b'invalid')
727 >>> u.configbool(s, b'invalid')
725 Traceback (most recent call last):
728 Traceback (most recent call last):
726 ...
729 ...
727 ConfigError: foo.invalid is not a boolean ('somevalue')
730 ConfigError: foo.invalid is not a boolean ('somevalue')
728 """
731 """
729
732
730 v = self._config(section, name, default, untrusted=untrusted)
733 v = self._config(section, name, default, untrusted=untrusted)
731 if v is None:
734 if v is None:
732 return v
735 return v
733 if v is _unset:
736 if v is _unset:
734 if default is _unset:
737 if default is _unset:
735 return False
738 return False
736 return default
739 return default
737 if isinstance(v, bool):
740 if isinstance(v, bool):
738 return v
741 return v
739 b = stringutil.parsebool(v)
742 b = stringutil.parsebool(v)
740 if b is None:
743 if b is None:
741 raise error.ConfigError(
744 raise error.ConfigError(
742 _(b"%s.%s is not a boolean ('%s')") % (section, name, v)
745 _(b"%s.%s is not a boolean ('%s')") % (section, name, v)
743 )
746 )
744 return b
747 return b
745
748
746 def configwith(
749 def configwith(
747 self, convert, section, name, default=_unset, desc=None, untrusted=False
750 self, convert, section, name, default=_unset, desc=None, untrusted=False
748 ):
751 ):
749 """parse a configuration element with a conversion function
752 """parse a configuration element with a conversion function
750
753
751 >>> u = ui(); s = b'foo'
754 >>> u = ui(); s = b'foo'
752 >>> u.setconfig(s, b'float1', b'42')
755 >>> u.setconfig(s, b'float1', b'42')
753 >>> u.configwith(float, s, b'float1')
756 >>> u.configwith(float, s, b'float1')
754 42.0
757 42.0
755 >>> u.setconfig(s, b'float2', b'-4.25')
758 >>> u.setconfig(s, b'float2', b'-4.25')
756 >>> u.configwith(float, s, b'float2')
759 >>> u.configwith(float, s, b'float2')
757 -4.25
760 -4.25
758 >>> u.configwith(float, s, b'unknown', 7)
761 >>> u.configwith(float, s, b'unknown', 7)
759 7.0
762 7.0
760 >>> u.setconfig(s, b'invalid', b'somevalue')
763 >>> u.setconfig(s, b'invalid', b'somevalue')
761 >>> u.configwith(float, s, b'invalid')
764 >>> u.configwith(float, s, b'invalid')
762 Traceback (most recent call last):
765 Traceback (most recent call last):
763 ...
766 ...
764 ConfigError: foo.invalid is not a valid float ('somevalue')
767 ConfigError: foo.invalid is not a valid float ('somevalue')
765 >>> u.configwith(float, s, b'invalid', desc=b'womble')
768 >>> u.configwith(float, s, b'invalid', desc=b'womble')
766 Traceback (most recent call last):
769 Traceback (most recent call last):
767 ...
770 ...
768 ConfigError: foo.invalid is not a valid womble ('somevalue')
771 ConfigError: foo.invalid is not a valid womble ('somevalue')
769 """
772 """
770
773
771 v = self.config(section, name, default, untrusted)
774 v = self.config(section, name, default, untrusted)
772 if v is None:
775 if v is None:
773 return v # do not attempt to convert None
776 return v # do not attempt to convert None
774 try:
777 try:
775 return convert(v)
778 return convert(v)
776 except (ValueError, error.ParseError):
779 except (ValueError, error.ParseError):
777 if desc is None:
780 if desc is None:
778 desc = pycompat.sysbytes(convert.__name__)
781 desc = pycompat.sysbytes(convert.__name__)
779 raise error.ConfigError(
782 raise error.ConfigError(
780 _(b"%s.%s is not a valid %s ('%s')") % (section, name, desc, v)
783 _(b"%s.%s is not a valid %s ('%s')") % (section, name, desc, v)
781 )
784 )
782
785
783 def configint(self, section, name, default=_unset, untrusted=False):
786 def configint(self, section, name, default=_unset, untrusted=False):
784 """parse a configuration element as an integer
787 """parse a configuration element as an integer
785
788
786 >>> u = ui(); s = b'foo'
789 >>> u = ui(); s = b'foo'
787 >>> u.setconfig(s, b'int1', b'42')
790 >>> u.setconfig(s, b'int1', b'42')
788 >>> u.configint(s, b'int1')
791 >>> u.configint(s, b'int1')
789 42
792 42
790 >>> u.setconfig(s, b'int2', b'-42')
793 >>> u.setconfig(s, b'int2', b'-42')
791 >>> u.configint(s, b'int2')
794 >>> u.configint(s, b'int2')
792 -42
795 -42
793 >>> u.configint(s, b'unknown', 7)
796 >>> u.configint(s, b'unknown', 7)
794 7
797 7
795 >>> u.setconfig(s, b'invalid', b'somevalue')
798 >>> u.setconfig(s, b'invalid', b'somevalue')
796 >>> u.configint(s, b'invalid')
799 >>> u.configint(s, b'invalid')
797 Traceback (most recent call last):
800 Traceback (most recent call last):
798 ...
801 ...
799 ConfigError: foo.invalid is not a valid integer ('somevalue')
802 ConfigError: foo.invalid is not a valid integer ('somevalue')
800 """
803 """
801
804
802 return self.configwith(
805 return self.configwith(
803 int, section, name, default, b'integer', untrusted
806 int, section, name, default, b'integer', untrusted
804 )
807 )
805
808
806 def configbytes(self, section, name, default=_unset, untrusted=False):
809 def configbytes(self, section, name, default=_unset, untrusted=False):
807 """parse a configuration element as a quantity in bytes
810 """parse a configuration element as a quantity in bytes
808
811
809 Units can be specified as b (bytes), k or kb (kilobytes), m or
812 Units can be specified as b (bytes), k or kb (kilobytes), m or
810 mb (megabytes), g or gb (gigabytes).
813 mb (megabytes), g or gb (gigabytes).
811
814
812 >>> u = ui(); s = b'foo'
815 >>> u = ui(); s = b'foo'
813 >>> u.setconfig(s, b'val1', b'42')
816 >>> u.setconfig(s, b'val1', b'42')
814 >>> u.configbytes(s, b'val1')
817 >>> u.configbytes(s, b'val1')
815 42
818 42
816 >>> u.setconfig(s, b'val2', b'42.5 kb')
819 >>> u.setconfig(s, b'val2', b'42.5 kb')
817 >>> u.configbytes(s, b'val2')
820 >>> u.configbytes(s, b'val2')
818 43520
821 43520
819 >>> u.configbytes(s, b'unknown', b'7 MB')
822 >>> u.configbytes(s, b'unknown', b'7 MB')
820 7340032
823 7340032
821 >>> u.setconfig(s, b'invalid', b'somevalue')
824 >>> u.setconfig(s, b'invalid', b'somevalue')
822 >>> u.configbytes(s, b'invalid')
825 >>> u.configbytes(s, b'invalid')
823 Traceback (most recent call last):
826 Traceback (most recent call last):
824 ...
827 ...
825 ConfigError: foo.invalid is not a byte quantity ('somevalue')
828 ConfigError: foo.invalid is not a byte quantity ('somevalue')
826 """
829 """
827
830
828 value = self._config(section, name, default, untrusted)
831 value = self._config(section, name, default, untrusted)
829 if value is _unset:
832 if value is _unset:
830 if default is _unset:
833 if default is _unset:
831 default = 0
834 default = 0
832 value = default
835 value = default
833 if not isinstance(value, bytes):
836 if not isinstance(value, bytes):
834 return value
837 return value
835 try:
838 try:
836 return util.sizetoint(value)
839 return util.sizetoint(value)
837 except error.ParseError:
840 except error.ParseError:
838 raise error.ConfigError(
841 raise error.ConfigError(
839 _(b"%s.%s is not a byte quantity ('%s')")
842 _(b"%s.%s is not a byte quantity ('%s')")
840 % (section, name, value)
843 % (section, name, value)
841 )
844 )
842
845
843 def configlist(self, section, name, default=_unset, untrusted=False):
846 def configlist(self, section, name, default=_unset, untrusted=False):
844 """parse a configuration element as a list of comma/space separated
847 """parse a configuration element as a list of comma/space separated
845 strings
848 strings
846
849
847 >>> u = ui(); s = b'foo'
850 >>> u = ui(); s = b'foo'
848 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
851 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
849 >>> u.configlist(s, b'list1')
852 >>> u.configlist(s, b'list1')
850 ['this', 'is', 'a small', 'test']
853 ['this', 'is', 'a small', 'test']
851 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ')
854 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ')
852 >>> u.configlist(s, b'list2')
855 >>> u.configlist(s, b'list2')
853 ['this', 'is', 'a small', 'test']
856 ['this', 'is', 'a small', 'test']
854 """
857 """
855 # default is not always a list
858 # default is not always a list
856 v = self.configwith(
859 v = self.configwith(
857 config.parselist, section, name, default, b'list', untrusted
860 config.parselist, section, name, default, b'list', untrusted
858 )
861 )
859 if isinstance(v, bytes):
862 if isinstance(v, bytes):
860 return config.parselist(v)
863 return config.parselist(v)
861 elif v is None:
864 elif v is None:
862 return []
865 return []
863 return v
866 return v
864
867
865 def configdate(self, section, name, default=_unset, untrusted=False):
868 def configdate(self, section, name, default=_unset, untrusted=False):
866 """parse a configuration element as a tuple of ints
869 """parse a configuration element as a tuple of ints
867
870
868 >>> u = ui(); s = b'foo'
871 >>> u = ui(); s = b'foo'
869 >>> u.setconfig(s, b'date', b'0 0')
872 >>> u.setconfig(s, b'date', b'0 0')
870 >>> u.configdate(s, b'date')
873 >>> u.configdate(s, b'date')
871 (0, 0)
874 (0, 0)
872 """
875 """
873 if self.config(section, name, default, untrusted):
876 if self.config(section, name, default, untrusted):
874 return self.configwith(
877 return self.configwith(
875 dateutil.parsedate, section, name, default, b'date', untrusted
878 dateutil.parsedate, section, name, default, b'date', untrusted
876 )
879 )
877 if default is _unset:
880 if default is _unset:
878 return None
881 return None
879 return default
882 return default
880
883
881 def configdefault(self, section, name):
884 def configdefault(self, section, name):
882 """returns the default value of the config item"""
885 """returns the default value of the config item"""
883 item = self._knownconfig.get(section, {}).get(name)
886 item = self._knownconfig.get(section, {}).get(name)
884 itemdefault = None
887 itemdefault = None
885 if item is not None:
888 if item is not None:
886 if callable(item.default):
889 if callable(item.default):
887 itemdefault = item.default()
890 itemdefault = item.default()
888 else:
891 else:
889 itemdefault = item.default
892 itemdefault = item.default
890 return itemdefault
893 return itemdefault
891
894
892 def hasconfig(self, section, name, untrusted=False):
895 def hasconfig(self, section, name, untrusted=False):
893 return self._data(untrusted).hasitem(section, name)
896 return self._data(untrusted).hasitem(section, name)
894
897
895 def has_section(self, section, untrusted=False):
898 def has_section(self, section, untrusted=False):
896 '''tell whether section exists in config.'''
899 '''tell whether section exists in config.'''
897 return section in self._data(untrusted)
900 return section in self._data(untrusted)
898
901
899 def configitems(self, section, untrusted=False, ignoresub=False):
902 def configitems(self, section, untrusted=False, ignoresub=False):
900 items = self._data(untrusted).items(section)
903 items = self._data(untrusted).items(section)
901 if ignoresub:
904 if ignoresub:
902 items = [i for i in items if b':' not in i[0]]
905 items = [i for i in items if b':' not in i[0]]
903 if self.debugflag and not untrusted and self._reportuntrusted:
906 if self.debugflag and not untrusted and self._reportuntrusted:
904 for k, v in self._ucfg.items(section):
907 for k, v in self._ucfg.items(section):
905 if self._tcfg.get(section, k) != v:
908 if self._tcfg.get(section, k) != v:
906 self.debug(
909 self.debug(
907 b"ignoring untrusted configuration option "
910 b"ignoring untrusted configuration option "
908 b"%s.%s = %s\n" % (section, k, v)
911 b"%s.%s = %s\n" % (section, k, v)
909 )
912 )
910 return items
913 return items
911
914
912 def walkconfig(self, untrusted=False):
915 def walkconfig(self, untrusted=False):
913 cfg = self._data(untrusted)
916 cfg = self._data(untrusted)
914 for section in cfg.sections():
917 for section in cfg.sections():
915 for name, value in self.configitems(section, untrusted):
918 for name, value in self.configitems(section, untrusted):
916 yield section, name, value
919 yield section, name, value
917
920
918 def plain(self, feature=None):
921 def plain(self, feature=None):
919 '''is plain mode active?
922 '''is plain mode active?
920
923
921 Plain mode means that all configuration variables which affect
924 Plain mode means that all configuration variables which affect
922 the behavior and output of Mercurial should be
925 the behavior and output of Mercurial should be
923 ignored. Additionally, the output should be stable,
926 ignored. Additionally, the output should be stable,
924 reproducible and suitable for use in scripts or applications.
927 reproducible and suitable for use in scripts or applications.
925
928
926 The only way to trigger plain mode is by setting either the
929 The only way to trigger plain mode is by setting either the
927 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
930 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
928
931
929 The return value can either be
932 The return value can either be
930 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
933 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
931 - False if feature is disabled by default and not included in HGPLAIN
934 - False if feature is disabled by default and not included in HGPLAIN
932 - True otherwise
935 - True otherwise
933 '''
936 '''
934 if (
937 if (
935 b'HGPLAIN' not in encoding.environ
938 b'HGPLAIN' not in encoding.environ
936 and b'HGPLAINEXCEPT' not in encoding.environ
939 and b'HGPLAINEXCEPT' not in encoding.environ
937 ):
940 ):
938 return False
941 return False
939 exceptions = (
942 exceptions = (
940 encoding.environ.get(b'HGPLAINEXCEPT', b'').strip().split(b',')
943 encoding.environ.get(b'HGPLAINEXCEPT', b'').strip().split(b',')
941 )
944 )
942 # TODO: add support for HGPLAIN=+feature,-feature syntax
945 # TODO: add support for HGPLAIN=+feature,-feature syntax
943 if b'+strictflags' not in encoding.environ.get(b'HGPLAIN', b'').split(
946 if b'+strictflags' not in encoding.environ.get(b'HGPLAIN', b'').split(
944 b','
947 b','
945 ):
948 ):
946 exceptions.append(b'strictflags')
949 exceptions.append(b'strictflags')
947 if feature and exceptions:
950 if feature and exceptions:
948 return feature not in exceptions
951 return feature not in exceptions
949 return True
952 return True
950
953
951 def username(self, acceptempty=False):
954 def username(self, acceptempty=False):
952 """Return default username to be used in commits.
955 """Return default username to be used in commits.
953
956
954 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
957 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
955 and stop searching if one of these is set.
958 and stop searching if one of these is set.
956 If not found and acceptempty is True, returns None.
959 If not found and acceptempty is True, returns None.
957 If not found and ui.askusername is True, ask the user, else use
960 If not found and ui.askusername is True, ask the user, else use
958 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
961 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
959 If no username could be found, raise an Abort error.
962 If no username could be found, raise an Abort error.
960 """
963 """
961 user = encoding.environ.get(b"HGUSER")
964 user = encoding.environ.get(b"HGUSER")
962 if user is None:
965 if user is None:
963 user = self.config(b"ui", b"username")
966 user = self.config(b"ui", b"username")
964 if user is not None:
967 if user is not None:
965 user = os.path.expandvars(user)
968 user = os.path.expandvars(user)
966 if user is None:
969 if user is None:
967 user = encoding.environ.get(b"EMAIL")
970 user = encoding.environ.get(b"EMAIL")
968 if user is None and acceptempty:
971 if user is None and acceptempty:
969 return user
972 return user
970 if user is None and self.configbool(b"ui", b"askusername"):
973 if user is None and self.configbool(b"ui", b"askusername"):
971 user = self.prompt(_(b"enter a commit username:"), default=None)
974 user = self.prompt(_(b"enter a commit username:"), default=None)
972 if user is None and not self.interactive():
975 if user is None and not self.interactive():
973 try:
976 try:
974 user = b'%s@%s' % (
977 user = b'%s@%s' % (
975 procutil.getuser(),
978 procutil.getuser(),
976 encoding.strtolocal(socket.getfqdn()),
979 encoding.strtolocal(socket.getfqdn()),
977 )
980 )
978 self.warn(_(b"no username found, using '%s' instead\n") % user)
981 self.warn(_(b"no username found, using '%s' instead\n") % user)
979 except KeyError:
982 except KeyError:
980 pass
983 pass
981 if not user:
984 if not user:
982 raise error.Abort(
985 raise error.Abort(
983 _(b'no username supplied'),
986 _(b'no username supplied'),
984 hint=_(b"use 'hg config --edit' " b'to set your username'),
987 hint=_(b"use 'hg config --edit' " b'to set your username'),
985 )
988 )
986 if b"\n" in user:
989 if b"\n" in user:
987 raise error.Abort(
990 raise error.Abort(
988 _(b"username %r contains a newline\n") % pycompat.bytestr(user)
991 _(b"username %r contains a newline\n") % pycompat.bytestr(user)
989 )
992 )
990 return user
993 return user
991
994
992 def shortuser(self, user):
995 def shortuser(self, user):
993 """Return a short representation of a user name or email address."""
996 """Return a short representation of a user name or email address."""
994 if not self.verbose:
997 if not self.verbose:
995 user = stringutil.shortuser(user)
998 user = stringutil.shortuser(user)
996 return user
999 return user
997
1000
998 def expandpath(self, loc, default=None):
1001 def expandpath(self, loc, default=None):
999 """Return repository location relative to cwd or from [paths]"""
1002 """Return repository location relative to cwd or from [paths]"""
1000 try:
1003 try:
1001 p = self.paths.getpath(loc)
1004 p = self.paths.getpath(loc)
1002 if p:
1005 if p:
1003 return p.rawloc
1006 return p.rawloc
1004 except error.RepoError:
1007 except error.RepoError:
1005 pass
1008 pass
1006
1009
1007 if default:
1010 if default:
1008 try:
1011 try:
1009 p = self.paths.getpath(default)
1012 p = self.paths.getpath(default)
1010 if p:
1013 if p:
1011 return p.rawloc
1014 return p.rawloc
1012 except error.RepoError:
1015 except error.RepoError:
1013 pass
1016 pass
1014
1017
1015 return loc
1018 return loc
1016
1019
1017 @util.propertycache
1020 @util.propertycache
1018 def paths(self):
1021 def paths(self):
1019 return paths(self)
1022 return paths(self)
1020
1023
1021 @property
1024 @property
1022 def fout(self):
1025 def fout(self):
1023 return self._fout
1026 return self._fout
1024
1027
1025 @fout.setter
1028 @fout.setter
1026 def fout(self, f):
1029 def fout(self, f):
1027 self._fout = f
1030 self._fout = f
1028 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1031 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1029
1032
1030 @property
1033 @property
1031 def ferr(self):
1034 def ferr(self):
1032 return self._ferr
1035 return self._ferr
1033
1036
1034 @ferr.setter
1037 @ferr.setter
1035 def ferr(self, f):
1038 def ferr(self, f):
1036 self._ferr = f
1039 self._ferr = f
1037 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1040 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1038
1041
1039 @property
1042 @property
1040 def fin(self):
1043 def fin(self):
1041 return self._fin
1044 return self._fin
1042
1045
1043 @fin.setter
1046 @fin.setter
1044 def fin(self, f):
1047 def fin(self, f):
1045 self._fin = f
1048 self._fin = f
1046
1049
1047 @property
1050 @property
1048 def fmsg(self):
1051 def fmsg(self):
1049 """Stream dedicated for status/error messages; may be None if
1052 """Stream dedicated for status/error messages; may be None if
1050 fout/ferr are used"""
1053 fout/ferr are used"""
1051 return self._fmsg
1054 return self._fmsg
1052
1055
1053 @fmsg.setter
1056 @fmsg.setter
1054 def fmsg(self, f):
1057 def fmsg(self, f):
1055 self._fmsg = f
1058 self._fmsg = f
1056 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1059 self._fmsgout, self._fmsgerr = _selectmsgdests(self)
1057
1060
1058 def pushbuffer(self, error=False, subproc=False, labeled=False):
1061 def pushbuffer(self, error=False, subproc=False, labeled=False):
1059 """install a buffer to capture standard output of the ui object
1062 """install a buffer to capture standard output of the ui object
1060
1063
1061 If error is True, the error output will be captured too.
1064 If error is True, the error output will be captured too.
1062
1065
1063 If subproc is True, output from subprocesses (typically hooks) will be
1066 If subproc is True, output from subprocesses (typically hooks) will be
1064 captured too.
1067 captured too.
1065
1068
1066 If labeled is True, any labels associated with buffered
1069 If labeled is True, any labels associated with buffered
1067 output will be handled. By default, this has no effect
1070 output will be handled. By default, this has no effect
1068 on the output returned, but extensions and GUI tools may
1071 on the output returned, but extensions and GUI tools may
1069 handle this argument and returned styled output. If output
1072 handle this argument and returned styled output. If output
1070 is being buffered so it can be captured and parsed or
1073 is being buffered so it can be captured and parsed or
1071 processed, labeled should not be set to True.
1074 processed, labeled should not be set to True.
1072 """
1075 """
1073 self._buffers.append([])
1076 self._buffers.append([])
1074 self._bufferstates.append((error, subproc, labeled))
1077 self._bufferstates.append((error, subproc, labeled))
1075 self._bufferapplylabels = labeled
1078 self._bufferapplylabels = labeled
1076
1079
1077 def popbuffer(self):
1080 def popbuffer(self):
1078 '''pop the last buffer and return the buffered output'''
1081 '''pop the last buffer and return the buffered output'''
1079 self._bufferstates.pop()
1082 self._bufferstates.pop()
1080 if self._bufferstates:
1083 if self._bufferstates:
1081 self._bufferapplylabels = self._bufferstates[-1][2]
1084 self._bufferapplylabels = self._bufferstates[-1][2]
1082 else:
1085 else:
1083 self._bufferapplylabels = None
1086 self._bufferapplylabels = None
1084
1087
1085 return b"".join(self._buffers.pop())
1088 return b"".join(self._buffers.pop())
1086
1089
1087 def _isbuffered(self, dest):
1090 def _isbuffered(self, dest):
1088 if dest is self._fout:
1091 if dest is self._fout:
1089 return bool(self._buffers)
1092 return bool(self._buffers)
1090 if dest is self._ferr:
1093 if dest is self._ferr:
1091 return bool(self._bufferstates and self._bufferstates[-1][0])
1094 return bool(self._bufferstates and self._bufferstates[-1][0])
1092 return False
1095 return False
1093
1096
1094 def canwritewithoutlabels(self):
1097 def canwritewithoutlabels(self):
1095 '''check if write skips the label'''
1098 '''check if write skips the label'''
1096 if self._buffers and not self._bufferapplylabels:
1099 if self._buffers and not self._bufferapplylabels:
1097 return True
1100 return True
1098 return self._colormode is None
1101 return self._colormode is None
1099
1102
1100 def canbatchlabeledwrites(self):
1103 def canbatchlabeledwrites(self):
1101 '''check if write calls with labels are batchable'''
1104 '''check if write calls with labels are batchable'''
1102 # Windows color printing is special, see ``write``.
1105 # Windows color printing is special, see ``write``.
1103 return self._colormode != b'win32'
1106 return self._colormode != b'win32'
1104
1107
1105 def write(self, *args, **opts):
1108 def write(self, *args, **opts):
1106 '''write args to output
1109 '''write args to output
1107
1110
1108 By default, this method simply writes to the buffer or stdout.
1111 By default, this method simply writes to the buffer or stdout.
1109 Color mode can be set on the UI class to have the output decorated
1112 Color mode can be set on the UI class to have the output decorated
1110 with color modifier before being written to stdout.
1113 with color modifier before being written to stdout.
1111
1114
1112 The color used is controlled by an optional keyword argument, "label".
1115 The color used is controlled by an optional keyword argument, "label".
1113 This should be a string containing label names separated by space.
1116 This should be a string containing label names separated by space.
1114 Label names take the form of "topic.type". For example, ui.debug()
1117 Label names take the form of "topic.type". For example, ui.debug()
1115 issues a label of "ui.debug".
1118 issues a label of "ui.debug".
1116
1119
1117 Progress reports via stderr are normally cleared before writing as
1120 Progress reports via stderr are normally cleared before writing as
1118 stdout and stderr go to the same terminal. This can be skipped with
1121 stdout and stderr go to the same terminal. This can be skipped with
1119 the optional keyword argument "keepprogressbar". The progress bar
1122 the optional keyword argument "keepprogressbar". The progress bar
1120 will continue to occupy a partial line on stderr in that case.
1123 will continue to occupy a partial line on stderr in that case.
1121 This functionality is intended when Mercurial acts as data source
1124 This functionality is intended when Mercurial acts as data source
1122 in a pipe.
1125 in a pipe.
1123
1126
1124 When labeling output for a specific command, a label of
1127 When labeling output for a specific command, a label of
1125 "cmdname.type" is recommended. For example, status issues
1128 "cmdname.type" is recommended. For example, status issues
1126 a label of "status.modified" for modified files.
1129 a label of "status.modified" for modified files.
1127 '''
1130 '''
1128 dest = self._fout
1131 dest = self._fout
1129
1132
1130 # inlined _write() for speed
1133 # inlined _write() for speed
1131 if self._buffers:
1134 if self._buffers:
1132 label = opts.get('label', b'')
1135 label = opts.get('label', b'')
1133 if label and self._bufferapplylabels:
1136 if label and self._bufferapplylabels:
1134 self._buffers[-1].extend(self.label(a, label) for a in args)
1137 self._buffers[-1].extend(self.label(a, label) for a in args)
1135 else:
1138 else:
1136 self._buffers[-1].extend(args)
1139 self._buffers[-1].extend(args)
1137 return
1140 return
1138
1141
1139 # inlined _writenobuf() for speed
1142 # inlined _writenobuf() for speed
1140 if not opts.get('keepprogressbar', False):
1143 if not opts.get('keepprogressbar', False):
1141 self._progclear()
1144 self._progclear()
1142 msg = b''.join(args)
1145 msg = b''.join(args)
1143
1146
1144 # opencode timeblockedsection because this is a critical path
1147 # opencode timeblockedsection because this is a critical path
1145 starttime = util.timer()
1148 starttime = util.timer()
1146 try:
1149 try:
1147 if self._colormode == b'win32':
1150 if self._colormode == b'win32':
1148 # windows color printing is its own can of crab, defer to
1151 # windows color printing is its own can of crab, defer to
1149 # the color module and that is it.
1152 # the color module and that is it.
1150 color.win32print(self, dest.write, msg, **opts)
1153 color.win32print(self, dest.write, msg, **opts)
1151 else:
1154 else:
1152 if self._colormode is not None:
1155 if self._colormode is not None:
1153 label = opts.get('label', b'')
1156 label = opts.get('label', b'')
1154 msg = self.label(msg, label)
1157 msg = self.label(msg, label)
1155 dest.write(msg)
1158 dest.write(msg)
1156 except IOError as err:
1159 except IOError as err:
1157 raise error.StdioError(err)
1160 raise error.StdioError(err)
1158 finally:
1161 finally:
1159 self._blockedtimes[b'stdio_blocked'] += (
1162 self._blockedtimes[b'stdio_blocked'] += (
1160 util.timer() - starttime
1163 util.timer() - starttime
1161 ) * 1000
1164 ) * 1000
1162
1165
1163 def write_err(self, *args, **opts):
1166 def write_err(self, *args, **opts):
1164 self._write(self._ferr, *args, **opts)
1167 self._write(self._ferr, *args, **opts)
1165
1168
1166 def _write(self, dest, *args, **opts):
1169 def _write(self, dest, *args, **opts):
1167 # update write() as well if you touch this code
1170 # update write() as well if you touch this code
1168 if self._isbuffered(dest):
1171 if self._isbuffered(dest):
1169 label = opts.get('label', b'')
1172 label = opts.get('label', b'')
1170 if label and self._bufferapplylabels:
1173 if label and self._bufferapplylabels:
1171 self._buffers[-1].extend(self.label(a, label) for a in args)
1174 self._buffers[-1].extend(self.label(a, label) for a in args)
1172 else:
1175 else:
1173 self._buffers[-1].extend(args)
1176 self._buffers[-1].extend(args)
1174 else:
1177 else:
1175 self._writenobuf(dest, *args, **opts)
1178 self._writenobuf(dest, *args, **opts)
1176
1179
1177 def _writenobuf(self, dest, *args, **opts):
1180 def _writenobuf(self, dest, *args, **opts):
1178 # update write() as well if you touch this code
1181 # update write() as well if you touch this code
1179 if not opts.get('keepprogressbar', False):
1182 if not opts.get('keepprogressbar', False):
1180 self._progclear()
1183 self._progclear()
1181 msg = b''.join(args)
1184 msg = b''.join(args)
1182
1185
1183 # opencode timeblockedsection because this is a critical path
1186 # opencode timeblockedsection because this is a critical path
1184 starttime = util.timer()
1187 starttime = util.timer()
1185 try:
1188 try:
1186 if dest is self._ferr and not getattr(self._fout, 'closed', False):
1189 if dest is self._ferr and not getattr(self._fout, 'closed', False):
1187 self._fout.flush()
1190 self._fout.flush()
1188 if getattr(dest, 'structured', False):
1191 if getattr(dest, 'structured', False):
1189 # channel for machine-readable output with metadata, where
1192 # channel for machine-readable output with metadata, where
1190 # no extra colorization is necessary.
1193 # no extra colorization is necessary.
1191 dest.write(msg, **opts)
1194 dest.write(msg, **opts)
1192 elif self._colormode == b'win32':
1195 elif self._colormode == b'win32':
1193 # windows color printing is its own can of crab, defer to
1196 # windows color printing is its own can of crab, defer to
1194 # the color module and that is it.
1197 # the color module and that is it.
1195 color.win32print(self, dest.write, msg, **opts)
1198 color.win32print(self, dest.write, msg, **opts)
1196 else:
1199 else:
1197 if self._colormode is not None:
1200 if self._colormode is not None:
1198 label = opts.get('label', b'')
1201 label = opts.get('label', b'')
1199 msg = self.label(msg, label)
1202 msg = self.label(msg, label)
1200 dest.write(msg)
1203 dest.write(msg)
1201 # stderr may be buffered under win32 when redirected to files,
1204 # stderr may be buffered under win32 when redirected to files,
1202 # including stdout.
1205 # including stdout.
1203 if dest is self._ferr and not getattr(dest, 'closed', False):
1206 if dest is self._ferr and not getattr(dest, 'closed', False):
1204 dest.flush()
1207 dest.flush()
1205 except IOError as err:
1208 except IOError as err:
1206 if dest is self._ferr and err.errno in (
1209 if dest is self._ferr and err.errno in (
1207 errno.EPIPE,
1210 errno.EPIPE,
1208 errno.EIO,
1211 errno.EIO,
1209 errno.EBADF,
1212 errno.EBADF,
1210 ):
1213 ):
1211 # no way to report the error, so ignore it
1214 # no way to report the error, so ignore it
1212 return
1215 return
1213 raise error.StdioError(err)
1216 raise error.StdioError(err)
1214 finally:
1217 finally:
1215 self._blockedtimes[b'stdio_blocked'] += (
1218 self._blockedtimes[b'stdio_blocked'] += (
1216 util.timer() - starttime
1219 util.timer() - starttime
1217 ) * 1000
1220 ) * 1000
1218
1221
1219 def _writemsg(self, dest, *args, **opts):
1222 def _writemsg(self, dest, *args, **opts):
1223 timestamp = self.showtimestamp and opts.get('type') in {
1224 b'debug',
1225 b'error',
1226 b'note',
1227 b'status',
1228 b'warning',
1229 }
1230 if timestamp:
1231 args = (
1232 b'[%s] ' % bytes(datetime.datetime.now().isoformat(), 'ASCII'),
1233 ) + args
1220 _writemsgwith(self._write, dest, *args, **opts)
1234 _writemsgwith(self._write, dest, *args, **opts)
1235 if timestamp:
1236 dest.flush()
1221
1237
1222 def _writemsgnobuf(self, dest, *args, **opts):
1238 def _writemsgnobuf(self, dest, *args, **opts):
1223 _writemsgwith(self._writenobuf, dest, *args, **opts)
1239 _writemsgwith(self._writenobuf, dest, *args, **opts)
1224
1240
1225 def flush(self):
1241 def flush(self):
1226 # opencode timeblockedsection because this is a critical path
1242 # opencode timeblockedsection because this is a critical path
1227 starttime = util.timer()
1243 starttime = util.timer()
1228 try:
1244 try:
1229 try:
1245 try:
1230 self._fout.flush()
1246 self._fout.flush()
1231 except IOError as err:
1247 except IOError as err:
1232 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1248 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1233 raise error.StdioError(err)
1249 raise error.StdioError(err)
1234 finally:
1250 finally:
1235 try:
1251 try:
1236 self._ferr.flush()
1252 self._ferr.flush()
1237 except IOError as err:
1253 except IOError as err:
1238 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1254 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1239 raise error.StdioError(err)
1255 raise error.StdioError(err)
1240 finally:
1256 finally:
1241 self._blockedtimes[b'stdio_blocked'] += (
1257 self._blockedtimes[b'stdio_blocked'] += (
1242 util.timer() - starttime
1258 util.timer() - starttime
1243 ) * 1000
1259 ) * 1000
1244
1260
1245 def _isatty(self, fh):
1261 def _isatty(self, fh):
1246 if self.configbool(b'ui', b'nontty'):
1262 if self.configbool(b'ui', b'nontty'):
1247 return False
1263 return False
1248 return procutil.isatty(fh)
1264 return procutil.isatty(fh)
1249
1265
1250 def protectfinout(self):
1266 def protectfinout(self):
1251 """Duplicate ui streams and redirect original if they are stdio
1267 """Duplicate ui streams and redirect original if they are stdio
1252
1268
1253 Returns (fin, fout) which point to the original ui fds, but may be
1269 Returns (fin, fout) which point to the original ui fds, but may be
1254 copy of them. The returned streams can be considered "owned" in that
1270 copy of them. The returned streams can be considered "owned" in that
1255 print(), exec(), etc. never reach to them.
1271 print(), exec(), etc. never reach to them.
1256 """
1272 """
1257 if self._finoutredirected:
1273 if self._finoutredirected:
1258 # if already redirected, protectstdio() would just create another
1274 # if already redirected, protectstdio() would just create another
1259 # nullfd pair, which is equivalent to returning self._fin/_fout.
1275 # nullfd pair, which is equivalent to returning self._fin/_fout.
1260 return self._fin, self._fout
1276 return self._fin, self._fout
1261 fin, fout = procutil.protectstdio(self._fin, self._fout)
1277 fin, fout = procutil.protectstdio(self._fin, self._fout)
1262 self._finoutredirected = (fin, fout) != (self._fin, self._fout)
1278 self._finoutredirected = (fin, fout) != (self._fin, self._fout)
1263 return fin, fout
1279 return fin, fout
1264
1280
1265 def restorefinout(self, fin, fout):
1281 def restorefinout(self, fin, fout):
1266 """Restore ui streams from possibly duplicated (fin, fout)"""
1282 """Restore ui streams from possibly duplicated (fin, fout)"""
1267 if (fin, fout) == (self._fin, self._fout):
1283 if (fin, fout) == (self._fin, self._fout):
1268 return
1284 return
1269 procutil.restorestdio(self._fin, self._fout, fin, fout)
1285 procutil.restorestdio(self._fin, self._fout, fin, fout)
1270 # protectfinout() won't create more than one duplicated streams,
1286 # protectfinout() won't create more than one duplicated streams,
1271 # so we can just turn the redirection flag off.
1287 # so we can just turn the redirection flag off.
1272 self._finoutredirected = False
1288 self._finoutredirected = False
1273
1289
1274 @contextlib.contextmanager
1290 @contextlib.contextmanager
1275 def protectedfinout(self):
1291 def protectedfinout(self):
1276 """Run code block with protected standard streams"""
1292 """Run code block with protected standard streams"""
1277 fin, fout = self.protectfinout()
1293 fin, fout = self.protectfinout()
1278 try:
1294 try:
1279 yield fin, fout
1295 yield fin, fout
1280 finally:
1296 finally:
1281 self.restorefinout(fin, fout)
1297 self.restorefinout(fin, fout)
1282
1298
1283 def disablepager(self):
1299 def disablepager(self):
1284 self._disablepager = True
1300 self._disablepager = True
1285
1301
1286 def pager(self, command):
1302 def pager(self, command):
1287 """Start a pager for subsequent command output.
1303 """Start a pager for subsequent command output.
1288
1304
1289 Commands which produce a long stream of output should call
1305 Commands which produce a long stream of output should call
1290 this function to activate the user's preferred pagination
1306 this function to activate the user's preferred pagination
1291 mechanism (which may be no pager). Calling this function
1307 mechanism (which may be no pager). Calling this function
1292 precludes any future use of interactive functionality, such as
1308 precludes any future use of interactive functionality, such as
1293 prompting the user or activating curses.
1309 prompting the user or activating curses.
1294
1310
1295 Args:
1311 Args:
1296 command: The full, non-aliased name of the command. That is, "log"
1312 command: The full, non-aliased name of the command. That is, "log"
1297 not "history, "summary" not "summ", etc.
1313 not "history, "summary" not "summ", etc.
1298 """
1314 """
1299 if self._disablepager or self.pageractive:
1315 if self._disablepager or self.pageractive:
1300 # how pager should do is already determined
1316 # how pager should do is already determined
1301 return
1317 return
1302
1318
1303 if not command.startswith(b'internal-always-') and (
1319 if not command.startswith(b'internal-always-') and (
1304 # explicit --pager=on (= 'internal-always-' prefix) should
1320 # explicit --pager=on (= 'internal-always-' prefix) should
1305 # take precedence over disabling factors below
1321 # take precedence over disabling factors below
1306 command in self.configlist(b'pager', b'ignore')
1322 command in self.configlist(b'pager', b'ignore')
1307 or not self.configbool(b'ui', b'paginate')
1323 or not self.configbool(b'ui', b'paginate')
1308 or not self.configbool(b'pager', b'attend-' + command, True)
1324 or not self.configbool(b'pager', b'attend-' + command, True)
1309 or encoding.environ.get(b'TERM') == b'dumb'
1325 or encoding.environ.get(b'TERM') == b'dumb'
1310 # TODO: if we want to allow HGPLAINEXCEPT=pager,
1326 # TODO: if we want to allow HGPLAINEXCEPT=pager,
1311 # formatted() will need some adjustment.
1327 # formatted() will need some adjustment.
1312 or not self.formatted()
1328 or not self.formatted()
1313 or self.plain()
1329 or self.plain()
1314 or self._buffers
1330 or self._buffers
1315 # TODO: expose debugger-enabled on the UI object
1331 # TODO: expose debugger-enabled on the UI object
1316 or b'--debugger' in pycompat.sysargv
1332 or b'--debugger' in pycompat.sysargv
1317 ):
1333 ):
1318 # We only want to paginate if the ui appears to be
1334 # We only want to paginate if the ui appears to be
1319 # interactive, the user didn't say HGPLAIN or
1335 # interactive, the user didn't say HGPLAIN or
1320 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1336 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1321 return
1337 return
1322
1338
1323 pagercmd = self.config(b'pager', b'pager', rcutil.fallbackpager)
1339 pagercmd = self.config(b'pager', b'pager', rcutil.fallbackpager)
1324 if not pagercmd:
1340 if not pagercmd:
1325 return
1341 return
1326
1342
1327 pagerenv = {}
1343 pagerenv = {}
1328 for name, value in rcutil.defaultpagerenv().items():
1344 for name, value in rcutil.defaultpagerenv().items():
1329 if name not in encoding.environ:
1345 if name not in encoding.environ:
1330 pagerenv[name] = value
1346 pagerenv[name] = value
1331
1347
1332 self.debug(
1348 self.debug(
1333 b'starting pager for command %s\n' % stringutil.pprint(command)
1349 b'starting pager for command %s\n' % stringutil.pprint(command)
1334 )
1350 )
1335 self.flush()
1351 self.flush()
1336
1352
1337 wasformatted = self.formatted()
1353 wasformatted = self.formatted()
1338 if util.safehasattr(signal, b"SIGPIPE"):
1354 if util.safehasattr(signal, b"SIGPIPE"):
1339 signal.signal(signal.SIGPIPE, _catchterm)
1355 signal.signal(signal.SIGPIPE, _catchterm)
1340 if self._runpager(pagercmd, pagerenv):
1356 if self._runpager(pagercmd, pagerenv):
1341 self.pageractive = True
1357 self.pageractive = True
1342 # Preserve the formatted-ness of the UI. This is important
1358 # Preserve the formatted-ness of the UI. This is important
1343 # because we mess with stdout, which might confuse
1359 # because we mess with stdout, which might confuse
1344 # auto-detection of things being formatted.
1360 # auto-detection of things being formatted.
1345 self.setconfig(b'ui', b'formatted', wasformatted, b'pager')
1361 self.setconfig(b'ui', b'formatted', wasformatted, b'pager')
1346 self.setconfig(b'ui', b'interactive', False, b'pager')
1362 self.setconfig(b'ui', b'interactive', False, b'pager')
1347
1363
1348 # If pagermode differs from color.mode, reconfigure color now that
1364 # If pagermode differs from color.mode, reconfigure color now that
1349 # pageractive is set.
1365 # pageractive is set.
1350 cm = self._colormode
1366 cm = self._colormode
1351 if cm != self.config(b'color', b'pagermode', cm):
1367 if cm != self.config(b'color', b'pagermode', cm):
1352 color.setup(self)
1368 color.setup(self)
1353 else:
1369 else:
1354 # If the pager can't be spawned in dispatch when --pager=on is
1370 # If the pager can't be spawned in dispatch when --pager=on is
1355 # given, don't try again when the command runs, to avoid a duplicate
1371 # given, don't try again when the command runs, to avoid a duplicate
1356 # warning about a missing pager command.
1372 # warning about a missing pager command.
1357 self.disablepager()
1373 self.disablepager()
1358
1374
1359 def _runpager(self, command, env=None):
1375 def _runpager(self, command, env=None):
1360 """Actually start the pager and set up file descriptors.
1376 """Actually start the pager and set up file descriptors.
1361
1377
1362 This is separate in part so that extensions (like chg) can
1378 This is separate in part so that extensions (like chg) can
1363 override how a pager is invoked.
1379 override how a pager is invoked.
1364 """
1380 """
1365 if command == b'cat':
1381 if command == b'cat':
1366 # Save ourselves some work.
1382 # Save ourselves some work.
1367 return False
1383 return False
1368 # If the command doesn't contain any of these characters, we
1384 # If the command doesn't contain any of these characters, we
1369 # assume it's a binary and exec it directly. This means for
1385 # assume it's a binary and exec it directly. This means for
1370 # simple pager command configurations, we can degrade
1386 # simple pager command configurations, we can degrade
1371 # gracefully and tell the user about their broken pager.
1387 # gracefully and tell the user about their broken pager.
1372 shell = any(c in command for c in b"|&;<>()$`\\\"' \t\n*?[#~=%")
1388 shell = any(c in command for c in b"|&;<>()$`\\\"' \t\n*?[#~=%")
1373
1389
1374 if pycompat.iswindows and not shell:
1390 if pycompat.iswindows and not shell:
1375 # Window's built-in `more` cannot be invoked with shell=False, but
1391 # Window's built-in `more` cannot be invoked with shell=False, but
1376 # its `more.com` can. Hide this implementation detail from the
1392 # its `more.com` can. Hide this implementation detail from the
1377 # user so we can also get sane bad PAGER behavior. MSYS has
1393 # user so we can also get sane bad PAGER behavior. MSYS has
1378 # `more.exe`, so do a cmd.exe style resolution of the executable to
1394 # `more.exe`, so do a cmd.exe style resolution of the executable to
1379 # determine which one to use.
1395 # determine which one to use.
1380 fullcmd = procutil.findexe(command)
1396 fullcmd = procutil.findexe(command)
1381 if not fullcmd:
1397 if not fullcmd:
1382 self.warn(
1398 self.warn(
1383 _(b"missing pager command '%s', skipping pager\n") % command
1399 _(b"missing pager command '%s', skipping pager\n") % command
1384 )
1400 )
1385 return False
1401 return False
1386
1402
1387 command = fullcmd
1403 command = fullcmd
1388
1404
1389 try:
1405 try:
1390 pager = subprocess.Popen(
1406 pager = subprocess.Popen(
1391 procutil.tonativestr(command),
1407 procutil.tonativestr(command),
1392 shell=shell,
1408 shell=shell,
1393 bufsize=-1,
1409 bufsize=-1,
1394 close_fds=procutil.closefds,
1410 close_fds=procutil.closefds,
1395 stdin=subprocess.PIPE,
1411 stdin=subprocess.PIPE,
1396 stdout=procutil.stdout,
1412 stdout=procutil.stdout,
1397 stderr=procutil.stderr,
1413 stderr=procutil.stderr,
1398 env=procutil.tonativeenv(procutil.shellenviron(env)),
1414 env=procutil.tonativeenv(procutil.shellenviron(env)),
1399 )
1415 )
1400 except OSError as e:
1416 except OSError as e:
1401 if e.errno == errno.ENOENT and not shell:
1417 if e.errno == errno.ENOENT and not shell:
1402 self.warn(
1418 self.warn(
1403 _(b"missing pager command '%s', skipping pager\n") % command
1419 _(b"missing pager command '%s', skipping pager\n") % command
1404 )
1420 )
1405 return False
1421 return False
1406 raise
1422 raise
1407
1423
1408 # back up original file descriptors
1424 # back up original file descriptors
1409 stdoutfd = os.dup(procutil.stdout.fileno())
1425 stdoutfd = os.dup(procutil.stdout.fileno())
1410 stderrfd = os.dup(procutil.stderr.fileno())
1426 stderrfd = os.dup(procutil.stderr.fileno())
1411
1427
1412 os.dup2(pager.stdin.fileno(), procutil.stdout.fileno())
1428 os.dup2(pager.stdin.fileno(), procutil.stdout.fileno())
1413 if self._isatty(procutil.stderr):
1429 if self._isatty(procutil.stderr):
1414 os.dup2(pager.stdin.fileno(), procutil.stderr.fileno())
1430 os.dup2(pager.stdin.fileno(), procutil.stderr.fileno())
1415
1431
1416 @self.atexit
1432 @self.atexit
1417 def killpager():
1433 def killpager():
1418 if util.safehasattr(signal, b"SIGINT"):
1434 if util.safehasattr(signal, b"SIGINT"):
1419 signal.signal(signal.SIGINT, signal.SIG_IGN)
1435 signal.signal(signal.SIGINT, signal.SIG_IGN)
1420 # restore original fds, closing pager.stdin copies in the process
1436 # restore original fds, closing pager.stdin copies in the process
1421 os.dup2(stdoutfd, procutil.stdout.fileno())
1437 os.dup2(stdoutfd, procutil.stdout.fileno())
1422 os.dup2(stderrfd, procutil.stderr.fileno())
1438 os.dup2(stderrfd, procutil.stderr.fileno())
1423 pager.stdin.close()
1439 pager.stdin.close()
1424 pager.wait()
1440 pager.wait()
1425
1441
1426 return True
1442 return True
1427
1443
1428 @property
1444 @property
1429 def _exithandlers(self):
1445 def _exithandlers(self):
1430 return _reqexithandlers
1446 return _reqexithandlers
1431
1447
1432 def atexit(self, func, *args, **kwargs):
1448 def atexit(self, func, *args, **kwargs):
1433 '''register a function to run after dispatching a request
1449 '''register a function to run after dispatching a request
1434
1450
1435 Handlers do not stay registered across request boundaries.'''
1451 Handlers do not stay registered across request boundaries.'''
1436 self._exithandlers.append((func, args, kwargs))
1452 self._exithandlers.append((func, args, kwargs))
1437 return func
1453 return func
1438
1454
1439 def interface(self, feature):
1455 def interface(self, feature):
1440 """what interface to use for interactive console features?
1456 """what interface to use for interactive console features?
1441
1457
1442 The interface is controlled by the value of `ui.interface` but also by
1458 The interface is controlled by the value of `ui.interface` but also by
1443 the value of feature-specific configuration. For example:
1459 the value of feature-specific configuration. For example:
1444
1460
1445 ui.interface.histedit = text
1461 ui.interface.histedit = text
1446 ui.interface.chunkselector = curses
1462 ui.interface.chunkselector = curses
1447
1463
1448 Here the features are "histedit" and "chunkselector".
1464 Here the features are "histedit" and "chunkselector".
1449
1465
1450 The configuration above means that the default interfaces for commands
1466 The configuration above means that the default interfaces for commands
1451 is curses, the interface for histedit is text and the interface for
1467 is curses, the interface for histedit is text and the interface for
1452 selecting chunk is crecord (the best curses interface available).
1468 selecting chunk is crecord (the best curses interface available).
1453
1469
1454 Consider the following example:
1470 Consider the following example:
1455 ui.interface = curses
1471 ui.interface = curses
1456 ui.interface.histedit = text
1472 ui.interface.histedit = text
1457
1473
1458 Then histedit will use the text interface and chunkselector will use
1474 Then histedit will use the text interface and chunkselector will use
1459 the default curses interface (crecord at the moment).
1475 the default curses interface (crecord at the moment).
1460 """
1476 """
1461 alldefaults = frozenset([b"text", b"curses"])
1477 alldefaults = frozenset([b"text", b"curses"])
1462
1478
1463 featureinterfaces = {
1479 featureinterfaces = {
1464 b"chunkselector": [b"text", b"curses",],
1480 b"chunkselector": [b"text", b"curses",],
1465 b"histedit": [b"text", b"curses",],
1481 b"histedit": [b"text", b"curses",],
1466 }
1482 }
1467
1483
1468 # Feature-specific interface
1484 # Feature-specific interface
1469 if feature not in featureinterfaces.keys():
1485 if feature not in featureinterfaces.keys():
1470 # Programming error, not user error
1486 # Programming error, not user error
1471 raise ValueError(b"Unknown feature requested %s" % feature)
1487 raise ValueError(b"Unknown feature requested %s" % feature)
1472
1488
1473 availableinterfaces = frozenset(featureinterfaces[feature])
1489 availableinterfaces = frozenset(featureinterfaces[feature])
1474 if alldefaults > availableinterfaces:
1490 if alldefaults > availableinterfaces:
1475 # Programming error, not user error. We need a use case to
1491 # Programming error, not user error. We need a use case to
1476 # define the right thing to do here.
1492 # define the right thing to do here.
1477 raise ValueError(
1493 raise ValueError(
1478 b"Feature %s does not handle all default interfaces" % feature
1494 b"Feature %s does not handle all default interfaces" % feature
1479 )
1495 )
1480
1496
1481 if self.plain() or encoding.environ.get(b'TERM') == b'dumb':
1497 if self.plain() or encoding.environ.get(b'TERM') == b'dumb':
1482 return b"text"
1498 return b"text"
1483
1499
1484 # Default interface for all the features
1500 # Default interface for all the features
1485 defaultinterface = b"text"
1501 defaultinterface = b"text"
1486 i = self.config(b"ui", b"interface")
1502 i = self.config(b"ui", b"interface")
1487 if i in alldefaults:
1503 if i in alldefaults:
1488 defaultinterface = i
1504 defaultinterface = i
1489
1505
1490 choseninterface = defaultinterface
1506 choseninterface = defaultinterface
1491 f = self.config(b"ui", b"interface.%s" % feature)
1507 f = self.config(b"ui", b"interface.%s" % feature)
1492 if f in availableinterfaces:
1508 if f in availableinterfaces:
1493 choseninterface = f
1509 choseninterface = f
1494
1510
1495 if i is not None and defaultinterface != i:
1511 if i is not None and defaultinterface != i:
1496 if f is not None:
1512 if f is not None:
1497 self.warn(_(b"invalid value for ui.interface: %s\n") % (i,))
1513 self.warn(_(b"invalid value for ui.interface: %s\n") % (i,))
1498 else:
1514 else:
1499 self.warn(
1515 self.warn(
1500 _(b"invalid value for ui.interface: %s (using %s)\n")
1516 _(b"invalid value for ui.interface: %s (using %s)\n")
1501 % (i, choseninterface)
1517 % (i, choseninterface)
1502 )
1518 )
1503 if f is not None and choseninterface != f:
1519 if f is not None and choseninterface != f:
1504 self.warn(
1520 self.warn(
1505 _(b"invalid value for ui.interface.%s: %s (using %s)\n")
1521 _(b"invalid value for ui.interface.%s: %s (using %s)\n")
1506 % (feature, f, choseninterface)
1522 % (feature, f, choseninterface)
1507 )
1523 )
1508
1524
1509 return choseninterface
1525 return choseninterface
1510
1526
1511 def interactive(self):
1527 def interactive(self):
1512 '''is interactive input allowed?
1528 '''is interactive input allowed?
1513
1529
1514 An interactive session is a session where input can be reasonably read
1530 An interactive session is a session where input can be reasonably read
1515 from `sys.stdin'. If this function returns false, any attempt to read
1531 from `sys.stdin'. If this function returns false, any attempt to read
1516 from stdin should fail with an error, unless a sensible default has been
1532 from stdin should fail with an error, unless a sensible default has been
1517 specified.
1533 specified.
1518
1534
1519 Interactiveness is triggered by the value of the `ui.interactive'
1535 Interactiveness is triggered by the value of the `ui.interactive'
1520 configuration variable or - if it is unset - when `sys.stdin' points
1536 configuration variable or - if it is unset - when `sys.stdin' points
1521 to a terminal device.
1537 to a terminal device.
1522
1538
1523 This function refers to input only; for output, see `ui.formatted()'.
1539 This function refers to input only; for output, see `ui.formatted()'.
1524 '''
1540 '''
1525 i = self.configbool(b"ui", b"interactive")
1541 i = self.configbool(b"ui", b"interactive")
1526 if i is None:
1542 if i is None:
1527 # some environments replace stdin without implementing isatty
1543 # some environments replace stdin without implementing isatty
1528 # usually those are non-interactive
1544 # usually those are non-interactive
1529 return self._isatty(self._fin)
1545 return self._isatty(self._fin)
1530
1546
1531 return i
1547 return i
1532
1548
1533 def termwidth(self):
1549 def termwidth(self):
1534 '''how wide is the terminal in columns?
1550 '''how wide is the terminal in columns?
1535 '''
1551 '''
1536 if b'COLUMNS' in encoding.environ:
1552 if b'COLUMNS' in encoding.environ:
1537 try:
1553 try:
1538 return int(encoding.environ[b'COLUMNS'])
1554 return int(encoding.environ[b'COLUMNS'])
1539 except ValueError:
1555 except ValueError:
1540 pass
1556 pass
1541 return scmutil.termsize(self)[0]
1557 return scmutil.termsize(self)[0]
1542
1558
1543 def formatted(self):
1559 def formatted(self):
1544 '''should formatted output be used?
1560 '''should formatted output be used?
1545
1561
1546 It is often desirable to format the output to suite the output medium.
1562 It is often desirable to format the output to suite the output medium.
1547 Examples of this are truncating long lines or colorizing messages.
1563 Examples of this are truncating long lines or colorizing messages.
1548 However, this is not often not desirable when piping output into other
1564 However, this is not often not desirable when piping output into other
1549 utilities, e.g. `grep'.
1565 utilities, e.g. `grep'.
1550
1566
1551 Formatted output is triggered by the value of the `ui.formatted'
1567 Formatted output is triggered by the value of the `ui.formatted'
1552 configuration variable or - if it is unset - when `sys.stdout' points
1568 configuration variable or - if it is unset - when `sys.stdout' points
1553 to a terminal device. Please note that `ui.formatted' should be
1569 to a terminal device. Please note that `ui.formatted' should be
1554 considered an implementation detail; it is not intended for use outside
1570 considered an implementation detail; it is not intended for use outside
1555 Mercurial or its extensions.
1571 Mercurial or its extensions.
1556
1572
1557 This function refers to output only; for input, see `ui.interactive()'.
1573 This function refers to output only; for input, see `ui.interactive()'.
1558 This function always returns false when in plain mode, see `ui.plain()'.
1574 This function always returns false when in plain mode, see `ui.plain()'.
1559 '''
1575 '''
1560 if self.plain():
1576 if self.plain():
1561 return False
1577 return False
1562
1578
1563 i = self.configbool(b"ui", b"formatted")
1579 i = self.configbool(b"ui", b"formatted")
1564 if i is None:
1580 if i is None:
1565 # some environments replace stdout without implementing isatty
1581 # some environments replace stdout without implementing isatty
1566 # usually those are non-interactive
1582 # usually those are non-interactive
1567 return self._isatty(self._fout)
1583 return self._isatty(self._fout)
1568
1584
1569 return i
1585 return i
1570
1586
1571 def _readline(self, prompt=b' ', promptopts=None):
1587 def _readline(self, prompt=b' ', promptopts=None):
1572 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1588 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1573 # because they have to be text streams with *no buffering*. Instead,
1589 # because they have to be text streams with *no buffering*. Instead,
1574 # we use rawinput() only if call_readline() will be invoked by
1590 # we use rawinput() only if call_readline() will be invoked by
1575 # PyOS_Readline(), so no I/O will be made at Python layer.
1591 # PyOS_Readline(), so no I/O will be made at Python layer.
1576 usereadline = (
1592 usereadline = (
1577 self._isatty(self._fin)
1593 self._isatty(self._fin)
1578 and self._isatty(self._fout)
1594 and self._isatty(self._fout)
1579 and procutil.isstdin(self._fin)
1595 and procutil.isstdin(self._fin)
1580 and procutil.isstdout(self._fout)
1596 and procutil.isstdout(self._fout)
1581 )
1597 )
1582 if usereadline:
1598 if usereadline:
1583 try:
1599 try:
1584 # magically add command line editing support, where
1600 # magically add command line editing support, where
1585 # available
1601 # available
1586 import readline
1602 import readline
1587
1603
1588 # force demandimport to really load the module
1604 # force demandimport to really load the module
1589 readline.read_history_file
1605 readline.read_history_file
1590 # windows sometimes raises something other than ImportError
1606 # windows sometimes raises something other than ImportError
1591 except Exception:
1607 except Exception:
1592 usereadline = False
1608 usereadline = False
1593
1609
1594 if self._colormode == b'win32' or not usereadline:
1610 if self._colormode == b'win32' or not usereadline:
1595 if not promptopts:
1611 if not promptopts:
1596 promptopts = {}
1612 promptopts = {}
1597 self._writemsgnobuf(
1613 self._writemsgnobuf(
1598 self._fmsgout, prompt, type=b'prompt', **promptopts
1614 self._fmsgout, prompt, type=b'prompt', **promptopts
1599 )
1615 )
1600 self.flush()
1616 self.flush()
1601 prompt = b' '
1617 prompt = b' '
1602 else:
1618 else:
1603 prompt = self.label(prompt, b'ui.prompt') + b' '
1619 prompt = self.label(prompt, b'ui.prompt') + b' '
1604
1620
1605 # prompt ' ' must exist; otherwise readline may delete entire line
1621 # prompt ' ' must exist; otherwise readline may delete entire line
1606 # - http://bugs.python.org/issue12833
1622 # - http://bugs.python.org/issue12833
1607 with self.timeblockedsection(b'stdio'):
1623 with self.timeblockedsection(b'stdio'):
1608 if usereadline:
1624 if usereadline:
1609 self.flush()
1625 self.flush()
1610 prompt = encoding.strfromlocal(prompt)
1626 prompt = encoding.strfromlocal(prompt)
1611 line = encoding.strtolocal(pycompat.rawinput(prompt))
1627 line = encoding.strtolocal(pycompat.rawinput(prompt))
1612 # When stdin is in binary mode on Windows, it can cause
1628 # When stdin is in binary mode on Windows, it can cause
1613 # raw_input() to emit an extra trailing carriage return
1629 # raw_input() to emit an extra trailing carriage return
1614 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'):
1630 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'):
1615 line = line[:-1]
1631 line = line[:-1]
1616 else:
1632 else:
1617 self._fout.write(pycompat.bytestr(prompt))
1633 self._fout.write(pycompat.bytestr(prompt))
1618 self._fout.flush()
1634 self._fout.flush()
1619 line = self._fin.readline()
1635 line = self._fin.readline()
1620 if not line:
1636 if not line:
1621 raise EOFError
1637 raise EOFError
1622 line = line.rstrip(pycompat.oslinesep)
1638 line = line.rstrip(pycompat.oslinesep)
1623
1639
1624 return line
1640 return line
1625
1641
1626 def prompt(self, msg, default=b"y"):
1642 def prompt(self, msg, default=b"y"):
1627 """Prompt user with msg, read response.
1643 """Prompt user with msg, read response.
1628 If ui is not interactive, the default is returned.
1644 If ui is not interactive, the default is returned.
1629 """
1645 """
1630 return self._prompt(msg, default=default)
1646 return self._prompt(msg, default=default)
1631
1647
1632 def _prompt(self, msg, **opts):
1648 def _prompt(self, msg, **opts):
1633 default = opts['default']
1649 default = opts['default']
1634 if not self.interactive():
1650 if not self.interactive():
1635 self._writemsg(self._fmsgout, msg, b' ', type=b'prompt', **opts)
1651 self._writemsg(self._fmsgout, msg, b' ', type=b'prompt', **opts)
1636 self._writemsg(
1652 self._writemsg(
1637 self._fmsgout, default or b'', b"\n", type=b'promptecho'
1653 self._fmsgout, default or b'', b"\n", type=b'promptecho'
1638 )
1654 )
1639 return default
1655 return default
1640 try:
1656 try:
1641 r = self._readline(prompt=msg, promptopts=opts)
1657 r = self._readline(prompt=msg, promptopts=opts)
1642 if not r:
1658 if not r:
1643 r = default
1659 r = default
1644 if self.configbool(b'ui', b'promptecho'):
1660 if self.configbool(b'ui', b'promptecho'):
1645 self._writemsg(self._fmsgout, r, b"\n", type=b'promptecho')
1661 self._writemsg(self._fmsgout, r, b"\n", type=b'promptecho')
1646 return r
1662 return r
1647 except EOFError:
1663 except EOFError:
1648 raise error.ResponseExpected()
1664 raise error.ResponseExpected()
1649
1665
1650 @staticmethod
1666 @staticmethod
1651 def extractchoices(prompt):
1667 def extractchoices(prompt):
1652 """Extract prompt message and list of choices from specified prompt.
1668 """Extract prompt message and list of choices from specified prompt.
1653
1669
1654 This returns tuple "(message, choices)", and "choices" is the
1670 This returns tuple "(message, choices)", and "choices" is the
1655 list of tuple "(response character, text without &)".
1671 list of tuple "(response character, text without &)".
1656
1672
1657 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1673 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1658 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1674 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1659 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1675 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1660 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1676 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1661 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1677 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1662 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1678 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1663 """
1679 """
1664
1680
1665 # Sadly, the prompt string may have been built with a filename
1681 # Sadly, the prompt string may have been built with a filename
1666 # containing "$$" so let's try to find the first valid-looking
1682 # containing "$$" so let's try to find the first valid-looking
1667 # prompt to start parsing. Sadly, we also can't rely on
1683 # prompt to start parsing. Sadly, we also can't rely on
1668 # choices containing spaces, ASCII, or basically anything
1684 # choices containing spaces, ASCII, or basically anything
1669 # except an ampersand followed by a character.
1685 # except an ampersand followed by a character.
1670 m = re.match(br'(?s)(.+?)\$\$([^$]*&[^ $].*)', prompt)
1686 m = re.match(br'(?s)(.+?)\$\$([^$]*&[^ $].*)', prompt)
1671 msg = m.group(1)
1687 msg = m.group(1)
1672 choices = [p.strip(b' ') for p in m.group(2).split(b'$$')]
1688 choices = [p.strip(b' ') for p in m.group(2).split(b'$$')]
1673
1689
1674 def choicetuple(s):
1690 def choicetuple(s):
1675 ampidx = s.index(b'&')
1691 ampidx = s.index(b'&')
1676 return s[ampidx + 1 : ampidx + 2].lower(), s.replace(b'&', b'', 1)
1692 return s[ampidx + 1 : ampidx + 2].lower(), s.replace(b'&', b'', 1)
1677
1693
1678 return (msg, [choicetuple(s) for s in choices])
1694 return (msg, [choicetuple(s) for s in choices])
1679
1695
1680 def promptchoice(self, prompt, default=0):
1696 def promptchoice(self, prompt, default=0):
1681 """Prompt user with a message, read response, and ensure it matches
1697 """Prompt user with a message, read response, and ensure it matches
1682 one of the provided choices. The prompt is formatted as follows:
1698 one of the provided choices. The prompt is formatted as follows:
1683
1699
1684 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1700 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1685
1701
1686 The index of the choice is returned. Responses are case
1702 The index of the choice is returned. Responses are case
1687 insensitive. If ui is not interactive, the default is
1703 insensitive. If ui is not interactive, the default is
1688 returned.
1704 returned.
1689 """
1705 """
1690
1706
1691 msg, choices = self.extractchoices(prompt)
1707 msg, choices = self.extractchoices(prompt)
1692 resps = [r for r, t in choices]
1708 resps = [r for r, t in choices]
1693 while True:
1709 while True:
1694 r = self._prompt(msg, default=resps[default], choices=choices)
1710 r = self._prompt(msg, default=resps[default], choices=choices)
1695 if r.lower() in resps:
1711 if r.lower() in resps:
1696 return resps.index(r.lower())
1712 return resps.index(r.lower())
1697 # TODO: shouldn't it be a warning?
1713 # TODO: shouldn't it be a warning?
1698 self._writemsg(self._fmsgout, _(b"unrecognized response\n"))
1714 self._writemsg(self._fmsgout, _(b"unrecognized response\n"))
1699
1715
1700 def getpass(self, prompt=None, default=None):
1716 def getpass(self, prompt=None, default=None):
1701 if not self.interactive():
1717 if not self.interactive():
1702 return default
1718 return default
1703 try:
1719 try:
1704 self._writemsg(
1720 self._writemsg(
1705 self._fmsgerr,
1721 self._fmsgerr,
1706 prompt or _(b'password: '),
1722 prompt or _(b'password: '),
1707 type=b'prompt',
1723 type=b'prompt',
1708 password=True,
1724 password=True,
1709 )
1725 )
1710 # disable getpass() only if explicitly specified. it's still valid
1726 # disable getpass() only if explicitly specified. it's still valid
1711 # to interact with tty even if fin is not a tty.
1727 # to interact with tty even if fin is not a tty.
1712 with self.timeblockedsection(b'stdio'):
1728 with self.timeblockedsection(b'stdio'):
1713 if self.configbool(b'ui', b'nontty'):
1729 if self.configbool(b'ui', b'nontty'):
1714 l = self._fin.readline()
1730 l = self._fin.readline()
1715 if not l:
1731 if not l:
1716 raise EOFError
1732 raise EOFError
1717 return l.rstrip(b'\n')
1733 return l.rstrip(b'\n')
1718 else:
1734 else:
1719 return getpass.getpass('')
1735 return getpass.getpass('')
1720 except EOFError:
1736 except EOFError:
1721 raise error.ResponseExpected()
1737 raise error.ResponseExpected()
1722
1738
1723 def status(self, *msg, **opts):
1739 def status(self, *msg, **opts):
1724 '''write status message to output (if ui.quiet is False)
1740 '''write status message to output (if ui.quiet is False)
1725
1741
1726 This adds an output label of "ui.status".
1742 This adds an output label of "ui.status".
1727 '''
1743 '''
1728 if not self.quiet:
1744 if not self.quiet:
1729 self._writemsg(self._fmsgout, type=b'status', *msg, **opts)
1745 self._writemsg(self._fmsgout, type=b'status', *msg, **opts)
1730
1746
1731 def warn(self, *msg, **opts):
1747 def warn(self, *msg, **opts):
1732 '''write warning message to output (stderr)
1748 '''write warning message to output (stderr)
1733
1749
1734 This adds an output label of "ui.warning".
1750 This adds an output label of "ui.warning".
1735 '''
1751 '''
1736 self._writemsg(self._fmsgerr, type=b'warning', *msg, **opts)
1752 self._writemsg(self._fmsgerr, type=b'warning', *msg, **opts)
1737
1753
1738 def error(self, *msg, **opts):
1754 def error(self, *msg, **opts):
1739 '''write error message to output (stderr)
1755 '''write error message to output (stderr)
1740
1756
1741 This adds an output label of "ui.error".
1757 This adds an output label of "ui.error".
1742 '''
1758 '''
1743 self._writemsg(self._fmsgerr, type=b'error', *msg, **opts)
1759 self._writemsg(self._fmsgerr, type=b'error', *msg, **opts)
1744
1760
1745 def note(self, *msg, **opts):
1761 def note(self, *msg, **opts):
1746 '''write note to output (if ui.verbose is True)
1762 '''write note to output (if ui.verbose is True)
1747
1763
1748 This adds an output label of "ui.note".
1764 This adds an output label of "ui.note".
1749 '''
1765 '''
1750 if self.verbose:
1766 if self.verbose:
1751 self._writemsg(self._fmsgout, type=b'note', *msg, **opts)
1767 self._writemsg(self._fmsgout, type=b'note', *msg, **opts)
1752
1768
1753 def debug(self, *msg, **opts):
1769 def debug(self, *msg, **opts):
1754 '''write debug message to output (if ui.debugflag is True)
1770 '''write debug message to output (if ui.debugflag is True)
1755
1771
1756 This adds an output label of "ui.debug".
1772 This adds an output label of "ui.debug".
1757 '''
1773 '''
1758 if self.debugflag:
1774 if self.debugflag:
1759 self._writemsg(self._fmsgout, type=b'debug', *msg, **opts)
1775 self._writemsg(self._fmsgout, type=b'debug', *msg, **opts)
1760 self.log(b'debug', b'%s', b''.join(msg))
1776 self.log(b'debug', b'%s', b''.join(msg))
1761
1777
1762 # Aliases to defeat check-code.
1778 # Aliases to defeat check-code.
1763 statusnoi18n = status
1779 statusnoi18n = status
1764 notenoi18n = note
1780 notenoi18n = note
1765 warnnoi18n = warn
1781 warnnoi18n = warn
1766 writenoi18n = write
1782 writenoi18n = write
1767
1783
1768 def edit(
1784 def edit(
1769 self,
1785 self,
1770 text,
1786 text,
1771 user,
1787 user,
1772 extra=None,
1788 extra=None,
1773 editform=None,
1789 editform=None,
1774 pending=None,
1790 pending=None,
1775 repopath=None,
1791 repopath=None,
1776 action=None,
1792 action=None,
1777 ):
1793 ):
1778 if action is None:
1794 if action is None:
1779 self.develwarn(
1795 self.develwarn(
1780 b'action is None but will soon be a required '
1796 b'action is None but will soon be a required '
1781 b'parameter to ui.edit()'
1797 b'parameter to ui.edit()'
1782 )
1798 )
1783 extra_defaults = {
1799 extra_defaults = {
1784 b'prefix': b'editor',
1800 b'prefix': b'editor',
1785 b'suffix': b'.txt',
1801 b'suffix': b'.txt',
1786 }
1802 }
1787 if extra is not None:
1803 if extra is not None:
1788 if extra.get(b'suffix') is not None:
1804 if extra.get(b'suffix') is not None:
1789 self.develwarn(
1805 self.develwarn(
1790 b'extra.suffix is not None but will soon be '
1806 b'extra.suffix is not None but will soon be '
1791 b'ignored by ui.edit()'
1807 b'ignored by ui.edit()'
1792 )
1808 )
1793 extra_defaults.update(extra)
1809 extra_defaults.update(extra)
1794 extra = extra_defaults
1810 extra = extra_defaults
1795
1811
1796 if action == b'diff':
1812 if action == b'diff':
1797 suffix = b'.diff'
1813 suffix = b'.diff'
1798 elif action:
1814 elif action:
1799 suffix = b'.%s.hg.txt' % action
1815 suffix = b'.%s.hg.txt' % action
1800 else:
1816 else:
1801 suffix = extra[b'suffix']
1817 suffix = extra[b'suffix']
1802
1818
1803 rdir = None
1819 rdir = None
1804 if self.configbool(b'experimental', b'editortmpinhg'):
1820 if self.configbool(b'experimental', b'editortmpinhg'):
1805 rdir = repopath
1821 rdir = repopath
1806 (fd, name) = pycompat.mkstemp(
1822 (fd, name) = pycompat.mkstemp(
1807 prefix=b'hg-' + extra[b'prefix'] + b'-', suffix=suffix, dir=rdir
1823 prefix=b'hg-' + extra[b'prefix'] + b'-', suffix=suffix, dir=rdir
1808 )
1824 )
1809 try:
1825 try:
1810 with os.fdopen(fd, 'wb') as f:
1826 with os.fdopen(fd, 'wb') as f:
1811 f.write(util.tonativeeol(text))
1827 f.write(util.tonativeeol(text))
1812
1828
1813 environ = {b'HGUSER': user}
1829 environ = {b'HGUSER': user}
1814 if b'transplant_source' in extra:
1830 if b'transplant_source' in extra:
1815 environ.update(
1831 environ.update(
1816 {b'HGREVISION': hex(extra[b'transplant_source'])}
1832 {b'HGREVISION': hex(extra[b'transplant_source'])}
1817 )
1833 )
1818 for label in (b'intermediate-source', b'source', b'rebase_source'):
1834 for label in (b'intermediate-source', b'source', b'rebase_source'):
1819 if label in extra:
1835 if label in extra:
1820 environ.update({b'HGREVISION': extra[label]})
1836 environ.update({b'HGREVISION': extra[label]})
1821 break
1837 break
1822 if editform:
1838 if editform:
1823 environ.update({b'HGEDITFORM': editform})
1839 environ.update({b'HGEDITFORM': editform})
1824 if pending:
1840 if pending:
1825 environ.update({b'HG_PENDING': pending})
1841 environ.update({b'HG_PENDING': pending})
1826
1842
1827 editor = self.geteditor()
1843 editor = self.geteditor()
1828
1844
1829 self.system(
1845 self.system(
1830 b"%s \"%s\"" % (editor, name),
1846 b"%s \"%s\"" % (editor, name),
1831 environ=environ,
1847 environ=environ,
1832 onerr=error.Abort,
1848 onerr=error.Abort,
1833 errprefix=_(b"edit failed"),
1849 errprefix=_(b"edit failed"),
1834 blockedtag=b'editor',
1850 blockedtag=b'editor',
1835 )
1851 )
1836
1852
1837 with open(name, 'rb') as f:
1853 with open(name, 'rb') as f:
1838 t = util.fromnativeeol(f.read())
1854 t = util.fromnativeeol(f.read())
1839 finally:
1855 finally:
1840 os.unlink(name)
1856 os.unlink(name)
1841
1857
1842 return t
1858 return t
1843
1859
1844 def system(
1860 def system(
1845 self,
1861 self,
1846 cmd,
1862 cmd,
1847 environ=None,
1863 environ=None,
1848 cwd=None,
1864 cwd=None,
1849 onerr=None,
1865 onerr=None,
1850 errprefix=None,
1866 errprefix=None,
1851 blockedtag=None,
1867 blockedtag=None,
1852 ):
1868 ):
1853 '''execute shell command with appropriate output stream. command
1869 '''execute shell command with appropriate output stream. command
1854 output will be redirected if fout is not stdout.
1870 output will be redirected if fout is not stdout.
1855
1871
1856 if command fails and onerr is None, return status, else raise onerr
1872 if command fails and onerr is None, return status, else raise onerr
1857 object as exception.
1873 object as exception.
1858 '''
1874 '''
1859 if blockedtag is None:
1875 if blockedtag is None:
1860 # Long cmds tend to be because of an absolute path on cmd. Keep
1876 # Long cmds tend to be because of an absolute path on cmd. Keep
1861 # the tail end instead
1877 # the tail end instead
1862 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1878 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1863 blockedtag = b'unknown_system_' + cmdsuffix
1879 blockedtag = b'unknown_system_' + cmdsuffix
1864 out = self._fout
1880 out = self._fout
1865 if any(s[1] for s in self._bufferstates):
1881 if any(s[1] for s in self._bufferstates):
1866 out = self
1882 out = self
1867 with self.timeblockedsection(blockedtag):
1883 with self.timeblockedsection(blockedtag):
1868 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1884 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1869 if rc and onerr:
1885 if rc and onerr:
1870 errmsg = b'%s %s' % (
1886 errmsg = b'%s %s' % (
1871 procutil.shellsplit(cmd)[0],
1887 procutil.shellsplit(cmd)[0],
1872 procutil.explainexit(rc),
1888 procutil.explainexit(rc),
1873 )
1889 )
1874 if errprefix:
1890 if errprefix:
1875 errmsg = b'%s: %s' % (errprefix, errmsg)
1891 errmsg = b'%s: %s' % (errprefix, errmsg)
1876 raise onerr(errmsg)
1892 raise onerr(errmsg)
1877 return rc
1893 return rc
1878
1894
1879 def _runsystem(self, cmd, environ, cwd, out):
1895 def _runsystem(self, cmd, environ, cwd, out):
1880 """actually execute the given shell command (can be overridden by
1896 """actually execute the given shell command (can be overridden by
1881 extensions like chg)"""
1897 extensions like chg)"""
1882 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
1898 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
1883
1899
1884 def traceback(self, exc=None, force=False):
1900 def traceback(self, exc=None, force=False):
1885 '''print exception traceback if traceback printing enabled or forced.
1901 '''print exception traceback if traceback printing enabled or forced.
1886 only to call in exception handler. returns true if traceback
1902 only to call in exception handler. returns true if traceback
1887 printed.'''
1903 printed.'''
1888 if self.tracebackflag or force:
1904 if self.tracebackflag or force:
1889 if exc is None:
1905 if exc is None:
1890 exc = sys.exc_info()
1906 exc = sys.exc_info()
1891 cause = getattr(exc[1], 'cause', None)
1907 cause = getattr(exc[1], 'cause', None)
1892
1908
1893 if cause is not None:
1909 if cause is not None:
1894 causetb = traceback.format_tb(cause[2])
1910 causetb = traceback.format_tb(cause[2])
1895 exctb = traceback.format_tb(exc[2])
1911 exctb = traceback.format_tb(exc[2])
1896 exconly = traceback.format_exception_only(cause[0], cause[1])
1912 exconly = traceback.format_exception_only(cause[0], cause[1])
1897
1913
1898 # exclude frame where 'exc' was chained and rethrown from exctb
1914 # exclude frame where 'exc' was chained and rethrown from exctb
1899 self.write_err(
1915 self.write_err(
1900 b'Traceback (most recent call last):\n',
1916 b'Traceback (most recent call last):\n',
1901 encoding.strtolocal(''.join(exctb[:-1])),
1917 encoding.strtolocal(''.join(exctb[:-1])),
1902 encoding.strtolocal(''.join(causetb)),
1918 encoding.strtolocal(''.join(causetb)),
1903 encoding.strtolocal(''.join(exconly)),
1919 encoding.strtolocal(''.join(exconly)),
1904 )
1920 )
1905 else:
1921 else:
1906 output = traceback.format_exception(exc[0], exc[1], exc[2])
1922 output = traceback.format_exception(exc[0], exc[1], exc[2])
1907 self.write_err(encoding.strtolocal(''.join(output)))
1923 self.write_err(encoding.strtolocal(''.join(output)))
1908 return self.tracebackflag or force
1924 return self.tracebackflag or force
1909
1925
1910 def geteditor(self):
1926 def geteditor(self):
1911 '''return editor to use'''
1927 '''return editor to use'''
1912 if pycompat.sysplatform == b'plan9':
1928 if pycompat.sysplatform == b'plan9':
1913 # vi is the MIPS instruction simulator on Plan 9. We
1929 # vi is the MIPS instruction simulator on Plan 9. We
1914 # instead default to E to plumb commit messages to
1930 # instead default to E to plumb commit messages to
1915 # avoid confusion.
1931 # avoid confusion.
1916 editor = b'E'
1932 editor = b'E'
1917 elif pycompat.isdarwin:
1933 elif pycompat.isdarwin:
1918 # vi on darwin is POSIX compatible to a fault, and that includes
1934 # vi on darwin is POSIX compatible to a fault, and that includes
1919 # exiting non-zero if you make any mistake when running an ex
1935 # exiting non-zero if you make any mistake when running an ex
1920 # command. Proof: `vi -c ':unknown' -c ':qa'; echo $?` produces 1,
1936 # command. Proof: `vi -c ':unknown' -c ':qa'; echo $?` produces 1,
1921 # while s/vi/vim/ doesn't.
1937 # while s/vi/vim/ doesn't.
1922 editor = b'vim'
1938 editor = b'vim'
1923 else:
1939 else:
1924 editor = b'vi'
1940 editor = b'vi'
1925 return encoding.environ.get(b"HGEDITOR") or self.config(
1941 return encoding.environ.get(b"HGEDITOR") or self.config(
1926 b"ui", b"editor", editor
1942 b"ui", b"editor", editor
1927 )
1943 )
1928
1944
1929 @util.propertycache
1945 @util.propertycache
1930 def _progbar(self):
1946 def _progbar(self):
1931 """setup the progbar singleton to the ui object"""
1947 """setup the progbar singleton to the ui object"""
1932 if (
1948 if (
1933 self.quiet
1949 self.quiet
1934 or self.debugflag
1950 or self.debugflag
1935 or self.configbool(b'progress', b'disable')
1951 or self.configbool(b'progress', b'disable')
1936 or not progress.shouldprint(self)
1952 or not progress.shouldprint(self)
1937 ):
1953 ):
1938 return None
1954 return None
1939 return getprogbar(self)
1955 return getprogbar(self)
1940
1956
1941 def _progclear(self):
1957 def _progclear(self):
1942 """clear progress bar output if any. use it before any output"""
1958 """clear progress bar output if any. use it before any output"""
1943 if not haveprogbar(): # nothing loaded yet
1959 if not haveprogbar(): # nothing loaded yet
1944 return
1960 return
1945 if self._progbar is not None and self._progbar.printed:
1961 if self._progbar is not None and self._progbar.printed:
1946 self._progbar.clear()
1962 self._progbar.clear()
1947
1963
1948 def makeprogress(self, topic, unit=b"", total=None):
1964 def makeprogress(self, topic, unit=b"", total=None):
1949 """Create a progress helper for the specified topic"""
1965 """Create a progress helper for the specified topic"""
1950 if getattr(self._fmsgerr, 'structured', False):
1966 if getattr(self._fmsgerr, 'structured', False):
1951 # channel for machine-readable output with metadata, just send
1967 # channel for machine-readable output with metadata, just send
1952 # raw information
1968 # raw information
1953 # TODO: consider porting some useful information (e.g. estimated
1969 # TODO: consider porting some useful information (e.g. estimated
1954 # time) from progbar. we might want to support update delay to
1970 # time) from progbar. we might want to support update delay to
1955 # reduce the cost of transferring progress messages.
1971 # reduce the cost of transferring progress messages.
1956 def updatebar(topic, pos, item, unit, total):
1972 def updatebar(topic, pos, item, unit, total):
1957 self._fmsgerr.write(
1973 self._fmsgerr.write(
1958 None,
1974 None,
1959 type=b'progress',
1975 type=b'progress',
1960 topic=topic,
1976 topic=topic,
1961 pos=pos,
1977 pos=pos,
1962 item=item,
1978 item=item,
1963 unit=unit,
1979 unit=unit,
1964 total=total,
1980 total=total,
1965 )
1981 )
1966
1982
1967 elif self._progbar is not None:
1983 elif self._progbar is not None:
1968 updatebar = self._progbar.progress
1984 updatebar = self._progbar.progress
1969 else:
1985 else:
1970
1986
1971 def updatebar(topic, pos, item, unit, total):
1987 def updatebar(topic, pos, item, unit, total):
1972 pass
1988 pass
1973
1989
1974 return scmutil.progress(self, updatebar, topic, unit, total)
1990 return scmutil.progress(self, updatebar, topic, unit, total)
1975
1991
1976 def getlogger(self, name):
1992 def getlogger(self, name):
1977 """Returns a logger of the given name; or None if not registered"""
1993 """Returns a logger of the given name; or None if not registered"""
1978 return self._loggers.get(name)
1994 return self._loggers.get(name)
1979
1995
1980 def setlogger(self, name, logger):
1996 def setlogger(self, name, logger):
1981 """Install logger which can be identified later by the given name
1997 """Install logger which can be identified later by the given name
1982
1998
1983 More than one loggers can be registered. Use extension or module
1999 More than one loggers can be registered. Use extension or module
1984 name to uniquely identify the logger instance.
2000 name to uniquely identify the logger instance.
1985 """
2001 """
1986 self._loggers[name] = logger
2002 self._loggers[name] = logger
1987
2003
1988 def log(self, event, msgfmt, *msgargs, **opts):
2004 def log(self, event, msgfmt, *msgargs, **opts):
1989 '''hook for logging facility extensions
2005 '''hook for logging facility extensions
1990
2006
1991 event should be a readily-identifiable subsystem, which will
2007 event should be a readily-identifiable subsystem, which will
1992 allow filtering.
2008 allow filtering.
1993
2009
1994 msgfmt should be a newline-terminated format string to log, and
2010 msgfmt should be a newline-terminated format string to log, and
1995 *msgargs are %-formatted into it.
2011 *msgargs are %-formatted into it.
1996
2012
1997 **opts currently has no defined meanings.
2013 **opts currently has no defined meanings.
1998 '''
2014 '''
1999 if not self._loggers:
2015 if not self._loggers:
2000 return
2016 return
2001 activeloggers = [
2017 activeloggers = [
2002 l for l in pycompat.itervalues(self._loggers) if l.tracked(event)
2018 l for l in pycompat.itervalues(self._loggers) if l.tracked(event)
2003 ]
2019 ]
2004 if not activeloggers:
2020 if not activeloggers:
2005 return
2021 return
2006 msg = msgfmt % msgargs
2022 msg = msgfmt % msgargs
2007 opts = pycompat.byteskwargs(opts)
2023 opts = pycompat.byteskwargs(opts)
2008 # guard against recursion from e.g. ui.debug()
2024 # guard against recursion from e.g. ui.debug()
2009 registeredloggers = self._loggers
2025 registeredloggers = self._loggers
2010 self._loggers = {}
2026 self._loggers = {}
2011 try:
2027 try:
2012 for logger in activeloggers:
2028 for logger in activeloggers:
2013 logger.log(self, event, msg, opts)
2029 logger.log(self, event, msg, opts)
2014 finally:
2030 finally:
2015 self._loggers = registeredloggers
2031 self._loggers = registeredloggers
2016
2032
2017 def label(self, msg, label):
2033 def label(self, msg, label):
2018 '''style msg based on supplied label
2034 '''style msg based on supplied label
2019
2035
2020 If some color mode is enabled, this will add the necessary control
2036 If some color mode is enabled, this will add the necessary control
2021 characters to apply such color. In addition, 'debug' color mode adds
2037 characters to apply such color. In addition, 'debug' color mode adds
2022 markup showing which label affects a piece of text.
2038 markup showing which label affects a piece of text.
2023
2039
2024 ui.write(s, 'label') is equivalent to
2040 ui.write(s, 'label') is equivalent to
2025 ui.write(ui.label(s, 'label')).
2041 ui.write(ui.label(s, 'label')).
2026 '''
2042 '''
2027 if self._colormode is not None:
2043 if self._colormode is not None:
2028 return color.colorlabel(self, msg, label)
2044 return color.colorlabel(self, msg, label)
2029 return msg
2045 return msg
2030
2046
2031 def develwarn(self, msg, stacklevel=1, config=None):
2047 def develwarn(self, msg, stacklevel=1, config=None):
2032 """issue a developer warning message
2048 """issue a developer warning message
2033
2049
2034 Use 'stacklevel' to report the offender some layers further up in the
2050 Use 'stacklevel' to report the offender some layers further up in the
2035 stack.
2051 stack.
2036 """
2052 """
2037 if not self.configbool(b'devel', b'all-warnings'):
2053 if not self.configbool(b'devel', b'all-warnings'):
2038 if config is None or not self.configbool(b'devel', config):
2054 if config is None or not self.configbool(b'devel', config):
2039 return
2055 return
2040 msg = b'devel-warn: ' + msg
2056 msg = b'devel-warn: ' + msg
2041 stacklevel += 1 # get in develwarn
2057 stacklevel += 1 # get in develwarn
2042 if self.tracebackflag:
2058 if self.tracebackflag:
2043 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout)
2059 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout)
2044 self.log(
2060 self.log(
2045 b'develwarn',
2061 b'develwarn',
2046 b'%s at:\n%s'
2062 b'%s at:\n%s'
2047 % (msg, b''.join(util.getstackframes(stacklevel))),
2063 % (msg, b''.join(util.getstackframes(stacklevel))),
2048 )
2064 )
2049 else:
2065 else:
2050 curframe = inspect.currentframe()
2066 curframe = inspect.currentframe()
2051 calframe = inspect.getouterframes(curframe, 2)
2067 calframe = inspect.getouterframes(curframe, 2)
2052 fname, lineno, fmsg = calframe[stacklevel][1:4]
2068 fname, lineno, fmsg = calframe[stacklevel][1:4]
2053 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg)
2069 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg)
2054 self.write_err(b'%s at: %s:%d (%s)\n' % (msg, fname, lineno, fmsg))
2070 self.write_err(b'%s at: %s:%d (%s)\n' % (msg, fname, lineno, fmsg))
2055 self.log(
2071 self.log(
2056 b'develwarn', b'%s at: %s:%d (%s)\n', msg, fname, lineno, fmsg
2072 b'develwarn', b'%s at: %s:%d (%s)\n', msg, fname, lineno, fmsg
2057 )
2073 )
2058
2074
2059 # avoid cycles
2075 # avoid cycles
2060 del curframe
2076 del curframe
2061 del calframe
2077 del calframe
2062
2078
2063 def deprecwarn(self, msg, version, stacklevel=2):
2079 def deprecwarn(self, msg, version, stacklevel=2):
2064 """issue a deprecation warning
2080 """issue a deprecation warning
2065
2081
2066 - msg: message explaining what is deprecated and how to upgrade,
2082 - msg: message explaining what is deprecated and how to upgrade,
2067 - version: last version where the API will be supported,
2083 - version: last version where the API will be supported,
2068 """
2084 """
2069 if not (
2085 if not (
2070 self.configbool(b'devel', b'all-warnings')
2086 self.configbool(b'devel', b'all-warnings')
2071 or self.configbool(b'devel', b'deprec-warn')
2087 or self.configbool(b'devel', b'deprec-warn')
2072 ):
2088 ):
2073 return
2089 return
2074 msg += (
2090 msg += (
2075 b"\n(compatibility will be dropped after Mercurial-%s,"
2091 b"\n(compatibility will be dropped after Mercurial-%s,"
2076 b" update your code.)"
2092 b" update your code.)"
2077 ) % version
2093 ) % version
2078 self.develwarn(msg, stacklevel=stacklevel, config=b'deprec-warn')
2094 self.develwarn(msg, stacklevel=stacklevel, config=b'deprec-warn')
2079
2095
2080 def exportableenviron(self):
2096 def exportableenviron(self):
2081 """The environment variables that are safe to export, e.g. through
2097 """The environment variables that are safe to export, e.g. through
2082 hgweb.
2098 hgweb.
2083 """
2099 """
2084 return self._exportableenviron
2100 return self._exportableenviron
2085
2101
2086 @contextlib.contextmanager
2102 @contextlib.contextmanager
2087 def configoverride(self, overrides, source=b""):
2103 def configoverride(self, overrides, source=b""):
2088 """Context manager for temporary config overrides
2104 """Context manager for temporary config overrides
2089 `overrides` must be a dict of the following structure:
2105 `overrides` must be a dict of the following structure:
2090 {(section, name) : value}"""
2106 {(section, name) : value}"""
2091 backups = {}
2107 backups = {}
2092 try:
2108 try:
2093 for (section, name), value in overrides.items():
2109 for (section, name), value in overrides.items():
2094 backups[(section, name)] = self.backupconfig(section, name)
2110 backups[(section, name)] = self.backupconfig(section, name)
2095 self.setconfig(section, name, value, source)
2111 self.setconfig(section, name, value, source)
2096 yield
2112 yield
2097 finally:
2113 finally:
2098 for __, backup in backups.items():
2114 for __, backup in backups.items():
2099 self.restoreconfig(backup)
2115 self.restoreconfig(backup)
2100 # just restoring ui.quiet config to the previous value is not enough
2116 # just restoring ui.quiet config to the previous value is not enough
2101 # as it does not update ui.quiet class member
2117 # as it does not update ui.quiet class member
2102 if (b'ui', b'quiet') in overrides:
2118 if (b'ui', b'quiet') in overrides:
2103 self.fixconfig(section=b'ui')
2119 self.fixconfig(section=b'ui')
2104
2120
2105
2121
2106 class paths(dict):
2122 class paths(dict):
2107 """Represents a collection of paths and their configs.
2123 """Represents a collection of paths and their configs.
2108
2124
2109 Data is initially derived from ui instances and the config files they have
2125 Data is initially derived from ui instances and the config files they have
2110 loaded.
2126 loaded.
2111 """
2127 """
2112
2128
2113 def __init__(self, ui):
2129 def __init__(self, ui):
2114 dict.__init__(self)
2130 dict.__init__(self)
2115
2131
2116 for name, loc in ui.configitems(b'paths', ignoresub=True):
2132 for name, loc in ui.configitems(b'paths', ignoresub=True):
2117 # No location is the same as not existing.
2133 # No location is the same as not existing.
2118 if not loc:
2134 if not loc:
2119 continue
2135 continue
2120 loc, sub = ui.configsuboptions(b'paths', name)
2136 loc, sub = ui.configsuboptions(b'paths', name)
2121 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
2137 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
2122
2138
2123 def getpath(self, name, default=None):
2139 def getpath(self, name, default=None):
2124 """Return a ``path`` from a string, falling back to default.
2140 """Return a ``path`` from a string, falling back to default.
2125
2141
2126 ``name`` can be a named path or locations. Locations are filesystem
2142 ``name`` can be a named path or locations. Locations are filesystem
2127 paths or URIs.
2143 paths or URIs.
2128
2144
2129 Returns None if ``name`` is not a registered path, a URI, or a local
2145 Returns None if ``name`` is not a registered path, a URI, or a local
2130 path to a repo.
2146 path to a repo.
2131 """
2147 """
2132 # Only fall back to default if no path was requested.
2148 # Only fall back to default if no path was requested.
2133 if name is None:
2149 if name is None:
2134 if not default:
2150 if not default:
2135 default = ()
2151 default = ()
2136 elif not isinstance(default, (tuple, list)):
2152 elif not isinstance(default, (tuple, list)):
2137 default = (default,)
2153 default = (default,)
2138 for k in default:
2154 for k in default:
2139 try:
2155 try:
2140 return self[k]
2156 return self[k]
2141 except KeyError:
2157 except KeyError:
2142 continue
2158 continue
2143 return None
2159 return None
2144
2160
2145 # Most likely empty string.
2161 # Most likely empty string.
2146 # This may need to raise in the future.
2162 # This may need to raise in the future.
2147 if not name:
2163 if not name:
2148 return None
2164 return None
2149
2165
2150 try:
2166 try:
2151 return self[name]
2167 return self[name]
2152 except KeyError:
2168 except KeyError:
2153 # Try to resolve as a local path or URI.
2169 # Try to resolve as a local path or URI.
2154 try:
2170 try:
2155 # We don't pass sub-options in, so no need to pass ui instance.
2171 # We don't pass sub-options in, so no need to pass ui instance.
2156 return path(None, None, rawloc=name)
2172 return path(None, None, rawloc=name)
2157 except ValueError:
2173 except ValueError:
2158 raise error.RepoError(_(b'repository %s does not exist') % name)
2174 raise error.RepoError(_(b'repository %s does not exist') % name)
2159
2175
2160
2176
2161 _pathsuboptions = {}
2177 _pathsuboptions = {}
2162
2178
2163
2179
2164 def pathsuboption(option, attr):
2180 def pathsuboption(option, attr):
2165 """Decorator used to declare a path sub-option.
2181 """Decorator used to declare a path sub-option.
2166
2182
2167 Arguments are the sub-option name and the attribute it should set on
2183 Arguments are the sub-option name and the attribute it should set on
2168 ``path`` instances.
2184 ``path`` instances.
2169
2185
2170 The decorated function will receive as arguments a ``ui`` instance,
2186 The decorated function will receive as arguments a ``ui`` instance,
2171 ``path`` instance, and the string value of this option from the config.
2187 ``path`` instance, and the string value of this option from the config.
2172 The function should return the value that will be set on the ``path``
2188 The function should return the value that will be set on the ``path``
2173 instance.
2189 instance.
2174
2190
2175 This decorator can be used to perform additional verification of
2191 This decorator can be used to perform additional verification of
2176 sub-options and to change the type of sub-options.
2192 sub-options and to change the type of sub-options.
2177 """
2193 """
2178
2194
2179 def register(func):
2195 def register(func):
2180 _pathsuboptions[option] = (attr, func)
2196 _pathsuboptions[option] = (attr, func)
2181 return func
2197 return func
2182
2198
2183 return register
2199 return register
2184
2200
2185
2201
2186 @pathsuboption(b'pushurl', b'pushloc')
2202 @pathsuboption(b'pushurl', b'pushloc')
2187 def pushurlpathoption(ui, path, value):
2203 def pushurlpathoption(ui, path, value):
2188 u = util.url(value)
2204 u = util.url(value)
2189 # Actually require a URL.
2205 # Actually require a URL.
2190 if not u.scheme:
2206 if not u.scheme:
2191 ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
2207 ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
2192 return None
2208 return None
2193
2209
2194 # Don't support the #foo syntax in the push URL to declare branch to
2210 # Don't support the #foo syntax in the push URL to declare branch to
2195 # push.
2211 # push.
2196 if u.fragment:
2212 if u.fragment:
2197 ui.warn(
2213 ui.warn(
2198 _(
2214 _(
2199 b'("#fragment" in paths.%s:pushurl not supported; '
2215 b'("#fragment" in paths.%s:pushurl not supported; '
2200 b'ignoring)\n'
2216 b'ignoring)\n'
2201 )
2217 )
2202 % path.name
2218 % path.name
2203 )
2219 )
2204 u.fragment = None
2220 u.fragment = None
2205
2221
2206 return bytes(u)
2222 return bytes(u)
2207
2223
2208
2224
2209 @pathsuboption(b'pushrev', b'pushrev')
2225 @pathsuboption(b'pushrev', b'pushrev')
2210 def pushrevpathoption(ui, path, value):
2226 def pushrevpathoption(ui, path, value):
2211 return value
2227 return value
2212
2228
2213
2229
2214 class path(object):
2230 class path(object):
2215 """Represents an individual path and its configuration."""
2231 """Represents an individual path and its configuration."""
2216
2232
2217 def __init__(self, ui, name, rawloc=None, suboptions=None):
2233 def __init__(self, ui, name, rawloc=None, suboptions=None):
2218 """Construct a path from its config options.
2234 """Construct a path from its config options.
2219
2235
2220 ``ui`` is the ``ui`` instance the path is coming from.
2236 ``ui`` is the ``ui`` instance the path is coming from.
2221 ``name`` is the symbolic name of the path.
2237 ``name`` is the symbolic name of the path.
2222 ``rawloc`` is the raw location, as defined in the config.
2238 ``rawloc`` is the raw location, as defined in the config.
2223 ``pushloc`` is the raw locations pushes should be made to.
2239 ``pushloc`` is the raw locations pushes should be made to.
2224
2240
2225 If ``name`` is not defined, we require that the location be a) a local
2241 If ``name`` is not defined, we require that the location be a) a local
2226 filesystem path with a .hg directory or b) a URL. If not,
2242 filesystem path with a .hg directory or b) a URL. If not,
2227 ``ValueError`` is raised.
2243 ``ValueError`` is raised.
2228 """
2244 """
2229 if not rawloc:
2245 if not rawloc:
2230 raise ValueError(b'rawloc must be defined')
2246 raise ValueError(b'rawloc must be defined')
2231
2247
2232 # Locations may define branches via syntax <base>#<branch>.
2248 # Locations may define branches via syntax <base>#<branch>.
2233 u = util.url(rawloc)
2249 u = util.url(rawloc)
2234 branch = None
2250 branch = None
2235 if u.fragment:
2251 if u.fragment:
2236 branch = u.fragment
2252 branch = u.fragment
2237 u.fragment = None
2253 u.fragment = None
2238
2254
2239 self.url = u
2255 self.url = u
2240 self.branch = branch
2256 self.branch = branch
2241
2257
2242 self.name = name
2258 self.name = name
2243 self.rawloc = rawloc
2259 self.rawloc = rawloc
2244 self.loc = b'%s' % u
2260 self.loc = b'%s' % u
2245
2261
2246 # When given a raw location but not a symbolic name, validate the
2262 # When given a raw location but not a symbolic name, validate the
2247 # location is valid.
2263 # location is valid.
2248 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
2264 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
2249 raise ValueError(
2265 raise ValueError(
2250 b'location is not a URL or path to a local '
2266 b'location is not a URL or path to a local '
2251 b'repo: %s' % rawloc
2267 b'repo: %s' % rawloc
2252 )
2268 )
2253
2269
2254 suboptions = suboptions or {}
2270 suboptions = suboptions or {}
2255
2271
2256 # Now process the sub-options. If a sub-option is registered, its
2272 # Now process the sub-options. If a sub-option is registered, its
2257 # attribute will always be present. The value will be None if there
2273 # attribute will always be present. The value will be None if there
2258 # was no valid sub-option.
2274 # was no valid sub-option.
2259 for suboption, (attr, func) in pycompat.iteritems(_pathsuboptions):
2275 for suboption, (attr, func) in pycompat.iteritems(_pathsuboptions):
2260 if suboption not in suboptions:
2276 if suboption not in suboptions:
2261 setattr(self, attr, None)
2277 setattr(self, attr, None)
2262 continue
2278 continue
2263
2279
2264 value = func(ui, self, suboptions[suboption])
2280 value = func(ui, self, suboptions[suboption])
2265 setattr(self, attr, value)
2281 setattr(self, attr, value)
2266
2282
2267 def _isvalidlocalpath(self, path):
2283 def _isvalidlocalpath(self, path):
2268 """Returns True if the given path is a potentially valid repository.
2284 """Returns True if the given path is a potentially valid repository.
2269 This is its own function so that extensions can change the definition of
2285 This is its own function so that extensions can change the definition of
2270 'valid' in this case (like when pulling from a git repo into a hg
2286 'valid' in this case (like when pulling from a git repo into a hg
2271 one)."""
2287 one)."""
2272 try:
2288 try:
2273 return os.path.isdir(os.path.join(path, b'.hg'))
2289 return os.path.isdir(os.path.join(path, b'.hg'))
2274 # Python 2 may return TypeError. Python 3, ValueError.
2290 # Python 2 may return TypeError. Python 3, ValueError.
2275 except (TypeError, ValueError):
2291 except (TypeError, ValueError):
2276 return False
2292 return False
2277
2293
2278 @property
2294 @property
2279 def suboptions(self):
2295 def suboptions(self):
2280 """Return sub-options and their values for this path.
2296 """Return sub-options and their values for this path.
2281
2297
2282 This is intended to be used for presentation purposes.
2298 This is intended to be used for presentation purposes.
2283 """
2299 """
2284 d = {}
2300 d = {}
2285 for subopt, (attr, _func) in pycompat.iteritems(_pathsuboptions):
2301 for subopt, (attr, _func) in pycompat.iteritems(_pathsuboptions):
2286 value = getattr(self, attr)
2302 value = getattr(self, attr)
2287 if value is not None:
2303 if value is not None:
2288 d[subopt] = value
2304 d[subopt] = value
2289 return d
2305 return d
2290
2306
2291
2307
2292 # we instantiate one globally shared progress bar to avoid
2308 # we instantiate one globally shared progress bar to avoid
2293 # competing progress bars when multiple UI objects get created
2309 # competing progress bars when multiple UI objects get created
2294 _progresssingleton = None
2310 _progresssingleton = None
2295
2311
2296
2312
2297 def getprogbar(ui):
2313 def getprogbar(ui):
2298 global _progresssingleton
2314 global _progresssingleton
2299 if _progresssingleton is None:
2315 if _progresssingleton is None:
2300 # passing 'ui' object to the singleton is fishy,
2316 # passing 'ui' object to the singleton is fishy,
2301 # this is how the extension used to work but feel free to rework it.
2317 # this is how the extension used to work but feel free to rework it.
2302 _progresssingleton = progress.progbar(ui)
2318 _progresssingleton = progress.progbar(ui)
2303 return _progresssingleton
2319 return _progresssingleton
2304
2320
2305
2321
2306 def haveprogbar():
2322 def haveprogbar():
2307 return _progresssingleton is not None
2323 return _progresssingleton is not None
2308
2324
2309
2325
2310 def _selectmsgdests(ui):
2326 def _selectmsgdests(ui):
2311 name = ui.config(b'ui', b'message-output')
2327 name = ui.config(b'ui', b'message-output')
2312 if name == b'channel':
2328 if name == b'channel':
2313 if ui.fmsg:
2329 if ui.fmsg:
2314 return ui.fmsg, ui.fmsg
2330 return ui.fmsg, ui.fmsg
2315 else:
2331 else:
2316 # fall back to ferr if channel isn't ready so that status/error
2332 # fall back to ferr if channel isn't ready so that status/error
2317 # messages can be printed
2333 # messages can be printed
2318 return ui.ferr, ui.ferr
2334 return ui.ferr, ui.ferr
2319 if name == b'stdio':
2335 if name == b'stdio':
2320 return ui.fout, ui.ferr
2336 return ui.fout, ui.ferr
2321 if name == b'stderr':
2337 if name == b'stderr':
2322 return ui.ferr, ui.ferr
2338 return ui.ferr, ui.ferr
2323 raise error.Abort(b'invalid ui.message-output destination: %s' % name)
2339 raise error.Abort(b'invalid ui.message-output destination: %s' % name)
2324
2340
2325
2341
2326 def _writemsgwith(write, dest, *args, **opts):
2342 def _writemsgwith(write, dest, *args, **opts):
2327 """Write ui message with the given ui._write*() function
2343 """Write ui message with the given ui._write*() function
2328
2344
2329 The specified message type is translated to 'ui.<type>' label if the dest
2345 The specified message type is translated to 'ui.<type>' label if the dest
2330 isn't a structured channel, so that the message will be colorized.
2346 isn't a structured channel, so that the message will be colorized.
2331 """
2347 """
2332 # TODO: maybe change 'type' to a mandatory option
2348 # TODO: maybe change 'type' to a mandatory option
2333 if 'type' in opts and not getattr(dest, 'structured', False):
2349 if 'type' in opts and not getattr(dest, 'structured', False):
2334 opts['label'] = opts.get('label', b'') + b' ui.%s' % opts.pop('type')
2350 opts['label'] = opts.get('label', b'') + b' ui.%s' % opts.pop('type')
2335 write(dest, *args, **opts)
2351 write(dest, *args, **opts)
@@ -1,363 +1,403 b''
1
1
2 $ cat > loop.py <<EOF
2 $ cat > loop.py <<EOF
3 > from __future__ import absolute_import
3 > from __future__ import absolute_import
4 > import time
4 > import time
5 > from mercurial import commands, registrar
5 > from mercurial import commands, registrar
6 >
6 >
7 > cmdtable = {}
7 > cmdtable = {}
8 > command = registrar.command(cmdtable)
8 > command = registrar.command(cmdtable)
9 >
9 >
10 > class incrementingtime(object):
10 > class incrementingtime(object):
11 > def __init__(self):
11 > def __init__(self):
12 > self._time = 0.0
12 > self._time = 0.0
13 > def __call__(self):
13 > def __call__(self):
14 > self._time += 0.25
14 > self._time += 0.25
15 > return self._time
15 > return self._time
16 > time.time = incrementingtime()
16 > time.time = incrementingtime()
17 >
17 >
18 > @command(b'loop',
18 > @command(b'loop',
19 > [(b'', b'total', b'', b'override for total'),
19 > [(b'', b'total', b'', b'override for total'),
20 > (b'', b'nested', False, b'show nested results'),
20 > (b'', b'nested', False, b'show nested results'),
21 > (b'', b'parallel', False, b'show parallel sets of results')],
21 > (b'', b'parallel', False, b'show parallel sets of results'),
22 > (b'', b'warn', False, b'show warning if step divisible by 3')],
22 > b'hg loop LOOPS',
23 > b'hg loop LOOPS',
23 > norepo=True)
24 > norepo=True)
24 > def loop(ui, loops, **opts):
25 > def loop(ui, loops, **opts):
25 > loops = int(loops)
26 > loops = int(loops)
26 > total = None
27 > total = None
27 > if loops >= 0:
28 > if loops >= 0:
28 > total = loops
29 > total = loops
29 > if opts.get('total', None):
30 > if opts.get('total', None):
30 > total = int(opts.get('total'))
31 > total = int(opts.get('total'))
31 > nested = False
32 > nested = False
32 > if opts.get('nested', None):
33 > if opts.get('nested', None):
33 > nested = True
34 > nested = True
34 > loops = abs(loops)
35 > loops = abs(loops)
36 > showwarn = opts.get('warn', False)
35 >
37 >
36 > progress = ui.makeprogress(topiclabel, unit=b'loopnum', total=total)
38 > progress = ui.makeprogress(topiclabel, unit=b'loopnum', total=total)
37 > other = ui.makeprogress(b'other', unit=b'othernum', total=total)
39 > other = ui.makeprogress(b'other', unit=b'othernum', total=total)
38 > for i in range(loops):
40 > for i in range(loops):
39 > progress.update(i, item=getloopitem(i))
41 > progress.update(i, item=getloopitem(i))
40 > if opts.get('parallel'):
42 > if opts.get('parallel'):
41 > other.update(i, item=b'other.%d' % i)
43 > other.update(i, item=b'other.%d' % i)
42 > if nested:
44 > if nested:
43 > nested_steps = 2
45 > nested_steps = 2
44 > if i and i % 4 == 0:
46 > if i and i % 4 == 0:
45 > nested_steps = 5
47 > nested_steps = 5
46 > nested = ui.makeprogress(b'nested', unit=b'nestnum',
48 > nested = ui.makeprogress(b'nested', unit=b'nestnum',
47 > total=nested_steps)
49 > total=nested_steps)
48 > for j in range(nested_steps):
50 > for j in range(nested_steps):
49 > nested.update(j, item=b'nested.%d' % j)
51 > nested.update(j, item=b'nested.%d' % j)
50 > nested.complete()
52 > nested.complete()
53 > if showwarn and i % 3 == 0:
54 > ui.warn(b'reached step %d\n' %i)
51 > progress.complete()
55 > progress.complete()
52 >
56 >
53 > topiclabel = b'loop'
57 > topiclabel = b'loop'
54 > def getloopitem(i):
58 > def getloopitem(i):
55 > return b'loop.%d' % i
59 > return b'loop.%d' % i
56 >
60 >
57 > EOF
61 > EOF
58
62
59 $ cp $HGRCPATH $HGRCPATH.orig
63 $ cp $HGRCPATH $HGRCPATH.orig
60 $ echo "[extensions]" >> $HGRCPATH
64 $ echo "[extensions]" >> $HGRCPATH
61 $ echo "progress=" >> $HGRCPATH
65 $ echo "progress=" >> $HGRCPATH
62 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
66 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
63 $ echo "[progress]" >> $HGRCPATH
67 $ echo "[progress]" >> $HGRCPATH
64 $ echo "format = topic bar number" >> $HGRCPATH
68 $ echo "format = topic bar number" >> $HGRCPATH
65 $ echo "assume-tty=1" >> $HGRCPATH
69 $ echo "assume-tty=1" >> $HGRCPATH
66 $ echo "width=60" >> $HGRCPATH
70 $ echo "width=60" >> $HGRCPATH
67
71
68 test default params, display nothing because of delay
72 test default params, display nothing because of delay
69
73
70 $ hg -y loop 3
74 $ hg -y loop 3
71 $ echo "delay=0" >> $HGRCPATH
75 $ echo "delay=0" >> $HGRCPATH
72 $ echo "refresh=0" >> $HGRCPATH
76 $ echo "refresh=0" >> $HGRCPATH
73
77
74 test with delay=0, refresh=0
78 test with delay=0, refresh=0
75
79
76 $ hg -y loop 3
80 $ hg -y loop 3
77 \r (no-eol) (esc)
81 \r (no-eol) (esc)
78 loop [ ] 0/3\r (no-eol) (esc)
82 loop [ ] 0/3\r (no-eol) (esc)
79 loop [===============> ] 1/3\r (no-eol) (esc)
83 loop [===============> ] 1/3\r (no-eol) (esc)
80 loop [===============================> ] 2/3\r (no-eol) (esc)
84 loop [===============================> ] 2/3\r (no-eol) (esc)
81 \r (no-eol) (esc)
85 \r (no-eol) (esc)
82 no progress with --quiet
86 no progress with --quiet
83 $ hg -y loop 3 --quiet
87 $ hg -y loop 3 --quiet
84
88
85 test plain mode exception
89 test plain mode exception
86 $ HGPLAINEXCEPT=progress hg -y loop 1
90 $ HGPLAINEXCEPT=progress hg -y loop 1
87 \r (no-eol) (esc)
91 \r (no-eol) (esc)
88 loop [ ] 0/1\r (no-eol) (esc)
92 loop [ ] 0/1\r (no-eol) (esc)
89 \r (no-eol) (esc)
93 \r (no-eol) (esc)
90
94
91 test nested short-lived topics (which shouldn't display with nestdelay):
95 test nested short-lived topics (which shouldn't display with nestdelay):
92
96
93 $ hg -y loop 3 --nested
97 $ hg -y loop 3 --nested
94 \r (no-eol) (esc)
98 \r (no-eol) (esc)
95 loop [ ] 0/3\r (no-eol) (esc)
99 loop [ ] 0/3\r (no-eol) (esc)
96 loop [===============> ] 1/3\r (no-eol) (esc)
100 loop [===============> ] 1/3\r (no-eol) (esc)
97 loop [===============================> ] 2/3\r (no-eol) (esc)
101 loop [===============================> ] 2/3\r (no-eol) (esc)
98 \r (no-eol) (esc)
102 \r (no-eol) (esc)
99
103
100 Test nested long-lived topic which has the same name as a short-lived
104 Test nested long-lived topic which has the same name as a short-lived
101 peer. We shouldn't get stuck showing the short-lived inner steps, and
105 peer. We shouldn't get stuck showing the short-lived inner steps, and
102 should go back to skipping the inner steps when the slow nested step
106 should go back to skipping the inner steps when the slow nested step
103 finishes.
107 finishes.
104
108
105 $ hg -y loop 7 --nested
109 $ hg -y loop 7 --nested
106 \r (no-eol) (esc)
110 \r (no-eol) (esc)
107 loop [ ] 0/7\r (no-eol) (esc)
111 loop [ ] 0/7\r (no-eol) (esc)
108 loop [=====> ] 1/7\r (no-eol) (esc)
112 loop [=====> ] 1/7\r (no-eol) (esc)
109 loop [============> ] 2/7\r (no-eol) (esc)
113 loop [============> ] 2/7\r (no-eol) (esc)
110 loop [===================> ] 3/7\r (no-eol) (esc)
114 loop [===================> ] 3/7\r (no-eol) (esc)
111 loop [==========================> ] 4/7\r (no-eol) (esc)
115 loop [==========================> ] 4/7\r (no-eol) (esc)
112 nested [==========================> ] 3/5\r (no-eol) (esc)
116 nested [==========================> ] 3/5\r (no-eol) (esc)
113 nested [===================================> ] 4/5\r (no-eol) (esc)
117 nested [===================================> ] 4/5\r (no-eol) (esc)
114 loop [=================================> ] 5/7\r (no-eol) (esc)
118 loop [=================================> ] 5/7\r (no-eol) (esc)
115 loop [========================================> ] 6/7\r (no-eol) (esc)
119 loop [========================================> ] 6/7\r (no-eol) (esc)
116 \r (no-eol) (esc)
120 \r (no-eol) (esc)
117
121
118
122
119 $ hg --config progress.changedelay=0 -y loop 3 --nested
123 $ hg --config progress.changedelay=0 -y loop 3 --nested
120 \r (no-eol) (esc)
124 \r (no-eol) (esc)
121 loop [ ] 0/3\r (no-eol) (esc)
125 loop [ ] 0/3\r (no-eol) (esc)
122 nested [ ] 0/2\r (no-eol) (esc)
126 nested [ ] 0/2\r (no-eol) (esc)
123 nested [======================> ] 1/2\r (no-eol) (esc)
127 nested [======================> ] 1/2\r (no-eol) (esc)
124 loop [===============> ] 1/3\r (no-eol) (esc)
128 loop [===============> ] 1/3\r (no-eol) (esc)
125 nested [ ] 0/2\r (no-eol) (esc)
129 nested [ ] 0/2\r (no-eol) (esc)
126 nested [======================> ] 1/2\r (no-eol) (esc)
130 nested [======================> ] 1/2\r (no-eol) (esc)
127 loop [===============================> ] 2/3\r (no-eol) (esc)
131 loop [===============================> ] 2/3\r (no-eol) (esc)
128 nested [ ] 0/2\r (no-eol) (esc)
132 nested [ ] 0/2\r (no-eol) (esc)
129 nested [======================> ] 1/2\r (no-eol) (esc)
133 nested [======================> ] 1/2\r (no-eol) (esc)
130 \r (no-eol) (esc)
134 \r (no-eol) (esc)
131
135
132
136
133 test two topics being printed in parallel (as when we're doing a local
137 test two topics being printed in parallel (as when we're doing a local
134 --pull clone, where you get the unbundle and bundle progress at the
138 --pull clone, where you get the unbundle and bundle progress at the
135 same time):
139 same time):
136 $ hg loop 3 --parallel
140 $ hg loop 3 --parallel
137 \r (no-eol) (esc)
141 \r (no-eol) (esc)
138 loop [ ] 0/3\r (no-eol) (esc)
142 loop [ ] 0/3\r (no-eol) (esc)
139 loop [===============> ] 1/3\r (no-eol) (esc)
143 loop [===============> ] 1/3\r (no-eol) (esc)
140 loop [===============================> ] 2/3\r (no-eol) (esc)
144 loop [===============================> ] 2/3\r (no-eol) (esc)
141 \r (no-eol) (esc)
145 \r (no-eol) (esc)
142 test refresh is taken in account
146 test refresh is taken in account
143
147
144 $ hg -y --config progress.refresh=100 loop 3
148 $ hg -y --config progress.refresh=100 loop 3
145
149
146 test format options 1
150 test format options 1
147
151
148 $ hg -y --config 'progress.format=number topic item+2' loop 2
152 $ hg -y --config 'progress.format=number topic item+2' loop 2
149 \r (no-eol) (esc)
153 \r (no-eol) (esc)
150 0/2 loop lo\r (no-eol) (esc)
154 0/2 loop lo\r (no-eol) (esc)
151 1/2 loop lo\r (no-eol) (esc)
155 1/2 loop lo\r (no-eol) (esc)
152 \r (no-eol) (esc)
156 \r (no-eol) (esc)
153
157
154 test format options 2
158 test format options 2
155
159
156 $ hg -y --config 'progress.format=number item-3 bar' loop 2
160 $ hg -y --config 'progress.format=number item-3 bar' loop 2
157 \r (no-eol) (esc)
161 \r (no-eol) (esc)
158 0/2 p.0 [ ]\r (no-eol) (esc)
162 0/2 p.0 [ ]\r (no-eol) (esc)
159 1/2 p.1 [=======================> ]\r (no-eol) (esc)
163 1/2 p.1 [=======================> ]\r (no-eol) (esc)
160 \r (no-eol) (esc)
164 \r (no-eol) (esc)
161
165
162 test format options and indeterminate progress
166 test format options and indeterminate progress
163
167
164 $ hg -y --config 'progress.format=number item bar' loop -- -2
168 $ hg -y --config 'progress.format=number item bar' loop -- -2
165 \r (no-eol) (esc)
169 \r (no-eol) (esc)
166 0 loop.0 [ <=> ]\r (no-eol) (esc)
170 0 loop.0 [ <=> ]\r (no-eol) (esc)
167 1 loop.1 [ <=> ]\r (no-eol) (esc)
171 1 loop.1 [ <=> ]\r (no-eol) (esc)
168 \r (no-eol) (esc)
172 \r (no-eol) (esc)
169
173
170 make sure things don't fall over if count > total
174 make sure things don't fall over if count > total
171
175
172 $ hg -y loop --total 4 6
176 $ hg -y loop --total 4 6
173 \r (no-eol) (esc)
177 \r (no-eol) (esc)
174 loop [ ] 0/4\r (no-eol) (esc)
178 loop [ ] 0/4\r (no-eol) (esc)
175 loop [===========> ] 1/4\r (no-eol) (esc)
179 loop [===========> ] 1/4\r (no-eol) (esc)
176 loop [=======================> ] 2/4\r (no-eol) (esc)
180 loop [=======================> ] 2/4\r (no-eol) (esc)
177 loop [===================================> ] 3/4\r (no-eol) (esc)
181 loop [===================================> ] 3/4\r (no-eol) (esc)
178 loop [===============================================>] 4/4\r (no-eol) (esc)
182 loop [===============================================>] 4/4\r (no-eol) (esc)
179 loop [ <=> ] 5/4\r (no-eol) (esc)
183 loop [ <=> ] 5/4\r (no-eol) (esc)
180 \r (no-eol) (esc)
184 \r (no-eol) (esc)
181
185
186 test interaction with ui.warn
187
188 $ hg loop --warn 6
189 \r (no-eol) (esc)
190 loop [ ] 0/6\r (no-eol) (esc)
191 \r (no-eol) (esc)
192 reached step 0
193 \r (no-eol) (esc)
194 loop [=======> ] 1/6\r (no-eol) (esc)
195 loop [===============> ] 2/6\r (no-eol) (esc)
196 loop [=======================> ] 3/6\r (no-eol) (esc)
197 \r (no-eol) (esc)
198 reached step 3
199 \r (no-eol) (esc)
200 loop [===============================> ] 4/6\r (no-eol) (esc)
201 loop [=======================================> ] 5/6\r (no-eol) (esc)
202 \r (no-eol) (esc)
203
204 test interaction with ui.timestamp-output
205
206 $ hg loop --warn --config ui.timestamp-output=true 6
207 \r (no-eol) (esc)
208 loop [ ] 0/6\r (no-eol) (esc)
209 \r (no-eol) (esc)
210 \[20[2-9][0-9]-[01][0-9]-[0-3][0-9]T[0-5][0-9]:[0-5][0-9]:[0-5][0-9]\.[0-9][0-9][0-9][0-9][0-9][0-9]\] reached step 0 (re)
211 \r (no-eol) (esc)
212 loop [=======> ] 1/6\r (no-eol) (esc)
213 loop [===============> ] 2/6\r (no-eol) (esc)
214 loop [=======================> ] 3/6\r (no-eol) (esc)
215 \r (no-eol) (esc)
216 \[20[2-9][0-9]-[01][0-9]-[0-3][0-9]T[0-5][0-9]:[0-5][0-9]:[0-5][0-9]\.[0-9][0-9][0-9][0-9][0-9][0-9]\] reached step 3 (re)
217 \r (no-eol) (esc)
218 loop [===============================> ] 4/6\r (no-eol) (esc)
219 loop [=======================================> ] 5/6\r (no-eol) (esc)
220 \r (no-eol) (esc)
221
182 test immediate progress completion
222 test immediate progress completion
183
223
184 $ hg -y loop 0
224 $ hg -y loop 0
185
225
186 test delay time estimates
226 test delay time estimates
187
227
188 #if no-chg
228 #if no-chg
189
229
190 $ cp $HGRCPATH.orig $HGRCPATH
230 $ cp $HGRCPATH.orig $HGRCPATH
191 $ echo "[extensions]" >> $HGRCPATH
231 $ echo "[extensions]" >> $HGRCPATH
192 $ echo "mocktime=$TESTDIR/mocktime.py" >> $HGRCPATH
232 $ echo "mocktime=$TESTDIR/mocktime.py" >> $HGRCPATH
193 $ echo "progress=" >> $HGRCPATH
233 $ echo "progress=" >> $HGRCPATH
194 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
234 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
195 $ echo "[progress]" >> $HGRCPATH
235 $ echo "[progress]" >> $HGRCPATH
196 $ echo "assume-tty=1" >> $HGRCPATH
236 $ echo "assume-tty=1" >> $HGRCPATH
197 $ echo "delay=25" >> $HGRCPATH
237 $ echo "delay=25" >> $HGRCPATH
198 $ echo "width=60" >> $HGRCPATH
238 $ echo "width=60" >> $HGRCPATH
199
239
200 $ MOCKTIME=11 hg -y loop 8
240 $ MOCKTIME=11 hg -y loop 8
201 \r (no-eol) (esc)
241 \r (no-eol) (esc)
202 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
242 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
203 loop [===============> ] 3/8 56s\r (no-eol) (esc)
243 loop [===============> ] 3/8 56s\r (no-eol) (esc)
204 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
244 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
205 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
245 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
206 loop [================================> ] 6/8 23s\r (no-eol) (esc)
246 loop [================================> ] 6/8 23s\r (no-eol) (esc)
207 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
247 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
208 \r (no-eol) (esc)
248 \r (no-eol) (esc)
209
249
210 $ MOCKTIME=10000 hg -y loop 4
250 $ MOCKTIME=10000 hg -y loop 4
211 \r (no-eol) (esc)
251 \r (no-eol) (esc)
212 loop [ ] 0/4\r (no-eol) (esc)
252 loop [ ] 0/4\r (no-eol) (esc)
213 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
253 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
214 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
254 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
215 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
255 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
216 \r (no-eol) (esc)
256 \r (no-eol) (esc)
217
257
218 $ MOCKTIME=1000000 hg -y loop 4
258 $ MOCKTIME=1000000 hg -y loop 4
219 \r (no-eol) (esc)
259 \r (no-eol) (esc)
220 loop [ ] 0/4\r (no-eol) (esc)
260 loop [ ] 0/4\r (no-eol) (esc)
221 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
261 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
222 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
262 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
223 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
263 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
224 \r (no-eol) (esc)
264 \r (no-eol) (esc)
225
265
226
266
227 $ MOCKTIME=14000000 hg -y loop 4
267 $ MOCKTIME=14000000 hg -y loop 4
228 \r (no-eol) (esc)
268 \r (no-eol) (esc)
229 loop [ ] 0/4\r (no-eol) (esc)
269 loop [ ] 0/4\r (no-eol) (esc)
230 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
270 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
231 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
271 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
232 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
272 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
233 \r (no-eol) (esc)
273 \r (no-eol) (esc)
234
274
235 Non-linear progress:
275 Non-linear progress:
236
276
237 $ MOCKTIME='20 20 20 20 20 20 20 20 20 20 500 500 500 500 500 20 20 20 20 20' hg -y loop 20
277 $ MOCKTIME='20 20 20 20 20 20 20 20 20 20 500 500 500 500 500 20 20 20 20 20' hg -y loop 20
238 \r (no-eol) (esc)
278 \r (no-eol) (esc)
239 loop [=> ] 1/20 6m21s\r (no-eol) (esc)
279 loop [=> ] 1/20 6m21s\r (no-eol) (esc)
240 loop [===> ] 2/20 6m01s\r (no-eol) (esc)
280 loop [===> ] 2/20 6m01s\r (no-eol) (esc)
241 loop [=====> ] 3/20 5m41s\r (no-eol) (esc)
281 loop [=====> ] 3/20 5m41s\r (no-eol) (esc)
242 loop [=======> ] 4/20 5m21s\r (no-eol) (esc)
282 loop [=======> ] 4/20 5m21s\r (no-eol) (esc)
243 loop [=========> ] 5/20 5m01s\r (no-eol) (esc)
283 loop [=========> ] 5/20 5m01s\r (no-eol) (esc)
244 loop [===========> ] 6/20 4m41s\r (no-eol) (esc)
284 loop [===========> ] 6/20 4m41s\r (no-eol) (esc)
245 loop [=============> ] 7/20 4m21s\r (no-eol) (esc)
285 loop [=============> ] 7/20 4m21s\r (no-eol) (esc)
246 loop [===============> ] 8/20 4m01s\r (no-eol) (esc)
286 loop [===============> ] 8/20 4m01s\r (no-eol) (esc)
247 loop [================> ] 9/20 25m40s\r (no-eol) (esc)
287 loop [================> ] 9/20 25m40s\r (no-eol) (esc)
248 loop [===================> ] 10/20 1h06m\r (no-eol) (esc)
288 loop [===================> ] 10/20 1h06m\r (no-eol) (esc)
249 loop [=====================> ] 11/20 1h13m\r (no-eol) (esc)
289 loop [=====================> ] 11/20 1h13m\r (no-eol) (esc)
250 loop [=======================> ] 12/20 1h07m\r (no-eol) (esc)
290 loop [=======================> ] 12/20 1h07m\r (no-eol) (esc)
251 loop [========================> ] 13/20 58m19s\r (no-eol) (esc)
291 loop [========================> ] 13/20 58m19s\r (no-eol) (esc)
252 loop [===========================> ] 14/20 7m09s\r (no-eol) (esc)
292 loop [===========================> ] 14/20 7m09s\r (no-eol) (esc)
253 loop [=============================> ] 15/20 3m38s\r (no-eol) (esc)
293 loop [=============================> ] 15/20 3m38s\r (no-eol) (esc)
254 loop [===============================> ] 16/20 2m15s\r (no-eol) (esc)
294 loop [===============================> ] 16/20 2m15s\r (no-eol) (esc)
255 loop [=================================> ] 17/20 1m27s\r (no-eol) (esc)
295 loop [=================================> ] 17/20 1m27s\r (no-eol) (esc)
256 loop [====================================> ] 18/20 52s\r (no-eol) (esc)
296 loop [====================================> ] 18/20 52s\r (no-eol) (esc)
257 loop [======================================> ] 19/20 25s\r (no-eol) (esc)
297 loop [======================================> ] 19/20 25s\r (no-eol) (esc)
258 \r (no-eol) (esc)
298 \r (no-eol) (esc)
259
299
260 Time estimates should not fail when there's no end point:
300 Time estimates should not fail when there's no end point:
261 $ MOCKTIME=11 hg -y loop -- -4
301 $ MOCKTIME=11 hg -y loop -- -4
262 \r (no-eol) (esc)
302 \r (no-eol) (esc)
263 loop [ <=> ] 2\r (no-eol) (esc)
303 loop [ <=> ] 2\r (no-eol) (esc)
264 loop [ <=> ] 3\r (no-eol) (esc)
304 loop [ <=> ] 3\r (no-eol) (esc)
265 \r (no-eol) (esc)
305 \r (no-eol) (esc)
266
306
267 #endif
307 #endif
268
308
269 test line trimming by '[progress] width', when progress topic contains
309 test line trimming by '[progress] width', when progress topic contains
270 multi-byte characters, of which length of byte sequence and columns in
310 multi-byte characters, of which length of byte sequence and columns in
271 display are different from each other.
311 display are different from each other.
272
312
273 $ cp $HGRCPATH.orig $HGRCPATH
313 $ cp $HGRCPATH.orig $HGRCPATH
274 $ cat >> $HGRCPATH <<EOF
314 $ cat >> $HGRCPATH <<EOF
275 > [extensions]
315 > [extensions]
276 > progress=
316 > progress=
277 > loop=`pwd`/loop.py
317 > loop=`pwd`/loop.py
278 > [progress]
318 > [progress]
279 > assume-tty = 1
319 > assume-tty = 1
280 > delay = 0
320 > delay = 0
281 > refresh = 0
321 > refresh = 0
282 > EOF
322 > EOF
283
323
284 $ rm -f loop.pyc
324 $ rm -f loop.pyc
285 $ cat >> loop.py <<EOF
325 $ cat >> loop.py <<EOF
286 > # use non-ascii characters as topic label of progress
326 > # use non-ascii characters as topic label of progress
287 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
327 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
288 > topiclabel = u'\u3042\u3044\u3046\u3048'.encode('utf-8')
328 > topiclabel = u'\u3042\u3044\u3046\u3048'.encode('utf-8')
289 > EOF
329 > EOF
290
330
291 $ cat >> $HGRCPATH <<EOF
331 $ cat >> $HGRCPATH <<EOF
292 > [progress]
332 > [progress]
293 > format = topic number
333 > format = topic number
294 > width= 12
334 > width= 12
295 > EOF
335 > EOF
296
336
297 $ hg --encoding utf-8 -y loop --total 3 3
337 $ hg --encoding utf-8 -y loop --total 3 3
298 \r (no-eol) (esc)
338 \r (no-eol) (esc)
299 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 0/3\r (no-eol) (esc)
339 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 0/3\r (no-eol) (esc)
300 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 1/3\r (no-eol) (esc)
340 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 1/3\r (no-eol) (esc)
301 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 2/3\r (no-eol) (esc)
341 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 2/3\r (no-eol) (esc)
302 \r (no-eol) (esc)
342 \r (no-eol) (esc)
303
343
304 test calculation of bar width, when progress topic contains multi-byte
344 test calculation of bar width, when progress topic contains multi-byte
305 characters, of which length of byte sequence and columns in display
345 characters, of which length of byte sequence and columns in display
306 are different from each other.
346 are different from each other.
307
347
308 $ cat >> $HGRCPATH <<EOF
348 $ cat >> $HGRCPATH <<EOF
309 > [progress]
349 > [progress]
310 > format = topic bar
350 > format = topic bar
311 > width= 21
351 > width= 21
312 > # progwidth should be 9 (= 21 - (8+1) - 3)
352 > # progwidth should be 9 (= 21 - (8+1) - 3)
313 > EOF
353 > EOF
314
354
315 $ hg --encoding utf-8 -y loop --total 3 3
355 $ hg --encoding utf-8 -y loop --total 3 3
316 \r (no-eol) (esc)
356 \r (no-eol) (esc)
317 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [ ]\r (no-eol) (esc)
357 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [ ]\r (no-eol) (esc)
318 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [==> ]\r (no-eol) (esc)
358 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [==> ]\r (no-eol) (esc)
319 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [=====> ]\r (no-eol) (esc)
359 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [=====> ]\r (no-eol) (esc)
320 \r (no-eol) (esc)
360 \r (no-eol) (esc)
321
361
322 test trimming progress items, when they contain multi-byte characters,
362 test trimming progress items, when they contain multi-byte characters,
323 of which length of byte sequence and columns in display are different
363 of which length of byte sequence and columns in display are different
324 from each other.
364 from each other.
325
365
326 $ rm -f loop.pyc
366 $ rm -f loop.pyc
327 $ rm -Rf __pycache__
367 $ rm -Rf __pycache__
328 $ cat >> loop.py <<EOF
368 $ cat >> loop.py <<EOF
329 > # use non-ascii characters as loop items of progress
369 > # use non-ascii characters as loop items of progress
330 > loopitems = [
370 > loopitems = [
331 > u'\u3042\u3044'.encode('utf-8'), # 2 x 2 = 4 columns
371 > u'\u3042\u3044'.encode('utf-8'), # 2 x 2 = 4 columns
332 > u'\u3042\u3044\u3046'.encode('utf-8'), # 2 x 3 = 6 columns
372 > u'\u3042\u3044\u3046'.encode('utf-8'), # 2 x 3 = 6 columns
333 > u'\u3042\u3044\u3046\u3048'.encode('utf-8'), # 2 x 4 = 8 columns
373 > u'\u3042\u3044\u3046\u3048'.encode('utf-8'), # 2 x 4 = 8 columns
334 > ]
374 > ]
335 > def getloopitem(i):
375 > def getloopitem(i):
336 > return loopitems[i % len(loopitems)]
376 > return loopitems[i % len(loopitems)]
337 > EOF
377 > EOF
338
378
339 $ cat >> $HGRCPATH <<EOF
379 $ cat >> $HGRCPATH <<EOF
340 > [progress]
380 > [progress]
341 > # trim at tail side
381 > # trim at tail side
342 > format = item+6
382 > format = item+6
343 > EOF
383 > EOF
344
384
345 $ hg --encoding utf-8 -y loop --total 3 3
385 $ hg --encoding utf-8 -y loop --total 3 3
346 \r (no-eol) (esc)
386 \r (no-eol) (esc)
347 \xe3\x81\x82\xe3\x81\x84 \r (no-eol) (esc)
387 \xe3\x81\x82\xe3\x81\x84 \r (no-eol) (esc)
348 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
388 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
349 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
389 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
350 \r (no-eol) (esc)
390 \r (no-eol) (esc)
351
391
352 $ cat >> $HGRCPATH <<EOF
392 $ cat >> $HGRCPATH <<EOF
353 > [progress]
393 > [progress]
354 > # trim at left side
394 > # trim at left side
355 > format = item-6
395 > format = item-6
356 > EOF
396 > EOF
357
397
358 $ hg --encoding utf-8 -y loop --total 3 3
398 $ hg --encoding utf-8 -y loop --total 3 3
359 \r (no-eol) (esc)
399 \r (no-eol) (esc)
360 \xe3\x81\x82\xe3\x81\x84 \r (no-eol) (esc)
400 \xe3\x81\x82\xe3\x81\x84 \r (no-eol) (esc)
361 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
401 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
362 \xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\r (no-eol) (esc)
402 \xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\r (no-eol) (esc)
363 \r (no-eol) (esc)
403 \r (no-eol) (esc)
@@ -1,152 +1,152 b''
1 #require serve
1 #require serve
2
2
3 #testcases sshv1 sshv2
3 #testcases sshv1 sshv2
4
4
5 #if sshv2
5 #if sshv2
6 $ cat >> $HGRCPATH << EOF
6 $ cat >> $HGRCPATH << EOF
7 > [experimental]
7 > [experimental]
8 > sshpeer.advertise-v2 = true
8 > sshpeer.advertise-v2 = true
9 > sshserver.support-v2 = true
9 > sshserver.support-v2 = true
10 > EOF
10 > EOF
11 #endif
11 #endif
12
12
13 $ hg init test
13 $ hg init test
14 $ cd test
14 $ cd test
15
15
16 $ echo foo>foo
16 $ echo foo>foo
17 $ hg addremove
17 $ hg addremove
18 adding foo
18 adding foo
19 $ hg commit -m 1
19 $ hg commit -m 1
20
20
21 $ hg verify
21 $ hg verify
22 checking changesets
22 checking changesets
23 checking manifests
23 checking manifests
24 crosschecking files in changesets and manifests
24 crosschecking files in changesets and manifests
25 checking files
25 checking files
26 checked 1 changesets with 1 changes to 1 files
26 checked 1 changesets with 1 changes to 1 files
27
27
28 $ hg serve -p $HGPORT -d --pid-file=hg.pid
28 $ hg serve -p $HGPORT -d --pid-file=hg.pid
29 $ cat hg.pid >> $DAEMON_PIDS
29 $ cat hg.pid >> $DAEMON_PIDS
30 $ cd ..
30 $ cd ..
31
31
32 $ hg clone --pull http://foo:bar@localhost:$HGPORT/ copy
32 $ hg clone --pull http://foo:bar@localhost:$HGPORT/ copy
33 requesting all changes
33 requesting all changes
34 adding changesets
34 adding changesets
35 adding manifests
35 adding manifests
36 adding file changes
36 adding file changes
37 added 1 changesets with 1 changes to 1 files
37 added 1 changesets with 1 changes to 1 files
38 new changesets 340e38bdcde4
38 new changesets 340e38bdcde4
39 updating to branch default
39 updating to branch default
40 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
41
41
42 $ cd copy
42 $ cd copy
43 $ hg verify
43 $ hg verify
44 checking changesets
44 checking changesets
45 checking manifests
45 checking manifests
46 crosschecking files in changesets and manifests
46 crosschecking files in changesets and manifests
47 checking files
47 checking files
48 checked 1 changesets with 1 changes to 1 files
48 checked 1 changesets with 1 changes to 1 files
49
49
50 $ hg co
50 $ hg co
51 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 $ cat foo
52 $ cat foo
53 foo
53 foo
54
54
55 $ hg manifest --debug
55 $ hg manifest --debug
56 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
56 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
57
57
58 $ hg pull
58 $ hg pull
59 pulling from http://foo@localhost:$HGPORT/
59 pulling from http://foo@localhost:$HGPORT/
60 searching for changes
60 searching for changes
61 no changes found
61 no changes found
62
62
63 $ hg rollback --dry-run --verbose
63 $ hg rollback --dry-run --verbose
64 repository tip rolled back to revision -1 (undo pull: http://foo:***@localhost:$HGPORT/)
64 repository tip rolled back to revision -1 (undo pull: http://foo:***@localhost:$HGPORT/)
65
65
66 Test pull of non-existing 20 character revision specification, making sure plain ascii identifiers
66 Test pull of non-existing 20 character revision specification, making sure plain ascii identifiers
67 not are encoded like a node:
67 not are encoded like a node:
68
68
69 $ hg pull -r 'xxxxxxxxxxxxxxxxxxxy'
69 $ hg pull -r 'xxxxxxxxxxxxxxxxxxxy'
70 pulling from http://foo@localhost:$HGPORT/
70 pulling from http://foo@localhost:$HGPORT/
71 abort: unknown revision 'xxxxxxxxxxxxxxxxxxxy'!
71 abort: unknown revision 'xxxxxxxxxxxxxxxxxxxy'!
72 [255]
72 [255]
73 $ hg pull -r 'xxxxxxxxxxxxxxxxxx y'
73 $ hg pull -r 'xxxxxxxxxxxxxxxxxx y'
74 pulling from http://foo@localhost:$HGPORT/
74 pulling from http://foo@localhost:$HGPORT/
75 abort: unknown revision 'xxxxxxxxxxxxxxxxxx y'!
75 abort: unknown revision 'xxxxxxxxxxxxxxxxxx y'!
76 [255]
76 [255]
77
77
78 Test pull of working copy revision
78 Test pull of working copy revision
79 $ hg pull -r 'ffffffffffff'
79 $ hg pull -r 'ffffffffffff'
80 pulling from http://foo@localhost:$HGPORT/
80 pulling from http://foo@localhost:$HGPORT/
81 abort: unknown revision 'ffffffffffff'!
81 abort: unknown revision 'ffffffffffff'!
82 [255]
82 [255]
83
83
84 Issue622: hg init && hg pull -u URL doesn't checkout default branch
84 Issue622: hg init && hg pull -u URL doesn't checkout default branch
85
85
86 $ cd ..
86 $ cd ..
87 $ hg init empty
87 $ hg init empty
88 $ cd empty
88 $ cd empty
89 $ hg pull -u ../test
89 $ hg pull -u ../test
90 pulling from ../test
90 pulling from ../test
91 requesting all changes
91 requesting all changes
92 adding changesets
92 adding changesets
93 adding manifests
93 adding manifests
94 adding file changes
94 adding file changes
95 added 1 changesets with 1 changes to 1 files
95 added 1 changesets with 1 changes to 1 files
96 new changesets 340e38bdcde4
96 new changesets 340e38bdcde4
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98
98
99 Test 'file:' uri handling:
99 Test 'file:' uri handling:
100
100
101 $ hg pull -q file://../test-does-not-exist
101 $ hg pull -q file://../test-does-not-exist
102 abort: file:// URLs can only refer to localhost
102 abort: file:// URLs can only refer to localhost
103 [255]
103 [255]
104
104
105 $ hg pull -q file://../test
105 $ hg pull -q file://../test
106 abort: file:// URLs can only refer to localhost
106 abort: file:// URLs can only refer to localhost
107 [255]
107 [255]
108
108
109 MSYS changes 'file:' into 'file;'
109 MSYS changes 'file:' into 'file;'
110
110
111 #if no-msys
111 #if no-msys
112 $ hg pull -q file:../test # no-msys
112 $ hg pull -q file:../test # no-msys
113 #endif
113 #endif
114
114
115 It's tricky to make file:// URLs working on every platform with
115 It's tricky to make file:// URLs working on every platform with
116 regular shell commands.
116 regular shell commands.
117
117
118 $ URL=`"$PYTHON" -c "from __future__ import print_function; import os; print('file://foobar' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test')"`
118 $ URL=`"$PYTHON" -c "from __future__ import print_function; import os; print('file://foobar' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test')"`
119 $ hg pull -q "$URL"
119 $ hg pull -q "$URL"
120 abort: file:// URLs can only refer to localhost
120 abort: file:// URLs can only refer to localhost
121 [255]
121 [255]
122
122
123 $ URL=`"$PYTHON" -c "from __future__ import print_function; import os; print('file://localhost' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test')"`
123 $ URL=`"$PYTHON" -c "from __future__ import print_function; import os; print('file://localhost' + ('/' + os.getcwd().replace(os.sep, '/')).replace('//', '/') + '/../test')"`
124 $ hg pull -q "$URL"
124 $ hg pull -q "$URL"
125
125
126 SEC: check for unsafe ssh url
126 SEC: check for unsafe ssh url
127
127
128 $ cat >> $HGRCPATH << EOF
128 $ cat >> $HGRCPATH << EOF
129 > [ui]
129 > [ui]
130 > ssh = sh -c "read l; read l; read l"
130 > ssh = sh -c "read l; read l; read l"
131 > EOF
131 > EOF
132
132
133 $ hg pull 'ssh://-oProxyCommand=touch${IFS}owned/path'
133 $ hg pull 'ssh://-oProxyCommand=touch${IFS}owned/path'
134 pulling from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
134 pulling from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
135 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
135 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
136 [255]
136 [255]
137 $ hg pull 'ssh://%2DoProxyCommand=touch${IFS}owned/path'
137 $ hg pull 'ssh://%2DoProxyCommand=touch${IFS}owned/path'
138 pulling from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
138 pulling from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
139 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
139 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
140 [255]
140 [255]
141 $ hg pull 'ssh://fakehost|touch${IFS}owned/path'
141 $ hg pull 'ssh://fakehost|touch${IFS}owned/path'
142 pulling from ssh://fakehost%7Ctouch%24%7BIFS%7Downed/path
142 pulling from ssh://fakehost%7Ctouch%24%7BIFS%7Downed/path
143 abort: no suitable response from remote hg!
143 abort: no suitable response from remote hg!
144 [255]
144 [255]
145 $ hg pull 'ssh://fakehost%7Ctouch%20owned/path'
145 $ hg --config ui.timestamp-output=true pull 'ssh://fakehost%7Ctouch%20owned/path'
146 pulling from ssh://fakehost%7Ctouch%20owned/path
146 \[20[2-9][0-9]-[01][0-9]-[0-3][0-9]T[0-5][0-9]:[0-5][0-9]:[0-5][0-9]\.[0-9][0-9][0-9][0-9][0-9][0-9]\] pulling from ssh://fakehost%7Ctouch%20owned/path (re)
147 abort: no suitable response from remote hg!
147 \[20[2-9][0-9]-[01][0-9]-[0-3][0-9]T[0-5][0-9]:[0-5][0-9]:[0-5][0-9]\.[0-9][0-9][0-9][0-9][0-9][0-9]\] abort: no suitable response from remote hg! (re)
148 [255]
148 [255]
149
149
150 $ [ ! -f owned ] || echo 'you got owned'
150 $ [ ! -f owned ] || echo 'you got owned'
151
151
152 $ cd ..
152 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now