blob: 621e1ecf0d46e5967dc8483a48159aefe973d778 [file] [log] [blame]
#!/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.
"""
Script to extract line-separated cache package paths with image_assembly.json from `ffx assembly product`.
"""
import argparse
import json
import os
import sys
from pathlib import Path
def _rebase_bazel_path(path: str, rebase_prefix: str) -> str:
"""Rebase paths relative to the Bazel execroot if needed.
This also takes care of paths that belong to the @gn_targets
repository. Because the content of this repository is regenerated
on every bazel_action() command launched from Ninja, these paths
may be dangling symlinks. However, they are intentionally formatted
in a way that allows extracting the corresponding Ninja path.
These can appear in two ways:
- Directly as a |path| value that starts with `external/gn_targets/`, e.g.:
external/gn_targets/src/foo/_files/obj/src/foo/cmd
- As a Bazel path to a symlink that points to an absolute path within
the Bazel {OUTPUT_BASE}/external/gn_targets/ repository, e.g.:
bazel-out/k8-fastbuild/bin/src/foo/cmd
--symlink-->
/work/out/default/gen/build/bazel/output_base/external/gn_targets/src/foo/_files/obj/src/foo/cmd
In both cases, keeping the path components that follow the `/_files/` one gets the
correct result (relative to the Ninja build dir, i.e. the current directory).
Args:
path: Input package path, relative to rebase_prefix.
rebase_prefix: Either an empty string, or a path prefix to the output base
that must contain a trailing separator.
Returns:
new path, relative to the current directory.
"""
rebased_path = rebase_prefix + path
if os.path.islink(rebased_path):
path = os.readlink(rebased_path)
_, external_gn_targets, suffix = path.partition("external/gn_targets/")
if external_gn_targets:
_, files, ninja_path = suffix.partition("/_files/")
assert files, f"Unexpected @gn_targets path: {path}"
return ninja_path
return rebased_path
def main():
parser = argparse.ArgumentParser(
description="Parse assembly product output manifest to get packages for a particular package set."
)
parser.add_argument(
"--assembly-manifest",
type=argparse.FileType("r"),
required=True,
help="Path to image_assembly.json created by `ffx assembly product`.",
)
parser.add_argument(
"--package-set",
required=True,
help="Package set to get the packages for",
)
parser.add_argument(
"--bazel-execroot",
required=False,
help="Optionally rebase the package manifest paths relative to the Bazel execroot, from the assembly manifest.",
)
parser.add_argument(
"--output",
required=True,
help="Path to which to write desired output list.",
)
args = parser.parse_args()
assert not args.bazel_execroot or os.path.isdir(
args.bazel_execroot
), "--bazel-execroot needs to specify a valid directory path!"
rebase_prefix = (
args.bazel_execroot.rstrip("/") + "/" if args.bazel_execroot else ""
)
assembly_manifest = json.load(args.assembly_manifest)
package_manifests = [
(
# Normalize the rebased path to remove any internal ../..'s.
os.path.normpath(_rebase_bazel_path(package, rebase_prefix))
)
for package in assembly_manifest[args.package_set]
]
Path(args.output).write_text(
json.dumps(
{
"content": {"manifests": package_manifests},
"version": "1",
},
indent=2,
)
)
return 0
if __name__ == "__main__":
sys.exit(main())