blob: 8e7854b106049a6a5c099458d7b141ed02d17c56 [file] [log] [blame] [edit]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import zipfile
import subprocess
import os
import shutil
import tempfile
def zip_dir(dir, zip_file):
for root, _dirs, files in os.walk(dir):
for file in files:
path = os.path.join(root, file)
zip_file.write(path, os.path.relpath(path, dir))
# rmtree manually removes all subdirectories and files instead of using
# shutil.rmtree, to avoid registering spurious reads on stale
# subdirectories. See https://fxbug.dev/74084.
def rmtree(dir):
if not os.path.exists(dir):
return
for root, dirs, files in os.walk(dir, topdown=False):
for file in files:
os.unlink(os.path.join(root, file))
for dir in dirs:
full_path = os.path.join(root, dir)
if os.path.islink(full_path):
os.unlink(full_path)
else:
os.rmdir(full_path)
def prepare_dirs(repo_dir):
path = os.path.join(repo_dir, 'repository')
os.makedirs(path)
return {'root': repo_dir, 'repository': path}
# `package-tool repository publish` expects the following inputs in its in/out directory:
# - `keys/{snapshot|targets|timestamp}.json` containing private metadata keys;
# - `repository/{{version-num}}.root.json` containing versioned root metadata;
# - `repository/root.json` containing default root metadata.
def prepare_publish(args, dirs):
for root_metadata_path in args.root_metadata:
shutil.copy(root_metadata_path, dirs['repository'])
shutil.copy(
args.default_root_metadata,
'{}/{}'.format(dirs['repository'], 'root.json'))
def package_tool_publish(args, dirs, depfile):
cmd_args = [
args.package_tool,
'repository',
'publish',
'--trusted-keys',
args.trusted_keys,
'--trusted-root',
'{}/{}'.format(dirs['repository'], 'root.json'),
'--package-list',
args.input,
'--depfile',
args.depfile,
]
if args.delivery_blob_type:
cmd_args.extend(['--delivery-blob-type', args.delivery_blob_type])
cmd_args.append(dirs['root'])
subprocess.run(cmd_args, check=True)
def main(args):
with tempfile.TemporaryDirectory(
dir=os.path.dirname(args.output)) as gendir:
dirs = prepare_dirs(gendir)
# Prepare for `package-tool repository publish` and gather deps associated with preparations.
prepare_publish(args, dirs)
depfile = os.path.join(gendir, 'deps')
# Invoke `package-tool repository publish` and gather deps associated with invocation.
package_tool_publish(args, dirs, depfile)
# Output repository directory to zip file.
with zipfile.ZipFile(args.output, 'w',
zipfile.ZIP_DEFLATED) as zip_file:
zip_dir(dirs['repository'], zip_file)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
'Creates a zip archive of the TUF repository output by `package-tool repository publish`'
)
parser.add_argument(
'--package-tool',
help='path to the package-tool executable',
required=True)
parser.add_argument(
'--trusted-keys',
help=
'path to a keys directory to be consumed by `package-tool repository publish`'
)
parser.add_argument(
'--root-metadata',
help='path to a root metadata file to be used in the TUF repository',
action='append')
parser.add_argument(
'--default-root-metadata',
help='path to the default TUF root metadata file',
required=True)
parser.add_argument(
'--input',
help='path to `package-tool repository publish` file input',
required=True)
parser.add_argument(
'--delivery-blob-type', help='the type of delivery blob to generate')
parser.add_argument('--depfile', help='generate a depfile', required=True)
parser.add_argument('--output', help='path output zip file', required=True)
main(parser.parse_args())