#!/usr/bin/env python

# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS.  All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.

"""Script for publishing WebRTC AAR on Bintray.

Set BINTRAY_USER and BINTRAY_API_KEY environment variables before running
this script for authentication.
"""

import argparse
import json
import logging
import os
import re
import shutil
import subprocess
import sys
import tempfile
import time


SCRIPT_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
CHECKOUT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))

sys.path.append(os.path.join(CHECKOUT_ROOT, 'third_party'))
import requests
import jinja2

sys.path.append(os.path.join(CHECKOUT_ROOT, 'tools_webrtc'))
from android.build_aar import BuildAar


ARCHS = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
MAVEN_REPOSITORY = 'https://google.bintray.com/webrtc'
API = 'https://api.bintray.com'
PACKAGE_PATH = 'google/webrtc/google-webrtc'
CONTENT_API = API + '/content/' + PACKAGE_PATH
PACKAGES_API = API + '/packages/' + PACKAGE_PATH
GROUP_ID = 'org/webrtc'
ARTIFACT_ID = 'google-webrtc'
COMMIT_POSITION_REGEX = r'^Cr-Commit-Position: refs/heads/master@{#(\d+)}$'
API_TIMEOUT_SECONDS = 10.0
UPLOAD_TRIES = 3
# The sleep time is increased exponentially.
UPLOAD_RETRY_BASE_SLEEP_SECONDS = 2.0
GRADLEW_BIN = os.path.join(CHECKOUT_ROOT,
                           'examples/androidtests/third_party/gradle/gradlew')
ADB_BIN = os.path.join(CHECKOUT_ROOT,
                       'third_party/android_tools/sdk/platform-tools/adb')
AAR_PROJECT_DIR = os.path.join(CHECKOUT_ROOT, 'examples/aarproject')
AAR_PROJECT_GRADLE = os.path.join(AAR_PROJECT_DIR, 'build.gradle')
AAR_PROJECT_APP_GRADLE = os.path.join(AAR_PROJECT_DIR, 'app', 'build.gradle')
AAR_PROJECT_DEPENDENCY = "implementation 'org.webrtc:google-webrtc:1.0.+'"
AAR_PROJECT_VERSION_DEPENDENCY = "implementation 'org.webrtc:google-webrtc:%s'"


def _ParseArgs():
  parser = argparse.ArgumentParser(description='Releases WebRTC on Bintray.')
  parser.add_argument('--use-goma', action='store_true', default=False,
      help='Use goma.')
  parser.add_argument('--skip-tests', action='store_true', default=False,
      help='Skips running the tests.')
  parser.add_argument('--publish', action='store_true', default=False,
      help='Automatically publishes the library if the tests pass.')
  parser.add_argument('--build-dir', default=None,
      help='Temporary directory to store the build files. If not specified, '
           'a new directory will be created.')
  parser.add_argument('--verbose', action='store_true', default=False,
      help='Debug logging.')
  return parser.parse_args()


def _GetCommitHash():
  commit_hash = subprocess.check_output(
    ['git', 'rev-parse', 'HEAD'], cwd=CHECKOUT_ROOT).strip()
  return commit_hash


def _GetCommitPos():
  commit_message = subprocess.check_output(
      ['git', 'rev-list', '--format=%B', '--max-count=1', 'HEAD'],
      cwd=CHECKOUT_ROOT)
  commit_pos_match = re.search(
      COMMIT_POSITION_REGEX, commit_message, re.MULTILINE)
  if not commit_pos_match:
    raise Exception('Commit position not found in the commit message: %s'
                      % commit_message)
  return commit_pos_match.group(1)


def _UploadFile(user, password, filename, version, target_file):
# URL is of format:
  # <repository_api>/<version>/<group_id>/<artifact_id>/<version>/<target_file>
  # Example:
  # https://api.bintray.com/content/google/webrtc/google-webrtc/1.0.19742/org/webrtc/google-webrtc/1.0.19742/google-webrtc-1.0.19742.aar

  target_dir = version + '/' + GROUP_ID + '/' + ARTIFACT_ID + '/' + version
  target_path = target_dir + '/' + target_file
  url = CONTENT_API + '/' + target_path

  logging.info('Uploading %s to %s', filename, url)
  with open(filename) as fh:
    file_data = fh.read()

  for attempt in xrange(UPLOAD_TRIES):
    try:
      response = requests.put(url, data=file_data, auth=(user, password),
                              timeout=API_TIMEOUT_SECONDS)
      break
    except requests.exceptions.Timeout as e:
      logging.warning('Timeout while uploading: %s', e)
      time.sleep(UPLOAD_RETRY_BASE_SLEEP_SECONDS ** attempt)
  else:
    raise Exception('Failed to upload %s' % filename)

  if not response.ok:
    raise Exception('Failed to upload %s. Response: %s' % (filename, response))
  logging.info('Uploaded %s: %s', filename, response)


def _GeneratePom(target_file, version, commit):
  env = jinja2.Environment(
    loader=jinja2.PackageLoader('release_aar'),
  )
  template = env.get_template('pom.jinja')
  pom = template.render(version=version, commit=commit)
  with open(target_file, 'w') as fh:
    fh.write(pom)


