diff --git a/README.md b/README.md
index 557243b5f0..f3fd26c8b7 100644
--- a/README.md
+++ b/README.md
@@ -67,21 +67,29 @@ java \
-Dlog.level=ALL \
-noverify \
-Xmx1G \
- -jar ./plugins/org.eclipse.equinox.launcher_1.5.200.v20180922-1751.jar \
- -configuration ./config_linux \
- -data /path/to/data \
--add-modules=ALL-SYSTEM \
--add-opens java.base/java.util=ALL-UNNAMED \
- --add-opens java.base/java.lang=ALL-UNNAMED
+ --add-opens java.base/java.lang=ALL-UNNAMED \
+ -jar ./plugins/org.eclipse.equinox.launcher_1.5.200.v20180922-1751.jar \
+ -configuration ./config_linux \
+ -data /path/to/data
```
1. Choose a value for `-configuration`: this is the path to your platform's configuration directory. For Linux, use `./config_linux`. For windows, use `./config_win`. For mac/OS X, use `./config_mac`.
2. Change the filename of the jar in `-jar ./plugins/...` to match the version you built or downloaded.
3. Choose a value for `-data`: An absolute path to your data directory. eclipse.jdt.ls stores workspace specific information in it. This should be unique per workspace/project.
-
If you want to debug eclipse.jdt.ls itself, add `-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044` right after `java` and ensure nothing else is running on port 1044. If you want to debug from the start of execution, change `suspend=n` to `suspend=y` so the JVM will wait for your debugger prior to starting the server.
+There is also a python wrapper script available that makes the start up of eclipse.jdt.ls more convenient (no need to juggle with Java options etc.). A sample usage is described below.
+
+```bash
+./org.eclipse.jdt.ls.product/target/repository/bin/jdtls \
+ -configuration ~/.cache/jdtls \
+ -data /path/to/data
+```
+
+All shown Java options will be set by the wrapper script. Please, note that the `-configuaration` options points to a user's folder to ensure that the configuration folder in `org.eclipse.jdt.ls.product/target/repository/config_*` remains untouched.
Development Setup
-----------------
diff --git a/org.eclipse.jdt.ls.product/pom.xml b/org.eclipse.jdt.ls.product/pom.xml
index ce5cb9a98b..29e2ff2649 100644
--- a/org.eclipse.jdt.ls.product/pom.xml
+++ b/org.eclipse.jdt.ls.product/pom.xml
@@ -66,7 +66,7 @@
maven-resources-plugin
- 3.0.1
+ 3.2.0
copy-config-mac
@@ -158,6 +158,21 @@
+
+ copy-launch-script
+ package
+
+ copy-resources
+
+
+ ${project.build.directory}/repository/bin/
+
+
+ ${basedir}/scripts
+
+
+
+
@@ -171,7 +186,7 @@
-
org.codehaus.mojo
diff --git a/org.eclipse.jdt.ls.product/publish-assembly.xml b/org.eclipse.jdt.ls.product/publish-assembly.xml
index ee3d4c4fda..26f2597581 100644
--- a/org.eclipse.jdt.ls.product/publish-assembly.xml
+++ b/org.eclipse.jdt.ls.product/publish-assembly.xml
@@ -9,8 +9,9 @@
${basedir}/target/repository
- /
+
+ bin/**
config_linux/**
config_mac/**
config_win/**
diff --git a/org.eclipse.jdt.ls.product/scripts/jdtls b/org.eclipse.jdt.ls.product/scripts/jdtls
new file mode 100755
index 0000000000..cce0b52620
--- /dev/null
+++ b/org.eclipse.jdt.ls.product/scripts/jdtls
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+import jdtls
+
+jdtls()
+
diff --git a/org.eclipse.jdt.ls.product/scripts/jdtls.py b/org.eclipse.jdt.ls.product/scripts/jdtls.py
new file mode 100644
index 0000000000..6b04f9f211
--- /dev/null
+++ b/org.eclipse.jdt.ls.product/scripts/jdtls.py
@@ -0,0 +1,93 @@
+import argparse
+import glob
+import os
+import platform
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+def get_java_executable(validate_java_version):
+ java_executable = 'java'
+
+ if 'JAVA_HOME' in os.environ:
+ java_exec_to_test = Path(os.environ['JAVA_HOME']) / 'bin' / 'java'
+ if java_exec_to_test.is_file():
+ java_executable = java_exec_to_test.resolve()
+
+ if not validate_java_version:
+ return java_executable
+
+ out = subprocess.check_output([java_executable, '-version'], stderr = subprocess.STDOUT, universal_newlines=True)
+
+ matches = re.finditer(r"(?P\d+)\.\d+\.\d+", out)
+ for matchNum, match in enumerate(matches):
+ java_major_version = int(match.group("major"))
+
+ if java_major_version < 11:
+ raise Exception("jdtls requires at least Java 11")
+
+ return java_executable
+
+ raise Exception("Could not determine Java version")
+
+def find_equinox_launcher(jdtls_base_directory):
+ plugins_dir = jdtls_base_directory / "plugins"
+ launchers = glob.glob('org.eclipse.equinox.launcher_*.jar', root_dir = plugins_dir)
+ if len(launchers) > 0:
+ return plugins_dir / launchers[0]
+
+ raise Exception("Cannot find equinox launcher")
+
+def get_shared_config_path(jdtls_base_path):
+ system = platform.system()
+
+ if system == 'Linux':
+ config_dir = 'config_linux'
+ elif system == 'Darwin':
+ config_dir = 'config_mac'
+ elif system == 'Windows':
+ config_dir = 'config_win'
+ else:
+ raise Exception("Unknown platform {} detected".format(platform))
+
+ return jdtls_base_path / config_dir
+
+def jdtls():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--validate-java-version", default=True, action=argparse.BooleanOptionalAction)
+ parser.add_argument("--jvm-arg",
+ default=[],
+ action="append",
+ help="An additional JVM option (can be used multiple times. Note, use with equal sign. For example: --jvm-arg=-Dlog.level=ALL")
+
+ known_args, args = parser.parse_known_args(sys.argv[1:])
+ java_executable = get_java_executable(known_args.validate_java_version)
+
+ jdtls_base_path = Path(__file__).parent.parent
+ shared_config_path = get_shared_config_path(jdtls_base_path)
+ jar_path = find_equinox_launcher(jdtls_base_path)
+
+ os.system(("{java_exec}"
+ " -Declipse.application=org.eclipse.jdt.ls.core.id1"
+ " -Dosgi.bundles.defaultStartLevel=4"
+ " -Declipse.product=org.eclipse.jdt.ls.core.product"
+ " -Dosgi.checkConfiguration=true"
+ " -Dosgi.sharedConfiguration.area='{shared_config_path}'"
+ " -Dosgi.sharedConfiguration.area.readOnly=true"
+ " -Dosgi.configuration.cascaded=true"
+ " -noverify"
+ " -Xms1G"
+ " --add-modules=ALL-SYSTEM"
+ " --add-opens java.base/java.util=ALL-UNNAMED"
+ " --add-opens java.base/java.lang=ALL-UNNAMED"
+ " {jvm_options}"
+ " -jar '{jar_path}'"
+ " {args}").format(
+ java_exec = java_executable,
+ shared_config_path = shared_config_path,
+ jar_path = jar_path,
+ jvm_options = " ".join(f"'{w}'" for w in known_args.jvm_arg),
+ args = " ".join(f"'{w}'" for w in args)))
+
+sys.modules[__name__] = jdtls