Add a script for building desugar_jdk_libs

Bug: 134732760
Change-Id: Ib9f2a1eb9970e00b6c2ee58aa16b755ea590b886
diff --git a/tools/archive.py b/tools/archive.py
index e6b9b37..15b0d23 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -112,8 +112,6 @@
   if not utils.is_bot() and not options.dry_run:
     raise Exception('You are not a bot, don\'t archive builds. '
       + 'Use --dry-run to test locally')
-  if options.dry_run_output and not options.dry_run:
-    raise Exception('Option --dry-run-output require --dry-run.')
   if (options.dry_run_output and
       (not os.path.exists(options.dry_run_output) or
        not os.path.isdir(options.dry_run_output))):
@@ -210,7 +208,7 @@
         print('File available at: %s' % GetUrl(version, file_name, is_master))
       if file == utils.R8_JAR:
         # Upload R8 to a maven compatible location.
-        maven_dst = GetUploadDestination(utils.get_maven_path(version),
+        maven_dst = GetUploadDestination(utils.get_maven_path('r8', version),
                                          'r8-%s.jar' % version, is_master)
         if options.dry_run:
           print('Dry run, not actually creating maven repo')
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
new file mode 100755
index 0000000..6edbd98
--- /dev/null
+++ b/tools/archive_desugar_jdk_libs.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This script is designed to run on a buildbot to build from the source
+# of https://github.com/google/desugar_jdk_libs and publish to the
+# r8-release Cloud Storage Bucket.
+#
+# These files are uploaded:
+#
+#   raw/desugar_jdk_libs/<VERSION>/desugar_jdk_libs.jar
+#   raw/desugar_jdk_libs/<VERSION>/desugar_jdk_libs.zip
+#   raw/com/android/tools/desugar_jdk_libs/<VERSION>/desugar_jdk_libs-<VERSION>.jar
+#
+# The first two are the raw jar file and the maven compatible zip file. The
+# third is the raw jar file placed and named so that the URL
+# http://storage.googleapis.com/r8-releases/raw can be treated as a maven
+# repository to fetch the artifact com.android.tools:desugar_jdk_libs:1.0.0
+
+import archive
+import git_utils
+import optparse
+import os
+import re
+import shutil
+import subprocess
+import sys
+import utils
+
+VERSION_FILE = 'VERSION.txt'
+LIBRARY_NAME = 'desugar_jdk_libs'
+
+def ParseOptions(argv):
+  result = optparse.OptionParser()
+  result.add_option('--dry-run', '--dry_run',
+      help='Running on bot, use third_party dependency.',
+      default=False,
+      action='store_true')
+  result.add_option('--dry-run-output', '--dry_run_output',
+      help='Output directory for dry run.',
+      type="string", action="store")
+  result.add_option('--github-account', '--github_account',
+      help='GitHub account to clone from.',
+      default="google",
+      type="string", action="store")
+  (options, args) = result.parse_args(argv)
+  return (options, args)
+
+
+def GetVersion():
+  with open(VERSION_FILE, 'r') as version_file:
+    lines = version_file.readlines()
+    if len(lines) != 1:
+      raise Exception('Version file '
+          + VERSION_FILE + ' is expected to have exactly one line')
+    version = lines[0].strip()
+    reg = re.compile('^([0-9]+)\\.([0-9]+)\\.([0-9]+)$')
+    if not reg.match(version):
+      raise Exception('Invalid version \''
+            + version
+            + '\' in version file '
+            + VERSION_FILE)
+    return version
+
+
+def Upload(options, file_name, storage_path, destination, is_master):
+  print('Uploading %s to %s' % (file_name, destination))
+  if options.dry_run:
+    if options.dry_run_output:
+      dry_run_destination = \
+          os.path.join(options.dry_run_output, os.path.basename(file_name))
+      print('Dry run, not actually uploading. Copying to '
+        + dry_run_destination)
+      shutil.copyfile(file_name, dry_run_destination)
+    else:
+      print('Dry run, not actually uploading')
+  else:
+    utils.upload_file_to_cloud_storage(file_name, destination)
+    print('File available at: %s' %
+        destination.replace('gs://', 'http://storage.googleapis.com/', 1))
+
+
+def Main(argv):
+  (options, args) = ParseOptions(argv)
+  if (len(args) > 0):
+    raise Exception('Unsupported arguments')
+  if not utils.is_bot() and not options.dry_run:
+    raise Exception('You are not a bot, don\'t archive builds. '
+        + 'Use --dry-run to test locally')
+  if (options.dry_run_output and
+      (not os.path.exists(options.dry_run_output) or
+       not os.path.isdir(options.dry_run_output))):
+    raise Exception(options.dry_run_output
+        + ' does not exist or is not a directory')
+
+  if utils.is_bot():
+    archive.SetRLimitToMax()
+
+  # Make sure bazel is extracted in third_party.
+  utils.DownloadFromGoogleCloudStorage(utils.BAZEL_SHA_FILE)
+
+  # Only handling versioned desugar_jdk_libs.
+  is_master = False
+
+  with utils.TempDir() as checkout_dir:
+    git_utils.GitClone(
+      'https://github.com/'
+          + options.github_account + '/' + LIBRARY_NAME, checkout_dir)
+    with utils.ChangedWorkingDirectory(checkout_dir):
+      version = GetVersion()
+
+      destination = archive.GetVersionDestination(
+          'gs://', LIBRARY_NAME + '/' + version, is_master)
+      if utils.cloud_storage_exists(destination) and not options.dry_run:
+        raise Exception(
+            'Target archive directory %s already exists' % destination)
+
+      bazel = os.path.join(utils.BAZEL_TOOL, 'lib', 'bazel', 'bin', 'bazel')
+      cmd = [bazel, 'build', 'maven_release']
+      utils.PrintCmd(cmd)
+      subprocess.check_call(cmd)
+      cmd = [bazel, 'shutdown']
+      utils.PrintCmd(cmd)
+      subprocess.check_call(cmd)
+
+      # Locate the library jar and the maven zip with the jar from the
+      # bazel build.
+      library_jar = os.path.join(
+          'bazel-bin', 'src', 'share', 'classes', 'java', 'libjava.jar')
+      maven_zip = os.path.join('bazel-bin', LIBRARY_NAME +'.zip')
+
+      storage_path = LIBRARY_NAME + '/' + version
+      # Upload the jar file with the library.
+      destination = archive.GetUploadDestination(
+          storage_path, LIBRARY_NAME + '.jar', is_master)
+      Upload(options, library_jar, storage_path, destination, is_master)
+
+      # Upload the maven zip file with the library.
+      destination = archive.GetUploadDestination(
+          storage_path, LIBRARY_NAME + '.zip', is_master)
+      Upload(options, maven_zip, storage_path, destination, is_master)
+
+      # Upload the jar file for accessing GCS as a maven repro.
+      maven_destination = archive.GetUploadDestination(
+          utils.get_maven_path('desugar_jdk_libs', version),
+          'desugar_jdk_libs-%s.jar' % version,
+          is_master)
+      if options.dry_run:
+        print('Dry run, not actually creating maven repo')
+      else:
+        utils.upload_file_to_cloud_storage(library_jar, maven_destination)
+        print('Maven repo root available at: %s' % archive.GetMavenUrl(is_master))
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/tools/create_maven_release.py b/tools/create_maven_release.py
index aa4c3f8..4eb931e 100755
--- a/tools/create_maven_release.py
+++ b/tools/create_maven_release.py
@@ -232,7 +232,7 @@
   # Create directory structure for this version.
   version = determine_version()
   with utils.TempDir() as tmp_dir:
-    version_dir = join(tmp_dir, utils.get_maven_path(version))
+    version_dir = join(tmp_dir, utils.get_maven_path('r8', version))
     makedirs(version_dir)
     # Write the pom file.
     pom_file = join(version_dir, 'r8-' + version + '.pom')
diff --git a/tools/git_utils.py b/tools/git_utils.py
new file mode 100644
index 0000000..bd1694e
--- /dev/null
+++ b/tools/git_utils.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import utils
+import subprocess
+
+def GitClone(url, checkout_dir):
+  cmd = ['git', 'clone', url, checkout_dir]
+  utils.PrintCmd(cmd)
+  return subprocess.check_call(cmd)
+
+def GetHeadRevision(checkout_dir):
+  cmd = ['git', 'rev-parse', 'HEAD']
+  utils.PrintCmd(cmd)
+  with ChangedWorkingDirectory(checkout_dir):
+    return subprocess.check_output(cmd).strip()
diff --git a/tools/utils.py b/tools/utils.py
index 7931c52..5305272 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -78,6 +78,8 @@
 OPENSOURCE_APPS_SHA_FILE = os.path.join(
     THIRD_PARTY, 'opensource_apps.tar.gz.sha1')
 OPENSOURCE_APPS_FOLDER = os.path.join(THIRD_PARTY, 'opensource_apps')
+BAZEL_SHA_FILE = os.path.join(THIRD_PARTY, 'bazel.tar.gz.sha1')
+BAZEL_TOOL = os.path.join(THIRD_PARTY, 'bazel')
 
 ANDROID_HOME_ENVIROMENT_NAME = "ANDROID_HOME"
 ANDROID_TOOLS_VERSION_ENVIRONMENT_NAME = "ANDROID_TOOLS_VERSION"
@@ -471,8 +473,8 @@
 
   return result
 
-def get_maven_path(version):
-  return os.path.join('com', 'android', 'tools', 'r8', version)
+def get_maven_path(artifact, version):
+  return os.path.join('com', 'android', 'tools', artifact, version)
 
 def print_cfsegments(prefix, cf_files):
   for cf_file in cf_files: