2019-07-30 14:01:45 -04:00
let tempDirectory = process . env [ 'RUNNER_TEMP' ] || '' ;
2019-07-10 23:11:48 -04:00
import * as core from '@actions/core' ;
import * as io from '@actions/io' ;
import * as exec from '@actions/exec' ;
2020-02-06 15:16:41 -05:00
import * as httpm from '@actions/http-client' ;
2019-07-10 23:11:48 -04:00
import * as tc from '@actions/tool-cache' ;
import * as fs from 'fs' ;
import * as path from 'path' ;
2019-07-18 16:00:58 -04:00
import * as semver from 'semver' ;
2019-07-10 23:11:48 -04:00
const IS_WINDOWS = process . platform === 'win32' ;
if ( ! tempDirectory ) {
let baseLocation ;
if ( IS_WINDOWS ) {
// On windows use the USERPROFILE env variable
baseLocation = process . env [ 'USERPROFILE' ] || 'C:\\' ;
} else {
if ( process . platform === 'darwin' ) {
baseLocation = '/Users' ;
} else {
baseLocation = '/home' ;
}
}
tempDirectory = path . join ( baseLocation , 'actions' , 'temp' );
}
export async function getJava (
version : string ,
arch : string ,
2019-11-02 21:39:35 -07:00
jdkFile : string ,
javaPackage : string
2019-07-10 23:11:48 -04:00
) : Promise < void > {
2019-11-02 21:39:35 -07:00
let toolPath = tc . find ( javaPackage , version );
2019-07-10 23:11:48 -04:00
if ( toolPath ) {
core . debug ( `Tool found in cache ${ toolPath } ` );
} else {
2019-07-15 14:59:23 -04:00
let compressedFileExtension = '' ;
2019-07-15 11:26:32 -04:00
if ( ! jdkFile ) {
2019-07-15 14:59:23 -04:00
core . debug ( 'Downloading Jdk from Azul' );
2019-07-18 16:00:58 -04:00
let http : httpm.HttpClient = new httpm . HttpClient ( 'setup-java' );
2019-11-25 10:12:17 -05:00
let contents = await (
await http . get ( 'https://static.azul.com/zulu/bin/' )
). readBody ();
2019-07-18 16:00:58 -04:00
let refs = contents . match ( /<a href.*\">/gi ) || [];
2019-11-02 21:39:35 -07:00
const downloadInfo = getDownloadInfo ( refs , version , javaPackage );
2019-07-18 16:00:58 -04:00
jdkFile = await tc . downloadTool ( downloadInfo . url );
version = downloadInfo . version ;
2019-07-15 14:59:23 -04:00
compressedFileExtension = IS_WINDOWS ? '.zip' : '.tar.gz' ;
} else {
core . debug ( 'Retrieving Jdk from local path' );
2019-07-15 11:26:32 -04:00
}
2019-07-15 14:59:23 -04:00
compressedFileExtension = compressedFileExtension || getFileEnding ( jdkFile );
2019-07-10 23:11:48 -04:00
let tempDir : string = path . join (
tempDirectory ,
'temp_' + Math . floor ( Math . random () * 2000000000 )
);
const jdkDir = await unzipJavaDownload (
jdkFile ,
compressedFileExtension ,
tempDir
);
core . debug ( `jdk extracted to ${ jdkDir } ` );
2019-07-15 14:59:23 -04:00
toolPath = await tc . cacheDir (
jdkDir ,
2019-11-02 21:39:35 -07:00
javaPackage ,
2019-07-18 16:00:58 -04:00
getCacheVersionString ( version ),
2019-07-15 14:59:23 -04:00
arch
);
2019-07-10 23:11:48 -04:00
}
let extendedJavaHome = 'JAVA_HOME_' + version + '_' + arch ;
core . exportVariable ( 'JAVA_HOME' , toolPath );
core . exportVariable ( extendedJavaHome , toolPath );
core . addPath ( path . join ( toolPath , 'bin' ));
}
2019-07-18 16:00:58 -04:00
function getCacheVersionString ( version : string ) {
2019-07-15 14:59:23 -04:00
const versionArray = version . split ( '.' );
const major = versionArray [ 0 ];
const minor = versionArray . length > 1 ? versionArray [ 1 ] : '0' ;
const patch = versionArray . length > 2 ? versionArray [ 2 ] : '0' ;
return ` ${ major } . ${ minor } . ${ patch } ` ;
}
2019-07-10 23:11:48 -04:00
function getFileEnding ( file : string ) : string {
let fileEnding = '' ;
if ( file . endsWith ( '.tar' )) {
fileEnding = '.tar' ;
} else if ( file . endsWith ( '.tar.gz' )) {
fileEnding = '.tar.gz' ;
} else if ( file . endsWith ( '.zip' )) {
fileEnding = '.zip' ;
} else if ( file . endsWith ( '.7z' )) {
fileEnding = '.7z' ;
} else {
throw new Error ( ` ${ file } has an unsupported file extension` );
}
return fileEnding ;
}
async function extractFiles (
file : string ,
fileEnding : string ,
destinationFolder : string
) : Promise < void > {
const stats = fs . statSync ( file );
if ( ! stats ) {
throw new Error ( `Failed to extract ${ file } - it doesn't exist` );
} else if ( stats . isDirectory ()) {
throw new Error ( `Failed to extract ${ file } - it is a directory` );
}
if ( '.tar' === fileEnding || '.tar.gz' === fileEnding ) {
await tc . extractTar ( file , destinationFolder );
} else if ( '.zip' === fileEnding ) {
await tc . extractZip ( file , destinationFolder );
} else {
// fall through and use sevenZip
await tc . extract7z ( file , destinationFolder );
}
}
// This method recursively finds all .pack files under fsPath and unpacks them with the unpack200 tool
async function unpackJars ( fsPath : string , javaBinPath : string ) {
if ( fs . existsSync ( fsPath )) {
if ( fs . lstatSync ( fsPath ). isDirectory ()) {
for ( const file in fs . readdirSync ( fsPath )) {
const curPath = path . join ( fsPath , file );
await unpackJars ( curPath , javaBinPath );
}
} else if ( path . extname ( fsPath ). toLowerCase () === '.pack' ) {
// Unpack the pack file synchonously
const p = path . parse ( fsPath );
const toolName = IS_WINDOWS ? 'unpack200.exe' : 'unpack200' ;
const args = IS_WINDOWS ? '-r -v -l ""' : '' ;
const name = path . join ( p . dir , p . name );
await exec . exec ( `" ${ path . join ( javaBinPath , toolName ) } "` , [
` ${ args } " ${ name } .pack" " ${ name } .jar"`
]);
}
}
}
async function unzipJavaDownload (
repoRoot : string ,
fileEnding : string ,
2019-07-15 14:59:23 -04:00
destinationFolder : string ,
extension? : string
2019-07-10 23:11:48 -04:00
) : Promise < string > {
// Create the destination folder if it doesn't exist
await io . mkdirP ( destinationFolder );
const jdkFile = path . normalize ( repoRoot );
const stats = fs . statSync ( jdkFile );
if ( stats . isFile ()) {
await extractFiles ( jdkFile , fileEnding , destinationFolder );
const jdkDirectory = path . join (
destinationFolder ,
fs . readdirSync ( destinationFolder )[ 0 ]
);
await unpackJars ( jdkDirectory , path . join ( jdkDirectory , 'bin' ));
return jdkDirectory ;
} else {
throw new Error ( `Jdk argument ${ jdkFile } is not a file` );
}
}
2019-07-15 14:59:23 -04:00
2019-07-18 16:00:58 -04:00
function getDownloadInfo (
refs : string [],
2019-11-02 21:39:35 -07:00
version : string ,
javaPackage : string
2019-07-18 16:00:58 -04:00
) : { version : string ; url : string } {
version = normalizeVersion ( version );
let extension = '' ;
2019-07-15 14:59:23 -04:00
if ( IS_WINDOWS ) {
2019-07-18 16:00:58 -04:00
extension = `-win_x64.zip` ;
2019-07-15 14:59:23 -04:00
} else {
if ( process . platform === 'darwin' ) {
2019-07-18 16:00:58 -04:00
extension = `-macosx_x64.tar.gz` ;
2019-07-15 14:59:23 -04:00
} else {
2019-07-18 16:00:58 -04:00
extension = `-linux_x64.tar.gz` ;
2019-07-15 14:59:23 -04:00
}
}
2019-07-18 16:00:58 -04:00
2019-11-02 21:39:35 -07:00
let pkgRegexp = new RegExp ( '' );
let pkgTypeLength = 0 ;
if ( javaPackage === 'jdk' ) {
pkgRegexp = /jdk.*-/gi ;
pkgTypeLength = 'jdk' . length ;
} else if ( javaPackage == 'jre' ) {
pkgRegexp = /jre.*-/gi ;
pkgTypeLength = 'jre' . length ;
} else if ( javaPackage == 'jdk+fx' ) {
pkgRegexp = /fx-jdk.*-/gi ;
pkgTypeLength = 'fx-jdk' . length ;
} else {
throw new Error (
`package argument ${ javaPackage } is not in [jdk | jre | jdk+fx]`
);
}
2019-07-18 16:00:58 -04:00
// Maps version to url
let versionMap = new Map ();
// Filter by platform
refs . forEach ( ref => {
2019-11-02 21:39:35 -07:00
if ( ! ref . endsWith ( extension + '">' )) {
2019-07-18 16:00:58 -04:00
return ;
}
// If we haven't returned, means we're looking at the correct platform
2019-11-02 21:39:35 -07:00
let versions = ref . match ( pkgRegexp ) || [];
2019-07-18 16:00:58 -04:00
if ( versions . length > 1 ) {
throw new Error (
`Invalid ref received from https://static.azul.com/zulu/bin/: ${ ref } `
);
}
if ( versions . length == 0 ) {
return ;
}
2019-11-02 21:39:35 -07:00
const refVersion = versions [ 0 ]. slice ( pkgTypeLength , versions [ 0 ]. length - 1 );
2019-07-18 16:00:58 -04:00
if ( semver . satisfies ( refVersion , version )) {
versionMap . set (
refVersion ,
'https://static.azul.com/zulu/bin/' +
ref . slice ( '<a href="' . length , ref . length - '">' . length )
);
2019-07-15 14:59:23 -04:00
}
});
2019-07-18 16:00:58 -04:00
// Choose the most recent satisfying version
let curVersion = '0.0.0' ;
let curUrl = '' ;
for ( const entry of versionMap . entries ()) {
const entryVersion = entry [ 0 ];
const entryUrl = entry [ 1 ];
if ( semver . gt ( entryVersion , curVersion )) {
curUrl = entryUrl ;
curVersion = entryVersion ;
}
}
if ( curUrl == '' ) {
2019-07-15 14:59:23 -04:00
throw new Error (
2019-11-02 21:39:35 -07:00
`No valid download found for version ${ version } and package ${ javaPackage } . Check https://static.azul.com/zulu/bin/ for a list of valid versions or download your own jdk file and add the jdkFile argument`
2019-07-15 14:59:23 -04:00
);
}
2019-07-18 16:00:58 -04:00
return { version : curVersion , url : curUrl };
}
function normalizeVersion ( version : string ) : string {
if ( version . slice ( 0 , 2 ) === '1.' ) {
// Trim leading 1. for versions like 1.8
version = version . slice ( 2 );
if ( ! version ) {
throw new Error ( '1. is not a valid version' );
}
}
2019-12-21 19:51:32 -08:00
if ( version . endsWith ( '-ea' )) {
// convert e.g. 14-ea to 14.0.0-ea
if ( version . indexOf ( '.' ) == - 1 ) {
version = version . slice ( 0 , version . length - 3 ) + '.0.0-ea' ;
}
2019-12-31 00:51:09 -05:00
// match anything in -ea.X (semver won't do .x matching on pre-release versions)
2019-12-21 19:51:32 -08:00
if ( version [ 0 ] >= '0' && version [ 0 ] <= '9' ) {
version = '>=' + version ;
}
} else if ( version . split ( '.' ). length < 3 ) {
// For non-ea versions, add trailing .x if it is missing
2019-07-18 16:00:58 -04:00
if ( version [ version . length - 1 ] != 'x' ) {
version = version + '.x' ;
}
}
2019-12-31 00:51:09 -05:00
2019-07-18 16:00:58 -04:00
return version ;
2019-07-15 14:59:23 -04:00
}