# Copyright 2021 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 copy part of the build directory to another repo."""

from PB.recipes.pigweed.target_to_git import InputProperties
from PB.recipe_modules.pigweed.checkout.options import (
    Options as CheckoutOptions,
)

DEPS = [
    'fuchsia/auto_roller',
    'fuchsia/git',
    'fuchsia/status_check',
    'pigweed/build',
    'pigweed/checkout',
    'pigweed/environment',
    'pigweed/roll_util',
    'recipe_engine/context',
    'recipe_engine/file',
    'recipe_engine/path',
    'recipe_engine/properties',
    'recipe_engine/step',
]

PROPERTIES = InputProperties


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

    with env():
        api.build(checkout.root, props.build_options)

    export_repo = api.path['start_dir'].join('export_repo')
    dest_checkout = api.checkout(
        CheckoutOptions(
            remote=props.remote,
            branch=props.branch or 'main',
            use_trigger=False,
        ),
        root=export_repo,
    )

    with api.step.nest('rm'):
        for entry in api.file.glob_paths(
            'glob',
            export_repo,
            '*',
            include_hidden=False,
            test_data=('pw_foo', 'pw_bar'),
        ):
            if 'OWNERS' not in api.path.basename(entry):
                api.file.rmtree(api.path.basename(entry), entry)

    with api.step.nest('mv'):
        for entry in api.file.glob_paths(
            'glob',
            api.build.dir.join(props.artifact_root),
            '*',
            test_data=('pw_foo', 'pw_bar'),
        ):
            api.file.move(api.path.basename(entry), entry, export_repo)

    with api.context(cwd=export_repo):
        api.git('git add --intent-to-add', 'add', '--intent-to-add', '.')

    change = api.auto_roller.attempt_roll(
        api.auto_roller.Options(
            remote=props.remote,
            upstream_ref=props.branch,
            dry_run=props.dry_run,
            labels_to_set=api.roll_util.labels_to_set,
            labels_to_wait_on=api.roll_util.labels_to_wait_on,
            bot_commit=props.bot_commit,
        ),
        repo_dir=export_repo,
        commit_message='Update for {}'.format(checkout.revision()),
    )

    return api.auto_roller.raw_result(change)


def GenTests(api):  # pylint: disable=invalid-name
    yield (
        api.status_check.test('success')
        + api.properties(
            artifact_root='out/generated',
            remote='https://pigweed.googlesource.com/generated',
            dry_run=False,
            **api.checkout.git_properties(),
        )
        + api.checkout.ci_test_data()
        + api.auto_roller.success()
    )
