예제 #1
0
    def check_file(self):
        """Perform all necessary checks on our file (including rulific ones).

        Raise FileCheckerError if an error is detected.

        :return: None.
        :rtype: None
        """
        log_info("Checking style of `%s' (%s)"
                 % (self.filename, self.file_type))

        # Build the error message into a list. And then, at the end of
        # this function, if it turns out we got at least one issue,
        # raise it via FileCheckerError.
        err_msgs = []

        # First, run the external checker...
        external_checker_err_msg = self.run_external_checker()
        if external_checker_err_msg is not None:
            # Stop immediately if the external checker detected some
            # errors.  We could continue, and run the rest of the
            # tests, but cvs_check, the previous style checker,
            # wasn't doing that, so we don't either so as to be
            # consistent with the traditional behavior.
            raise FileCheckerError(external_checker_err_msg)

        # First, feed line-by-line the contents of the file to each
        # rulific checker.
        with open(self.filename) as f:
            for lineno, line in enumerate(f, 1):
                eol = get_eol(line)
                line = line[:-len(eol or '')]
                for rulific_checker in self.my_rulific_checkers:
                    rulific_checker.process_line(lineno, line, eol)

        # Merge all the result of the line-by-line checking, currently
        # stored in each rulific checker, into a combined dictionary,
        # where keys are still line numbers, but the value is a list
        # of error messages applying to that line number.
        all_linenos = sorted(
            set().union(*(rulific_checker.errors_found.keys()
                          for rulific_checker in self.my_rulific_checkers)))
        for lineno in all_linenos:
            for rulific_checker in self.my_rulific_checkers:
                if lineno in rulific_checker.errors_found:
                    err_msgs.append('%s:%d: %s'
                                    % (self.filename, lineno,
                                       rulific_checker.errors_found[lineno]))

        for rulific_checker in self.my_rulific_checkers:
            global_check_err_msg = rulific_checker.global_check()
            if global_check_err_msg:
                err_msgs.append(global_check_err_msg)

        if err_msgs:
            raise FileCheckerError(*err_msgs)
예제 #2
0
def get_file_type(filename):
    """Run the "file" command on filename and return its output.

    :param filename: The name of the file on which to run the "file"
        command.
    :type filename: str
    """
    try:
        p = Run(["file", filename])
        if p.status != 0:
            raise FileCheckerError(
                "%s returned nonzero (%d):" %
                (p.command_line_image(), p.status), p.out)
    except OSError as e:
        raise FileCheckerError("Failed to run `file %s': %s" % (filename, e))

    return p.out
예제 #3
0
    def run_external_checker(self):
        """Run an external program to check the contents of the file.

        This is typically a tool which will perform some kind of
        language-specific check, making sure the file compiles,
        follows the proper coding style, etc.

        :return: A string with the corresponding error message if
            the checker discovered some issues, None otherwise.
        :rtype: str | None
        """
        raise FileCheckerError(
            'abstract TypificChecker.run_external_checker method'
            ' unexpectedly called.')
예제 #4
0
    def file_type(self):
        """Return a string describing the kind of file this checker applies to.

        NOTE: This was turned into a property so as to allow checkers
        to handle multiple kinds of files.  This can be useful when
        there are only very slight variations on how the set of files
        is checked (Eg: with Ada, the compiler units typically have
        some extra checks).  As such, a class attribute would not have
        worked in this context.

        :rtype: str
        """
        raise FileCheckerError(
            'abstract TypificChecker.file_type property unexpectedly called.')
예제 #5
0
def style_checker(argv=None):
    """Run the style checker with the given command-line arguments.

    :param argv: Same as in parse_cmdline.
    :type argv: list[str] | None
    """
    args = parse_cmdline(argv)
    asclib.logging.logging_level = args.verbose_level

    if not args.filenames:
        # No filename provided, which means the user wants us to
        # read the list of filesnames from standard input.
        args.filenames = [
            filename for filename in sys.stdin.read().splitlines() if filename
        ]

    config = Config(
        args.system_config, args.module_name, args.module_config, args.forced_year
    )

    n_files_with_errors = 0
    for filename in args.filenames:
        try:
            # Before even trying to launch the style checker, first verify
            # that the file exists, and if it doesn't then report the error,
            # and look at the next file to check...
            if not os.path.isfile(filename):
                raise FileCheckerError(
                    "Error: `%s' is not a valid filename." % filename
                )

            checker = get_file_checker(filename, config)
            if checker is None:
                # No checks for this kind of file.
                continue
            checker.check_file()
        except FileCheckerError as e:
            n_files_with_errors += 1
            if n_files_with_errors > args.max_files_with_errors:
                log_error("[other files with style violations were found]")
                break
            else:
                log_error(e.args)

    return n_files_with_errors == 0
예제 #6
0
    def check_rule(self, lineno, line, eol):
        """Report an error the given line contains a style violation.

        This is an abstract method which we expect child classes
        to override.

        :param lineno: Same as self.process_line.
        :type lineno: int
        :param line: Same as self.process_line.
        :type line: str
        :param eol: Same as self.process_line.
        :type eol: str | None

        :return: A string with the error message if a violation is detected.
            None otherwise.
        :rtype: str | None
        """
        raise FileCheckerError("abstract RuleChecker.check_rule method called")