blob: 3c34c5473f5142000c2e4444c580f56aa276c0a7 [file] [log] [blame]
#!/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/42153728.
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())