Skip to content
This repository was archived by the owner on May 4, 2022. It is now read-only.

Commit 7d730c0

Browse files
committed
Add the Java DAP implementation (+LSP uprev)
This change bundles a pre-built binary of the Java DAP with microsoft/java-debug#379 and replit/java-debug@2a556e5 applied, so that we can specify what host/port it should bind to, in addition to always using localhost as the interface that it binds to. In order for this to function correctly, it also needs to be running a more recent version of the Java LSP, so we will upgrade that too.
1 parent 0bb3692 commit 7d730c0

File tree

9 files changed

+143
-18
lines changed

9 files changed

+143
-18
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
!extra/cquery11
1010
!extra/fluxbox/apps
1111
!extra/fluxbox/init
12+
!extra/java-dap
1213
!extra/lang-gitignore
1314
!extra/matplotlibrc
1415
!extra/polygott-gitignore

extra/java-dap

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python3
2+
"""Small wrapper to correctly initialize the Java DAP."""
3+
4+
import json
5+
import logging
6+
import os
7+
import signal
8+
import subprocess
9+
import sys
10+
import time
11+
12+
from typing import Any, IO, Dict, List, Optional
13+
14+
_JAVA_DAP_BUNDLE = '/run_dir/com.microsoft.java.debug.plugin-0.32.0.jar'
15+
16+
17+
def _send_lsp_message(msg: Dict[str, Any], lsp: IO[bytes]) -> None:
18+
serialized_msg = json.dumps({
19+
'jsonrpc': '2.0',
20+
**msg,
21+
})
22+
payload = len(serialized_msg)
23+
lsp.write((f'Content-Length: {len(serialized_msg)}\r\n\r\n' +
24+
serialized_msg).encode('utf-8'))
25+
lsp.flush()
26+
27+
28+
def _receive_lsp_message(lsp: IO[bytes]) -> Optional[Dict[str, Any]]:
29+
headers = b''
30+
while not headers.endswith(b'\r\n\r\n'):
31+
byte = lsp.read(1)
32+
if len(byte) == 0:
33+
return None
34+
headers += byte
35+
content_length = 0
36+
for header in headers.strip().split(b'\r\n'):
37+
name, value = header.split(b':', maxsplit=2)
38+
if name.strip().lower() == b'content-length':
39+
content_length = int(value.strip())
40+
serialized = b''
41+
while content_length:
42+
chunk = lsp.read(content_length)
43+
if not chunk:
44+
raise Exception(f'short read: {serialized!r}')
45+
content_length -= len(chunk)
46+
serialized += chunk
47+
return json.loads(serialized)
48+
49+
50+
def _main() -> None:
51+
with subprocess.Popen(['/usr/bin/run-language-server', '-l', 'java'],
52+
stdout=subprocess.PIPE,
53+
stdin=subprocess.PIPE) as dap:
54+
try:
55+
_send_lsp_message(
56+
{
57+
'id': 1,
58+
'method': 'initialize',
59+
'params': {
60+
'processId': None,
61+
'initializationOptions': {
62+
'bundles': [
63+
_JAVA_DAP_BUNDLE,
64+
],
65+
},
66+
'trace': 'verbose',
67+
'capabilities': {},
68+
},
69+
}, dap.stdin)
70+
# Wait for the initialize message has been acknowledged.
71+
# This maximizes the probability of success.
72+
while True:
73+
message = _receive_lsp_message(dap.stdout)
74+
assert message
75+
if message.get('method') == 'window/logMessage':
76+
print(message.get('params', {}).get('message'),
77+
file=sys.stderr)
78+
if message.get('id') == 1:
79+
break
80+
_send_lsp_message(
81+
{
82+
'id': 2,
83+
'method': 'workspace/executeCommand',
84+
'params': {
85+
'command': 'vscode.java.startDebugSession',
86+
},
87+
}, dap.stdin)
88+
# Wait for the reply. If the request errored out, exit early to
89+
# send a clear signal to the caller.
90+
while True:
91+
message = _receive_lsp_message(dap.stdout)
92+
assert message
93+
if message.get('method') == 'window/logMessage':
94+
print(message.get('params', {}).get('message'),
95+
file=sys.stderr)
96+
if message.get('id') == 2:
97+
if 'error' in message:
98+
print(message['error'].get('message'), file=sys.stderr)
99+
return
100+
break
101+
# Keep reading to drain the queue.
102+
while True:
103+
message = _receive_lsp_message(dap.stdout)
104+
if not message:
105+
break
106+
if message.get('method') == 'window/logMessage':
107+
print(message.get('params', {}).get('message'),
108+
file=sys.stderr)
109+
except Exception:
110+
logging.exception('failed')
111+
finally:
112+
pgrp = os.getpgid(dap.pid)
113+
os.killpg(pgrp, signal.SIGINT)
114+
115+
116+
if __name__ == '__main__':
117+
_main()

