#!/usr/bin/env python3
# Copyright lowRISC contributors (OpenTitan project).
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
r"""Parses lint report and dump filtered messages in hjson format.
"""
import argparse
import logging as log
import sys

from pathlib import Path
from LintParser import LintParser


# TODO(#9079): this script will be removed long term once the
# parser has been merged with the Dvsim core code.
def main():
    parser = argparse.ArgumentParser(
        description="""This script parses AscentLint log and report files from
        a lint run, filters the messages and creates an aggregated result
        .hjson file with lint messages and their severities.

        The script returns nonzero status if any warnings or errors are
        present.
        """)
    parser.add_argument('--repdir',
                        type=lambda p: Path(p).resolve(),
                        default="./",
                        help="""The script searches the 'ascentlint.log' and
                        'ascentlint.rpt' files in this directory.
                        Defaults to './'""")

    parser.add_argument('--outfile',
                        type=lambda p: Path(p).resolve(),
                        default="./results.hjson",
                        help="""Path to the results Hjson file.
                        Defaults to './results.hjson'""")

    args = parser.parse_args()

    # Define warning/error patterns for each logfile
    parser_args = {}

    # Patterns for lint.log
    parser_args.update({
        args.repdir.joinpath('ascentlint.log'): [
            # If lint warnings have been found, the lint tool will exit
            # with a nonzero status code and fusesoc will always spit out
            # an error like
            #
            #    ERROR: Failed to build ip:core:name:0.1 : 'make' exited with an error code
            #
            # If we found any other warnings or errors, there's no point in
            # listing this too. BUT we want to make sure we *do* see this
            # error if there are no other errors or warnings, since that
            # shows something has come unstuck. (Probably the lint tool
            # spat out a warning that we don't understand)
            ("fusesoc-error",
             r"^ERROR: Failed to build .* : 'make' exited with an error code")
        ]
    })

    # Patterns for ascentlint.log
    parser_args.update({
        args.repdir.joinpath('fusesoc-work/ascentlint.log'): [
            ("flow_error", r"^FlexNet Licensing error.*"),
            ("flow_error", r"^Error: .*"),
            ("flow_error", r"^ERROR.*"),
            ("flow_error", r"^  ERR .*"),
            ("flow_info", r"^Warning: License will expire.*"),
            ("flow_warning", r"^Warning: .*"),
            # TODO: struct assignment labels within concatenation
            # not supported. check with newer ascentlint version.
            ("flow_warning", r"^  (?!WARN \[#39024\])WARN .*")
        ]
    })

    # Patterns for ascentlint.rpt
    parser_args.update({
        args.repdir.joinpath('fusesoc-work/ascentlint.rpt'): [
            ("lint_error", r"^E  .*"),
            ("lint_warning", r"^W  .*"),
            ("lint_info", r"^I  .*")
        ]
    })

    # Parse logs
    parser = LintParser()
    num_messages = parser.get_results(parser_args)

    # Write out results file
    parser.write_results_as_hjson(args.outfile)

    # return nonzero status if any warnings or errors are present
    # lint infos do not count as failures
    if num_messages['error'] > 0 or num_messages['warning'] > 0:
        log.info("Found %d lint errors and %d lint warnings",
                 num_messages['error'],
                 num_messages['warning'])
        sys.exit(1)

    log.info("Lint logfile parsed succesfully")
    sys.exit(0)


if __name__ == "__main__":
    main()
