98 lines
3.5 KiB
JavaScript
98 lines
3.5 KiB
JavaScript
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
|
|
function executable(filename) {
|
|
try {
|
|
fs.accessSync(filename, fs.constants.X_OK);
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function localPythonVersion(workspace) {
|
|
if (!workspace) return null;
|
|
let directory = path.resolve(workspace);
|
|
while (directory !== path.dirname(directory)) {
|
|
try {
|
|
const version = fs.readFileSync(path.join(directory, '.python-version'),
|
|
'utf8').trim().split(/\s+/)[0];
|
|
return /^[A-Za-z0-9._-]+$/.test(version) ? version : null;
|
|
} catch (_) {}
|
|
directory = path.dirname(directory);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function installedPyenvPythons(home) {
|
|
try {
|
|
const versions = fs.readdirSync(path.join(home, '.pyenv', 'versions'));
|
|
return versions.filter(version => /^3\.12(?:\.\d+)?$/.test(version))
|
|
.sort((a, b) => Number(b.split('.')[2] || 0) -
|
|
Number(a.split('.')[2] || 0))
|
|
.map(version => path.join(home, '.pyenv', 'versions', version,
|
|
'bin', 'python'));
|
|
} catch (_) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function resolvePython(options = {}) {
|
|
const command = String(options.command || 'auto').trim();
|
|
const args = Array.isArray(options.args) ? options.args : [];
|
|
if (command !== 'auto') {
|
|
return {command, args};
|
|
}
|
|
|
|
const home = options.home || os.homedir();
|
|
const workspace = options.workspace;
|
|
const isExecutable = options.isExecutable || executable;
|
|
const candidates = [];
|
|
const shim = path.join(home, '.pyenv', 'shims', 'python');
|
|
const version = options.localVersion === undefined ?
|
|
localPythonVersion(workspace) : options.localVersion;
|
|
const installed = options.installedPyenv === undefined ?
|
|
installedPyenvPythons(home) : options.installedPyenv;
|
|
if (version) candidates.push(shim);
|
|
candidates.push(...installed);
|
|
if (!version) candidates.push(shim);
|
|
if (workspace) {
|
|
candidates.push(path.join(workspace, '.venv', 'bin', 'python'));
|
|
}
|
|
candidates.push(
|
|
'/opt/homebrew/bin/python3.12',
|
|
'/usr/local/bin/python3.12',
|
|
'/usr/bin/python3.12',
|
|
);
|
|
const found = candidates.find(isExecutable);
|
|
if (!found) {
|
|
throw new Error(
|
|
'Не найден Python 3.12. Задайте абсолютный путь в ' +
|
|
'sprinterDebugger.pythonCommand.');
|
|
}
|
|
return {command: found, args: []};
|
|
}
|
|
|
|
function pyenvEnvironment(command, workspace, home = os.homedir()) {
|
|
const shim = path.join(home, '.pyenv', 'shims', 'python');
|
|
const version = command === shim ? localPythonVersion(workspace) : null;
|
|
return version ? {PYENV_VERSION: version} : undefined;
|
|
}
|
|
|
|
function resolveSdkRoot(configured, workspace, environment = process.env) {
|
|
const candidates = [configured, environment.SPRINTER_ROOT, workspace]
|
|
.filter(Boolean).map(value => path.resolve(value));
|
|
const found = candidates.find(root =>
|
|
fs.existsSync(path.join(root, 'toolchain', 'sdbg_dap.py')) &&
|
|
fs.existsSync(path.join(root, 'bin', 'sprinter-cc')));
|
|
if (!found) {
|
|
throw new Error('Не найден Sprinter-CC: задайте sprinterDebugger.sdkRoot ' +
|
|
'или SPRINTER_ROOT');
|
|
}
|
|
return found;
|
|
}
|
|
|
|
module.exports = {resolvePython, localPythonVersion, installedPyenvPythons,
|
|
pyenvEnvironment, resolveSdkRoot};
|