| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2020 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. |
| """Reads the contents of a package config file generated by the build and |
| converts it to a real package_config.json file |
| """ |
| |
| import argparse |
| import collections |
| import json |
| import os |
| import re |
| import sys |
| |
| DEFAULT_LANGUAGE_VERSION = "2.8" |
| |
| Package = collections.namedtuple( |
| "Package", ["name", "rootUri", "languageVersion", "packageUri"] |
| ) |
| |
| |
| class PackageConfig: |
| # The version of the package config. |
| VERSION = 2 |
| |
| # The name of the generator which gets written to the json output |
| GENERATOR_NAME = os.path.basename(__file__) |
| |
| def __init__(self, packages): |
| self.packages = packages |
| |
| def asdict(self): |
| """Converts the package config to a dictionary""" |
| return { |
| "configVersion": self.VERSION, |
| "packages": [p._asdict() for p in sorted(self.packages)], |
| "generator": self.GENERATOR_NAME, |
| } |
| |
| |
| def language_version_from_pubspec(pubspec): |
| """parse the content of a pubspec.yaml""" |
| import yaml |
| |
| with open(pubspec) as pubspec: |
| parsed = yaml.safe_load(pubspec) |
| if not parsed: |
| return DEFAULT_LANGUAGE_VERSION |
| |
| # If a format like sdk: '>=a.b' or sdk: 'a.b' is found, we'll use a.b. |
| # In all other cases we default to "2.8" |
| env_sdk = parsed.get("environment", {}).get("sdk", "any") |
| match = re.search(r"^(>=)?((0|[1-9]\d*)\.(0|[1-9]\d*))", env_sdk) |
| if match: |
| min_sdk_version = match.group(2) |
| else: |
| min_sdk_version = DEFAULT_LANGUAGE_VERSION |
| |
| return min_sdk_version |
| |
| |
| def collect_packages(items, relative_to): |
| """Reads metadata produced by GN to create lists of packages and pubspecs. |
| - items: a list of objects collected from gn |
| - relative_to: The directory which the packages are relative to. This is |
| the location that contains the package_config.json file |
| |
| Returns None if there was a problem parsing packages |
| """ |
| packages = [] |
| pubspec_paths = [] |
| for item in items: |
| if "language_version" in item: |
| language_version = item["language_version"] |
| elif "pubspec_path" in item: |
| pubspec_paths.append(item["pubspec_path"]) |
| language_version = language_version_from_pubspec( |
| item["pubspec_path"] |
| ) |
| else: |
| language_version = DEFAULT_LANGUAGE_VERSION |
| |
| package = Package( |
| name=item["name"], |
| rootUri=os.path.relpath(item["root_uri"], relative_to), |
| languageVersion=language_version, |
| packageUri=item["package_uri"], |
| ) |
| |
| # TODO(https://fxbug.dev/42134166): enable once we sort out our duplicate packages |
| # for p in packages: |
| # if p.rootUri == package.rootUri: |
| # print('Failed to create package_config.json file') |
| # print('The following packages contain the same package root ' + p.rootUri) |
| # print(' - ' + p.rootUri) |
| # print(' - ' + package.rootUri) |
| # return None |
| |
| packages.append(package) |
| |
| return packages, pubspec_paths |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument( |
| "--input", help="Path to original package_config", required=True |
| ) |
| parser.add_argument( |
| "--output", help="Path to the updated package_config", required=True |
| ) |
| parser.add_argument("--root", help="Path to fuchsia root", required=True) |
| parser.add_argument("--depfile", help="Path to the depfile", required=True) |
| args = parser.parse_args() |
| |
| sys.path += [os.path.join(args.root, "third_party", "pyyaml", "lib3")] |
| |
| with open(args.input, "r") as input_file: |
| contents = json.load(input_file) |
| |
| output_dir = os.path.dirname(os.path.abspath(args.output)) |
| packages, pubspec_paths = collect_packages(contents, output_dir) |
| if packages is None: |
| return 1 |
| |
| with open(args.depfile, "w") as depfile: |
| depfile.write("%s: %s" % (args.output, " ".join(pubspec_paths))) |
| |
| with open(args.output, "w") as output_file: |
| package_config = PackageConfig(packages) |
| json.dump( |
| package_config.asdict(), |
| output_file, |
| indent=2, |
| sort_keys=True, |
| separators=(",", ": "), |
| ) |
| |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |