1b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#!/usr/bin/env python
2b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#
3b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# Copyright (C) 2016 The Android Open Source Project
4b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#
5b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# Licensed under the Apache License, Version 2.0 (the "License");
6b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# you may not use this file except in compliance with the License.
7b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# You may obtain a copy of the License at
8b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#
9b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#      http://www.apache.org/licenses/LICENSE-2.0
10b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#
11b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# Unless required by applicable law or agreed to in writing, software
12b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# distributed under the License is distributed on an "AS IS" BASIS,
13b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# See the License for the specific language governing permissions and
15b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui# limitations under the License.
16b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui#
17b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui"""Downloads simpleperf prebuilts from the build server."""
18b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiimport argparse
19b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiimport logging
20b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiimport os
21b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiimport shutil
22b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiimport stat
23b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiimport textwrap
24b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
25b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
26b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin CuiTHIS_DIR = os.path.realpath(os.path.dirname(__file__))
27b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
28b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
29b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiclass InstallEntry(object):
30b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    def __init__(self, target, name, install_path, need_strip=False):
31b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        self.target = target
32b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        self.name = name
33b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        self.install_path = install_path
34b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        self.need_strip = need_strip
35b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
36b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
37b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiinstall_list = [
38b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    # simpleperf on device
39b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_arm64-sdk', 'simpleperf', 'android/arm64/simpleperf'),
40b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_arm64-sdk', 'simpleperf32', 'android/arm/simpleperf'),
41b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_x86_64-sdk', 'simpleperf', 'android/x86_64/simpleperf'),
42b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_x86_64-sdk', 'simpleperf32', 'android/x86/simpleperf'),
43b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
44b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    # simpleperf on host
45b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_arm64-sdk', 'simpleperf_host', 'linux/x86_64/simpleperf', True),
46b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_arm64-sdk', 'simpleperf_host32', 'linux/x86/simpleperf', True),
47b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_mac', 'simpleperf_host', 'darwin/x86_64/simpleperf'),
48b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_mac', 'simpleperf_host32', 'darwin/x86/simpleperf'),
49b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk', 'simpleperf.exe', 'windows/x86_64/simpleperf.exe', True),
50b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86/simpleperf.exe', True),
51b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
52b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    # libsimpleperf_report.so on host
53b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report.so', 'linux/x86_64/libsimpleperf_report.so', True),
54b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report32.so', 'linux/x86/libsimpleperf_report.so', True),
55b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_mac', 'libsimpleperf_report.dylib', 'darwin/x86_64/libsimpleperf_report.dylib'),
56b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk_mac', 'libsimpleperf_report32.so', 'darwin/x86/libsimpleperf_report.dylib'),
57b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk', 'libsimpleperf_report.dll', 'windows/x86_64/libsimpleperf_report.dll', True),
58b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    InstallEntry('sdk', 'libsimpleperf_report32.dll', 'windows/x86/libsimpleperf_report.dll', True),
59b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui]
60b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
61b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
62b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef logger():
63b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Returns the main logger for this module."""
64b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    return logging.getLogger(__name__)
65b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
66b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
67b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef check_call(cmd):
68b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Proxy for subprocess.check_call with logging."""
69b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    import subprocess
70b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    logger().debug('check_call `%s`', ' '.join(cmd))
71b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    subprocess.check_call(cmd)
72b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
73b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
74b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef fetch_artifact(branch, build, target, pattern):
75b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Fetches and artifact from the build server."""
76b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    logger().info('Fetching %s from %s %s (artifacts matching %s)', build,
77b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui                  target, branch, pattern)
78b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
79b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    cmd = [fetch_artifact_path, '--branch', branch, '--target', target,
80b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui           '--bid', build, pattern]
81b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    check_call(cmd)
82b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
83b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
84b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef start_branch(build):
85b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Creates a new branch in the project."""
86b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    branch_name = 'update-' + (build or 'latest')
87b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    logger().info('Creating branch %s', branch_name)
88b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    check_call(['repo', 'start', branch_name, '.'])
89b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
90b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
91b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef commit(branch, build, add_paths):
92b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Commits the new prebuilts."""
93b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    logger().info('Making commit')
94b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    check_call(['git', 'add'] + add_paths)
95b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    message = textwrap.dedent("""\
96b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        simpleperf: update simpleperf prebuilts to build {build}.
97b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
98b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        Taken from branch {branch}.""").format(branch=branch, build=build)
99b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    check_call(['git', 'commit', '-m', message])
100b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
101b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
102b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef remove_old_release(install_dir):
103b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Removes the old prebuilts."""
104b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    if os.path.exists(install_dir):
105b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        logger().info('Removing old install directory "%s"', install_dir)
106b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        check_call(['git', 'rm', '-rf', '--ignore-unmatch', install_dir])
107b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
108b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    # Need to check again because git won't remove directories if they have
109b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    # non-git files in them.
110b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    if os.path.exists(install_dir):
111b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        shutil.rmtree(install_dir)
112b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
113b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
114b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef install_new_release(branch, build, install_dir):
115b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Installs the new release."""
116b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    for entry in install_list:
117b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        install_entry(branch, build, install_dir, entry)
118b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
119b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
120b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef install_entry(branch, build, install_dir, entry):
121b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Installs the device specific components of the release."""
122b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    target = entry.target
123b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    name = entry.name
124b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    install_path = os.path.join(install_dir, entry.install_path)
125b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    need_strip = entry.need_strip
126b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
127b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    fetch_artifact(branch, build, target, name)
128b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    exe_stat = os.stat(name)
129b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    os.chmod(name, exe_stat.st_mode | stat.S_IEXEC)
130b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    if need_strip:
131b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        check_call(['strip', name])
132b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    dir = os.path.dirname(install_path)
133b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    if not os.path.isdir(dir):
134b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        os.makedirs(dir)
135b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    shutil.move(name, install_path)
136b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
137b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
138b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef get_args():
139b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Parses and returns command line arguments."""
140b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    parser = argparse.ArgumentParser()
141b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
142b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    parser.add_argument(
143b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        '-b', '--branch', default='aosp-master',
144b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        help='Branch to pull build from.')
145b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    parser.add_argument('--build', required=True, help='Build number to pull.')
146b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    parser.add_argument(
147b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        '--use-current-branch', action='store_true',
148b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        help='Perform the update in the current branch. Do not repo start.')
149b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    parser.add_argument(
150b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        '-v', '--verbose', action='count', default=0,
151b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        help='Increase output verbosity.')
152b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
153b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    return parser.parse_args()
154b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
155b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
156b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuidef main():
157b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    """Program entry point."""
158b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    os.chdir(THIS_DIR)
159b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
160b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    args = get_args()
161b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
162b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    verbosity = args.verbose
163b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    if verbosity > 2:
164b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        verbosity = 2
165b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    logging.basicConfig(level=verbose_map[verbosity])
166b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
167b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    install_dir = 'bin'
168b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
169b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    if not args.use_current_branch:
170b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui        start_branch(args.build)
171b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    remove_old_release(install_dir)
172b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    install_new_release(args.branch, args.build, install_dir)
173b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    artifacts = [install_dir]
174b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    commit(args.branch, args.build, artifacts)
175b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
176b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui
177b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cuiif __name__ == '__main__':
178b3a66f1687e349ee20a3a00fdedf79b604c8fe2bYabin Cui    main()