| #!/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], |
| ) |