Permalink
Cannot retrieve contributors at this time
193 lines (168 sloc)
5.86 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
setup-python/src/find-pypy.ts
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as path from 'path'; | |
import * as pypyInstall from './install-pypy'; | |
import { | |
IS_WINDOWS, | |
WINDOWS_ARCHS, | |
validateVersion, | |
getPyPyVersionFromPath, | |
readExactPyPyVersionFile, | |
validatePythonVersionFormatForPyPy, | |
IPyPyManifestRelease | |
} 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, | |
architecture: string, | |
updateEnvironment: boolean, | |
checkLatest: boolean, | |
allowPreReleases: boolean | |
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> { | |
let resolvedPyPyVersion = ''; | |
let resolvedPythonVersion = ''; | |
let installDir: string | null; | |
let releases: IPyPyManifestRelease[] | undefined; | |
const pypyVersionSpec = parsePyPyVersion(versionSpec); | |
if (checkLatest) { | |
releases = await pypyInstall.getAvailablePyPyVersions(); | |
if (releases && releases.length > 0) { | |
const releaseData = pypyInstall.findRelease( | |
releases, | |
pypyVersionSpec.pythonVersion, | |
pypyVersionSpec.pypyVersion, | |
architecture, | |
false | |
); | |
if (releaseData) { | |
core.info( | |
`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})` | |
); | |
pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion; | |
pypyVersionSpec.pypyVersion = releaseData.resolvedPyPyVersion; | |
} else { | |
core.info( | |
`Failed to resolve PyPy ${pypyVersionSpec.pypyVersion} with Python (${pypyVersionSpec.pythonVersion}) from manifest` | |
); | |
} | |
} | |
} | |
({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache( | |
pypyVersionSpec.pythonVersion, | |
pypyVersionSpec.pypyVersion, | |
architecture | |
)); | |
if (!installDir) { | |
({ | |
installDir, | |
resolvedPythonVersion, | |
resolvedPyPyVersion | |
} = await pypyInstall.installPyPy( | |
pypyVersionSpec.pypyVersion, | |
pypyVersionSpec.pythonVersion, | |
architecture, | |
allowPreReleases, | |
releases | |
)); | |
} | |
const pipDir = IS_WINDOWS ? 'Scripts' : 'bin'; | |
const _binDir = path.join(installDir, pipDir); | |
const binaryExtension = IS_WINDOWS ? '.exe' : ''; | |
const pythonPath = path.join( | |
IS_WINDOWS ? installDir : _binDir, | |
`python${binaryExtension}` | |
); | |
const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir); | |
if (updateEnvironment) { | |
core.exportVariable('pythonLocation', installDir); | |
// 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); | |
core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig'); | |
core.addPath(pythonLocation); | |
core.addPath(_binDir); | |
} | |
core.setOutput('python-version', 'pypy' + resolvedPyPyVersion); | |
core.setOutput('python-path', pythonPath); | |
return {resolvedPyPyVersion, resolvedPythonVersion}; | |
} | |
export function findPyPyToolCache( | |
pythonVersion: string, | |
pypyVersion: string, | |
architecture: string | |
) { | |
let resolvedPyPyVersion = ''; | |
let resolvedPythonVersion = ''; | |
let installDir: string | null = IS_WINDOWS | |
? findPyPyInstallDirForWindows(pythonVersion) | |
: tc.find('PyPy', pythonVersion, architecture); | |
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); | |
if (/^(pypy)(.+)/.test(versions[0])) { | |
let pythonVersion = versions[0].replace('pypy', ''); | |
versions.splice(0, 1, 'pypy', pythonVersion); | |
} | |
if (versions.length < 2 || versions[0] != 'pypy') { | |
throw new Error( | |
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy<python-version>' or 'pypy-<python-version>'. See README for examples and documentation." | |
); | |
} | |
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 | |
}; | |
} | |
export function findPyPyInstallDirForWindows(pythonVersion: string): string { | |
let installDir = ''; | |
WINDOWS_ARCHS.forEach( | |
architecture => | |
(installDir = installDir || tc.find('PyPy', pythonVersion, architecture)) | |
); | |
return installDir; | |
} |