#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

import argparse
from distutils.version import StrictVersion
import logging as log
import os
import re
import shlex
import subprocess
import sys

# Display INFO log messages and up.
log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")


def get_tool_requirements_path():
    '''Return the path to tool_requirements.py, at the top of the repo'''
    # top_src_dir is the top of the repository
    top_src_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),
                                                '..'))

    return os.path.join(top_src_dir, 'tool_requirements.py')


class ReqErr(Exception):
    def __init__(self, path, msg):
        self.path = path
        self.msg = msg

    def __str__(self):
        return ('Error parsing tool requirements from {!r}: {}'
                .format(self.path, self.msg))


class ToolReq:
    # A subclass can set this to configure the command that's run to get the
    # version of a tool. If tool_cmd is None, get_version will call "self.tool
    # --version".
    tool_cmd = None

    # Used by get_version. If not None, this is a dictionary that's added to
    # the environment when running the command.
    tool_env = None

    # A subclass can set this to configure _parse_version_output. If set, it
    # should be a Regex object with a single capturing group that captures the
    # version.
    version_regex = None

    def __init__(self, tool, min_version):
        self.tool = tool
        self.min_version = min_version
        self.optional = False

    def _get_tool_cmd(self):
        '''Return the command to run to get the installed version'''
        return self.tool_cmd or [self.tool, '--version']

    def _get_version(self):
        '''Run the tool to get the installed version.

        Raises a RuntimeError on failure. The default version uses the class
        variable tool_cmd to figure out what to run.

        '''

    def _parse_version_output(self, stdout):
        '''Parse the nonempty stdout to get a version number

        Raises a ValueError on failure. The default implementation returns the
        last word of the first line if version_regex is None or the first match
        for version_regex if it is not None.

        '''
        if self.version_regex is None:
            line0 = stdout.split('\n', 1)[0]
            words = line0.rsplit(None, 1)
            if not words:
                raise ValueError('Empty first line.')

            return words[-1]

        for line in stdout.split('\n'):
            match = self.version_regex.match(line.rstrip())
            if match is not None:
                return match.group(1)
        raise ValueError('No line matched version regex.')

    def get_version(self):
        '''Run the tool to get a version.

        Returns a version string on success. Raises a RuntimeError on failure.
        The default version uses the class variable tool_cmd to figure out what
        to run.

        '''
        cmd = self._get_tool_cmd()
        cmd_txt = ' '.join(shlex.quote(w) for w in cmd)

        env = None
        if self.tool_env is not None:
            env = os.environ.copy()
            env.update(self.tool_env)

        try:
            proc = subprocess.run(cmd,
                                  check=True,
                                  stdout=subprocess.PIPE,
                                  universal_newlines=True,
                                  env=env)
        except (subprocess.CalledProcessError, FileNotFoundError) as err:
            env_msg = ('' if not self.tool_env else
                       ' (with environment overrides: {})'
                       .format(', '.join('{}={}'.format(k, v)
                                         for k, v in self.tool_env.items())))
            raise RuntimeError('Failed to run {!r}{} to check version: {}'
                               .format(cmd_txt, env_msg, err))

        if not proc.stdout:
            raise RuntimeError('No output from running {!r} to check version.'
                               .format(cmd_txt))

        try:
            return self._parse_version_output(proc.stdout)
        except ValueError as err:
            raise RuntimeError('Bad output from running {!r} '
                               'to check version: {}'
                               .format(cmd_txt, err))

    def to_semver(self, version, from_req):
        '''Convert a tool version to semantic versioning format

        If from_req is true, this version comes from the requirements file
        (rather than being reported from an installed application). That might
        mean stricter checking. If version is not a known format, raises a
        ValueError.

        '''
        return version

    def check(self):
        '''Get the installed version and check it matches the requirements

        Returns (is_good, msg). is_good is true if we matched the requirements
        and false otherwise. msg describes what happened (an error message on
        failure, or extra information on success).

        '''
        try:
            min_semver = self.to_semver(self.min_version, True)
        except ValueError as err:
            return (False,
                    'Failed to convert requirement to semantic version: {}'
                    .format(err))
        try:
            min_sv = StrictVersion(min_semver)
        except ValueError as err:
            return (False,
                    'Bad semver inferred from required version ({}): {}'
                    .format(min_semver, err))

        try:
            actual_version = self.get_version()
        except RuntimeError as err:
            return (False, str(err))

        try:
            actual_semver = self.to_semver(actual_version, False)
        except ValueError as err:
            return (False,
                    'Failed to convert installed to semantic version: {}'
                    .format(err))
        try:
            actual_sv = StrictVersion(actual_semver)
        except ValueError as err:
            return (False,
                    'Bad semver inferred from installed version ({}): {}'
                    .format(actual_semver, err))

        if actual_sv < min_sv:
            return (False,
                    'Installed version is too old: '
                    'found version {}, but need at least {}'
                    .format(actual_version, self.min_version))

        return (True,
                'Sufficiently recent version (found {}; needed {})'
                .format(actual_version, self.min_version))


