mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-12 16:15:33 +00:00
Introduce DownloadedDependency abstraction with URL-keyed hash database
* Add DownloadedDependency abstraction to facilitate handling of downloaded and hash-verified dependencies. In CI, missing hashes raise an exception. For users, unverified downloads log a warning. * Add DownloadedDependencyHashDatabase which manages a URL-keyed database of sha256 hashes. It can be conveniently updated incrementally through a script (src/solidlsp/resources/downloaded_dependency_hashes.json), provided that language server implementations provide DownloadedDependency instances statically Applied in EclipseJDTLS: * Replace the untyped nested-dict runtime dependency descriptors with DownloadedDependency instances * Move the JDTLS version-pinning constants into DependencyProvider * Replace the platform dependency dicts with the VSCodeJavaConfig dataclass Utils: * Add FileUtils.ArchiveType to type archive types that were previously plain str * Add is_running_in_ci() to ls_utils Updated memory on adding a language server accordingly.
This commit is contained in:
1 parent
c7dbe3bd11
commit
9fc8033ece
11 files changed
+401
-231
No files matched your search
@@ -66,6 +66,50 @@ To implement a new language server using the DependencyProvider pattern:
|
||||
|
||||
You should look at at least one existing implementation of each base class to understand how they work.
|
||||
|
||||
#### Downloading Runtime Dependencies
|
||||
|
||||
Use `DownloadedDependency` (in `solidlsp.dependency_provider`), which bundles the URL,
|
||||
archive type, allowed hosts and checksum verification behind a single `download_to()` call:
|
||||
|
||||
```python
|
||||
dep = DownloadedDependency(
|
||||
url=f"https://example.org/foo-{version}-{platform}.zip",
|
||||
archive_type="zip", # optional FileUtils.ArchiveType for extraction
|
||||
allowed_hosts=FOO_ALLOWED_HOSTS, # optional list of allowed hosts
|
||||
)
|
||||
dep.download_to(target_dir)
|
||||
```
|
||||
|
||||
Checksums for downloads live in a URL-keyed database, `src/solidlsp/resources/downloaded_dependency_hashes.json`,
|
||||
managed by `DownloadedDependencyHashDatabase`.
|
||||
|
||||
Consequences for your implementation:
|
||||
|
||||
* Build each dependency in a factory classmethod (`_create_dep_*`) that takes an
|
||||
optional version and falls back to the pinned `DEFAULT_*` constant.
|
||||
* Add an `update_dep_hashes()` classmethod that constructs every dependency
|
||||
and updates the hashes:
|
||||
```python
|
||||
@classmethod
|
||||
def update_dep_hashes(cls) -> None:
|
||||
deps = [cls._create_dep_foo(), cls_._create_dep_bar(), ...]
|
||||
with DownloadedDependencyHashDatabase.get_instance().update_context() as db:
|
||||
for dep in deps:
|
||||
db.update(dep)
|
||||
```
|
||||
Hook a call to this method into `scripts/update_downloaded_dependency_hashes.py`, run that script,
|
||||
and commit the resulting JSON changes.
|
||||
* After bumping any pinned version, re-run the script. Add a NOTE comment next to
|
||||
the version constants saying so; a stale database means unverified downloads
|
||||
locally and a CI failure.
|
||||
* Pass `verified=False` only for dependencies whose hash cannot be pinned by design
|
||||
(e.g. a user-supplied version override).
|
||||
|
||||
Reference implementation: `EclipseJDTLS.DependencyProvider`
|
||||
|
||||
Note that several older language servers still define hashes locally in constants and
|
||||
call `FileUtils.download_and_extract_archive_verified`directly. Do not apply this legacy approach.
|
||||
|
||||
### 1.2 LSP Initialization
|
||||
|
||||
Override `_create_base_initialize_params` to provide server-specific initialization
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
from sensai.util import logging
|
||||
|
||||
from solidlsp.language_servers.eclipse_jdtls import EclipseJDTLS
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.configure()
|
||||
EclipseJDTLS.DependencyProvider.update_dep_hashes()
|
||||
@@ -1,10 +1,16 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import threading
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Sequence
|
||||
from collections.abc import Iterator, Sequence
|
||||
from contextlib import contextmanager
|
||||
from os import PathLike
|
||||
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
from solidlsp.ls_utils import FileUtils, is_running_in_ci
|
||||
from solidlsp.settings import SOLIDLSP_RESOURCES_DIR, SolidLSPSettings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -239,3 +245,125 @@ class LanguageServerDependencyProviderUvx(LanguageServerDependencyProviderBaseCo
|
||||
|
||||
def _create_launch_command_from_base_command(self, base_command: list[str]) -> list[str]:
|
||||
return base_command + list(self._extra_args)
|
||||
|
||||
|
||||
class DownloadedDependencyHashDatabase:
|
||||
RESOURCE_FILE_NAME = "downloaded_dependency_hashes.json"
|
||||
_instance: "DownloadedDependencyHashDatabase | None" = None
|
||||
_instance_lock: threading.Lock = threading.Lock()
|
||||
|
||||
def __init__(self, _singleton: bool):
|
||||
self._json_file = os.path.join(SOLIDLSP_RESOURCES_DIR, self.RESOURCE_FILE_NAME)
|
||||
self._hashes = {}
|
||||
if os.path.exists(self._json_file):
|
||||
try:
|
||||
with open(self._json_file, encoding="utf-8") as f:
|
||||
self._hashes = json.load(f)
|
||||
except:
|
||||
log.warning("Error loading %s", self._json_file, exc_info=True)
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls) -> "DownloadedDependencyHashDatabase":
|
||||
if cls._instance is None:
|
||||
with cls._instance_lock:
|
||||
if cls._instance is None:
|
||||
cls._instance = DownloadedDependencyHashDatabase(True)
|
||||
return cls._instance
|
||||
|
||||
def get_sha256(self, dep: "DownloadedDependency") -> str | None:
|
||||
return self._hashes.get(dep.get_url())
|
||||
|
||||
class Updater:
|
||||
def __init__(self, db: "DownloadedDependencyHashDatabase"):
|
||||
self._db = db
|
||||
|
||||
def update(self, dep: "DownloadedDependency", force: bool = False) -> None:
|
||||
"""
|
||||
:param dep: the dependency to update the hash for
|
||||
:param force: whether to force an update even if the hash already exists
|
||||
"""
|
||||
self._db._update(dep, force)
|
||||
|
||||
@contextmanager
|
||||
def update_context(self) -> Iterator[Updater]:
|
||||
try:
|
||||
yield self.Updater(self)
|
||||
finally:
|
||||
self._save()
|
||||
|
||||
def _update(self, dep: "DownloadedDependency", force: bool = False) -> None:
|
||||
if not force and dep.get_url() in self._hashes:
|
||||
log.info("SHA256 for %s already exists, skipping update", dep.get_url())
|
||||
return
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
path = os.path.join(temp_dir, "downloaded_dependency")
|
||||
log.info("Downloading %s for hash calculation", dep.get_url())
|
||||
FileUtils.download_file(dep.get_url(), path)
|
||||
sha = FileUtils.calculate_sha256(path)
|
||||
log.info("SHA256 for %s: %s", dep.get_url(), sha)
|
||||
self._hashes[dep.get_url()] = sha
|
||||
except:
|
||||
log.warning("Error updating hash for %s", dep.get_url(), exc_info=True)
|
||||
|
||||
def _save(self) -> None:
|
||||
try:
|
||||
with open(self._json_file, "w", encoding="utf-8") as f:
|
||||
json.dump(self._hashes, f, indent=2)
|
||||
except:
|
||||
log.warning("Error saving %s", self._json_file, exc_info=True)
|
||||
|
||||
|
||||
class DownloadedDependency:
|
||||
"""
|
||||
Represents a dependency that can be downloaded from a URL, optionally verified against a known SHA256 hash,
|
||||
and optionally extracted if it is an archive.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
url: str,
|
||||
archive_type: FileUtils.ArchiveType | None = None,
|
||||
allowed_hosts: Sequence[str] | None = None,
|
||||
verified: bool = True,
|
||||
):
|
||||
"""
|
||||
:param url: the URL of the file to be downloaded
|
||||
:param archive_type: optional type of archive for the case where `url` points to an archive.
|
||||
Use `None` or "binary" for a binary file (no extraction).
|
||||
:param allowed_hosts: optional list of allowed hosts for the download URL
|
||||
:param verified: whether to verify the downloaded file against a known SHA256 hash (if available).
|
||||
If enabled and the hash for the URL is not known, will raise an exception in CI and issue a warning
|
||||
in non-CI environments.
|
||||
"""
|
||||
self._url = url
|
||||
self._allowed_hosts = allowed_hosts
|
||||
self._archive_type = archive_type if archive_type is not None else "binary"
|
||||
self._verified = verified
|
||||
|
||||
def get_url(self) -> str:
|
||||
return self._url
|
||||
|
||||
def download_to(self, target_path: str | PathLike) -> None:
|
||||
"""
|
||||
Downloads the dependency to the specified target path.
|
||||
If defined at construction, will apply hash verification and archive extraction.
|
||||
|
||||
:param target_path: the path to which the dependency should be downloaded (or extracted if applicable)
|
||||
"""
|
||||
if not isinstance(target_path, str):
|
||||
target_path = str(target_path)
|
||||
if self._verified:
|
||||
sha256 = DownloadedDependencyHashDatabase.get_instance().get_sha256(self)
|
||||
if sha256 is None:
|
||||
if is_running_in_ci():
|
||||
raise RuntimeError(
|
||||
f"No SHA256 hash found for {self._url}. "
|
||||
"Please update the hash database by running 'scripts/update_downloaded_dependency_hashes.py'."
|
||||
)
|
||||
log.warning("No SHA256 hash found for %s. The downloaded file will not be verified.", self._url)
|
||||
else:
|
||||
sha256 = None
|
||||
FileUtils.download_and_extract_archive_verified(
|
||||
self._url, target_path, archive_type=self._archive_type, expected_sha256=sha256, allowed_hosts=self._allowed_hosts
|
||||
)
|
||||
@@ -24,7 +24,7 @@ class RuntimeDependency:
|
||||
url: str | None = None
|
||||
sha256: str | None = None
|
||||
allowed_hosts: tuple[str, ...] | list[str] | None = None
|
||||
archive_type: str | None = None
|
||||
archive_type: FileUtils.ArchiveType | None = None
|
||||
binary_name: str | None = None
|
||||
command: str | list[str] | None = None
|
||||
package_name: str | None = None
|
||||
|
||||
@@ -13,18 +13,20 @@ import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path, PurePath
|
||||
from time import sleep
|
||||
from typing import Any, cast
|
||||
from typing import Any
|
||||
|
||||
from overrides import override
|
||||
|
||||
from solidlsp import ls_types
|
||||
from solidlsp.dependency_provider import DownloadedDependency, DownloadedDependencyHashDatabase
|
||||
from solidlsp.ls import LanguageServerDependencyProvider, LSPFileBuffer, SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_exceptions import SolidLSPException
|
||||
from solidlsp.ls_types import UnifiedSymbolInformation
|
||||
from solidlsp.ls_utils import FileUtils, PlatformUtils
|
||||
from solidlsp.ls_utils import PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import DocumentSymbol, SymbolInformation
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
from solidlsp.util.subprocess_util import subprocess_run
|
||||
@@ -32,7 +34,6 @@ from solidlsp.util.subprocess_util import subprocess_run
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
GRADLE_ALLOWED_HOSTS = ("services.gradle.org", "github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
|
||||
GRADLE_SHA256 = "7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999"
|
||||
VSCODE_JAVA_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
|
||||
INTELLICODE_ALLOWED_HOSTS = (
|
||||
"visualstudioexptteam.gallery.vsassets.io",
|
||||
@@ -41,30 +42,6 @@ INTELLICODE_ALLOWED_HOSTS = (
|
||||
)
|
||||
|
||||
|
||||
# Version pinning convention (read this before bumping anything below):
|
||||
#
|
||||
# INITIAL_* — the very first version we shipped runtime-dependency support for, paired with
|
||||
# its SHA. NEVER edited. The legacy unversioned install directory (e.g. "vscode-java/")
|
||||
# is reserved exclusively for this version, so users who installed under the original
|
||||
# layout keep their existing cache forever.
|
||||
#
|
||||
# DEFAULT_* — the version (and matching SHA) used when the user does not override via
|
||||
# custom_settings. THIS is what we edit to upgrade: copy the new version + new SHA over
|
||||
# the existing DEFAULT_* literals, leave INITIAL_* alone.
|
||||
#
|
||||
# Resolution at install time:
|
||||
# resolved_version = custom_settings.get("..._version", DEFAULT_*_VERSION)
|
||||
# - resolved == INITIAL_* -> legacy unversioned dir, SHA = INITIAL_*_SHA256
|
||||
# - resolved == DEFAULT_* -> versioned dir "{name}-{resolved}", SHA = DEFAULT_*_SHA256
|
||||
# - any other version -> versioned dir "{name}-{resolved}", SHA verification skipped
|
||||
#
|
||||
# Consequences of this scheme:
|
||||
# - Bumping DEFAULT_* makes new installs land in a new versioned subdir => no silent reuse
|
||||
# of stale binaries (the bug this scheme exists to fix).
|
||||
# - Previously-downloaded versions are not lost: a user can request any past version via
|
||||
# custom_settings and the matching cached subdir is picked up without re-downloading.
|
||||
# - INITIAL_* and DEFAULT_* hold identical literals when first introduced; they diverge on
|
||||
# the first DEFAULT_* bump and stay independent thereafter.
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class VsixResourcePaths:
|
||||
"""
|
||||
@@ -81,40 +58,6 @@ class VsixResourcePaths:
|
||||
equinox_launcher_basename: str # e.g. "org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar"
|
||||
|
||||
|
||||
INITIAL_VSCODE_JAVA_VERSION = "1.42.0-561"
|
||||
INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM = {
|
||||
"osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933",
|
||||
"osx-x64": "03ae1db1a22c15561a620f1b722d6797d35d4faaa7c4666dbe6ca2715089852f",
|
||||
"linux-arm64": "e15bc9b2a665d3453203402621b5441062aa41b0ec2d140661f439326fd248c1",
|
||||
"linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9",
|
||||
"win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3",
|
||||
}
|
||||
INITIAL_VSCODE_JAVA_PATHS = VsixResourcePaths(
|
||||
jre_version="21.0.7",
|
||||
lombok_jar_basename="lombok-1.18.36.jar",
|
||||
equinox_launcher_basename="org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar",
|
||||
)
|
||||
# Bumped from 1.42.0-561 to surface Lombok-generated methods (#1432); brings JDTLS commit b2d8952
|
||||
# (java.symbols.includeGeneratedCode), JRE 21.0.10, Lombok 1.18.39 and Equinox launcher 1.7.100.
|
||||
DEFAULT_VSCODE_JAVA_VERSION = "1.54.0-923"
|
||||
DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM = {
|
||||
"osx-arm64": "c54c45cb0d2579d8e0a4ddeb24d4a9dd0b460d07d9366adea2b38a1da22a463c",
|
||||
"osx-x64": "dfc98abc4e54165a78372e280242a039671729b1b03420608df3b10c6b629fb6",
|
||||
"linux-arm64": "e2bb22c427d90da8dbb1afff72ff1e2dce38d50b76deb02d7bc313a330a1330c",
|
||||
"linux-x64": "9d4b15da54e25a0192f9bac073f086c015397d3676623b68dbf83a5dbaf5132b",
|
||||
"win-x64": "66f3914987edeccfee8a2558470e0fde4f8c4154232ff4baa5d73373ebc819d4",
|
||||
}
|
||||
DEFAULT_VSCODE_JAVA_PATHS = VsixResourcePaths(
|
||||
jre_version="21.0.10",
|
||||
lombok_jar_basename="lombok-1.18.39-4050.jar",
|
||||
equinox_launcher_basename="org.eclipse.equinox.launcher_1.7.100.v20251111-0406.jar",
|
||||
)
|
||||
|
||||
INITIAL_INTELLICODE_VERSION = "1.2.30"
|
||||
INITIAL_INTELLICODE_SHA256 = "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251"
|
||||
DEFAULT_INTELLICODE_VERSION = "1.2.30"
|
||||
DEFAULT_INTELLICODE_SHA256 = "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251"
|
||||
|
||||
# Mapping from Serena's platform identifiers to upstream JDTLS config_<platform> directory names
|
||||
JDTLS_CONFIG_DIR_BY_PLATFORM = {
|
||||
"osx-arm64": "config_mac_arm",
|
||||
@@ -150,6 +93,19 @@ class RuntimeDependencyPaths:
|
||||
intellisense_members_path: str | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class VSCodeJavaConfig:
|
||||
"""
|
||||
Represents a (platform-specific) configuration for VSCode Java
|
||||
"""
|
||||
|
||||
jre_home_path: str
|
||||
jre_path: str
|
||||
lombok_jar_path: str
|
||||
jdtls_launcher_jar_path: str
|
||||
jdtls_readonly_config_path: str
|
||||
|
||||
|
||||
class EclipseJDTLS(SolidLanguageServer):
|
||||
r"""
|
||||
The EclipseJDTLS class provides a Java specific implementation of the LanguageServer class
|
||||
@@ -271,6 +227,56 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
return self.DependencyProvider(self._custom_settings, ls_resources_dir, self._solidlsp_settings, self.repository_root_path)
|
||||
|
||||
class DependencyProvider(LanguageServerDependencyProvider):
|
||||
"""
|
||||
Dependency provider for Eclipse JDTLS.
|
||||
|
||||
Version pinning convention (read this before bumping anything below):
|
||||
|
||||
INITIAL_* — the very first version we shipped runtime-dependency support for, paired with
|
||||
its SHA. NEVER edited. The legacy unversioned install directory (e.g. "vscode-java/")
|
||||
is reserved exclusively for this version, so users who installed under the original
|
||||
layout keep their existing cache forever.
|
||||
|
||||
DEFAULT_* — the version (and matching SHA) used when the user does not override via
|
||||
custom_settings. THIS is what we edit to upgrade: copy the new version + new SHA over
|
||||
the existing DEFAULT_* literals, leave INITIAL_* alone.
|
||||
|
||||
Resolution at install time:
|
||||
resolved_version = custom_settings.get("..._version", DEFAULT_*_VERSION)
|
||||
- resolved == INITIAL_* -> legacy unversioned dir, SHA = INITIAL_*_SHA256
|
||||
- resolved == DEFAULT_* -> versioned dir "{name}-{resolved}", SHA = DEFAULT_*_SHA256
|
||||
- any other version -> versioned dir "{name}-{resolved}", SHA verification skipped
|
||||
|
||||
Consequences of this scheme:
|
||||
- Bumping DEFAULT_* makes new installs land in a new versioned subdir => no silent reuse
|
||||
of stale binaries (the bug this scheme exists to fix).
|
||||
- Previously-downloaded versions are not lost: a user can request any past version via
|
||||
custom_settings and the matching cached subdir is picked up without re-downloading.
|
||||
- INITIAL_* and DEFAULT_* hold identical literals when first introduced; they diverge on
|
||||
the first DEFAULT_* bump and stay independent thereafter.
|
||||
"""
|
||||
|
||||
# versions used initially (which use default paths without version suffix)
|
||||
INITIAL_VSCODE_JAVA_VERSION = "1.42.0-561"
|
||||
INITIAL_INTELLICODE_VERSION = "1.2.30"
|
||||
INITIAL_VSCODE_JAVA_PATHS = VsixResourcePaths(
|
||||
jre_version="21.0.7",
|
||||
lombok_jar_basename="lombok-1.18.36.jar",
|
||||
equinox_launcher_basename="org.eclipse.equinox.launcher_1.7.0.v20250424-1814.jar",
|
||||
)
|
||||
|
||||
# currently used default versions
|
||||
# NOTE: After bumping any of these, also update the corresponding hashes by running
|
||||
# scripts/update_downloaded_dependency_hashes.py and commit the resulting changes.
|
||||
DEFAULT_GRADLE_VERSION = "8.14.2"
|
||||
DEFAULT_VSCODE_JAVA_VERSION = "1.54.0-923"
|
||||
DEFAULT_INTELLICODE_VERSION = "1.2.30"
|
||||
DEFAULT_VSCODE_JAVA_PATHS = VsixResourcePaths(
|
||||
jre_version="21.0.10",
|
||||
lombok_jar_basename="lombok-1.18.39-4050.jar",
|
||||
equinox_launcher_basename="org.eclipse.equinox.launcher_1.7.100.v20251111-0406.jar",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
custom_settings: SolidLSPSettings.CustomLSSettings,
|
||||
@@ -283,9 +289,57 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
self._repository_root_path = repository_root_path
|
||||
self.runtime_dependency_paths = self._setup_runtime_dependencies(ls_resources_dir, custom_settings)
|
||||
|
||||
@staticmethod
|
||||
@classmethod
|
||||
def _create_dep_gradle(cls, gradle_version: str | None = None) -> DownloadedDependency:
|
||||
gradle_version = gradle_version or cls.DEFAULT_GRADLE_VERSION
|
||||
return DownloadedDependency(
|
||||
url=f"https://services.gradle.org/distributions/gradle-{gradle_version}-bin.zip",
|
||||
archive_type="zip",
|
||||
allowed_hosts=GRADLE_ALLOWED_HOSTS,
|
||||
verified=gradle_version == cls.DEFAULT_GRADLE_VERSION,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _create_deps_vscode_java(cls, vscode_java_version: str | None = None) -> dict[str, DownloadedDependency]:
|
||||
vscode_java_version = vscode_java_version or cls.DEFAULT_VSCODE_JAVA_VERSION
|
||||
vscode_java_tag = f"v{vscode_java_version.rsplit('-', 1)[0]}"
|
||||
urls = {
|
||||
"osx-arm64": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-arm64-{vscode_java_version}.vsix",
|
||||
"osx-x64": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-x64-{vscode_java_version}.vsix",
|
||||
"linux-arm64": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-arm64-{vscode_java_version}.vsix",
|
||||
"linux-x64": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-x64-{vscode_java_version}.vsix",
|
||||
"win-x64": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-win32-x64-{vscode_java_version}.vsix",
|
||||
}
|
||||
deps = {}
|
||||
for platform_key, url in urls.items():
|
||||
deps[platform_key] = DownloadedDependency(
|
||||
url=url,
|
||||
archive_type="zip",
|
||||
allowed_hosts=VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
verified=vscode_java_version == cls.DEFAULT_VSCODE_JAVA_VERSION,
|
||||
)
|
||||
return deps
|
||||
|
||||
@classmethod
|
||||
def _create_dep_intellicode(cls, intellicode_version: str | None = None) -> DownloadedDependency:
|
||||
intellicode_version = intellicode_version or cls.DEFAULT_INTELLICODE_VERSION
|
||||
return DownloadedDependency(
|
||||
url=f"https://VisualStudioExptTeam.gallery.vsassets.io/_apis/public/gallery/publisher/VisualStudioExptTeam/extension/vscodeintellicode/{intellicode_version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage",
|
||||
archive_type="zip",
|
||||
allowed_hosts=INTELLICODE_ALLOWED_HOSTS,
|
||||
verified=intellicode_version == cls.DEFAULT_INTELLICODE_VERSION,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def update_dep_hashes(cls) -> None:
|
||||
deps = [cls._create_dep_gradle(), cls._create_dep_intellicode()] + list(cls._create_deps_vscode_java().values())
|
||||
with DownloadedDependencyHashDatabase.get_instance().update_context() as db:
|
||||
for dep in deps:
|
||||
db.update(dep)
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(
|
||||
ls_resources_dir: str, custom_settings: SolidLSPSettings.CustomLSSettings
|
||||
cls, ls_resources_dir: str, custom_settings: SolidLSPSettings.CustomLSSettings
|
||||
) -> RuntimeDependencyPaths:
|
||||
"""
|
||||
Setup runtime dependencies for EclipseJDTLS and return the paths.
|
||||
@@ -313,145 +367,72 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
return EclipseJDTLS.DependencyProvider._setup_from_existing_install(str(jdtls_path), str(lombok_path), custom_settings)
|
||||
|
||||
platformId = PlatformUtils.get_platform_id()
|
||||
gradle_version = custom_settings.get("gradle_version", "8.14.2")
|
||||
vscode_java_version = custom_settings.get("vscode_java_version", DEFAULT_VSCODE_JAVA_VERSION)
|
||||
vscode_java_tag = f"v{vscode_java_version.rsplit('-', 1)[0]}"
|
||||
intellicode_version = custom_settings.get("intellicode_version", DEFAULT_INTELLICODE_VERSION)
|
||||
default_gradle_version = gradle_version == "8.14.2"
|
||||
gradle_version = custom_settings.get("gradle_version", cls.DEFAULT_GRADLE_VERSION)
|
||||
vscode_java_version = custom_settings.get("vscode_java_version", cls.DEFAULT_VSCODE_JAVA_VERSION)
|
||||
intellicode_version = custom_settings.get("intellicode_version", cls.DEFAULT_INTELLICODE_VERSION)
|
||||
|
||||
# install-dir name per the version-pinning convention (see module-level block):
|
||||
# INITIAL -> legacy unversioned dir; everything else -> "{name}-{resolved}" subdir
|
||||
vscode_java_dirname = (
|
||||
"vscode-java" if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION else f"vscode-java-{vscode_java_version}"
|
||||
"vscode-java" if vscode_java_version == cls.INITIAL_VSCODE_JAVA_VERSION else f"vscode-java-{vscode_java_version}"
|
||||
)
|
||||
intellicode_dirname = (
|
||||
"intellicode" if intellicode_version == INITIAL_INTELLICODE_VERSION else f"intellicode-{intellicode_version}"
|
||||
"intellicode" if intellicode_version == cls.INITIAL_INTELLICODE_VERSION else f"intellicode-{intellicode_version}"
|
||||
)
|
||||
|
||||
# SHA is only known for our two pinned versions (INITIAL and current DEFAULT);
|
||||
# for any other user-supplied version we skip verification (returns None)
|
||||
def vscode_java_sha(platform_key: str) -> str | None:
|
||||
if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION:
|
||||
return INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM[platform_key]
|
||||
if vscode_java_version == DEFAULT_VSCODE_JAVA_VERSION:
|
||||
return DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM[platform_key]
|
||||
return None
|
||||
|
||||
def intellicode_sha() -> str | None:
|
||||
if intellicode_version == INITIAL_INTELLICODE_VERSION:
|
||||
return INITIAL_INTELLICODE_SHA256
|
||||
if intellicode_version == DEFAULT_INTELLICODE_VERSION:
|
||||
return DEFAULT_INTELLICODE_SHA256
|
||||
return None
|
||||
|
||||
# Resolve internal VSIX paths (JRE / Lombok / launcher filenames). For pinned versions
|
||||
# these are known; for any other user-supplied version we bail out — guessing would
|
||||
# silently produce broken paths at JDTLS launch time, which is a worse UX than failing
|
||||
# fast here with a pointer to upstream-JDTLS mode (which doesn't need pinned paths).
|
||||
if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION:
|
||||
vsix_paths = INITIAL_VSCODE_JAVA_PATHS
|
||||
elif vscode_java_version == DEFAULT_VSCODE_JAVA_VERSION:
|
||||
vsix_paths = DEFAULT_VSCODE_JAVA_PATHS
|
||||
if vscode_java_version == cls.INITIAL_VSCODE_JAVA_VERSION:
|
||||
vsix_paths = cls.INITIAL_VSCODE_JAVA_PATHS
|
||||
elif vscode_java_version == cls.DEFAULT_VSCODE_JAVA_VERSION:
|
||||
vsix_paths = cls.DEFAULT_VSCODE_JAVA_PATHS
|
||||
else:
|
||||
raise SolidLSPException(
|
||||
f"Resource paths inside the vscode-java {vscode_java_version} VSIX are not pinned in serena "
|
||||
f"(known: {INITIAL_VSCODE_JAVA_VERSION}, {DEFAULT_VSCODE_JAVA_VERSION}). "
|
||||
f"Either remove the 'vscode_java_version' override (defaults to {DEFAULT_VSCODE_JAVA_VERSION}), "
|
||||
f"(known: {cls.INITIAL_VSCODE_JAVA_VERSION}, {cls.DEFAULT_VSCODE_JAVA_VERSION}). "
|
||||
f"Either remove the 'vscode_java_version' override (defaults to {cls.DEFAULT_VSCODE_JAVA_VERSION}), "
|
||||
f"or use upstream JDTLS mode by setting both 'jdtls_path' and 'lombok_path' in "
|
||||
f"ls_specific_settings.java (no pinning required)."
|
||||
)
|
||||
|
||||
runtime_dependencies: dict[str, dict[str, dict[str, object]]] = {
|
||||
"gradle": {
|
||||
"platform-agnostic": {
|
||||
"url": f"https://services.gradle.org/distributions/gradle-{gradle_version}-bin.zip",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": ".",
|
||||
"sha256": GRADLE_SHA256 if default_gradle_version else None,
|
||||
"allowed_hosts": GRADLE_ALLOWED_HOSTS,
|
||||
}
|
||||
},
|
||||
"vscode-java": {
|
||||
"darwin-arm64": {
|
||||
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-arm64-{vscode_java_version}.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": vscode_java_dirname,
|
||||
"sha256": vscode_java_sha("osx-arm64"),
|
||||
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
},
|
||||
"osx-arm64": {
|
||||
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-arm64-{vscode_java_version}.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": vscode_java_dirname,
|
||||
"sha256": vscode_java_sha("osx-arm64"),
|
||||
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
"jre_home_path": f"extension/jre/{vsix_paths.jre_version}-macosx-aarch64",
|
||||
"jre_path": f"extension/jre/{vsix_paths.jre_version}-macosx-aarch64/bin/java",
|
||||
"lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
"jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
"jdtls_readonly_config_path": "extension/server/config_mac_arm",
|
||||
},
|
||||
"osx-x64": {
|
||||
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-x64-{vscode_java_version}.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": vscode_java_dirname,
|
||||
"sha256": vscode_java_sha("osx-x64"),
|
||||
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
"jre_home_path": f"extension/jre/{vsix_paths.jre_version}-macosx-x86_64",
|
||||
"jre_path": f"extension/jre/{vsix_paths.jre_version}-macosx-x86_64/bin/java",
|
||||
"lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
"jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
"jdtls_readonly_config_path": "extension/server/config_mac",
|
||||
},
|
||||
"linux-arm64": {
|
||||
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-arm64-{vscode_java_version}.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": vscode_java_dirname,
|
||||
"sha256": vscode_java_sha("linux-arm64"),
|
||||
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
"jre_home_path": f"extension/jre/{vsix_paths.jre_version}-linux-aarch64",
|
||||
"jre_path": f"extension/jre/{vsix_paths.jre_version}-linux-aarch64/bin/java",
|
||||
"lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
"jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
"jdtls_readonly_config_path": "extension/server/config_linux_arm",
|
||||
},
|
||||
"linux-x64": {
|
||||
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-x64-{vscode_java_version}.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": vscode_java_dirname,
|
||||
"sha256": vscode_java_sha("linux-x64"),
|
||||
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
"jre_home_path": f"extension/jre/{vsix_paths.jre_version}-linux-x86_64",
|
||||
"jre_path": f"extension/jre/{vsix_paths.jre_version}-linux-x86_64/bin/java",
|
||||
"lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
"jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
"jdtls_readonly_config_path": "extension/server/config_linux",
|
||||
},
|
||||
"win-x64": {
|
||||
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-win32-x64-{vscode_java_version}.vsix",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": vscode_java_dirname,
|
||||
"sha256": vscode_java_sha("win-x64"),
|
||||
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
|
||||
"jre_home_path": f"extension/jre/{vsix_paths.jre_version}-win32-x86_64",
|
||||
"jre_path": f"extension/jre/{vsix_paths.jre_version}-win32-x86_64/bin/java.exe",
|
||||
"lombok_jar_path": f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
"jdtls_launcher_jar_path": f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
"jdtls_readonly_config_path": "extension/server/config_win",
|
||||
},
|
||||
},
|
||||
"intellicode": {
|
||||
"platform-agnostic": {
|
||||
"url": f"https://VisualStudioExptTeam.gallery.vsassets.io/_apis/public/gallery/publisher/VisualStudioExptTeam/extension/vscodeintellicode/{intellicode_version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage",
|
||||
"alternate_url": f"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioExptTeam/vsextensions/vscodeintellicode/{intellicode_version}/vspackage",
|
||||
"archiveType": "zip",
|
||||
"relative_extraction_path": intellicode_dirname,
|
||||
"sha256": intellicode_sha(),
|
||||
"allowed_hosts": INTELLICODE_ALLOWED_HOSTS,
|
||||
"intellicode_jar_path": "extension/dist/com.microsoft.jdtls.intellicode.core-0.7.0.jar",
|
||||
"intellisense_members_path": "extension/dist/bundledModels/java_intellisense-members",
|
||||
}
|
||||
},
|
||||
vscode_java_configs: dict[str, VSCodeJavaConfig] = {
|
||||
"osx-arm64": VSCodeJavaConfig(
|
||||
jre_home_path=f"extension/jre/{vsix_paths.jre_version}-macosx-aarch64",
|
||||
jre_path=f"extension/jre/{vsix_paths.jre_version}-macosx-aarch64/bin/java",
|
||||
lombok_jar_path=f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
jdtls_launcher_jar_path=f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
jdtls_readonly_config_path="extension/server/config_mac_arm",
|
||||
),
|
||||
"osx-x64": VSCodeJavaConfig(
|
||||
jre_home_path=f"extension/jre/{vsix_paths.jre_version}-macosx-x86_64",
|
||||
jre_path=f"extension/jre/{vsix_paths.jre_version}-macosx-x86_64/bin/java",
|
||||
lombok_jar_path=f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
jdtls_launcher_jar_path=f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
jdtls_readonly_config_path="extension/server/config_mac",
|
||||
),
|
||||
"linux-arm64": VSCodeJavaConfig(
|
||||
jre_home_path=f"extension/jre/{vsix_paths.jre_version}-linux-aarch64",
|
||||
jre_path=f"extension/jre/{vsix_paths.jre_version}-linux-aarch64/bin/java",
|
||||
lombok_jar_path=f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
jdtls_launcher_jar_path=f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
jdtls_readonly_config_path="extension/server/config_linux_arm",
|
||||
),
|
||||
"linux-x64": VSCodeJavaConfig(
|
||||
jre_home_path=f"extension/jre/{vsix_paths.jre_version}-linux-x86_64",
|
||||
jre_path=f"extension/jre/{vsix_paths.jre_version}-linux-x86_64/bin/java",
|
||||
lombok_jar_path=f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
jdtls_launcher_jar_path=f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
jdtls_readonly_config_path="extension/server/config_linux",
|
||||
),
|
||||
"win-x64": VSCodeJavaConfig(
|
||||
jre_home_path=f"extension/jre/{vsix_paths.jre_version}-win32-x86_64",
|
||||
jre_path=f"extension/jre/{vsix_paths.jre_version}-win32-x86_64/bin/java.exe",
|
||||
lombok_jar_path=f"extension/lombok/{vsix_paths.lombok_jar_basename}",
|
||||
jdtls_launcher_jar_path=f"extension/server/plugins/{vsix_paths.equinox_launcher_basename}",
|
||||
jdtls_readonly_config_path="extension/server/config_win",
|
||||
),
|
||||
}
|
||||
|
||||
gradle_path = str(
|
||||
@@ -462,25 +443,20 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
)
|
||||
|
||||
if not os.path.exists(gradle_path):
|
||||
gradle_dependency = runtime_dependencies["gradle"]["platform-agnostic"]
|
||||
FileUtils.download_and_extract_archive_verified(
|
||||
cast(str, gradle_dependency["url"]),
|
||||
str(PurePath(gradle_path).parent),
|
||||
cast(str, gradle_dependency["archiveType"]),
|
||||
expected_sha256=cast(str | None, gradle_dependency["sha256"]),
|
||||
allowed_hosts=cast(tuple[str, ...], gradle_dependency["allowed_hosts"]),
|
||||
)
|
||||
gradle_dependency = cls._create_dep_gradle(gradle_version)
|
||||
gradle_dependency.download_to(PurePath(gradle_path).parent)
|
||||
|
||||
assert os.path.exists(gradle_path)
|
||||
|
||||
dependency = runtime_dependencies["vscode-java"][platformId.value]
|
||||
vscode_java_path = str(PurePath(ls_resources_dir, cast(str, dependency["relative_extraction_path"])))
|
||||
vscode_java_dep = cls._create_deps_vscode_java(vscode_java_version)[platformId.value]
|
||||
vscode_java_cfg = vscode_java_configs[platformId.value]
|
||||
vscode_java_path = str(PurePath(ls_resources_dir, vscode_java_dirname))
|
||||
os.makedirs(vscode_java_path, exist_ok=True)
|
||||
jre_home_path = str(PurePath(vscode_java_path, cast(str, dependency["jre_home_path"])))
|
||||
jre_path = str(PurePath(vscode_java_path, cast(str, dependency["jre_path"])))
|
||||
lombok_jar_path = str(PurePath(vscode_java_path, cast(str, dependency["lombok_jar_path"])))
|
||||
jdtls_launcher_jar_path = str(PurePath(vscode_java_path, cast(str, dependency["jdtls_launcher_jar_path"])))
|
||||
jdtls_readonly_config_path = str(PurePath(vscode_java_path, cast(str, dependency["jdtls_readonly_config_path"])))
|
||||
jre_home_path = str(PurePath(vscode_java_path, vscode_java_cfg.jre_home_path))
|
||||
jre_path = str(PurePath(vscode_java_path, vscode_java_cfg.jre_path))
|
||||
lombok_jar_path = str(PurePath(vscode_java_path, vscode_java_cfg.lombok_jar_path))
|
||||
jdtls_launcher_jar_path = str(PurePath(vscode_java_path, vscode_java_cfg.jdtls_launcher_jar_path))
|
||||
jdtls_readonly_config_path = str(PurePath(vscode_java_path, vscode_java_cfg.jdtls_readonly_config_path))
|
||||
if not all(
|
||||
[
|
||||
os.path.exists(vscode_java_path),
|
||||
@@ -491,13 +467,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
os.path.exists(jdtls_readonly_config_path),
|
||||
]
|
||||
):
|
||||
FileUtils.download_and_extract_archive_verified(
|
||||
cast(str, dependency["url"]),
|
||||
vscode_java_path,
|
||||
cast(str, dependency["archiveType"]),
|
||||
expected_sha256=cast(str | None, dependency["sha256"]),
|
||||
allowed_hosts=cast(tuple[str, ...], dependency["allowed_hosts"]),
|
||||
)
|
||||
vscode_java_dep.download_to(vscode_java_path)
|
||||
|
||||
os.chmod(jre_path, 0o755)
|
||||
|
||||
@@ -508,11 +478,13 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
assert os.path.exists(jdtls_launcher_jar_path)
|
||||
assert os.path.exists(jdtls_readonly_config_path)
|
||||
|
||||
dependency = runtime_dependencies["intellicode"]["platform-agnostic"]
|
||||
intellicode_directory_path = str(PurePath(ls_resources_dir, cast(str, dependency["relative_extraction_path"])))
|
||||
intellicode_dep = cls._create_dep_intellicode(intellicode_version)
|
||||
intellicode_directory_path = str(PurePath(ls_resources_dir, intellicode_dirname))
|
||||
os.makedirs(intellicode_directory_path, exist_ok=True)
|
||||
intellicode_jar_path = str(PurePath(intellicode_directory_path, cast(str, dependency["intellicode_jar_path"])))
|
||||
intellisense_members_path = str(PurePath(intellicode_directory_path, cast(str, dependency["intellisense_members_path"])))
|
||||
intellicode_jar_path = str(
|
||||
PurePath(intellicode_directory_path, "extension/dist/com.microsoft.jdtls.intellicode.core-0.7.0.jar")
|
||||
)
|
||||
intellisense_members_path = str(PurePath(intellicode_directory_path, "extension/dist/bundledModels/java_intellisense-members"))
|
||||
if not all(
|
||||
[
|
||||
os.path.exists(intellicode_directory_path),
|
||||
@@ -520,13 +492,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
os.path.exists(intellisense_members_path),
|
||||
]
|
||||
):
|
||||
FileUtils.download_and_extract_archive_verified(
|
||||
cast(str, dependency["url"]),
|
||||
intellicode_directory_path,
|
||||
cast(str, dependency["archiveType"]),
|
||||
expected_sha256=cast(str | None, dependency["sha256"]),
|
||||
allowed_hosts=cast(tuple[str, ...], dependency["allowed_hosts"]),
|
||||
)
|
||||
intellicode_dep.download_to(intellicode_directory_path)
|
||||
|
||||
assert os.path.exists(intellicode_directory_path)
|
||||
assert os.path.exists(intellicode_jar_path)
|
||||
@@ -764,8 +730,9 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
major = int(version_match.group(1))
|
||||
return real_home, major
|
||||
|
||||
@staticmethod
|
||||
@classmethod
|
||||
def _compute_workspace_hash(
|
||||
cls,
|
||||
repository_root_path: str,
|
||||
jdtls_launcher_jar_path: str,
|
||||
custom_settings: SolidLSPSettings.CustomLSSettings,
|
||||
@@ -802,7 +769,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
|
||||
is_legacy_initial = (
|
||||
not custom_settings.get("jdtls_path")
|
||||
and custom_settings.get("vscode_java_version", DEFAULT_VSCODE_JAVA_VERSION) == INITIAL_VSCODE_JAVA_VERSION
|
||||
and custom_settings.get("vscode_java_version", cls.DEFAULT_VSCODE_JAVA_VERSION) == cls.INITIAL_VSCODE_JAVA_VERSION
|
||||
and not workspace_settings
|
||||
)
|
||||
if is_legacy_initial:
|
||||
|
||||
@@ -11,6 +11,7 @@ from overrides import override
|
||||
|
||||
from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_utils import is_running_in_ci
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
from solidlsp.util.subprocess_util import subprocess_run
|
||||
@@ -160,7 +161,7 @@ class ErlangLanguageServer(SolidLanguageServer):
|
||||
self.server.notify.initialized({})
|
||||
|
||||
# Wait for Erlang LS to be ready - adjust timeout based on environment
|
||||
is_ci = os.getenv("CI") == "true" or os.getenv("GITHUB_ACTIONS") == "true"
|
||||
is_ci = is_running_in_ci()
|
||||
is_macos = os.uname().sysname == "Darwin" if hasattr(os, "uname") else False
|
||||
|
||||
# macOS in CI can be particularly slow for language server startup
|
||||
|
||||
@@ -6,6 +6,7 @@ import dataclasses
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
from typing import cast
|
||||
|
||||
from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerConfig, LanguageServerId
|
||||
@@ -184,7 +185,7 @@ class GroovyLanguageServer(SolidLanguageServer):
|
||||
java_home_relative_path = java_dependency["java_home_path"]
|
||||
java_relative_path = java_dependency["java_path"]
|
||||
java_download_url = java_dependency["url"]
|
||||
java_archive_type = java_dependency["archiveType"]
|
||||
java_archive_type = cast(FileUtils.ArchiveType, java_dependency["archiveType"])
|
||||
assert java_home_relative_path is not None
|
||||
assert java_relative_path is not None
|
||||
assert java_download_url is not None
|
||||
|
||||
@@ -13,6 +13,7 @@ import tarfile
|
||||
import tempfile
|
||||
import uuid
|
||||
import zipfile
|
||||
from collections.abc import Sequence
|
||||
from enum import Enum
|
||||
from pathlib import Path, PurePath
|
||||
from typing import Literal, cast
|
||||
@@ -28,6 +29,15 @@ from solidlsp.util.subprocess_util import subprocess_run
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def is_running_in_ci() -> bool:
|
||||
"""
|
||||
Determines whether the current process is running in a Continuous Integration (CI) environment.
|
||||
|
||||
:return: True if running in CI, False otherwise
|
||||
"""
|
||||
return os.getenv("CI") == "true" or os.getenv("GITHUB_ACTIONS") == "true"
|
||||
|
||||
|
||||
class TextStepper:
|
||||
r"""
|
||||
A utility class for stepping through a text string line by line, keeping track of the current line and column numbers.
|
||||
@@ -383,6 +393,8 @@ class FileUtils:
|
||||
Utility functions for file operations.
|
||||
"""
|
||||
|
||||
ArchiveType = Literal["tar", "gztar", "bztar", "xztar", "zip", "zip.gz", "gz", "binary"]
|
||||
|
||||
@staticmethod
|
||||
def read_file(file_path: str, encoding: str) -> str:
|
||||
"""
|
||||
@@ -429,7 +441,7 @@ class FileUtils:
|
||||
url: str,
|
||||
target_path: str,
|
||||
expected_sha256: str | None = None,
|
||||
allowed_hosts: tuple[str, ...] | list[str] | None = None,
|
||||
allowed_hosts: Sequence[str] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Downloads a file from ``url`` to ``target_path`` with optional integrity and host validation.
|
||||
@@ -468,7 +480,7 @@ class FileUtils:
|
||||
Path.unlink(Path(temp_file_path))
|
||||
|
||||
@staticmethod
|
||||
def download_and_extract_archive(url: str, target_path: str, archive_type: str) -> None:
|
||||
def download_and_extract_archive(url: str, target_path: str, archive_type: ArchiveType) -> None:
|
||||
"""
|
||||
Downloads the archive from the given URL having format {archive_type} and extracts it to the given {target_path}
|
||||
"""
|
||||
@@ -478,9 +490,9 @@ class FileUtils:
|
||||
def download_and_extract_archive_verified(
|
||||
url: str,
|
||||
target_path: str,
|
||||
archive_type: str,
|
||||
archive_type: ArchiveType,
|
||||
expected_sha256: str | None = None,
|
||||
allowed_hosts: tuple[str, ...] | list[str] | None = None,
|
||||
allowed_hosts: Sequence[str] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Downloads an archive from ``url`` and extracts it safely into ``target_path``.
|
||||
@@ -560,7 +572,7 @@ class FileUtils:
|
||||
raise SolidLSPException(f"Checksum verification failed for '{file_path}': expected {expected_sha256}, got {actual_sha256}")
|
||||
|
||||
@staticmethod
|
||||
def _validate_download_host(url: str, allowed_hosts: tuple[str, ...] | list[str] | None) -> None:
|
||||
def _validate_download_host(url: str, allowed_hosts: Sequence[str] | None) -> None:
|
||||
"""
|
||||
Validates that a download URL resolves to one of the configured hosts.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"https://services.gradle.org/distributions/gradle-8.14.2-bin.zip": "7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999",
|
||||
"https://VisualStudioExptTeam.gallery.vsassets.io/_apis/public/gallery/publisher/VisualStudioExptTeam/extension/vscodeintellicode/1.2.30/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage": "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251",
|
||||
"https://github.com/redhat-developer/vscode-java/releases/download/v1.54.0/java-darwin-arm64-1.54.0-923.vsix": "c54c45cb0d2579d8e0a4ddeb24d4a9dd0b460d07d9366adea2b38a1da22a463c",
|
||||
"https://github.com/redhat-developer/vscode-java/releases/download/v1.54.0/java-darwin-x64-1.54.0-923.vsix": "dfc98abc4e54165a78372e280242a039671729b1b03420608df3b10c6b629fb6",
|
||||
"https://github.com/redhat-developer/vscode-java/releases/download/v1.54.0/java-linux-arm64-1.54.0-923.vsix": "e2bb22c427d90da8dbb1afff72ff1e2dce38d50b76deb02d7bc313a330a1330c",
|
||||
"https://github.com/redhat-developer/vscode-java/releases/download/v1.54.0/java-linux-x64-1.54.0-923.vsix": "9d4b15da54e25a0192f9bac073f086c015397d3676623b68dbf83a5dbaf5132b",
|
||||
"https://github.com/redhat-developer/vscode-java/releases/download/v1.54.0/java-win32-x64-1.54.0-923.vsix": "66f3914987edeccfee8a2558470e0fde4f8c4154232ff4baa5d73373ebc819d4"
|
||||
}
|
||||
@@ -16,6 +16,9 @@ if TYPE_CHECKING:
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
SOLIDLSP_RESOURCES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources")
|
||||
|
||||
|
||||
@dataclass
|
||||
class SolidLSPSettings:
|
||||
"""
|
||||
|
||||
@@ -545,9 +545,7 @@ class TestComputeWorkspaceHash:
|
||||
UPSTREAM_LAUNCHER = "/opt/homebrew/Cellar/jdtls/1.50.0/libexec/plugins/org.eclipse.equinox.launcher_1.7.0.jar"
|
||||
|
||||
def _initial_settings(self) -> "SolidLSPSettings.CustomLSSettings":
|
||||
from solidlsp.language_servers.eclipse_jdtls import INITIAL_VSCODE_JAVA_VERSION
|
||||
|
||||
return SolidLSPSettings.CustomLSSettings({"vscode_java_version": INITIAL_VSCODE_JAVA_VERSION})
|
||||
return SolidLSPSettings.CustomLSSettings({"vscode_java_version": EclipseJDTLS.DependencyProvider.INITIAL_VSCODE_JAVA_VERSION})
|
||||
|
||||
def test_initial_default_mode_matches_pre_upstream_format(self) -> None:
|
||||
"""Legacy carve-out: INITIAL default-mode hash MUST equal md5(repository_root_path)."""
|
||||
|
||||
Reference in new issue
Block a user