148 lines
5.2 KiB
Python
Executable File
148 lines
5.2 KiB
Python
Executable File
#!/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.
|
|
""" Builds all the revisions in channels.json and deploys them if --upload.
|
|
|
|
See go/perfetto-ui-autopush for docs on how this works end-to-end.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
from os.path import dirname
|
|
pjoin = os.path.join
|
|
|
|
BUCKET_NAME = 'ui.perfetto.dev'
|
|
CUR_DIR = dirname(os.path.abspath(__file__))
|
|
ROOT_DIR = dirname(dirname(CUR_DIR))
|
|
|
|
|
|
def check_call_and_log(args):
|
|
print(' '.join(args))
|
|
subprocess.check_call(args)
|
|
|
|
|
|
def check_output(args):
|
|
return subprocess.check_output(args).decode().strip()
|
|
|
|
|
|
def version_exists(version):
|
|
url = 'https://commondatastorage.googleapis.com/%s/%s/manifest.json' % (
|
|
BUCKET_NAME, version)
|
|
return 0 == subprocess.call(['curl', '-fLs', '-o', '/dev/null', url])
|
|
|
|
|
|
def build_git_revision(channel, git_ref, tmp_dir):
|
|
workdir = pjoin(tmp_dir, channel)
|
|
check_call_and_log(['rm', '-rf', workdir])
|
|
check_call_and_log(['git', 'clone', '--quiet', '--shared', ROOT_DIR, workdir])
|
|
old_cwd = os.getcwd()
|
|
os.chdir(workdir)
|
|
try:
|
|
check_call_and_log(['git', 'reset', '--hard', git_ref])
|
|
check_call_and_log(['git', 'clean', '-dfx'])
|
|
git_sha = check_output(['git', 'rev-parse', 'HEAD'])
|
|
print('===================================================================')
|
|
print('Building UI for channel %s @ %s (%s)' % (channel, git_ref, git_sha))
|
|
print('===================================================================')
|
|
version = check_output(['tools/write_version_header.py', '--stdout'])
|
|
check_call_and_log(['tools/install-build-deps', '--ui'])
|
|
check_call_and_log(['ui/build'])
|
|
return version, pjoin(workdir, 'ui/out/dist')
|
|
finally:
|
|
os.chdir(old_cwd)
|
|
|
|
|
|
def build_all_channels(channels, tmp_dir, merged_dist_dir):
|
|
channel_map = {}
|
|
for chan in channels:
|
|
channel = chan['name']
|
|
git_ref = chan['rev']
|
|
# version here is something like "v1.2.3".
|
|
version, dist_dir = build_git_revision(channel, git_ref, tmp_dir)
|
|
channel_map[channel] = version
|
|
check_call_and_log(['cp', '-an', pjoin(dist_dir, version), merged_dist_dir])
|
|
if channel != 'stable':
|
|
continue
|
|
# Copy also the /index.html and /service_worker.*, but only for the stable
|
|
# channel. The /index.html and SW must be shared between all channels,
|
|
# because they are all reachable through ui.perfetto.dev/. Both the index
|
|
# and the SQ are supposed to be version-independent (go/perfetto-channels).
|
|
# If an accidental incompatibility bug sneaks in, we should much rather
|
|
# crash canary (or any other channel) rather than stable. Hence why we copy
|
|
# the index+sw from the stable channel.
|
|
for fname in os.listdir(dist_dir):
|
|
fpath = pjoin(dist_dir, fname)
|
|
if os.path.isfile(fpath):
|
|
check_call_and_log(['cp', '-an', fpath, merged_dist_dir])
|
|
return channel_map
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--upload', action='store_true')
|
|
parser.add_argument('--tmp', default='/tmp/perfetto_ui')
|
|
args = parser.parse_args()
|
|
|
|
# Read the releases.json, which maps channel names to git refs, e.g.:
|
|
# {name:'stable', rev:'a0b1c2...0}, {name:'canary', rev:'HEAD'}
|
|
channels = []
|
|
with open(pjoin(CUR_DIR, 'channels.json')) as f:
|
|
channels = json.load(f)['channels']
|
|
|
|
merged_dist_dir = pjoin(args.tmp, 'dist')
|
|
check_call_and_log(['rm', '-rf', merged_dist_dir])
|
|
shutil.os.makedirs(merged_dist_dir)
|
|
channel_map = build_all_channels(channels, args.tmp, merged_dist_dir)
|
|
|
|
print('Updating index in ' + merged_dist_dir)
|
|
with open(pjoin(merged_dist_dir, 'index.html'), 'r+') as f:
|
|
index_html = f.read()
|
|
f.seek(0, 0)
|
|
f.truncate()
|
|
index_html = re.sub(r"data-perfetto_version='[^']*'",
|
|
"data-perfetto_version='%s'" % json.dumps(channel_map),
|
|
index_html)
|
|
f.write(index_html)
|
|
|
|
if not args.upload:
|
|
return
|
|
|
|
print('===================================================================')
|
|
print('Uploading to gs://%s' % BUCKET_NAME)
|
|
print('===================================================================')
|
|
cp_cmd = [
|
|
'gsutil', '-m', '-h', 'Cache-Control:public, max-age=3600', 'cp', '-j',
|
|
'html,js,css,wasm'
|
|
]
|
|
for name in os.listdir(merged_dist_dir):
|
|
path = pjoin(merged_dist_dir, name)
|
|
if os.path.isdir(path):
|
|
if version_exists(name):
|
|
print('Skipping upload of %s because it already exists on GCS' % name)
|
|
continue
|
|
check_call_and_log(cp_cmd + ['-r', path, 'gs://%s/' % BUCKET_NAME])
|
|
else:
|
|
# /index.html or /service_worker.js{,.map}
|
|
check_call_and_log(cp_cmd + [path, 'gs://%s/%s' % (BUCKET_NAME, name)])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|