##// END OF EJS Templates
check-config: syntax to allow inconsistent config values...
Gregory Szorc -
r33192:5d8942db default
parent child Browse files
Show More
@@ -1,130 +1,139 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # check-config - a config flag documentation checker for Mercurial
3 # check-config - a config flag documentation checker for Mercurial
4 #
4 #
5 # Copyright 2015 Matt Mackall <mpm@selenic.com>
5 # Copyright 2015 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 from __future__ import absolute_import, print_function
10 from __future__ import absolute_import, print_function
11 import re
11 import re
12 import sys
12 import sys
13
13
14 foundopts = {}
14 foundopts = {}
15 documented = {}
15 documented = {}
16 allowinconsistent = set()
16
17
17 configre = re.compile(r'''
18 configre = re.compile(r'''
18 # Function call
19 # Function call
19 ui\.config(?P<ctype>|int|bool|list)\(
20 ui\.config(?P<ctype>|int|bool|list)\(
20 # First argument.
21 # First argument.
21 ['"](?P<section>\S+)['"],\s*
22 ['"](?P<section>\S+)['"],\s*
22 # Second argument
23 # Second argument
23 ['"](?P<option>\S+)['"](,\s+
24 ['"](?P<option>\S+)['"](,\s+
24 (?:default=)?(?P<default>\S+?))?
25 (?:default=)?(?P<default>\S+?))?
25 \)''', re.VERBOSE | re.MULTILINE)
26 \)''', re.VERBOSE | re.MULTILINE)
26
27
27 configwithre = re.compile('''
28 configwithre = re.compile('''
28 ui\.config(?P<ctype>with)\(
29 ui\.config(?P<ctype>with)\(
29 # First argument is callback function. This doesn't parse robustly
30 # First argument is callback function. This doesn't parse robustly
30 # if it is e.g. a function call.
31 # if it is e.g. a function call.
31 [^,]+,\s*
32 [^,]+,\s*
32 ['"](?P<section>\S+)['"],\s*
33 ['"](?P<section>\S+)['"],\s*
33 ['"](?P<option>\S+)['"](,\s+
34 ['"](?P<option>\S+)['"](,\s+
34 (?:default=)?(?P<default>\S+?))?
35 (?:default=)?(?P<default>\S+?))?
35 \)''', re.VERBOSE | re.MULTILINE)
36 \)''', re.VERBOSE | re.MULTILINE)
36
37
37 configpartialre = (r"""ui\.config""")
38 configpartialre = (r"""ui\.config""")
38
39
40 ignorere = re.compile(r'''
41 \#\s(?P<reason>internal|experimental|deprecated|developer|inconsistent)\s
42 config:\s(?P<config>\S+\.\S+)$
43 ''', re.VERBOSE | re.MULTILINE)
44
39 def main(args):
45 def main(args):
40 for f in args:
46 for f in args:
41 sect = ''
47 sect = ''
42 prevname = ''
48 prevname = ''
43 confsect = ''
49 confsect = ''
44 carryover = ''
50 carryover = ''
45 for l in open(f):
51 for l in open(f):
46
52
47 # check topic-like bits
53 # check topic-like bits
48 m = re.match('\s*``(\S+)``', l)
54 m = re.match('\s*``(\S+)``', l)
49 if m:
55 if m:
50 prevname = m.group(1)
56 prevname = m.group(1)
51 if re.match('^\s*-+$', l):
57 if re.match('^\s*-+$', l):
52 sect = prevname
58 sect = prevname
53 prevname = ''
59 prevname = ''
54
60
55 if sect and prevname:
61 if sect and prevname:
56 name = sect + '.' + prevname
62 name = sect + '.' + prevname
57 documented[name] = 1
63 documented[name] = 1
58
64
59 # check docstring bits
65 # check docstring bits
60 m = re.match(r'^\s+\[(\S+)\]', l)
66 m = re.match(r'^\s+\[(\S+)\]', l)
61 if m:
67 if m:
62 confsect = m.group(1)
68 confsect = m.group(1)
63 continue
69 continue
64 m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
70 m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
65 if m:
71 if m:
66 name = confsect + '.' + m.group(1)
72 name = confsect + '.' + m.group(1)
67 documented[name] = 1
73 documented[name] = 1
68
74
69 # like the bugzilla extension
75 # like the bugzilla extension
70 m = re.match(r'^\s*(\S+\.\S+)$', l)
76 m = re.match(r'^\s*(\S+\.\S+)$', l)
71 if m:
77 if m:
72 documented[m.group(1)] = 1
78 documented[m.group(1)] = 1
73
79
74 # like convert
80 # like convert
75 m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
81 m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
76 if m:
82 if m:
77 documented[m.group(1)] = 1
83 documented[m.group(1)] = 1
78
84
79 # quoted in help or docstrings
85 # quoted in help or docstrings
80 m = re.match(r'.*?``(\S+\.\S+)``', l)
86 m = re.match(r'.*?``(\S+\.\S+)``', l)
81 if m:
87 if m:
82 documented[m.group(1)] = 1
88 documented[m.group(1)] = 1
83
89
84 # look for ignore markers
90 # look for ignore markers
85 m = re.search(r'# (?:internal|experimental|deprecated|developer)'
91 m = ignorere.search(l)
86 ' config: (\S+\.\S+)$', l)
87 if m:
92 if m:
88 documented[m.group(1)] = 1
93 if m.group('reason') == 'inconsistent':
94 allowinconsistent.add(m.group('config'))
95 else:
96 documented[m.group('config')] = 1
89
97
90 # look for code-like bits
98 # look for code-like bits
91 line = carryover + l
99 line = carryover + l
92 m = configre.search(line) or configwithre.search(line)
100 m = configre.search(line) or configwithre.search(line)
93 if m:
101 if m:
94 ctype = m.group('ctype')
102 ctype = m.group('ctype')
95 if not ctype:
103 if not ctype:
96 ctype = 'str'
104 ctype = 'str'
97 name = m.group('section') + "." + m.group('option')
105 name = m.group('section') + "." + m.group('option')
98 default = m.group('default')
106 default = m.group('default')
99 if default in (None, 'False', 'None', '0', '[]', '""', "''"):
107 if default in (None, 'False', 'None', '0', '[]', '""', "''"):
100 default = ''
108 default = ''
101 if re.match('[a-z.]+$', default):
109 if re.match('[a-z.]+$', default):
102 default = '<variable>'
110 default = '<variable>'
103 if name in foundopts and (ctype, default) != foundopts[name]:
111 if (name in foundopts and (ctype, default) != foundopts[name]
112 and name not in allowinconsistent):
104 print(l)
113 print(l)
105 print("conflict on %s: %r != %r" % (name, (ctype, default),
114 print("conflict on %s: %r != %r" % (name, (ctype, default),
106 foundopts[name]))
115 foundopts[name]))
107 foundopts[name] = (ctype, default)
116 foundopts[name] = (ctype, default)
108 carryover = ''
117 carryover = ''
109 else:
118 else:
110 m = re.search(configpartialre, line)
119 m = re.search(configpartialre, line)
111 if m:
120 if m:
112 carryover = line
121 carryover = line
113 else:
122 else:
114 carryover = ''
123 carryover = ''
115
124
116 for name in sorted(foundopts):
125 for name in sorted(foundopts):
117 if name not in documented:
126 if name not in documented:
118 if not (name.startswith("devel.") or
127 if not (name.startswith("devel.") or
119 name.startswith("experimental.") or
128 name.startswith("experimental.") or
120 name.startswith("debug.")):
129 name.startswith("debug.")):
121 ctype, default = foundopts[name]
130 ctype, default = foundopts[name]
122 if default:
131 if default:
123 default = ' [%s]' % default
132 default = ' [%s]' % default
124 print("undocumented: %s (%s)%s" % (name, ctype, default))
133 print("undocumented: %s (%s)%s" % (name, ctype, default))
125
134
126 if __name__ == "__main__":
135 if __name__ == "__main__":
127 if len(sys.argv) > 1:
136 if len(sys.argv) > 1:
128 sys.exit(main(sys.argv[1:]))
137 sys.exit(main(sys.argv[1:]))
129 else:
138 else:
130 sys.exit(main([l.rstrip() for l in sys.stdin]))
139 sys.exit(main([l.rstrip() for l in sys.stdin]))
@@ -1,237 +1,238 b''
1 # profiling.py - profiling functions
1 # profiling.py - profiling functions
2 #
2 #
3 # Copyright 2016 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2016 Gregory Szorc <gregory.szorc@gmail.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, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import contextlib
10 import contextlib
11
11
12 from .i18n import _
12 from .i18n import _
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 extensions,
16 extensions,
17 util,
17 util,
18 )
18 )
19
19
20 def _loadprofiler(ui, profiler):
20 def _loadprofiler(ui, profiler):
21 """load profiler extension. return profile method, or None on failure"""
21 """load profiler extension. return profile method, or None on failure"""
22 extname = profiler
22 extname = profiler
23 extensions.loadall(ui, whitelist=[extname])
23 extensions.loadall(ui, whitelist=[extname])
24 try:
24 try:
25 mod = extensions.find(extname)
25 mod = extensions.find(extname)
26 except KeyError:
26 except KeyError:
27 return None
27 return None
28 else:
28 else:
29 return getattr(mod, 'profile', None)
29 return getattr(mod, 'profile', None)
30
30
31 @contextlib.contextmanager
31 @contextlib.contextmanager
32 def lsprofile(ui, fp):
32 def lsprofile(ui, fp):
33 format = ui.config('profiling', 'format', default='text')
33 format = ui.config('profiling', 'format', default='text')
34 field = ui.config('profiling', 'sort', default='inlinetime')
34 field = ui.config('profiling', 'sort', default='inlinetime')
35 limit = ui.configint('profiling', 'limit', default=30)
35 limit = ui.configint('profiling', 'limit', default=30)
36 climit = ui.configint('profiling', 'nested', default=0)
36 climit = ui.configint('profiling', 'nested', default=0)
37
37
38 if format not in ['text', 'kcachegrind']:
38 if format not in ['text', 'kcachegrind']:
39 ui.warn(_("unrecognized profiling format '%s'"
39 ui.warn(_("unrecognized profiling format '%s'"
40 " - Ignored\n") % format)
40 " - Ignored\n") % format)
41 format = 'text'
41 format = 'text'
42
42
43 try:
43 try:
44 from . import lsprof
44 from . import lsprof
45 except ImportError:
45 except ImportError:
46 raise error.Abort(_(
46 raise error.Abort(_(
47 'lsprof not available - install from '
47 'lsprof not available - install from '
48 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
48 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
49 p = lsprof.Profiler()
49 p = lsprof.Profiler()
50 p.enable(subcalls=True)
50 p.enable(subcalls=True)
51 try:
51 try:
52 yield
52 yield
53 finally:
53 finally:
54 p.disable()
54 p.disable()
55
55
56 if format == 'kcachegrind':
56 if format == 'kcachegrind':
57 from . import lsprofcalltree
57 from . import lsprofcalltree
58 calltree = lsprofcalltree.KCacheGrind(p)
58 calltree = lsprofcalltree.KCacheGrind(p)
59 calltree.output(fp)
59 calltree.output(fp)
60 else:
60 else:
61 # format == 'text'
61 # format == 'text'
62 stats = lsprof.Stats(p.getstats())
62 stats = lsprof.Stats(p.getstats())
63 stats.sort(field)
63 stats.sort(field)
64 stats.pprint(limit=limit, file=fp, climit=climit)
64 stats.pprint(limit=limit, file=fp, climit=climit)
65
65
66 @contextlib.contextmanager
66 @contextlib.contextmanager
67 def flameprofile(ui, fp):
67 def flameprofile(ui, fp):
68 try:
68 try:
69 from flamegraph import flamegraph
69 from flamegraph import flamegraph
70 except ImportError:
70 except ImportError:
71 raise error.Abort(_(
71 raise error.Abort(_(
72 'flamegraph not available - install from '
72 'flamegraph not available - install from '
73 'https://github.com/evanhempel/python-flamegraph'))
73 'https://github.com/evanhempel/python-flamegraph'))
74 # developer config: profiling.freq
74 # developer config: profiling.freq
75 freq = ui.configint('profiling', 'freq', default=1000)
75 freq = ui.configint('profiling', 'freq', default=1000)
76 filter_ = None
76 filter_ = None
77 collapse_recursion = True
77 collapse_recursion = True
78 thread = flamegraph.ProfileThread(fp, 1.0 / freq,
78 thread = flamegraph.ProfileThread(fp, 1.0 / freq,
79 filter_, collapse_recursion)
79 filter_, collapse_recursion)
80 start_time = util.timer()
80 start_time = util.timer()
81 try:
81 try:
82 thread.start()
82 thread.start()
83 yield
83 yield
84 finally:
84 finally:
85 thread.stop()
85 thread.stop()
86 thread.join()
86 thread.join()
87 print('Collected %d stack frames (%d unique) in %2.2f seconds.' % (
87 print('Collected %d stack frames (%d unique) in %2.2f seconds.' % (
88 util.timer() - start_time, thread.num_frames(),
88 util.timer() - start_time, thread.num_frames(),
89 thread.num_frames(unique=True)))
89 thread.num_frames(unique=True)))
90
90
91 @contextlib.contextmanager
91 @contextlib.contextmanager
92 def statprofile(ui, fp):
92 def statprofile(ui, fp):
93 from . import statprof
93 from . import statprof
94
94
95 freq = ui.configint('profiling', 'freq', default=1000)
95 freq = ui.configint('profiling', 'freq', default=1000)
96 if freq > 0:
96 if freq > 0:
97 # Cannot reset when profiler is already active. So silently no-op.
97 # Cannot reset when profiler is already active. So silently no-op.
98 if statprof.state.profile_level == 0:
98 if statprof.state.profile_level == 0:
99 statprof.reset(freq)
99 statprof.reset(freq)
100 else:
100 else:
101 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
101 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
102
102
103 statprof.start(mechanism='thread')
103 statprof.start(mechanism='thread')
104
104
105 try:
105 try:
106 yield
106 yield
107 finally:
107 finally:
108 data = statprof.stop()
108 data = statprof.stop()
109
109
110 profformat = ui.config('profiling', 'statformat', 'hotpath')
110 profformat = ui.config('profiling', 'statformat', 'hotpath')
111
111
112 formats = {
112 formats = {
113 'byline': statprof.DisplayFormats.ByLine,
113 'byline': statprof.DisplayFormats.ByLine,
114 'bymethod': statprof.DisplayFormats.ByMethod,
114 'bymethod': statprof.DisplayFormats.ByMethod,
115 'hotpath': statprof.DisplayFormats.Hotpath,
115 'hotpath': statprof.DisplayFormats.Hotpath,
116 'json': statprof.DisplayFormats.Json,
116 'json': statprof.DisplayFormats.Json,
117 'chrome': statprof.DisplayFormats.Chrome,
117 'chrome': statprof.DisplayFormats.Chrome,
118 }
118 }
119
119
120 if profformat in formats:
120 if profformat in formats:
121 displayformat = formats[profformat]
121 displayformat = formats[profformat]
122 else:
122 else:
123 ui.warn(_('unknown profiler output format: %s\n') % profformat)
123 ui.warn(_('unknown profiler output format: %s\n') % profformat)
124 displayformat = statprof.DisplayFormats.Hotpath
124 displayformat = statprof.DisplayFormats.Hotpath
125
125
126 kwargs = {}
126 kwargs = {}
127
127
128 def fraction(s):
128 def fraction(s):
129 if isinstance(s, (float, int)):
129 if isinstance(s, (float, int)):
130 return float(s)
130 return float(s)
131 if s.endswith('%'):
131 if s.endswith('%'):
132 v = float(s[:-1]) / 100
132 v = float(s[:-1]) / 100
133 else:
133 else:
134 v = float(s)
134 v = float(s)
135 if 0 <= v <= 1:
135 if 0 <= v <= 1:
136 return v
136 return v
137 raise ValueError(s)
137 raise ValueError(s)
138
138
139 if profformat == 'chrome':
139 if profformat == 'chrome':
140 showmin = ui.configwith(fraction, 'profiling', 'showmin', 0.005)
140 showmin = ui.configwith(fraction, 'profiling', 'showmin', 0.005)
141 showmax = ui.configwith(fraction, 'profiling', 'showmax', 0.999)
141 showmax = ui.configwith(fraction, 'profiling', 'showmax', 0.999)
142 kwargs.update(minthreshold=showmin, maxthreshold=showmax)
142 kwargs.update(minthreshold=showmin, maxthreshold=showmax)
143 elif profformat == 'hotpath':
143 elif profformat == 'hotpath':
144 # inconsistent config: profiling.showmin
144 limit = ui.configwith(fraction, 'profiling', 'showmin', 0.05)
145 limit = ui.configwith(fraction, 'profiling', 'showmin', 0.05)
145 kwargs['limit'] = limit
146 kwargs['limit'] = limit
146
147
147 statprof.display(fp, data=data, format=displayformat, **kwargs)
148 statprof.display(fp, data=data, format=displayformat, **kwargs)
148
149
149 class profile(object):
150 class profile(object):
150 """Start profiling.
151 """Start profiling.
151
152
152 Profiling is active when the context manager is active. When the context
153 Profiling is active when the context manager is active. When the context
153 manager exits, profiling results will be written to the configured output.
154 manager exits, profiling results will be written to the configured output.
154 """
155 """
155 def __init__(self, ui, enabled=True):
156 def __init__(self, ui, enabled=True):
156 self._ui = ui
157 self._ui = ui
157 self._output = None
158 self._output = None
158 self._fp = None
159 self._fp = None
159 self._fpdoclose = True
160 self._fpdoclose = True
160 self._profiler = None
161 self._profiler = None
161 self._enabled = enabled
162 self._enabled = enabled
162 self._entered = False
163 self._entered = False
163 self._started = False
164 self._started = False
164
165
165 def __enter__(self):
166 def __enter__(self):
166 self._entered = True
167 self._entered = True
167 if self._enabled:
168 if self._enabled:
168 self.start()
169 self.start()
169 return self
170 return self
170
171
171 def start(self):
172 def start(self):
172 """Start profiling.
173 """Start profiling.
173
174
174 The profiling will stop at the context exit.
175 The profiling will stop at the context exit.
175
176
176 If the profiler was already started, this has no effect."""
177 If the profiler was already started, this has no effect."""
177 if not self._entered:
178 if not self._entered:
178 raise error.ProgrammingError()
179 raise error.ProgrammingError()
179 if self._started:
180 if self._started:
180 return
181 return
181 self._started = True
182 self._started = True
182 profiler = encoding.environ.get('HGPROF')
183 profiler = encoding.environ.get('HGPROF')
183 proffn = None
184 proffn = None
184 if profiler is None:
185 if profiler is None:
185 profiler = self._ui.config('profiling', 'type', default='stat')
186 profiler = self._ui.config('profiling', 'type', default='stat')
186 if profiler not in ('ls', 'stat', 'flame'):
187 if profiler not in ('ls', 'stat', 'flame'):
187 # try load profiler from extension with the same name
188 # try load profiler from extension with the same name
188 proffn = _loadprofiler(self._ui, profiler)
189 proffn = _loadprofiler(self._ui, profiler)
189 if proffn is None:
190 if proffn is None:
190 self._ui.warn(_("unrecognized profiler '%s' - ignored\n")
191 self._ui.warn(_("unrecognized profiler '%s' - ignored\n")
191 % profiler)
192 % profiler)
192 profiler = 'stat'
193 profiler = 'stat'
193
194
194 self._output = self._ui.config('profiling', 'output')
195 self._output = self._ui.config('profiling', 'output')
195
196
196 try:
197 try:
197 if self._output == 'blackbox':
198 if self._output == 'blackbox':
198 self._fp = util.stringio()
199 self._fp = util.stringio()
199 elif self._output:
200 elif self._output:
200 path = self._ui.expandpath(self._output)
201 path = self._ui.expandpath(self._output)
201 self._fp = open(path, 'wb')
202 self._fp = open(path, 'wb')
202 else:
203 else:
203 self._fpdoclose = False
204 self._fpdoclose = False
204 self._fp = self._ui.ferr
205 self._fp = self._ui.ferr
205
206
206 if proffn is not None:
207 if proffn is not None:
207 pass
208 pass
208 elif profiler == 'ls':
209 elif profiler == 'ls':
209 proffn = lsprofile
210 proffn = lsprofile
210 elif profiler == 'flame':
211 elif profiler == 'flame':
211 proffn = flameprofile
212 proffn = flameprofile
212 else:
213 else:
213 proffn = statprofile
214 proffn = statprofile
214
215
215 self._profiler = proffn(self._ui, self._fp)
216 self._profiler = proffn(self._ui, self._fp)
216 self._profiler.__enter__()
217 self._profiler.__enter__()
217 except: # re-raises
218 except: # re-raises
218 self._closefp()
219 self._closefp()
219 raise
220 raise
220
221
221 def __exit__(self, exception_type, exception_value, traceback):
222 def __exit__(self, exception_type, exception_value, traceback):
222 propagate = None
223 propagate = None
223 if self._profiler is not None:
224 if self._profiler is not None:
224 propagate = self._profiler.__exit__(exception_type, exception_value,
225 propagate = self._profiler.__exit__(exception_type, exception_value,
225 traceback)
226 traceback)
226 if self._output == 'blackbox':
227 if self._output == 'blackbox':
227 val = 'Profile:\n%s' % self._fp.getvalue()
228 val = 'Profile:\n%s' % self._fp.getvalue()
228 # ui.log treats the input as a format string,
229 # ui.log treats the input as a format string,
229 # so we need to escape any % signs.
230 # so we need to escape any % signs.
230 val = val.replace('%', '%%')
231 val = val.replace('%', '%%')
231 self._ui.log('profile', val)
232 self._ui.log('profile', val)
232 self._closefp()
233 self._closefp()
233 return propagate
234 return propagate
234
235
235 def _closefp(self):
236 def _closefp(self):
236 if self._fpdoclose and self._fp is not None:
237 if self._fpdoclose and self._fp is not None:
237 self._fp.close()
238 self._fp.close()
@@ -1,38 +1,47 b''
1 #require test-repo
1 #require test-repo
2
2
3 $ . "$TESTDIR/helpers-testrepo.sh"
3 $ . "$TESTDIR/helpers-testrepo.sh"
4
4
5 Sanity check check-config.py
5 Sanity check check-config.py
6
6
7 $ cat > testfile.py << EOF
7 $ cat > testfile.py << EOF
8 > # Good
8 > # Good
9 > foo = ui.config('ui', 'username')
9 > foo = ui.config('ui', 'username')
10 > # Missing
10 > # Missing
11 > foo = ui.config('ui', 'doesnotexist')
11 > foo = ui.config('ui', 'doesnotexist')
12 > # Missing different type
12 > # Missing different type
13 > foo = ui.configint('ui', 'missingint')
13 > foo = ui.configint('ui', 'missingint')
14 > # Missing with default value
14 > # Missing with default value
15 > foo = ui.configbool('ui', 'missingbool1', default=True)
15 > foo = ui.configbool('ui', 'missingbool1', default=True)
16 > foo = ui.configbool('ui', 'missingbool2', False)
16 > foo = ui.configbool('ui', 'missingbool2', False)
17 > # Inconsistent values for defaults.
18 > foo = ui.configint('ui', 'intdefault', default=1)
19 > foo = ui.configint('ui', 'intdefault', default=42)
20 > # Can suppress inconsistent value error
21 > foo = ui.configint('ui', 'intdefault2', default=1)
22 > # inconsistent config: ui.intdefault2
23 > foo = ui.configint('ui', 'intdefault2', default=42)
17 > EOF
24 > EOF
18
25
19 $ cat > files << EOF
26 $ cat > files << EOF
20 > mercurial/help/config.txt
27 > mercurial/help/config.txt
21 > $TESTTMP/testfile.py
28 > $TESTTMP/testfile.py
22 > EOF
29 > EOF
23
30
24 $ cd "$TESTDIR"/..
31 $ cd "$TESTDIR"/..
25
32
26 $ $PYTHON contrib/check-config.py < $TESTTMP/files
33 $ $PYTHON contrib/check-config.py < $TESTTMP/files
34 foo = ui.configint('ui', 'intdefault', default=42)
35
36 conflict on ui.intdefault: ('int', '42') != ('int', '1')
27 undocumented: ui.doesnotexist (str)
37 undocumented: ui.doesnotexist (str)
38 undocumented: ui.intdefault (int) [42]
39 undocumented: ui.intdefault2 (int) [42]
28 undocumented: ui.missingbool1 (bool) [True]
40 undocumented: ui.missingbool1 (bool) [True]
29 undocumented: ui.missingbool2 (bool)
41 undocumented: ui.missingbool2 (bool)
30 undocumented: ui.missingint (int)
42 undocumented: ui.missingint (int)
31
43
32 New errors are not allowed. Warnings are strongly discouraged.
44 New errors are not allowed. Warnings are strongly discouraged.
33
45
34 $ syshg files "set:(**.py or **.txt) - tests/**" | sed 's|\\|/|g' |
46 $ syshg files "set:(**.py or **.txt) - tests/**" | sed 's|\\|/|g' |
35 > $PYTHON contrib/check-config.py
47 > $PYTHON contrib/check-config.py
36 limit = ui.configwith(fraction, 'profiling', 'showmin', 0.05)
37
38 conflict on profiling.showmin: ('with', '0.05') != ('with', '0.005')
General Comments 0
You need to be logged in to leave comments. Login now