# 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):
    api.checkout()

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

    setup_path = api.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 twice because occasionally there are issues with the second
    # call but not the first.
    commands.append(bootstrap_command)
    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'])
    )
