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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
|
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import json
import pathlib
import urllib.request as url_lib
import nox
def _install_requirements(session: nox.Session):
session.install(
"-r",
"./packages/python/requirements.txt",
"-r",
"./requirements.txt",
)
session.run("pip", "list")
@nox.session()
def tests(session: nox.Session):
"""Run tests for generator and generated code in python."""
_install_requirements(session)
session.log("Running test data generator.")
session.run("python", "-m", "generator", "--plugin", "testdata")
session.log("Running tests: generator and generated Python code.")
session.run("pytest", "./tests")
@nox.session()
def coverage(session: nox.Session):
"""Run coverage for generator and generated code in python."""
_install_requirements(session)
session.install("pytest-cov")
session.log("Running test data generator.")
session.run("python", "-m", "generator", "--plugin", "testdata")
session.log("Running coverage: generator and generated Python code.")
session.run("pytest", "--cov=lsprotocol", "./tests")
@nox.session()
def lint(session: nox.Session):
"""Linting for generator and generated code in all languages."""
_install_requirements(session)
session.log("Linting: generator and generated Python code.")
session.install("mypy", "ruff")
session.run("ruff", "--version")
session.run("mypy", "--version")
session.run("ruff", "format", "--check", ".")
session.run("mypy", "--strict", "--no-incremental", "./packages/python/lsprotocol")
session.log("Linting: generated Rust code.")
with session.chdir("./packages/rust/lsprotocol"):
session.run("cargo", "fmt", "--check", external=True)
@nox.session()
def format(session: nox.Session):
"""Format generator and lsprotocol package for PyPI."""
_install_requirements(session)
_format_code(session)
def _format_code(session: nox.Session):
session.install("ruff")
session.run("ruff", "--version")
session.run("ruff", "format", ".")
@nox.session()
def build_python_package(session: nox.Session):
"""Build lsprotocol (python) package for PyPI."""
session.install("flit")
with session.chdir("./packages/python"):
session.run("flit", "build")
def _get_content(uri) -> str:
with url_lib.urlopen(uri) as response:
content = response.read()
if isinstance(content, str):
return content
else:
return content.decode("utf-8")
MODEL_SCHEMA = "https://raw.githubusercontent.com/microsoft/vscode-languageserver-node/main/protocol/metaModel.schema.json"
MODEL = "https://raw.githubusercontent.com/microsoft/vscode-languageserver-node/main/protocol/metaModel.json"
def _download_models(session: nox.Session):
session.log("Downloading LSP model schema.")
model_schema_text: str = _get_content(MODEL_SCHEMA)
session.log("Downloading LSP model.")
model_text: str = _get_content(MODEL)
schema_path = pathlib.Path(__file__).parent / "generator" / "lsp.schema.json"
model_path = schema_path.parent / "lsp.json"
schema_path.write_text(
json.dumps(json.loads(model_schema_text), indent=4, ensure_ascii=False) + "\n",
encoding="utf-8",
)
model_path.write_text(
json.dumps(json.loads(model_text), indent=4, ensure_ascii=False) + "\n",
encoding="utf-8",
)
@nox.session()
def build_lsp(session: nox.Session):
"""Generate lsprotocol for all languages."""
generate_python(session)
generate_dotnet(session)
generate_rust(session)
@nox.session()
def update_lsp(session: nox.Session):
"""Update the LSP model and generate the lsprotocol for all languages."""
update_packages(session)
_download_models(session)
build_lsp(session)
@nox.session()
def update_packages(session: nox.Session):
"""Update dependencies of generator and lsprotocol."""
session.install("wheel", "pip-tools")
session.run(
"pip-compile",
"--generate-hashes",
"--resolver=backtracking",
"--upgrade",
"./packages/python/requirements.in",
)
session.run(
"pip-compile",
"--generate-hashes",
"--resolver=backtracking",
"--upgrade",
"./requirements.in",
)
@nox.session()
def create_plugin(session: nox.Session):
"""Create a new plugin."""
name = input("Enter the name of the plugin: ")
plugin_root = pathlib.Path(__file__).parent / "generator" / "plugins" / name
plugin_root.mkdir(parents=True, exist_ok=True)
init_text = "\n".join(
[
"# Copyright (c) Microsoft Corporation. All rights reserved.",
"# Licensed under the MIT License.",
"",
f"from .{name}_utils import generate_from_spec as generate",
"",
]
)
plugin_root.joinpath("__init__.py").write_text(init_text, encoding="utf-8")
utils_text = "\n".join(
[
"# Copyright (c) Microsoft Corporation. All rights reserved.",
"# Licensed under the MIT License.",
"",
"import pathlib",
"from typing import List, Dict",
"",
"import generator.model as model",
"",
"",
'PACKAGE_DIR_NAME = "lsprotocol"',
"",
"",
"def generate_from_spec(spec: model.LSPModel, output_dir: str) -> None:",
' """Generate the code for the given spec."""',
" # key is the relative path to the file, value is the content",
" code: Dict[str, str] = generate_package_code(spec)",
" for file_name in code:",
" pathlib.Path(output_dir, PACKAGE_DIR_NAME, file_name).write_text(",
' code[file_name], encoding="utf-8"',
" )",
"",
"def generate_package_code(spec: model.LSPModel) -> List[str]:",
" return {",
' "src/lib.rs": "code for lib.rs",',
" }",
"",
]
)
plugin_root.joinpath(f"{name}_utils.py").write_text(utils_text, encoding="utf-8")
package_root = pathlib.Path(__file__).parent / "packages" / name / "lsprotocol"
package_root.mkdir(parents=True, exist_ok=True)
package_root.joinpath("README.md").write_text(
"# your generated code and other package files go under this directory.",
encoding="utf-8",
)
tests_root = pathlib.Path(__file__).parent / "tests" / name
tests_root.mkdir(parents=True, exist_ok=True)
tests_root.joinpath("README.md").write_text(
"# your tests go under this directory.", encoding="utf-8"
)
launch_json_path = pathlib.Path(__file__).parent / ".vscode" / "launch.json"
launch_json = json.loads(launch_json_path.read_text(encoding="utf-8"))
for i in launch_json["inputs"]:
if i["id"] == "plugin":
i["options"].append(name)
launch_json_path.write_text(json.dumps(launch_json, indent=4), encoding="utf-8")
session.log(f"Created plugin {name}.")
@nox.session()
def generate_dotnet(session: nox.Session):
"""Update the dotnet code."""
_install_requirements(session)
session.run("python", "-m", "generator", "--plugin", "dotnet")
with session.chdir("./packages/dotnet/lsprotocol"):
session.run("dotnet", "format", external=True)
session.run("dotnet", "build", external=True)
@nox.session()
def generate_python(session: nox.Session):
"""Update the python code."""
_install_requirements(session)
session.run("python", "-m", "generator", "--plugin", "python")
_format_code(session)
@nox.session()
def generate_rust(session: nox.Session):
"""Update the rust code."""
_install_requirements(session)
session.run("python", "-m", "generator", "--plugin", "rust")
with session.chdir("./packages/rust/lsprotocol"):
session.run("cargo", "fmt", external=True)
with session.chdir("./tests/rust"):
session.run("cargo", "fmt", external=True)
session.run("cargo", "build", external=True)
|