diff --git a/extra/java-dap b/extra/java-dap new file mode 100755 index 00000000..74fae9e0 --- /dev/null +++ b/extra/java-dap @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Small wrapper to correctly initialize the Java DAP.""" + +import json +import logging +import os +import signal +import subprocess +import sys +import time + +from typing import Any, IO, Dict, List, Optional + +_JAVA_DAP_BUNDLE = '/run_dir/com.microsoft.java.debug.plugin-0.32.0.jar' + + +def _send_lsp_message(msg: Dict[str, Any], lsp: IO[bytes]) -> None: + serialized_msg = json.dumps({ + 'jsonrpc': '2.0', + **msg, + }) + payload = len(serialized_msg) + lsp.write((f'Content-Length: {len(serialized_msg)}\r\n\r\n' + + serialized_msg).encode('utf-8')) + lsp.flush() + + +def _receive_lsp_message(lsp: IO[bytes]) -> Optional[Dict[str, Any]]: + headers = b'' + while not headers.endswith(b'\r\n\r\n'): + byte = lsp.read(1) + if len(byte) == 0: + return None + headers += byte + content_length = 0 + for header in headers.strip().split(b'\r\n'): + name, value = header.split(b':', maxsplit=2) + if name.strip().lower() == b'content-length': + content_length = int(value.strip()) + serialized = b'' + while content_length: + chunk = lsp.read(content_length) + if not chunk: + raise Exception(f'short read: {serialized!r}') + content_length -= len(chunk) + serialized += chunk + return json.loads(serialized) + + +def _main() -> None: + with subprocess.Popen(['/usr/bin/run-language-server', '-l', 'java'], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE) as dap: + try: + _send_lsp_message( + { + 'id': 1, + 'method': 'initialize', + 'params': { + 'processId': None, + 'initializationOptions': { + 'bundles': [ + _JAVA_DAP_BUNDLE, + ], + }, + 'trace': 'verbose', + 'capabilities': {}, + }, + }, dap.stdin) + # Wait for the initialize message has been acknowledged. + # This maximizes the probability of success. + while True: + message = _receive_lsp_message(dap.stdout) + assert message + if message.get('method') == 'window/logMessage': + print(message.get('params', {}).get('message'), + file=sys.stderr) + if message.get('id') == 1: + break + _send_lsp_message( + { + 'id': 2, + 'method': 'workspace/executeCommand', + 'params': { + 'command': 'vscode.java.startDebugSession', + }, + }, dap.stdin) + # Wait for the reply. If the request errored out, exit early to + # send a clear signal to the caller. + while True: + message = _receive_lsp_message(dap.stdout) + assert message + if message.get('method') == 'window/logMessage': + print(message.get('params', {}).get('message'), + file=sys.stderr) + if message.get('id') == 2: + if 'error' in message: + print(message['error'].get('message'), file=sys.stderr) + return + break + # Keep reading to drain the queue. + while True: + message = _receive_lsp_message(dap.stdout) + if not message: + break + if message.get('method') == 'window/logMessage': + print(message.get('params', {}).get('message'), + file=sys.stderr) + except Exception: + logging.exception('failed') + finally: + pgrp = os.getpgid(dap.pid) + os.killpg(pgrp, signal.SIGINT) + + +if __name__ == '__main__': + _main() diff --git a/gen/Dockerfile.ejs b/gen/Dockerfile.ejs index 50c1581d..16e48f99 100644 --- a/gen/Dockerfile.ejs +++ b/gen/Dockerfile.ejs @@ -95,6 +95,9 @@ COPY ./run_dir /run_dir/ RUN ln -sf /usr/lib/chromium-browser/chromedriver /usr/local/bin COPY ./extra/apt-install /usr/bin/install-pkg +RUN mkdir -p /opt/dap/java/ +COPY ./extra/java-dap /opt/dap/java/run +RUN chmod +x /opt/dap/java/run COPY ./extra/_test_runner.py /home/runner/_test_runner.py COPY ./extra/cquery11 /opt/homes/cpp11/.cquery diff --git a/gen/run-language-server.ejs b/gen/run-language-server.ejs index 541e71ec..d1f48071 100644 --- a/gen/run-language-server.ejs +++ b/gen/run-language-server.ejs @@ -21,7 +21,7 @@ case "$LANGUAGE" in <% for ( let lang of languages ) { -%> <%- lang.names.map(x => `"${x}"`).join('|') %>) <% if ( lang.languageServer ) { -%> - <%- c(lang.languageServer.command) %> + exec <%- c(lang.languageServer.command) %> <% } else { -%> echo "No language server configured for <%= lang.name %>" >&2 exit 1 diff --git a/languages/java.toml b/languages/java.toml index 651e74a5..56878c80 100644 --- a/languages/java.toml +++ b/languages/java.toml @@ -8,7 +8,7 @@ packages = [ "openjdk-11-jdk" ] setup = [ - "mkdir -p /config/language-server && cd /config/language-server && wget http://download.eclipse.org/jdtls/milestones/0.21.0/jdt-language-server-0.21.0-201806152234.tar.gz && tar -xzf jdt-language-server-0.21.0-201806152234.tar.gz && rm jdt-language-server-0.21.0-201806152234.tar.gz && chown runner:runner -R /config/language-server", + "mkdir -p /config/language-server && cd /config/language-server && wget https://download.eclipse.org/jdtls/milestones/1.1.2/jdt-language-server-1.1.2-202105191944.tar.gz && tar -xzf jdt-language-server-1.1.2-202105191944.tar.gz && rm jdt-language-server-1.1.2-202105191944.tar.gz && chown runner:runner -R /config/language-server", "echo ' 4.0.0 mygroupid myartifactid 0.0-SNAPSHOT de.qaware.maven go-offline-maven-plugin 1.2.5 org.apache.maven.surefire surefire-junit4 2.20.1 PLUGIN com.querydsl querydsl-apt 4.2.1 jpa MAIN ' > /tmp/emptypom.xml", "mvn -f /tmp/emptypom.xml -Dmaven.repo.local=/home/runner/.m2/repository de.qaware.maven:go-offline-maven-plugin:resolve-dependencies dependency:copy-dependencies", "rm /tmp/emptypom.xml" @@ -43,11 +43,12 @@ command = [ "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Dosgi.bundles.defaultStartLevel=4", "-Declipse.product=org.eclipse.jdt.ls.core.product", + "-Dcom.microsoft.java.debug.serverAddress=localhost:41010", "-noverify", "-Xmx256m", "-XX:+UseConcMarkSweepGC", "-jar", - "/config/language-server/plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar", + "/config/language-server/plugins/org.eclipse.equinox.launcher_1.6.100.v20201223-0822.jar", "-configuration", "/config/language-server/config_linux", "-data", diff --git a/out/Dockerfile b/out/Dockerfile index 742b075f..aa1348fd 100755 --- a/out/Dockerfile +++ b/out/Dockerfile @@ -817,6 +817,9 @@ COPY ./run_dir /run_dir/ RUN ln -sf /usr/lib/chromium-browser/chromedriver /usr/local/bin COPY ./extra/apt-install /usr/bin/install-pkg +RUN mkdir -p /opt/dap/java/ +COPY ./extra/java-dap /opt/dap/java/run +RUN chmod +x /opt/dap/java/run COPY ./extra/_test_runner.py /home/runner/_test_runner.py COPY ./extra/cquery11 /opt/homes/cpp11/.cquery diff --git a/out/run-language-server b/out/run-language-server index 901b5cfa..e117c0b3 100755 --- a/out/run-language-server +++ b/out/run-language-server @@ -23,7 +23,7 @@ case "$LANGUAGE" in exit 1 ;; "java") - java -Declipse.application=org.eclipse.jdt.ls.core.id1 -Dosgi.bundles.defaultStartLevel=4 -Declipse.product=org.eclipse.jdt.ls.core.product -noverify -Xmx256m -XX:+UseConcMarkSweepGC -jar /config/language-server/plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar -configuration /config/language-server/config_linux -data /home/runner + exec java -Declipse.application=org.eclipse.jdt.ls.core.id1 -Dosgi.bundles.defaultStartLevel=4 -Declipse.product=org.eclipse.jdt.ls.core.product -Dcom.microsoft.java.debug.serverAddress=localhost:41010 -noverify -Xmx256m -XX:+UseConcMarkSweepGC -jar /config/language-server/plugins/org.eclipse.equinox.launcher_1.6.100.v20201223-0822.jar -configuration /config/language-server/config_linux -data /home/runner ;; "ballerina") echo "No language server configured for ballerina" >&2 @@ -34,7 +34,7 @@ case "$LANGUAGE" in exit 1 ;; "c") - cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery"}' + exec cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery"}' ;; "common lisp"|"clisp"|"lisp") echo "No language server configured for common lisp" >&2 @@ -45,10 +45,10 @@ case "$LANGUAGE" in exit 1 ;; "cpp"|"c++") - cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++17", "-pthread"]}' + exec cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++17", "-pthread"]}' ;; "cpp11") - cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++11", "-pthread"]}' + exec cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++11", "-pthread"]}' ;; "crystal") echo "No language server configured for crystal" >&2 @@ -63,10 +63,10 @@ case "$LANGUAGE" in exit 1 ;; "dart") - /usr/lib/dart/bin/dart /usr/lib/dart/bin/snapshots/analysis_server.dart.snapshot --lsp + exec /usr/lib/dart/bin/dart /usr/lib/dart/bin/snapshots/analysis_server.dart.snapshot --lsp ;; "deno") - deno lsp + exec deno lsp ;; "elisp") echo "No language server configured for elisp" >&2 @@ -93,7 +93,7 @@ case "$LANGUAGE" in exit 1 ;; "flow") - flow-language-server --stdio + exec flow-language-server --stdio ;; "forth") echo "No language server configured for forth" >&2 @@ -112,7 +112,7 @@ case "$LANGUAGE" in exit 1 ;; "go"|"golang") - /bin/bash -c /opt/homes/go/go/bin/bingo + exec /bin/bash -c /opt/homes/go/go/bin/bingo ;; "guile"|"scheme") echo "No language server configured for guile" >&2 @@ -123,7 +123,7 @@ case "$LANGUAGE" in exit 1 ;; "haxe") - haxe --server-listen stdio + exec haxe --server-listen stdio ;; "jest") echo "No language server configured for jest" >&2 @@ -186,16 +186,16 @@ case "$LANGUAGE" in exit 1 ;; "python3") - pyls -v + exec pyls -v ;; "pygame") - pyls -v + exec pyls -v ;; "python") - pyls -v + exec pyls -v ;; "pyxel") - pyls -v + exec pyls -v ;; "quil") echo "No language server configured for quil" >&2 @@ -222,7 +222,7 @@ case "$LANGUAGE" in exit 1 ;; "ruby") - solargraph stdio + exec solargraph stdio ;; "rust") echo "No language server configured for rust" >&2 diff --git a/out/share/polygott/phase2.d/java b/out/share/polygott/phase2.d/java index be12bb8a..7a92ecab 100755 --- a/out/share/polygott/phase2.d/java +++ b/out/share/polygott/phase2.d/java @@ -10,7 +10,7 @@ chown -R $(id -u):$(id -g) /home/runner echo 'Setup java' cd "${HOME}" -mkdir -p /config/language-server && cd /config/language-server && wget http://download.eclipse.org/jdtls/milestones/0.21.0/jdt-language-server-0.21.0-201806152234.tar.gz && tar -xzf jdt-language-server-0.21.0-201806152234.tar.gz && rm jdt-language-server-0.21.0-201806152234.tar.gz && chown runner:runner -R /config/language-server +mkdir -p /config/language-server && cd /config/language-server && wget https://download.eclipse.org/jdtls/milestones/1.1.2/jdt-language-server-1.1.2-202105191944.tar.gz && tar -xzf jdt-language-server-1.1.2-202105191944.tar.gz && rm jdt-language-server-1.1.2-202105191944.tar.gz && chown runner:runner -R /config/language-server echo ' 4.0.0 mygroupid myartifactid 0.0-SNAPSHOT de.qaware.maven go-offline-maven-plugin 1.2.5 org.apache.maven.surefire surefire-junit4 2.20.1 PLUGIN com.querydsl querydsl-apt 4.2.1 jpa MAIN ' > /tmp/emptypom.xml mvn -f /tmp/emptypom.xml -Dmaven.repo.local=/home/runner/.m2/repository de.qaware.maven:go-offline-maven-plugin:resolve-dependencies dependency:copy-dependencies rm /tmp/emptypom.xml diff --git a/run_dir/com.microsoft.java.debug.plugin-0.32.0.jar b/run_dir/com.microsoft.java.debug.plugin-0.32.0.jar new file mode 100644 index 00000000..44436186 Binary files /dev/null and b/run_dir/com.microsoft.java.debug.plugin-0.32.0.jar differ