mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[platform] improves JDK version detection
(vaguely related to IDEA-159314)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,11 +49,6 @@ public abstract class JdkVersionDetector {
|
||||
@Nullable
|
||||
public abstract JdkVersionInfo detectJdkVersionInfo(@NotNull String homePath, @NotNull ActionRunner actionRunner);
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public abstract String readVersionFromProcessOutput(@NotNull String homePath, @NotNull String[] command, String versionLineMarker,
|
||||
@NotNull ActionRunner actionRunner);
|
||||
|
||||
//todo[nik] replace with a service with different implementations for IDE process and for JPS process (need to exclude jps-builders module from IDEA classpath)
|
||||
public interface ActionRunner {
|
||||
Future<?> run(Runnable runnable);
|
||||
@@ -78,4 +73,4 @@ public abstract class JdkVersionDetector {
|
||||
return myBitness;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+103
-170
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,14 +17,23 @@ package org.jetbrains.jps.model.java.impl;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Bitness;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.util.io.BaseOutputReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.java.JdkVersionDetector;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
@@ -47,42 +56,31 @@ public class JdkVersionDetectorImpl extends JdkVersionDetector {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String detectJdkVersion(@NotNull String homePath, @NotNull final ActionRunner actionRunner) {
|
||||
final File path = new File(homePath, "jre/lib/rt.jar");
|
||||
try {
|
||||
JarFile runtimeArchive;
|
||||
public String detectJdkVersion(@NotNull String homePath, @NotNull ActionRunner runner) {
|
||||
File rtFile = new File(homePath, "jre/lib/rt.jar");
|
||||
if (rtFile.isFile()) {
|
||||
try {
|
||||
runtimeArchive = new JarFile(path, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
JarFile rtJar = new JarFile(rtFile, false);
|
||||
try {
|
||||
runtimeArchive = new JarFile(path.getParentFile(), false);
|
||||
}
|
||||
catch (IOException e1) {
|
||||
// jdk9 case. Alternatively, if jrt-fs.jar is not available, we could read the 'release' file
|
||||
runtimeArchive = new JarFile(new File(homePath, "jrt-fs.jar"));
|
||||
}
|
||||
}
|
||||
try {
|
||||
final Manifest manifest = runtimeArchive.getManifest();
|
||||
if (manifest != null) {
|
||||
final String version = manifest.getMainAttributes().getValue("Implementation-Version");
|
||||
if (version != null) {
|
||||
return "java version \"" + version + "\"";
|
||||
Manifest manifest = rtJar.getManifest();
|
||||
if (manifest != null) {
|
||||
String version = manifest.getMainAttributes().getValue("Implementation-Version");
|
||||
if (version != null) {
|
||||
return "java version \"" + version + "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
rtJar.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
runtimeArchive.close();
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
JdkVersionInfo info = detectJdkVersionInfo(homePath, actionRunner);
|
||||
if (info != null) {
|
||||
return info.getVersion();
|
||||
}
|
||||
return null;
|
||||
|
||||
JdkVersionInfo info = detectJdkVersionInfo(homePath, runner);
|
||||
return info != null ? info.getVersion() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,33 +89,34 @@ public class JdkVersionDetectorImpl extends JdkVersionDetector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdkVersionInfo detectJdkVersionInfo(@NotNull String homePath, @NotNull ActionRunner actionRunner) {
|
||||
String[] command = {homePath + File.separator + "bin" + File.separator + "java", "-version"};
|
||||
return readVersionInfoFromProcessOutput(homePath, command, null, actionRunner);
|
||||
}
|
||||
|
||||
public String readVersionFromProcessOutput(@NotNull String homePath, @NotNull String[] command, String versionLineMarker,
|
||||
@NotNull ActionRunner actionRunner) {
|
||||
JdkVersionInfo info = readVersionInfoFromProcessOutput(homePath, command, versionLineMarker, actionRunner);
|
||||
if (info != null) {
|
||||
return info.getVersion();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static JdkVersionInfo readVersionInfoFromProcessOutput(@NotNull String homePath, @NotNull String[] command, String versionLineMarker, @NotNull ActionRunner actionRunner) {
|
||||
if (!new File(homePath).exists()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
//noinspection HardCodedStringLiteral
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
VersionParsingThread parsingThread = new VersionParsingThread(process.getErrorStream(), versionLineMarker);
|
||||
final Future<?> parsingThreadFuture = actionRunner.run(parsingThread);
|
||||
ReadStreamThread readThread = new ReadStreamThread(process.getInputStream());
|
||||
actionRunner.run(readThread);
|
||||
|
||||
public JdkVersionInfo detectJdkVersionInfo(@NotNull String homePath, @NotNull ActionRunner runner) {
|
||||
File releaseFile = new File(homePath, "release");
|
||||
if (releaseFile.isFile()) {
|
||||
try {
|
||||
Properties p = new Properties();
|
||||
p.load(new FileInputStream(releaseFile));
|
||||
String version = p.getProperty("JAVA_FULL_VERSION", p.getProperty("JAVA_VERSION"));
|
||||
if (version != null) {
|
||||
version = StringUtil.unquoteString(version);
|
||||
int i = version.indexOf('+');
|
||||
if (i > 0) {
|
||||
version = version.substring(0, i);
|
||||
}
|
||||
String arch = StringUtil.unquoteString(p.getProperty("OS_ARCH", ""));
|
||||
boolean x64 = "x86_64".equals(arch) || "amd64".equals(arch);
|
||||
return new JdkVersionInfo("java version \"" + version + "\"", x64 ? Bitness.x64 : Bitness.x32);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
|
||||
String javaExe = homePath + File.separator + "bin" + File.separator + (SystemInfo.isWindows ? "java.exe" : "java");
|
||||
if (new File(javaExe).canExecute()) {
|
||||
try {
|
||||
Process process = new ProcessBuilder(javaExe, "-version").redirectErrorStream(true).start();
|
||||
VersionOutputReader reader = new VersionOutputReader(process.getInputStream(), runner);
|
||||
try {
|
||||
process.waitFor();
|
||||
}
|
||||
@@ -125,128 +124,62 @@ public class JdkVersionDetectorImpl extends JdkVersionDetector {
|
||||
LOG.info(e);
|
||||
process.destroy();
|
||||
}
|
||||
return reader.getVersionInfo();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
parsingThreadFuture.get();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
String version = parsingThread.getVersion();
|
||||
if (version != null) {
|
||||
return new JdkVersionInfo(version, parsingThread.getBitness());
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
LOG.info(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class ReadStreamThread implements Runnable {
|
||||
private final InputStream myStream;
|
||||
private static class VersionOutputReader extends BaseOutputReader {
|
||||
private static final BaseOutputReader.Options OPTIONS = new BaseOutputReader.Options() {
|
||||
@Override public SleepingPolicy policy() { return SleepingPolicy.BLOCKING; }
|
||||
@Override public boolean splitToLines() { return true; }
|
||||
@Override public boolean sendIncompleteLines() { return false; }
|
||||
@Override public boolean withSeparators() { return false; }
|
||||
};
|
||||
|
||||
protected ReadStreamThread(InputStream stream) {
|
||||
myStream = stream;
|
||||
private final ActionRunner myRunner;
|
||||
private final List<String> myLines;
|
||||
|
||||
public VersionOutputReader(@NotNull InputStream stream, @NotNull ActionRunner runner) {
|
||||
super(stream, CharsetToolkit.getDefaultSystemCharset(), OPTIONS);
|
||||
myRunner = runner;
|
||||
myLines = new CopyOnWriteArrayList<String>();
|
||||
start("java -version");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
int b = myStream.read();
|
||||
if (b == -1) break;
|
||||
@NotNull
|
||||
@Override
|
||||
protected Future<?> executeOnPooledThread(@NotNull Runnable runnable) {
|
||||
return myRunner.run(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTextAvailable(@NotNull String text) {
|
||||
myLines.add(text);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JdkVersionInfo getVersionInfo() {
|
||||
String version = null;
|
||||
Bitness arch = Bitness.x32;
|
||||
|
||||
for (String line : myLines) {
|
||||
if (line.contains("version")) {
|
||||
if (version == null) {
|
||||
version = line;
|
||||
}
|
||||
}
|
||||
else if (line.contains("64-Bit") || line.contains("x86_64") || line.contains("amd64")) {
|
||||
arch = Bitness.x64;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
|
||||
return version != null ? new JdkVersionInfo(version, arch) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VersionParsingThread implements Runnable {
|
||||
private Reader myReader;
|
||||
private final InputStream myStream;
|
||||
private boolean mySkipLF = false;
|
||||
private final String myVersionLineMarker;
|
||||
|
||||
private final AtomicReference<String> myVersionString = new AtomicReference<String>();
|
||||
private final AtomicReference<Bitness> myBitness = new AtomicReference<Bitness>(Bitness.x32);
|
||||
private static final String VERSION_LINE_MARKER = "version";
|
||||
private static final String BITNESS_64_MARKER = "64-Bit";
|
||||
|
||||
protected VersionParsingThread(InputStream input, String versionLineMarker) {
|
||||
myStream = input;
|
||||
myVersionLineMarker = versionLineMarker != null ? versionLineMarker : VERSION_LINE_MARKER;
|
||||
}
|
||||
|
||||
Bitness getBitness() {
|
||||
return myBitness.get();
|
||||
}
|
||||
|
||||
String getVersion() {
|
||||
return myVersionString.get();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
myReader = new InputStreamReader(myStream);
|
||||
while (true) {
|
||||
String line = readLine();
|
||||
if (line == null) return;
|
||||
if (line.contains(myVersionLineMarker)) {
|
||||
myVersionString.set(line);
|
||||
}
|
||||
if (line.contains(BITNESS_64_MARKER)) {
|
||||
myBitness.set(Bitness.x64);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
finally {
|
||||
if (myReader != null){
|
||||
try {
|
||||
myReader.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String readLine() throws IOException {
|
||||
boolean first = true;
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
while (true) {
|
||||
int c = myReader.read();
|
||||
if (c == -1) break;
|
||||
first = false;
|
||||
if (c == '\n') {
|
||||
if (mySkipLF) {
|
||||
mySkipLF = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (c == '\r') {
|
||||
mySkipLF = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
mySkipLF = false;
|
||||
buffer.append((char)c);
|
||||
}
|
||||
}
|
||||
if (first) return null;
|
||||
String s = buffer.toString();
|
||||
//if (Diagnostic.TRACE_ENABLED){
|
||||
// Diagnostic.trace(s);
|
||||
//}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.model
|
||||
|
||||
import com.intellij.openapi.util.Bitness
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import org.jetbrains.jps.model.java.JdkVersionDetector
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class JdkVersionDetectorTest {
|
||||
private val service = Executors.newFixedThreadPool(3)
|
||||
|
||||
@After fun tearDown() = service.shutdown()
|
||||
|
||||
@Test fun detectJdkVersion() {
|
||||
val jdkHome = System.getProperty("java.home")
|
||||
val jdkVersion = JdkVersionDetector.getInstance().detectJdkVersion(jdkHome, { service.submit(it) })
|
||||
assertEquals("java version \"${SystemInfo.JAVA_VERSION}\"", jdkVersion)
|
||||
}
|
||||
|
||||
@Test fun detectJdkVersionInfo() {
|
||||
val jdkHome = System.getProperty("java.home")
|
||||
val jdkVersion = JdkVersionDetector.getInstance().detectJdkVersionInfo(jdkHome, { service.submit(it) })
|
||||
assertEquals("java version \"${SystemInfo.JAVA_VERSION}\"", jdkVersion?.version)
|
||||
assertEquals(if (SystemInfo.is64Bit) Bitness.x64 else Bitness.x32, jdkVersion?.bitness)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,38 +13,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: Anna.Kozlova
|
||||
* Date: 12-Aug-2006
|
||||
* Time: 21:25:38
|
||||
*/
|
||||
package com.intellij.openapi.projectRoots.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.java.JdkVersionDetector;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* @author Anna.Kozlova
|
||||
* @since 12-Aug-2006
|
||||
*/
|
||||
public class SdkVersionUtil {
|
||||
private static final JdkVersionDetector.ActionRunner ACTION_RUNNER = new JdkVersionDetector.ActionRunner() {
|
||||
@Override
|
||||
public Future<?> run(Runnable runnable) {
|
||||
return ApplicationManager.getApplication().executeOnPooledThread(runnable);
|
||||
}
|
||||
};
|
||||
private static final JdkVersionDetector.ActionRunner ACTION_RUNNER = (r) -> ApplicationManager.getApplication().executeOnPooledThread(r);
|
||||
|
||||
private SdkVersionUtil() {
|
||||
}
|
||||
private SdkVersionUtil() { }
|
||||
|
||||
@Deprecated
|
||||
/** @deprecated use {@link #detectJdkVersion(String)} to be removed in IDEA 2018 */
|
||||
@Nullable
|
||||
public static String readVersionFromProcessOutput(@NotNull String homePath, @NonNls @NotNull String[] command, @NonNls String versionLineMarker) {
|
||||
return JdkVersionDetector.getInstance().readVersionFromProcessOutput(homePath, command, versionLineMarker, ACTION_RUNNER);
|
||||
@SuppressWarnings("unused")
|
||||
public static String readVersionFromProcessOutput(@NotNull String homePath, @NotNull String[] command, String versionLineMarker) {
|
||||
return JdkVersionDetector.getInstance().detectJdkVersion(homePath, ACTION_RUNNER);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -56,4 +45,4 @@ public class SdkVersionUtil {
|
||||
public static JdkVersionDetector.JdkVersionInfo getJdkVersionInfo(@NotNull String homePath) {
|
||||
return JdkVersionDetector.getInstance().detectJdkVersionInfo(homePath, ACTION_RUNNER);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user