Beispiel #1
0
def main():
    # Parse command-line arguments
    parser = argparse.ArgumentParser(
        description=
        "Runs all formatting tasks on the code base. This should be invoked from a directory within the project."
    )
    parser.add_argument(
        "-v",
        dest="verbose1",
        action="store_true",
        help="verbosity level 1 (prints names of processed files)")
    parser.add_argument(
        "-vv",
        dest="verbose2",
        action="store_true",
        help=
        "verbosity level 2 (prints names of processed files and tasks run on them)"
    )
    parser.add_argument(
        "-j",
        dest="jobs",
        type=int,
        default=mp.cpu_count(),
        help="number of jobs to run (default is number of cores)")
    parser.add_argument(
        "-y",
        dest="year",
        type=int,
        default=date.today().year,
        help=
        "year to use when updating license headers (default is current year)")
    parser.add_argument(
        "-clang",
        dest="clang_version",
        type=str,
        default="",
        help=
        "version suffix for clang-format (invokes \"clang-format-CLANG_VERSION\" or \"clang-format\" if no suffix provided)"
    )
    parser.add_argument(
        "-f",
        dest="file",
        type=str,
        default="",
        nargs="+",
        help=
        "file or directory names (can be path relative to python invocation directory or absolute path)"
    )
    args = parser.parse_args()

    # All discovered files are relative to Git repo root directory, so find the
    # root.
    root_path = Task.get_repo_root()
    if root_path == "":
        print("Error: not invoked within a Git repository", file=sys.stderr)
        sys.exit(1)

    # If no files explicitly specified
    if not args.file:
        # Delete temporary files from previous incomplete run
        files = [
            os.path.join(dp, f)
            for dp, dn, fn in os.walk(root_path)
            for f in fn
            if f.endswith(".tmp")
        ]
        for f in files:
            os.remove(f)

        # Recursively create list of files in given directory
        files = [
            os.path.join(dp, f) for dp, dn, fn in os.walk(root_path) for f in fn
        ]

        if not files:
            print("Error: no files found to format", file=sys.stderr)
            sys.exit(1)
    else:
        files = []
        for name in args.file:
            # If a directory was specified, recursively expand it
            if os.path.isdir(name):
                files.extend([
                    os.path.join(dp, f)
                    for dp, dn, fn in os.walk(name)
                    for f in fn
                ])
            else:
                files.append(name)

    # Convert relative paths of files to absolute paths
    files = [os.path.abspath(name) for name in files]

    # Don't run tasks on Git metadata
    files = [name for name in files if os.sep + ".git" + os.sep not in name]

    # Don't check for changes in or run tasks on ignored files
    files = filter_ignored_files(files)

    # Create list of all changed files
    changed_file_list = []

    output_list = subprocess.run(
        ["git", "diff", "--name-only", "master"],
        stdout=subprocess.PIPE).stdout.split()
    for line in output_list:
        changed_file_list.append(root_path + os.sep +
                                 line.strip().decode("ascii"))

    # Don't run tasks on modifiable or generated files
    work = []
    for name in files:
        config_file = Config(os.path.dirname(name), ".styleguide")

        if config_file.is_modifiable_file(name):
            continue
        if config_file.is_generated_file(name):
            # Emit warning if a generated file was editted
            if name in changed_file_list:
                print("Warning: generated file '" + name + "' modified")
            continue

        work.append(name)
    files = work

    # If there are no files left, do nothing
    if len(files) == 0:
        sys.exit(0)

    # Prepare file batches for batch tasks
    chunksize = math.ceil(len(files) / args.jobs)
    file_batches = [
        files[i:i + chunksize] for i in range(0, len(files), chunksize)
    ]

    # IncludeOrder is run after Stdlib so any C std headers changed to C++ or
    # vice versa are sorted properly. ClangFormat is run after the other tasks
    # so it can clean up their formatting.
    task_pipeline = [
        BraceComment(),
        CIdentList(),
        IncludeGuard(),
        LicenseUpdate(str(args.year)),
        JavaClass(),
        Newline(),
        Stdlib(),
        IncludeOrder(),
        UsingDeclaration(),
        UsingNamespaceStd(),
        Whitespace()
    ]
    run_pipeline(task_pipeline, args, files)

    task_pipeline = [ClangFormat(args.clang_version)]
    run_batch(task_pipeline, args, file_batches)

    # These tasks fix clang-format formatting
    task_pipeline = [Jni()]
    run_pipeline(task_pipeline, args, files)

    # Lint is run last since previous tasks can affect its output.
    task_pipeline = [PyFormat(), Lint()]
    run_batch(task_pipeline, args, file_batches)
