| #!/usr/bin/python |
| # |
| # Copyright 2014 Google Inc. All Rights Reserved. |
| |
| import argparse |
| import os |
| import re |
| import shutil |
| import subprocess |
| import sys |
| import zipfile |
| |
| |
| parser = argparse.ArgumentParser( |
| description=('Update prebuilt android support libraries')) |
| 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) |
| |
| |
| supportZipRE = re.compile(r'^sdk-repo-linux-support-.*\.zip$') |
| supportZipFile = None |
| for fname in listing: |
| if supportZipRE.match(fname): |
| supportZipFile = fname |
| break |
| if not supportZipFile: |
| src = 'directory' if args.localDir else 'build' |
| print >> sys.stderr, "FAIL: The specified %s contains no support library ZIP" % src |
| sys.exit(1) |
| |
| |
| try: |
| FetchFile(supportZipFile, supportZipFile) |
| except: |
| print >> sys.stderr, "FAIL: Unable to fetch %s" % supportZipFile |
| sys.exit(1) |
| |
| |
| try: # make sure we delete the downloaded ZIP |
| SUPPORT_LIBS = [ |
| ('support/v4', 'v4'), |
| ('support/v7/appcompat', 'appcompat'), |
| ('support/v7/cardview', 'cardview'), |
| ('support/v7/gridlayout', 'gridlayout'), |
| ('support/v7/mediarouter', 'mediarouter'), |
| ('support/v7/recyclerview', 'recyclerview'), |
| ('support/v7/palette', 'palette'), |
| ('support/v13', 'v13'), |
| ('support/v17/leanback', 'leanback'), |
| ('support/multidex/library', 'multidex'), |
| ] |
| |
| with zipfile.ZipFile(supportZipFile) as supportZip: |
| # update each support library |
| for libEntry in SUPPORT_LIBS: |
| # clean out the existing prebuilt |
| buildDotGradle = os.path.join(libEntry[1], 'build.gradle') |
| hadBuildDotGradle = False |
| if os.path.exists(libEntry[1]) and os.path.isdir(libEntry[1]): |
| hadBuildDotGradle = os.path.isfile(buildDotGradle) |
| subprocess.check_call(['git', 'rm', '-rf', libEntry[1]]) |
| |
| # extract the new version of the library |
| libZipDir = libEntry[0] + '/' |
| libSrcZipDir = libEntry[0] + '/src/' |
| |
| for fname in supportZip.namelist(): |
| if (fname[-1] != '/' |
| and fname.startswith(libZipDir) |
| and not fname.startswith(libSrcZipDir)): |
| relativePath = fname[len(libZipDir):] |
| subdirs = os.path.join(libEntry[1], os.path.dirname(relativePath)) |
| if not os.path.exists(subdirs): |
| os.makedirs(subdirs) |
| with supportZip.open(fname, 'r') as infile: |
| with open(os.path.join(libEntry[1], relativePath), 'w+') as outfile: |
| shutil.copyfileobj(infile, outfile) |
| |
| subprocess.check_call(['git', 'add', libEntry[1]]) |
| |
| # bring back any pre-existing build.gradle |
| if hadBuildDotGradle: |
| subprocess.check_call(['git', 'checkout', 'HEAD', buildDotGradle]) |
| |
| if not args.no_git: |
| # commit all changes |
| if not args.localDir: |
| # gather useful info |
| buildInfo = dict( |
| buildURL = buildURL, |
| buildId = args.buildId, |
| branch = branch, |
| supportZipFile = supportZipFile, |
| ) |
| msg = """Import prebuilt android support libs build {buildId} |
| |
| {buildURL}/{supportZipFile} |
| """.format(**buildInfo) |
| else: |
| msg = "DO NOT SUBMIT Import locally built android support libs from %s" % args.localDir |
| |
| subprocess.check_call(['git', 'commit', '-m', msg]) |
| |
| print 'Update successful.' |
| 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!!!" |