| #!/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!!!" |