#!/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_sdk/public/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())