gen/Dockerfile.ejs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ COPY ./run_dir /run_dir/
9595
RUN ln -sf /usr/lib/chromium-browser/chromedriver /usr/local/bin
9696

9797
COPY ./extra/apt-install /usr/bin/install-pkg
98+
RUN mkdir -p /opt/dap/java/
99+
COPY ./extra/java-dap /opt/dap/java/run
100+
RUN chmod +x /opt/dap/java/run
98101

99102
COPY ./extra/_test_runner.py /home/runner/_test_runner.py
100103
COPY ./extra/cquery11 /opt/homes/cpp11/.cquery

gen/run-language-server.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ case "$LANGUAGE" in
2121
<% for ( let lang of languages ) { -%>
2222
<%- lang.names.map(x => `"${x}"`).join('|') %>)
2323
<% if ( lang.languageServer ) { -%>
24-
<%- c(lang.languageServer.command) %>
24+
exec <%- c(lang.languageServer.command) %>
2525
<% } else { -%>
2626
echo "No language server configured for <%= lang.name %>" >&2
2727
exit 1

languages/java.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ packages = [
88
"openjdk-11-jdk"
99
]
1010
setup = [
11-
"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",
11+
"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",
1212
"echo '<project> <modelVersion>4.0.0</modelVersion> <groupId>mygroupid</groupId> <artifactId>myartifactid</artifactId> <version>0.0-SNAPSHOT</version> <build><plugins> <plugin> <groupId>de.qaware.maven</groupId> <artifactId>go-offline-maven-plugin</artifactId> <version>1.2.5</version> <configuration> <dynamicDependencies> <DynamicDependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit4</artifactId> <version>2.20.1</version> <repositoryType>PLUGIN</repositoryType> </DynamicDependency> <DynamicDependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>4.2.1</version> <classifier>jpa</classifier> <repositoryType>MAIN</repositoryType> </DynamicDependency> </dynamicDependencies> </configuration> </plugin> </plugins></build> </project>' > /tmp/emptypom.xml",
1313
"mvn -f /tmp/emptypom.xml -Dmaven.repo.local=/home/runner/.m2/repository de.qaware.maven:go-offline-maven-plugin:resolve-dependencies dependency:copy-dependencies",
1414
"rm /tmp/emptypom.xml"
@@ -43,11 +43,12 @@ command = [
4343
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
4444
"-Dosgi.bundles.defaultStartLevel=4",
4545
"-Declipse.product=org.eclipse.jdt.ls.core.product",
46+
"-Dcom.microsoft.java.debug.serverAddress=localhost:41010",
4647
"-noverify",
4748
"-Xmx256m",
4849
"-XX:+UseConcMarkSweepGC",
4950
"-jar",
50-
"/config/language-server/plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar",
51+
"/config/language-server/plugins/org.eclipse.equinox.launcher_1.6.100.v20201223-0822.jar",
5152
"-configuration",
5253
"/config/language-server/config_linux",
5354
"-data",

out/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,9 @@ COPY ./run_dir /run_dir/
817817
RUN ln -sf /usr/lib/chromium-browser/chromedriver /usr/local/bin
818818

819819
COPY ./extra/apt-install /usr/bin/install-pkg
820+
RUN mkdir -p /opt/dap/java/
821+
COPY ./extra/java-dap /opt/dap/java/run
822+
RUN chmod +x /opt/dap/java/run
820823

821824
COPY ./extra/_test_runner.py /home/runner/_test_runner.py
822825
COPY ./extra/cquery11 /opt/homes/cpp11/.cquery

out/run-language-server

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ case "$LANGUAGE" in
2323
exit 1
2424
;;
2525
"java")
26-
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
26+
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
2727
;;
2828
"ballerina")
2929
echo "No language server configured for ballerina" >&2
@@ -34,7 +34,7 @@ case "$LANGUAGE" in
3434
exit 1
3535
;;
3636
"c")
37-
cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery"}'
37+
exec cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery"}'
3838
;;
3939
"common lisp"|"clisp"|"lisp")
4040
echo "No language server configured for common lisp" >&2
@@ -45,10 +45,10 @@ case "$LANGUAGE" in
4545
exit 1
4646
;;
4747
"cpp"|"c++")
48-
cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++17", "-pthread"]}'
48+
exec cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++17", "-pthread"]}'
4949
;;
5050
"cpp11")
51-
cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++11", "-pthread"]}'
51+
exec cquery '--init={"progressReportFrequencyMs": -1,"cacheDirectory":"/tmp/cquery", "extraClangArguments": ["-std=c++11", "-pthread"]}'
5252
;;
5353
"crystal")
5454
echo "No language server configured for crystal" >&2
@@ -63,10 +63,10 @@ case "$LANGUAGE" in
6363
exit 1
6464
;;
6565
"dart")
66-
/usr/lib/dart/bin/dart /usr/lib/dart/bin/snapshots/analysis_server.dart.snapshot --lsp
66+
exec /usr/lib/dart/bin/dart /usr/lib/dart/bin/snapshots/analysis_server.dart.snapshot --lsp
6767
;;
6868
"deno")
69-
deno lsp
69+
exec deno lsp
7070
;;
7171
"elisp")
7272
echo "No language server configured for elisp" >&2
@@ -93,7 +93,7 @@ case "$LANGUAGE" in
9393
exit 1
9494
;;
9595
"flow")
96-
flow-language-server --stdio
96+
exec flow-language-server --stdio
9797
;;
9898
"forth")
9999
echo "No language server configured for forth" >&2
@@ -112,7 +112,7 @@ case "$LANGUAGE" in
112112
exit 1
113113
;;
114114
"go"|"golang")
115-
/bin/bash -c /opt/homes/go/go/bin/bingo
115+
exec /bin/bash -c /opt/homes/go/go/bin/bingo
116116
;;
117117
"guile"|"scheme")
118118
echo "No language server configured for guile" >&2
@@ -123,7 +123,7 @@ case "$LANGUAGE" in
123123
exit 1
124124
;;
125125
"haxe")
126-
haxe --server-listen stdio
126+
exec haxe --server-listen stdio
127127
;;
128128
"jest")
129129
echo "No language server configured for jest" >&2
@@ -186,16 +186,16 @@ case "$LANGUAGE" in
186186
exit 1
187187
;;
188188
"python3")
189-
pyls -v
189+
exec pyls -v
190190
;;
191191
"pygame")
192-
pyls -v
192+
exec pyls -v
193193
;;
194194
"python")
195-
pyls -v
195+
exec pyls -v
196196
;;
197197
"pyxel")
198-
pyls -v
198+
exec pyls -v
199199
;;
200200
"quil")
201201
echo "No language server configured for quil" >&2
@@ -222,7 +222,7 @@ case "$LANGUAGE" in
222222
exit 1
223223
;;
224224
"ruby")
225-
solargraph stdio
225+
exec solargraph stdio
226226
;;
227227
"rust")
228228
echo "No language server configured for rust" >&2

out/share/polygott/phase2.d/java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ chown -R $(id -u):$(id -g) /home/runner
1010
echo 'Setup java'
1111
cd "${HOME}"
1212

13-
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
13+
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
1414
echo '<project> <modelVersion>4.0.0</modelVersion> <groupId>mygroupid</groupId> <artifactId>myartifactid</artifactId> <version>0.0-SNAPSHOT</version> <build><plugins> <plugin> <groupId>de.qaware.maven</groupId> <artifactId>go-offline-maven-plugin</artifactId> <version>1.2.5</version> <configuration> <dynamicDependencies> <DynamicDependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit4</artifactId> <version>2.20.1</version> <repositoryType>PLUGIN</repositoryType> </DynamicDependency> <DynamicDependency> <groupId>com.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>4.2.1</version> <classifier>jpa</classifier> <repositoryType>MAIN</repositoryType> </DynamicDependency> </dynamicDependencies> </configuration> </plugin> </plugins></build> </project>' > /tmp/emptypom.xml
1515
mvn -f /tmp/emptypom.xml -Dmaven.repo.local=/home/runner/.m2/repository de.qaware.maven:go-offline-maven-plugin:resolve-dependencies dependency:copy-dependencies
1616
rm /tmp/emptypom.xml
2.4 MB
Binary file not shown.

0 commit comments

Comments
 (0)