From dc73133d4da04e56a135ae2246682783cc7c7cb6 Mon Sep 17 00:00:00 2001 From: Alena Sviridenko Date: Mon, 12 Apr 2021 20:59:38 +0300 Subject: [PATCH] Fix PyPy installation on Windows to adopt new parameters format (#201) * test for pypy new version notation * formatting * uncommented condition * test * added pypy to test matrix * test * test * restored all tests * removed logs, added multiarch support for toolcache * reduced test matrix * removed extra condition about arch --- .github/workflows/test-pypy.yml | 4 +-- __tests__/data/pypy.json | 39 +++++++++++++++++++++++++ dist/index.js | 42 ++++++++++++++++++++++----- src/find-pypy.ts | 21 ++++++++++---- src/install-pypy.ts | 50 +++++++++++++++++++++++++++++---- src/utils.ts | 2 ++ 6 files changed, 137 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml index 4041440..547d034 100644 --- a/.github/workflows/test-pypy.yml +++ b/.github/workflows/test-pypy.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04] + os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest] pypy: - 'pypy-2.7' - 'pypy-3.6' @@ -28,7 +28,7 @@ jobs: - 'pypy-3.7-v7.3.2' - 'pypy-3.6-v7.3.x' - 'pypy-3.7-v7.x' - - 'pypy-3.6-v7.3.3rc1' + - 'pypy-2.7-v7.3.4rc1' - 'pypy-3.7-nightly' steps: diff --git a/__tests__/data/pypy.json b/__tests__/data/pypy.json index 95e06bb..c8889a3 100644 --- a/__tests__/data/pypy.json +++ b/__tests__/data/pypy.json @@ -89,6 +89,45 @@ } ] }, + { + "pypy_version": "7.3.4rc1", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-03-19", + "files": [ + { + "filename": "pypy2.7-v7.3.4rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-win64.zip" + } + ] + }, { "pypy_version": "7.3.3rc2", "python_version": "3.7.7", diff --git a/dist/index.js b/dist/index.js index f093942..16cab22 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1108,10 +1108,6 @@ function findPyPyVersion(versionSpec, architecture) { let resolvedPythonVersion = ''; let installDir; const pypyVersionSpec = parsePyPyVersion(versionSpec); - // PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64. - if (utils_1.IS_WINDOWS && architecture === 'x64') { - architecture = 'x86'; - } ({ installDir, resolvedPythonVersion, resolvedPyPyVersion } = findPyPyToolCache(pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture)); if (!installDir) { ({ @@ -1133,7 +1129,9 @@ exports.findPyPyVersion = findPyPyVersion; function findPyPyToolCache(pythonVersion, pypyVersion, architecture) { let resolvedPyPyVersion = ''; let resolvedPythonVersion = ''; - let installDir = tc.find('PyPy', pythonVersion, architecture); + let installDir = utils_1.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. @@ -1177,6 +1175,12 @@ function parsePyPyVersion(versionSpec) { }; } exports.parsePyPyVersion = parsePyPyVersion; +function findPyPyInstallDirForWindows(pythonVersion) { + let installDir = ''; + utils_1.WINDOWS_ARCHS.forEach(architecture => (installDir = installDir || tc.find('PyPy', pythonVersion, architecture))); + return installDir; +} +exports.findPyPyInstallDirForWindows = findPyPyInstallDirForWindows; /***/ }), @@ -2327,6 +2331,8 @@ const path = __importStar(__webpack_require__(622)); const semver = __importStar(__webpack_require__(876)); exports.IS_WINDOWS = process.platform === 'win32'; exports.IS_LINUX = process.platform === 'linux'; +exports.WINDOWS_ARCHS = ['x86', 'x64']; +exports.WINDOWS_PLATFORMS = ['win32', 'win64']; const PYPY_VERSION_FILE = 'PYPY_VERSION'; /** create Symlinks for downloaded PyPy * It should be executed only for downloaded versions in runtime, because @@ -2893,7 +2899,9 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) { const isPyPyVersionSatisfied = isPyPyNightly || semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); const isArchPresent = item.files && - item.files.some(file => file.arch === architecture && file.platform === process.platform); + (utils_1.IS_WINDOWS + ? isArchPresentForWindows(item) + : isArchPresentForMacOrLinux(item, architecture, process.platform)); return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent; }); if (filterReleases.length === 0) { @@ -2904,7 +2912,9 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) { semver.compare(semver.coerce(current.python_version), semver.coerce(previous.python_version))); }); const foundRelease = sortedReleases[0]; - const foundAsset = foundRelease.files.find(item => item.arch === architecture && item.platform === process.platform); + const foundAsset = utils_1.IS_WINDOWS + ? findAssetForWindows(foundRelease) + : findAssetForMacOrLinux(foundRelease, architecture, process.platform); return { foundAsset, resolvedPythonVersion: foundRelease.python_version, @@ -2926,6 +2936,24 @@ function pypyVersionToSemantic(versionSpec) { return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); } exports.pypyVersionToSemantic = pypyVersionToSemantic; +function isArchPresentForWindows(item) { + return item.files.some((file) => utils_1.WINDOWS_ARCHS.includes(file.arch) && + utils_1.WINDOWS_PLATFORMS.includes(file.platform)); +} +exports.isArchPresentForWindows = isArchPresentForWindows; +function isArchPresentForMacOrLinux(item, architecture, platform) { + return item.files.some((file) => file.arch === architecture && file.platform === platform); +} +exports.isArchPresentForMacOrLinux = isArchPresentForMacOrLinux; +function findAssetForWindows(releases) { + return releases.files.find((item) => utils_1.WINDOWS_ARCHS.includes(item.arch) && + utils_1.WINDOWS_PLATFORMS.includes(item.platform)); +} +exports.findAssetForWindows = findAssetForWindows; +function findAssetForMacOrLinux(releases, architecture, platform) { + return releases.files.find((item) => item.arch === architecture && item.platform === platform); +} +exports.findAssetForMacOrLinux = findAssetForMacOrLinux; /***/ }), diff --git a/src/find-pypy.ts b/src/find-pypy.ts index 700ce9e..eb8dfac 100644 --- a/src/find-pypy.ts +++ b/src/find-pypy.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import * as pypyInstall from './install-pypy'; import { IS_WINDOWS, + WINDOWS_ARCHS, validateVersion, getPyPyVersionFromPath, readExactPyPyVersionFile, @@ -27,11 +28,6 @@ export async function findPyPyVersion( const pypyVersionSpec = parsePyPyVersion(versionSpec); - // PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64. - if (IS_WINDOWS && architecture === 'x64') { - architecture = 'x86'; - } - ({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache( pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, @@ -67,7 +63,9 @@ export function findPyPyToolCache( ) { let resolvedPyPyVersion = ''; let resolvedPythonVersion = ''; - let installDir: string | null = tc.find('PyPy', pythonVersion, architecture); + 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 @@ -129,3 +127,14 @@ export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec { pythonVersion: pythonVersion }; } + +export function findPyPyInstallDirForWindows(pythonVersion: string): string { + let installDir = ''; + + WINDOWS_ARCHS.forEach( + architecture => + (installDir = installDir || tc.find('PyPy', pythonVersion, architecture)) + ); + + return installDir; +} diff --git a/src/install-pypy.ts b/src/install-pypy.ts index 99d6030..402525a 100644 --- a/src/install-pypy.ts +++ b/src/install-pypy.ts @@ -8,6 +8,8 @@ import fs from 'fs'; import { IS_WINDOWS, + WINDOWS_ARCHS, + WINDOWS_PLATFORMS, IPyPyManifestRelease, createSymlinkInFolder, isNightlyKeyword, @@ -143,9 +145,9 @@ export function findRelease( semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); const isArchPresent = item.files && - item.files.some( - file => file.arch === architecture && file.platform === process.platform - ); + (IS_WINDOWS + ? isArchPresentForWindows(item) + : isArchPresentForMacOrLinux(item, architecture, process.platform)); return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent; }); @@ -167,9 +169,9 @@ export function findRelease( }); const foundRelease = sortedReleases[0]; - const foundAsset = foundRelease.files.find( - item => item.arch === architecture && item.platform === process.platform - ); + const foundAsset = IS_WINDOWS + ? findAssetForWindows(foundRelease) + : findAssetForMacOrLinux(foundRelease, architecture, process.platform); return { foundAsset, @@ -191,3 +193,39 @@ export function pypyVersionToSemantic(versionSpec: string) { const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g; return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); } + +export function isArchPresentForWindows(item: any) { + return item.files.some( + (file: any) => + WINDOWS_ARCHS.includes(file.arch) && + WINDOWS_PLATFORMS.includes(file.platform) + ); +} + +export function isArchPresentForMacOrLinux( + item: any, + architecture: string, + platform: string +) { + return item.files.some( + (file: any) => file.arch === architecture && file.platform === platform + ); +} + +export function findAssetForWindows(releases: any) { + return releases.files.find( + (item: any) => + WINDOWS_ARCHS.includes(item.arch) && + WINDOWS_PLATFORMS.includes(item.platform) + ); +} + +export function findAssetForMacOrLinux( + releases: any, + architecture: string, + platform: string +) { + return releases.files.find( + (item: any) => item.arch === architecture && item.platform === platform + ); +} diff --git a/src/utils.ts b/src/utils.ts index e96d5b2..c15fe3d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,6 +4,8 @@ import * as semver from 'semver'; export const IS_WINDOWS = process.platform === 'win32'; export const IS_LINUX = process.platform === 'linux'; +export const WINDOWS_ARCHS = ['x86', 'x64']; +export const WINDOWS_PLATFORMS = ['win32', 'win64']; const PYPY_VERSION_FILE = 'PYPY_VERSION'; export interface IPyPyManifestAsset {