diff --git a/.gitignore b/.gitignore index f8bbe2a6f..7b4f85db1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ node_modules undefined target dist +jre bin/ .settings .classpath diff --git a/.vscode/launch.json b/.vscode/launch.json index 2620f81f0..633056f87 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -110,6 +110,26 @@ "outFiles": ["${workspaceRoot}/out/**/*.js"], "preLaunchTask": "prepareLightweightTest", "postDebugTask": "cleanTestFolder" + }, + { + "args": [ + "${input:gulpTask}" + ], + "name": "Launch Gulp Task", + "program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js", + "request": "launch", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + } + ], + "inputs": [ + { + "id": "gulpTask", + "type": "promptString", + "description": "Name of the Gulp task to execute", + "default": "download_jre" } ] } diff --git a/.vscodeignore b/.vscodeignore index b06821d22..aabc1e1ae 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -22,3 +22,4 @@ gulpfile.js Jenkinsfile tslint.json webpack.config.js +.DS_Store \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74edcb553..69fe5e875 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,6 +54,12 @@ The following will be a start to finish guide to get the entire language server ```bash $ npm install ``` +5. (**\*Optional**) Build a platform specific JRE: + + ```bash + $ npx gulp download_jre + ``` + You can also use the options `--target` and `--javaVersion` to build the specified JRE version for the specified target architecture. # diff --git a/Jenkinsfile b/Jenkinsfile index dc23d79fa..d36d976bb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -46,7 +46,8 @@ node('rhel8'){ stage "Package vscode-java" def packageJson = readJSON file: 'package.json' - sh "vsce package -o java-${packageJson.version}-${env.BUILD_NUMBER}.vsix" + env.EXTENSION_VERSION = "${packageJson.version}" + sh "vsce package -o java-${env.EXTENSION_VERSION}-${env.BUILD_NUMBER}.vsix" stage 'Test vscode-java for staging' wrap([$class: 'Xvnc']) { @@ -55,10 +56,28 @@ node('rhel8'){ sh "npm test --silent" } - stage 'Upload vscode-java to staging' def vsix = findFiles(glob: '**.vsix') - sh "rsync -Pzrlt --rsh=ssh --protocol=28 ${vsix[0].path} ${UPLOAD_LOCATION}/jdt.ls/staging" - stash name:'vsix', includes:files[0].path + stash name:'vsix', includes:vsix[0].path + + // Package platform specific versions + stage "Package platform specific vscode-java" + def platforms = ["win32-x64", "linux-x64", "linux-arm64", "darwin-x64", "darwin-arm64"] + def embeddedJRE = 17 + for(platform in platforms){ + sh "npx gulp download_jre --target ${platform} --javaVersion ${embeddedJRE}" + sh "vsce package --target ${platform} -o java-${platform}-${env.EXTENSION_VERSION}-${env.BUILD_NUMBER}.vsix" + } + stash name:'platformVsix', includes:'java-win32-*.vsix,java-linux-*.vsix,java-darwin-*.vsix' + + stage 'Upload vscode-java to staging' + def artifacts = findFiles(glob: '**.vsix') + def artifactDir = "java-${env.EXTENSION_VERSION}-${env.BUILD_NUMBER}" + sh "mkdir ${artifactDir}" + sh "mv *.vsix ${artifactDir}" + + for(artifact in artifacts){ + sh "rsync -Pzrlt --rsh=ssh --protocol=28 --relative ${artifactDir}/${artifact.path} ${UPLOAD_LOCATION}/jdt.ls/staging" + } } node('rhel8'){ @@ -67,24 +86,40 @@ node('rhel8'){ input message:'Approve deployment?', submitter: 'fbricon,rgrunber' } - stage "Publish to Marketplaces" + stage "Publish to Open-vsx Marketplace" unstash 'vsix' def vsix = findFiles(glob: '**.vsix') - // VS Code Marketplace - withCredentials([[$class: 'StringBinding', credentialsId: 'vscode_java_marketplace', variable: 'TOKEN']]) { - sh 'vsce publish -p ${TOKEN} --packagePath' + " ${vsix[0].path}" - } - // Open-vsx Marketplace sh "npm install -g ovsx" withCredentials([[$class: 'StringBinding', credentialsId: 'open-vsx-access-token', variable: 'OVSX_TOKEN']]) { sh 'ovsx publish -p ${OVSX_TOKEN}' + " ${vsix[0].path}" } - archive includes:"**.vsix" + stage "Publish to VS Code Marketplace" + // VS Code Marketplace + withCredentials([[$class: 'StringBinding', credentialsId: 'vscode_java_marketplace', variable: 'TOKEN']]) { + // Publish a generic version + sh 'vsce publish -p ${TOKEN} --target win32-ia32 win32-arm64 linux-armhf alpine-x64 alpine-arm64' + + // Publish platform specific versions + unstash 'platformVsix' + def platformVsixes = findFiles(glob: '**.vsix', excludes: vsix[0].path) + for(platformVsix in platformVsixes){ + sh 'vsce publish -p ${TOKEN}' + " --packagePath ${platformVsix.path}" + } + } stage "Publish to http://download.jboss.org/jbosstools/static/jdt.ls/stable/" + def artifacts = findFiles(glob: '**.vsix') + def artifactDir = "java-${env.EXTENSION_VERSION}" + sh "mkdir ${artifactDir}" + sh "mv *.vsix ${artifactDir}" + + archive includes:"${artifactDir}/**/*.*" + // copy this stable build to Akamai-mirrored /static/ URL, so staging can be cleaned out more easily - sh "rsync -Pzrlt --rsh=ssh --protocol=28 ${vsix[0].path} ${UPLOAD_LOCATION}/static/jdt.ls/stable/" + for(artifact in artifacts){ + sh "rsync -Pzrlt --rsh=ssh --protocol=28 --relative ${artifactDir}/${artifact.path} ${UPLOAD_LOCATION}/static/jdt.ls/stable/" + } }// if publishToMarketPlace } diff --git a/README.md b/README.md index d67397054..cd89beb44 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,16 @@ See the [changelog](CHANGELOG.md) for the latest release. You might also find us Setting the JDK =============== ## Java Tooling JDK -This JDK will be used to launch the Java Language Server. And by default, will also be used to compile your projects. +Now that Java extension will publish platform specific versions, it will embed a JRE for supported platforms such as `win32-x64`, `linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`. The embedded JRE is used to launch the Language Server for Java. Users are only responsible for configuring [Project JDKs](#project-jdks) to compile your Java projects. -The path to the Java Development Kit can be specified by the `java.home` setting in VS Code settings (workspace/user settings). If not specified, it is searched in the following order until a JDK meets current minimum requirement. +The following part is only kept for the universal version without embedded JRE. -- the `JDK_HOME` environment variable -- the `JAVA_HOME` environment variable -- on the current system path +>The tooling JDK will be used to launch the Language Server for Java. And by default, will also be used to compile your projects.\ +\ +The path to the Java Development Kit can be specified by the `java.home` setting in VS Code settings (workspace/user settings). If not specified, it is searched in the following order until a JDK meets current minimum requirement. +>- the `JDK_HOME` environment variable +>- the `JAVA_HOME` environment variable +>- on the current system path ## Project JDKs If you need to compile your projects against a different JDK version, it's recommended you configure the `java.configuration.runtimes` property in your user settings, eg: @@ -107,7 +110,7 @@ Supported VS Code settings ========================== The following settings are supported: -* `java.home` : Absolute path to JDK home folder used to launch the Java Language Server. Requires VS Code restart. +* `java.home` : **Deprecated, only used for universal version without embedded JRE.** Absolute path to JDK home folder used to launch the Java Language Server. Requires VS Code restart. * `java.jdt.ls.vmargs` : Extra VM arguments used to launch the Java Language Server. Requires VS Code restart. * `java.errors.incompleteClasspath.severity` : Specifies the severity of the message when the classpath is incomplete for a Java file. Supported values are `ignore`, `info`, `warning`, `error`. * `java.trace.server` : Traces the communication between VS Code and the Java language server. diff --git a/gulpfile.js b/gulpfile.js index 0dabd7a08..93c30cceb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,15 +3,119 @@ const gulp = require('gulp'); const cp = require('child_process'); const decompress = require('gulp-decompress'); const download = require('gulp-download'); +const request = require('request'); const glob = require('glob'); const fse = require('fs-extra'); const path = require('path'); +const url = require("url"); +const argv = require('minimist')(process.argv.slice(2)); const server_dir = '../eclipse.jdt.ls'; const originalTestFolder = path.join(__dirname, 'test', 'resources', 'projects', 'maven', 'salut'); const tempTestFolder = path.join(__dirname, 'test-temp'); const testSettings = path.join(tempTestFolder, '.vscode', 'settings.json'); //... +gulp.task('clean_jre', function(done) { + if (fse.existsSync('./jre')) { + fse.removeSync('./jre'); + } + + done(); +}); + +// Pls update the latest JRE if a new JDK is announced. +const LATEST_JRE = 17; + +/** + * Usage: + * npx gulp download_jre // Download the latest JRE for the platform of the current running machine. + * npx gulp download_jre --target darwin-x64 --javaVersion 17 // Download the specified JRE for the specified platform. + * + * Supported platforms: + * win32-x64, + * linux-x64, + * linux-arm64, + * darwin-x64, + * darwin-arm64 + */ +gulp.task('download_jre', async function(done) { + if (fse.existsSync('./jre')) { + fse.removeSync('./jre'); + } + + const platformMapping = { + "linux-arm64": "linux-aarch64", + "linux-x64": "linux-x86_64", + "darwin-arm64": "macosx-aarch64", + "darwin-x64": "macosx-x86_64", + "win32-x64": "win32-x86_64" + } + + const targetPlatform = argv.target || process.platform + "-" + process.arch; + if (targetPlatform && Object.keys(platformMapping).includes(targetPlatform)) { + const javaVersion = (!argv.javaVersion || argv.javaVersion === "latest") ? LATEST_JRE : argv.javaVersion; + console.log("Downloading justj JRE " + javaVersion + " for the platform " + targetPlatform) + "..."; + + const manifestUrl = `https://download.eclipse.org/justj/jres/${javaVersion}/downloads/latest/justj.manifest`; + // Download justj.manifest file + const manifest = await new Promise(function(resolve, reject) { + request.get(manifestUrl, function(err, response, body) { + if(err || response.statusCode >= 400) { + reject(err || `${response.statusCode} returned from ${manifestUrl}`); + } else { + resolve(String(body)); + } + }); + }); + + if (!manifest) { + done(new Error(`Failed to download justj.manifest, please check if the link ${manifestUrl} is valid.`)) + return; + } + + /** + * Here are the contents for a sample justj.manifest file: + * ../20211012_0921/org.eclipse.justj.openjdk.hotspot.jre.full.stripped-17-linux-aarch64.tar.gz + * ../20211012_0921/org.eclipse.justj.openjdk.hotspot.jre.full.stripped-17-linux-x86_64.tar.gz + * ../20211012_0921/org.eclipse.justj.openjdk.hotspot.jre.full.stripped-17-macosx-aarch64.tar.gz + * ../20211012_0921/org.eclipse.justj.openjdk.hotspot.jre.full.stripped-17-macosx-x86_64.tar.gz + * ../20211012_0921/org.eclipse.justj.openjdk.hotspot.jre.full.stripped-17-win32-x86_64.tar.gz + */ + const javaPlatform = platformMapping[targetPlatform]; + const list = manifest.split(/\r?\n/); + const jreIdentifier = list.find((value) => { + return value.indexOf("org.eclipse.justj.openjdk.hotspot.jre.full.stripped") >= 0 && value.indexOf(javaPlatform) >= 0; + }); + + if (!jreIdentifier) { + done(new Error(`justj doesn't support the jre ${javaVersion} for the platform ${javaPlatform} (${targetPlatform}), please refer to the link ${manifestUrl} for the supported platforms.`)); + return; + } + + const jreDownloadUrl = `https://download.eclipse.org/justj/jres/${javaVersion}/downloads/latest/${jreIdentifier}`; + const parsedDownloadUrl = url.parse(jreDownloadUrl); + const jreFileName = path.basename(parsedDownloadUrl.pathname) + .replace(/[\.7z|\.bz2|\.gz|\.rar|\.tar|\.zip|\.xz]*$/, ""); + const idx = jreFileName.indexOf('-'); + const jreVersionLabel = idx >= 0 ? jreFileName.substring(idx + 1) : jreFileName; + // Download justj JRE. + await new Promise(function(resolve, reject) { + download(jreDownloadUrl) + .on('error', reject) + .pipe(decompress({strip: 0})) + .pipe(gulp.dest('./jre/' + jreVersionLabel)) + .on('end', resolve); + }); + } else { + console.log("[Error] download_jre failed, please specify a valid target platform via --target argument. Here are the supported platform list:"); + for (const platform of Object.keys(platformMapping)) { + console.log(platform); + } + } + + done(); +}); + gulp.task('download_server', function(done) { fse.removeSync('./server'); download("http://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz") diff --git a/package-lock.json b/package-lock.json index 6a8e11594..c06e55e31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -322,12 +322,12 @@ } }, "ajv": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz", - "integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -534,9 +534,9 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "requires": { "safer-buffer": "~2.1.0" @@ -605,9 +605,9 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, "babel-code-frame": { @@ -1099,9 +1099,9 @@ } }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { "delayed-stream": "~1.0.0" @@ -1911,9 +1911,9 @@ } }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, "fast-json-stable-stringify": { @@ -2420,7 +2420,7 @@ "dev": true, "requires": { "gulp-util": "^3.0.8", - "request": "^2.88.0", + "request": "^2.88.2", "request-progress": "^3.0.0", "through": "^2.3.8" }, @@ -2535,12 +2535,12 @@ "dev": true }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "dev": true, "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, @@ -3039,9 +3039,9 @@ "dev": true }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "json-schema-traverse": { @@ -3071,14 +3071,14 @@ } }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, @@ -3505,18 +3505,18 @@ } }, "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", "dev": true }, "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "dev": true, "requires": { - "mime-db": "~1.37.0" + "mime-db": "1.51.0" } }, "mimic-fn": { @@ -4449,9 +4449,9 @@ "dev": true }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, "pump": { @@ -4620,9 +4620,9 @@ } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -4632,7 +4632,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -4642,7 +4642,7 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } @@ -5083,9 +5083,9 @@ "dev": true }, "sshpk": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -5396,21 +5396,13 @@ } }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "triple-beam": { @@ -5778,9 +5770,9 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, "v8-compile-cache": { diff --git a/package.json b/package.json index 709396a27..66dd25cc3 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "virtualWorkspaces": false }, "engines": { - "vscode": "^1.53.2" + "vscode": "^1.61.0" }, "repository": { "type": "git", @@ -170,7 +170,8 @@ ], "default": null, "description": "Specifies the folder path to the JDK (11 or more recent) used to launch the Java Language Server.\nOn Windows, backslashes must be escaped, i.e.\n\"java.home\":\"C:\\\\Program Files\\\\Java\\\\jdk11.0_8\"", - "scope": "machine-overridable" + "scope": "machine-overridable", + "deprecationMessage": "This setting will be deprecated, please use the environment variable 'JAVA_HOME' instead." }, "java.jdt.ls.vmargs": { "type": [ @@ -1138,6 +1139,7 @@ "lodash.template": ">=4.5.0", "minimist": ">=1.2.5", "mocha": "^9.1.3", + "request": "^2.88.2", "ts-loader": "^9.2.6", "tslint": "^5.11.0", "typescript": "^4.2.4", diff --git a/src/javaServerStarter.ts b/src/javaServerStarter.ts index 847b7b81e..ed500aafa 100644 --- a/src/javaServerStarter.ts +++ b/src/javaServerStarter.ts @@ -29,7 +29,7 @@ export function prepareExecutable(requirements: RequirementsData, workspacePath, const options: ExecutableOptions = Object.create(null); options.env = Object.assign({ syntaxserver : isSyntaxServer }, process.env); executable.options = options; - executable.command = path.resolve(requirements.java_home + '/bin/java'); + executable.command = path.resolve(requirements.tooling_jre + '/bin/java'); executable.args = prepareParams(requirements, javaConfig, workspacePath, context, isSyntaxServer); logger.info(`Starting Java server with: ${executable.command} ${executable.args.join(' ')}`); return executable; @@ -59,13 +59,12 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp // suspend=y is the default. Use this form if you need to debug the server startup code: // params.push('-agentlib:jdwp=transport=dt_socket,server=y,address=1044'); } - if (requirements.java_version > 8) { - params.push('--add-modules=ALL-SYSTEM', - '--add-opens', - 'java.base/java.util=ALL-UNNAMED', - '--add-opens', - 'java.base/java.lang=ALL-UNNAMED'); - } + + params.push('--add-modules=ALL-SYSTEM', + '--add-opens', + 'java.base/java.util=ALL-UNNAMED', + '--add-opens', + 'java.base/java.lang=ALL-UNNAMED'); params.push('-Declipse.application=org.eclipse.jdt.ls.core.id1', '-Dosgi.bundles.defaultStartLevel=4', @@ -122,7 +121,7 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp // "OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify // were deprecated in JDK 13 and will likely be removed in a future release." // so only add -noverify for older versions - if (params.indexOf('-noverify') < 0 && params.indexOf('-Xverify:none') < 0 && requirements.java_version < 13) { + if (params.indexOf('-noverify') < 0 && params.indexOf('-Xverify:none') < 0 && requirements.tooling_jre_version < 13) { params.push('-noverify'); } diff --git a/src/requirements.ts b/src/requirements.ts index afec0221a..a46a7e5d4 100644 --- a/src/requirements.ts +++ b/src/requirements.ts @@ -8,14 +8,16 @@ import * as expandHomeDir from 'expand-home-dir'; import findJavaHome = require("find-java-home"); import { Commands } from './commands'; import { checkJavaPreferences } from './settings'; -import { getJavaConfiguration } from './utils'; -import { findJavaHomes, getJavaVersion, JavaRuntime } from './findJavaRuntimes'; +import { findJavaHomes, getJavaVersion, JavaRuntime, verifyJavaHome } from './findJavaRuntimes'; +import { logger } from './log'; const isWindows = process.platform.indexOf('win') === 0; const JAVAC_FILENAME = 'javac' + (isWindows ? '.exe' : ''); const JAVA_FILENAME = 'java' + (isWindows ? '.exe' : ''); const REQUIRED_JDK_VERSION = 11; export interface RequirementsData { + tooling_jre: string; + tooling_jre_version: number; java_home: string; java_version: number; } @@ -34,12 +36,13 @@ interface ErrorData { * */ export async function resolveRequirements(context: ExtensionContext): Promise { + let toolingJre: string = await findEmbeddedJRE(context); + let toolingJreVersion: number = await getJavaVersion(toolingJre); return new Promise(async (resolve, reject) => { let source: string; let javaVersion: number = 0; let javaHome = await checkJavaPreferences(context); - if (javaHome) { - // java.home explictly specified + if (!toolingJre && javaHome) { // "java.home" setting is only used for the universal version. source = `java.home variable defined in ${env.appName} settings`; javaHome = expandHomeDir(javaHome); if (!await fse.pathExists(javaHome)) { @@ -54,25 +57,98 @@ export async function resolveRequirements(context: ExtensionContext): Promise r.version >= REQUIRED_JDK_VERSION); - if (validJdks.length > 0) { - sortJdksBySource(validJdks); - javaHome = validJdks[0].home; - javaVersion = validJdks[0].version; + if (!toolingJre) { // universal version + const validJdks = javaRuntimes.filter(r => r.version >= REQUIRED_JDK_VERSION); + if (validJdks.length > 0) { + sortJdksBySource(validJdks); + javaHome = validJdks[0].home; + javaVersion = validJdks[0].version; + toolingJre = javaHome; + toolingJreVersion = javaVersion; + } + } else { // pick a default project JDK + /** + * For legacy users, we implicitly following the order below to + * set a default project JDK during initialization: + * java.home > env.JDK_HOME > env.JAVA_HOME > env.PATH + * + * We'll keep it for compatibility. + */ + if (javaHome && (javaHome = await verifyJavaHome(javaHome, JAVAC_FILENAME))) { + javaVersion = await getJavaVersion(javaHome); + logger.info("Use the JDK from 'java.home' setting as the initial default project JDK."); + } else if (javaRuntimes.length) { + sortJdksBySource(javaRuntimes); + javaHome = javaRuntimes[0].home; + javaVersion = javaRuntimes[0].version; + logger.info(`Use the JDK from '${javaRuntimes[0].sources}' as the initial default project JDK.`); + } else if (javaHome = await findDefaultJDKFromSettings()) { + javaVersion = await getJavaVersion(javaHome); + logger.info("Use the JDK from 'java.configuration.runtimes' as the initial default project JDK."); + } else { + openJDKDownload(reject, "Please download and install a JDK to compile your project. You can configure your projects with different JDKs by the setting ['java.configuration.runtimes'](https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements#java.configuration.runtimes)"); + } } } - if (javaVersion < REQUIRED_JDK_VERSION) { + if (!toolingJre || toolingJreVersion < REQUIRED_JDK_VERSION) { + // For universal version, we still require users to install a qualified JDK to run Java extension. openJDKDownload(reject, `Java ${REQUIRED_JDK_VERSION} or more recent is required to run the Java extension. Please download and install a recent JDK. You can still compile your projects with older JDKs by configuring ['java.configuration.runtimes'](https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements#java.configuration.runtimes)`); } - resolve({ java_home: javaHome, java_version: javaVersion }); + resolve({ + tooling_jre: toolingJre, // Used to launch Java extension. + tooling_jre_version: toolingJreVersion, + java_home: javaHome, // Used as default project JDK. + java_version: javaVersion, + }); }); } +async function findEmbeddedJRE(context: ExtensionContext): Promise { + const jreHome = context.asAbsolutePath("jre"); + if (fse.existsSync(jreHome) && fse.statSync(jreHome).isDirectory()) { + const candidates = fse.readdirSync(jreHome); + for (const candidate of candidates) { + if (fse.existsSync(path.join(jreHome, candidate, "bin", JAVA_FILENAME))) { + return path.join(jreHome, candidate); + } + } + } + + return; +} + +async function findDefaultJDKFromSettings(): Promise { + const runtimes = workspace.getConfiguration().get("java.configuration.runtimes"); + if (Array.isArray(runtimes) && runtimes.length) { + let candidate: string; + for (const runtime of runtimes) { + if (!runtime || typeof runtime !== 'object' || !runtime.path) { + continue; + } + + const javaHome = await verifyJavaHome(runtime.path, JAVAC_FILENAME); + if (javaHome) { + candidate = javaHome; + } + + if (runtime.default) { + break; + } + } + + return candidate; + } + + return undefined; +} + function sortJdksBySource(jdks: JavaRuntime[]) { const rankedJdks = jdks as Array; const sources = ["env.JDK_HOME", "env.JAVA_HOME", "env.PATH"];