Beispiel #2
0
def test_includeguard():
    test = TaskTest(IncludeGuard())

    # Fix incorrect include guard
    test.add_input("./Test.h",
        "#ifndef WRONG_H" + os.linesep + \
        "#define WRONG_C" + os.linesep + \
        os.linesep + \
        "#endif" + os.linesep)
    test.add_output(
        "#ifndef STYLEGUIDE_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_TEST_H_" + os.linesep, True, True)

    # Ensure nested preprocessor statements are handled properly for incorrect
    # include guard
    test.add_input("./Test.h",
        "#ifndef WRONG_H" + os.linesep + \
        "#define WRONG_C" + os.linesep + \
        os.linesep + \
        "#if SOMETHING" + os.linesep + \
        "// do something" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif" + os.linesep)
    test.add_output(
        "#ifndef STYLEGUIDE_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_TEST_H_" + os.linesep + \
        os.linesep + \
        "#if SOMETHING" + os.linesep + \
        "// do something" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif  // STYLEGUIDE_TEST_H_" + os.linesep, True, True)

    # Don't touch correct include guard
    test.add_input("./Test.h",
        "#ifndef STYLEGUIDE_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_TEST_H_" + os.linesep)
    test.add_latest_input_as_output(True)

    # Fail on missing include guard
    test.add_input("./Test.h", "// Empty file" + os.linesep)
    test.add_latest_input_as_output(False)

    # Verify pragma once counts as include guard
    test.add_input("./Test.h", "#pragma once" + os.linesep)
    test.add_latest_input_as_output(True)

    # Ensure include guard roots are processed correctly
    test.add_input("./Test.h",
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep)
    test.add_output(
        "#ifndef STYLEGUIDE_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_TEST_H_" + os.linesep, True, True)

    # Ensure leading underscores are removed (this occurs if the user doesn't
    # include a trailing "/" in the include guard root)
    test.add_input("./Test/Test.h",
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_TEST_H_" + os.linesep)
    test.add_output(
        "#ifndef STYLEGUIDE_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_TEST_H_" + os.linesep, True, True)

    test.run(OutputType.FILE)
Beispiel #3
0
def test_includeguard():
    task = IncludeGuard()

    inputs = []
    outputs = []

    # Fix incorrect include guard
    inputs.append(("./Test.h",
        "#ifndef WRONG_H" + os.linesep + \
        "#define WRONG_C" + os.linesep + \
        os.linesep + \
        "#endif" + os.linesep))
    outputs.append((
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep, True, True))

    # Ensure nested preprocessor statements are handled properly for incorrect
    # include guard
    inputs.append(("./Test.h",
        "#ifndef WRONG_H" + os.linesep + \
        "#define WRONG_C" + os.linesep + \
        os.linesep + \
        "#if SOMETHING" + os.linesep + \
        "// do something" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif" + os.linesep))
    outputs.append((
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#if SOMETHING" + os.linesep + \
        "// do something" + os.linesep + \
        "#endif" + os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep, True, True))

    # Don't touch correct include guard
    inputs.append(("./Test.h",
        "#ifndef STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        "#define STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep + \
        os.linesep + \
        "#endif  // STYLEGUIDE_WPIFORMAT_TEST_H_" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    # Fail on missing include guard
    inputs.append(("./Test.h", "// Empty file" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, False))

    # Verify pragma once counts as include guard
    inputs.append(("./Test.h", "#pragma once" + os.linesep))
    outputs.append((inputs[len(inputs) - 1][1], False, True))

    assert len(inputs) == len(outputs)

    config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
    for i in range(len(inputs)):
        output, file_changed, success = task.run_pipeline(
            config_file, inputs[i][0], inputs[i][1])
        assert output == outputs[i][0]
        assert file_changed == outputs[i][1]
        assert success == outputs[i][2]