|  | #!/usr/bin/env python3 | 
|  | # | 
|  | # 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. | 
|  | """ | 
|  | generate fidl_project.json file declaring FIDL libraries | 
|  |  | 
|  | The first command line argument is the root $FUCHSIA_DIR. | 
|  | The second command line argument is the path to generated_sources.json. | 
|  | The third command line argument is the path to which the script will write | 
|  | fidl_project.json. | 
|  |  | 
|  | This script reads the generated_sources.json file which contains the paths to | 
|  | fidlc-generated JSON IR, and generates a fidl_project.json file which declares | 
|  | all FIDL libraries along with their constituent files, dependencies, and build | 
|  | artifacts (JSON IR and bindings). This is for use in the FIDL Language Server, | 
|  | which uses fidl_project to do dependency resolution. | 
|  | """ | 
|  |  | 
|  | import glob | 
|  | import json | 
|  | import os | 
|  | import re | 
|  | import sys | 
|  | from pathlib import Path | 
|  |  | 
|  | # fidl_project.json schema: list of Library | 
|  | # where Library is | 
|  | # { | 
|  | #     "name": string, | 
|  | #     "files": []string, | 
|  | #     "json": string, | 
|  | #     "deps": []string, | 
|  | #     "bindings": { | 
|  | #         "hlcpp": {}, | 
|  | #         "llcpp": {}, | 
|  | #         "rust": {}, | 
|  | #         "go": {}, | 
|  | #         "dart": {}, | 
|  | #         ... | 
|  | #     } | 
|  | # } | 
|  |  | 
|  | # https://fuchsia.dev/fuchsia-src/development/languages/fidl/reference/language.md#identifiers | 
|  | identifier_pattern = r'[a-zA-Z](?:[a-zA-Z0-9_]*[a-zA-Z0-9])?' | 
|  |  | 
|  | # Although "library" can be used anywhere (e.g. as a type name), this regex | 
|  | # is robust because the the library declaration must appear at the top of | 
|  | # the file (only comments and whitespace can precede it). | 
|  | library_pattern = ( | 
|  | r'^(?:\s*//[^\n]*\n)*\s*' + | 
|  | r'library\s+(' + | 
|  | identifier_pattern + | 
|  | r'(?:\.' + identifier_pattern + r')*' + | 
|  | r')\s*;' | 
|  | ) | 
|  |  | 
|  | def find_files(library_name, library_json, fuchsia_dir=""): | 
|  | pattern = r'^fidling\/gen\/([\w\.\/-]+)\/[\w\-. ]+\.fidl\.json$' | 
|  | result = re.search(pattern, library_json) | 
|  | if not result or not result.group(1): | 
|  | return [] | 
|  |  | 
|  | fidl_dir = Path(f'{fuchsia_dir}/{result.group(1)}') | 
|  | globs = [ | 
|  | fidl_dir.glob('*.fidl'), | 
|  | fidl_dir.parent.glob('*.fidl'), | 
|  | ] | 
|  |  | 
|  | files = [] | 
|  | for glob in globs: | 
|  | for file in glob: | 
|  | # Read in FIDL file | 
|  | with open(file, 'r') as f: | 
|  | # Parse `library` decl | 
|  | result = re.search(library_pattern, f.read()) | 
|  | # Check that it matches library name | 
|  | if not result or not result.group(1): | 
|  | continue | 
|  | if result.group(1) != library_name: | 
|  | continue | 
|  | files.append(str(file)) | 
|  | return files | 
|  |  | 
|  |  | 
|  | def find_deps(library_json, fuchsia_dir=""): | 
|  | library_json_path = Path(f'{fuchsia_dir}/out/default/{library_json}') | 
|  |  | 
|  | if not os.path.isfile(library_json_path): | 
|  | return None | 
|  |  | 
|  | with open(library_json_path, 'r') as f: | 
|  | library = json.load(f) | 
|  | deps = library['library_dependencies'] | 
|  | deps = [dep['name'] for dep in deps] | 
|  | return deps | 
|  |  | 
|  |  | 
|  | def gen_fidl_project(fuchsia_dir="", generated_sources_path="", fidl_project_path=""): | 
|  | result = [] | 
|  | with open(generated_sources_path, 'r') as f: | 
|  | artifacts = json.load(f) | 
|  |  | 
|  | processed = set() | 
|  | for artifact in artifacts: | 
|  | if artifact in processed: | 
|  | continue | 
|  |  | 
|  | if not artifact.endswith('.fidl.json'): | 
|  | continue | 
|  |  | 
|  | deps = find_deps(artifact, fuchsia_dir=fuchsia_dir) | 
|  | if deps is None: | 
|  | continue | 
|  |  | 
|  | # Get JSON filename out of artifact | 
|  | library_name = os.path.basename(artifact) | 
|  | # Remove .fidl.json suffix | 
|  | library_name = library_name[:-10] | 
|  |  | 
|  | processed.add(artifact) | 
|  | result.append({ | 
|  | 'name': library_name, | 
|  | 'json': f"{fuchsia_dir}/out/default/{artifact}", | 
|  | 'files': find_files(library_name, artifact, fuchsia_dir=fuchsia_dir), | 
|  | 'deps': deps, | 
|  | 'bindings': {},  # TODO | 
|  | }) | 
|  |  | 
|  | with open(fidl_project_path, 'w') as f: | 
|  | json.dump(result, f, indent=4, sort_keys=True) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | if len(sys.argv) < 4: | 
|  | print('Please run this script as:') | 
|  | print('  fx exec scripts/generate-fidl-project.py <root/build/dir> <generated_sources.json> <fidl_project.json>') | 
|  | sys.exit(1) | 
|  |  | 
|  | gen_fidl_project( | 
|  | fuchsia_dir=sys.argv[1], | 
|  | generated_sources_path=sys.argv[2], | 
|  | fidl_project_path=sys.argv[3], | 
|  | ) |