Skip to content

Commit dc73133

Browse files
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
1 parent a112144 commit dc73133

File tree

6 files changed

+137
-21
lines changed

6 files changed

+137
-21
lines changed

.github/workflows/test-pypy.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
strategy:
1919
fail-fast: false
2020
matrix:
21-
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
21+
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest]
2222
pypy:
2323
- 'pypy-2.7'
2424
- 'pypy-3.6'
@@ -28,7 +28,7 @@ jobs:
2828
- 'pypy-3.7-v7.3.2'
2929
- 'pypy-3.6-v7.3.x'
3030
- 'pypy-3.7-v7.x'
31-
- 'pypy-3.6-v7.3.3rc1'
31+
- 'pypy-2.7-v7.3.4rc1'
3232
- 'pypy-3.7-nightly'
3333

3434
steps:

__tests__/data/pypy.json

+39
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,45 @@
8989
}
9090
]
9191
},
92+
{
93+
"pypy_version": "7.3.4rc1",
94+
"python_version": "2.7.18",
95+
"stable": false,
96+
"latest_pypy": false,
97+
"date": "2021-03-19",
98+
"files": [
99+
{
100+
"filename": "pypy2.7-v7.3.4rc1-aarch64.tar.bz2",
101+
"arch": "aarch64",
102+
"platform": "linux",
103+
"download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-aarch64.tar.bz2"
104+
},
105+
{
106+
"filename": "pypy2.7-v7.3.4rc1-linux32.tar.bz2",
107+
"arch": "i686",
108+
"platform": "linux",
109+
"download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux32.tar.bz2"
110+
},
111+
{
112+
"filename": "pypy2.7-v7.3.4rc1-linux64.tar.bz2",
113+
"arch": "x64",
114+
"platform": "linux",
115+
"download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux64.tar.bz2"
116+
},
117+
{
118+
"filename": "pypy2.7-v7.3.4rc1-osx64.tar.bz2",
119+
"arch": "x64",
120+
"platform": "darwin",
121+
"download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-osx64.tar.bz2"
122+
},
123+
{
124+
"filename": "pypy2.7-v7.3.4rc1-win64.zip",
125+
"arch": "x64",
126+
"platform": "win64",
127+
"download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-win64.zip"
128+
}
129+
]
130+
},
92131
{
93132
"pypy_version": "7.3.3rc2",
94133
"python_version": "3.7.7",

dist/index.js

+35-7
Original file line numberDiff line numberDiff line change
@@ -1108,10 +1108,6 @@ function findPyPyVersion(versionSpec, architecture) {
11081108
let resolvedPythonVersion = '';
11091109
let installDir;
11101110
const pypyVersionSpec = parsePyPyVersion(versionSpec);
1111-
// PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64.
1112-
if (utils_1.IS_WINDOWS && architecture === 'x64') {
1113-
architecture = 'x86';
1114-
}
11151111
({ installDir, resolvedPythonVersion, resolvedPyPyVersion } = findPyPyToolCache(pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture));
11161112
if (!installDir) {
11171113
({
@@ -1133,7 +1129,9 @@ exports.findPyPyVersion = findPyPyVersion;
11331129
function findPyPyToolCache(pythonVersion, pypyVersion, architecture) {
11341130
let resolvedPyPyVersion = '';
11351131
let resolvedPythonVersion = '';
1136-
let installDir = tc.find('PyPy', pythonVersion, architecture);
1132+
let installDir = utils_1.IS_WINDOWS
1133+
? findPyPyInstallDirForWindows(pythonVersion)
1134+
: tc.find('PyPy', pythonVersion, architecture);
11371135
if (installDir) {
11381136
// 'tc.find' finds tool based on Python version but we also need to check
11391137
// whether PyPy version satisfies requested version.
@@ -1177,6 +1175,12 @@ function parsePyPyVersion(versionSpec) {
11771175
};
11781176
}
11791177
exports.parsePyPyVersion = parsePyPyVersion;
1178+
function findPyPyInstallDirForWindows(pythonVersion) {
1179+
let installDir = '';
1180+
utils_1.WINDOWS_ARCHS.forEach(architecture => (installDir = installDir || tc.find('PyPy', pythonVersion, architecture)));
1181+
return installDir;
1182+
}
1183+
exports.findPyPyInstallDirForWindows = findPyPyInstallDirForWindows;
11801184

11811185

11821186
/***/ }),
@@ -2327,6 +2331,8 @@ const path = __importStar(__webpack_require__(622));
23272331
const semver = __importStar(__webpack_require__(876));
23282332
exports.IS_WINDOWS = process.platform === 'win32';
23292333
exports.IS_LINUX = process.platform === 'linux';
2334+
exports.WINDOWS_ARCHS = ['x86', 'x64'];
2335+
exports.WINDOWS_PLATFORMS = ['win32', 'win64'];
23302336
const PYPY_VERSION_FILE = 'PYPY_VERSION';
23312337
/** create Symlinks for downloaded PyPy
23322338
* It should be executed only for downloaded versions in runtime, because
@@ -2893,7 +2899,9 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) {
28932899
const isPyPyVersionSatisfied = isPyPyNightly ||
28942900
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
28952901
const isArchPresent = item.files &&
2896-
item.files.some(file => file.arch === architecture && file.platform === process.platform);
2902+
(utils_1.IS_WINDOWS
2903+
? isArchPresentForWindows(item)
2904+
: isArchPresentForMacOrLinux(item, architecture, process.platform));
28972905
return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
28982906
});
28992907
if (filterReleases.length === 0) {
@@ -2904,7 +2912,9 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) {
29042912
semver.compare(semver.coerce(current.python_version), semver.coerce(previous.python_version)));
29052913
});
29062914
const foundRelease = sortedReleases[0];
2907-
const foundAsset = foundRelease.files.find(item => item.arch === architecture && item.platform === process.platform);
2915+
const foundAsset = utils_1.IS_WINDOWS
2916+
? findAssetForWindows(foundRelease)
2917+
: findAssetForMacOrLinux(foundRelease, architecture, process.platform);
29082918
return {
29092919
foundAsset,
29102920
resolvedPythonVersion: foundRelease.python_version,
@@ -2926,6 +2936,24 @@ function pypyVersionToSemantic(versionSpec) {
29262936
return versionSpec.replace(prereleaseVersion, '$1-$2.$3');
29272937
}
29282938
exports.pypyVersionToSemantic = pypyVersionToSemantic;
2939+
function isArchPresentForWindows(item) {
2940+
return item.files.some((file) => utils_1.WINDOWS_ARCHS.includes(file.arch) &&
2941+
utils_1.WINDOWS_PLATFORMS.includes(file.platform));
2942+
}
2943+
exports.isArchPresentForWindows = isArchPresentForWindows;
2944+
function isArchPresentForMacOrLinux(item, architecture, platform) {
2945+
return item.files.some((file) => file.arch === architecture && file.platform === platform);
2946+
}
2947+
exports.isArchPresentForMacOrLinux = isArchPresentForMacOrLinux;
2948+
function findAssetForWindows(releases) {
2949+
return releases.files.find((item) => utils_1.WINDOWS_ARCHS.includes(item.arch) &&
2950+
utils_1.WINDOWS_PLATFORMS.includes(item.platform));
2951+
}
2952+
exports.findAssetForWindows = findAssetForWindows;
2953+
function findAssetForMacOrLinux(releases, architecture, platform) {
2954+
return releases.files.find((item) => item.arch === architecture && item.platform === platform);
2955+
}
2956+
exports.findAssetForMacOrLinux = findAssetForMacOrLinux;
29292957

29302958

29312959
/***/ }),

src/find-pypy.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as path from 'path';
22
import * as pypyInstall from './install-pypy';
33
import {
44
IS_WINDOWS,
5+
WINDOWS_ARCHS,
56
validateVersion,
67
getPyPyVersionFromPath,
78
readExactPyPyVersionFile,
@@ -27,11 +28,6 @@ export async function findPyPyVersion(
2728

2829
const pypyVersionSpec = parsePyPyVersion(versionSpec);
2930

30-
// PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64.
31-
if (IS_WINDOWS && architecture === 'x64') {
32-
architecture = 'x86';
33-
}
34-
3531
({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache(
3632
pypyVersionSpec.pythonVersion,
3733
pypyVersionSpec.pypyVersion,
@@ -67,7 +63,9 @@ export function findPyPyToolCache(
6763
) {
6864
let resolvedPyPyVersion = '';
6965
let resolvedPythonVersion = '';
70-
let installDir: string | null = tc.find('PyPy', pythonVersion, architecture);
66+
let installDir: string | null = IS_WINDOWS
67+
? findPyPyInstallDirForWindows(pythonVersion)
68+
: tc.find('PyPy', pythonVersion, architecture);
7169

7270
if (installDir) {
7371
// 'tc.find' finds tool based on Python version but we also need to check
@@ -129,3 +127,14 @@ export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec {
129127
pythonVersion: pythonVersion
130128
};
131129
}
130+
131+
export function findPyPyInstallDirForWindows(pythonVersion: string): string {
132+
let installDir = '';
133+
134+
WINDOWS_ARCHS.forEach(
135+
architecture =>
136+
(installDir = installDir || tc.find('PyPy', pythonVersion, architecture))
137+
);
138+
139+
return installDir;
140+
}

src/install-pypy.ts

+44-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import fs from 'fs';
88

99
import {
1010
IS_WINDOWS,
11+
WINDOWS_ARCHS,
12+
WINDOWS_PLATFORMS,
1113
IPyPyManifestRelease,
1214
createSymlinkInFolder,
1315
isNightlyKeyword,
@@ -143,9 +145,9 @@ export function findRelease(
143145
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
144146
const isArchPresent =
145147
item.files &&
146-
item.files.some(
147-
file => file.arch === architecture && file.platform === process.platform
148-
);
148+
(IS_WINDOWS
149+
? isArchPresentForWindows(item)
150+
: isArchPresentForMacOrLinux(item, architecture, process.platform));
149151
return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
150152
});
151153

@@ -167,9 +169,9 @@ export function findRelease(
167169
});
168170

169171
const foundRelease = sortedReleases[0];
170-
const foundAsset = foundRelease.files.find(
171-
item => item.arch === architecture && item.platform === process.platform
172-
);
172+
const foundAsset = IS_WINDOWS
173+
? findAssetForWindows(foundRelease)
174+
: findAssetForMacOrLinux(foundRelease, architecture, process.platform);
173175

174176
return {
175177
foundAsset,
@@ -191,3 +193,39 @@ export function pypyVersionToSemantic(versionSpec: string) {
191193
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g;
192194
return versionSpec.replace(prereleaseVersion, '$1-$2.$3');
193195
}
196+
197+
export function isArchPresentForWindows(item: any) {
198+
return item.files.some(
199+
(file: any) =>
200+
WINDOWS_ARCHS.includes(file.arch) &&
201+
WINDOWS_PLATFORMS.includes(file.platform)
202+
);
203+
}
204+
205+
export function isArchPresentForMacOrLinux(
206+
item: any,
207+
architecture: string,
208+
platform: string
209+
) {
210+
return item.files.some(
211+
(file: any) => file.arch === architecture && file.platform === platform
212+
);
213+
}
214+
215+
export function findAssetForWindows(releases: any) {
216+
return releases.files.find(
217+
(item: any) =>
218+
WINDOWS_ARCHS.includes(item.arch) &&
219+
WINDOWS_PLATFORMS.includes(item.platform)
220+
);
221+
}
222+
223+
export function findAssetForMacOrLinux(
224+
releases: any,
225+
architecture: string,
226+
platform: string
227+
) {
228+
return releases.files.find(
229+
(item: any) => item.arch === architecture && item.platform === platform
230+
);
231+
}

src/utils.ts

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as semver from 'semver';
44

55
export const IS_WINDOWS = process.platform === 'win32';
66
export const IS_LINUX = process.platform === 'linux';
7+
export const WINDOWS_ARCHS = ['x86', 'x64'];
8+
export const WINDOWS_PLATFORMS = ['win32', 'win64'];
79
const PYPY_VERSION_FILE = 'PYPY_VERSION';
810

911
export interface IPyPyManifestAsset {

0 commit comments

Comments
 (0)