1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import argparse
import importlib
import json
import logging
import os
import pathlib
import sys
from typing import Sequence
import importlib_resources as ir
import jsonschema
from . import model
PACKAGES_ROOT = pathlib.Path(__file__).parent.parent / "packages"
TESTS_ROOT = pathlib.Path(__file__).parent.parent / "tests"
LOGGER = logging.getLogger("generator")
def setup_logging() -> None:
logging.basicConfig(
stream=sys.stdout,
level=logging.DEBUG,
format="[%(levelname)s][%(asctime)s] %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
def get_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Generate types from LSP JSON model.")
parser.add_argument(
"--model",
"-m",
help="Path to a model JSON file. By default uses packaged model file.",
type=str,
nargs="*",
)
parser.add_argument(
"--plugin",
"-p",
help="Name of a builtin plugin module. By default uses all plugins.",
type=str,
required=True,
)
parser.add_argument(
"--output-dir",
"-o",
help="Path to a directory where the generated content is written.",
type=str,
)
parser.add_argument(
"--test-dir",
"-t",
help="Path to a directory where the generated tests are written.",
type=str,
)
return parser
def custom_plugin(plugin: str) -> None:
LOGGER.info(f"Loading plugin: {plugin}.")
try:
plugin_module = importlib.import_module(plugin)
except ImportError:
LOGGER.info(f"Loading plugin: generator.plugins.{plugin}.")
plugin_module = importlib.import_module(f"generator.plugins.{plugin}")
return plugin_module
def main(argv: Sequence[str]) -> None:
parser = get_parser()
args = parser.parse_args(argv)
# Validate against LSP model JSON schema.
schema_file = ir.files("generator") / "lsp.schema.json"
LOGGER.info("Using schema file %s", os.fspath(schema_file))
schema = json.load(schema_file.open("rb"))
if args.model:
model_files = [pathlib.Path(m) for m in args.model]
else:
model_files = [ir.files("generator") / "lsp.json"]
json_models = []
for model_file in model_files:
LOGGER.info("Validating model file %s", os.fspath(model_file))
json_model = json.load(model_file.open("rb"))
jsonschema.validate(json_model, schema)
json_models.append(json_model)
plugin = args.plugin
LOGGER.info(f"Running plugin {plugin}.")
output_dir = args.output_dir or os.fspath(PACKAGES_ROOT / plugin)
test_dir = args.test_dir or os.fspath(TESTS_ROOT / plugin)
LOGGER.info(f"Writing output to {output_dir}")
# load model and generate types for each plugin to avoid
# any conflicts between plugins.
spec: model.LSPModel = model.create_lsp_model(json_models)
try:
plugin_module = custom_plugin(plugin)
LOGGER.info(f"Running plugin: {plugin}.")
plugin_module.generate(spec, output_dir, test_dir)
LOGGER.info(f"Plugin {plugin} completed.")
except Exception as e:
LOGGER.error(f"Error running plugin {plugin}:", exc_info=e)
raise e
if __name__ == "__main__":
setup_logging()
main(sys.argv[1:])
|