#!/usr/bin/env vpython3
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
A wrapper script for upload_to_google_storage_first_class.py.
Usage:
# Uploads file and generates .sha256 file
$ ./test_data.py upload data/trace.pftrace
# Generates deps entry for a single file
$ ./test_data.py get_deps data/trace.pftrace
# Generate full deps entry for all files in base/tracing/test/data/
$ ./test_data.py get_all_deps
The upload command uploads the given file to the gs://perfetto bucket and
generates a .sha256 file in the base/tracing/test/data/ directory,
which is rolled to the Perfetto repository.
The .sha256 file is used by Perfetto to download the files with their
own test_data download script (third_party/perfetto/tools/test_data).
The script outputs a GCS entry which should be manually added to the
deps dict in /DEPS. See
https://chromium.googlesource.com/chromium/src/+/HEAD/docs/gcs_dependencies.md.
The files are uploaded as gs://perfetto/test_data/file_name-a1b2c3f4.
"""
import argparse
import os
import subprocess
import sys
import json
import re
SRC_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
TEST_DATA_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data'))
DEPOT_TOOLS_PATH = os.path.abspath(os.path.join(SRC_PATH, 'third_party', 'depot_tools'))
sys.path.append(DEPOT_TOOLS_PATH)
from upload_to_google_storage_first_class import get_sha256sum
from download_from_google_storage import Gsutil, GSUTIL_DEFAULT_PATH
# Write .sha256 file to test/data_sha256 to be rolled into Perfetto.
def write_sha256_file(filepath: str):
sha256sum = get_sha256sum(filepath)
sha256_filepath = os.path.abspath(os.path.join(
os.path.dirname(filepath),
'..',
'data_sha256',
os.path.basename(filepath) + '.sha256'))
with open(sha256_filepath, 'w') as sha_file:
sha_file.write(sha256sum)
return sha256sum
# Run `upload_to_google_storage_first_class.py --bucket perfetto <file>`.
def upload_file(filepath: str, dry_run: bool, force: bool):
sha256sum = write_sha256_file(filepath)
# Perfetto uses 'test_data/file_name-a1b2c3f4' object name format.
object_name = '%s/%s-%s' % ('test_data', os.path.basename(filepath), sha256sum)
tool = 'upload_to_google_storage_first_class.py'
command = [tool, '--bucket', 'perfetto', '--object-name', object_name, filepath]
if dry_run:
command.append('--dry-run')
if force:
command.append('--force')
completed_process = subprocess.run(
command,
check=False,
capture_output=True)
if completed_process.returncode == 0:
print('Manually add the deps entry below to the DEPS file. See '
'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/gcs_dependencies.md '
'for more details. Run `test_data.py get_all_deps` to get the full deps entry.')
sys.stdout.buffer.write(completed_process.stdout)
else:
sys.stderr.buffer.write(completed_process.stderr)
# Generate the deps entry for `filepath`, assuming it has been uploaded already.
def generate_deps_entry(filepath: str):
sha256sum = get_sha256sum(filepath)
object_name = '%s/%s-%s' % ('test_data', os.path.basename(filepath), sha256sum)
# Run `gcloud storage ls -L gs://perfetto/test_data/file_name-a1b2c3f4` to
# get the 'generation' and 'size_bytes' fields for the deps entry
gsutil = Gsutil(GSUTIL_DEFAULT_PATH)
gsutil_args = ['ls', '-L', 'gs://perfetto/%s' % object_name]
code, out, err = gsutil.check_call(*gsutil_args)
if code != 0:
raise Exception(code, err + ' ' + object_name)
generation = int(out.split()[out.split().index('Generation:') + 1])
size = int(out.split()[out.split().index('Content-Length:') + 1])
return {
'object_name': object_name,
'sha256sum': sha256sum,
'size_bytes': size,
'generation': generation,
'output_file': os.path.basename(filepath),
}
# Generate the full deps entry for Perfetto test data
def generate_all_deps():
sha256_path = os.path.join(SRC_PATH, 'base/tracing/test/data_sha256')
data_path = os.path.join(SRC_PATH, 'base/tracing/test/data')
objects = []
for file in os.listdir(sha256_path):
if file.endswith('.sha256'):
filepath = os.path.join(data_path, file)[:-7]
assert os.path.isfile(filepath), 'File does not exist'
object_entry = generate_deps_entry(filepath)
objects.append(object_entry)
return {
'src/base/tracing/test/data': {
'bucket':
'perfetto',
'objects': objects,
'dep_type':
'gcs',
},
}
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='cmd')
upload_parser = subparsers.add_parser('upload', help='Upload a file to gs://perfetto')
upload_parser.add_argument('filepath', help='Path to file you want to upload')
upload_parser.add_argument('--dry-run', action='store_true',
help='Check if file already exists on GCS without '
'uploading it and output DEP blob.')
upload_parser.add_argument('-f',
'--force',
action='store_true',
help='Force upload even if remote file exists.')
get_deps_parser = subparsers.add_parser('get_deps', help='Print deps entry for a single file')
get_deps_parser.add_argument('filepath', help='Path to test data file you want the deps entry for.')
subparsers.add_parser('get_all_deps', help='Print deps entry for all files in `base/tracing/test/data/`')
args = parser.parse_args()
if args.cmd == 'get_all_deps':
print(json.dumps(generate_all_deps(), indent=2).replace('"', "'"))
return
filepath = os.path.abspath(args.filepath)
assert os.path.dirname(filepath) == TEST_DATA_PATH, ('You can only '
'upload files in base/tracing/test/data/')
if args.cmd == 'upload':
upload_file(filepath, args.dry_run, args.force)
elif args.cmd == 'get_deps':
print(json.dumps(generate_deps_entry(filepath), indent=2).replace('"', "'"))
if __name__ == '__main__':
sys.exit(main())