Chromium Code Reviews| Index: build/install_android_sdk_ndk.py |
| diff --git a/build/install_android_sdk_ndk.py b/build/install_android_sdk_ndk.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..ac410d2088dfa24f98767dbf1fef5af4116366c4 |
| --- /dev/null |
| +++ b/build/install_android_sdk_ndk.py |
| @@ -0,0 +1,197 @@ |
| +#!/usr/bin/python |
| +# |
| +# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| +"""A script to automatically install the android sdk and ndk.""" |
| + |
| +import optparse |
| +import os |
| +import re |
| +import shutil |
| +import subprocess |
| +import sys |
| +import tarfile |
| + |
| +SDK_CONFIG = {'varname': 'ANDROID_SDK_ROOT', |
| + 'default_dir': '/usr/local/google/android-sdk-linux', |
| + 'url': 'http://dl.google.com/android/android-sdk_r20-linux.tgz', |
| + 'tar_md5': 0x22a81cf1d4a951c62f71a8758290e9bb, |
| + 'version': 1} |
|
bulach
2012/07/17 11:27:20
nit: "version" here seems related to the package v
Isaac (away)
2012/07/18 09:45:05
Will fix.
|
| +SDK_TARGET_ID = 'android-15' |
| + |
| + |
| +# Do not change without updating the 64-bit linker! |
| +NDK_CONFIG = {'varname': 'ANDROID_NDK_ROOT', |
| + 'default_dir': '/usr/local/google/android-ndk-r7', |
| + 'url': ('http://dl.google.com/android/ndk' |
| + '/android-ndk-r7-linux-x86.tar.bz2'), |
| + 'tar_md5': 0xbf15e6b47bf50824c4b96849bf003ca3, |
| + 'version': 1} |
| +NDK_LINKER = 'arm-linux-androideabi-ld.e4df3e0a5bb640ccfa2f30ee67fe9b3146b152d6' |
| + |
| + |
| +def GetCmdOutput(cmd, shell=False): |
| + proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE) |
| + return proc.communicate()[0] |
| + |
| + |
| +def GetRoot(config): |
|
bulach
2012/07/17 11:27:20
nit: maybe clearer as "GetInstallPathForConfig". m
Isaac (away)
2012/07/18 09:45:05
OK will adjust
|
| + env_var_name = config['varname'] |
| + default_path = config['default_dir'] |
| + path = os.environ.get(env_var_name) |
| + if not path: |
| + raw_input('%s not set. Hit enter to use %s' % (env_var_name, |
|
bulach
2012/07/17 11:27:20
nit: since this is going to be used by bots, it'd
Isaac (away)
2012/07/17 16:35:30
If a user calls the script I want to confirm befor
John Grabowski
2012/07/17 18:38:15
Strongly agree. Raw input is bad form.
Isaac (away)
2012/07/18 09:45:05
I want to distinguish between an automated 'bot mo
John Grabowski
2012/07/18 20:48:43
No. No option. Just no raw input. If user doesn
|
| + default_path)) |
| + path = default_path |
| + base_dir = os.path.dirname(path) |
| + if not os.path.exists(base_dir): |
| + print '%s does not exist, creating...' % base_dir |
| + os.makedirs(base_dir, 0755) |
| + return path |
| + |
| + |
| +def VersionedInstall(root, version, installer, options): |
|
bulach
2012/07/17 11:27:20
nit: rather than root, perhaps install_dir would b
John Grabowski
2012/07/17 18:38:15
Looks like you're adding undocumented features tha
Isaac (away)
2012/07/18 09:45:05
Well, I'm happy to document it before landing. fo
John Grabowski
2012/07/18 20:48:43
You missed the point.
This is unnecessary complexi
|
| + version_filename = os.path.join(root, 'SCRIPT_VERSION') |
| + try: |
| + with open(version_filename) as f: |
| + if int(f.read()) == version: |
| + print 'Skipping %s (version is up to date).' % installer.__name__ |
| + return |
| + except IOError: |
|
bulach
2012/07/17 11:27:20
probably need ValueError as well for the int cast.
Isaac (away)
2012/07/17 16:35:30
IOError is expected because file might not exist.
|
| + pass |
| + |
| + if os.path.exists(root): |
| + print 'Removing %s for reinstall' % root |
| + shutil.rmtree(root) |
| + |
| + success = installer(root, options) |
| + |
| + if success: |
| + with open(version_filename, 'w') as f: |
| + f.write('%d' % version) |
| + |
| + |
| +def Download(base_dir, config, options): |
| + url = config['url'] |
| + md5 = config['tar_md5'] |
| + tar_filepath = os.path.join(base_dir, os.path.basename(url)) |
| + if not options.dry_run: |
| + subprocess.check_call(['wget', url, '-O', tar_filepath]) |
| + assert os.path.exists(tar_filepath) |
| + md5str = GetCmdOutput(['md5sum', tar_filepath]) |
| + assert md5 == int('0x' + md5str.split()[0], 16), 'md5 mismatch!' |
| + return tar_filepath |
| + |
| + |
| +def ExtractTgz(path, tar_filepath, options): |
| + base_dir = os.path.dirname(path) |
| + print 'extracting %s...' % tar_filepath |
| + if options.dry_run: |
| + if not os.path.exists(path): |
| + os.mkdir(path) |
| + return |
| + |
| + f = tarfile.open(tar_filepath) |
| + f.extractall(path=base_dir) |
| + extract_prefix = os.path.commonprefix(f.getnames()).split('/') |
| + f.close() |
| + extract_path = os.path.join(base_dir, extract_prefix[0]) |
| + if os.path.abspath(path) != os.path.abspath(extract_path): |
| + print 'Moving files from %s to %s' % (extract_path, path) |
| + os.rename(extract_path, path) |
| + os.remove(tar_filepath) |
| + |
| + |
| +def InstallSdk(sdk_root, options): |
| + if not os.path.exists(sdk_root): |
| + tar_filepath = Download(os.path.dirname(sdk_root), SDK_CONFIG, options) |
| + ExtractTgz(sdk_root, tar_filepath, options) |
| + android_bin = os.path.join(sdk_root, 'tools/android') |
| + |
| + def Android(args, stdin=None): |
|
bulach
2012/07/17 11:27:20
nit: remove the default value, there's only one ca
|
| + if options.dry_run: |
| + print 'android', args |
| + else: |
| + proc = subprocess.Popen([android_bin] + args, stdin=subprocess.PIPE) |
| + proc.communicate(stdin) |
| + |
| + print 'Getting available targets...' |
| + raw_targets = GetCmdOutput([android_bin, 'list', 'sdk', '--extended']) |
| + targets = re.findall('^id:[\w ]*"([-\w_]+)"$', raw_targets, re.MULTILINE) |
| + |
| + def AndroidUpdate(sdk_filter): |
| + if any(t in targets for t in sdk_filter.split(',')): |
| + Android(['update', 'sdk', '--no-ui', '--filter', sdk_filter]) |
| + else: |
| + print 'SDK targets %s already up to date' % sdk_filter |
| + |
| + AndroidUpdate('platform-tool,tool,%s' % SDK_TARGET_ID) |
| + |
| + if options.emulator: |
| + AndroidUpdate('system-image') |
| + |
| + def CreateAvd(name, abi): |
| + Android(['create', 'avd', '--name', name, '--abi', abi, |
| + '--target', SDK_TARGET_ID, '--force'], stdin='no\n') |
| + CreateAvd('avd-armeabi', 'armeabi-v7a') |
| + CreateAvd('avd-x86', 'x86') |
| + |
| + return True |
| + |
| + |
| +def ReplaceBinary(source_file, dest_file): |
| + dest_dir = os.path.dirname(dest_file) |
| + backup_file = dest_file + '.orig' |
| + if not os.path.exists(backup_file): |
| + os.rename(dest_file, backup_file) |
| + print 'replacing %s with %s' % (dest_file, source_file) |
| + shutil.copyfile(source_file, dest_file) |
| + with open(os.path.join(dest_dir, 'README.PATCH'), 'w') as f: |
| + f.write('%s replaced by %s' % (dest_file, source_file)) |
| + |
| + |
| +def InstallNdk(ndk_root, options): |
| + if os.path.exists(ndk_root): |
| + print 'NDK directory already exists, skipping install' |
| + return True |
| + |
| + tar_filepath = Download(os.path.dirname(ndk_root), NDK_CONFIG, options) |
| + ExtractTgz(ndk_root, tar_filepath, options) |
| + |
| + new_linker = os.path.join(options.src_root, 'third_party/aosp', NDK_LINKER) |
| + if not os.path.exists(new_linker): |
| + print 'Error installing NDK: linker %s does not exist' % new_linker |
| + return False |
| + linker_base = 'toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86' |
| + ReplaceBinary(new_linker, os.path.join(ndk_root, linker_base, |
| + 'bin/arm-linux-androideabi-ld')) |
| + ReplaceBinary(new_linker, os.path.join(ndk_root, linker_base, |
| + 'arm-linux-androideabi/bin/ld')) |
| + return True |
| + |
| + |
| +def main(argv): |
| + parser = optparse.OptionParser() |
| + parser.add_option('--versioned', action='store_true') |
|
bulach
2012/07/17 11:27:20
nit: see above, I think this would be clearer as -
|
| + parser.add_option('--emulator', action='store_true') |
| + parser.add_option('--dry-run', action='store_true') |
| + parser.add_option('--src-root', default=os.path.realpath(__file__ + '/../..')) |
|
bulach
2012/07/17 11:27:20
nit: probably best to keep as dry_run and src_root
|
| + |
| + options, args = parser.parse_args(argv) |
| + if args[1:]: |
| + parser.error('Unknown options %s' % args[1:]) |
| + |
| + sdk_root = GetRoot(SDK_CONFIG) |
| + ndk_root = GetRoot(NDK_CONFIG) |
| + |
| + if options.versioned: |
| + VersionedInstall(sdk_root, SDK_CONFIG['version'], InstallSdk, options) |
| + VersionedInstall(ndk_root, NDK_CONFIG['version'], InstallNdk, options) |
| + else: |
| + InstallSdk(sdk_root, options) |
| + InstallNdk(ndk_root, options) |
| + |
| + |
| +if __name__ == '__main__': |
| + sys.exit(main(sys.argv)) |