Commit 715bfa4e authored by Julian Lettner's avatar Julian Lettner
Browse files

[lit] Move argument parsing/validation to separate file

Reviewed By: serge-sans-paille

Differential Revision: https://reviews.llvm.org/D68529

llvm-svn: 374400
parent 3b4c8f68
Loading
Loading
Loading
Loading
+218 −0
Original line number Diff line number Diff line
import argparse
import os
import shlex
import sys

import lit.util

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('test_paths',
            nargs='*',
            help='Files or paths to include in the test suite')

    parser.add_argument("--version",
            dest="show_version",
            help="Show version and exit",
            action="store_true",
            default=False)
    parser.add_argument("-j", "--workers",
            dest="numWorkers",
            metavar="N",
            help="Number of workers used for testing",
            type=int,
            default=None)
    parser.add_argument("--config-prefix",
            dest="configPrefix",
            metavar="NAME",
            help="Prefix for 'lit' config files",
            action="store",
            default=None)
    parser.add_argument("-D", "--param",
            dest="userParameters",
            metavar="NAME=VAL",
            help="Add 'NAME' = 'VAL' to the user defined parameters",
            type=str,
            action="append",
            default=[])

    format_group = parser.add_argument_group("Output Format")
    # FIXME: I find these names very confusing, although I like the
    # functionality.
    format_group.add_argument("-q", "--quiet",
            help="Suppress no error output",
            action="store_true",
            default=False)
    format_group.add_argument("-s", "--succinct",
            help="Reduce amount of output",
            action="store_true",
            default=False)
    format_group.add_argument("-v", "--verbose",
            dest="showOutput",
            help="Show test output for failures",
            action="store_true",
            default=False)
    format_group.add_argument("-vv", "--echo-all-commands",
            dest="echoAllCommands",
            action="store_true",
            default=False,
            help="Echo all commands as they are executed to stdout. In case of "
                 "failure, last command shown will be the failing one.")
    format_group.add_argument("-a", "--show-all",
            dest="showAllOutput",
            help="Display all commandlines and output",
            action="store_true",
            default=False)
    format_group.add_argument("-o", "--output",
            dest="output_path",
            help="Write test results to the provided path",
            action="store",
            metavar="PATH")
    format_group.add_argument("--no-progress-bar",
            dest="useProgressBar",
            help="Do not use curses based progress bar",
            action="store_false",
            default=True)
    format_group.add_argument("--show-unsupported",
            help="Show unsupported tests",
            action="store_true",
            default=False)
    format_group.add_argument("--show-xfail",
            help="Show tests that were expected to fail",
            action="store_true",
            default=False)

    execution_group = parser.add_argument_group("Test Execution")
    execution_group.add_argument("--path",
            help="Additional paths to add to testing environment",
            action="append",
            type=str,
            default=[])
    execution_group.add_argument("--vg",
            dest="useValgrind",
            help="Run tests under valgrind",
            action="store_true",
            default=False)
    execution_group.add_argument("--vg-leak",
            dest="valgrindLeakCheck",
            help="Check for memory leaks under valgrind",
            action="store_true",
            default=False)
    execution_group.add_argument("--vg-arg",
            dest="valgrindArgs",
            metavar="ARG",
            help="Specify an extra argument for valgrind",
            type=str,
            action="append",
            default=[])
    execution_group.add_argument("--time-tests",
            dest="timeTests",
            help="Track elapsed wall time for each test",
            action="store_true",
            default=False)
    execution_group.add_argument("--no-execute",
            dest="noExecute",
            help="Don't execute any tests (assume PASS)",
            action="store_true",
            default=False)
    execution_group.add_argument("--xunit-xml-output",
            dest="xunit_output_file",
            help="Write XUnit-compatible XML test reports to the specified file",
            default=None)
    execution_group.add_argument("--timeout",
            dest="maxIndividualTestTime",
            help="Maximum time to spend running a single test (in seconds). "
                 "0 means no time limit. [Default: 0]",
            type=int,
            default=None)
    execution_group.add_argument("--max-failures",
            dest="maxFailures",
            help="Stop execution after the given number of failures.",
            action="store",
            type=int,
            default=None)

    selection_group = parser.add_argument_group("Test Selection")
    selection_group.add_argument("--max-tests",
            dest="maxTests",
            metavar="N",
            help="Maximum number of tests to run",
            action="store",
            type=int,
            default=None)
    selection_group.add_argument("--max-time",
            dest="maxTime",
            metavar="N",
            help="Maximum time to spend testing (in seconds)",
            action="store",
            type=float,
            default=None)
    selection_group.add_argument("--shuffle",
            help="Run tests in random order",
            action="store_true",
            default=False)
    selection_group.add_argument("-i", "--incremental",
            help="Run modified and failing tests first (updates mtimes)",
            action="store_true",
            default=False)
    selection_group.add_argument("--filter",
            metavar="REGEX",
            help="Only run tests with paths matching the given regular expression",
            action="store",
            default=os.environ.get("LIT_FILTER"))
    selection_group.add_argument("--num-shards", dest="numShards", metavar="M",
            help="Split testsuite into M pieces and only run one",
            action="store",
            type=int,
            default=os.environ.get("LIT_NUM_SHARDS"))
    selection_group.add_argument("--run-shard",
            dest="runShard",
            metavar="N",
            help="Run shard #N of the testsuite",
            action="store",
            type=int,
            default=os.environ.get("LIT_RUN_SHARD"))

    debug_group = parser.add_argument_group("Debug and Experimental Options")
    debug_group.add_argument("--debug",
            help="Enable debugging (for 'lit' development)",
            action="store_true",
            default=False)
    debug_group.add_argument("--show-suites",
            dest="showSuites",
            help="Show discovered test suites",
            action="store_true",
            default=False)
    debug_group.add_argument("--show-tests",
            dest="showTests",
            help="Show all discovered tests",
            action="store_true",
            default=False)

    opts = parser.parse_args(sys.argv[1:] +
                             shlex.split(os.environ.get("LIT_OPTS", "")))

    # Validate options
    if not opts.test_paths:
        parser.error('No inputs specified')

    if opts.numWorkers is None:
        opts.numWorkers = lit.util.detectCPUs()
    elif opts.numWorkers <= 0:
        parser.error("Option '--workers' or '-j' requires positive integer")

    if opts.maxFailures is not None and opts.maxFailures <= 0:
        parser.error("Option '--max-failures' requires positive integer")

    if opts.echoAllCommands:
        opts.showOutput = True

    if (opts.numShards is not None) or (opts.runShard is not None):
        if (opts.numShards is None) or (opts.runShard is None):
            parser.error("--num-shards and --run-shard must be used together")
        if opts.numShards <= 0:
            parser.error("--num-shards must be positive")
        if (opts.runShard < 1) or (opts.runShard > opts.numShards):
            parser.error("--run-shard must be between 1 and --num-shards (inclusive)")

    return opts
+10 −159
Original line number Diff line number Diff line
@@ -11,14 +11,13 @@ import os
import platform
import random
import re
import shlex
import sys
import time
import argparse
import tempfile
import shutil
from xml.sax.saxutils import quoteattr

import lit.cl_arguments
import lit.discovery
import lit.display
import lit.LitConfig
@@ -90,14 +89,12 @@ def update_incremental_cache(test):
    fname = test.getFilePath()
    os.utime(fname, None)

def sort_by_incremental_cache(run):
    def sortIndex(test):
def by_mtime(test):
    fname = test.getFilePath()
    try:
            return -os.path.getmtime(fname)
        return os.path.getmtime(fname)
    except:
        return 0
    run.tests.sort(key = lambda t: sortIndex(t))

def main(builtinParameters = {}):
    # Create a temp directory inside the normal temp directory so that we can
@@ -129,152 +126,12 @@ def main(builtinParameters = {}):
                pass

def main_with_tmp(builtinParameters):
    parser = argparse.ArgumentParser()
    parser.add_argument('test_paths',
                        nargs='*',
                        help='Files or paths to include in the test suite')

    parser.add_argument("--version", dest="show_version",
                      help="Show version and exit",
                      action="store_true", default=False)
    parser.add_argument("-j", "--threads", "--workers", dest="numWorkers", metavar="N",
                      help="Number of workers used for testing",
                      type=int, default=None)
    parser.add_argument("--config-prefix", dest="configPrefix",
                      metavar="NAME", help="Prefix for 'lit' config files",
                      action="store", default=None)
    parser.add_argument("-D", "--param", dest="userParameters",
                      metavar="NAME=VAL",
                      help="Add 'NAME' = 'VAL' to the user defined parameters",
                      type=str, action="append", default=[])

    format_group = parser.add_argument_group("Output Format")
    # FIXME: I find these names very confusing, although I like the
    # functionality.
    format_group.add_argument("-q", "--quiet",
                     help="Suppress no error output",
                     action="store_true", default=False)
    format_group.add_argument("-s", "--succinct",
                     help="Reduce amount of output",
                     action="store_true", default=False)
    format_group.add_argument("-v", "--verbose", dest="showOutput",
                     help="Show test output for failures",
                     action="store_true", default=False)
    format_group.add_argument("-vv", "--echo-all-commands",
                     dest="echoAllCommands",
                     action="store_true", default=False,
                     help="Echo all commands as they are executed to stdout.\
                     In case of failure, last command shown will be the\
                     failing one.")
    format_group.add_argument("-a", "--show-all", dest="showAllOutput",
                     help="Display all commandlines and output",
                     action="store_true", default=False)
    format_group.add_argument("-o", "--output", dest="output_path",
                     help="Write test results to the provided path",
                     action="store", metavar="PATH")
    format_group.add_argument("--no-progress-bar", dest="useProgressBar",
                     help="Do not use curses based progress bar",
                     action="store_false", default=True)
    format_group.add_argument("--show-unsupported",
                     help="Show unsupported tests",
                     action="store_true", default=False)
    format_group.add_argument("--show-xfail",
                     help="Show tests that were expected to fail",
                     action="store_true", default=False)

    execution_group = parser.add_argument_group("Test Execution")
    execution_group.add_argument("--path",
                     help="Additional paths to add to testing environment",
                     action="append", type=str, default=[])
    execution_group.add_argument("--vg", dest="useValgrind",
                     help="Run tests under valgrind",
                     action="store_true", default=False)
    execution_group.add_argument("--vg-leak", dest="valgrindLeakCheck",
                     help="Check for memory leaks under valgrind",
                     action="store_true", default=False)
    execution_group.add_argument("--vg-arg", dest="valgrindArgs", metavar="ARG",
                     help="Specify an extra argument for valgrind",
                     type=str, action="append", default=[])
    execution_group.add_argument("--time-tests", dest="timeTests",
                     help="Track elapsed wall time for each test",
                     action="store_true", default=False)
    execution_group.add_argument("--no-execute", dest="noExecute",
                     help="Don't execute any tests (assume PASS)",
                     action="store_true", default=False)
    execution_group.add_argument("--xunit-xml-output", dest="xunit_output_file",
                      help=("Write XUnit-compatible XML test reports to the"
                            " specified file"), default=None)
    execution_group.add_argument("--timeout", dest="maxIndividualTestTime",
                     help="Maximum time to spend running a single test (in seconds)."
                     "0 means no time limit. [Default: 0]",
                    type=int, default=None)
    execution_group.add_argument("--max-failures", dest="maxFailures",
                     help="Stop execution after the given number of failures.",
                     action="store", type=int, default=None)

    selection_group = parser.add_argument_group("Test Selection")
    selection_group.add_argument("--max-tests", dest="maxTests", metavar="N",
                     help="Maximum number of tests to run",
                     action="store", type=int, default=None)
    selection_group.add_argument("--max-time", dest="maxTime", metavar="N",
                     help="Maximum time to spend testing (in seconds)",
                     action="store", type=float, default=None)
    selection_group.add_argument("--shuffle",
                     help="Run tests in random order",
                     action="store_true", default=False)
    selection_group.add_argument("-i", "--incremental",
                     help="Run modified and failing tests first (updates "
                     "mtimes)",
                     action="store_true", default=False)
    selection_group.add_argument("--filter", metavar="REGEX",
                     help=("Only run tests with paths matching the given "
                           "regular expression"),
                     action="store",
                     default=os.environ.get("LIT_FILTER"))
    selection_group.add_argument("--num-shards", dest="numShards", metavar="M",
                     help="Split testsuite into M pieces and only run one",
                     action="store", type=int,
                     default=os.environ.get("LIT_NUM_SHARDS"))
    selection_group.add_argument("--run-shard", dest="runShard", metavar="N",
                     help="Run shard #N of the testsuite",
                     action="store", type=int,
                     default=os.environ.get("LIT_RUN_SHARD"))

    debug_group = parser.add_argument_group("Debug and Experimental Options")
    debug_group.add_argument("--debug",
                      help="Enable debugging (for 'lit' development)",
                      action="store_true", default=False)
    debug_group.add_argument("--show-suites", dest="showSuites",
                      help="Show discovered test suites",
                      action="store_true", default=False)
    debug_group.add_argument("--show-tests", dest="showTests",
                      help="Show all discovered tests",
                      action="store_true", default=False)

    opts = parser.parse_args(sys.argv[1:] +
                             shlex.split(os.environ.get("LIT_OPTS", "")))
    args = opts.test_paths
    opts = lit.cl_arguments.parse_args()

    if opts.show_version:
        print("lit %s" % (lit.__version__,))
        return

    if not args:
        parser.error('No inputs specified')

    if opts.numWorkers is None:
        opts.numWorkers = lit.util.detectCPUs()
    elif opts.numWorkers <= 0:
        parser.error("Option '--workers' or '-j' requires positive integer")

    if opts.maxFailures is not None and opts.maxFailures <= 0:
        parser.error("Option '--max-failures' requires positive integer")

    if opts.echoAllCommands:
        opts.showOutput = True

    inputs = args

    # Create the user defined parameters.
    userParams = dict(builtinParameters)
    for entry in opts.userParameters:
