Esempio n. 1
0
def consider_function_size(fname, f):
    """yield a FunctionSizeItem for every function in f.
    """

    for name, lines in metrics.get_function_lines(f):
        canonical_function_name = "%s:%s()" % (fname, name)
        yield problem.FunctionSizeItem(canonical_function_name, lines)
Esempio n. 2
0
def main(argv):
    import argparse

    progname = argv[0]
    parser = argparse.ArgumentParser(prog=progname)
    parser.add_argument("--regen",
                        action="store_true",
                        help="Regenerate the exceptions file")
    parser.add_argument("--list-overbroad",
                        action="store_true",
                        help="List over-strict exceptions")
    parser.add_argument("--exceptions",
                        help="Override the location for the exceptions file")
    parser.add_argument("--strict",
                        action="store_true",
                        help="Make all warnings into errors")
    parser.add_argument("--terse",
                        action="store_true",
                        help="Do not emit helpful instructions.")
    parser.add_argument("--max-h-file-size",
                        default=MAX_H_FILE_SIZE,
                        help="Maximum lines per .h file")
    parser.add_argument("--max-h-include-count",
                        default=MAX_H_INCLUDE_COUNT,
                        help="Maximum includes per .h file")
    parser.add_argument("--max-file-size",
                        default=MAX_FILE_SIZE,
                        help="Maximum lines per .c file")
    parser.add_argument("--max-include-count",
                        default=MAX_INCLUDE_COUNT,
                        help="Maximum includes per .c file")
    parser.add_argument("--max-function-size",
                        default=MAX_FUNCTION_SIZE,
                        help="Maximum lines per function")
    parser.add_argument(
        "--max-dependency-violations",
        default=MAX_DEP_VIOLATIONS,
        help="Maximum number of dependency violations to allow")
    parser.add_argument("--include-dir",
                        action="append",
                        default=["src"],
                        help="A directory (under topdir) to search for source")
    parser.add_argument("topdir",
                        default=".",
                        nargs="?",
                        help="Top-level directory for the tor source")
    args = parser.parse_args(argv[1:])

    global TOR_TOPDIR
    TOR_TOPDIR = args.topdir
    if args.exceptions:
        exceptions_file = args.exceptions
    else:
        exceptions_file = os.path.join(TOR_TOPDIR, "scripts/maint/practracker",
                                       EXCEPTIONS_FNAME)

    # 0) Configure our thresholds of "what is a problem actually"
    filt = problem.ProblemFilter()
    filt.addThreshold(problem.FileSizeItem("*.c", int(args.max_file_size)))
    filt.addThreshold(
        problem.IncludeCountItem("*.c", int(args.max_include_count)))
    filt.addThreshold(problem.FileSizeItem("*.h", int(args.max_h_file_size)))
    filt.addThreshold(
        problem.IncludeCountItem("*.h", int(args.max_h_include_count)))
    filt.addThreshold(
        problem.FunctionSizeItem("*.c", int(args.max_function_size)))
    filt.addThreshold(
        problem.DependencyViolationItem("*.c",
                                        int(args.max_dependency_violations)))
    filt.addThreshold(
        problem.DependencyViolationItem("*.h",
                                        int(args.max_dependency_violations)))

    # 1) Get all the .c files we care about
    files_list = util.get_tor_c_files(TOR_TOPDIR, args.include_dir)

    # 2) Initialize problem vault and load an optional exceptions file so that
    # we don't warn about the past
    if args.regen:
        tmpname = exceptions_file + ".tmp"
        tmpfile = open(tmpname, "w")
        problem_file = tmpfile
        problem_file.write(HEADER)
        ProblemVault = problem.ProblemVault()
    else:
        ProblemVault = problem.ProblemVault(exceptions_file)
        problem_file = sys.stdout

    # 2.1) Adjust the exceptions so that we warn only about small problems,
    # and produce errors on big ones.
    if not (args.regen or args.list_overbroad or args.strict):
        ProblemVault.set_tolerances(TOLERANCE_FNS)

    # 3) Go through all the files and report problems if they are not exceptions
    found_new_issues = 0
    for item in filt.filter(consider_all_metrics(files_list)):
        status = ProblemVault.register_problem(item)
        if status == problem.STATUS_ERR:
            print(item, file=problem_file)
            found_new_issues += 1
        elif status == problem.STATUS_WARN:
            # warnings always go to stdout.
            print("(warning) {}".format(item))

    if args.regen:
        tmpfile.close()
        os.rename(tmpname, exceptions_file)
        sys.exit(0)

    # If new issues were found, try to give out some advice to the developer on how to resolve it.
    if found_new_issues and not args.regen and not args.terse:
        new_issues_str = """\
FAILURE: practracker found {} new problem(s) in the code: see warnings above.

Please fix the problems if you can, and update the exceptions file
({}) if you can't.

See doc/HACKING/HelpfulTools.md for more information on using practracker.\

You can disable this message by setting the TOR_DISABLE_PRACTRACKER environment
variable.
""".format(found_new_issues, exceptions_file)
        print(new_issues_str)

    if args.list_overbroad:

        def k_fn(tup):
            return tup[0].key()

        for (ex, p) in sorted(ProblemVault.list_overbroad_exceptions(),
                              key=k_fn):
            if p is None:
                print(ex, "->", 0)
            else:
                print(ex, "->", p.metric_value)

    sys.exit(found_new_issues)