2020-12-17 18:03:54 +03:00
import * as path from 'path' ;
import * as pypyInstall from './install-pypy' ;
import {
IS_WINDOWS ,
2021-04-12 20:59:38 +03:00
WINDOWS_ARCHS ,
2020-12-17 18:03:54 +03: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 17:00:51 +02:00
architecture : string ,
updateEnvironment : boolean
2020-12-17 18:03:54 +03: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-23 20:59:37 +02:00
const binaryExtension = IS_WINDOWS ? '.exe' : '' ;
const pythonPath = path . join (
IS_WINDOWS ? installDir : _binDir ,
`python ${ binaryExtension } `
);
2020-12-17 18:03:54 +03:00
const pythonLocation = pypyInstall . getPyPyBinaryPath ( installDir );
2022-06-29 17:00:51 +02:00
if ( updateEnvironment ) {
core . exportVariable ( 'pythonLocation' , installDir );
2022-06-28 08:37:00 +02: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 17:00:51 +02:00
core . exportVariable ( 'PKG_CONFIG_PATH' , pythonLocation + '/lib/pkgconfig' );
core . addPath ( pythonLocation );
core . addPath ( _binDir );
}
2022-04-04 22:12:56 +05:00
core . setOutput ( 'python-version' , 'pypy' + resolvedPyPyVersion . trim ());
2022-05-23 20:59:37 +02:00
core . setOutput ( 'python-path' , pythonPath );
2020-12-17 18:03:54 +03:00
return { resolvedPyPyVersion , resolvedPythonVersion };
}
export function findPyPyToolCache (
pythonVersion : string ,
pypyVersion : string ,
architecture : string
) {
let resolvedPyPyVersion = '' ;
let resolvedPythonVersion = '' ;
2021-04-12 20:59:38 +03:00
let installDir : string | null = IS_WINDOWS
? findPyPyInstallDirForWindows ( pythonVersion )
: tc . find ( 'PyPy' , pythonVersion , architecture );
2020-12-17 18:03:54 +03: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 15:20:53 +02:00
if ( /^(pypy)(.+)/ . test ( versions [ 0 ])) {
let pythonVersion = versions [ 0 ]. replace ( 'pypy' , '' );
versions . splice ( 0 , 1 , 'pypy' , pythonVersion );
}
2020-12-17 18:03:54 +03:00
if ( versions . length < 2 || versions [ 0 ] != 'pypy' ) {
throw new Error (
2022-05-18 15:20:53 +02: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 18:03:54 +03: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-12 20:59:38 +03:00
export function findPyPyInstallDirForWindows ( pythonVersion : string ) : string {
let installDir = '' ;
WINDOWS_ARCHS . forEach (
architecture =>
( installDir = installDir || tc . find ( 'PyPy' , pythonVersion , architecture ))
);
return installDir ;
}