# 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.
"""Build a GN target and upload to CIPD."""

from typing import Generator

from PB.recipes.pigweed.target_to_cipd import InputProperties
from recipe_engine import recipe_test_api

DEPS = [
    'fuchsia/buildbucket_util',
    'pigweed/build',
    'pigweed/checkout',
    'pigweed/cipd_upload',
    'pigweed/environment',
    'pigweed/pw_presubmit',
    'recipe_engine/buildbucket',
    'recipe_engine/file',
    'recipe_engine/path',
    'recipe_engine/properties',
    'recipe_engine/scheduler',
    'recipe_engine/step',
]

PROPERTIES = InputProperties


def RunSteps(api, props):
    checkout = api.checkout(props.checkout_options)
    env = api.environment.init(checkout, props.environment_options)

    with env():
        if props.artifacts:
            build = api.build.create(checkout.root, props.build_options)
            api.build(build)
            export_dir = build.root / props.pw_presubmit_options.export_dir_name

        else:
            presubmit = api.pw_presubmit.init(
                checkout, props.pw_presubmit_options
            )

            # Presubmit steps from this recipe only make sense if there's only
            # one, so complain if there's more than one.
            assert len(presubmit.steps) == 1

            # If using steps we use the entirety of export_dir_name instead of
            # artifact globs.
            assert not props.artifacts

            # OrderedDict.values() is not subscriptable, so iterate over the
            # single value instead of using steps[0].
            for step in presubmit.steps:
                assert step.export_dir
                log_dir = api.path.start_dir / 'logs'
                api.pw_presubmit.run(presubmit, step, log_dir=log_dir)
                build_dir = step.dir
                export_dir = step.export_dir
                break  # Not required but makes flow clearer at a glance.

    pkg_dir = api.path.start_dir / 'cipd-package'

    if props.artifacts:
        api.file.ensure_directory('mkdir cipd-package', pkg_dir)

        for glob in props.artifacts:
            with api.step.nest(glob):
                sources = api.file.glob_paths(
                    'glob', build.root, glob, test_data=(glob,)
                )
                if not sources:  # pragma: no cover
                    api.file.listdir('ls build', build.root, recursive=True)
                    raise api.step.StepFailure(f'no matches for {glob}')
                for source in sources:
                    with api.step.nest('source') as pres:
                        pres.step_summary_text = '\n'.join(
                            (str(source), str(build.root))
                        )
                        relpath = api.path.relpath(source, build.root)
                        for replacement in props.replacements:
                            relpath = relpath.replace(
                                replacement.old, replacement.new
                            )
                        dest = pkg_dir / relpath
                        pres.step_summary_text += f'\n{dest}'
                    dirname = api.path.dirname(dest)
                    api.file.ensure_directory(f'mkdir {dirname}', dirname)
                    api.file.copy(f'copy {source} {dest}', source, dest)

    else:
        if api.path.isdir(export_dir):
            api.file.copytree('copy', export_dir, pkg_dir)

    if checkout.options.use_repo:
        api.file.write_text(
            'write manifest',
            pkg_dir / 'manifest.xml',
            checkout.manifest_snapshot(),
        )

    files = api.file.listdir('ls package-dir', pkg_dir, recursive=True)
    if not files:  # pragma: no cover
        raise api.step.StepFailure('no files in package-dir')

    if not props.dry_run and not api.buildbucket_util.is_tryjob:
        assert checkout.changes
        change = checkout.changes[0]
        search_tag = {'git_revision': change.ref}

        api.cipd_upload(
            cipd_path=props.cipd_path,
            package_root=pkg_dir,
            search_tag=search_tag,
            repository=checkout.options.remote,
            add_platform=props.add_cipd_platform,
        )

        if props.roller_name:
            api.scheduler.emit_trigger(
                api.scheduler.GitilesTrigger(
                    change.remote,
                    f'refs/heads/{change.branch}',
                    change.ref,
                ),
                api.buildbucket.build.builder.project,
                (props.roller_name,),
                f'trigger {props.roller_name}',
            )


def GenTests(api) -> Generator[recipe_test_api.TestData, None, None]:
    def properties(**kwargs):
        kwargs.setdefault('cipd_path', 'pigweed/cipd/path')
        kwargs.setdefault('dry_run', False)
        kwargs.setdefault('roller_name', 'ROLL')
        props = InputProperties(**kwargs)
        return api.properties(props)

    yield (
        api.test('success')
        + properties(
            artifacts=['foo/bar/baz'],
            replacements=[{'old': '/bar/', 'new': '/replacement/'}],
            checkout_options=api.checkout.repo_options(),
            build_options=api.build.options(ninja_targets=['foo', 'bar']),
        )
        + api.checkout.ci_test_data(api.checkout.manifest_repo)
        + api.checkout.manifest_test_data(name='pigweed')
        + api.step_data('ls package-dir', api.file.listdir(('foo', 'bar')))
    )

    yield (
        api.test('pw-presubmit')
        + properties(
            checkout_options=api.checkout.git_options(),
            pw_presubmit_options=api.pw_presubmit.options(step=['step']),
        )
        + api.step_data('ls package-dir', api.file.listdir(('foo', 'bar')))
    )
