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