s3:utils: Fix 'Usage:' for 'net ads enctypes'
[samba4-gss.git] / third_party / waf / waflib / Options.py
blobd4104917c82456c6c78701a78f05873c483d198d
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Scott Newton, 2005 (scottn)
4 # Thomas Nagy, 2006-2018 (ita)
6 """
7 Support for waf command-line options
9 Provides default and command-line options, as well the command
10 that reads the ``options`` wscript function.
11 """
13 import os, tempfile, optparse, sys, re
14 from waflib import Logs, Utils, Context, Errors
16 options = optparse.Values()
17 """
18 A global dictionary representing user-provided command-line options::
20 $ waf --foo=bar
21 """
23 commands = []
24 """
25 List of commands to execute extracted from the command-line. This list
26 is consumed during the execution by :py:func:`waflib.Scripting.run_commands`.
27 """
29 envvars = []
30 """
31 List of environment variable declarations placed after the Waf executable name.
32 These are detected by searching for "=" in the remaining arguments.
33 You probably do not want to use this.
34 """
36 lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform)
37 """
38 Name of the lock file that marks a project as configured
39 """
41 class opt_parser(optparse.OptionParser):
42 """
43 Command-line options parser.
44 """
45 def __init__(self, ctx, allow_unknown=False):
46 optparse.OptionParser.__init__(self, conflict_handler='resolve', add_help_option=False,
47 version='%s %s (%s)' % (Context.WAFNAME, Context.WAFVERSION, Context.WAFREVISION))
48 self.formatter.width = Logs.get_term_cols()
49 self.ctx = ctx
50 self.allow_unknown = allow_unknown
52 def _process_args(self, largs, rargs, values):
53 """
54 Custom _process_args to allow unknown options according to the allow_unknown status
55 """
56 while rargs:
57 try:
58 optparse.OptionParser._process_args(self,largs,rargs,values)
59 except (optparse.BadOptionError, optparse.AmbiguousOptionError) as e:
60 if self.allow_unknown:
61 largs.append(e.opt_str)
62 else:
63 self.error(str(e))
65 def _process_long_opt(self, rargs, values):
66 # --custom-option=-ftxyz is interpreted as -f -t... see #2280
67 if self.allow_unknown:
68 back = [] + rargs
69 try:
70 optparse.OptionParser._process_long_opt(self, rargs, values)
71 except optparse.BadOptionError:
72 while rargs:
73 rargs.pop()
74 rargs.extend(back)
75 rargs.pop(0)
76 raise
77 else:
78 optparse.OptionParser._process_long_opt(self, rargs, values)
80 def print_usage(self, file=None):
81 return self.print_help(file)
83 def get_usage(self):
84 """
85 Builds the message to print on ``waf --help``
87 :rtype: string
88 """
89 cmds_str = {}
90 for cls in Context.classes:
91 if not cls.cmd or cls.cmd == 'options' or cls.cmd.startswith( '_' ):
92 continue
94 s = cls.__doc__ or ''
95 cmds_str[cls.cmd] = s
97 if Context.g_module:
98 for (k, v) in Context.g_module.__dict__.items():
99 if k in ('options', 'init', 'shutdown'):
100 continue
102 if type(v) is type(Context.create_context):
103 if v.__doc__ and not k.startswith('_'):
104 cmds_str[k] = v.__doc__
106 just = 0
107 for k in cmds_str:
108 just = max(just, len(k))
110 lst = [' %s: %s' % (k.ljust(just), v) for (k, v) in cmds_str.items()]
111 lst.sort()
112 ret = '\n'.join(lst)
114 return '''%s [commands] [options]
116 Main commands (example: ./%s build -j4)
118 ''' % (Context.WAFNAME, Context.WAFNAME, ret)
121 class OptionsContext(Context.Context):
123 Collects custom options from wscript files and parses the command line.
124 Sets the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
126 cmd = 'options'
127 fun = 'options'
129 def __init__(self, **kw):
130 super(OptionsContext, self).__init__(**kw)
132 self.parser = opt_parser(self)
133 """Instance of :py:class:`waflib.Options.opt_parser`"""
135 self.option_groups = {}
137 jobs = self.jobs()
138 p = self.add_option
139 color = os.environ.get('NOCOLOR', '') and 'no' or 'auto'
140 if os.environ.get('CLICOLOR', '') == '0':
141 color = 'no'
142 elif os.environ.get('CLICOLOR_FORCE', '') == '1':
143 color = 'yes'
144 p('-c', '--color', dest='colors', default=color, action='store', help='whether to use colors (yes/no/auto) [default: auto]', choices=('yes', 'no', 'auto'))
145 p('-j', '--jobs', dest='jobs', default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs)
146 p('-k', '--keep', dest='keep', default=0, action='count', help='continue despite errors (-kk to try harder)')
147 p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]')
148 p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)')
149 p('--profile', dest='profile', default=0, action='store_true', help=optparse.SUPPRESS_HELP)
150 p('--pdb', dest='pdb', default=0, action='store_true', help=optparse.SUPPRESS_HELP)
151 p('-h', '--help', dest='whelp', default=0, action='store_true', help="show this help message and exit")
153 gr = self.add_option_group('Configuration options')
154 self.option_groups['configure options'] = gr
156 gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out')
157 gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top')
159 gr.add_option('--no-lock-in-run', action='store_true', default=os.environ.get('NO_LOCK_IN_RUN', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_run')
160 gr.add_option('--no-lock-in-out', action='store_true', default=os.environ.get('NO_LOCK_IN_OUT', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_out')
161 gr.add_option('--no-lock-in-top', action='store_true', default=os.environ.get('NO_LOCK_IN_TOP', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_top')
163 default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX'))
164 if not default_prefix:
165 if Utils.unversioned_sys_platform() == 'win32':
166 d = tempfile.gettempdir()
167 default_prefix = d[0].upper() + d[1:]
168 # win32 preserves the case, but gettempdir does not
169 else:
170 default_prefix = '/usr/local/'
171 gr.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: %r]' % default_prefix)
172 gr.add_option('--bindir', dest='bindir', help='bindir')
173 gr.add_option('--libdir', dest='libdir', help='libdir')
175 gr = self.add_option_group('Build and installation options')
176 self.option_groups['build and install options'] = gr
177 gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output')
178 gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"')
180 gr = self.add_option_group('Step options')
181 self.option_groups['step options'] = gr
182 gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
184 default_destdir = os.environ.get('DESTDIR', '')
186 gr = self.add_option_group('Installation and uninstallation options')
187 self.option_groups['install/uninstall options'] = gr
188 gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir')
189 gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation')
190 gr.add_option('--distcheck-args', metavar='ARGS', help='arguments to pass to distcheck', default=None, action='store')
192 def jobs(self):
194 Finds the optimal amount of cpu cores to use for parallel jobs.
195 At runtime the options can be obtained from :py:const:`waflib.Options.options` ::
197 from waflib.Options import options
198 njobs = options.jobs
200 :return: the amount of cpu cores
201 :rtype: int
203 count = int(os.environ.get('JOBS', 0))
204 if count < 1:
205 if 'NUMBER_OF_PROCESSORS' in os.environ:
206 # on Windows, use the NUMBER_OF_PROCESSORS environment variable
207 count = int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
208 else:
209 # on everything else, first try the POSIX sysconf values
210 if hasattr(os, 'sysconf_names'):
211 if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
212 count = int(os.sysconf('SC_NPROCESSORS_ONLN'))
213 elif 'SC_NPROCESSORS_CONF' in os.sysconf_names:
214 count = int(os.sysconf('SC_NPROCESSORS_CONF'))
215 if not count and os.name not in ('nt', 'java'):
216 try:
217 tmp = self.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet=0)
218 except Errors.WafError:
219 pass
220 else:
221 if re.match('^[0-9]+$', tmp):
222 count = int(tmp)
223 if count < 1:
224 count = 1
225 elif count > 1024:
226 count = 1024
227 return count
229 def add_option(self, *k, **kw):
231 Wraps ``optparse.add_option``::
233 def options(ctx):
234 ctx.add_option('-u', '--use', dest='use', default=False,
235 action='store_true', help='a boolean option')
237 :rtype: optparse option object
239 return self.parser.add_option(*k, **kw)
241 def add_option_group(self, *k, **kw):
243 Wraps ``optparse.add_option_group``::
245 def options(ctx):
246 gr = ctx.add_option_group('some options')
247 gr.add_option('-u', '--use', dest='use', default=False, action='store_true')
249 :rtype: optparse option group object
251 try:
252 gr = self.option_groups[k[0]]
253 except KeyError:
254 gr = self.parser.add_option_group(*k, **kw)
255 self.option_groups[k[0]] = gr
256 return gr
258 def get_option_group(self, opt_str):
260 Wraps ``optparse.get_option_group``::
262 def options(ctx):
263 gr = ctx.get_option_group('configure options')
264 gr.add_option('-o', '--out', action='store', default='',
265 help='build dir for the project', dest='out')
267 :rtype: optparse option group object
269 try:
270 return self.option_groups[opt_str]
271 except KeyError:
272 for group in self.parser.option_groups:
273 if group.title == opt_str:
274 return group
275 return None
277 def sanitize_path(self, path, cwd=None):
278 if not cwd:
279 cwd = Context.launch_dir
280 p = os.path.expanduser(path)
281 p = os.path.join(cwd, p)
282 p = os.path.normpath(p)
283 p = os.path.abspath(p)
284 return p
286 def parse_cmd_args(self, _args=None, cwd=None, allow_unknown=False):
288 Just parse the arguments
290 self.parser.allow_unknown = allow_unknown
291 (options, leftover_args) = self.parser.parse_args(args=_args)
292 envvars = []
293 commands = []
294 for arg in leftover_args:
295 if '=' in arg:
296 envvars.append(arg)
297 elif arg != 'options':
298 commands.append(arg)
300 if options.jobs < 1:
301 options.jobs = 1
302 for name in 'top out destdir prefix bindir libdir'.split():
303 # those paths are usually expanded from Context.launch_dir
304 if getattr(options, name, None):
305 path = self.sanitize_path(getattr(options, name), cwd)
306 setattr(options, name, path)
307 return options, commands, envvars
309 def init_module_vars(self, arg_options, arg_commands, arg_envvars):
310 options.__dict__.clear()
311 del commands[:]
312 del envvars[:]
314 options.__dict__.update(arg_options.__dict__)
315 commands.extend(arg_commands)
316 envvars.extend(arg_envvars)
318 for var in envvars:
319 (name, value) = var.split('=', 1)
320 os.environ[name.strip()] = value
322 def init_logs(self, options, commands, envvars):
323 Logs.verbose = options.verbose
324 if options.verbose >= 1:
325 self.load('errcheck')
327 colors = {'yes' : 2, 'auto' : 1, 'no' : 0}[options.colors]
328 Logs.enable_colors(colors)
330 if options.zones:
331 Logs.zones = options.zones.split(',')
332 if not Logs.verbose:
333 Logs.verbose = 1
334 elif Logs.verbose > 0:
335 Logs.zones = ['runner']
336 if Logs.verbose > 2:
337 Logs.zones = ['*']
339 def parse_args(self, _args=None):
341 Parses arguments from a list which is not necessarily the command-line.
342 Initializes the module variables options, commands and envvars
343 If help is requested, prints it and exit the application
345 :param _args: arguments
346 :type _args: list of strings
348 options, commands, envvars = self.parse_cmd_args()
349 self.init_logs(options, commands, envvars)
350 self.init_module_vars(options, commands, envvars)
352 def execute(self):
354 See :py:func:`waflib.Context.Context.execute`
356 super(OptionsContext, self).execute()
357 self.parse_args()
358 Utils.alloc_process_pool(options.jobs)