| #!/usr/bin/env python3.8 |
| # 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(fxbug.dev/56428): 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()) |