2
0
mirror of https://gitlab.com/ita1024/waf.git synced 2024-11-22 09:57:15 +01:00

Move from optparse to argparse

This commit is contained in:
Waf Project 2024-04-27 19:02:00 +02:00
parent a3fec9f0b3
commit bd5c22d484
7 changed files with 79 additions and 97 deletions

View File

@ -4,6 +4,7 @@ CHANGES IN WAF 2.1.0
+ Added wafcache + Added wafcache
+ waf_unit_test: Added task in returned tuples, custom reports should be adapted + waf_unit_test: Added task in returned tuples, custom reports should be adapted
~ Ensure ConfigurationContext.load and Context.load definitions are consistent and remove unused *k parameters ~ Ensure ConfigurationContext.load and Context.load definitions are consistent and remove unused *k parameters
~ Remove the dependency on optparse and use argparse instead
- Remove waflib.Runner.PriorityTasks.appendleft - Remove waflib.Runner.PriorityTasks.appendleft
- Remove waflib.Task.TaskBase - Remove waflib.Task.TaskBase
- Remove the upper class of waflib.Task.Task (metaclass syntax) - Remove the upper class of waflib.Task.Task (metaclass syntax)

View File

@ -10,10 +10,15 @@ Provides default and command-line options, as well the command
that reads the ``options`` wscript function. that reads the ``options`` wscript function.
""" """
import os, tempfile, optparse, sys, re import os, tempfile, argparse, sys, re
from waflib import Logs, Utils, Context, Errors from waflib import Logs, Utils, Context, Errors
options = optparse.Values()
class OptionValues:
def __str__(self):
return str(self.__dict__)
options = OptionValues()
""" """
A global dictionary representing user-provided command-line options:: A global dictionary representing user-provided command-line options::
@ -26,59 +31,40 @@ List of commands to execute extracted from the command-line. This list
is consumed during the execution by :py:func:`waflib.Scripting.run_commands`. is consumed during the execution by :py:func:`waflib.Scripting.run_commands`.
""" """
envvars = []
"""
List of environment variable declarations placed after the Waf executable name.
These are detected by searching for "=" in the remaining arguments.
You probably do not want to use this.
"""
lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform) lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform)
""" """
Name of the lock file that marks a project as configured Name of the lock file that marks a project as configured
""" """
class opt_parser(optparse.OptionParser): class ArgParser(argparse.ArgumentParser):
""" """
Command-line options parser. Command-line options parser.
""" """
def __init__(self, ctx, allow_unknown=False): def __init__(self, ctx):
optparse.OptionParser.__init__(self, conflict_handler='resolve', add_help_option=False, argparse.ArgumentParser.__init__(self, add_help=False)
version='%s %s (%s)' % (Context.WAFNAME, Context.WAFVERSION, Context.WAFREVISION))
self.formatter.width = Logs.get_term_cols()
self.ctx = ctx self.ctx = ctx
self.allow_unknown = allow_unknown self.usage = self.get_usage()
def _process_args(self, largs, rargs, values):
"""
Custom _process_args to allow unknown options according to the allow_unknown status
"""
while rargs:
try:
optparse.OptionParser._process_args(self,largs,rargs,values)
except (optparse.BadOptionError, optparse.AmbiguousOptionError) as e:
if self.allow_unknown:
largs.append(e.opt_str)
else:
self.error(str(e))
def _process_long_opt(self, rargs, values): def _get_formatter(self):
# --custom-option=-ftxyz is interpreted as -f -t... see #2280 """Initialize the argument parser to the adequate terminal width"""
if self.allow_unknown: return self.formatter_class(prog=self.prog, width=Logs.get_term_cols())
back = [] + rargs
try:
optparse.OptionParser._process_long_opt(self, rargs, values)
except optparse.BadOptionError:
while rargs:
rargs.pop()
rargs.extend(back)
rargs.pop(0)
raise
else:
optparse.OptionParser._process_long_opt(self, rargs, values)
def print_usage(self, file=None): def get_option(self, name):
return self.print_help(file) if name in self._option_string_actions:
return self._option_string_actions[name]
def remove_option(self, name):
if name in self._option_string_actions:
action = self._option_string_actions[name]
self._remove_action(action)
action.option_strings.remove(name)
self._option_string_actions.pop(name, None)
for group in self._action_groups:
try:
group._group_actions.remove(action)
except ValueError:
pass
def get_usage(self): def get_usage(self):
""" """
@ -100,7 +86,7 @@ class opt_parser(optparse.OptionParser):
continue continue
if type(v) is type(Context.create_context): if type(v) is type(Context.create_context):
if v.__doc__ and not k.startswith('_'): if v.__doc__ and len(v.__doc__.splitlines()) < 3 and not k.startswith('_'):
cmds_str[k] = v.__doc__ cmds_str[k] = v.__doc__
just = 0 just = 0
@ -129,8 +115,8 @@ class OptionsContext(Context.Context):
def __init__(self, **kw): def __init__(self, **kw):
super(OptionsContext, self).__init__(**kw) super(OptionsContext, self).__init__(**kw)
self.parser = opt_parser(self) self.parser = ArgParser(self)
"""Instance of :py:class:`waflib.Options.opt_parser`""" """Instance of :py:class:`waflib.Options.ArgParser`"""
self.option_groups = {} self.option_groups = {}
@ -142,23 +128,22 @@ class OptionsContext(Context.Context):
elif os.environ.get('CLICOLOR_FORCE', '') == '1': elif os.environ.get('CLICOLOR_FORCE', '') == '1':
color = 'yes' color = 'yes'
p('-c', '--color', dest='colors', default=color, action='store', help='whether to use colors (yes/no/auto) [default: auto]', choices=('yes', 'no', 'auto')) p('-c', '--color', dest='colors', default=color, action='store', help='whether to use colors (yes/no/auto) [default: auto]', choices=('yes', 'no', 'auto'))
p('-j', '--jobs', dest='jobs', default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs) p('-j', '--jobs', dest='jobs', default=jobs, type=int, help='amount of parallel jobs (%r)' % jobs)
p('-k', '--keep', dest='keep', default=0, action='count', help='continue despite errors (-kk to try harder)') p('-k', '--keep', dest='keep', default=0, action='count', help='continue despite errors (-kk to try harder)')
p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]') p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]')
p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)') p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)')
p('--profile', dest='profile', default=0, action='store_true', help=optparse.SUPPRESS_HELP) p('--profile', dest='profile', default=0, action='store_true', help=argparse.SUPPRESS)
p('--pdb', dest='pdb', default=0, action='store_true', help=optparse.SUPPRESS_HELP) p('--pdb', dest='pdb', default=0, action='store_true', help=argparse.SUPPRESS)
p('-h', '--help', dest='whelp', default=0, action='store_true', help="show this help message and exit") p('-h', '--help', dest='whelp', default=0, action='store_true', help="show this help message and exit")
gr = self.add_option_group('Configuration options') gr = self.add_option_group('Configuration options')
self.option_groups['configure options'] = gr
gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out') gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out')
gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top') gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top')
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') gr.add_option('--no-lock-in-run', action='store_true', default=os.environ.get('NO_LOCK_IN_RUN', ''), help=argparse.SUPPRESS, dest='no_lock_in_run')
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') gr.add_option('--no-lock-in-out', action='store_true', default=os.environ.get('NO_LOCK_IN_OUT', ''), help=argparse.SUPPRESS, dest='no_lock_in_out')
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') gr.add_option('--no-lock-in-top', action='store_true', default=os.environ.get('NO_LOCK_IN_TOP', ''), help=argparse.SUPPRESS, dest='no_lock_in_top')
default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX')) default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX'))
if not default_prefix: if not default_prefix:
@ -173,18 +158,15 @@ class OptionsContext(Context.Context):
gr.add_option('--libdir', dest='libdir', help='libdir') gr.add_option('--libdir', dest='libdir', help='libdir')
gr = self.add_option_group('Build and installation options') gr = self.add_option_group('Build and installation options')
self.option_groups['build and install options'] = gr
gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output') gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output')
gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"') gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"')
gr = self.add_option_group('Step options') gr = self.add_option_group('Step options')
self.option_groups['step options'] = gr
gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"') gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
default_destdir = os.environ.get('DESTDIR', '') default_destdir = os.environ.get('DESTDIR', '')
gr = self.add_option_group('Installation and uninstallation options') gr = self.add_option_group('Installation and uninstallation options')
self.option_groups['install/uninstall options'] = gr
gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir') gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir')
gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation') gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation')
gr.add_option('--distcheck-args', metavar='ARGS', help='arguments to pass to distcheck', default=None, action='store') gr.add_option('--distcheck-args', metavar='ARGS', help='arguments to pass to distcheck', default=None, action='store')
@ -227,16 +209,22 @@ class OptionsContext(Context.Context):
return count return count
def add_option(self, *k, **kw): def add_option(self, *k, **kw):
if 'type' in kw and kw['type'] == 'int':
Logs.warn('Invalid "type=str" in add_option (must be a class, not a string)')
kw['type'] = int
return self.add_argument(*k, **kw)
def add_argument(self, *k, **kw):
""" """
Wraps ``optparse.add_option``:: Wraps ``argparse.add_argument``::
def options(ctx): def options(ctx):
ctx.add_option('-u', '--use', dest='use', default=False, ctx.add_option('-u', '--use', dest='use', default=False,
action='store_true', help='a boolean option') action='store_true', help='a boolean option')
:rtype: optparse option object :rtype: argparse option object
""" """
return self.parser.add_option(*k, **kw) return self.parser.add_argument(*k, **kw)
def add_option_group(self, *k, **kw): def add_option_group(self, *k, **kw):
""" """
@ -248,11 +236,11 @@ class OptionsContext(Context.Context):
:rtype: optparse option group object :rtype: optparse option group object
""" """
try: gr = self.get_option_group(k[0])
gr = self.option_groups[k[0]] if not gr:
except KeyError: gr = self.parser.add_argument_group(*k, **kw)
gr = self.parser.add_option_group(*k, **kw) gr.add_option = gr.add_argument
self.option_groups[k[0]] = gr self.option_groups[k[0]] = gr
return gr return gr
def get_option_group(self, opt_str): def get_option_group(self, opt_str):
@ -269,7 +257,7 @@ class OptionsContext(Context.Context):
try: try:
return self.option_groups[opt_str] return self.option_groups[opt_str]
except KeyError: except KeyError:
for group in self.parser.option_groups: for group in self.parser._action_groups:
if group.title == opt_str: if group.title == opt_str:
return group return group
return None return None
@ -287,15 +275,13 @@ class OptionsContext(Context.Context):
""" """
Just parse the arguments Just parse the arguments
""" """
self.parser.allow_unknown = allow_unknown (options, leftover_args) = self.parser.parse_known_args(args=_args)
(options, leftover_args) = self.parser.parse_args(args=_args)
envvars = []
commands = [] commands = []
for arg in leftover_args: for arg in leftover_args:
if '=' in arg: if not allow_unknown and arg.startswith('-'):
envvars.append(arg) self.parser.print_help()
elif arg != 'options': raise Errors.WafError('Unknown option: %r' % arg)
commands.append(arg) commands.append(arg)
if options.jobs < 1: if options.jobs < 1:
options.jobs = 1 options.jobs = 1
@ -304,22 +290,9 @@ class OptionsContext(Context.Context):
if getattr(options, name, None): if getattr(options, name, None):
path = self.sanitize_path(getattr(options, name), cwd) path = self.sanitize_path(getattr(options, name), cwd)
setattr(options, name, path) setattr(options, name, path)
return options, commands, envvars return options, commands
def init_module_vars(self, arg_options, arg_commands, arg_envvars): def init_logs(self, options, commands):
options.__dict__.clear()
del commands[:]
del envvars[:]
options.__dict__.update(arg_options.__dict__)
commands.extend(arg_commands)
envvars.extend(arg_envvars)
for var in envvars:
(name, value) = var.split('=', 1)
os.environ[name.strip()] = value
def init_logs(self, options, commands, envvars):
Logs.verbose = options.verbose Logs.verbose = options.verbose
if options.verbose >= 1: if options.verbose >= 1:
self.load('errcheck') self.load('errcheck')
@ -339,15 +312,20 @@ class OptionsContext(Context.Context):
def parse_args(self, _args=None): def parse_args(self, _args=None):
""" """
Parses arguments from a list which is not necessarily the command-line. Parses arguments from a list which is not necessarily the command-line.
Initializes the module variables options, commands and envvars Initializes the module variables options and commands
If help is requested, prints it and exit the application If help is requested, prints it and exit the application
:param _args: arguments :param _args: arguments
:type _args: list of strings :type _args: list of strings
""" """
options, commands, envvars = self.parse_cmd_args(_args) arg_options, arg_commands = self.parse_cmd_args(_args)
self.init_logs(options, commands, envvars) self.init_logs(arg_options, commands)
self.init_module_vars(options, commands, envvars)
options.__dict__.clear()
del commands[:]
options.__dict__.update(arg_options.__dict__)
commands.extend(arg_commands)
def execute(self): def execute(self):
""" """

