2020-12-17 22:03:54 +07:00
import * as path from 'path' ;
import * as pypyInstall from './install-pypy' ;
import {
IS_WINDOWS ,
2021-04-13 00:59:38 +07:00
WINDOWS_ARCHS ,
2020-12-17 22:03:54 +07:00
validateVersion ,
getPyPyVersionFromPath ,
readExactPyPyVersionFile ,
validatePythonVersionFormatForPyPy
} from './utils' ;
import * as semver from 'semver' ;
import * as core from '@actions/core' ;
import * as tc from '@actions/tool-cache' ;
interface IPyPyVersionSpec {
pypyVersion : string ;
pythonVersion : string ;
}
export async function findPyPyVersion (
versionSpec : string ,
2022-06-29 22:00:51 +07:00
architecture : string ,
updateEnvironment : boolean
2020-12-17 22:03:54 +07:00
) : Promise < { resolvedPyPyVersion : string ; resolvedPythonVersion : string } > {
let resolvedPyPyVersion = '' ;
let resolvedPythonVersion = '' ;
let installDir : string | null ;
const pypyVersionSpec = parsePyPyVersion ( versionSpec ) ;
( { installDir , resolvedPythonVersion , resolvedPyPyVersion } = findPyPyToolCache (
pypyVersionSpec . pythonVersion ,
pypyVersionSpec . pypyVersion ,
architecture
) ) ;
if ( ! installDir ) {
( {
installDir ,
resolvedPythonVersion ,
resolvedPyPyVersion
} = await pypyInstall . installPyPy (
pypyVersionSpec . pypyVersion ,
pypyVersionSpec . pythonVersion ,
architecture
) ) ;
}
const pipDir = IS_WINDOWS ? 'Scripts' : 'bin' ;
const _binDir = path . join ( installDir , pipDir ) ;
2022-05-24 01:59:37 +07:00
const binaryExtension = IS_WINDOWS ? '.exe' : '' ;
const pythonPath = path . join (
IS_WINDOWS ? installDir : _binDir ,
` python ${ binaryExtension } `
) ;
2020-12-17 22:03:54 +07:00
const pythonLocation = pypyInstall . getPyPyBinaryPath ( installDir ) ;
2022-06-29 22:00:51 +07:00
if ( updateEnvironment ) {
core . exportVariable ( 'pythonLocation' , installDir ) ;
2022-06-28 13:37:00 +07:00
// https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
core . exportVariable ( 'Python_ROOT_DIR' , installDir ) ;
// https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
core . exportVariable ( 'Python2_ROOT_DIR' , installDir ) ;
// https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
core . exportVariable ( 'Python3_ROOT_DIR' , installDir ) ;
2022-06-29 22:00:51 +07:00
core . exportVariable ( 'PKG_CONFIG_PATH' , pythonLocation + '/lib/pkgconfig' ) ;
core . addPath ( pythonLocation ) ;
core . addPath ( _binDir ) ;
}
2022-04-05 00:12:56 +07:00
core . setOutput ( 'python-version' , 'pypy' + resolvedPyPyVersion . trim ( ) ) ;
2022-05-24 01:59:37 +07:00
core . setOutput ( 'python-path' , pythonPath ) ;
2020-12-17 22:03:54 +07:00
return { resolvedPyPyVersion , resolvedPythonVersion } ;
}
export function findPyPyToolCache (
pythonVersion : string ,
pypyVersion : string ,
architecture : string
) {
let resolvedPyPyVersion = '' ;
let resolvedPythonVersion = '' ;
2021-04-13 00:59:38 +07:00
let installDir : string | null = IS_WINDOWS
? findPyPyInstallDirForWindows ( pythonVersion )
: tc . find ( 'PyPy' , pythonVersion , architecture ) ;
2020-12-17 22:03:54 +07:00
if ( installDir ) {
// 'tc.find' finds tool based on Python version but we also need to check
// whether PyPy version satisfies requested version.
resolvedPythonVersion = getPyPyVersionFromPath ( installDir ) ;
resolvedPyPyVersion = readExactPyPyVersionFile ( installDir ) ;
const isPyPyVersionSatisfies = semver . satisfies (
resolvedPyPyVersion ,
pypyVersion
) ;
if ( ! isPyPyVersionSatisfies ) {
installDir = null ;
resolvedPyPyVersion = '' ;
resolvedPythonVersion = '' ;
}
}
if ( ! installDir ) {
core . info (
` PyPy version ${ pythonVersion } ( ${ pypyVersion } ) was not found in the local cache `
) ;
}
return { installDir , resolvedPythonVersion , resolvedPyPyVersion } ;
}
export function parsePyPyVersion ( versionSpec : string ) : IPyPyVersionSpec {
const versions = versionSpec . split ( '-' ) . filter ( item = > ! ! item ) ;
2022-05-18 20:20:53 +07:00
if ( /^(pypy)(.+)/ . test ( versions [ 0 ] ) ) {
let pythonVersion = versions [ 0 ] . replace ( 'pypy' , '' ) ;
versions . splice ( 0 , 1 , 'pypy' , pythonVersion ) ;
}
2020-12-17 22:03:54 +07:00
if ( versions . length < 2 || versions [ 0 ] != 'pypy' ) {
throw new Error (
2022-05-18 20:20:53 +07:00
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy<python-version>' or 'pypy-<python-version>'. See README for examples and documentation."
2020-12-17 22:03:54 +07:00
) ;
}
const pythonVersion = versions [ 1 ] ;
let pypyVersion : string ;
if ( versions . length > 2 ) {
pypyVersion = pypyInstall . pypyVersionToSemantic ( versions [ 2 ] ) ;
} else {
pypyVersion = 'x' ;
}
if ( ! validateVersion ( pythonVersion ) || ! validateVersion ( pypyVersion ) ) {
throw new Error (
"Invalid 'version' property for PyPy. Both Python version and PyPy versions should satisfy SemVer notation. See README for examples and documentation."
) ;
}
if ( ! validatePythonVersionFormatForPyPy ( pythonVersion ) ) {
throw new Error (
"Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation."
) ;
}
return {
pypyVersion : pypyVersion ,
pythonVersion : pythonVersion
} ;
}
2021-04-13 00:59:38 +07:00
export function findPyPyInstallDirForWindows ( pythonVersion : string ) : string {
let installDir = '' ;
WINDOWS_ARCHS . forEach (
architecture = >
( installDir = installDir || tc . find ( 'PyPy' , pythonVersion , architecture ) )
) ;
return installDir ;
}