1#!/usr/bin/python3 2 3import argparse 4import os 5import re 6import subprocess 7import sys 8import tempfile 9import zipfile 10 11from collections import defaultdict 12 13# See go/fetch_artifact for details on this script. 14FETCH_ARTIFACT = '/google/data/ro/projects/android/fetch_artifact' 15BUILD_TARGET = 'mainline_modules-userdebug' 16ARTIFACT_PATTERN = 'mainline-sdks/*-%d.zip' 17COMMIT_TEMPLATE = """Finalize artifacts for extension SDK %d 18 19Import from build id %s. 20 21Generated with: 22$ %s 23 24Bug: %d 25Test: presubmit""" 26 27def fail(*args, **kwargs): 28 print(*args, file=sys.stderr, **kwargs) 29 sys.exit(1) 30 31def fetch_artifacts(target, build_id, artifact_path): 32 tmpdir = tempfile.TemporaryDirectory().name 33 os.mkdir(tmpdir) 34 print('Fetching %s from %s ...' % (artifact_path, target)) 35 fetch_cmd = [FETCH_ARTIFACT] 36 fetch_cmd.extend(['--bid', str(build_id)]) 37 fetch_cmd.extend(['--target', target]) 38 fetch_cmd.append(artifact_path) 39 fetch_cmd.append(tmpdir) 40 print("Running: " + ' '.join(fetch_cmd)) 41 try: 42 subprocess.check_output(fetch_cmd, stderr=subprocess.STDOUT) 43 except subprocess.CalledProcessError: 44 fail('FAIL: Unable to retrieve %s artifact for build ID %s' % (artifact_path, build_id)) 45 return tmpdir 46 47def repo_for_sdk(filename): 48 module = filename.split('-')[0] 49 target_dir = '' 50 if module == 'media': return 'prebuilts/module_sdk/Media' 51 if module == 'tethering': return 'prebuilts/module_sdk/Connectivity' 52 for dir in os.listdir('prebuilts/module_sdk/'): 53 if module.lower() in dir.lower(): 54 if target_dir: 55 fail('Multiple target dirs matched "%s": %s' % (module, (target_dir, dir))) 56 target_dir = dir 57 if not target_dir: 58 fail('Could not find a target dir for %s' % filename) 59 60 return 'prebuilts/module_sdk/%s' % target_dir 61 62def dir_for_sdk(filename, version): 63 base = str(version) 64 if 'test-exports' in filename: 65 return os.path.join(base, 'test-exports') 66 if 'host-exports' in filename: 67 return os.path.join(base, 'host-exports') 68 return base 69 70if not os.path.isdir('build/soong'): 71 fail("This script must be run from the top of an Android source tree.") 72 73parser = argparse.ArgumentParser(description=('Finalize an extension SDK with prebuilts')) 74parser.add_argument('-f', '--finalize_sdk', type=int, required=True, help='The numbered SDK to finalize.') 75parser.add_argument('-b', '--bug', type=int, required=True, help='The bug number to add to the commit message.') 76parser.add_argument('-a', '--amend_last_commit', action="store_true", help='Amend current HEAD commits instead of making new commits.') 77parser.add_argument('bid', help='Build server build ID') 78args = parser.parse_args() 79 80branch_name = 'finalize-%d' % args.finalize_sdk 81cmdline = " ".join(filter(lambda x: x not in ['-a', '--amend_last_commit'], sys.argv)) 82commit_message = COMMIT_TEMPLATE % (args.finalize_sdk, args.bid, cmdline, args.bug) 83 84tmpdir = fetch_artifacts(BUILD_TARGET, args.bid, ARTIFACT_PATTERN % args.finalize_sdk) 85 86created_dirs = defaultdict(list) 87 88for f in os.listdir(tmpdir): 89 repo = repo_for_sdk(f) 90 dir = dir_for_sdk(f, args.finalize_sdk) 91 target_dir = os.path.join(repo, dir) 92 if os.path.isfile(target_dir): 93 print('Removing existing dir %s' % target_dir) 94 shutil.rmtree(target_dir) 95 with zipfile.ZipFile(os.path.join(tmpdir, f)) as zipFile: 96 zipFile.extractall(target_dir) 97 98 print('Created %s' % target_dir) 99 created_dirs[repo].append(dir) 100 101subprocess.check_output(['repo', 'start', branch_name] + list(created_dirs.keys())) 102print('Running git commit') 103for repo in created_dirs: 104 git = ['git', '-C', repo] 105 subprocess.check_output(git + ['add'] + created_dirs[repo]) 106 if args.amend_last_commit: 107 change_id = '\n' + re.search(r'Change-Id: [^\\n]+', str(subprocess.check_output(git + ['log', '-1']))).group(0) 108 subprocess.check_output(git + ['commit', '--amend', '-m', commit_message + change_id]) 109 else: 110 subprocess.check_output(git + ['commit', '-m', commit_message]) 111