blob: d499e00fa8e04ac5562bfa21a5862a785c5d9a39 [file] [log] [blame] [edit]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2022 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 json
import os
import sys
from assembly import FilePath, PackageManifest
from depfile import DepFile
from serialization import json_load
def get_relative_path(relative_path: str, relative_to_file: str) -> str:
file_parent = os.path.dirname(relative_to_file)
path = os.path.join(file_parent, relative_path)
path = os.path.relpath(path, os.getcwd())
return path
def add_inputs_from_packages(
package_paths: set[FilePath],
all_manifest_paths: set[FilePath],
inputs: list[FilePath],
in_subpackage: bool = False,
) -> None:
anonymous_subpackages: set[FilePath] = set()
for manifest_path in package_paths:
inputs.append(manifest_path)
with open(manifest_path, "r") as f:
package_manifest = json_load(PackageManifest, f)
for blob in package_manifest.blobs:
blob_source = str(blob.source_path)
if package_manifest.blob_sources_relative == "file":
blob_source = get_relative_path(blob_source, str(manifest_path))
inputs.append(blob_source)
for subpackage in package_manifest.subpackages:
subpackage_path = str(subpackage.manifest_path)
if package_manifest.blob_sources_relative == "file":
subpackage_path = get_relative_path(
subpackage_path, str(manifest_path)
)
if not subpackage_path in all_manifest_paths:
anonymous_subpackages.add(subpackage_path)
all_manifest_paths.add(subpackage_path)
if anonymous_subpackages:
add_inputs_from_packages(
anonymous_subpackages,
all_manifest_paths,
inputs,
in_subpackage=True,
)
def main() -> int:
parser = argparse.ArgumentParser(
description="Generate a hermetic inputs file that includes the outputs of Assembly"
)
parser.add_argument(
"--partitions",
type=argparse.FileType("r"),
help="The partitions config that follows this schema: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/developer/ffx/plugins/assembly/#partitions-config",
)
parser.add_argument(
"--output",
required=True,
help="The location to write the hermetic inputs file",
)
parser.add_argument(
"--system",
nargs="*",
help="A list of system image manifests that follow this schema: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/developer/ffx/plugins/assembly/#images-manifest",
)
parser.add_argument(
"--depfile",
help="A depfile listing all the files opened by this script",
)
args = parser.parse_args()
# A list of files opened by this script.
deps: set[FilePath] = set()
# A list of the implicit inputs.
inputs = []
# Add all the bootloaders as inputs.
if args.partitions:
inputs.append(args.partitions.name)
partitions = json.load(args.partitions)
base_dir = os.path.dirname(args.partitions.name)
for bootloader in partitions.get("bootloader_partitions", []):
inputs.append(os.path.join(base_dir, bootloader["image"]))
for bootstrap in partitions.get("bootstrap_partitions", []):
inputs.append(os.path.join(base_dir, bootstrap["image"]))
for credential in partitions.get("unlock_credentials", []):
inputs.append(os.path.join(base_dir, credential))
# Add all the system images as inputs.
package_manifest_paths: set[FilePath] = set()
for image_manifest_dir in args.system:
image_manifest_path = image_manifest_dir + "/assembled_system.json"
deps.add(image_manifest_path)
with open(image_manifest_path, "r") as f:
image_manifest = json.load(f)
for image in image_manifest["images"]:
inputs.append(os.path.join(image_manifest_dir, image["path"]))
# Collect the package manifests from the blobfs/Fxblob image.
if (image["type"] == "blk" and image["name"] == "blob") or (
image["type"] == "blk" and image["name"] == "fxfs.fastboot"
):
packages = []
packages.extend(
image["contents"]["packages"].get("base", [])
)
packages.extend(
image["contents"]["packages"].get("cache", [])
)
package_manifest_paths.update(
[
os.path.join(
image_manifest_dir, package["manifest"]
)
for package in packages
]
)
# Add all the bootloaders as inputs.
if "partitions_config" in image_manifest:
partitions_config_dir = (
image_manifest_dir
+ "/"
+ image_manifest["partitions_config"]
)
partitions_config_path = (
partitions_config_dir + "/partitions_config.json"
)
deps.add(partitions_config_path)
with open(partitions_config_path, "r") as f:
partitions = json.load(f)
for bootloader in partitions.get(
"bootloader_partitions", []
):
inputs.append(
os.path.join(
partitions_config_dir, bootloader["image"]
)
)
for bootstrap in partitions.get("bootstrap_partitions", []):
inputs.append(
os.path.join(
partitions_config_dir, bootstrap["image"]
)
)
for credential in partitions.get("unlock_credentials", []):
inputs.append(
os.path.join(partitions_config_dir, credential)
)
# If we collected any package manifests, include all the blobs referenced
# by them.
all_manifest_paths: set[FilePath] = set(package_manifest_paths)
add_inputs_from_packages(
package_manifest_paths,
all_manifest_paths,
inputs,
)
deps.update(all_manifest_paths)
# Write the hermetic inputs file.
with open(args.output, "w") as f:
f.writelines(f"{input}\n" for input in sorted(inputs))
# Write the depfile.
if args.depfile:
with open(args.depfile, "w") as f:
DepFile.from_deps(args.output, deps).write_to(f)
return 0
if __name__ == "__main__":
sys.exit(main())