1*924841ffSAndroid Build Coastguard Worker# Copyright (C) 2018 The Android Open Source Project 2*924841ffSAndroid Build Coastguard Worker# 3*924841ffSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*924841ffSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*924841ffSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*924841ffSAndroid Build Coastguard Worker# 7*924841ffSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*924841ffSAndroid Build Coastguard Worker# 9*924841ffSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*924841ffSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*924841ffSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*924841ffSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*924841ffSAndroid Build Coastguard Worker# limitations under the License. 14*924841ffSAndroid Build Coastguard Worker# 15*924841ffSAndroid Build Coastguard Worker"""Downloads prebuilt from the build server.""" 16*924841ffSAndroid Build Coastguard Worker 17*924841ffSAndroid Build Coastguard Workerimport argparse 18*924841ffSAndroid Build Coastguard Workerimport logging 19*924841ffSAndroid Build Coastguard Workerimport os 20*924841ffSAndroid Build Coastguard Workerimport os.path 21*924841ffSAndroid Build Coastguard Workerimport shutil 22*924841ffSAndroid Build Coastguard Workerimport stat 23*924841ffSAndroid Build Coastguard Workerimport sys 24*924841ffSAndroid Build Coastguard Workerimport textwrap 25*924841ffSAndroid Build Coastguard Worker 26*924841ffSAndroid Build Coastguard Worker 27*924841ffSAndroid Build Coastguard Workerclass InstallEntry(object): 28*924841ffSAndroid Build Coastguard Worker def __init__(self, target, name, install_path, 29*924841ffSAndroid Build Coastguard Worker need_strip=False, need_exec=False, need_unzip=False, 30*924841ffSAndroid Build Coastguard Worker install_unzipped=False): 31*924841ffSAndroid Build Coastguard Worker self.target = target 32*924841ffSAndroid Build Coastguard Worker self.name = name 33*924841ffSAndroid Build Coastguard Worker self.install_path = install_path 34*924841ffSAndroid Build Coastguard Worker self.need_strip = need_strip 35*924841ffSAndroid Build Coastguard Worker self.need_exec = need_exec 36*924841ffSAndroid Build Coastguard Worker 37*924841ffSAndroid Build Coastguard Worker # Installs a zip file, and also unzips it into the same directory. The 38*924841ffSAndroid Build Coastguard Worker # unzipped contents are not automatically installed. 39*924841ffSAndroid Build Coastguard Worker self.need_unzip = need_unzip 40*924841ffSAndroid Build Coastguard Worker 41*924841ffSAndroid Build Coastguard Worker # Install the unzipped contents of a zip file into install_path, but not 42*924841ffSAndroid Build Coastguard Worker # the file itself. All old content in install_path is removed first. 43*924841ffSAndroid Build Coastguard Worker self.install_unzipped = install_unzipped 44*924841ffSAndroid Build Coastguard Worker 45*924841ffSAndroid Build Coastguard Workerdef logger(): 46*924841ffSAndroid Build Coastguard Worker """Returns the main logger for this module.""" 47*924841ffSAndroid Build Coastguard Worker return logging.getLogger(__name__) 48*924841ffSAndroid Build Coastguard Worker 49*924841ffSAndroid Build Coastguard Worker 50*924841ffSAndroid Build Coastguard Workerdef check_call(cmd): 51*924841ffSAndroid Build Coastguard Worker """Proxy for subprocess.check_call with logging.""" 52*924841ffSAndroid Build Coastguard Worker import subprocess 53*924841ffSAndroid Build Coastguard Worker logger().debug('check_call `%s`', ' '.join(cmd)) 54*924841ffSAndroid Build Coastguard Worker subprocess.check_call(cmd) 55*924841ffSAndroid Build Coastguard Worker 56*924841ffSAndroid Build Coastguard Worker 57*924841ffSAndroid Build Coastguard Workerdef fetch_artifact(branch, build, target, pattern): 58*924841ffSAndroid Build Coastguard Worker """Fetches artifact from the build server.""" 59*924841ffSAndroid Build Coastguard Worker logger().info('Fetching %s from %s %s (artifacts matching %s)', build, 60*924841ffSAndroid Build Coastguard Worker target, branch, pattern) 61*924841ffSAndroid Build Coastguard Worker if target.startswith('local:'): 62*924841ffSAndroid Build Coastguard Worker shutil.copyfile(target[6:], pattern) 63*924841ffSAndroid Build Coastguard Worker return 64*924841ffSAndroid Build Coastguard Worker fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact' 65*924841ffSAndroid Build Coastguard Worker cmd = [fetch_artifact_path, '--branch', branch, '--target', target, 66*924841ffSAndroid Build Coastguard Worker '--bid', build, pattern] 67*924841ffSAndroid Build Coastguard Worker check_call(cmd) 68*924841ffSAndroid Build Coastguard Worker 69*924841ffSAndroid Build Coastguard Worker 70*924841ffSAndroid Build Coastguard Workerdef copy_artifact(local_dist, target, name): 71*924841ffSAndroid Build Coastguard Worker """Copies artifact from a local dist directory.""" 72*924841ffSAndroid Build Coastguard Worker source_path = (target[6:] if target.startswith('local:') 73*924841ffSAndroid Build Coastguard Worker else os.path.join(local_dist, name)) 74*924841ffSAndroid Build Coastguard Worker logger().info('Copying from %s', source_path) 75*924841ffSAndroid Build Coastguard Worker shutil.copyfile(source_path, os.path.basename(name)) 76*924841ffSAndroid Build Coastguard Worker 77*924841ffSAndroid Build Coastguard Worker 78*924841ffSAndroid Build Coastguard Workerdef start_branch(build): 79*924841ffSAndroid Build Coastguard Worker """Creates a new branch in the project.""" 80*924841ffSAndroid Build Coastguard Worker branch_name = 'update-' + (build or 'latest') 81*924841ffSAndroid Build Coastguard Worker logger().info('Creating branch %s', branch_name) 82*924841ffSAndroid Build Coastguard Worker check_call(['repo', 'start', branch_name, '.']) 83*924841ffSAndroid Build Coastguard Worker 84*924841ffSAndroid Build Coastguard Worker 85*924841ffSAndroid Build Coastguard Workerdef commit(prebuilts, branch, build, add_paths, commit_message_note): 86*924841ffSAndroid Build Coastguard Worker """Commits the new prebuilts.""" 87*924841ffSAndroid Build Coastguard Worker logger().info('Making commit') 88*924841ffSAndroid Build Coastguard Worker check_call(['git', 'add'] + add_paths) 89*924841ffSAndroid Build Coastguard Worker if build: 90*924841ffSAndroid Build Coastguard Worker message = textwrap.dedent("""\ 91*924841ffSAndroid Build Coastguard Worker Update {prebuilts} prebuilts to build {build}. 92*924841ffSAndroid Build Coastguard Worker 93*924841ffSAndroid Build Coastguard Worker Taken from branch {branch}.""").format( 94*924841ffSAndroid Build Coastguard Worker prebuilts=prebuilts, branch=branch, build=build) 95*924841ffSAndroid Build Coastguard Worker else: 96*924841ffSAndroid Build Coastguard Worker message = ( 97*924841ffSAndroid Build Coastguard Worker 'DO NOT SUBMIT: Update {prebuilts} prebuilts from local build.' 98*924841ffSAndroid Build Coastguard Worker .format(prebuilts=prebuilts)) 99*924841ffSAndroid Build Coastguard Worker if commit_message_note: 100*924841ffSAndroid Build Coastguard Worker message += "\n\n" + commit_message_note 101*924841ffSAndroid Build Coastguard Worker check_call(['git', 'commit', '-m', message]) 102*924841ffSAndroid Build Coastguard Worker 103*924841ffSAndroid Build Coastguard Worker 104*924841ffSAndroid Build Coastguard Workerdef list_installed_files(install_list, extracted_list): 105*924841ffSAndroid Build Coastguard Worker """List all prebuilts in current directory.""" 106*924841ffSAndroid Build Coastguard Worker result = [] 107*924841ffSAndroid Build Coastguard Worker for entry in install_list: 108*924841ffSAndroid Build Coastguard Worker result += [entry.install_path] 109*924841ffSAndroid Build Coastguard Worker for entry in extracted_list: 110*924841ffSAndroid Build Coastguard Worker result += [entry.install_path] 111*924841ffSAndroid Build Coastguard Worker return result 112*924841ffSAndroid Build Coastguard Worker 113*924841ffSAndroid Build Coastguard Worker 114*924841ffSAndroid Build Coastguard Workerdef remove_old_files(install_list, extracted_list): 115*924841ffSAndroid Build Coastguard Worker """Removes the old files.""" 116*924841ffSAndroid Build Coastguard Worker old_files = list_installed_files(install_list, extracted_list) 117*924841ffSAndroid Build Coastguard Worker if not old_files: 118*924841ffSAndroid Build Coastguard Worker return 119*924841ffSAndroid Build Coastguard Worker logger().info('Removing old files %s', old_files) 120*924841ffSAndroid Build Coastguard Worker check_call(['git', 'rm', '-qrf', '--ignore-unmatch'] + old_files) 121*924841ffSAndroid Build Coastguard Worker 122*924841ffSAndroid Build Coastguard Worker # Need to check again because git won't remove directories if they have 123*924841ffSAndroid Build Coastguard Worker # non-git files in them. 124*924841ffSAndroid Build Coastguard Worker check_call(['rm', '-rf'] + old_files) 125*924841ffSAndroid Build Coastguard Worker 126*924841ffSAndroid Build Coastguard Worker 127*924841ffSAndroid Build Coastguard Workerdef install_new_files(branch, build, local_dist, install_list, extracted_list): 128*924841ffSAndroid Build Coastguard Worker """Installs the new release.""" 129*924841ffSAndroid Build Coastguard Worker for entry in install_list: 130*924841ffSAndroid Build Coastguard Worker install_entry(branch, build, local_dist, entry) 131*924841ffSAndroid Build Coastguard Worker for entry in extracted_list: 132*924841ffSAndroid Build Coastguard Worker if entry.need_strip: 133*924841ffSAndroid Build Coastguard Worker check_call(['strip', entry.name]) 134*924841ffSAndroid Build Coastguard Worker 135*924841ffSAndroid Build Coastguard Worker 136*924841ffSAndroid Build Coastguard Workerdef install_entry(branch, build, local_dist, entry): 137*924841ffSAndroid Build Coastguard Worker """Installs one file specified by entry.""" 138*924841ffSAndroid Build Coastguard Worker target = entry.target 139*924841ffSAndroid Build Coastguard Worker name = entry.name 140*924841ffSAndroid Build Coastguard Worker install_path = entry.install_path 141*924841ffSAndroid Build Coastguard Worker need_strip = entry.need_strip 142*924841ffSAndroid Build Coastguard Worker need_exec = entry.need_exec 143*924841ffSAndroid Build Coastguard Worker need_unzip = entry.need_unzip 144*924841ffSAndroid Build Coastguard Worker install_unzipped = entry.install_unzipped 145*924841ffSAndroid Build Coastguard Worker 146*924841ffSAndroid Build Coastguard Worker if build: 147*924841ffSAndroid Build Coastguard Worker fetch_artifact(branch, build, target, name) 148*924841ffSAndroid Build Coastguard Worker else: 149*924841ffSAndroid Build Coastguard Worker copy_artifact(local_dist, target, name) 150*924841ffSAndroid Build Coastguard Worker if need_strip: 151*924841ffSAndroid Build Coastguard Worker check_call(['strip', name]) 152*924841ffSAndroid Build Coastguard Worker if need_exec: 153*924841ffSAndroid Build Coastguard Worker check_call(['chmod', 'a+x', name]) 154*924841ffSAndroid Build Coastguard Worker 155*924841ffSAndroid Build Coastguard Worker if install_unzipped: 156*924841ffSAndroid Build Coastguard Worker os.makedirs(install_path) 157*924841ffSAndroid Build Coastguard Worker zip_file = os.path.basename(name) 158*924841ffSAndroid Build Coastguard Worker unzip(zip_file, install_path) 159*924841ffSAndroid Build Coastguard Worker check_call(['rm', zip_file]) 160*924841ffSAndroid Build Coastguard Worker else: 161*924841ffSAndroid Build Coastguard Worker dir = os.path.dirname(install_path) 162*924841ffSAndroid Build Coastguard Worker if dir and not os.path.isdir(dir): 163*924841ffSAndroid Build Coastguard Worker os.makedirs(dir) 164*924841ffSAndroid Build Coastguard Worker shutil.move(os.path.basename(name), install_path) 165*924841ffSAndroid Build Coastguard Worker if need_unzip: 166*924841ffSAndroid Build Coastguard Worker unzip(install_path, os.path.dirname(install_path)) 167*924841ffSAndroid Build Coastguard Worker 168*924841ffSAndroid Build Coastguard Workerdef unzip(zip_file, unzip_path): 169*924841ffSAndroid Build Coastguard Worker # Add -DD to not extract timestamps that may confuse the build system. 170*924841ffSAndroid Build Coastguard Worker check_call(['unzip', '-DD', zip_file, '-d', unzip_path]) 171*924841ffSAndroid Build Coastguard Worker 172*924841ffSAndroid Build Coastguard Worker 173*924841ffSAndroid Build Coastguard Workerdef parse_args(parser_modifier=None): 174*924841ffSAndroid Build Coastguard Worker """Parses and returns command line arguments.""" 175*924841ffSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 176*924841ffSAndroid Build Coastguard Worker epilog='Either --build or --local-dist is required.') 177*924841ffSAndroid Build Coastguard Worker 178*924841ffSAndroid Build Coastguard Worker parser.add_argument( 179*924841ffSAndroid Build Coastguard Worker '-b', '--branch', default='aosp-master', 180*924841ffSAndroid Build Coastguard Worker help='Branch to pull build from.') 181*924841ffSAndroid Build Coastguard Worker parser.add_argument('--build', help='Build number to pull.') 182*924841ffSAndroid Build Coastguard Worker parser.add_argument('--local-dist', 183*924841ffSAndroid Build Coastguard Worker help='Take prebuilts from this local dist dir instead of ' 184*924841ffSAndroid Build Coastguard Worker 'using fetch_artifact') 185*924841ffSAndroid Build Coastguard Worker parser.add_argument( 186*924841ffSAndroid Build Coastguard Worker '--use-current-branch', action='store_true', 187*924841ffSAndroid Build Coastguard Worker help='Perform the update in the current branch. Do not repo start.') 188*924841ffSAndroid Build Coastguard Worker parser.add_argument( 189*924841ffSAndroid Build Coastguard Worker '-v', '--verbose', action='count', default=0, 190*924841ffSAndroid Build Coastguard Worker help='Increase output verbosity.') 191*924841ffSAndroid Build Coastguard Worker 192*924841ffSAndroid Build Coastguard Worker if parser_modifier: 193*924841ffSAndroid Build Coastguard Worker parser_modifier(parser) 194*924841ffSAndroid Build Coastguard Worker 195*924841ffSAndroid Build Coastguard Worker args = parser.parse_args() 196*924841ffSAndroid Build Coastguard Worker if ((not args.build and not args.local_dist) or 197*924841ffSAndroid Build Coastguard Worker (args.build and args.local_dist)): 198*924841ffSAndroid Build Coastguard Worker sys.exit(parser.format_help()) 199*924841ffSAndroid Build Coastguard Worker return args 200*924841ffSAndroid Build Coastguard Worker 201*924841ffSAndroid Build Coastguard Worker 202*924841ffSAndroid Build Coastguard Workerdef main(args, work_dir, prebuilts, install_list, extracted_list, commit_message_note=None): 203*924841ffSAndroid Build Coastguard Worker """Program entry point.""" 204*924841ffSAndroid Build Coastguard Worker 205*924841ffSAndroid Build Coastguard Worker verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG) 206*924841ffSAndroid Build Coastguard Worker verbosity = args.verbose 207*924841ffSAndroid Build Coastguard Worker if verbosity > 2: 208*924841ffSAndroid Build Coastguard Worker verbosity = 2 209*924841ffSAndroid Build Coastguard Worker logging.basicConfig(level=verbose_map[verbosity]) 210*924841ffSAndroid Build Coastguard Worker 211*924841ffSAndroid Build Coastguard Worker local_dist = args.local_dist 212*924841ffSAndroid Build Coastguard Worker if local_dist: 213*924841ffSAndroid Build Coastguard Worker local_dist = os.path.abspath(local_dist) 214*924841ffSAndroid Build Coastguard Worker 215*924841ffSAndroid Build Coastguard Worker os.chdir(work_dir) 216*924841ffSAndroid Build Coastguard Worker 217*924841ffSAndroid Build Coastguard Worker if not args.use_current_branch: 218*924841ffSAndroid Build Coastguard Worker start_branch(args.build) 219*924841ffSAndroid Build Coastguard Worker remove_old_files(install_list, extracted_list) 220*924841ffSAndroid Build Coastguard Worker install_new_files(args.branch, args.build, local_dist, install_list, extracted_list) 221*924841ffSAndroid Build Coastguard Worker files = list_installed_files(install_list, extracted_list) 222*924841ffSAndroid Build Coastguard Worker commit(prebuilts, args.branch, args.build, files, commit_message_note) 223