class VerilatorToolReq(ToolReq):
    def get_version(self):
        try:
            # Note: "verilator" needs to be called through a shell and with all
            # arguments in a string, as it doesn't have a shebang, but instead
            # relies on perl magic to parse command line arguments.
            version_str = subprocess.run('verilator --version', shell=True,
                                         check=True, stdout=subprocess.PIPE,
                                         stderr=subprocess.STDOUT,
                                         universal_newlines=True)
        except subprocess.CalledProcessError as err:
            raise RuntimeError('Unable to call Verilator to check version: {}'
                               .format(err)) from None

        return version_str.stdout.split(' ')[1].strip()


class VeribleToolReq(ToolReq):
    tool_cmd = ['verible-verilog-lint', '--version']

    def to_semver(self, version, from_req):
        # Drop the hash suffix and convert into version string that
        # is compatible with StrictVersion in check_version below.
        # Example: v0.0-808-g1e17daa -> 0.0.808
        m = re.fullmatch(r'v([0-9]+)\.([0-9]+)-([0-9]+)-g[0-9a-f]+$', version)
        if m is None:
            raise ValueError("{} has invalid version string format."
                             .format(version))

        return '.'.join(m.group(1, 2, 3))


class VivadoToolReq(ToolReq):
    tool_cmd = ['vivado', '-version']
    version_regex = re.compile(r'Vivado v(.*)\s')

    def to_semver(self, version, from_req):
        # Regular Vivado releases just have a major and minor version.
        # In this case, we set the patch level to 0.
        m = re.fullmatch(r'([0-9]+)\.([0-9]+)(?:\.([0-9]+))?', version)
        if m is None:
            raise ValueError("{} has invalid version string format."
                             .format(version))

        return '.'.join((m.group(1), m.group(2), m.group(3) or '0'))


class VcsToolReq(ToolReq):
    tool_cmd = ['vcs', '-full64', '-ID']
    tool_env = {'VCS_ARCH_OVERRIDE': 'linux'}
    version_regex = re.compile(r'Compiler version = VCS [A-Z]-(.*)')

    def to_semver(self, version, from_req):
        # VCS has a rather strange numbering scheme, where the most general
        # versions look something like this:
        #
        #    Q-2020.03-SP1-2
        #
        # Our version_regex strips out the "Q" part (a "platform prefix")
        # already. A version always has the "2020.03" (year and month) part,
        # and may also have an -SP<n> and/or -<patch> suffix.
        #
        # Since StrictVersion expects a 3 digit versioning scheme, we multiply
        # any SP number by 100, which should work as long as the patch version
        # isn't greater than 99.
        #
        # Some VCS builds also report other cruft (like _Full64) after this
        # version number. If from_req is False, allow (and ignore) that too.
        regex = r'([0-9]+).([0-9]+)(?:-SP([0-9]+))?(?:-([0-9]+))?'
        if from_req:
            regex += '$'

        match = re.match(regex, version)
        if match is None:
            raise ValueError("{!r} is not a recognised VCS version string."
                             .format(version))
        major = match.group(1)
        minor = match.group(2)
        sp = int(match.group(3) or 0)
        patch = int(match.group(4) or 0)
        comb = str(sp * 100 + patch)
        return '{}.{}{}'.format(major, minor, comb)


class NinjaToolReq(ToolReq):
    tool_cmd = ['ninja', '--version']

    def to_semver(self, version, from_req):
        # There exist different version string variants that we need to be
        # able to parse. Some only contain the semantic version, e.g. "1.10.0",
        # while others contain an additional suffix, e.g.
        # "1.10.0.git.kitware.jobserver-1". This parser only extracts the first
        # three digits and ignores the rest.
        m = re.fullmatch(r'([0-9]+)\.([0-9]+)\.([0-9]+).*', version)
        if m is None:
            raise ValueError("{} has invalid version string format."
                             .format(version))

        return '.'.join(m.group(1, 2, 3))


