# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
"""Recipe for building GN."""

DEPS = [
    'recipe_engine/buildbucket',
    'recipe_engine/cipd',
    'recipe_engine/context',
    'recipe_engine/json',
    'recipe_engine/path',
    'recipe_engine/platform',
    'recipe_engine/properties',
    'recipe_engine/python',
    'recipe_engine/step',
]


def RunSteps(api):
  src_dir = api.path['start_dir'].join('gn')

  with api.step.nest('git'), api.context(infra_steps=True):
    api.step('init', ['git', 'init', src_dir])

    with api.context(cwd=src_dir):
      build_input = api.buildbucket.build_input
      ref = (
          build_input.gitiles_commit.id
          if build_input.gitiles_commit else 'refs/heads/master')
      api.step('fetch', ['git', 'fetch', 'https://gn.googlesource.com/gn', ref])
      api.step('checkout', ['git', 'checkout', 'FETCH_HEAD'])
      for change in build_input.gerrit_changes:
        api.step('fetch %s/%s' % (change.change, change.patchset), [
            'git', 'fetch',
            'https://%s/gn' % change.host,
            'refs/changes/%s/%s/%s' %
            (str(change.change)[-2:], change.change, change.patchset)
        ])
        api.step('cherry-pick %s/%s' % (change.change, change.patchset),
                 ['git', 'cherry-pick', 'FETCH_HEAD'])

  with api.context(infra_steps=True):
    cipd_dir = api.path['start_dir'].join('cipd')
    packages = {
        'infra/ninja/${platform}': 'version:1.8.2',
    }
    packages.update({
        'linux': {
            'fuchsia/clang/${platform}': 'goma',
        },
        'mac': {},
        'win': {
            'chrome_internal/third_party/sdk/windows': 'uploaded:2018-06-13',
        },
    }[api.platform.name])
    api.cipd.ensure(cipd_dir, packages)

  environ_pre = {}

  win_env = {}
  if api.platform.name == 'win':
    # Load .../win_sdk/bin/SetEnv.x64.json to extract the required environment.
    # It contains a dict that looks like this:
    # {
    #   "env": {
    #     "VAR": [["..", "..", "x"], ["..", "..", "y"]],
    #     ...
    #   }
    # }
    # All these environment variables need to be added to the environment
    # for the compiler and linker to work.

    json_file = cipd_dir.join('win_sdk', 'bin', 'SetEnv.x64.json')
    env = api.json.read('SetEnv.x64.json', json_file).json.output.get('env')
    for k in env:
      # recipes' Path() does not like .., ., \, or /, so this is cumbersome.
      # What we want to do is:
      #   [sdk_bin_dir.join(*e) for e in env[k]]
      # Instead do that badly, and rely (but verify) on the fact that the paths
      # are all specified relative to the root, but specified relative to
      # win_sdk/bin (i.e. everything starts with "../../".)
      results = []
      for data in env[k]:
        assert data[0] == '..' and (data[1] == '..' or data[1] == '..\\')
        root_relative = data[2:]
        results.append('%s' % cipd_dir.join(*root_relative))

      # PATH is special-cased because we don't want to overwrite other things
      # like C:\Windows\System32. Others are replacements because prepending
      # doesn't necessarily makes sense, like VSINSTALLDIR.
      if k.lower() == 'path':
        # env_prefixes wants a list, not a string like env.
        environ_pre[k] = results
      else:
        win_env[k] = ';'.join(results)

  environ = {
      'linux': {
          'CC': cipd_dir.join('bin', 'clang'),
          'CXX': cipd_dir.join('bin', 'clang++'),
          'AR': cipd_dir.join('bin', 'llvm-ar'),
          'LDFLAGS': '-static-libstdc++ -ldl -lpthread',
      },
      'mac': {},
      'win': win_env,
  }[api.platform.name]

  configs = [
      {
          'name': 'debug',
          'args': ['-d']
      },
      {
          'name': 'release',
          'args': []
      },
  ]

  for config in configs:
    with api.step.nest(config['name']):
      with api.step.nest('build'):
        with api.context(env=environ, env_prefixes=environ_pre, cwd=src_dir):
          api.python('generate',
                     src_dir.join('build', 'gen.py'),
                     args=config['args'])

          # Windows requires the environment modifications when building too.
          api.step('ninja', [cipd_dir.join('ninja'), '-C', src_dir.join('out')])

        if api.platform.name == 'win':
          # Swarming won't be able to tidy up after the compiler leaves this
          # daemon running, so we have to manually kill it.
          api.step('taskkill mspdbsrv',
                   ['taskkill.exe', '/f', '/t', '/im', 'mspdbsrv.exe'])

      api.step('test', [src_dir.join('out', 'gn_unittests')])


def GenTests(api):
  WIN_TOOLCHAIN_DATA = {
    "env": {
      "VSINSTALLDIR": [["..", "..\\"]],
      "INCLUDE": [["..", "..", "win_sdk", "Include", "10.0.17134.0", "um"], ["..", "..", "win_sdk", "Include", "10.0.17134.0", "shared"], ["..", "..", "win_sdk", "Include", "10.0.17134.0", "winrt"]],
      "PATH": [["..", "..", "win_sdk", "bin", "10.0.17134.0", "x64"], ["..", "..", "VC", "Tools", "MSVC", "14.14.26428", "bin", "HostX64", "x64"]],
    }
  }
  for platform in ('linux', 'mac', 'win'):
    to_yield = (api.test('ci_' + platform) + api.platform.name(platform) +
                api.properties(buildbucket={
                  'build': {
                    'tags': [
                      'buildset:commit/gitiles/gn.googlesource.com/gn/+/'
                      'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
                    ]
                  }
                }))
    if platform == 'win':
      to_yield += api.override_step_data('SetEnv.x64.json',
          api.json.output(WIN_TOOLCHAIN_DATA))
    yield to_yield

    to_yield = (api.test('cq_' + platform) + api.platform.name(platform) +
                api.properties(buildbucket={
                  'build': {
                    'tags': [
                      'buildset:patch/gerrit/gn-review.googlesource.com/1000/1',
                    ]
                  }
                }))
    if platform == 'win':
      to_yield += api.override_step_data('SetEnv.x64.json',
          api.json.output(WIN_TOOLCHAIN_DATA))
    yield to_yield
