# Copyright 2019 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Python wrapper that runs a program. For use in GN."""

import argparse
import logging
import os
import re
import shlex
import subprocess
import sys
from typing import Dict, Optional

# Need to be able to run without pw_cli installed in the virtualenv.
try:
    import pw_cli.log
except ImportError:
    pass

_LOG = logging.getLogger(__name__)


def argument_parser(
    parser: Optional[argparse.ArgumentParser] = None
) -> argparse.ArgumentParser:
    """Registers the script's arguments on an argument parser."""

    if parser is None:
        parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument(
        '--args-file',
        type=argparse.FileType('r'),
        help='File containing extra positional arguments to the program',
    )
    parser.add_argument(
        '--capture-output',
        action='store_true',
        help='Hide output from the program unless it fails',
    )
    parser.add_argument(
        '-e',
        '--env',
        action='append',
        default=[],
        help='key=value environment pair for the process',
    )
    parser.add_argument(
        '--env-file',
        type=argparse.FileType('r'),
        help='File defining environment variables for the process',
    )
    parser.add_argument(
        '--skip-empty-args',
        action='store_true',
        help='Don\'t run the program if --args-file is empty',
    )
    parser.add_argument(
        '--target',
        help='GN build target that runs the program',
    )
    parser.add_argument(
        'command',
        nargs=argparse.REMAINDER,
        help='Program to run with arguments',
    )

    return parser


_ENV_REGEX = re.compile(r'(\w+)(\+)?=(.+)')


def apply_env_var(string: str, env: Dict[str, str]) -> None:
    """Update an environment map with provided a key-value pair.

    Pairs are accepted in two forms:

      KEY=value    sets environment variable "KEY" to "value"
      KEY+=value   appends OS-specific PATH separator and "value" to
                   environment variable "KEY"
    """
    result = _ENV_REGEX.search(string.strip())
    if not result:
        return

    key, append, val = result.groups()
    if append is not None:
        curr = env.get(key)
        val = f'{curr}{os.path.pathsep}{val}' if curr else val

    env[key] = val


def main() -> int:
    """Runs a program specified by command-line arguments."""
    args = argument_parser().parse_args()
    if not args.command or args.command[0] != '--':
        return 1

    env = os.environ.copy()

    # Command starts after the "--".
    command = args.command[1:]

    if args.args_file is not None:
        empty = True
        for line in args.args_file:
            empty = False
            command.append(line.strip())

        if args.skip_empty_args and empty:
            return 0

    if args.env_file is not None:
        for line in args.env_file:
            apply_env_var(line, env)

    # Apply command-line overrides at a higher priority than the env file.
    for string in args.env:
        apply_env_var(string, env)

    if args.capture_output:
        output_args = {'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT}
    else:
        output_args = {}

    process = subprocess.run(command, env=env, **output_args)  # type: ignore

    if process.returncode != 0 and args.capture_output:
        _LOG.error('')
        _LOG.error('Command failed with exit code %d in GN build.',
                   process.returncode)
        _LOG.error('')
        _LOG.error('Build target:')
        _LOG.error('')
        _LOG.error('  %s', args.target)
        _LOG.error('')
        _LOG.error('Full command:')
        _LOG.error('')
        _LOG.error('  %s', ' '.join(shlex.quote(arg) for arg in command))
        _LOG.error('')
        _LOG.error('Process output:')
        print(flush=True)
        sys.stdout.buffer.write(process.stdout)
        print(flush=True)
        _LOG.error('')

    return process.returncode


if __name__ == '__main__':
    # If pw_cli is not yet installed in the virtualenv just skip it.
    if 'pw_cli' in globals():
        pw_cli.log.install()
    sys.exit(main())