class PyModuleToolReq(ToolReq):
    '''A tool in a Python module (its version can be found by running pip)'''
    version_regex = re.compile(r'Version: (.*)')

    def _get_tool_cmd(self):
        return ['pip3', 'show', self.tool]


def dict_to_tool_req(path, tool, raw):
    '''Parse a dict (as read from Python) as a ToolReq

    Required keys: version. Optional keys: as_needed.

    '''
    where = 'Dict for {} in __TOOL_REQUIREMENTS__'.format(tool)
    # We operate in place on the dictionary. Take a copy to avoid an
    # obnoxious API.
    raw = raw.copy()

    if 'min_version' not in raw:
        raise ReqErr(path,
                     '{} is missing required key: "min_version".'
                     .format(where))
    min_version = raw['min_version']
    if not isinstance(min_version, str):
        raise ReqErr(path,
                     '{} has min_version that is not a string.'
                     .format(where))
    del raw['min_version']

    as_needed = False
    if 'as_needed' in raw:
        as_needed = raw['as_needed']
        if not isinstance(as_needed, bool):
            raise ReqErr(path,
                         '{} has as_needed that is not a bool.'
                         .format(where))
        del raw['as_needed']

    if raw:
        raise ReqErr(path,
                     '{} has unexpected keys: {}.'
                     .format(where, ', '.join(raw.keys())))

    classes = {
        'edalize': PyModuleToolReq,
        'vcs': VcsToolReq,
        'verible': VeribleToolReq,
        'verilator': VerilatorToolReq,
        'vivado': VivadoToolReq,
        'ninja': NinjaToolReq
    }
    cls = classes.get(tool, ToolReq)

    ret = cls(tool, min_version)
    ret.as_needed = as_needed
    return ret


def read_tool_requirements(path=None):
    '''Read tool requirements from a Python file'''
    if path is None:
        path = get_tool_requirements_path()

    with open(path, 'r') as pyfile:
        globs = {}
        exec(pyfile.read(), globs)

        # We expect the exec call to have populated globs with a
        # __TOOL_REQUIREMENTS__ dictionary.
        raw = globs.get('__TOOL_REQUIREMENTS__')
        if raw is None:
            raise ReqErr(path,
                         'The Python file at did not define '
                         '__TOOL_REQUIREMENTS__.')

        # raw should be a dictionary (keyed by tool name)
        if not isinstance(raw, dict):
            raise ReqErr(path, '__TOOL_REQUIREMENTS__ is not a dict.')

        reqs = {}
        for tool, raw_val in raw.items():
            if not isinstance(tool, str):
                raise ReqErr(path,
                             'Invalid key in __TOOL_REQUIREMENTS__: {!r}'
                             .format(tool))

            if isinstance(raw_val, str):
                # Shorthand notation: value is just a string, which we
                # interpret as a minimum version
                raw_val = {'min_version': raw_val}

            if not isinstance(raw_val, dict):
                raise ReqErr(path,
                             'Value for {} in __TOOL_REQUIREMENTS__ '
                             'is not a string or dict.'.format(tool))

            reqs[tool] = dict_to_tool_req(path, tool, raw_val)

        return reqs


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('tool', nargs='*')
    args = parser.parse_args()

    # Get tool requirements
    try:
        tool_requirements = read_tool_requirements()
    except ReqErr as err:
        log.error(str(err))
        return 1

    pending_tools = set(args.tool)
    missing_tools = []
    for tool, req in tool_requirements.items():
        if req.as_needed and tool not in pending_tools:
            continue
        pending_tools.discard(tool)

        good, msg = req.check()
        if not good:
            log.error('Failed tool requirement for {}: {}'
                      .format(tool, msg))
            missing_tools.append(tool)
        else:
            log.info('Tool {} present: {}'
                     .format(tool, msg))

    all_good = True
    if missing_tools:
        log.error("Tool requirements not fulfilled. "
                  "Please update tools ({}) and retry."
                  .format(', '.join(missing_tools)))
        all_good = False

    if pending_tools:
        log.error("Some tools specified on command line don't appear in "
                  "tool requirements file: {}"
                  .format(', '.join(sorted(pending_tools))))
        all_good = False

    return 0 if all_good else 1


if __name__ == "__main__":
    sys.exit(main())
