OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/python | |
2 # | |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 """A script to automatically install the android sdk and ndk.""" | |
7 | |
8 import optparse | |
9 import os | |
10 import re | |
11 import shutil | |
12 import subprocess | |
13 import sys | |
14 import tarfile | |
15 | |
16 SDK_CONFIG = {'varname': 'ANDROID_SDK_ROOT', | |
17 'default_dir': '/usr/local/google/android-sdk-linux', | |
18 'url': 'http://dl.google.com/android/android-sdk_r20-linux.tgz', | |
19 'tar_md5': 0x22a81cf1d4a951c62f71a8758290e9bb, | |
20 '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.
| |
21 SDK_TARGET_ID = 'android-15' | |
22 | |
23 | |
24 # Do not change without updating the 64-bit linker! | |
25 NDK_CONFIG = {'varname': 'ANDROID_NDK_ROOT', | |
26 'default_dir': '/usr/local/google/android-ndk-r7', | |
27 'url': ('http://dl.google.com/android/ndk' | |
28 '/android-ndk-r7-linux-x86.tar.bz2'), | |
29 'tar_md5': 0xbf15e6b47bf50824c4b96849bf003ca3, | |
30 'version': 1} | |
31 NDK_LINKER = 'arm-linux-androideabi-ld.e4df3e0a5bb640ccfa2f30ee67fe9b3146b152d6' | |
32 | |
33 | |
34 def GetCmdOutput(cmd, shell=False): | |
35 proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE) | |
36 return proc.communicate()[0] | |
37 | |
38 | |
39 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
| |
40 env_var_name = config['varname'] | |
41 default_path = config['default_dir'] | |
42 path = os.environ.get(env_var_name) | |
43 if not path: | |
44 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
| |
45 default_path)) | |
46 path = default_path | |
47 base_dir = os.path.dirname(path) | |
48 if not os.path.exists(base_dir): | |
49 print '%s does not exist, creating...' % base_dir | |
50 os.makedirs(base_dir, 0755) | |
51 return path | |
52 | |
53 | |
54 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
| |
55 version_filename = os.path.join(root, 'SCRIPT_VERSION') | |
56 try: | |
57 with open(version_filename) as f: | |
58 if int(f.read()) == version: | |
59 print 'Skipping %s (version is up to date).' % installer.__name__ | |
60 return | |
61 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.
| |
62 pass | |
63 | |
64 if os.path.exists(root): | |
65 print 'Removing %s for reinstall' % root | |
66 shutil.rmtree(root) | |
67 | |
68 success = installer(root, options) | |
69 | |
70 if success: | |
71 with open(version_filename, 'w') as f: | |
72 f.write('%d' % version) | |
73 | |
74 | |
75 def Download(base_dir, config, options): | |
76 url = config['url'] | |
77 md5 = config['tar_md5'] | |
78 tar_filepath = os.path.join(base_dir, os.path.basename(url)) | |
79 if not options.dry_run: | |
80 subprocess.check_call(['wget', url, '-O', tar_filepath]) | |
81 assert os.path.exists(tar_filepath) | |
82 md5str = GetCmdOutput(['md5sum', tar_filepath]) | |
83 assert md5 == int('0x' + md5str.split()[0], 16), 'md5 mismatch!' | |
84 return tar_filepath | |
85 | |
86 | |
87 def ExtractTgz(path, tar_filepath, options): | |
88 base_dir = os.path.dirname(path) | |
89 print 'extracting %s...' % tar_filepath | |
90 if options.dry_run: | |
91 if not os.path.exists(path): | |
92 os.mkdir(path) | |
93 return | |
94 | |
95 f = tarfile.open(tar_filepath) | |
96 f.extractall(path=base_dir) | |
97 extract_prefix = os.path.commonprefix(f.getnames()).split('/') | |
98 f.close() | |
99 extract_path = os.path.join(base_dir, extract_prefix[0]) | |
100 if os.path.abspath(path) != os.path.abspath(extract_path): | |
101 print 'Moving files from %s to %s' % (extract_path, path) | |
102 os.rename(extract_path, path) | |
103 os.remove(tar_filepath) | |
104 | |
105 | |
106 def InstallSdk(sdk_root, options): | |
107 if not os.path.exists(sdk_root): | |
108 tar_filepath = Download(os.path.dirname(sdk_root), SDK_CONFIG, options) | |
109 ExtractTgz(sdk_root, tar_filepath, options) | |
110 android_bin = os.path.join(sdk_root, 'tools/android') | |
111 | |
112 def Android(args, stdin=None): | |
bulach
2012/07/17 11:27:20
nit: remove the default value, there's only one ca
| |
113 if options.dry_run: | |
114 print 'android', args | |
115 else: | |
116 proc = subprocess.Popen([android_bin] + args, stdin=subprocess.PIPE) | |
117 proc.communicate(stdin) | |
118 | |
119 print 'Getting available targets...' | |
120 raw_targets = GetCmdOutput([android_bin, 'list', 'sdk', '--extended']) | |
121 targets = re.findall('^id:[\w ]*"([-\w_]+)"$', raw_targets, re.MULTILINE) | |
122 | |
123 def AndroidUpdate(sdk_filter): | |
124 if any(t in targets for t in sdk_filter.split(',')): | |
125 Android(['update', 'sdk', '--no-ui', '--filter', sdk_filter]) | |
126 else: | |
127 print 'SDK targets %s already up to date' % sdk_filter | |
128 | |
129 AndroidUpdate('platform-tool,tool,%s' % SDK_TARGET_ID) | |
130 | |
131 if options.emulator: | |
132 AndroidUpdate('system-image') | |
133 | |
134 def CreateAvd(name, abi): | |
135 Android(['create', 'avd', '--name', name, '--abi', abi, | |
136 '--target', SDK_TARGET_ID, '--force'], stdin='no\n') | |
137 CreateAvd('avd-armeabi', 'armeabi-v7a') | |
138 CreateAvd('avd-x86', 'x86') | |
139 | |
140 return True | |
141 | |
142 | |
143 def ReplaceBinary(source_file, dest_file): | |
144 dest_dir = os.path.dirname(dest_file) | |
145 backup_file = dest_file + '.orig' | |
146 if not os.path.exists(backup_file): | |
147 os.rename(dest_file, backup_file) | |
148 print 'replacing %s with %s' % (dest_file, source_file) | |
149 shutil.copyfile(source_file, dest_file) | |
150 with open(os.path.join(dest_dir, 'README.PATCH'), 'w') as f: | |
151 f.write('%s replaced by %s' % (dest_file, source_file)) | |
152 | |
153 | |
154 def InstallNdk(ndk_root, options): | |
155 if os.path.exists(ndk_root): | |
156 print 'NDK directory already exists, skipping install' | |
157 return True | |
158 | |
159 tar_filepath = Download(os.path.dirname(ndk_root), NDK_CONFIG, options) | |
160 ExtractTgz(ndk_root, tar_filepath, options) | |
161 | |
162 new_linker = os.path.join(options.src_root, 'third_party/aosp', NDK_LINKER) | |
163 if not os.path.exists(new_linker): | |
164 print 'Error installing NDK: linker %s does not exist' % new_linker | |
165 return False | |
166 linker_base = 'toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86' | |
167 ReplaceBinary(new_linker, os.path.join(ndk_root, linker_base, | |
168 'bin/arm-linux-androideabi-ld')) | |
169 ReplaceBinary(new_linker, os.path.join(ndk_root, linker_base, | |
170 'arm-linux-androideabi/bin/ld')) | |
171 return True | |
172 | |
173 | |
174 def main(argv): | |
175 parser = optparse.OptionParser() | |
176 parser.add_option('--versioned', action='store_true') | |
bulach
2012/07/17 11:27:20
nit: see above, I think this would be clearer as -
| |
177 parser.add_option('--emulator', action='store_true') | |
178 parser.add_option('--dry-run', action='store_true') | |
179 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
| |
180 | |
181 options, args = parser.parse_args(argv) | |
182 if args[1:]: | |
183 parser.error('Unknown options %s' % args[1:]) | |
184 | |
185 sdk_root = GetRoot(SDK_CONFIG) | |
186 ndk_root = GetRoot(NDK_CONFIG) | |
187 | |
188 if options.versioned: | |
189 VersionedInstall(sdk_root, SDK_CONFIG['version'], InstallSdk, options) | |
190 VersionedInstall(ndk_root, NDK_CONFIG['version'], InstallNdk, options) | |
191 else: | |
192 InstallSdk(sdk_root, options) | |
193 InstallNdk(ndk_root, options) | |
194 | |
195 | |
196 if __name__ == '__main__': | |
197 sys.exit(main(sys.argv)) | |
OLD | NEW |