# Copyright 2020 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.
"""Recipe for testing Pigweed using developer env setup scripts."""

import re

from PB.recipes.pigweed.envtest import InputProperties

DEPS = [
    'fuchsia/macos_sdk',
    'fuchsia/status_check',
    'pigweed/checkout',
    'recipe_engine/context',
    'recipe_engine/file',
    'recipe_engine/path',
    'recipe_engine/platform',
    'recipe_engine/properties',
    'recipe_engine/step',
]

PROPERTIES = InputProperties

PYTHON_VERSION_COMPATIBILITY = "PY3"


def RunSteps(api, props):
    checkout = api.checkout(props.checkout_options)

    run = api.path['start_dir'].join('run')
    api.file.ensure_directory('mkdir run', run)

    setup_path = checkout.root.join(props.setup_path or 'bootstrap.sh')
    env = {}

    for entry in props.environment_variables:
        k, v = entry.split(u'=', 1)
        env[str(k)] = str(v)

    env_root = api.path['start_dir'].join('environment')
    env['PW_ENVIRONMENT_ROOT'] = env_root
    env['PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE'] = '1'
    env['PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED'] = '1'

    setup_path_dir = api.path.abs_to_path(api.path.dirname(setup_path))

    if api.platform.is_win and api.path.splitext(setup_path)[1] == '.sh':
        setup_name = api.path.basename(setup_path)
        setup_name = api.path.splitext(setup_name)[0] + '.bat'
        setup_path = setup_path_dir.join(setup_name)

    command = (
        str(props.command)
        or 'pw --directory $PW_ROOT --loglevel debug presubmit '
        '--step gn_clang_build'
    )
    # Replace '$ABC' with '%ABC%' on Windows.
    if api.platform.is_win:
        command = re.sub(r'\$([\w_]+)\b', r'%\1%', command)

    bootstrap_command = '{dot}{env_setup}'.format(
        dot='call ' if api.platform.is_win else '. ',
        # Without the replace here we end up with paths that have no
        # separators. Not sure why, but this fixes it.
        env_setup=api.path.realpath(setup_path).replace('\\', '\\\\'),
    )

    commands = []
    # Call bootstrap multiple times because occasionally there are issues with
    # subsequent calls but not the first.
    for _ in range(props.bootstrap_count or 2):
        commands.append(bootstrap_command)
    commands.append(command)

    sh_source = ''.join(x + '\n' for x in commands)
    base = 'run.bat' if api.platform.is_win else 'run.sh'
    sh_path = setup_path_dir.join(base)
    api.file.write_text('write {}'.format(base), sh_path, sh_source)

    with api.macos_sdk(), api.step.defer_results():
        with api.context(cwd=run, env=env):
            if api.platform.is_win:
                api.step(base, [sh_path])
            else:
                api.step(base, ['sh', '-x', sh_path])

        with api.step.nest('logs') as pres:
            for pattern in [
                '*.bat',
                '*.json',
                '*.log',
                '*.sh',
                '*/*.cfg',
                '*/*.log',
            ]:
                for path in api.file.glob_paths(
                    'glob environment/{}'.format(pattern), env_root, pattern
                ).get_result():
                    log = api.file.read_text(
                        'read {}'.format(api.path.basename(path)), path
                    ).get_result()
                    pres.logs[api.path.relpath(path, env_root)] = log


def GenTests(api):  # pylint: disable=invalid-name
    def properties(**kwargs):
        new_kwargs = api.checkout.git_properties()
        new_kwargs.update(kwargs)
        return api.properties(**new_kwargs)

    yield (
        api.status_check.test('pigweed')
        + properties()
        + api.checkout.ci_test_data()
    )

    yield (
        api.status_check.test('windows')
        + properties()
        + api.platform.name('win')
        + api.checkout.ci_test_data()
    )

    yield (
        api.status_check.test('fail', status='failure')
        + properties()
        + api.checkout.ci_test_data()
        + api.step_data('run.sh', retcode=1)
        + api.step_data(
            'logs.glob environment/*.json', api.file.glob_paths(['foo.json']),
        )
    )

    yield (
        api.status_check.test('environment_variables')
        + properties(environment_variables=['PW_BOOTSTRAP_PY27=1'])
    )
