blob: f9c69051a707aeddd4c5dc1bdafc1bb394379aa2 [file] [log] [blame]
Alan Viverette95f6d362017-04-06 09:40:50 -04001#!/usr/bin/python
2
3import os, sys, getopt, zipfile, re
Alan Viveretted4527e62017-05-11 15:03:25 -04004import argparse
5import subprocess
Alan Viverette95f6d362017-04-06 09:40:50 -04006from shutil import copyfile, rmtree
Alan Viveretted4527e62017-05-11 15:03:25 -04007from distutils.version import LooseVersion
Alan Viverette95f6d362017-04-06 09:40:50 -04008
Alan Viverette45837092017-05-12 14:50:53 -04009current_path = 'current'
10system_path = 'system_current'
11support_path = os.path.join(current_path, 'support')
Alan Viverette95f6d362017-04-06 09:40:50 -040012
Alan Viveretted4527e62017-05-11 15:03:25 -040013# See go/fetch_artifact
14FETCH_ARTIFACT = '/google/data/ro/projects/android/fetch_artifact'
15
Alan Viverette95f6d362017-04-06 09:40:50 -040016# Does not import support-v4, which is handled as a separate Android.mk (../support-v4) to
17# statically include dependencies. Similarly, the support-v13 module is imported as
18# support-v13-nodeps and then handled as a separate Android.mk (../support-v13) to statically
19# include dependencies.
20maven_to_make = {
21 'animated-vector-drawable': ['android-support-animatedvectordrawable', 'graphics/drawable'],
Alan Viverette0aaa6252017-05-12 11:33:52 -040022 'appcompat-v7': ['android-support-v7-appcompat-nodeps', 'v7/appcompat'],
Alan Viverette95f6d362017-04-06 09:40:50 -040023 'cardview-v7': ['android-support-v7-cardview', 'v7/cardview'],
24 'customtabs': ['android-support-customtabs', 'customtabs'],
25 'design': ['android-support-design', 'design'],
26 'exifinterface': ['android-support-exifinterface', 'exifinterface'],
27 'gridlayout-v7': ['android-support-v7-gridlayout', 'v7/gridlayout'],
28 'leanback-v17': ['android-support-v17-leanback', 'v17/leanback'],
29 'mediarouter-v7': ['android-support-v7-mediarouter', 'v7/mediarouter'],
30 'multidex': ['android-support-multidex', 'multidex/library'],
31 'multidex-instrumentation': ['android-support-multidex-instrumentation', 'multidex/instrumentation'],
32 'palette-v7': ['android-support-v7-palette', 'v7/palette'],
33 'percent': ['android-support-percent', 'percent'],
34 'preference-leanback-v17': ['android-support-v17-preference-leanback', 'v17/preference-leanback'],
35 'preference-v14': ['android-support-v14-preference', 'v14/preference'],
36 'preference-v7': ['android-support-v7-preference', 'v7/preference'],
37 'recommendation': ['android-support-recommendation', 'recommendation'],
38 'recyclerview-v7': ['android-support-v7-recyclerview', 'v7/recyclerview'],
39 'support-annotations': ['android-support-annotations', 'annotations'],
40 'support-compat': ['android-support-compat', 'compat'],
41 'support-core-ui': ['android-support-core-ui', 'core-ui'],
42 'support-core-utils': ['android-support-core-utils', 'core-utils'],
43 'support-dynamic-animation': ['android-support-dynamic-animation', 'dynamic-animation'],
44 'support-emoji': ['android-support-emoji', 'emoji'],
45 'support-emoji-appcompat': ['android-support-emoji-appcompat', 'emoji-appcompat'],
46 'support-emoji-bundled': ['android-support-emoji-bundled', 'emoji-bundled'],
47 'support-fragment': ['android-support-fragment', 'fragment'],
48 'support-media-compat': ['android-support-media-compat', 'media-compat'],
49 'support-tv-provider': ['android-support-tv-provider', 'tv-provider'],
Alan Viverette0aaa6252017-05-12 11:33:52 -040050 'support-v13': ['android-support-v13-nodeps', 'v13'],
Alan Viverette95f6d362017-04-06 09:40:50 -040051 'support-vector-drawable': ['android-support-vectordrawable', 'graphics/drawable'],
52 'transition': ['android-support-transition', 'transition'],
53 'wear': ['android-support-wear', 'wear']
54}
55
56# Always remove these files.
57blacklist_files = [
58 'annotations.zip',
59 'public.txt',
60 'R.txt',
61 'AndroidManifest.xml'
62]
63
Alan Viverettef17c9402017-07-19 12:57:40 -040064artifact_pattern = re.compile(r"^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d+)?)\.(jar|aar)$")
Alan Viverette95f6d362017-04-06 09:40:50 -040065
66
67def touch(fname, times=None):
68 with open(fname, 'a'):
69 os.utime(fname, times)
70
71
Alan Viverette45837092017-05-12 14:50:53 -040072def path(*path_parts):
73 return reduce((lambda x, y: os.path.join(x, y)), path_parts)
74
75
76def rm(path):
77 if os.path.isdir(path):
78 rmtree(path)
79 elif os.path.exists(path):
80 os.remove(path)
81
82
83def mv(src_path, dst_path):
84 rm(dst_path)
85 os.rename(src_path, dst_path)
86
87
Alan Viveretted4527e62017-05-11 15:03:25 -040088def transform_support(repoDir):
Alan Viverette95f6d362017-04-06 09:40:50 -040089 cwd = os.getcwd()
90
Alan Viverette95f6d362017-04-06 09:40:50 -040091 # Use a temporary working directory.
92 working_dir = os.path.join(cwd, 'support_tmp')
93 if os.path.exists(working_dir):
94 rmtree(working_dir)
95 os.mkdir(working_dir)
96
Alan Viveretted4527e62017-05-11 15:03:25 -040097 maven_lib_info = {}
98
Alan Viverette5bfe05b2017-06-06 14:21:29 -040099 # Find the latest revision for each artifact.
Alan Viveretted4527e62017-05-11 15:03:25 -0400100 for root, dirs, files in os.walk(repoDir):
Alan Viverette95f6d362017-04-06 09:40:50 -0400101 for file in files:
102 matcher = artifact_pattern.match(file)
103 if matcher:
104 maven_lib_name = matcher.group(1)
Alan Viveretted4527e62017-05-11 15:03:25 -0400105 maven_lib_vers = LooseVersion(matcher.group(2))
Alan Viverette95f6d362017-04-06 09:40:50 -0400106
107 if maven_lib_name in maven_to_make:
Alan Viveretted4527e62017-05-11 15:03:25 -0400108 if maven_lib_name not in maven_lib_info \
109 or maven_lib_vers > maven_lib_info[maven_lib_name][0]:
110 maven_lib_info[maven_lib_name] = [maven_lib_vers, root, file]
Alan Viverette95f6d362017-04-06 09:40:50 -0400111
Alan Viveretted4527e62017-05-11 15:03:25 -0400112 for info in maven_lib_info.values():
113 transform_maven_lib(working_dir, info[1], info[2])
Alan Viverette95f6d362017-04-06 09:40:50 -0400114
115 # Replace the old directory.
Alan Viverette45837092017-05-12 14:50:53 -0400116 output_dir = os.path.join(cwd, support_path)
Alan Viverette95f6d362017-04-06 09:40:50 -0400117 if os.path.exists(output_dir):
118 rmtree(output_dir)
119 os.rename(working_dir, output_dir)
120
Alan Viveretted4527e62017-05-11 15:03:25 -0400121
122def transform_maven_lib(working_dir, root, file):
123 matcher = artifact_pattern.match(file)
124 maven_lib_name = matcher.group(1)
125 maven_lib_vers = matcher.group(2)
126 maven_lib_type = matcher.group(3)
127
128 make_lib_name = maven_to_make[maven_lib_name][0]
129 make_dir_name = maven_to_make[maven_lib_name][1]
130 artifact_file = os.path.join(root, file)
131 target_dir = os.path.join(working_dir, make_dir_name)
132 if not os.path.exists(target_dir):
133 os.makedirs(target_dir)
134
135 if maven_lib_type == "aar":
136 process_aar(artifact_file, target_dir, make_lib_name)
137 else:
138 target_file = os.path.join(target_dir, make_lib_name + ".jar")
139 os.rename(artifact_file, target_file)
140
141 print maven_lib_vers, ":", maven_lib_name, "->", make_lib_name
142
Alan Viverette95f6d362017-04-06 09:40:50 -0400143
144def process_aar(artifact_file, target_dir, make_lib_name):
145 # Extract AAR file to target_dir.
146 with zipfile.ZipFile(artifact_file) as zip:
147 zip.extractall(target_dir)
148
149 # Rename classes.jar to match the make artifact
150 classes_jar = os.path.join(target_dir, "classes.jar")
151 if os.path.exists(classes_jar):
152 # If it has resources, it needs a libs dir.
153 res_dir = os.path.join(target_dir, "res")
154 if os.path.exists(res_dir) and os.listdir(res_dir):
155 libs_dir = os.path.join(target_dir, "libs")
156 if not os.path.exists(libs_dir):
157 os.mkdir(libs_dir)
158 else:
159 libs_dir = target_dir
160 target_jar = os.path.join(libs_dir, make_lib_name + ".jar")
161 os.rename(classes_jar, target_jar)
162
163 # Remove or preserve empty dirs.
164 for root, dirs, files in os.walk(target_dir):
165 for dir in dirs:
166 dir_path = os.path.join(root, dir)
167 if not os.listdir(dir_path):
168 os.rmdir(dir_path)
169
170 # Remove top-level cruft.
171 for file in blacklist_files:
172 file_path = os.path.join(target_dir, file)
173 if os.path.exists(file_path):
174 os.remove(file_path)
175
Alan Viverettef17c9402017-07-19 12:57:40 -0400176
Alan Viverette45837092017-05-12 14:50:53 -0400177def fetch_artifact(target, buildId, artifact_path):
178 print 'Fetching %s from %s...' % (artifact_path, target)
179 fetchCmd = [FETCH_ARTIFACT, '--bid', str(buildId), '--target', target, artifact_path]
180 try:
181 subprocess.check_output(fetchCmd, stderr=subprocess.STDOUT)
182 except subprocess.CalledProcessError:
183 print >> sys.stderr, 'FAIL: Unable to retrieve %s artifact for build ID %d' % (artifact_path, buildId)
184 return None
185 return artifact_path
186
187
188def update_support(target, buildId):
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400189 artifact_path = fetch_artifact(target, buildId, 'top-of-tree-m2repository-%s.zip' % (buildId))
Alan Viverette45837092017-05-12 14:50:53 -0400190 if not artifact_path:
191 return
192
193 # Unzip the repo archive into a separate directory.
194 repoDir = os.path.basename(artifact_path)[:-4]
195 with zipfile.ZipFile(artifact_path) as zipFile:
196 zipFile.extractall(repoDir)
197
198 # Transform the repo archive into a Makefile-compatible format.
199 transform_support(repoDir)
200
201
202def extract_to(zip_file, paths, filename, parent_path):
203 zip_path = filter(lambda path: filename in path, paths)[0]
204 src_path = zip_file.extract(zip_path)
205 dst_path = path(parent_path, filename)
206 mv(src_path, dst_path)
207
208
209def update_sdk_repo(target, buildId):
210 platform = 'darwin' if 'mac' in target else 'linux'
211 artifact_path = fetch_artifact(target, buildId, 'sdk-repo-%s-platforms-%s.zip' % (platform, buildId))
212 if not artifact_path:
213 return
214
215 with zipfile.ZipFile(artifact_path) as zipFile:
216 paths = zipFile.namelist()
217
218 extract_to(zipFile, paths, 'android.jar', current_path)
219 extract_to(zipFile, paths, 'uiautomator.jar', current_path)
220 extract_to(zipFile, paths, 'framework.aidl', current_path)
221
222 # Unclear if this is actually necessary.
223 extract_to(zipFile, paths, 'framework.aidl', system_path)
224
225
226def update_system(target, buildId):
227 artifact_path = fetch_artifact(target, buildId, 'android_system.jar')
228 if not artifact_path:
229 return
230
231 mv(artifact_path, path(system_path, 'android.jar'))
232
Alan Viverette95f6d362017-04-06 09:40:50 -0400233
Alan Viveretted4527e62017-05-11 15:03:25 -0400234parser = argparse.ArgumentParser(
Alan Viverette45837092017-05-12 14:50:53 -0400235 description=('Update current prebuilts'))
Alan Viveretted4527e62017-05-11 15:03:25 -0400236parser.add_argument(
237 'buildId',
238 type=int,
Alan Viveretted4527e62017-05-11 15:03:25 -0400239 help='Build server build ID')
240parser.add_argument(
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400241 '-s', '--support', action="store_true",
242 help='If specified, updates only the Support Library')
Alan Viverette45837092017-05-12 14:50:53 -0400243parser.add_argument(
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400244 '-p', '--platform', action="store_true",
245 help='If specified, updates only the Android Platform')
Alan Viveretted4527e62017-05-11 15:03:25 -0400246args = parser.parse_args()
247if not args.buildId:
248 parser.error("You must specify a build ID")
249 sys.exit(1)
250
251try:
252 # Make sure we don't overwrite any pending changes.
253 subprocess.check_call(['git', 'diff', '--quiet', '--', '**'])
254 subprocess.check_call(['git', 'diff', '--quiet', '--cached', '--', '**'])
255except subprocess.CalledProcessError:
256 print >> sys.stderr, "FAIL: There are uncommitted changes here; please revert or stash"
257 sys.exit(1)
258
259try:
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400260 has_args = args.support or args.platform
261
262 if has_args and args.support:
263 update_support('support_library', args.buildId)
264 if has_args and args.platform:
265 update_sdk_repo('sdk_phone_armv7-sdk_mac', args.buildId)
266 update_system('sdk_phone_armv7-sdk_mac', args.buildId)
Alan Viveretted4527e62017-05-11 15:03:25 -0400267
268 # Commit all changes.
Alan Viverette45837092017-05-12 14:50:53 -0400269 subprocess.check_call(['git', 'add', current_path])
270 subprocess.check_call(['git', 'add', system_path])
271 msg = "Import support libs from build %s" % args.buildId
Alan Viveretted4527e62017-05-11 15:03:25 -0400272 subprocess.check_call(['git', 'commit', '-m', msg])
273 print 'Be sure to upload this manually to gerrit.'
274
275finally:
276 # Revert all stray files, including the downloaded zip.
277 try:
278 with open(os.devnull, 'w') as bitbucket:
279 subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
280 subprocess.check_call(
281 ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!'], stdout=bitbucket)
282 subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
283 except subprocess.CalledProcessError:
284 print >> sys.stderr, "ERROR: Failed cleaning up, manual cleanup required!!!"