Migrate old update script to directly pull from build server

Change-Id: I3877efad1c4ceade9df7a13488b9ad960097dbd4
diff --git a/update_current.py b/update_current.py
new file mode 100755
index 0000000..db2675e
--- /dev/null
+++ b/update_current.py
@@ -0,0 +1,286 @@
+#!/usr/bin/python
+
+import os, sys, getopt, zipfile, re
+import argparse
+import subprocess
+from shutil import copyfile, rmtree
+from distutils.version import LooseVersion
+
+current_path = 'current'
+system_path = 'system_current'
+support_path = os.path.join(current_path, 'support')
+
+# See go/fetch_artifact
+FETCH_ARTIFACT = '/google/data/ro/projects/android/fetch_artifact'
+
+# Does not import support-v4, which is handled as a separate Android.mk (../support-v4) to
+# statically include dependencies. Similarly, the support-v13 module is imported as
+# support-v13-nodeps and then handled as a separate Android.mk (../support-v13) to statically
+# include dependencies.
+maven_to_make = {
+    'animated-vector-drawable':     ['android-support-animatedvectordrawable',      'graphics/drawable'],
+    'appcompat-v7':                 ['android-support-v7-appcompat-nodeps',         'v7/appcompat'],
+    'cardview-v7':                  ['android-support-v7-cardview',                 'v7/cardview'],
+    'customtabs':                   ['android-support-customtabs',                  'customtabs'],
+    'design':                       ['android-support-design',                      'design'],
+    'exifinterface':                ['android-support-exifinterface',               'exifinterface'],
+    'gridlayout-v7':                ['android-support-v7-gridlayout',               'v7/gridlayout'],
+    'leanback-v17':                 ['android-support-v17-leanback',                'v17/leanback'],
+    'mediarouter-v7':               ['android-support-v7-mediarouter',              'v7/mediarouter'],
+    'multidex':                     ['android-support-multidex',                    'multidex/library'],
+    'multidex-instrumentation':     ['android-support-multidex-instrumentation',    'multidex/instrumentation'],
+    'palette-v7':                   ['android-support-v7-palette',                  'v7/palette'],
+    'percent':                      ['android-support-percent',                     'percent'],
+    'preference-leanback-v17':      ['android-support-v17-preference-leanback',     'v17/preference-leanback'],
+    'preference-v14':               ['android-support-v14-preference',              'v14/preference'],
+    'preference-v7':                ['android-support-v7-preference',               'v7/preference'],
+    'recommendation':               ['android-support-recommendation',              'recommendation'],
+    'recyclerview-v7':              ['android-support-v7-recyclerview',             'v7/recyclerview'],
+    'support-annotations':          ['android-support-annotations',                 'annotations'],
+    'support-compat':               ['android-support-compat',                      'compat'],
+    'support-core-ui':              ['android-support-core-ui',                     'core-ui'],
+    'support-core-utils':           ['android-support-core-utils',                  'core-utils'],
+    'support-dynamic-animation':    ['android-support-dynamic-animation',           'dynamic-animation'],
+    'support-emoji':                ['android-support-emoji',                       'emoji'],
+    'support-emoji-appcompat':      ['android-support-emoji-appcompat',             'emoji-appcompat'],
+    'support-emoji-bundled':        ['android-support-emoji-bundled',               'emoji-bundled'],
+    'support-fragment':             ['android-support-fragment',                    'fragment'],
+    'support-media-compat':         ['android-support-media-compat',                'media-compat'],
+    'support-tv-provider':          ['android-support-tv-provider',                 'tv-provider'],
+    'support-v13':                  ['android-support-v13-nodeps',                  'v13'],
+    'support-vector-drawable':      ['android-support-vectordrawable',              'graphics/drawable'],
+    'transition':                   ['android-support-transition',                  'transition'],
+    'wear':                         ['android-support-wear',                        'wear']
+}
+
+# Always remove these files.
+blacklist_files = [
+    'annotations.zip',
+    'public.txt',
+    'R.txt',
+    'AndroidManifest.xml'
+]
+
+artifact_pattern = re.compile(r"^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d*)?)\.(jar|aar)$")
+
+
+def touch(fname, times=None):
+    with open(fname, 'a'):
+        os.utime(fname, times)
+
+
+def path(*path_parts):
+    return reduce((lambda x, y: os.path.join(x, y)), path_parts)
+
+
+def rm(path):
+    if os.path.isdir(path):
+        rmtree(path)
+    elif os.path.exists(path):
+        os.remove(path)
+
+
+def mv(src_path, dst_path):
+    rm(dst_path)
+    os.rename(src_path, dst_path)
+
+
+def transform_support(repoDir):
+    cwd = os.getcwd()
+
+    # Use a temporary working directory.
+    working_dir = os.path.join(cwd, 'support_tmp')
+    if os.path.exists(working_dir):
+        rmtree(working_dir)
+    os.mkdir(working_dir)
+
+    maven_lib_info = {}
+
+    for root, dirs, files in os.walk(repoDir):
+        for file in files:
+            matcher = artifact_pattern.match(file)
+            if matcher:
+                maven_lib_name = matcher.group(1)
+                maven_lib_vers = LooseVersion(matcher.group(2))
+
+                if maven_lib_name in maven_to_make:
+                    if maven_lib_name not in maven_lib_info \
+                            or maven_lib_vers > maven_lib_info[maven_lib_name][0]:
+                        maven_lib_info[maven_lib_name] = [maven_lib_vers, root, file]
+
+    for info in maven_lib_info.values():
+        transform_maven_lib(working_dir, info[1], info[2])
+
+    # Replace the old directory.
+    output_dir = os.path.join(cwd, support_path)
+    if os.path.exists(output_dir):
+        rmtree(output_dir)
+    os.rename(working_dir, output_dir)
+
+
+def transform_maven_lib(working_dir, root, file):
+    matcher = artifact_pattern.match(file)
+    maven_lib_name = matcher.group(1)
+    maven_lib_vers = matcher.group(2)
+    maven_lib_type = matcher.group(3)
+
+    make_lib_name = maven_to_make[maven_lib_name][0]
+    make_dir_name = maven_to_make[maven_lib_name][1]
+    artifact_file = os.path.join(root, file)
+    target_dir = os.path.join(working_dir, make_dir_name)
+    if not os.path.exists(target_dir):
+        os.makedirs(target_dir)
+
+    if maven_lib_type == "aar":
+        process_aar(artifact_file, target_dir, make_lib_name)
+    else:
+        target_file = os.path.join(target_dir, make_lib_name + ".jar")
+        os.rename(artifact_file, target_file)
+
+    print maven_lib_vers, ":", maven_lib_name, "->", make_lib_name
+
+
+def process_aar(artifact_file, target_dir, make_lib_name):
+    # Extract AAR file to target_dir.
+    with zipfile.ZipFile(artifact_file) as zip:
+        zip.extractall(target_dir)
+
+    # Rename classes.jar to match the make artifact
+    classes_jar = os.path.join(target_dir, "classes.jar")
+    if os.path.exists(classes_jar):
+        # If it has resources, it needs a libs dir.
+        res_dir = os.path.join(target_dir, "res")
+        if os.path.exists(res_dir) and os.listdir(res_dir):
+            libs_dir = os.path.join(target_dir, "libs")
+            if not os.path.exists(libs_dir):
+                os.mkdir(libs_dir)
+        else:
+            libs_dir = target_dir
+        target_jar = os.path.join(libs_dir, make_lib_name + ".jar")
+        os.rename(classes_jar, target_jar)
+
+    # Remove or preserve empty dirs.
+    for root, dirs, files in os.walk(target_dir):
+        for dir in dirs:
+            dir_path = os.path.join(root, dir)
+            if not os.listdir(dir_path):
+                os.rmdir(dir_path)
+
+    # Remove top-level cruft.
+    for file in blacklist_files:
+        file_path = os.path.join(target_dir, file)
+        if os.path.exists(file_path):
+            os.remove(file_path)
+
+def fetch_artifact(target, buildId, artifact_path):
+    print 'Fetching %s from %s...' % (artifact_path, target)
+    fetchCmd = [FETCH_ARTIFACT, '--bid', str(buildId), '--target', target, artifact_path]
+    try:
+        subprocess.check_output(fetchCmd, stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError:
+        print >> sys.stderr, 'FAIL: Unable to retrieve %s artifact for build ID %d' % (artifact_path, buildId)
+        return None
+    return artifact_path
+
+
+def update_support(target, buildId):
+    platform = 'darwin' if 'mac' in target else 'linux'
+    artifact_path = fetch_artifact(target, buildId, 'sdk-repo-%s-m2repository-%s.zip' % (platform, buildId))
+    if not artifact_path:
+        return
+
+    # Unzip the repo archive into a separate directory.
+    repoDir = os.path.basename(artifact_path)[:-4]
+    with zipfile.ZipFile(artifact_path) as zipFile:
+        zipFile.extractall(repoDir)
+
+    # Transform the repo archive into a Makefile-compatible format.
+    transform_support(repoDir)
+
+
+def extract_to(zip_file, paths, filename, parent_path):
+    zip_path = filter(lambda path: filename in path, paths)[0]
+    src_path = zip_file.extract(zip_path)
+    dst_path = path(parent_path, filename)
+    mv(src_path, dst_path)
+
+
+def update_sdk_repo(target, buildId):
+    platform = 'darwin' if 'mac' in target else 'linux'
+    artifact_path = fetch_artifact(target, buildId, 'sdk-repo-%s-platforms-%s.zip' % (platform, buildId))
+    if not artifact_path:
+        return
+
+    with zipfile.ZipFile(artifact_path) as zipFile:
+        paths = zipFile.namelist()
+
+        extract_to(zipFile, paths, 'android.jar', current_path)
+        extract_to(zipFile, paths, 'uiautomator.jar', current_path)
+        extract_to(zipFile, paths, 'framework.aidl', current_path)
+
+        # Unclear if this is actually necessary.
+        extract_to(zipFile, paths, 'framework.aidl', system_path)
+
+
+def update_system(target, buildId):
+    artifact_path = fetch_artifact(target, buildId, 'android_system.jar')
+    if not artifact_path:
+        return
+
+    mv(artifact_path, path(system_path, 'android.jar'))
+
+
+parser = argparse.ArgumentParser(
+    description=('Update current prebuilts'))
+parser.add_argument(
+    'buildId',
+    type=int,
+    nargs='?',
+    help='Build server build ID')
+parser.add_argument(
+    '--support',
+    default='support_library',
+    help='Specifies the build server target from which the m2repository ZIP is obtained')
+parser.add_argument(
+    '--sdk_repo',
+    default='sdk_phone_armv7-sdk_mac',
+    help='Specifies the build server target from which the platforms ZIP is obtained')
+parser.add_argument(
+    '--system',
+    default='sdk_phone_armv7-sdk_mac',
+    help='Specifies the build server target from which the android_system JAR is obtained')
+args = parser.parse_args()
+if not args.buildId:
+    parser.error("You must specify a build ID")
+    sys.exit(1)
+
+try:
+    # Make sure we don't overwrite any pending changes.
+    subprocess.check_call(['git', 'diff', '--quiet', '--', '**'])
+    subprocess.check_call(['git', 'diff', '--quiet', '--cached', '--', '**'])
+except subprocess.CalledProcessError:
+    print >> sys.stderr, "FAIL: There are uncommitted changes here; please revert or stash"
+    sys.exit(1)
+
+try:
+    update_support(args.support, args.buildId)
+    update_sdk_repo(args.sdk_repo, args.buildId)
+    update_system(args.system, args.buildId)
+
+    # Commit all changes.
+    subprocess.check_call(['git', 'add', current_path])
+    subprocess.check_call(['git', 'add', system_path])
+    msg = "Import support libs from build %s" % args.buildId
+    subprocess.check_call(['git', 'commit', '-m', msg])
+    print 'Be sure to upload this manually to gerrit.'
+
+finally:
+    # Revert all stray files, including the downloaded zip.
+    try:
+        with open(os.devnull, 'w') as bitbucket:
+            subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
+            subprocess.check_call(
+                ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!'], stdout=bitbucket)
+            subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
+    except subprocess.CalledProcessError:
+        print >> sys.stderr, "ERROR: Failed cleaning up, manual cleanup required!!!"
\ No newline at end of file