# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from contextlib import contextmanager

from PB.recipes.flutter.engine.engine_lint import InputProperties
from PB.recipes.flutter.engine.engine_lint import EnvProperties

DEPS = [
    'depot_tools/depot_tools',
    'depot_tools/gclient',
    'flutter/build_util',
    'flutter/flutter_deps',
    'flutter/logs_util',
    'flutter/os_utils',
    'flutter/osx_sdk',
    'flutter/repo_util',
    'flutter/retry',
    'flutter/test_utils',
    'fuchsia/goma',
    'recipe_engine/buildbucket',
    'recipe_engine/context',
    'recipe_engine/file',
    'recipe_engine/path',
    'recipe_engine/platform',
    'recipe_engine/properties',
    'recipe_engine/runtime',
    'recipe_engine/step',
]

GIT_REPO = 'https://flutter.googlesource.com/mirrors/engine'

PROPERTIES = InputProperties
ENV_PROPERTIES = EnvProperties


def GetCheckoutPath(api):
  return api.path['cache'].join('builder', 'src')


def RunGN(api, *args):
  checkout = GetCheckoutPath(api)
  api.build_util.run_gn(args, checkout)


def Build(api, config, *targets):
  checkout = GetCheckoutPath(api)
  api.build_util.build(config, checkout, targets)


def Lint(api, config, shardId=None, shardVariants=""):
  checkout = GetCheckoutPath(api)
  with api.context(cwd=checkout):
    lint_cmd = checkout.join('flutter', 'ci', 'lint.sh')
    cmd = [lint_cmd, '--variant', config]
    if api.properties.get('lint_all', True):
      cmd += ['--lint-all']
    if api.properties.get('lint_head', False):
      cmd += ['--lint-head']
    if shardId != None:
      cmd += ['--shard-id=%d' % shardId, '--shard-variants=%s' % shardVariants]
    api.step(api.test_utils.test_step_name('lint %s' % config), cmd)


def DoLints(api):
  if api.platform.is_linux:
    RunGN(api, '--android', '--android-cpu', 'arm64', '--no-lto')
    RunGN(api, '--runtime-mode', 'debug', '--prebuilt-dart-sdk', '--no-lto')
    if api.properties.get('lint_android', True):
      Build(api, 'android_debug_arm64')
      Lint(api, 'android_debug_arm64', shardId=0, shardVariants="host_debug")

    if api.properties.get('lint_host', True):
      # We have to build before linting because source files #include header
      # files that are generated during the build.
      Build(api, 'host_debug')
      Lint(api, 'host_debug', shardId=1, shardVariants="android_debug_arm64")

  elif api.platform.is_mac:
    with api.osx_sdk('ios'):
      RunGN(
          api, '--ios', '--runtime-mode', 'debug', '--simulator', '--no-lto',
      )
      RunGN(api, '--runtime-mode', 'debug', '--prebuilt-dart-sdk', '--no-lto')
      if api.properties.get('lint_ios', True):
        Build(api, 'ios_debug_sim')
        Lint(api, 'ios_debug_sim', shardId=0, shardVariants="host_debug")

      if api.properties.get('lint_host', True):
        # We have to build before linting because source files #include header
        # files that are generated during the build.
        Build(api, 'host_debug')
        Lint(api, 'host_debug', shardId=1, shardVariants="ios_debug_sim")


def RunSteps(api, properties, env_properties):
  # Collect memory/cpu/process before task execution.
  api.os_utils.collect_os_info()

  cache_root = api.path['cache'].join('builder')
  checkout = GetCheckoutPath(api)

  api.file.ensure_directory('Ensure checkout cache', cache_root)
  api.goma.ensure()
  dart_bin = checkout.join(
      'third_party', 'dart', 'tools', 'sdks', 'dart-sdk', 'bin'
  )

  android_home = checkout.join('third_party', 'android_tools', 'sdk')

  env = {
    'GOMA_DIR': api.goma.goma_dir,
    'ANDROID_HOME': str(android_home),
    'FLUTTER_PREBUILT_DART_SDK': 'True',
  }
  env_prefixes = {'PATH': [dart_bin]}

  api.logs_util.initialize_logs_collection(env)

  # Add certificates and print the ones required for pub.
  api.flutter_deps.certs(env, env_prefixes)
  api.os_utils.print_pub_certs()

  # Enable long path support on Windows.
  api.os_utils.enable_long_paths()

  api.repo_util.engine_checkout(cache_root, env, env_prefixes)

  # Delete derived data on mac. This is a noop for other platforms.
  api.os_utils.clean_derived_data()

  # Various scripts we run assume access to depot_tools on path for `ninja`.
  with api.context(cwd=cache_root, env=env,
                   env_prefixes=env_prefixes), api.depot_tools.on_path():

    api.gclient.runhooks()

    try:
      DoLints(api)
    finally:
      api.logs_util.upload_logs('engine')
      # This is to clean up leaked processes.
      api.os_utils.kill_processes()

  # Collect memory/cpu/process after task execution.
  api.os_utils.collect_os_info()


# pylint: disable=line-too-long
# See https://chromium.googlesource.com/infra/luci/recipes-py/+/refs/heads/master/doc/user_guide.md
# The tests in here make sure that every line of code is used and does not fail.
# pylint: enable=line-too-long
def GenTests(api):
  for platform in ('mac', 'linux'):
    for lint_set in ('all', 'head', 'branch'):
      for lint_target in ('host', 'ios', 'android'):
        if lint_target == 'ios' and platform == 'linux':
          continue
        if lint_target == 'android' and platform == 'mac':
          continue
        test = api.test(
            '%s %s %s' % (
                platform, lint_target, lint_set,
            ),
            api.platform(platform, 64),
            api.buildbucket.ci_build(
                builder='%s Engine Lint' % platform.capitalize(),
                git_repo=GIT_REPO,
                project='flutter',
            ),
            api.runtime(is_experimental=False),
            api.properties(
                InputProperties(
                    goma_jobs='1024',
                    lint_all=lint_set == 'all',
                    lint_head=lint_set == 'head',
                    lint_host=lint_target == 'host',
                    lint_android=lint_target == 'android',
                    lint_ios=lint_target == 'ios',
                ),
            ),
            api.properties.environ(
                EnvProperties(SWARMING_TASK_ID='deadbeef')
            ),
        )
        yield test
