| #!/usr/bin/env python3 |
| # Copyright (C) 2021 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """Updates the python scripts in python/perfetto/prebuilts/manifests |
| |
| This script does the following, for each entry in MANIFESTS_TO_UPDATE: |
| - Downloads the artifact by the LUCI infrastructure, one for each arch. |
| - Computes the SHA-256 of each artifact. |
| - Generates a manifest with URL, SHA-256 and other details. |
| - Merges get_perfetto_prebuilt.py with the manifest and writes tools/xxx. |
| |
| This script is supposed to be run by Perfetto OWNERS after every monthly release |
| after the LUCI jobs have completed. |
| """ |
| |
| import argparse |
| import hashlib |
| import logging |
| import os |
| import subprocess |
| import sys |
| |
| from concurrent.futures import ThreadPoolExecutor |
| |
| GCS_URL = 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts' |
| |
| ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| MANIFESTS_DIR = os.path.join(ROOT_DIR, 'python/perfetto/prebuilts/manifests') |
| |
| UNIX_ARCHS = [ |
| 'mac-amd64', |
| 'mac-arm64', |
| 'linux-amd64', |
| 'linux-arm', |
| 'linux-arm64', |
| 'android-arm', |
| 'android-arm64', |
| 'android-x86', |
| 'android-x64', |
| ] |
| ALL_ARCHS = UNIX_ARCHS + ['windows-amd64'] |
| |
| MANIFESTS_TO_UPDATE = [ |
| { |
| 'tool': 'trace_processor_shell', |
| 'archs': ALL_ARCHS |
| }, |
| { |
| 'tool': 'traceconv', |
| 'archs': ALL_ARCHS |
| }, |
| { |
| 'tool': 'tracebox', |
| 'archs': UNIX_ARCHS |
| }, |
| ] |
| |
| # Maps a 'os-arch' string (were arch follows LUCI conventions) into |
| # corresponding tuples that match against python's platform / machine API |
| # (see get_perfetto_prebuilt.py for usage). |
| ARCH_TO_PYTHON = { |
| 'mac-amd64': { |
| 'platform': 'darwin', |
| 'machine': ['x86_64'], |
| }, |
| 'mac-arm64': { |
| 'platform': 'darwin', |
| 'machine': ['arm64'], |
| }, |
| 'windows-amd64': { |
| 'platform': 'win32', |
| 'machine': ['amd64'], |
| }, |
| 'linux-amd64': { |
| 'platform': 'linux', |
| 'machine': ['x86_64'], |
| }, |
| 'linux-arm': { |
| 'platform': 'linux', |
| 'machine': ['armv6l', 'armv7l', 'armv8l'], |
| }, |
| 'linux-arm64': { |
| 'platform': 'linux', |
| 'machine': ['aarch64'], |
| }, |
| } |
| |
| |
| def make_manifest(git_revision, tool, arch): |
| ext = '.exe' if arch.startswith('windows') else '' |
| file_name = tool + ext |
| url = '%s/%s/%s/%s' % (GCS_URL, git_revision, arch, file_name) |
| logging.info('Downloading %s', url) |
| data = subprocess.check_output(['curl', '-fsL', '-o', '-', url]) |
| manifest = { |
| 'arch': arch, |
| 'file_name': file_name, |
| 'file_size': len(data), |
| 'url': url, |
| 'sha256': hashlib.sha256(data).hexdigest() |
| } |
| manifest.update(ARCH_TO_PYTHON.get(arch, {})) |
| return manifest |
| |
| |
| def update_manifest(git_revision, tool_name, archs): |
| with ThreadPoolExecutor(max_workers=8) as executor: |
| manifests = list( |
| executor.map(lambda arch: make_manifest(git_revision, tool_name, arch), |
| archs)) |
| out_file = os.path.join(MANIFESTS_DIR, tool_name + '.py') |
| |
| content = '# This file has been generated by: {script} {git_revision}\n' |
| content += '{tool_uppercase}_MANIFEST = {manifests}\n' |
| content = content.format( |
| script=os.path.relpath(__file__), |
| tool_uppercase=tool_name.upper(), |
| git_revision=git_revision, |
| manifests=str(manifests)) |
| |
| with open(out_file + '.tmp', 'w') as f: |
| f.write(content) |
| subprocess.check_call(['yapf', '-i', out_file + '.tmp']) |
| os.rename(out_file + '.tmp', out_file) |
| os.chmod(out_file, 0o755) |
| |
| |
| def main(): |
| usage = '%s v20.0 | 0a1b2c3d\n\n' % __file__ |
| usage += 'To list available revisions run\n' |
| usage += 'gsutil ls gs://perfetto-luci-artifacts/\n' |
| usage += 'or visit https://chrome-infra-packages.appspot.com/p/perfetto\n' |
| parser = argparse.ArgumentParser(usage=usage) |
| parser.add_argument('version') |
| args = parser.parse_args() |
| |
| git_revision = args.version |
| for spec in MANIFESTS_TO_UPDATE: |
| logging.info('Updating %s', spec['tool']) |
| update_manifest(git_revision, spec['tool'], spec['archs']) |
| |
| |
| if __name__ == '__main__': |
| logging.basicConfig(level=logging.INFO) |
| sys.exit(main()) |