# Copyright 2018 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 recipe_engine import recipe_api


class DockerApi(recipe_api.RecipeApi):
  """Provides steps to connect and run Docker images."""

  def __init__(self, *args, **kwargs):
    super(DockerApi, self).__init__(*args, **kwargs)
    self._config_file = None
    self._project = None
    self._server = None

  def ensure_installed(self, **kwargs):
    """Checks that the docker binary is in the PATH.

    Raises StepFailure if binary is not found.
    """
    try:
      self.m.step('ensure docker installed', ['which', 'docker'], **kwargs)
    except self.m.step.StepFailure as f:
      f.result.presentation.step_text = (
          'Error: is docker not installed or not in the PATH')
      raise

  def get_version(self, **kwargs):
    """Returns Docker version installed or None if failed to detect."""
    docker_version_step = self(
        'version', stdout=self.m.raw_io.output(),
        step_test_data=(
          lambda: self.m.raw_io.test_api.stream_output('Version: 1.2.3')))
    for line in docker_version_step.stdout.splitlines():
      line = line.strip().lower()
      if line.startswith('version: '):
        version = line[len('version: '):]
        docker_version_step.presentation.step_text = version
        return version
    else:
      docker_version_step.presentation.step_text = 'Version unknown?'
      return None


  def login(self, server='gcr.io', project='chromium-container-registry',
            service_account=None, step_name=None, **kwargs):
    """Connect to a Docker registry.

    This step must be executed before any other step in this module that
    requires authentication.

    Args:
      server: Docker server to connect to.
      project: Name of the Cloud project where Docker images are hosted.
      service_account: service_account.api.ServiceAccount used for
          authenticating with the container registry. Defaults to the task's
          associated service account.
      step_name: Override step name. Default is 'docker login'.
    """
    # We store config file in the cleanup dir to ensure that it is deleted after
    # the build finishes running. This way no subsequent builds running on the
    # same bot can re-use credentials obtained below.
    self._config_file = self.m.path['cleanup'].join('.docker')
    self._project = project
    self._server = server
    if not service_account:
      service_account = self.m.service_account.default()
    token = service_account.get_access_token(
        ['https://www.googleapis.com/auth/cloud-platform'])
    self.m.python(
        step_name or 'docker login',
        self.resource('docker_login.py'),
        args=[
          '--server', server,
          '--service-account-token-file', self.m.raw_io.input(token),
          '--config-file', self._config_file,
        ],
        **kwargs)

  def run(self, image, step_name=None, cmd_args=None, dir_mapping=None,
          **kwargs):
    """Run a command in a Docker image as the current user:group.

    Args:
      image: Name of the image to run.
      cmd_args: Used to specify command to run in an image as a list of
          arguments. If not specified, then the default command embedded into
          the image is executed.
      dir_mapping: List of tuples (host_dir, docker_dir) mapping host
          directories to directories in a Docker container. Directories are
          mapped as read-write.
      step_name: Override step name. Default is 'docker run'.
    """
    assert self._config_file, 'Did you forget to call docker.login?'
    args = [
      '--config-file', self._config_file,
      '--image', '%s/%s/%s' % (self._server, self._project, image),
    ]

    if dir_mapping:
      for host_dir, docker_dir in dir_mapping:
        args.extend(['--dir-map', host_dir, docker_dir])

    if cmd_args:
      args.append('--')
      args += cmd_args

    self.m.python(
        step_name or 'docker run',
        self.resource('docker_run.py'),
        args=args, **kwargs)

  def __call__(self, *args, **kwargs):
    """Executes specified docker command.

    Please make sure to use api.docker.login method before if specified command
    requires authentication.

    Args:
      args: arguments passed to the 'docker' command including subcommand name,
          e.g. api.docker('push', 'my_image:latest').
      kwargs: arguments passed down to api.step module.
    """
    cmd = ['docker']
    if '--config' not in args and self._config_file:
      cmd += ['--config', self._config_file]
    step_name = kwargs.pop('step_name', 'docker %s' % args[0])
    return self.m.step(step_name, cmd + list(args), **kwargs)
