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

import re
from recipe_engine import recipe_api

class DepsDiffException(Exception):
  pass

class RevisionResolver(object):
  """Resolves the revision based on build properties."""

  def resolve(self, properties):  # pragma: no cover
    raise NotImplementedError()


class RevisionFallbackChain(RevisionResolver):
  """Specify that a given project's sync revision follows the fallback
  chain."""

  def __init__(self, default=None):
    self._default = default

  def resolve(self, properties):
    """Resolves the revision via the revision fallback chain.

    If the given revision was set using the revision_fallback_chain() function,
    this function will follow the chain, looking at relevant build properties
    until it finds one set or reaches the end of the chain and returns the
    default. If the given revision was not set using revision_fallback_chain(),
    this function just returns it as-is.
    """
    return (properties.get('parent_got_revision') or
            properties.get('orig_revision') or
            properties.get('revision') or
            self._default)


def jsonish_to_python(spec, is_top=False):
  """Turns a json spec into a python parsable object.

  This exists because Gclient specs, while resembling json, is actually
  ingested using a python "eval()".  Therefore a bit of plumming is required
  to turn our newly constructed Gclient spec into a gclient-readable spec.
  """
  ret = ''
  if is_top:  # We're the 'top' level, so treat this dict as a suite.
    ret = '\n'.join(
      '%s = %s' % (k, jsonish_to_python(spec[k])) for k in sorted(spec)
    )
  else:
    if isinstance(spec, dict):
      ret += '{'
      ret += ', '.join(
        "%s: %s" % (repr(str(k)), jsonish_to_python(spec[k]))
        for k in sorted(spec)
      )
      ret += '}'
    elif isinstance(spec, list):
      ret += '['
      ret += ', '.join(jsonish_to_python(x) for x in spec)
      ret += ']'
    elif isinstance(spec, basestring):
      ret = repr(str(spec))
    else:
      ret = repr(spec)
  return ret

