#!/usr/bin/env vpython3
# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import errno
import logging
import os
import shutil
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
import devil_chromium  # pylint: disable=unused-import
from devil.utils import cmd_helper
from devil.utils import parallelizer


def _MakeDirsIfAbsent(path):
  try:
    os.makedirs(path)
  except OSError as err:
    if err.errno != errno.EEXIST or not os.path.isdir(path):
      raise


class MavenDownloader:
  '''
  Downloads and installs the requested artifacts from the Google Maven repo.
  The artifacts are expected to be specified in the format
  "group_id:artifact_id:version:file_type", as the default file type is JAR
  but most Android libraries are provided as AARs, which would otherwise fail
  downloading. See Install()
  '''

  # Remote repository to download the artifacts from. The support library and
  # Google Play service are only distributed there, but third party libraries
  # could use Maven Central or JCenter for example. The default Maven remote
  # is Maven Central.
  _REMOTE_REPO = 'https://maven.google.com'

  # Default Maven repository.
  _DEFAULT_REPO_PATH = os.path.join(
      os.path.expanduser('~'), '.m2', 'repository')

  def __init__(self, debug=False):
    self._repo_path = MavenDownloader._DEFAULT_REPO_PATH
    self._remote_url = MavenDownloader._REMOTE_REPO
    self._debug = debug

  def Install(self, target_repo, artifacts, include_poms=False):
    logging.info('Installing %d artifacts...', len(artifacts))
    downloaders = [_SingleArtifactDownloader(self, artifact, target_repo)
                   for artifact in artifacts]
    if self._debug:
      for downloader in downloaders:
        downloader.Run(include_poms)
    else:
      parallelizer.SyncParallelizer(downloaders).Run(include_poms)
    logging.info('%d artifacts installed to %s', len(artifacts), target_repo)

  @property
  def repo_path(self):
    return self._repo_path

  @property
  def remote_url(self):
    return self._remote_url

  @property
  def debug(self):
    return self._debug


class _SingleArtifactDownloader:
  '''Handles downloading and installing a single Maven artifact.'''

  _POM_FILE_TYPE = 'pom'

  def __init__(self, download_manager, artifact, target_repo):
    self._download_manager = download_manager
    self._artifact = artifact
    self._target_repo = target_repo

  def Run(self, include_pom=False):
    parts = self._artifact.split(':')
    if len(parts) != 4:
      raise Exception('Artifacts expected as '
                      '"group_id:artifact_id:version:file_type".')
    group_id, artifact_id, version, file_type = parts
    self._InstallArtifact(group_id, artifact_id, version, file_type)

    if include_pom and file_type != _SingleArtifactDownloader._POM_FILE_TYPE:
      self._InstallArtifact(group_id, artifact_id, version,
                            _SingleArtifactDownloader._POM_FILE_TYPE)

  def _InstallArtifact(self, group_id, artifact_id, version, file_type):
    logging.debug('Processing %s', self._artifact)

    download_relpath = self._DownloadArtifact(
        group_id, artifact_id, version, file_type)
    logging.debug('Downloaded.')

    install_path = self._ImportArtifact(download_relpath)
    logging.debug('Installed %s', os.path.relpath(install_path))

  def _DownloadArtifact(self, group_id, artifact_id, version, file_type):
    '''
    Downloads the specified artifact using maven, to its standard location, see
    MavenDownloader._DEFAULT_REPO_PATH.
    '''
    cmd = ['mvn',
           'org.apache.maven.plugins:maven-dependency-plugin:RELEASE:get',
           '-DremoteRepositories={}'.format(self._download_manager.remote_url),
           '-Dartifact={}:{}:{}:{}'.format(group_id, artifact_id, version,
                                           file_type)]

    stdout = None if self._download_manager.debug else open(os.devnull, 'wb')

    try:
      ret_code = cmd_helper.Call(cmd, stdout=stdout)
      if ret_code != 0:
        raise Exception('Command "{}" failed'.format(' '.join(cmd)))
    except OSError as e:
      if e.errno == errno.ENOENT:
        raise Exception('mvn command not found. Please install Maven.') from e
      raise

    return os.path.join(os.path.join(*group_id.split('.')),
                        artifact_id,
                        version,
                        '{}-{}.{}'.format(artifact_id, version, file_type))

  def _ImportArtifact(self, artifact_path):
    src_dir = os.path.join(self._download_manager.repo_path, artifact_path)
    dst_dir = os.path.join(self._target_repo, os.path.dirname(artifact_path))

    _MakeDirsIfAbsent(dst_dir)
    shutil.copy(src_dir, dst_dir)

    return dst_dir
