#!/usr/bin/python # # Copyright 2014 Google Inc. All Rights Reserved. import argparse import os import re import shutil import subprocess import sys import zipfile ANDROID_SYSTEM_JAR = "android_system.jar" ANDROID_JAR = "android.jar" parser = argparse.ArgumentParser( description=('Update prebuilt android SDK')) parser.add_argument( 'buildId', type=int, nargs='?', help='Build server build ID') parser.add_argument( '--target', default='sdk', help='Download from the specified build server target') parser.add_argument( '--from-local-dir', dest='localDir', help='Copy prebuilts from local directory instead of buildserver') parser.add_argument( '--no-git', action='store_true', help='Do not create a git commit for the import') args = parser.parse_args() if not args.buildId and not args.localDir: parser.error("you must specify either a build ID or --from-local-dir") sys.exit(1) if not args.no_git: # Make sure we don't overwrite any pending changes try: 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) def GetSSOCmdline(url): return ['sso_client', '--location', '--request_timeout', '90', '--url', url] def SSOFetch(url): return subprocess.check_output(GetSSOCmdline(url), stderr=subprocess.STDOUT) def FetchFile(srcFile, dstFile): if not args.localDir: fileURL = buildURL + '/' + srcFile subprocess.check_call(' '.join(GetSSOCmdline(fileURL) + ['>', dstFile]), shell=True) else: shutil.copyfile(os.path.join(args.localDir, srcFile), dstFile) if not args.localDir: # to start, find the build server branch we're downloading from try: branch = SSOFetch("http://android-build/buildbot-update?op=GET-BRANCH&bid=%d" % args.buildId) except subprocess.CalledProcessError: print >> sys.stderr, "FAIL: Unable to retrieve branch for build ID %d" % args.buildId sys.exit(1) buildURL = "http://android-build/builds/%s-linux-%s/%d" % (branch, args.target, args.buildId) # fetch the list build artifacts try: listingText = SSOFetch(buildURL + "?output=text") except subprocess.CalledProcessError: print >> sys.stderr, "FAIL: Unable to retrieve listing for build ID %d" % args.buildId sys.exit(1) listing = listingText.strip().split('\n') else: listing = os.listdir(args.localDir) platformZipRE = re.compile(r'^sdk-repo-linux-platforms-.*\.zip$') platformZipFile = None for fname in listing: if platformZipRE.match(fname): platformZipFile = fname break if not platformZipFile: src = 'directory' if args.localDir else 'build' print >> sys.stderr, "FAIL: The specified %s contains no platform ZIP" % src sys.exit(1) try: FetchFile(platformZipFile, platformZipFile) FetchFile(ANDROID_SYSTEM_JAR, ANDROID_JAR) except: print >> sys.stderr, "FAIL: Unable to fetch %s" % platformZipFile sys.exit(1) try: # make sure we delete the downloaded ZIP PLATFORM_DIRS = [ ('android-5.0/data', 'data'), ('android-5.0/skins', 'skins'), ('android-5.0/templates', 'templates'), ] PLATFORM_FILES = [ ('android-5.0/build.prop', 'build.prop'), ('android-5.0/framework.aidl', 'framework.aidl'), ('android-5.0/sdk.properties', 'sdk.properties'), ('android-5.0/source.properties', 'source.properties'), ('android-5.0/uiautomator.jar', 'uiautomator.jar'), ] subprocess.check_call(['git', 'add', ANDROID_JAR]) with zipfile.ZipFile(platformZipFile) as platformZip: for fileEntry in PLATFORM_FILES: if os.path.exists(fileEntry[1]): if os.path.isdir(fileEntry[1]): subprocess.check_call(['git', 'rm', '-rf', fileEntry[1]]) else: subprocess.check_call(['git', 'rm', fileEntry[1]]) with platformZip.open(fileEntry[0], 'r') as infile: with open(fileEntry[1], 'w+') as outfile: shutil.copyfileobj(infile, outfile) subprocess.check_call(['git', 'add', fileEntry[1]]) for dirEntry in PLATFORM_DIRS: if os.path.exists(dirEntry[1]): if os.path.isdir(dirEntry[1]): subprocess.check_call(['git', 'rm', '-rf', dirEntry[1]]) else: subprocess.check_call(['git', 'rm', dirEntry[1]]) # extract the new version of the directory fileZipDir = dirEntry[0] + '/' for fname in platformZip.namelist(): if (fname[-1] != '/' and fname.startswith(dirEntry[0])): relativePath = fname[len(fileZipDir):] subdirs = os.path.join(dirEntry[1], os.path.dirname(relativePath)) if not os.path.exists(subdirs): os.makedirs(subdirs) with platformZip.open(fname, 'r') as infile: with open(os.path.join(dirEntry[1], relativePath), 'w+') as outfile: shutil.copyfileobj(infile, outfile) subprocess.check_call(['git', 'add', dirEntry[1]]) # modify the build.prop and source.properties subprocess.check_call(['sed', '-i', 's/AndroidVersion.ApiLevel=20/AndroidVersion.ApiLevel=21/', 'source.properties']) subprocess.check_call(['sed', '-i', '/AndroidVersion.CodeName=L/d', 'source.properties']) subprocess.check_call(['sed', '-i', 's/ro.build.version.sdk=20/ro.build.version.sdk=21/', 'build.prop']) subprocess.check_call(['sed', '-i', 's/ro.build.version.codename=L/ro.build.version.codename=REL/', 'build.prop']) subprocess.check_call(['git', 'add', 'source.properties']) subprocess.check_call(['git', 'add', 'build.prop']) if not args.no_git: # commit all changes if not args.localDir: # gather useful info buildInfo = dict( buildURL = buildURL, buildId = args.buildId, branch = branch, platformZipFile = platformZipFile, androidJar = ANDROID_SYSTEM_JAR, ) msg = """Import L SDK from {branch} build {buildId} {buildURL}/{platformZipFile} {buildURL}/{androidJar} build.prop & source.properties have been modified to make this appear as API 21 android_system.jar has been submitted as android.jar """.format(**buildInfo) else: msg = "DO NOT SUBMIT Import locally built android platform from %s" % args.localDir subprocess.check_call(['git', 'commit', '-m', msg]) print 'Update the support library as well.' if args.target == 'sdk': print '\tcd support && ./update_support_libs.py %s' % (args.buildId) else: print '\tcd support && ./update_support_libs.py --target %s %s' % (args.target, args.buildId) if not args.localDir: 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!!!"