# 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.
"""Calls to build code."""

import dataclasses
from typing import Any

from PB.recipe_modules.pigweed.build import options as options_pb2
from recipe_engine import recipe_api


@dataclasses.dataclass
class Context:
    _api: Any
    checkout_root: Any
    root: Any
    options: options_pb2.Options


class BuildApi(recipe_api.RecipeApi):
    """Calls to build code."""

    CAS_DIGEST_PROPERTY_NAME = 'cas_build_digest'

    def create(self, checkout_root, options, root=None):
        if not root:
            root = checkout_root / 'out'
        return Context(self.m, checkout_root, root, options)

    def __call__(self, ctx):
        self.install_packages(ctx)
        self.gn_gen(ctx)
        self.ninja(ctx)

    def install_packages(self, ctx):
        if not ctx.options.packages:
            return

        with self.m.step.nest('install packages'):
            cmd = ['python', '-m', 'pw_cli', 'package', 'install']
            for package in ctx.options.packages:
                self.m.step(package, cmd + [package])

    def gn_gen(self, ctx):
        cmd = ['gn', 'gen']

        for gn_arg in ctx.options.gn_args:
            cmd.append(f'--args={gn_arg}')

        # Infrequently needed but harmless to always add this.
        cmd.append('--export-compile-commands')

        cmd.append(ctx.root)

        with self.m.context(cwd=ctx.checkout_root):
            self.m.step('gn gen', cmd)

    def get_gn_args(self, ctx, test_data=None):
        context_kwargs = {'cwd': ctx.checkout_root} if ctx.checkout_root else {}
        with self.m.context(**context_kwargs):
            cmd = ['gn', 'args', ctx.root, '--list', '--json']
            args = self.m.step(
                'all gn args',
                cmd,
                stdout=self.m.json.output(),
                step_test_data=lambda: self.m.json.test_api.output_stream(
                    test_data or []
                ),
            ).stdout
            return {x['name']: x for x in args or ()}

    def ninja(self, ctx):
        cmd = ['ninja', '-C', ctx.root]
        cmd.extend(ctx.options.ninja_targets)
        with self.m.default_timeout():
            self.m.step('ninja', cmd)

    def archive_to_cas(self, ctx):
        # TODO(b/234879756) Only archive necessary files.
        with self.m.step.nest('archive to cas') as pres:
            digest = self.m.cas.archive('archive', ctx.root, ctx.root)
            pres.properties[self.CAS_DIGEST_PROPERTY_NAME] = digest
            return digest

    def download_from_cas(self, ctx, digest):
        return self.m.cas.download('download from cas', digest, ctx.root)
