import * as cp from "child_process" ; import * as fs from "fs" ; import * as _ from "lodash" ; import * as path from "path" ; import * as vscode from "vscode" ; import { UNSUPPORTED_CLASS_VERSION_ERROR } from "./anchor" ; import { fetchPlatformSettings , inferLaunchCommandLength } from "./languageServerPlugin" ; import { getJavaHome , showWarningMessageWithTroubleshooting } from "./utility" ; enum shortenApproach { none = "none" , jarmanifest = "jarmanifest" , argfile = "argfile" } const HELPFUL_NPE_VMARGS = "-XX:+ShowCodeDetailsInExceptionMessages" ; param config param runtimeVersion export async function getShortenApproachForCLI ( config , runtimeVersion ) { const recommendedShortenApproach = runtimeVersion <= 8 ? shortenApproach . jarmanifest : shortenApproach . argfile ; return ( await shouldShortenIfNecessary ( config ) ) ? recommendedShortenApproach : shortenApproach . none ; } param runtimeVersion export async function validateRuntimeCompatibility ( runtimeVersion ) { try { const platformSettings = await fetchPlatformSettings ( ) ; if ( platformSettings && platformSettings . latestSupportedJavaVersion ) { const latestSupportedVersion = flattenMajorVersion ( platformSettings . latestSupportedJavaVersion ) ; if ( latestSupportedVersion < runtimeVersion ) { showWarningMessageWithTroubleshooting ( { message : "The compiled classes are not compatible with the runtime JDK. To mitigate the issue, please refer to \"Learn More\"." , anchor : UNSUPPORTED_CLASS_VERSION_ERROR , } ) ; } } } catch ( err ) { } } param config param runtimeVersion export async function addMoreHelpfulVMArgs ( config , runtimeVersion ) { try { if ( runtimeVersion >= 14 ) { if ( config . vmArgs && config . vmArgs . indexOf ( HELPFUL_NPE_VMARGS ) >= 0 ) { return ; } config . vmArgs = ( config . vmArgs || "" ) + " " + HELPFUL_NPE_VMARGS ; } } catch ( error ) { } } param javaExec export async function getJavaVersion ( javaExec ) { javaExec = javaExec || path . join ( await getJavaHome ( ) , "bin" , "java" ) ; let javaVersion = await checkVersionInReleaseFile ( path . resolve ( javaExec , ".." , ".." ) ) ; if ( ! javaVersion ) { javaVersion = await checkVersionByCLI ( javaExec ) ; } return javaVersion ; } async function checkVersionInReleaseFile ( javaHome ) { if ( ! javaHome ) { return 0 ; } const releaseFile = path . join ( javaHome , "release" ) ; if ( ! await fs . existsSync ( releaseFile ) ) { return 0 ; } try { const content = fs . readFileSync ( releaseFile ) ; const regexp = /^JAVA_VERSION="(.*)"/gm ; const match = regexp . exec ( content . toString ( ) ) ; if ( ! match ) { return 0 ; } const majorVersion = flattenMajorVersion ( match [ 1 ] ) ; return majorVersion ; } catch ( error ) { } return 0 ; } /**
 * Get version by parsing `JAVA_HOME/bin/java -version`
 */ async function checkVersionByCLI ( javaExec ) { if ( ! javaExec ) { return 0 ; } return new Promise ( ( resolve ) => { cp . execFile ( javaExec , [ "-version" ] , { } , ( _error , _stdout , stderr ) => { const regexp = /version "(.*)"/g ; const match = regexp . exec ( stderr ) ; if ( ! match ) { return resolve ( 0 ) ; } const javaVersion = flattenMajorVersion ( match [ 1 ] ) ; resolve ( javaVersion ) ; } ) ; } ) ; } function flattenMajorVersion ( version ) { if ( version . startsWith ( "1." ) ) { version = version . substring ( 2 ) ; } const regexp = /\d+/g ; const match = regexp . exec ( version ) ; let javaVersion = 0 ; if ( match ) { javaVersion = parseInt ( match [ 0 ] , 10 ) ; } return javaVersion ; } async function shouldShortenIfNecessary ( config ) { const cliLength = await inferLaunchCommandLength ( config ) ; const classPaths = config . classPaths || [ ] ; const modulePaths = config . modulePaths || [ ] ; const classPathLength = classPaths . join ( path . delimiter ) . length ; const modulePathLength = modulePaths . join ( path . delimiter ) . length ; if ( ! config . console || config . console === "internalConsole" ) { return cliLength >= getMaxProcessCommandLineLength ( config ) || classPathLength >= getMaxArgLength ( ) || modulePathLength >= getMaxArgLength ( ) ; } else { return classPaths . length > 1 || modulePaths . length > 1 ; } } function getMaxProcessCommandLineLength ( config ) { const ARG_MAX_WINDOWS = 32768 ; const ARG_MAX_MACOS = 262144 ; const ARG_MAX_LINUX = 2097152 ; if ( process . platform === "win32" ) { return ARG_MAX_WINDOWS - 2048 ; } else if ( process . platform === "darwin" ) { return ARG_MAX_MACOS - getEnvironmentLength ( config ) - 2048 ; } else if ( process . platform === "linux" ) { return ARG_MAX_LINUX - getEnvironmentLength ( config ) - 2048 ; } return Number . MAX_SAFE_INTEGER ; } function getEnvironmentLength ( config ) { const env = config . env || { } ; return _ . isEmpty ( env ) ? 0 : Object . keys ( env ) . map ( ( key ) => strlen ( key ) + strlen ( env [ key ] ) + 1 ) . reduce ( ( a , b ) => a + b ) ; } function strlen ( str ) { return str ? str . length : 0 ; } function getMaxArgLength ( ) { const MAX_ARG_STRLEN_LINUX = 131072 ; if ( process . platform === "linux" ) { return MAX_ARG_STRLEN_LINUX - 2048 ; } return Number . MAX_SAFE_INTEGER ; }