mirror of
https://github.com/actions/setup-python.git
synced 2025-04-24 15:32:13 +00:00
Support installation specified of Python version for Linux
This commit is contained in:
parent
4ff1108c39
commit
d3f7e79d54
3 changed files with 336 additions and 212 deletions
495
dist/index.js
vendored
495
dist/index.js
vendored
|
@ -1250,6 +1250,73 @@ module.exports = SemVer
|
|||
|
||||
module.exports = require("os");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 98:
|
||||
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const exec = __importStar(__webpack_require__(986));
|
||||
function getVariable(variableName) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let variableValue = '';
|
||||
const options = {
|
||||
listeners: {
|
||||
stdout: (data) => {
|
||||
variableValue += data.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
yield exec.exec('bash', ['-c', `echo $${variableName}`], options);
|
||||
return variableValue.trim();
|
||||
});
|
||||
}
|
||||
function downloadLinuxCpython(version) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const home = yield getVariable('HOME');
|
||||
yield exec.exec('bash', [
|
||||
'-c',
|
||||
`
|
||||
set -e # Any command which returns non-zero exit code will cause this shell script to exit immediately
|
||||
set -x # Activate debugging to show execution details: all commands will be printed before execution
|
||||
|
||||
sudo apt-get install build-essential checkinstall
|
||||
sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
|
||||
|
||||
cd $HOME
|
||||
wget https://www.python.org/ftp/python/${version}/Python-${version}.tgz
|
||||
|
||||
tar -xvf Python-${version}.tgz
|
||||
cd Python-${version}
|
||||
./configure
|
||||
make
|
||||
sudo checkinstall -y
|
||||
`
|
||||
]);
|
||||
return `${home}/Python-${version}`;
|
||||
});
|
||||
}
|
||||
exports.downloadLinuxCpython = downloadLinuxCpython;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 120:
|
||||
|
@ -2235,45 +2302,45 @@ const Range = __webpack_require__(124)
|
|||
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core = __importStar(__webpack_require__(470));
|
||||
const finder = __importStar(__webpack_require__(927));
|
||||
const path = __importStar(__webpack_require__(622));
|
||||
function run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
let version = core.getInput('python-version');
|
||||
if (version) {
|
||||
const arch = core.getInput('architecture', { required: true });
|
||||
const installed = yield finder.findPythonVersion(version, arch);
|
||||
core.info(`Successfully setup ${installed.impl} (${installed.version})`);
|
||||
}
|
||||
const matchersPath = path.join(__dirname, '..', '.github');
|
||||
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
|
||||
}
|
||||
catch (err) {
|
||||
core.setFailed(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
run();
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core = __importStar(__webpack_require__(470));
|
||||
const finder = __importStar(__webpack_require__(927));
|
||||
const path = __importStar(__webpack_require__(622));
|
||||
function run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
let version = core.getInput('python-version');
|
||||
if (version) {
|
||||
const arch = core.getInput('architecture', { required: true });
|
||||
const installed = yield finder.findPythonVersion(version, arch);
|
||||
core.info(`Successfully setup ${installed.impl} (${installed.version})`);
|
||||
}
|
||||
const matchersPath = path.join(__dirname, '..', '.github');
|
||||
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
|
||||
}
|
||||
catch (err) {
|
||||
core.setFailed(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
run();
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
@ -6258,178 +6325,184 @@ module.exports = lte
|
|||
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const os = __importStar(__webpack_require__(87));
|
||||
const path = __importStar(__webpack_require__(622));
|
||||
const semver = __importStar(__webpack_require__(876));
|
||||
let cacheDirectory = process.env['RUNNER_TOOLSDIRECTORY'] || '';
|
||||
if (!cacheDirectory) {
|
||||
let baseLocation;
|
||||
if (process.platform === 'win32') {
|
||||
// On windows use the USERPROFILE env variable
|
||||
baseLocation = process.env['USERPROFILE'] || 'C:\\';
|
||||
}
|
||||
else {
|
||||
if (process.platform === 'darwin') {
|
||||
baseLocation = '/Users';
|
||||
}
|
||||
else {
|
||||
baseLocation = '/home';
|
||||
}
|
||||
}
|
||||
cacheDirectory = path.join(baseLocation, 'actions', 'cache');
|
||||
}
|
||||
const core = __importStar(__webpack_require__(470));
|
||||
const tc = __importStar(__webpack_require__(533));
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
// Python has "scripts" or "bin" directories where command-line tools that come with packages are installed.
|
||||
// This is where pip is, along with anything that pip installs.
|
||||
// There is a seperate directory for `pip install --user`.
|
||||
//
|
||||
// For reference, these directories are as follows:
|
||||
// macOS / Linux:
|
||||
// <sys.prefix>/bin (by default /usr/local/bin, but not on hosted agents -- see the `else`)
|
||||
// (--user) ~/.local/bin
|
||||
// Windows:
|
||||
// <Python installation dir>\Scripts
|
||||
// (--user) %APPDATA%\Python\PythonXY\Scripts
|
||||
// See https://docs.python.org/3/library/sysconfig.html
|
||||
function binDir(installDir) {
|
||||
if (IS_WINDOWS) {
|
||||
return path.join(installDir, 'Scripts');
|
||||
}
|
||||
else {
|
||||
return path.join(installDir, 'bin');
|
||||
}
|
||||
}
|
||||
// Note on the tool cache layout for PyPy:
|
||||
// PyPy has its own versioning scheme that doesn't follow the Python versioning scheme.
|
||||
// A particular version of PyPy may contain one or more versions of the Python interpreter.
|
||||
// For example, PyPy 7.0 contains Python 2.7, 3.5, and 3.6-alpha.
|
||||
// We only care about the Python version, so we don't use the PyPy version for the tool cache.
|
||||
function usePyPy(majorVersion, architecture) {
|
||||
const findPyPy = tc.find.bind(undefined, 'PyPy', majorVersion.toString());
|
||||
let installDir = findPyPy(architecture);
|
||||
if (!installDir && IS_WINDOWS) {
|
||||
// PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64.
|
||||
// On our Windows virtual environments, we only install an x86 version.
|
||||
// Fall back to x86.
|
||||
installDir = findPyPy('x86');
|
||||
}
|
||||
if (!installDir) {
|
||||
// PyPy not installed in $(Agent.ToolsDirectory)
|
||||
throw new Error(`PyPy ${majorVersion} not found`);
|
||||
}
|
||||
// For PyPy, Windows uses 'bin', not 'Scripts'.
|
||||
const _binDir = path.join(installDir, 'bin');
|
||||
// On Linux and macOS, the Python interpreter is in 'bin'.
|
||||
// On Windows, it is in the installation root.
|
||||
const pythonLocation = IS_WINDOWS ? installDir : _binDir;
|
||||
core.exportVariable('pythonLocation', pythonLocation);
|
||||
core.addPath(installDir);
|
||||
core.addPath(_binDir);
|
||||
const impl = 'pypy' + majorVersion.toString();
|
||||
core.setOutput('python-version', impl);
|
||||
return { impl: impl, version: versionFromPath(installDir) };
|
||||
}
|
||||
function useCpythonVersion(version, architecture) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const desugaredVersionSpec = desugarDevVersion(version);
|
||||
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
||||
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
||||
const installDir = tc.find('Python', semanticVersionSpec, architecture);
|
||||
if (!installDir) {
|
||||
// Fail and list available versions
|
||||
const x86Versions = tc
|
||||
.findAllVersions('Python', 'x86')
|
||||
.map(s => `${s} (x86)`)
|
||||
.join(os.EOL);
|
||||
const x64Versions = tc
|
||||
.findAllVersions('Python', 'x64')
|
||||
.map(s => `${s} (x64)`)
|
||||
.join(os.EOL);
|
||||
throw new Error([
|
||||
`Version ${version} with arch ${architecture} not found`,
|
||||
'Available versions:',
|
||||
x86Versions,
|
||||
x64Versions
|
||||
].join(os.EOL));
|
||||
}
|
||||
core.exportVariable('pythonLocation', installDir);
|
||||
core.addPath(installDir);
|
||||
core.addPath(binDir(installDir));
|
||||
if (IS_WINDOWS) {
|
||||
// Add --user directory
|
||||
// `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python/<semantic version>/x64/
|
||||
// So if `findLocalTool` succeeded above, we must have a conformant `installDir`
|
||||
const version = path.basename(path.dirname(installDir));
|
||||
const major = semver.major(version);
|
||||
const minor = semver.minor(version);
|
||||
const userScriptsDir = path.join(process.env['APPDATA'] || '', 'Python', `Python${major}${minor}`, 'Scripts');
|
||||
core.addPath(userScriptsDir);
|
||||
}
|
||||
// On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
|
||||
const installed = versionFromPath(installDir);
|
||||
core.setOutput('python-version', installed);
|
||||
return { impl: 'CPython', version: installed };
|
||||
});
|
||||
}
|
||||
/** Convert versions like `3.8-dev` to a version like `>= 3.8.0-a0`. */
|
||||
function desugarDevVersion(versionSpec) {
|
||||
if (versionSpec.endsWith('-dev')) {
|
||||
const versionRoot = versionSpec.slice(0, -'-dev'.length);
|
||||
return `>= ${versionRoot}.0-a0`;
|
||||
}
|
||||
else {
|
||||
return versionSpec;
|
||||
}
|
||||
}
|
||||
/** Extracts python version from install path from hosted tool cache as described in README.md */
|
||||
function versionFromPath(installDir) {
|
||||
const parts = installDir.split(path.sep);
|
||||
const idx = parts.findIndex(part => part === 'PyPy' || part === 'Python');
|
||||
return parts[idx + 1] || '';
|
||||
}
|
||||
/**
|
||||
* Python's prelease versions look like `3.7.0b2`.
|
||||
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
|
||||
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
|
||||
*/
|
||||
function pythonVersionToSemantic(versionSpec) {
|
||||
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
|
||||
return versionSpec.replace(prereleaseVersion, '$1-$2');
|
||||
}
|
||||
exports.pythonVersionToSemantic = pythonVersionToSemantic;
|
||||
function findPythonVersion(version, architecture) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
switch (version.toUpperCase()) {
|
||||
case 'PYPY2':
|
||||
return usePyPy(2, architecture);
|
||||
case 'PYPY3':
|
||||
return usePyPy(3, architecture);
|
||||
default:
|
||||
return yield useCpythonVersion(version, architecture);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.findPythonVersion = findPythonVersion;
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const os = __importStar(__webpack_require__(87));
|
||||
const path = __importStar(__webpack_require__(622));
|
||||
const semver = __importStar(__webpack_require__(876));
|
||||
const downloader = __importStar(__webpack_require__(98));
|
||||
let cacheDirectory = process.env['RUNNER_TOOLSDIRECTORY'] || '';
|
||||
if (!cacheDirectory) {
|
||||
let baseLocation;
|
||||
if (process.platform === 'win32') {
|
||||
// On windows use the USERPROFILE env variable
|
||||
baseLocation = process.env['USERPROFILE'] || 'C:\\';
|
||||
}
|
||||
else {
|
||||
if (process.platform === 'darwin') {
|
||||
baseLocation = '/Users';
|
||||
}
|
||||
else {
|
||||
baseLocation = '/home';
|
||||
}
|
||||
}
|
||||
cacheDirectory = path.join(baseLocation, 'actions', 'cache');
|
||||
}
|
||||
const core = __importStar(__webpack_require__(470));
|
||||
const tc = __importStar(__webpack_require__(533));
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
const IS_LINUX = process.platform === 'linux';
|
||||
// Python has "scripts" or "bin" directories where command-line tools that come with packages are installed.
|
||||
// This is where pip is, along with anything that pip installs.
|
||||
// There is a seperate directory for `pip install --user`.
|
||||
//
|
||||
// For reference, these directories are as follows:
|
||||
// macOS / Linux:
|
||||
// <sys.prefix>/bin (by default /usr/local/bin, but not on hosted agents -- see the `else`)
|
||||
// (--user) ~/.local/bin
|
||||
// Windows:
|
||||
// <Python installation dir>\Scripts
|
||||
// (--user) %APPDATA%\Python\PythonXY\Scripts
|
||||
// See https://docs.python.org/3/library/sysconfig.html
|
||||
function binDir(installDir) {
|
||||
if (IS_WINDOWS) {
|
||||
return path.join(installDir, 'Scripts');
|
||||
}
|
||||
else {
|
||||
return path.join(installDir, 'bin');
|
||||
}
|
||||
}
|
||||
// Note on the tool cache layout for PyPy:
|
||||
// PyPy has its own versioning scheme that doesn't follow the Python versioning scheme.
|
||||
// A particular version of PyPy may contain one or more versions of the Python interpreter.
|
||||
// For example, PyPy 7.0 contains Python 2.7, 3.5, and 3.6-alpha.
|
||||
// We only care about the Python version, so we don't use the PyPy version for the tool cache.
|
||||
function usePyPy(majorVersion, architecture) {
|
||||
const findPyPy = tc.find.bind(undefined, 'PyPy', majorVersion.toString());
|
||||
let installDir = findPyPy(architecture);
|
||||
if (!installDir && IS_WINDOWS) {
|
||||
// PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64.
|
||||
// On our Windows virtual environments, we only install an x86 version.
|
||||
// Fall back to x86.
|
||||
installDir = findPyPy('x86');
|
||||
}
|
||||
if (!installDir) {
|
||||
// PyPy not installed in $(Agent.ToolsDirectory)
|
||||
throw new Error(`PyPy ${majorVersion} not found`);
|
||||
}
|
||||
// For PyPy, Windows uses 'bin', not 'Scripts'.
|
||||
const _binDir = path.join(installDir, 'bin');
|
||||
// On Linux and macOS, the Python interpreter is in 'bin'.
|
||||
// On Windows, it is in the installation root.
|
||||
const pythonLocation = IS_WINDOWS ? installDir : _binDir;
|
||||
core.exportVariable('pythonLocation', pythonLocation);
|
||||
core.addPath(installDir);
|
||||
core.addPath(_binDir);
|
||||
const impl = 'pypy' + majorVersion.toString();
|
||||
core.setOutput('python-version', impl);
|
||||
return { impl: impl, version: versionFromPath(installDir) };
|
||||
}
|
||||
function useCpythonVersion(version, architecture) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const desugaredVersionSpec = desugarDevVersion(version);
|
||||
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
||||
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
||||
let installDir = tc.find('Python', semanticVersionSpec, architecture);
|
||||
if (!installDir && IS_LINUX) {
|
||||
core.info(`Can't find installed CPython ${version}; trying to download`);
|
||||
installDir = yield downloader.downloadLinuxCpython(version);
|
||||
}
|
||||
if (!installDir) {
|
||||
// Fail and list available versions
|
||||
const x86Versions = tc
|
||||
.findAllVersions('Python', 'x86')
|
||||
.map(s => `${s} (x86)`)
|
||||
.join(os.EOL);
|
||||
const x64Versions = tc
|
||||
.findAllVersions('Python', 'x64')
|
||||
.map(s => `${s} (x64)`)
|
||||
.join(os.EOL);
|
||||
throw new Error([
|
||||
`Version ${version} with arch ${architecture} not found`,
|
||||
'Available versions:',
|
||||
x86Versions,
|
||||
x64Versions
|
||||
].join(os.EOL));
|
||||
}
|
||||
core.exportVariable('pythonLocation', installDir);
|
||||
core.addPath(installDir);
|
||||
core.addPath(binDir(installDir));
|
||||
if (IS_WINDOWS) {
|
||||
// Add --user directory
|
||||
// `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python/<semantic version>/x64/
|
||||
// So if `findLocalTool` succeeded above, we must have a conformant `installDir`
|
||||
const version = path.basename(path.dirname(installDir));
|
||||
const major = semver.major(version);
|
||||
const minor = semver.minor(version);
|
||||
const userScriptsDir = path.join(process.env['APPDATA'] || '', 'Python', `Python${major}${minor}`, 'Scripts');
|
||||
core.addPath(userScriptsDir);
|
||||
}
|
||||
// On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
|
||||
const installed = versionFromPath(installDir);
|
||||
core.setOutput('python-version', installed);
|
||||
return { impl: 'CPython', version: installed };
|
||||
});
|
||||
}
|
||||
/** Convert versions like `3.8-dev` to a version like `>= 3.8.0-a0`. */
|
||||
function desugarDevVersion(versionSpec) {
|
||||
if (versionSpec.endsWith('-dev')) {
|
||||
const versionRoot = versionSpec.slice(0, -'-dev'.length);
|
||||
return `>= ${versionRoot}.0-a0`;
|
||||
}
|
||||
else {
|
||||
return versionSpec;
|
||||
}
|
||||
}
|
||||
/** Extracts python version from install path from hosted tool cache as described in README.md */
|
||||
function versionFromPath(installDir) {
|
||||
const parts = installDir.split(path.sep);
|
||||
const idx = parts.findIndex(part => part === 'PyPy' || part === 'Python');
|
||||
return parts[idx + 1] || '';
|
||||
}
|
||||
/**
|
||||
* Python's prelease versions look like `3.7.0b2`.
|
||||
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
|
||||
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
|
||||
*/
|
||||
function pythonVersionToSemantic(versionSpec) {
|
||||
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
|
||||
return versionSpec.replace(prereleaseVersion, '$1-$2');
|
||||
}
|
||||
exports.pythonVersionToSemantic = pythonVersionToSemantic;
|
||||
function findPythonVersion(version, architecture) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
switch (version.toUpperCase()) {
|
||||
case 'PYPY2':
|
||||
return usePyPy(2, architecture);
|
||||
case 'PYPY3':
|
||||
return usePyPy(3, architecture);
|
||||
default:
|
||||
return yield useCpythonVersion(version, architecture);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.findPythonVersion = findPythonVersion;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
|
43
src/download-python.ts
Normal file
43
src/download-python.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import * as exec from '@actions/exec';
|
||||
|
||||
async function getVariable(variableName: string): Promise<string> {
|
||||
let variableValue = '';
|
||||
|
||||
const options = {
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
variableValue += data.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await exec.exec('bash', ['-c', `echo $${variableName}`], options);
|
||||
|
||||
return variableValue.trim();
|
||||
}
|
||||
|
||||
export async function downloadLinuxCpython(version: string): Promise<string> {
|
||||
const home = await getVariable('HOME');
|
||||
|
||||
await exec.exec('bash', [
|
||||
'-c',
|
||||
`
|
||||
set -e # Any command which returns non-zero exit code will cause this shell script to exit immediately
|
||||
set -x # Activate debugging to show execution details: all commands will be printed before execution
|
||||
|
||||
sudo apt-get install build-essential checkinstall
|
||||
sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
|
||||
|
||||
cd $HOME
|
||||
wget https://www.python.org/ftp/python/${version}/Python-${version}.tgz
|
||||
|
||||
tar -xvf Python-${version}.tgz
|
||||
cd Python-${version}
|
||||
./configure
|
||||
make
|
||||
sudo checkinstall -y
|
||||
`
|
||||
]);
|
||||
|
||||
return `${home}/Python-${version}`;
|
||||
}
|
|
@ -3,6 +3,8 @@ import * as path from 'path';
|
|||
|
||||
import * as semver from 'semver';
|
||||
|
||||
import * as downloader from './download-python';
|
||||
|
||||
let cacheDirectory = process.env['RUNNER_TOOLSDIRECTORY'] || '';
|
||||
|
||||
if (!cacheDirectory) {
|
||||
|
@ -24,6 +26,7 @@ import * as core from '@actions/core';
|
|||
import * as tc from '@actions/tool-cache';
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
const IS_LINUX = process.platform === 'linux';
|
||||
|
||||
// Python has "scripts" or "bin" directories where command-line tools that come with packages are installed.
|
||||
// This is where pip is, along with anything that pip installs.
|
||||
|
@ -92,11 +95,16 @@ async function useCpythonVersion(
|
|||
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
||||
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
||||
|
||||
const installDir: string | null = tc.find(
|
||||
let installDir: string | null = tc.find(
|
||||
'Python',
|
||||
semanticVersionSpec,
|
||||
architecture
|
||||
);
|
||||
if (!installDir && IS_LINUX) {
|
||||
core.info(`Can't find installed CPython ${version}; trying to download`);
|
||||
installDir = await downloader.downloadLinuxCpython(version);
|
||||
}
|
||||
|
||||
if (!installDir) {
|
||||
// Fail and list available versions
|
||||
const x86Versions = tc
|
||||
|
|
Loading…
Add table
Reference in a new issue