| #!/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 build tools')) |
| parser.add_argument( |
| 'buildId', |
| type=int, |
| nargs='?', |
| help='Build server build ID') |
| parser.add_argument( |
| '--target', |
| default='sdk_phone_armv7-win_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) |
| |
| |
| buildToolsZipRE = re.compile(r'^sdk-repo-windows-build-tools-.*\.zip$') |
| buildToolsZipFile = None |
| for fname in listing: |
| if buildToolsZipRE.match(fname): |
| buildToolsZipFile = fname |
| break |
| if not buildToolsZipFile: |
| src = 'directory' if args.localDir else 'build' |
| print >> sys.stderr, "FAIL: The specified %s contains no platform ZIP" % src |
| sys.exit(1) |
| |
| try: |
| FetchFile(buildToolsZipFile, buildToolsZipFile) |
| except: |
| print >> sys.stderr, "FAIL: Unable to fetch %s" % buildToolsZipFile |
| sys.exit(1) |
| |
| |
| try: # make sure we delete the downloaded ZIP |
| BUILD_TOOLS_DIRS = [ |
| ('android-5.1/lib', 'lib'), |
| ('android-5.1/renderscript', 'renderscript'), |
| ] |
| |
| executableMap = {} |
| with zipfile.ZipFile(buildToolsZipFile) as buildToolsZip: |
| files = filter(lambda x: x.count('/') == 1 and not x[-1] == '/', buildToolsZip.namelist()) |
| for fileEntry in map(lambda x: (x, x[x.find('/')+1:]) , files): |
| executable = False |
| if os.path.exists(fileEntry[1]): |
| if os.path.isdir(fileEntry[1]): |
| subprocess.check_call(['git', 'rm', '-rf', fileEntry[1]]) |
| else: |
| executable = os.access(fileEntry[1], os.X_OK) |
| subprocess.check_call(['git', 'rm', fileEntry[1]]) |
| |
| with buildToolsZip.open(fileEntry[0], 'r') as infile: |
| with open(fileEntry[1], 'w+') as outfile: |
| shutil.copyfileobj(infile, outfile) |
| if executable: |
| subprocess.check_call(['chmod', '+x', fileEntry[1]]) |
| subprocess.check_call(['git', 'add', fileEntry[1]]) |
| |
| for dirEntry in BUILD_TOOLS_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 buildToolsZip.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 buildToolsZip.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 source.properties |
| subprocess.check_call(['sed', '-i', 's/Pkg.Revision=/\/\/Pkg.Revision=/', |
| 'source.properties']) |
| |
| subprocess.check_call(' '.join(['echo', '-e', |
| '"Archive.Os=LINUX\nPkg.Revision=22.0.0\nArchive.Arch=ANY"'] + |
| ['>>', 'source.properties']), shell=True) |
| |
| subprocess.check_call(['git', 'add', 'source.properties']) |
| |
| if not args.no_git: |
| # commit all changes |
| if not args.localDir: |
| # gather useful info |
| buildInfo = dict( |
| buildURL = buildURL, |
| buildId = args.buildId, |
| branch = branch, |
| buildToolsZipFile = buildToolsZipFile, |
| ) |
| msg = """Import L Build Tools from {branch} build {buildId} |
| |
| {buildURL}/{buildToolsZipFile} |
| |
| source.properties has been modified to make this appear as API 22 |
| """.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 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!!!" |