Index: third_party/typ/typ/arg_parser.py |
diff --git a/third_party/typ/typ/arg_parser.py b/third_party/typ/typ/arg_parser.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3327e060c637d2d13884ec1819b95f570c4ae203 |
--- /dev/null |
+++ b/third_party/typ/typ/arg_parser.py |
@@ -0,0 +1,264 @@ |
+# Copyright 2014 Google Inc. All rights reserved. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+import argparse |
+import optparse |
+ |
+from typ.host import Host |
+ |
+ |
+class _Bailout(Exception): |
+ pass |
+ |
+ |
+DEFAULT_COVERAGE_OMIT = ['*/typ/*', '*/site-packages/*'] |
+DEFAULT_STATUS_FORMAT = '[%f/%t] ' |
+DEFAULT_SUFFIXES = ['*_test.py', '*_unittest.py'] |
+ |
+ |
+class ArgumentParser(argparse.ArgumentParser): |
+ |
+ @staticmethod |
+ def add_option_group(parser, title, discovery=False, |
+ running=False, reporting=False, skip=None): |
+ # TODO: Get rid of this when telemetry upgrades to argparse. |
+ ap = ArgumentParser(add_help=False, version=False, discovery=discovery, |
+ running=running, reporting=reporting) |
+ optlist = ap.optparse_options(skip=skip) |
+ group = optparse.OptionGroup(parser, title) |
+ group.add_options(optlist) |
+ parser.add_option_group(group) |
+ |
+ def __init__(self, host=None, add_help=True, version=True, discovery=True, |
+ reporting=True, running=True): |
+ super(ArgumentParser, self).__init__(prog='typ', add_help=add_help) |
+ |
+ self._host = host or Host() |
+ self.exit_status = None |
+ |
+ self.usage = '%(prog)s [options] [tests...]' |
+ |
+ if version: |
+ self.add_argument('-V', '--version', action='store_true', |
+ help='Print the typ version and exit.') |
+ |
+ if discovery: |
+ self.add_argument('-f', '--file-list', metavar='FILENAME', |
+ action='store', |
+ help=('Takes the list of tests from the file ' |
+ '(use "-" for stdin).')) |
+ self.add_argument('--isolate', metavar='glob', default=[], |
+ action='append', |
+ help=('Globs of tests to run in isolation ' |
+ '(serially).')) |
+ self.add_argument('--skip', metavar='glob', default=[], |
+ action='append', |
+ help=('Globs of test names to skip (can specify ' |
+ 'multiple times).')) |
+ self.add_argument('--suffixes', metavar='glob', default=[], |
+ action='append', |
+ help=('Globs of test filenames to look for (' |
+ 'can specify multiple times; defaults ' |
+ 'to %s).' % DEFAULT_SUFFIXES)) |
+ |
+ if reporting: |
+ self.add_argument('--builder-name', |
+ help=('Builder name to include in the ' |
+ 'uploaded data.')) |
+ self.add_argument('-c', '--coverage', action='store_true', |
+ help='Reports coverage information.') |
+ self.add_argument('--coverage-source', action='append', |
+ default=[], |
+ help=('Directories to include when running and ' |
+ 'reporting coverage (defaults to ' |
+ '--top-level-dir plus --path)')) |
+ self.add_argument('--coverage-omit', action='append', |
+ default=[], |
+ help=('Globs to omit when reporting coverage ' |
+ '(defaults to %s).' % |
+ DEFAULT_COVERAGE_OMIT)) |
+ self.add_argument('--coverage-show-missing', action='store_true', |
+ help=('Show missing line ranges in coverage ' |
+ 'report.')) |
+ self.add_argument('--master-name', |
+ help=('Buildbot master name to include in the ' |
+ 'uploaded data.')) |
+ self.add_argument('--metadata', action='append', default=[], |
+ help=('Optional key=value metadata that will ' |
+ 'be included in the results.')) |
+ self.add_argument('--test-results-server', |
+ help=('If specified, uploads the full results ' |
+ 'to this server.')) |
+ self.add_argument('--test-type', |
+ help=('Name of test type to include in the ' |
+ 'uploaded data (e.g., ' |
+ '"telemetry_unittests").')) |
+ self.add_argument('--write-full-results-to', metavar='FILENAME', |
+ action='store', |
+ help=('If specified, writes the full results to ' |
+ 'that path.')) |
+ self.add_argument('--write-trace-to', metavar='FILENAME', |
+ action='store', |
+ help=('If specified, writes the trace to ' |
+ 'that path.')) |
+ self.add_argument('tests', nargs='*', default=[], |
+ help=argparse.SUPPRESS) |
+ |
+ if running: |
+ self.add_argument('-d', '--debugger', action='store_true', |
+ help='Runs the tests under the debugger.') |
+ self.add_argument('-j', '--jobs', metavar='N', type=int, |
+ default=self._host.cpu_count(), |
+ help=('Runs N jobs in parallel ' |
+ '(defaults to %(default)s).')) |
+ self.add_argument('-l', '--list-only', action='store_true', |
+ help='Lists all the test names found and exits.') |
+ self.add_argument('-n', '--dry-run', action='store_true', |
+ help=argparse.SUPPRESS) |
+ self.add_argument('-q', '--quiet', action='store_true', |
+ default=False, |
+ help=('Runs as quietly as possible ' |
+ '(only prints errors).')) |
+ self.add_argument('-s', '--status-format', |
+ default=self._host.getenv('NINJA_STATUS', |
+ DEFAULT_STATUS_FORMAT), |
+ help=argparse.SUPPRESS) |
+ self.add_argument('-t', '--timing', action='store_true', |
+ help='Prints timing info.') |
+ self.add_argument('-v', '--verbose', action='count', default=0, |
+ help=('Prints more stuff (can specify multiple ' |
+ 'times for more output).')) |
+ self.add_argument('--passthrough', action='store_true', |
+ default=False, |
+ help='Prints all output while running.') |
+ self.add_argument('--retry-limit', type=int, default=0, |
+ help='Retries each failure up to N times.') |
+ self.add_argument('--terminal-width', type=int, |
+ default=self._host.terminal_width(), |
+ help=argparse.SUPPRESS) |
+ self.add_argument('--overwrite', action='store_true', |
+ default=None, |
+ help=argparse.SUPPRESS) |
+ self.add_argument('--no-overwrite', action='store_false', |
+ dest='overwrite', default=None, |
+ help=argparse.SUPPRESS) |
+ self.add_argument('--setup', help=argparse.SUPPRESS) |
+ self.add_argument('--teardown', help=argparse.SUPPRESS) |
+ self.add_argument('--context', help=argparse.SUPPRESS) |
+ |
+ if discovery or running: |
+ self.add_argument('-P', '--path', action='append', default=[], |
+ help=('Adds dir to sys.path (can specify ' |
+ 'multiple times).')) |
+ self.add_argument('--top-level-dir', default=None, |
+ help=('Sets the top directory of project ' |
+ '(used when running subdirs).')) |
+ |
+ def parse_args(self, args=None, namespace=None): |
+ try: |
+ rargs = super(ArgumentParser, self).parse_args(args=args, |
+ namespace=namespace) |
+ except _Bailout: |
+ return None |
+ |
+ for val in rargs.metadata: |
+ if '=' not in val: |
+ self._print_message('Error: malformed --metadata "%s"' % val) |
+ self.exit_status = 2 |
+ |
+ if rargs.test_results_server: |
+ if not rargs.builder_name: |
+ self._print_message('Error: --builder-name must be specified ' |
+ 'along with --test-result-server') |
+ self.exit_status = 2 |
+ if not rargs.master_name: |
+ self._print_message('Error: --master-name must be specified ' |
+ 'along with --test-result-server') |
+ self.exit_status = 2 |
+ if not rargs.test_type: |
+ self._print_message('Error: --test-type must be specified ' |
+ 'along with --test-result-server') |
+ self.exit_status = 2 |
+ |
+ if not rargs.suffixes: |
+ rargs.suffixes = DEFAULT_SUFFIXES |
+ |
+ if not rargs.coverage_omit: |
+ rargs.coverage_omit = DEFAULT_COVERAGE_OMIT |
+ |
+ if rargs.debugger: # pragma: untested |
+ rargs.jobs = 1 |
+ rargs.passthrough = True |
+ |
+ if rargs.overwrite is None: |
+ rargs.overwrite = self._host.stdout.isatty() and not rargs.verbose |
+ |
+ return rargs |
+ |
+ # Redefining built-in 'file' pylint: disable=W0622 |
+ |
+ def _print_message(self, msg, file=None): |
+ self._host.print_(msg=msg, stream=file, end='\n') |
+ |
+ def print_help(self, file=None): |
+ self._print_message(msg=self.format_help(), file=file) |
+ |
+ def error(self, message): |
+ self.exit(2, '%s: error: %s\n' % (self.prog, message)) |
+ |
+ def exit(self, status=0, message=None): |
+ self.exit_status = status |
+ if message: |
+ self._print_message(message, file=self._host.stderr) |
+ raise _Bailout() |
+ |
+ def optparse_options(self, skip=None): |
+ skip = skip or [] |
+ options = [] |
+ for action in self._actions: |
+ args = [flag for flag in action.option_strings if flag not in skip] |
+ if not args or action.help == '==SUPPRESS==': |
+ # must either be a positional argument like 'tests' |
+ # or an option we want to skip altogether. |
+ continue |
+ |
+ kwargs = { |
+ 'default': action.default, |
+ 'dest': action.dest, |
+ 'help': action.help, |
+ 'metavar': action.metavar, |
+ 'type': action.type, |
+ 'action': _action_str(action) |
+ } |
+ options.append(optparse.make_option(*args, **kwargs)) |
+ return options |
+ |
+ |
+def _action_str(action): |
+ # Access to a protected member pylint: disable=W0212 |
+ assert action.__class__ in ( |
+ argparse._AppendAction, |
+ argparse._CountAction, |
+ argparse._StoreAction, |
+ argparse._StoreTrueAction |
+ ) |
+ |
+ if isinstance(action, argparse._AppendAction): |
+ return 'append' |
+ if isinstance(action, argparse._CountAction): |
+ return 'count' |
+ if isinstance(action, argparse._StoreAction): |
+ return 'store' |
+ if isinstance(action, argparse._StoreTrueAction): |
+ return 'store_true' |