Refine runtime dependency helpers (#286)

This commit is contained in:
Dominik Jain
2025-07-06 22:10:11 +02:00
committed by GitHub
parent aa0c0e5373
commit bb595eb7e7
9 changed files with 334 additions and 287 deletions
@@ -12,6 +12,7 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -47,58 +48,44 @@ class ClangdLanguageServer(SolidLanguageServer):
"""
platform_id = PlatformUtils.get_platform_id()
runtime_dependencies = [
{
"id": "Clangd",
"description": "Clangd for Linux (x64)",
"url": "https://github.com/clangd/clangd/releases/download/19.1.2/clangd-linux-19.1.2.zip",
"platformId": "linux-x64",
"archiveType": "zip",
"binaryName": "clangd",
},
{
"id": "Clangd",
"description": "Clangd for Windows (x64)",
"url": "https://github.com/clangd/clangd/releases/download/19.1.2/clangd-windows-19.1.2.zip",
"platformId": "win-x64",
"archiveType": "zip",
"binaryName": "clangd.exe",
},
{
"id": "Clangd",
"description": "Clangd for macOS (Arm64)",
"url": "https://github.com/clangd/clangd/releases/download/19.1.2/clangd-mac-19.1.2.zip",
"platformId": "osx-arm64",
"archiveType": "zip",
"binaryName": "clangd",
},
]
assert platform_id.value in [
"linux-x64",
"win-x64",
"osx-arm64",
], (
"Unsupported platform: " + platform_id.value
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
id="Clangd",
description="Clangd for Linux (x64)",
url="https://github.com/clangd/clangd/releases/download/19.1.2/clangd-linux-19.1.2.zip",
platform_id="linux-x64",
archive_type="zip",
binary_name="clangd_19.1.2/bin/clangd",
),
RuntimeDependency(
id="Clangd",
description="Clangd for Windows (x64)",
url="https://github.com/clangd/clangd/releases/download/19.1.2/clangd-windows-19.1.2.zip",
platform_id="win-x64",
archive_type="zip",
binary_name="clangd_19.1.2/bin/clangd.exe",
),
RuntimeDependency(
id="Clangd",
description="Clangd for macOS (Arm64)",
url="https://github.com/clangd/clangd/releases/download/19.1.2/clangd-mac-19.1.2.zip",
platform_id="osx-arm64",
archive_type="zip",
binary_name="clangd_19.1.2/bin/clangd",
),
]
)
runtime_dependencies = [dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value]
assert len(runtime_dependencies) == 1
# Select dependency matching the current platform
dependency = next((dep for dep in runtime_dependencies if dep["platformId"] == platform_id.value), None)
if dependency is None:
raise RuntimeError(f"No runtime dependency found for platform {platform_id.value}")
clangd_ls_dir = os.path.join(os.path.dirname(__file__), "static", "clangd")
clangd_executable_path = os.path.join(clangd_ls_dir, "clangd_19.1.2", "bin", dependency["binaryName"])
dep = deps.single_for_current_platform()
clangd_executable_path = deps.binary_path(clangd_ls_dir)
if not os.path.exists(clangd_executable_path):
clangd_url = dependency["url"]
logger.log(f"Clangd executable not found at {clangd_executable_path}. Downloading from {clangd_url}", logging.INFO)
os.makedirs(clangd_ls_dir, exist_ok=True)
if dependency["archiveType"] == "zip":
FileUtils.download_and_extract_archive(logger, clangd_url, clangd_ls_dir, dependency["archiveType"])
else:
raise RuntimeError(f"Unsupported archive type: {dependency['archiveType']}")
logger.log(
f"Clangd executable not found at {clangd_executable_path}. Downloading from {dep.url}",
logging.INFO,
)
deps.install(logger, clangd_ls_dir)
if not os.path.exists(clangd_executable_path):
raise FileNotFoundError(
f"Clangd executable not found at {clangd_executable_path}.\n"
+41 -37
View File
@@ -14,6 +14,7 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -44,32 +45,38 @@ class ClojureLSP(SolidLanguageServer):
"""
clojure_lsp_releases = "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download"
runtime_dependencies = [
{
"url": f"{clojure_lsp_releases}/clojure-lsp-native-macos-aarch64.zip",
"platformId": "osx-arm64",
"archiveType": "zip",
"binaryName": "clojure-lsp",
},
{
"url": f"{clojure_lsp_releases}/clojure-lsp-native-linux-aarch64.zip",
"platformId": "linux-arm64",
"archiveType": "zip",
"binaryName": "clojure-lsp",
},
{
"url": f"{clojure_lsp_releases}/clojure-lsp-native-linux-amd64.zip",
"platformId": "linux-x64",
"archiveType": "zip",
"binaryName": "clojure-lsp",
},
{
"url": f"{clojure_lsp_releases}/clojure-lsp-native-windows-amd64.zip",
"platformId": "win-x64",
"archiveType": "zip",
"binaryName": "clojure-lsp.exe",
},
]
runtime_dependencies = RuntimeDependencyCollection(
[
RuntimeDependency(
id="clojure-lsp",
url=f"{clojure_lsp_releases}/clojure-lsp-native-macos-aarch64.zip",
platform_id="osx-arm64",
archive_type="zip",
binary_name="clojure-lsp",
),
RuntimeDependency(
id="clojure-lsp",
url=f"{clojure_lsp_releases}/clojure-lsp-native-linux-aarch64.zip",
platform_id="linux-arm64",
archive_type="zip",
binary_name="clojure-lsp",
),
RuntimeDependency(
id="clojure-lsp",
url=f"{clojure_lsp_releases}/clojure-lsp-native-linux-amd64.zip",
platform_id="linux-x64",
archive_type="zip",
binary_name="clojure-lsp",
),
RuntimeDependency(
id="clojure-lsp",
url=f"{clojure_lsp_releases}/clojure-lsp-native-windows-amd64.zip",
platform_id="win-x64",
archive_type="zip",
binary_name="clojure-lsp.exe",
),
]
)
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
@@ -92,21 +99,18 @@ class ClojureLSP(SolidLanguageServer):
def _setup_runtime_dependencies(logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
"""Setup runtime dependencies for clojure-lsp and return the command to start the server."""
verify_clojure_cli()
platform_id = PlatformUtils.get_platform_id()
runtime_dependencies = [
dependency for dependency in ClojureLSP.runtime_dependencies if dependency["platformId"] == platform_id.value
]
if len(runtime_dependencies) != 1:
raise RuntimeError(f"Could not find a suitable clojure-lsp runtime dependency for platform {platform_id.value}.")
dependency = runtime_dependencies[0]
deps = ClojureLSP.runtime_dependencies
dependency = deps.single_for_current_platform()
clojurelsp_ls_dir = os.path.join(os.path.dirname(__file__), "static", "clojure-lsp")
clojurelsp_executable_path = os.path.join(clojurelsp_ls_dir, dependency["binaryName"])
clojurelsp_executable_path = deps.binary_path(clojurelsp_ls_dir)
if not os.path.exists(clojurelsp_executable_path):
os.makedirs(clojurelsp_ls_dir, exist_ok=True)
logger.log(f"Downloading and extracting clojure-lsp from {dependency['url']} to {clojurelsp_ls_dir}", logging.INFO)
FileUtils.download_and_extract_archive(logger, dependency["url"], clojurelsp_ls_dir, dependency["archiveType"])
logger.log(
f"Downloading and extracting clojure-lsp from {dependency.url} to {clojurelsp_ls_dir}",
logging.INFO,
)
deps.install(logger, clojurelsp_ls_dir)
if not os.path.exists(clojurelsp_executable_path):
raise FileNotFoundError(f"Download failed? Could not find clojure-lsp executable at {clojurelsp_executable_path}")
os.chmod(clojurelsp_executable_path, stat.S_IEXEC)
+107
View File
@@ -0,0 +1,107 @@
from __future__ import annotations
import os
import subprocess
from dataclasses import dataclass
from typing import Sequence, Dict
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
@dataclass(kw_only=True)
class RuntimeDependency:
"""Represents a runtime dependency for a language server."""
id: str
platform_id: str | None = None
url: str | None = None
archive_type: str | None = None
binary_name: str | None = None
command: str | None = None
package_name: str | None = None
package_version: str | None = None
extract_path: str | None = None
description: str | None = None
class RuntimeDependencyCollection:
"""Utility to handle installation of runtime dependencies."""
def __init__(self, dependencies: Sequence[RuntimeDependency]):
self._dependencies = list(dependencies)
def for_platform(self, platform_id: str) -> list[RuntimeDependency]:
return [
d
for d in self._dependencies
if d.platform_id in (platform_id, "any", "platform-agnostic", None)
]
def for_current_platform(self) -> list[RuntimeDependency]:
return self.for_platform(PlatformUtils.get_platform_id().value)
def single_for_current_platform(self) -> RuntimeDependency:
deps = self.for_current_platform()
if len(deps) != 1:
raise RuntimeError(
f"Expected exactly one runtime dependency for {PlatformUtils.get_platform_id().value}, found {len(deps)}"
)
return deps[0]
def binary_path(self, target_dir: str) -> str:
dep = self.single_for_current_platform()
if not dep.binary_name:
return target_dir
return os.path.join(target_dir, dep.binary_name)
def install(self, logger: LanguageServerLogger, target_dir: str) -> Dict[str, str]:
"""Install all dependencies for the current platform into *target_dir*.
Returns a mapping from dependency id to the resolved binary path.
"""
os.makedirs(target_dir, exist_ok=True)
results: Dict[str, str] = {}
for dep in self.for_current_platform():
if dep.url:
self._install_from_url(dep, logger, target_dir)
if dep.command:
self._run_command(dep.command, target_dir)
if dep.binary_name:
results[dep.id] = os.path.join(target_dir, dep.binary_name)
else:
results[dep.id] = target_dir
return results
@staticmethod
def _run_command(command: str, cwd: str) -> None:
if PlatformUtils.get_platform_id().value.startswith("win"):
subprocess.run(
command,
shell=True,
check=True,
cwd=cwd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
else:
import pwd
user = pwd.getpwuid(os.getuid()).pw_name
subprocess.run(
command,
shell=True,
check=True,
user=user,
cwd=cwd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
@staticmethod
def _install_from_url(dep: RuntimeDependency, logger: LanguageServerLogger, target_dir: str) -> None:
if dep.archive_type == "gz" and dep.binary_name:
dest = os.path.join(target_dir, dep.binary_name)
FileUtils.download_and_extract_archive(logger, dep.url, dest, dep.archive_type)
else:
FileUtils.download_and_extract_archive(logger, dep.url, target_dir, dep.archive_type or "zip")
@@ -13,10 +13,11 @@ import tarfile
import threading
import urllib.request
import zipfile
from dataclasses import dataclass
from pathlib import Path
from typing import cast
from .common import RuntimeDependency
from overrides import override
from solidlsp.ls import SolidLanguageServer
@@ -28,21 +29,6 @@ from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@dataclass(kw_only=True)
class RuntimeDependency:
"""Represents a runtime dependency for the C# language server."""
id: str
description: str | None
platform_id: str
archive_type: str
binary_name: str
package_name: str | None = None
package_version: str | None = None
extract_path: str | None = None
url: str | None = None
# Runtime dependencies configuration
RUNTIME_DEPENDENCIES = [
RuntimeDependency(
@@ -6,6 +6,7 @@ import stat
from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -31,60 +32,57 @@ class DartLanguageServer(SolidLanguageServer):
def _setup_runtime_dependencies(cls, logger: "LanguageServerLogger") -> str:
platform_id = PlatformUtils.get_platform_id()
runtime_dependencies = [
{
"id": "DartLanguageServer",
"description": "Dart Language Server for Linux (x64)",
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-linux-x64-release.zip",
"platformId": "linux-x64",
"archiveType": "zip",
"binaryName": "dart-sdk/bin/dart",
},
{
"id": "DartLanguageServer",
"description": "Dart Language Server for Windows (x64)",
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-windows-x64-release.zip",
"platformId": "win-x64",
"archiveType": "zip",
"binaryName": "dart-sdk/bin/dart.exe",
},
{
"id": "DartLanguageServer",
"description": "Dart Language Server for Windows (arm64)",
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-windows-arm64-release.zip",
"platformId": "win-arm64",
"archiveType": "zip",
"binaryName": "dart-sdk/bin/dart.exe",
},
{
"id": "DartLanguageServer",
"description": "Dart Language Server for macOS (x64)",
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-macos-x64-release.zip",
"platformId": "osx-x64",
"archiveType": "zip",
"binaryName": "dart-sdk/bin/dart",
},
{
"id": "DartLanguageServer",
"description": "Dart Language Server for macOS (arm64)",
"url": "https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-macos-arm64-release.zip",
"platformId": "osx-arm64",
"archiveType": "zip",
"binaryName": "dart-sdk/bin/dart",
},
]
runtime_dependencies = [dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value]
assert len(runtime_dependencies) == 1
dependency = runtime_dependencies[0]
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
id="DartLanguageServer",
description="Dart Language Server for Linux (x64)",
url="https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-linux-x64-release.zip",
platform_id="linux-x64",
archive_type="zip",
binary_name="dart-sdk/bin/dart",
),
RuntimeDependency(
id="DartLanguageServer",
description="Dart Language Server for Windows (x64)",
url="https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-windows-x64-release.zip",
platform_id="win-x64",
archive_type="zip",
binary_name="dart-sdk/bin/dart.exe",
),
RuntimeDependency(
id="DartLanguageServer",
description="Dart Language Server for Windows (arm64)",
url="https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-windows-arm64-release.zip",
platform_id="win-arm64",
archive_type="zip",
binary_name="dart-sdk/bin/dart.exe",
),
RuntimeDependency(
id="DartLanguageServer",
description="Dart Language Server for macOS (x64)",
url="https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-macos-x64-release.zip",
platform_id="osx-x64",
archive_type="zip",
binary_name="dart-sdk/bin/dart",
),
RuntimeDependency(
id="DartLanguageServer",
description="Dart Language Server for macOS (arm64)",
url="https://storage.googleapis.com/dart-archive/channels/stable/release/3.7.1/sdk/dartsdk-macos-arm64-release.zip",
platform_id="osx-arm64",
archive_type="zip",
binary_name="dart-sdk/bin/dart",
),
]
)
dart_ls_dir = cls.ls_resources_dir()
dart_executable_path = os.path.join(dart_ls_dir, dependency["binaryName"])
dart_executable_path = deps.binary_path(dart_ls_dir)
if not os.path.exists(dart_ls_dir):
os.makedirs(dart_ls_dir)
FileUtils.download_and_extract_archive(logger, dependency["url"], dart_ls_dir, dependency["archiveType"])
deps.install(logger, dart_ls_dir)
assert os.path.exists(dart_executable_path)
os.chmod(dart_executable_path, stat.S_IEXEC)
+11 -26
View File
@@ -15,6 +15,7 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import PlatformId, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.lsp_types import DefinitionParams, InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -61,32 +62,16 @@ class Intelephense(SolidLanguageServer):
os.makedirs(intelephense_ls_dir, exist_ok=True)
intelephense_executable_path = os.path.join(intelephense_ls_dir, "node_modules", ".bin", "intelephense")
if not os.path.exists(intelephense_executable_path):
install_command = "npm install --prefix ./ intelephense@1.14.4"
is_windows = PlatformUtils.get_platform_id().value.startswith("win")
# Windows doesn't support the 'user' parameter and doesn't have pwd module
if is_windows:
subprocess.run(
install_command,
shell=True,
check=True,
cwd=intelephense_ls_dir,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
else:
# On Unix-like systems, run as non-root user
import pwd
user = pwd.getpwuid(os.getuid()).pw_name
subprocess.run(
install_command,
shell=True,
check=True,
user=user,
cwd=intelephense_ls_dir,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
id="intelephense",
command="npm install --prefix ./ intelephense@1.14.4",
platform_id="any",
)
]
)
deps.install(logger, intelephense_ls_dir)
assert os.path.exists(
intelephense_executable_path
+32 -34
View File
@@ -14,6 +14,7 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -51,50 +52,47 @@ class RustAnalyzer(SolidLanguageServer):
"""
platform_id = PlatformUtils.get_platform_id()
runtime_dependencies = [
{
"id": "RustAnalyzer",
"description": "RustAnalyzer for Linux (x64)",
"url": "https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-aarch64-apple-darwin.gz",
"platformId": "osx-arm64",
"archiveType": "gz",
"binaryName": "rust_analyzer",
},
{
"id": "RustAnalyzer",
"description": "RustAnalyzer for Linux (x64)",
"url": "https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-x86_64-unknown-linux-gnu.gz",
"platformId": "linux-x64",
"archiveType": "gz",
"binaryName": "rust_analyzer",
},
{
"id": "RustAnalyzer",
"description": "RustAnalyzer for Windows (x64)",
"url": "https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-x86_64-pc-windows-msvc.zip",
"platformId": "win-x64",
"archiveType": "zip",
"binaryName": "rust-analyzer.exe",
},
]
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
id="RustAnalyzer",
description="RustAnalyzer for macOS (arm64)",
url="https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-aarch64-apple-darwin.gz",
platform_id="osx-arm64",
archive_type="gz",
binary_name="rust_analyzer",
),
RuntimeDependency(
id="RustAnalyzer",
description="RustAnalyzer for Linux (x64)",
url="https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-x86_64-unknown-linux-gnu.gz",
platform_id="linux-x64",
archive_type="gz",
binary_name="rust_analyzer",
),
RuntimeDependency(
id="RustAnalyzer",
description="RustAnalyzer for Windows (x64)",
url="https://github.com/rust-lang/rust-analyzer/releases/download/2023-10-09/rust-analyzer-x86_64-pc-windows-msvc.zip",
platform_id="win-x64",
archive_type="zip",
binary_name="rust-analyzer.exe",
),
]
)
# assert platform_id.value in [
# "linux-x64",
# "win-x64",
# ], "Only linux-x64 and win-x64 platform is supported for in multilspy at the moment"
runtime_dependencies = [dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value]
assert len(runtime_dependencies) == 1
dependency = runtime_dependencies[0]
dependency = deps.single_for_current_platform()
rustanalyzer_ls_dir = os.path.join(cls.ls_resources_dir(), "RustAnalyzer")
rustanalyzer_executable_path = os.path.join(rustanalyzer_ls_dir, dependency["binaryName"])
rustanalyzer_executable_path = deps.binary_path(rustanalyzer_ls_dir)
if not os.path.exists(rustanalyzer_ls_dir):
os.makedirs(rustanalyzer_ls_dir)
if dependency["archiveType"] == "gz":
FileUtils.download_and_extract_archive(logger, dependency["url"], rustanalyzer_executable_path, dependency["archiveType"])
else:
FileUtils.download_and_extract_archive(logger, dependency["url"], rustanalyzer_ls_dir, dependency["archiveType"])
deps.install(logger, rustanalyzer_ls_dir)
assert os.path.exists(rustanalyzer_executable_path)
os.chmod(rustanalyzer_executable_path, stat.S_IEXEC)
+41 -42
View File
@@ -10,6 +10,7 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PathUtils, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -62,50 +63,48 @@ class TerraformLS(SolidLanguageServer):
"""
cls._ensure_tf_command_available(logger)
platform_id = PlatformUtils.get_platform_id()
runtime_dependencies = [
{
"id": "TerraformLS",
"description": "terraform-ls for macOS (ARM64)",
"url": "https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_darwin_arm64.zip",
"platformId": "osx-arm64",
"archiveType": "zip",
"binaryName": "terraform-ls",
},
{
"id": "TerraformLS",
"description": "terraform-ls for macOS (x64)",
"url": "https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_darwin_amd64.zip",
"platformId": "osx-x64",
"archiveType": "zip",
"binaryName": "terraform-ls",
},
{
"id": "TerraformLS",
"description": "terraform-ls for Linux (x64)",
"url": "https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_linux_amd64.zip",
"platformId": "linux-x64",
"archiveType": "zip",
"binaryName": "terraform-ls",
},
{
"id": "TerraformLS",
"description": "terraform-ls for Windows (x64)",
"url": "https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_windows_amd64.zip",
"platformId": "win-x64",
"archiveType": "zip",
"binaryName": "terraform-ls.exe",
},
]
runtime_dependencies = [dependency for dependency in runtime_dependencies if dependency["platformId"] == platform_id.value]
assert (
len(runtime_dependencies) == 1
), f"Expected exactly one runtime dependency for platform {platform_id.value}, found {len(runtime_dependencies)}"
dependency = runtime_dependencies[0]
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
id="TerraformLS",
description="terraform-ls for macOS (ARM64)",
url="https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_darwin_arm64.zip",
platform_id="osx-arm64",
archive_type="zip",
binary_name="terraform-ls",
),
RuntimeDependency(
id="TerraformLS",
description="terraform-ls for macOS (x64)",
url="https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_darwin_amd64.zip",
platform_id="osx-x64",
archive_type="zip",
binary_name="terraform-ls",
),
RuntimeDependency(
id="TerraformLS",
description="terraform-ls for Linux (x64)",
url="https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_linux_amd64.zip",
platform_id="linux-x64",
archive_type="zip",
binary_name="terraform-ls",
),
RuntimeDependency(
id="TerraformLS",
description="terraform-ls for Windows (x64)",
url="https://releases.hashicorp.com/terraform-ls/0.36.5/terraform-ls_0.36.5_windows_amd64.zip",
platform_id="win-x64",
archive_type="zip",
binary_name="terraform-ls.exe",
),
]
)
dependency = deps.single_for_current_platform()
terraform_ls_executable_path = os.path.join(cls.ls_resources_dir(), dependency["binaryName"])
terraform_ls_executable_path = deps.binary_path(cls.ls_resources_dir())
if not os.path.exists(terraform_ls_executable_path):
logger.log(f"Downloading terraform-ls from {dependency['url']}", logging.INFO)
FileUtils.download_and_extract_archive(logger, dependency["url"], cls.ls_resources_dir(), dependency["archiveType"])
logger.log(f"Downloading terraform-ls from {dependency.url}", logging.INFO)
deps.install(logger, cls.ls_resources_dir())
assert os.path.exists(terraform_ls_executable_path), f"terraform-ls executable not found at {terraform_ls_executable_path}"
@@ -16,6 +16,7 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import PlatformId, PlatformUtils
from .common import RuntimeDependency, RuntimeDependencyCollection
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -82,18 +83,22 @@ class TypeScriptLanguageServer(SolidLanguageServer):
]
assert platform_id in valid_platforms, f"Platform {platform_id} is not supported for multilspy javascript/typescript at the moment"
runtime_dependencies = [
{
"id": "typescript",
"description": "typescript package for Linux, OSX, and Windows. Both x64 and arm64 are supported.",
"command": "npm install --prefix ./ typescript@5.5.4",
},
{
"id": "typescript-language-server",
"description": "typescript-language-server package for Linux, OSX, and Windows. Both x64 and arm64 are supported.",
"command": "npm install --prefix ./ typescript-language-server@4.3.3",
},
]
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
id="typescript",
description="typescript package",
command="npm install --prefix ./ typescript@5.5.4",
platform_id="any",
),
RuntimeDependency(
id="typescript-language-server",
description="typescript-language-server package",
command="npm install --prefix ./ typescript-language-server@4.3.3",
platform_id="any",
),
]
)
tsserver_ls_dir = os.path.join(cls.ls_resources_dir(), "ts-lsp")
tsserver_executable_path = os.path.join(tsserver_ls_dir, "typescript-language-server")
@@ -106,29 +111,7 @@ class TypeScriptLanguageServer(SolidLanguageServer):
# Install typescript and typescript-language-server if not already installed
if not os.path.exists(tsserver_ls_dir):
os.makedirs(tsserver_ls_dir, exist_ok=True)
for dependency in runtime_dependencies:
# Windows doesn't support the 'user' parameter and doesn't have pwd module
if PlatformUtils.get_platform_id().value.startswith("win"):
subprocess.run(
dependency["command"],
shell=True,
check=True,
cwd=tsserver_ls_dir,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
else:
# On Unix-like systems, run as non-root user
user = pwd.getpwuid(os.getuid()).pw_name
subprocess.run(
dependency["command"],
shell=True,
check=True,
user=user,
cwd=tsserver_ls_dir,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
deps.install(logger, tsserver_ls_dir)
tsserver_executable_path = os.path.join(tsserver_ls_dir, "node_modules", ".bin", "typescript-language-server")