xref: /aosp_15_r20/prebuilts/runtime/common/python/update_prebuilts.py (revision 924841fff420cd6b931e1027ee46b85e0a18fe17)
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