class GclientApi(recipe_api.RecipeApi):
  # Singleton object to indicate to checkout() that we should run a revert if
  # we detect that we're on the tryserver.
  RevertOnTryserver = object()

  def __init__(self, **kwargs):
    super(GclientApi, self).__init__(**kwargs)
    self.USE_MIRROR = None
    self._spec_alias = None

  def __call__(self, name, cmd, infra_step=True, **kwargs):
    """Wrapper for easy calling of gclient steps."""
    assert isinstance(cmd, (list, tuple))
    prefix = 'gclient '
    if self.spec_alias:
      prefix = ('[spec: %s] ' % self.spec_alias) + prefix

    with self.m.context(
        env_suffixes={'PATH': [self.repo_resource()]}):
      return self.m.python(prefix + name,
                           self.repo_resource('gclient.py'),
                           cmd,
                           infra_step=infra_step,
                           **kwargs)

  @property
  def use_mirror(self):
    """Indicates if gclient will use mirrors in its configuration."""
    if self.USE_MIRROR is None:
      self.USE_MIRROR = self.m.properties.get('use_mirror', True)
    return self.USE_MIRROR

  @use_mirror.setter
  def use_mirror(self, val):  # pragma: no cover
    self.USE_MIRROR = val

  @property
  def spec_alias(self):
    """Optional name for the current spec for step naming."""
    return self._spec_alias

  @spec_alias.setter
  def spec_alias(self, name):
    self._spec_alias = name

  @spec_alias.deleter
  def spec_alias(self):
    self._spec_alias = None

  def get_config_defaults(self):
    return {
      'USE_MIRROR': self.use_mirror,
      'CACHE_DIR': self.m.path['cache'].join('git'),
    }

  @staticmethod
  def config_to_pythonish(cfg):
    return jsonish_to_python(cfg.as_jsonish(), True)

  # TODO(machenbach): Remove this method when the old mapping is deprecated.
  @staticmethod
  def got_revision_reverse_mapping(cfg):
    """Returns the merged got_revision_reverse_mapping.

    Returns (dict): A mapping from property name -> project name. It merges the
        values of the deprecated got_revision_mapping and the new
        got_revision_reverse_mapping.
    """
    rev_map = cfg.got_revision_mapping.as_jsonish()
    reverse_rev_map = cfg.got_revision_reverse_mapping.as_jsonish()
    combined_length = len(rev_map) + len(reverse_rev_map)
    reverse_rev_map.update({v: k for k, v in rev_map.items()})

    # Make sure we never have duplicate values in the old map.
    assert combined_length == len(reverse_rev_map)
    return reverse_rev_map

  def resolve_revision(self, revision):
    if hasattr(revision, 'resolve'):
      return revision.resolve(self.m.properties)
    return revision

  def sync(self, cfg, extra_sync_flags=None, **kwargs):
    revisions = []
    self.set_patch_repo_revision(gclient_config=cfg)
    for i, s in enumerate(cfg.solutions):
      if i == 0 and s.revision is None:
        s.revision = RevisionFallbackChain()

      if s.revision is not None and s.revision != '':
        fixed_revision = self.resolve_revision(s.revision)
        if fixed_revision:
          revisions.extend(['--revision', '%s@%s' % (s.name, fixed_revision)])

    for name, revision in sorted(cfg.revisions.items()):
      fixed_revision = self.resolve_revision(revision)
      if fixed_revision:
        revisions.extend(['--revision', '%s@%s' % (name, fixed_revision)])

    test_data_paths = set(self.got_revision_reverse_mapping(cfg).values() +
                          [s.name for s in cfg.solutions])
    step_test_data = lambda: (
      self.test_api.output_json(test_data_paths))
    try:
      # clean() isn't used because the gclient sync flags passed in checkout()
      # do much the same thing, and they're more correct than doing a separate
      # 'gclient revert' because it makes sure the other args are correct when
      # a repo was deleted and needs to be re-cloned (notably
      # --with_branch_heads), whereas 'revert' uses default args for clone
      # operations.
      #
      # TODO(mmoss): To be like current official builders, this step could
      # just delete the whole <slave_name>/build/ directory and start each
      # build from scratch. That might be the least bad solution, at least
      # until we have a reliable gclient method to produce a pristine working
      # dir for git-based builds (e.g. maybe some combination of 'git
      # reset/clean -fx' and removing the 'out' directory).
      j = '-j2' if self.m.platform.is_win else '-j8'
      args = ['sync', '--verbose', '--nohooks', j, '--reset', '--force',
              '--upstream', '--no-nag-max', '--with_branch_heads',
              '--with_tags']
      args.extend(extra_sync_flags or [])
      if cfg.delete_unversioned_trees:
        args.append('--delete_unversioned_trees')
      self('sync', args + revisions +
                 ['--output-json', self.m.json.output()],
                 step_test_data=step_test_data,
                 **kwargs)
    finally:
      result = self.m.step.active_result
      if result.json.output is not None:
        solutions = result.json.output['solutions']
        for propname, path in sorted(
            self.got_revision_reverse_mapping(cfg).items()):
          # gclient json paths always end with a slash
          info = solutions.get(path + '/') or solutions.get(path)
          if info:
            result.presentation.properties[propname] = info['revision']

    return result

  def inject_parent_got_revision(self, gclient_config=None, override=False):
    """Match gclient config to build revisions obtained from build_properties.

    Args:
      gclient_config (gclient config object) - The config to manipulate. A value
        of None manipulates the module's built-in config (self.c).
      override (bool) - If True, will forcibly set revision and custom_vars
        even if the config already contains values for them.
    """
    cfg = gclient_config or self.c

    for prop, custom_var in cfg.parent_got_revision_mapping.items():
      val = str(self.m.properties.get(prop, ''))
      # TODO(infra): Fix coverage.
      if val:  # pragma: no cover
        # Special case for 'src', inject into solutions[0]
        if custom_var is None:
          # This is not covered because we are deprecating this feature and
          # it is no longer used by the public recipes.
          if cfg.solutions[0].revision is None or override:  # pragma: no cover
            cfg.solutions[0].revision = val
        else:
          if custom_var not in cfg.solutions[0].custom_vars or override:
            cfg.solutions[0].custom_vars[custom_var] = val

  def checkout(self, gclient_config=None, revert=RevertOnTryserver,
               inject_parent_got_revision=True, extra_sync_flags=None,
               **kwargs):
    """Return a step generator function for gclient checkouts."""
    cfg = gclient_config or self.c
    assert cfg.complete()

    if revert is self.RevertOnTryserver:
      revert = self.m.tryserver.is_tryserver

    if inject_parent_got_revision:
      self.inject_parent_got_revision(cfg, override=True)

    self('setup', ['config', '--spec', self.config_to_pythonish(cfg)], **kwargs)

    sync_step = None
    try:
      sync_step = self.sync(cfg, extra_sync_flags=extra_sync_flags, **kwargs)

      cfg_cmds = [
        ('user.name', 'local_bot'),
        ('user.email', 'local_bot@example.com'),
      ]
      for var, val in cfg_cmds:
        name = 'recurse (git config %s)' % var
        self(name, ['recurse', 'git', 'config', var, val], **kwargs)
    finally:
      cwd = self.m.context.cwd or self.m.path['start_dir']
      if 'checkout' not in self.m.path:
        self.m.path['checkout'] = cwd.join(
          *cfg.solutions[0].name.split(self.m.path.sep))

    return sync_step

  def runhooks(self, args=None, name='runhooks', **kwargs):
    args = args or []
    assert isinstance(args, (list, tuple))
    with self.m.context(cwd=(self.m.context.cwd or self.m.path['checkout'])):
      return self(name, ['runhooks'] + list(args), infra_step=False, **kwargs)

  def break_locks(self):
    """Remove all index.lock files. If a previous run of git crashed, bot was
    reset, etc... we might end up with leftover index.lock files.
    """
    self.m.python.inline(
      'cleanup index.lock',
      """
        import os, sys

        build_path = sys.argv[1]
        if os.path.exists(build_path):
          for (path, dir, files) in os.walk(build_path):
            for cur_file in files:
              if cur_file.endswith('index.lock'):
                path_to_file = os.path.join(path, cur_file)
                print('deleting %s' % path_to_file)
                os.remove(path_to_file)
      """,
      args=[self.m.path['start_dir']],
      infra_step=True,
    )

  def get_gerrit_patch_root(self, gclient_config=None):
    """Returns local path to the repo where gerrit patch will be applied.

    If there is no patch, returns None.
    If patch is specified, but such repo is not found among configured solutions
    or repo_path_map, returns name of the first solution. This is done solely
    for backward compatibility with existing tests.
    Please do not rely on this logic in new code.
    Instead, properly map a repository to a local path using repo_path_map.
    TODO(nodir): remove this. Update all recipe tests to specify a git_repo
    matching the recipe.
    """
    cfg = gclient_config or self.c
    repo_url = self.m.tryserver.gerrit_change_repo_url
    if not repo_url:
      return None
    root =  self.get_repo_path(repo_url, gclient_config=cfg)

    # This is wrong, but that's what a ton of recipe tests expect today
    root = root or cfg.solutions[0].name

    return root

  def _canonicalize_repo_url(self, repo_url):
    """Attempts to make repo_url canonical. Supports Gitiles URL."""
    return self.m.gitiles.canonicalize_repo_url(repo_url)

  def get_repo_path(self, repo_url, gclient_config=None):
    """Returns local path to the repo checkout given its url.

    Consults cfg.repo_path_map and fallbacks to urls in configured solutions.

    Returns None if not found.
    """
    rel_path = self._get_repo_path(repo_url, gclient_config=gclient_config)
    if rel_path:
      return self.m.path.join(*rel_path.split('/'))
    return None

  def _get_repo_path(self, repo_url, gclient_config=None):
    repo_url = self._canonicalize_repo_url(repo_url)
    cfg = gclient_config or self.c
    rel_path, _ = cfg.repo_path_map.get(repo_url, ('', ''))
    if rel_path:
      return rel_path

    # repo_path_map keys may be non-canonical.
    for key, (rel_path, _) in cfg.repo_path_map.items():
      if self._canonicalize_repo_url(key) == repo_url:
        return rel_path

    for s in cfg.solutions:
      if self._canonicalize_repo_url(s.url) == repo_url:
        return s.name

    return None

  def set_patch_repo_revision(self, gclient_config=None):
    """Updates config revision corresponding to patched project.

    Useful for bot_update only, as this is the only consumer of gclient's config
    revision map. This doesn't overwrite the revision if it was already set.
    """
    cfg = gclient_config or self.c
    repo_url = self.m.tryserver.gerrit_change_repo_url
    path, revision = cfg.repo_path_map.get(repo_url, (None, None))
    if path and revision and path not in cfg.revisions:
      cfg.revisions[path] = revision

  def diff_deps(self, cwd):
    with self.m.context(cwd=cwd):
      step_result = self.m.git(
          '-c',
          'core.quotePath=false',
          'checkout',
          'HEAD~',
          '--',
          'DEPS',
          name='checkout the previous DEPS',
          stdout=self.m.raw_io.output()
      )

      try:
        cfg = self.c

        step_result = self(
            'recursively git diff all DEPS',
            ['recurse', 'python', self.resource('diff_deps.py')],
            stdout=self.m.raw_io.output_text(add_output_log=True),
        )

        paths = []
        # gclient recurse prepends a number and a > to each line
        # Let's take that out
        for line in step_result.stdout.strip().splitlines():
          if 'fatal: bad object' in line:
            msg = "Couldn't checkout previous ref: %s" % line
            step_result.presentation.logs['DepsDiffException'] = msg
            raise self.DepsDiffException(msg)
          elif re.match('\d+>', line):
            paths.append(line[line.index('>') + 1:])


        # Normalize paths
        if self.m.platform.is_win:
          # Looks like "analyze" wants POSIX slashes even on Windows (since git
          # uses that format even on Windows).
          paths = [path.replace('\\', '/') for path in paths]

        if len(paths) > 0:
          return paths
        else:
          msg = 'Unexpected result: autoroll diff found 0 files changed'
          step_result.presentation.logs['DepsDiffException'] = msg
          raise self.DepsDiffException(msg)

      finally:
        self.m.git(
            '-c',
            'core.quotePath=false',
            'checkout',
            'HEAD',
            '--',
            'DEPS',
            name="checkout the original DEPS")

  @property
  def DepsDiffException(self):
    return DepsDiffException
