11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT license.
33import * as cp from "child_process" ;
4+ import * as fs from "fs" ;
45import * as _ from "lodash" ;
56import * as path from "path" ;
67import * as vscode from "vscode" ;
@@ -17,19 +18,25 @@ enum shortenApproach {
1718
1819const HELPFUL_NPE_VMARGS = "-XX:+ShowCodeDetailsInExceptionMessages" ;
1920
20- export async function detectLaunchCommandStyle ( config : vscode . DebugConfiguration ) : Promise < shortenApproach > {
21- const javaExec : string = config . javaExec || path . join ( await getJavaHome ( ) , "bin" , "java" ) ;
22- const javaVersion = await checkJavaVersion ( javaExec ) ;
23- const recommendedShortenApproach = javaVersion <= 8 ? shortenApproach . jarmanifest : shortenApproach . argfile ;
21+ /**
22+ * Returns the recommended approach to shorten the command line length.
23+ * @param config the launch configuration
24+ * @param runtimeVersion the target runtime version
25+ */
26+ export async function getShortenApproachForCLI ( config : vscode . DebugConfiguration , runtimeVersion : number ) : Promise < shortenApproach > {
27+ const recommendedShortenApproach = runtimeVersion <= 8 ? shortenApproach . jarmanifest : shortenApproach . argfile ;
2428 return ( await shouldShortenIfNecessary ( config ) ) ? recommendedShortenApproach : shortenApproach . none ;
2529}
2630
27- export async function validateRuntime ( config : vscode . DebugConfiguration ) {
31+ /**
32+ * Validates whether the specified runtime version could be supported by the Java tooling.
33+ * @param runtimeVersion the target runtime version
34+ */
35+ export async function validateRuntimeCompatibility ( runtimeVersion : number ) {
2836 try {
2937 const platformSettings = await fetchPlatformSettings ( ) ;
3038 if ( platformSettings && platformSettings . latestSupportedJavaVersion ) {
3139 const latestSupportedVersion = flattenMajorVersion ( platformSettings . latestSupportedJavaVersion ) ;
32- const runtimeVersion = await checkJavaVersion ( config . javaExec || path . join ( await getJavaHome ( ) , "bin" , "java" ) ) ;
3340 if ( latestSupportedVersion < runtimeVersion ) {
3441 showWarningMessageWithTroubleshooting ( {
3542 message : "The compiled classes are not compatible with the runtime JDK. To mitigate the issue, please refer to \"Learn More\"." ,
@@ -42,11 +49,14 @@ export async function validateRuntime(config: vscode.DebugConfiguration) {
4249 }
4350}
4451
45- export async function addMoreHelpfulVMArgs ( config : vscode . DebugConfiguration ) {
52+ /**
53+ * Add some helpful VM arguments to the launch configuration based on the target runtime version.
54+ * @param config the launch configuration
55+ * @param runtimeVersion the target runtime version
56+ */
57+ export async function addMoreHelpfulVMArgs ( config : vscode . DebugConfiguration , runtimeVersion : number ) {
4658 try {
47- const javaExec = config . javaExec || path . join ( await getJavaHome ( ) , "bin" , "java" ) ;
48- const version = await checkJavaVersion ( javaExec ) ;
49- if ( version >= 14 ) {
59+ if ( runtimeVersion >= 14 ) {
5060 // JEP-358: https://openjdk.java.net/jeps/358
5161 if ( config . vmArgs && config . vmArgs . indexOf ( HELPFUL_NPE_VMARGS ) >= 0 ) {
5262 return ;
@@ -59,23 +69,63 @@ export async function addMoreHelpfulVMArgs(config: vscode.DebugConfiguration) {
5969 }
6070}
6171
62- function checkJavaVersion ( javaExec : string ) : Promise < number > {
63- return new Promise ( ( resolve , _reject ) => {
64- cp . execFile ( javaExec , [ "-version" ] , { } , ( _error , _stdout , stderr ) => {
65- const javaVersion = parseMajorVersion ( stderr ) ;
66- resolve ( javaVersion ) ;
67- } ) ;
68- } ) ;
72+ /**
73+ * Returns the target runtime version. If the javaExec is not specified, then return the current Java version
74+ * that the Java tooling used.
75+ * @param javaExec the path of the Java executable
76+ */
77+ export async function getJavaVersion ( javaExec : string ) : Promise < number > {
78+ javaExec = javaExec || path . join ( await getJavaHome ( ) , "bin" , "java" ) ;
79+ let javaVersion = await checkVersionInReleaseFile ( path . resolve ( javaExec , ".." , ".." ) ) ;
80+ if ( ! javaVersion ) {
81+ javaVersion = await checkVersionByCLI ( javaExec ) ;
82+ }
83+ return javaVersion ;
6984}
7085
71- function parseMajorVersion ( content : string ) : number {
72- const regexp = / v e r s i o n " ( .* ) " / g;
73- const match = regexp . exec ( content ) ;
74- if ( ! match ) {
86+ async function checkVersionInReleaseFile ( javaHome : string ) : Promise < number > {
87+ if ( ! javaHome ) {
7588 return 0 ;
7689 }
90+ const releaseFile = path . join ( javaHome , "release" ) ;
91+ if ( ! await fs . existsSync ( releaseFile ) ) {
92+ return 0 ;
93+ }
94+
95+ try {
96+ const content = fs . readFileSync ( releaseFile ) ;
97+ const regexp = / ^ J A V A _ V E R S I O N = " ( .* ) " / gm;
98+ const match = regexp . exec ( content . toString ( ) ) ;
99+ if ( ! match ) {
100+ return 0 ;
101+ }
102+ const majorVersion = flattenMajorVersion ( match [ 1 ] ) ;
103+ return majorVersion ;
104+ } catch ( error ) {
105+ // ignore
106+ }
107+
108+ return 0 ;
109+ }
77110
78- return flattenMajorVersion ( match [ 1 ] ) ;
111+ /**
112+ * Get version by parsing `JAVA_HOME/bin/java -version`
113+ */
114+ async function checkVersionByCLI ( javaExec : string ) : Promise < number > {
115+ if ( ! javaExec ) {
116+ return 0 ;
117+ }
118+ return new Promise ( ( resolve ) => {
119+ cp . execFile ( javaExec , [ "-version" ] , { } , ( _error , _stdout , stderr ) => {
120+ const regexp = / v e r s i o n " ( .* ) " / g;
121+ const match = regexp . exec ( stderr ) ;
122+ if ( ! match ) {
123+ return resolve ( 0 ) ;
124+ }
125+ const javaVersion = flattenMajorVersion ( match [ 1 ] ) ;
126+ resolve ( javaVersion ) ;
127+ } ) ;
128+ } ) ;
79129}
80130
81131function flattenMajorVersion ( version : string ) : number {
0 commit comments