#!/usr/bin/env python # Copyright (c) Facebook, Inc. and its affiliates. from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals 'Argument parsing logic shared by all fbcode_builder CLI tools.' import argparse import logging from shell_quoting import raw_shell, ShellQuoted def parse_args_to_fbcode_builder_opts(add_args_fn, top_level_opts, opts, help): ''' Provides some standard arguments: --debug, --option, --shell-quoted-option Then, calls `add_args_fn(parser)` to add application-specific arguments. `opts` are first used as defaults for the various command-line arguments. Then, the parsed arguments are mapped back into `opts`, which then become the values for `FBCodeBuilder.option()`, to be used both by the builder and by `get_steps_fn()`. `help` is printed in response to the `--help` argument. ''' top_level_opts = set(top_level_opts) parser = argparse.ArgumentParser( description=help, formatter_class=argparse.RawDescriptionHelpFormatter ) add_args_fn(parser) parser.add_argument( '--option', nargs=2, metavar=('KEY', 'VALUE'), action='append', default=[ (k, v) for k, v in opts.items() if k not in top_level_opts and not isinstance(v, ShellQuoted) ], help='Set project-specific options. These are assumed to be raw ' 'strings, to be shell-escaped as needed. Default: %(default)s.', ) parser.add_argument( '--shell-quoted-option', nargs=2, metavar=('KEY', 'VALUE'), action='append', default=[ (k, raw_shell(v)) for k, v in opts.items() if k not in top_level_opts and isinstance(v, ShellQuoted) ], help='Set project-specific options. These are assumed to be shell-' 'quoted, and may be used in commands as-is. Default: %(default)s.', ) parser.add_argument('--debug', action='store_true', help='Log more') args = parser.parse_args() logging.basicConfig( level=logging.DEBUG if args.debug else logging.INFO, format='%(levelname)s: %(message)s' ) # Map command-line args back into opts. logging.debug('opts before command-line arguments: {0}'.format(opts)) new_opts = {} for key in top_level_opts: val = getattr(args, key) # Allow clients to unset a default by passing a value of None in opts if val is not None: new_opts[key] = val for key, val in args.option: new_opts[key] = val for key, val in args.shell_quoted_option: new_opts[key] = ShellQuoted(val) logging.debug('opts after command-line arguments: {0}'.format(new_opts)) return new_opts