View File

@ -50,7 +50,7 @@ def waf_entry_point(current_directory, version, wafdir):
sys.argv.pop(1) sys.argv.pop(1)
ctx = Context.create_context('options') ctx = Context.create_context('options')
(options, commands, env) = ctx.parse_cmd_args(allow_unknown=True) (options, commands) = ctx.parse_cmd_args(allow_unknown=True)
if options.top: if options.top:
start_dir = Context.run_dir = Context.top_dir = options.top start_dir = Context.run_dir = Context.top_dir = options.top
no_climb = True no_climb = True

View File

@ -114,7 +114,7 @@ def options(opt):
option = opt.parser.get_option(k) option = opt.parser.get_option(k)
if option: if option:
opt.parser.remove_option(k) opt.parser.remove_option(k)
inst_dir.add_option(option) inst_dir.add_argument(k, dest=option.dest, help=option.help, default=option.default)
inst_dir.add_option('--exec-prefix', inst_dir.add_option('--exec-prefix',
help = 'installation prefix for binaries [PREFIX]', help = 'installation prefix for binaries [PREFIX]',
@ -125,7 +125,10 @@ def options(opt):
for name, help, default in _options: for name, help, default in _options:
option_name = '--' + name option_name = '--' + name
opt.parser.remove_option(option_name)
str_default = default str_default = default
str_help = '%s [%s]' % (help, re.sub(r'\$\{([^}]+)\}', r'\1', str_default)) str_help = '%s [%s]' % (help, re.sub(r'\$\{([^}]+)\}', r'\1', str_default))
dirs_options.add_option(option_name, help=str_help, default='', dest=name.upper()) dirs_options.add_option(option_name, help=str_help, default='', dest=name)

View File

@ -42,7 +42,7 @@ def name_to_dest(x):
def options(opt): def options(opt):
def x(opt, param): def x(opt, param):
dest = name_to_dest(param) dest = name_to_dest(param)
gr = opt.get_option_group("configure options") gr = opt.get_option_group("Configuration options")
gr.add_option('--%s-root' % dest, gr.add_option('--%s-root' % dest,
help="path containing include and lib subfolders for %s" \ help="path containing include and lib subfolders for %s" \
% param, % param,

View File

@ -116,7 +116,7 @@ class OptionsReview(Options.OptionsContext):
their default value from their optparse object and store them their default value from their optparse object and store them
into the review dictionaries. into the review dictionaries.
""" """
gr = self.get_option_group('configure options') gr = self.get_option_group('Configuration options')
for opt in gr.option_list: for opt in gr.option_list:
if opt.action != 'store' or opt.dest in ("out", "top"): if opt.action != 'store' or opt.dest in ("out", "top"):
continue continue

View File

@ -88,7 +88,7 @@ DEFAULT_DIR = 'wafcfg'
sys.path.append(osp.abspath(DEFAULT_DIR)) sys.path.append(osp.abspath(DEFAULT_DIR))
def options(self): def options(self):
group = self.add_option_group('configure options') group = self.add_option_group('Configuration options')
group.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing') group.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing')
group.add_option('--use-config', action='store', default=None, group.add_option('--use-config', action='store', default=None,