# Copyright 2014 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.


# pylint: disable=W0201


from recipe_engine import recipe_api
from recipe_engine import config_types


class CheckoutApi(recipe_api.RecipeApi):

  @property
  def default_checkout_root(self):
    """The default location for cached persistent checkouts."""
    return self.m.vars.cache_dir.join('work')

  def assert_git_is_from_cipd(self):
    """Fail if git is not obtained from CIPD."""
    self.m.run(self.m.python.inline, 'Assert that Git is from CIPD', program='''
import subprocess
import sys

which = 'where' if sys.platform == 'win32' else 'which'
git = subprocess.check_output([which, 'git'])
print 'git was found at %s' % git
if 'cipd_bin_packages' not in git:
  print >> sys.stderr, 'Git must be obtained through CIPD.'
  sys.exit(1)
''')

  def git(self, checkout_root):
    """Run the steps to perform a pure-git checkout without DEPS."""
    self.assert_git_is_from_cipd()
    skia_dir = checkout_root.join('skia')
    self.m.git.checkout(
        self.m.properties['repository'], dir_path=skia_dir,
        ref=self.m.properties['revision'], submodules=False)
    if self.m.vars.is_trybot:
      self.m.git('fetch', 'origin', self.m.properties['patch_ref'])
      self.m.git('checkout', 'FETCH_HEAD')
      self.m.git('rebase', self.m.properties['revision'])
      return self.m.properties['revision']

  def bot_update(self, checkout_root, gclient_cache=None,
                 checkout_chromium=False, checkout_flutter=False,
                 extra_gclient_env=None,
                 flutter_android=False):
    """Run the steps to obtain a checkout using bot_update.

    Args:
      checkout_root: Root directory where the code will be synced.
      gclient_cache: Optional, directory of the gclient cache.
      checkout_chromium: If True, will check out chromium/src.git in addition
          to the primary repo.
      checkout_flutter: If True, will checkout flutter in addition to the
          primary repo.
      extra_gclient_env: Map of extra environment variable names to their values
          to supply while running gclient.
      flutter_android: Indicates that we're checking out flutter for Android.
    """
    self.assert_git_is_from_cipd()
    if not gclient_cache:
      gclient_cache = self.m.vars.cache_dir.join('git')
    if not extra_gclient_env:
      extra_gclient_env = {}

    cfg_kwargs = {}

    # Use a persistent gclient cache for Swarming.
    cfg_kwargs['CACHE_DIR'] = gclient_cache

    # Create the checkout path if necessary.
    # TODO(borenet): 'makedirs checkout_root'
    self.m.file.ensure_directory('makedirs checkout_path', checkout_root)

    # Initial cleanup.
    gclient_cfg = self.m.gclient.make_config(**cfg_kwargs)

    main_repo = self.m.properties['repository']
    if checkout_flutter:
      main_repo = 'https://github.com/flutter/engine.git'
    main_name = self.m.path.basename(main_repo)
    if main_name.endswith('.git'):
      main_name = main_name[:-len('.git')]
      # Special case for flutter because it seems to need a very specific
      # directory structure to successfully build.
      if checkout_flutter and main_name == 'engine':
        main_name = 'src/flutter'
    main = gclient_cfg.solutions.add()
    main.name = main_name
    main.managed = False
    main.url = main_repo
    main.revision = self.m.properties.get('revision') or 'origin/master'
    m = gclient_cfg.got_revision_mapping
    m[main_name] = 'got_revision'
    patch_root = main_name
    patch_repo = main.url
    if self.m.properties.get('patch_repo'):
      patch_repo = self.m.properties['patch_repo']
      patch_root = patch_repo.split('/')[-1]
      if patch_root.endswith('.git'):
        patch_root = patch_root[:-4]

    if checkout_flutter:
      # Skia is a DEP of Flutter; the 'revision' property is a Skia revision,
      # and any patch should be applied to Skia, not Flutter.
      main.revision = 'origin/master'
      main.managed = True
      m[main_name] = 'got_flutter_revision'
      if flutter_android:
        gclient_cfg.target_os.add('android')

      skia_dep_path = 'src/third_party/skia'
      gclient_cfg.repo_path_map['https://skia.googlesource.com/skia'] = (
          skia_dep_path, 'HEAD')
      gclient_cfg.revisions[skia_dep_path] = self.m.properties['revision']
      m[skia_dep_path] = 'got_revision'
      patch_root = skia_dep_path

    if checkout_chromium:
      main.custom_vars['checkout_chromium'] = True
      extra_gclient_env['GYP_CHROMIUM_NO_ACTION'] = '0'

    # TODO(rmistry): Remove the below block after there is a solution for
    #                crbug.com/616443
    entries_file = checkout_root.join('.gclient_entries')
    if self.m.path.exists(entries_file) or self._test_data.enabled:
      self.m.file.remove('remove %s' % entries_file,
                         entries_file)

    # Run bot_update.
    patch_refs = None
    patch_ref = self.m.properties.get('patch_ref')
    if patch_ref:
      patch_refs = ['%s@%s:%s' % (self.m.properties['patch_repo'],
                                  self.m.properties['revision'],
                                  patch_ref)]

    self.m.gclient.c = gclient_cfg
    with self.m.context(cwd=checkout_root):
      update_step = self.m.bot_update.ensure_checkout(
          patch_root=patch_root,
          # The logic in ensure_checkout for this arg is fairly naive, so if
          # patch=False, we'll see "... (without patch)" in the step names, even
          # for non-trybot runs, which is misleading and confusing. Therefore,
          # always specify patch=True.
          patch=True,
          patch_refs=patch_refs,
      )

    if checkout_chromium or checkout_flutter:
      gclient_env = {'DEPOT_TOOLS_UPDATE': '0'}
      if extra_gclient_env:
        gclient_env.update(extra_gclient_env)
      with self.m.context(cwd=checkout_root, env=gclient_env):
        self.m.gclient.runhooks()
    return update_step.presentation.properties['got_revision']
