resolved comments, update readme, add e2e tests.

This commit is contained in:
Dmitry Shibanov 2020-12-15 16:27:56 +03:00 committed by GitHub
parent 739154f76b
commit 3d613a97df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 180 additions and 38 deletions

47
.github/workflows/test-pypy.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: Validate PyPy e2e
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
schedule:
- cron: 0 0 * * *
jobs:
setup-pypy:
name: Setup PyPy ${{ matrix.pypy }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
pypy:
- 'pypy-2.7'
- 'pypy-3.6'
- 'pypy-3.7'
- 'pypy-2.7-v7.3.2'
- 'pypy-3.6-v7.3.2'
- 'pypy-3.7-v7.3.2'
- 'pypy-3.6-v7.3.x'
- 'pypy-3.7-v7.x'
- 'pypy-3.6-v7.3.3rc1'
- 'pypy-3.7-nightly'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup-python ${{ matrix.pypy }}
uses: ./
with:
python-version: ${{ matrix.pypy }}
- name: PyPy and Python version
run: python --version
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'

View file

@ -1,4 +1,4 @@
name: Validate 'setup-python' name: Validate Python e2e
on: on:
push: push:
branches: branches:
@ -18,7 +18,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04] os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -38,7 +38,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04] os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.1] python: [3.5.4, 3.6.7, 3.7.5, 3.8.1]
steps: steps:
- name: Checkout - name: Checkout
@ -68,7 +68,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04] os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -91,13 +91,13 @@ jobs:
- name: Run simple code - name: Run simple code
run: python -c 'import math; print(math.factorial(5))' run: python -c 'import math; print(math.factorial(5))'
setup-pypy: setup-pypy-legacy-way:
name: Setup PyPy ${{ matrix.os }} name: Setup PyPy ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04] os: [macos-latest, windows-latest, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2

View file

@ -17,6 +17,7 @@ This action sets up a Python environment for use in actions by:
- Allows for pinning to a specific patch version of Python without the worry of it ever being removed or changed. - Allows for pinning to a specific patch version of Python without the worry of it ever being removed or changed.
- Automatic setup and download of Python packages if using a self-hosted runner. - Automatic setup and download of Python packages if using a self-hosted runner.
- Support for pre-release versions of Python. - Support for pre-release versions of Python.
- Support for installation any version of PyPy on-flight
# Usage # Usage
@ -40,7 +41,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: [ '2.x', '3.x', 'pypy2', 'pypy3' ] python-version: [ '2.x', '3.x', 'pypy-2.7', 'pypy-3.6', 'pypy-3.7' ]
name: Python ${{ matrix.python-version }} sample name: Python ${{ matrix.python-version }} sample
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -60,7 +61,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [2.7, 3.6, 3.7, 3.8, pypy2, pypy3] python-version: [2.7, 3.6, 3.7, 3.8, pypy-2.7, pypy-3.6]
exclude: exclude:
- os: macos-latest - os: macos-latest
python-version: 3.8 python-version: 3.8
@ -91,7 +92,6 @@ jobs:
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- run: python my_script.py - run: python my_script.py
``` ```
Download and set up an accurate pre-release version of Python: Download and set up an accurate pre-release version of Python:
@ -114,6 +114,27 @@ steps:
- run: python my_script.py - run: python my_script.py
``` ```
Download and set up PyPy:
```yaml
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version:
- pypy-3.6 # the latest available version of PyPy
- pypy-3.7 # the latest available version of PyPy
- pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- run: python my_script.py
```
More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in [Available versions of PyPy](#available-versions-of-pypy) section.
# Getting started with Python + Actions # Getting started with Python + Actions
Check out our detailed guide on using [Python with GitHub Actions](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions). Check out our detailed guide on using [Python with GitHub Actions](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions).
@ -129,7 +150,21 @@ Check out our detailed guide on using [Python with GitHub Actions](https://help.
- If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache. - If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)). - Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
- All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file. - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
- If there is a specific version of Python that is not available, you can open an issue here. - If there is a specific version of Python that is not available, you can open an issue here
# Available versions of PyPy
`setup-python` is able to configure PyPy from two sources:
- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners
- For detailed information regarding the available versions of PyPy that are installed see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For the latest PyPy release, all version of Python are cached.
- Cache is updated with 1-2 weeks delay. if you specify PyPy as `pypy-3.6`, the version from cache will be used although a new version is available. If you need to start using the recently released version right after release, you should specify exact PyPy version `pypy-3.6-v7.3.3`.
- Downloadable PyPy versions from [official PyPy site](https://downloads.python.org/pypy/).
- All available versions are listed in the [versions.json](https://downloads.python.org/pypy/versions.json) file.
- PyPy < 7.3.3 are not available to install on-flight.
- If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/
# Hosted Tool Cache # Hosted Tool Cache
@ -156,6 +191,20 @@ You should specify only a major and minor version if you are okay with the most
- The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced. - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced.
- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used. - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used.
# Specifying a PyPy version
The version of PyPy should be specified in the format `pypy-<python_version>[-v<pypy_version>]`.
Parameter `<pypy_version>` is optional and can be skipped. The latest version will be used in this case.
```
pypy-3.6 # the latest available version of PyPy
pypy-3.7 # the latest available version of PyPy
pypy-2.7 # the latest available version of PyPy
pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x
pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy
pypy-3.7-nightly # Python 3.7 and nightly PyPy
```
# Using `setup-python` with a self hosted runner # Using `setup-python` with a self hosted runner
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner. Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.

42
dist/index.js vendored
View file

@ -1154,7 +1154,8 @@ function findPyPyToolCache(pythonVersion, pypyVersion, architecture) {
function parsePyPyVersion(versionSpec) { function parsePyPyVersion(versionSpec) {
const versions = versionSpec.split('-').filter(item => !!item); const versions = versionSpec.split('-').filter(item => !!item);
if (versions.length < 2) { if (versions.length < 2) {
throw new Error("Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See readme for more examples."); core.setFailed("Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See README for examples and documentation.");
process.exit();
} }
const pythonVersion = versions[1]; const pythonVersion = versions[1];
let pypyVersion; let pypyVersion;
@ -1164,6 +1165,10 @@ function parsePyPyVersion(versionSpec) {
else { else {
pypyVersion = 'x'; pypyVersion = 'x';
} }
if (!utils_1.validateVersion(pythonVersion) || !utils_1.validateVersion(pypyVersion)) {
core.setFailed("Invalid 'version' property for PyPy. Both Python version and PyPy versions should satisfy SemVer notation. See README for examples and documentation.");
process.exit();
}
return { return {
pypyVersion: pypyVersion, pypyVersion: pypyVersion,
pythonVersion: pythonVersion pythonVersion: pythonVersion
@ -2316,6 +2321,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(__webpack_require__(747)); const fs = __importStar(__webpack_require__(747));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const semver = __importStar(__webpack_require__(876));
exports.IS_WINDOWS = process.platform === 'win32'; exports.IS_WINDOWS = process.platform === 'win32';
exports.IS_LINUX = process.platform === 'linux'; exports.IS_LINUX = process.platform === 'linux';
/** create Symlinks for downloaded PyPy /** create Symlinks for downloaded PyPy
@ -2334,6 +2340,14 @@ function createSymlinkInFolder(folderPath, sourceName, targetName, setExecutable
} }
} }
exports.createSymlinkInFolder = createSymlinkInFolder; exports.createSymlinkInFolder = createSymlinkInFolder;
function validateVersion(version) {
return isNightlyKeyword(version) || Boolean(semver.validRange(version));
}
exports.validateVersion = validateVersion;
function isNightlyKeyword(pypyVersion) {
return pypyVersion === 'nightly';
}
exports.isNightlyKeyword = isNightlyKeyword;
/***/ }), /***/ }),
@ -2766,9 +2780,14 @@ function installPyPy(pypyVersion, pythonVersion, architecture) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let downloadDir; let downloadDir;
const releases = yield getAvailablePyPyVersions(); const releases = yield getAvailablePyPyVersions();
if (!releases || releases.length === 0) {
core.setFailed('No release was found in PyPy version.json');
process.exit();
}
const releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture); const releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture);
if (!releaseData || !releaseData.foundAsset) { if (!releaseData || !releaseData.foundAsset) {
throw new Error(`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`); core.setFailed(`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`);
process.exit();
} }
const { foundAsset, resolvedPythonVersion, resolvedPyPyVersion } = releaseData; const { foundAsset, resolvedPythonVersion, resolvedPyPyVersion } = releaseData;
let downloadUrl = `${foundAsset.download_url}`; let downloadUrl = `${foundAsset.download_url}`;
@ -2786,7 +2805,7 @@ function installPyPy(pypyVersion, pythonVersion, architecture) {
const archiveName = fs.readdirSync(downloadDir)[0]; const archiveName = fs.readdirSync(downloadDir)[0];
const toolDir = path.join(downloadDir, archiveName); const toolDir = path.join(downloadDir, archiveName);
let installDir = toolDir; let installDir = toolDir;
if (!isNightlyKeyword(resolvedPyPyVersion)) { if (!utils_1.isNightlyKeyword(resolvedPyPyVersion)) {
installDir = yield tc.cacheDir(toolDir, 'PyPy', resolvedPythonVersion, architecture); installDir = yield tc.cacheDir(toolDir, 'PyPy', resolvedPythonVersion, architecture);
} }
writeExactPyPyVersionFile(installDir, resolvedPyPyVersion); writeExactPyPyVersionFile(installDir, resolvedPyPyVersion);
@ -2803,7 +2822,8 @@ function getAvailablePyPyVersions() {
const http = new httpm.HttpClient('tool-cache'); const http = new httpm.HttpClient('tool-cache');
const response = yield http.getJson(url); const response = yield http.getJson(url);
if (!response.result) { if (!response.result) {
throw new Error(`Unable to retrieve the list of available PyPy versions from '${url}'`); core.setFailed(`Unable to retrieve the list of available PyPy versions from '${url}'`);
process.exit();
} }
return response.result; return response.result;
}); });
@ -2830,12 +2850,13 @@ function installPip(pythonLocation) {
} }
function findRelease(releases, pythonVersion, pypyVersion, architecture) { function findRelease(releases, pythonVersion, pypyVersion, architecture) {
const filterReleases = releases.filter(item => { const filterReleases = releases.filter(item => {
const isPythonVersionSatisfies = semver.satisfies(semver.coerce(item.python_version), pythonVersion); const isPythonVersionSatisfied = semver.satisfies(semver.coerce(item.python_version), pythonVersion);
const isPyPyNightly = isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version); const isPyPyNightly = utils_1.isNightlyKeyword(pypyVersion) && utils_1.isNightlyKeyword(item.pypy_version);
const isPyPyVersionSatisfies = isPyPyNightly || const isPyPyVersionSatisfied = isPyPyNightly ||
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
const isArchExists = item.files.some(file => file.arch === architecture && file.platform === process.platform); const isArchPresent = item.files &&
return isPythonVersionSatisfies && isPyPyVersionSatisfies && isArchExists; item.files.some(file => file.arch === architecture && file.platform === process.platform);
return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
}); });
if (filterReleases.length === 0) { if (filterReleases.length === 0) {
return null; return null;
@ -2884,9 +2905,6 @@ function getPyPyBinaryPath(installDir) {
return utils_1.IS_WINDOWS ? installDir : _binDir; return utils_1.IS_WINDOWS ? installDir : _binDir;
} }
exports.getPyPyBinaryPath = getPyPyBinaryPath; exports.getPyPyBinaryPath = getPyPyBinaryPath;
function isNightlyKeyword(pypyVersion) {
return pypyVersion === 'nightly';
}
function pypyVersionToSemantic(versionSpec) { function pypyVersionToSemantic(versionSpec) {
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g; const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g;
return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); return versionSpec.replace(prereleaseVersion, '$1-$2.$3');

View file

@ -1,6 +1,6 @@
import * as path from 'path'; import * as path from 'path';
import * as pypyInstall from './install-pypy'; import * as pypyInstall from './install-pypy';
import {IS_WINDOWS} from './utils'; import {IS_WINDOWS, validateVersion} from './utils';
import * as semver from 'semver'; import * as semver from 'semver';
import * as core from '@actions/core'; import * as core from '@actions/core';
@ -93,10 +93,12 @@ function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec {
const versions = versionSpec.split('-').filter(item => !!item); const versions = versionSpec.split('-').filter(item => !!item);
if (versions.length < 2) { if (versions.length < 2) {
throw new Error( core.setFailed(
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See readme for more examples." "Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See README for examples and documentation."
); );
process.exit();
} }
const pythonVersion = versions[1]; const pythonVersion = versions[1];
let pypyVersion: string; let pypyVersion: string;
if (versions.length > 2) { if (versions.length > 2) {
@ -105,6 +107,13 @@ function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec {
pypyVersion = 'x'; pypyVersion = 'x';
} }
if (!validateVersion(pythonVersion) || !validateVersion(pypyVersion)) {
core.setFailed(
"Invalid 'version' property for PyPy. Both Python version and PyPy versions should satisfy SemVer notation. See README for examples and documentation."
);
process.exit();
}
return { return {
pypyVersion: pypyVersion, pypyVersion: pypyVersion,
pythonVersion: pythonVersion pythonVersion: pythonVersion

View file

@ -6,7 +6,12 @@ import * as httpm from '@actions/http-client';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as fs from 'fs'; import * as fs from 'fs';
import {IS_WINDOWS, IPyPyManifestRelease, createSymlinkInFolder} from './utils'; import {
IS_WINDOWS,
IPyPyManifestRelease,
createSymlinkInFolder,
isNightlyKeyword
} from './utils';
const PYPY_VERSION_FILE = 'PYPY_VERSION'; const PYPY_VERSION_FILE = 'PYPY_VERSION';
@ -18,6 +23,11 @@ export async function installPyPy(
let downloadDir; let downloadDir;
const releases = await getAvailablePyPyVersions(); const releases = await getAvailablePyPyVersions();
if (!releases || releases.length === 0) {
core.setFailed('No release was found in PyPy version.json');
process.exit();
}
const releaseData = findRelease( const releaseData = findRelease(
releases, releases,
pythonVersion, pythonVersion,
@ -26,9 +36,10 @@ export async function installPyPy(
); );
if (!releaseData || !releaseData.foundAsset) { if (!releaseData || !releaseData.foundAsset) {
throw new Error( core.setFailed(
`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found` `PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`
); );
process.exit();
} }
const {foundAsset, resolvedPythonVersion, resolvedPyPyVersion} = releaseData; const {foundAsset, resolvedPythonVersion, resolvedPyPyVersion} = releaseData;
@ -74,9 +85,10 @@ async function getAvailablePyPyVersions() {
const response = await http.getJson<IPyPyManifestRelease[]>(url); const response = await http.getJson<IPyPyManifestRelease[]>(url);
if (!response.result) { if (!response.result) {
throw new Error( core.setFailed(
`Unable to retrieve the list of available PyPy versions from '${url}'` `Unable to retrieve the list of available PyPy versions from '${url}'`
); );
process.exit();
} }
return response.result; return response.result;
@ -124,19 +136,21 @@ function findRelease(
architecture: string architecture: string
) { ) {
const filterReleases = releases.filter(item => { const filterReleases = releases.filter(item => {
const isPythonVersionSatisfies = semver.satisfies( const isPythonVersionSatisfied = semver.satisfies(
semver.coerce(item.python_version)!, semver.coerce(item.python_version)!,
pythonVersion pythonVersion
); );
const isPyPyNightly = const isPyPyNightly =
isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version); isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version);
const isPyPyVersionSatisfies = const isPyPyVersionSatisfied =
isPyPyNightly || isPyPyNightly ||
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
const isArchExists = item.files.some( const isArchPresent =
item.files &&
item.files.some(
file => file.arch === architecture && file.platform === process.platform file => file.arch === architecture && file.platform === process.platform
); );
return isPythonVersionSatisfies && isPyPyVersionSatisfies && isArchExists; return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
}); });
if (filterReleases.length === 0) { if (filterReleases.length === 0) {
@ -206,10 +220,6 @@ export function getPyPyBinaryPath(installDir: string) {
return IS_WINDOWS ? installDir : _binDir; return IS_WINDOWS ? installDir : _binDir;
} }
function isNightlyKeyword(pypyVersion: string) {
return pypyVersion === 'nightly';
}
export function pypyVersionToSemantic(versionSpec: string) { export function pypyVersionToSemantic(versionSpec: string) {
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g; const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g;
return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); return versionSpec.replace(prereleaseVersion, '$1-$2.$3');

View file

@ -1,5 +1,6 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver';
export const IS_WINDOWS = process.platform === 'win32'; export const IS_WINDOWS = process.platform === 'win32';
export const IS_LINUX = process.platform === 'linux'; export const IS_LINUX = process.platform === 'linux';
@ -40,3 +41,11 @@ export function createSymlinkInFolder(
fs.chmodSync(targetPath, '755'); fs.chmodSync(targetPath, '755');
} }
} }
export function validateVersion(version: string) {
return isNightlyKeyword(version) || Boolean(semver.validRange(version));
}
export function isNightlyKeyword(pypyVersion: string) {
return pypyVersion === 'nightly';
}