@@ -313,7 +170,7 @@ def main_with_tmp(builtinParameters):

    # Perform test discovery.
    run = lit.run.Run(litConfig,
                      lit.discovery.find_tests_for_inputs(litConfig, inputs))
                      lit.discovery.find_tests_for_inputs(litConfig, opts.test_paths))

    # After test discovery the configuration might have changed
    # the maxIndividualTestTime. If we explicitly set this on the
@@ -377,18 +234,12 @@ def main_with_tmp(builtinParameters):
    if opts.shuffle:
        random.shuffle(run.tests)
    elif opts.incremental:
        sort_by_incremental_cache(run)
        run.tests.sort(key=by_mtime, reverse=True)
    else:
        run.tests.sort(key = lambda t: (not t.isEarlyTest(), t.getFullName()))

    # Then optionally restrict our attention to a shard of the tests.
    if (opts.numShards is not None) or (opts.runShard is not None):
        if (opts.numShards is None) or (opts.runShard is None):
            parser.error("--num-shards and --run-shard must be used together")
        if opts.numShards <= 0:
            parser.error("--num-shards must be positive")
        if (opts.runShard < 1) or (opts.runShard > opts.numShards):
            parser.error("--run-shard must be between 1 and --num-shards (inclusive)")
        num_tests = len(run.tests)
        # Note: user views tests and shard numbers counting from 1.
        test_ixs = range(opts.runShard - 1, num_tests, opts.numShards)