blob: a459dc08b4f8adcd77b212bdd5c2520fc92ffac0 [file] [log] [blame] [edit]
#!/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.
"""Packages prebuilts and SDK sources for GitHub releases.
Usage: ./tools/release/package-github-release-artifacts v20.0
IMPORTANT: This script must be run from the git tag being packaged. The SDK
source files are generated from the current working directory, so running this
script from a different commit will result in mismatched SDK sources.
This will generate:
- One .zip file for every os-arch combo (e.g. android-arm.zip)
- SDK source zips (perfetto-cpp-sdk-src.zip, perfetto-c-sdk-src.zip)
All files will be placed into /tmp/perfetto-v20.0-github-release/ .
"""
import argparse
import subprocess
import os
import sys
import tempfile
import shutil
def exec(*args):
print(' '.join(args))
subprocess.check_call(args)
def get_repo_root():
"""Returns the root directory of the Perfetto repository."""
script_dir = os.path.dirname(os.path.abspath(__file__))
return os.path.abspath(os.path.join(script_dir, '..', '..'))
def verify_git_state(expected_version):
"""Verifies git is on the correct tag with no uncommitted changes."""
warnings = []
# Check for uncommitted changes
try:
result = subprocess.run(['git', 'status', '--porcelain'],
capture_output=True,
text=True)
if result.returncode == 0 and result.stdout.strip():
warnings.append(
f'Working directory has uncommitted changes:\n{result.stdout}')
except Exception as e:
warnings.append(f'Could not check git status: {e}')
# Check current tag
try:
result = subprocess.run(['git', 'describe', '--exact-match', '--tags'],
capture_output=True,
text=True)
if result.returncode == 0:
current_tag = result.stdout.strip()
if current_tag != expected_version:
warnings.append(
f'On tag {current_tag}, but packaging {expected_version}')
else:
warnings.append(f'Not on a git tag (expected {expected_version})')
except Exception as e:
warnings.append(f'Could not check git tag: {e}')
if warnings:
print('WARNING: SDK sources may not match the release tag:')
for warning in warnings:
print(f' - {warning}')
return input('\nContinue anyway? [y/N] ').lower().strip() in ['y', 'yes']
print(f'✓ On tag {expected_version} with clean working directory')
return True
def generate_sdk_sources(tmpdir):
"""Generates SDK source zips using gen_amalgamated."""
repo_root = get_repo_root()
gen_amalgamated = os.path.join(repo_root, 'tools', 'gen_amalgamated')
sdk_zips = []
# Generate C++ SDK (default targets)
print('\n--- Generating C++ SDK amalgamated sources ---')
cpp_sdk_staging = tempfile.mkdtemp(prefix='perfetto-cpp-sdk-')
try:
exec('python3', gen_amalgamated, '--output',
os.path.join(cpp_sdk_staging, 'perfetto'))
os.chdir(tmpdir)
exec('zip', '-9rj', 'perfetto-cpp-sdk-src.zip', cpp_sdk_staging)
sdk_zips.append('perfetto-cpp-sdk-src.zip')
print('C++ SDK source zip created: perfetto-cpp-sdk-src.zip')
finally:
shutil.rmtree(cpp_sdk_staging, ignore_errors=True)
# Generate C SDK
# TODO(lalitm): determine the correct target for C SDK
print('\n--- Generating C SDK amalgamated sources ---')
c_sdk_staging = tempfile.mkdtemp(prefix='perfetto-c-sdk-')
try:
# For now, use the same targets as C++ SDK
# This should be updated with the correct C SDK target
exec('python3', gen_amalgamated, '--output',
os.path.join(c_sdk_staging, 'perfetto'))
os.chdir(tmpdir)
exec('zip', '-9rj', 'perfetto-c-sdk-src.zip', c_sdk_staging)
sdk_zips.append('perfetto-c-sdk-src.zip')
print('C SDK source zip created: perfetto-c-sdk-src.zip')
finally:
shutil.rmtree(c_sdk_staging, ignore_errors=True)
return sdk_zips
def main():
parser = argparse.ArgumentParser(epilog='Example: %s v19.0' % __file__)
parser.add_argument('version', help='Version tag (e.g., v20.0)')
args = parser.parse_args()
# Verify we're on the correct tag with no uncommitted changes
if not verify_git_state(args.version):
print('Aborted.')
return 1
tmpdir = '/tmp/perfetto-%s-github-release' % args.version
src = 'gs://perfetto-luci-artifacts/%s/' % args.version
os.makedirs(tmpdir, exist_ok=True)
# Download and package prebuilts
print('--- Downloading prebuilts from GCS ---')
os.chdir(tmpdir)
exec('gsutil', '-m', 'rsync', '-rc', src, tmpdir + '/')
zips = []
for arch in os.listdir(tmpdir):
if not os.path.isdir(arch):
continue
exec('zip', '-9r', '%s.zip' % arch, arch)
zips.append(arch + '.zip')
# Generate SDK source zips
sdk_zips = generate_sdk_sources(tmpdir)
zips.extend(sdk_zips)
print('')
print('=' * 70)
print('%d zip files saved in %s' % (len(zips), tmpdir))
print('Prebuilt binaries: %d' % (len(zips) - len(sdk_zips)))
print('SDK sources: %d' % len(sdk_zips))
print('Files: %s' % ', '.join(sorted(zips)))
print('=' * 70)
if __name__ == '__main__':
sys.exit(main())