def _TestAAR(tmp_dir, username, password, version):
  """Runs AppRTCMobile tests using the AAR. Returns true if the tests pass."""
  logging.info('Testing library.')
  env = jinja2.Environment(
    loader=jinja2.PackageLoader('release_aar'),
  )

  gradle_backup = os.path.join(tmp_dir, 'build.gradle.backup')
  app_gradle_backup = os.path.join(tmp_dir, 'app-build.gradle.backup')

  # Make backup copies of the project files before modifying them.
  shutil.copy2(AAR_PROJECT_GRADLE, gradle_backup)
  shutil.copy2(AAR_PROJECT_APP_GRADLE, app_gradle_backup)

  try:
    maven_repository_template = env.get_template('maven-repository.jinja')
    maven_repository = maven_repository_template.render(
        url=MAVEN_REPOSITORY, username=username, password=password)

    # Append Maven repository to build file to download unpublished files.
    with open(AAR_PROJECT_GRADLE, 'a') as gradle_file:
      gradle_file.write(maven_repository)

    # Read app build file.
    with open(AAR_PROJECT_APP_GRADLE, 'r') as gradle_app_file:
      gradle_app = gradle_app_file.read()

    if AAR_PROJECT_DEPENDENCY not in gradle_app:
      raise Exception(
          '%s not found in the build file.' % AAR_PROJECT_DEPENDENCY)
    # Set version to the version to be tested.
    target_dependency = AAR_PROJECT_VERSION_DEPENDENCY % version
    gradle_app = gradle_app.replace(AAR_PROJECT_DEPENDENCY, target_dependency)

    # Write back.
    with open(AAR_PROJECT_APP_GRADLE, 'w') as gradle_app_file:
      gradle_app_file.write(gradle_app)

    # Uninstall any existing version of AppRTCMobile.
    logging.info('Uninstalling previous AppRTCMobile versions. It is okay for '
                 'these commands to fail if AppRTCMobile is not installed.')
    subprocess.call([ADB_BIN, 'uninstall', 'org.appspot.apprtc'])
    subprocess.call([ADB_BIN, 'uninstall', 'org.appspot.apprtc.test'])

    # Run tests.
    try:
      # First clean the project.
      subprocess.check_call([GRADLEW_BIN, 'clean'], cwd=AAR_PROJECT_DIR)
      # Then run the tests.
      subprocess.check_call([GRADLEW_BIN, 'connectedDebugAndroidTest'],
                            cwd=AAR_PROJECT_DIR)
    except subprocess.CalledProcessError:
      logging.exception('Test failure.')
      return False  # Clean or tests failed

    return True  # Tests pass
  finally:
    # Restore backups.
    shutil.copy2(gradle_backup, AAR_PROJECT_GRADLE)
    shutil.copy2(app_gradle_backup, AAR_PROJECT_APP_GRADLE)


def _PublishAAR(user, password, version, additional_args):
  args = {
    'publish_wait_for_secs': 0  # Publish asynchronously.
  }
  args.update(additional_args)

  url = CONTENT_API + '/' + version + '/publish'
  response = requests.post(url, data=json.dumps(args), auth=(user, password),
                           timeout=API_TIMEOUT_SECONDS)

  if not response.ok:
    raise Exception('Failed to publish. Response: %s' % response)


def _DeleteUnpublishedVersion(user, password, version):
  url = PACKAGES_API + '/versions/' + version
  response = requests.get(url, auth=(user, password),
                          timeout=API_TIMEOUT_SECONDS)
  if not response.ok:
    raise Exception('Failed to get version info. Response: %s' % response)

  version_info = json.loads(response.content)
  if version_info['published']:
    logging.info('Version has already been published, not deleting.')
    return

  logging.info('Deleting unpublished version.')
  response = requests.delete(url, auth=(user, password),
                             timeout=API_TIMEOUT_SECONDS)
  if not response.ok:
    raise Exception('Failed to delete version. Response: %s' % response)


def ReleaseAar(use_goma, skip_tests, publish, build_dir):
  version = '1.0.' + _GetCommitPos()
  commit = _GetCommitHash()
  logging.info('Releasing AAR version %s with hash %s', version, commit)

  user = os.environ.get('BINTRAY_USER', None)
  api_key = os.environ.get('BINTRAY_API_KEY', None)
  if not user or not api_key:
    raise Exception('Environment variables BINTRAY_USER and BINTRAY_API_KEY '
                    'must be defined.')

  # If build directory is not specified, create a temporary directory.
  use_tmp_dir = not build_dir
  if use_tmp_dir:
    build_dir = tempfile.mkdtemp()

  try:
    base_name = ARTIFACT_ID + '-' + version
    aar_file = os.path.join(build_dir, base_name + '.aar')
    third_party_licenses_file = os.path.join(build_dir, 'LICENSE.md')
    pom_file = os.path.join(build_dir, base_name + '.pom')

    logging.info('Building at %s', build_dir)
    BuildAar(ARCHS, aar_file,
             use_goma=use_goma,
             ext_build_dir=os.path.join(build_dir, 'aar-build'))
    _GeneratePom(pom_file, version, commit)

    _UploadFile(user, api_key, aar_file, version, base_name + '.aar')
    _UploadFile(user, api_key, third_party_licenses_file, version,
                'THIRD_PARTY_LICENSES.md')
    _UploadFile(user, api_key, pom_file, version, base_name + '.pom')

    tests_pass = skip_tests or _TestAAR(build_dir, user, api_key, version)
    if not tests_pass:
      logging.info('Discarding library.')
      _PublishAAR(user, api_key, version, {'discard': True})
      _DeleteUnpublishedVersion(user, api_key, version)
      raise Exception('Test failure. Discarded library.')

    if publish:
      logging.info('Publishing library.')
      _PublishAAR(user, api_key, version, {})
    else:
      logging.info('Note: The library has not not been published automatically.'
                   ' Please do so manually if desired.')
  finally:
    if use_tmp_dir:
      shutil.rmtree(build_dir, True)


def main():
  args = _ParseArgs()
  logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
  ReleaseAar(args.use_goma, args.skip_tests, args.publish, args.build_dir)


if __name__ == '__main__':
  sys.exit(main())
