mirror of
https://github.com/actions/setup-python.git
synced 2026-03-19 23:50:24 +08:00
fix: address review feedback on system Python fallback
- Gate fallback on architecture having no manifest entries, preventing false triggers on supported architectures with missing versions - Skip fallback for free-threaded Python builds - Return early with correct outputs (sys.executable, version, bin dir) instead of relying on toolcache path parsing which breaks with system prefix paths like /usr - Set environment variables (pythonLocation, Python_ROOT_DIR, etc.) correctly for system Python paths Signed-off-by: Bruno Verachten <gounthar@gmail.com>
This commit is contained in:
parent
156786c425
commit
02cd31ab13
2 changed files with 80 additions and 39 deletions
51
dist/setup/index.js
vendored
51
dist/setup/index.js
vendored
|
|
@ -82997,28 +82997,43 @@ async function useCpythonVersion(version, architecture, updateEnvironment, check
|
|||
installDir = tc.find('Python', semanticVersionSpec, architecture);
|
||||
}
|
||||
}
|
||||
if (!installDir) {
|
||||
// Try system Python as fallback (e.g., on architectures without pre-built binaries)
|
||||
try {
|
||||
const { exitCode, stdout } = await exec.getExecOutput('python3', [
|
||||
'-c',
|
||||
'import sys; print(sys.prefix)'
|
||||
]);
|
||||
if (exitCode === 0) {
|
||||
const systemPrefix = stdout.trim();
|
||||
const systemVersion = await exec.getExecOutput('python3', [
|
||||
if (!installDir && !freethreaded) {
|
||||
// Try system Python as fallback, but only for architectures that have
|
||||
// no pre-built binaries in the manifest at all. This prevents the
|
||||
// fallback from firing when a specific version is missing on a
|
||||
// supported architecture (e.g., requesting Python 3.99 on x86_64).
|
||||
const baseArchitecture = architecture.replace('-freethreaded', '');
|
||||
if (!manifest) {
|
||||
manifest = await installer.getManifest();
|
||||
}
|
||||
const archHasManifestEntries = manifest?.some(release => release.files?.some((file) => file.arch === baseArchitecture));
|
||||
if (!archHasManifestEntries) {
|
||||
try {
|
||||
const sysInfo = await exec.getExecOutput('python3', [
|
||||
'-c',
|
||||
'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")'
|
||||
'import sys, os; print(sys.executable + "\\n" + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" + "\\n" + sys.prefix + "\\n" + os.path.dirname(sys.executable))'
|
||||
]);
|
||||
if (systemVersion.exitCode === 0 &&
|
||||
semver.satisfies(systemVersion.stdout.trim(), semanticVersionSpec)) {
|
||||
installDir = systemPrefix;
|
||||
core.warning(`Pre-built Python not available for architecture '${architecture}'. Using system Python ${systemVersion.stdout.trim()} at ${systemPrefix}.`);
|
||||
if (sysInfo.exitCode === 0) {
|
||||
const [sysExecutable, sysVersion, sysPrefix, sysBinDir] = sysInfo.stdout.trim().split('\n');
|
||||
if (semver.satisfies(sysVersion, semanticVersionSpec)) {
|
||||
core.warning(`Pre-built Python not available for architecture '${baseArchitecture}'. Using system Python ${sysVersion} at ${sysExecutable}.`);
|
||||
if (updateEnvironment) {
|
||||
core.exportVariable('pythonLocation', sysPrefix);
|
||||
core.exportVariable('PKG_CONFIG_PATH', sysPrefix + '/lib/pkgconfig');
|
||||
core.exportVariable('Python_ROOT_DIR', sysPrefix);
|
||||
core.exportVariable('Python2_ROOT_DIR', sysPrefix);
|
||||
core.exportVariable('Python3_ROOT_DIR', sysPrefix);
|
||||
core.addPath(sysBinDir);
|
||||
}
|
||||
core.setOutput('python-version', sysVersion);
|
||||
core.setOutput('python-path', sysExecutable);
|
||||
return { impl: 'CPython', version: sysVersion };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// System Python not available, fall through to error
|
||||
catch {
|
||||
// System Python not available, fall through to error
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!installDir) {
|
||||
|
|
|
|||
|
|
@ -122,31 +122,57 @@ export async function useCpythonVersion(
|
|||
}
|
||||
}
|
||||
|
||||
if (!installDir) {
|
||||
// Try system Python as fallback (e.g., on architectures without pre-built binaries)
|
||||
try {
|
||||
const {exitCode, stdout} = await exec.getExecOutput('python3', [
|
||||
'-c',
|
||||
'import sys; print(sys.prefix)'
|
||||
]);
|
||||
if (exitCode === 0) {
|
||||
const systemPrefix = stdout.trim();
|
||||
const systemVersion = await exec.getExecOutput('python3', [
|
||||
if (!installDir && !freethreaded) {
|
||||
// Try system Python as fallback, but only for architectures that have
|
||||
// no pre-built binaries in the manifest at all. This prevents the
|
||||
// fallback from firing when a specific version is missing on a
|
||||
// supported architecture (e.g., requesting Python 3.99 on x86_64).
|
||||
const baseArchitecture = architecture.replace('-freethreaded', '');
|
||||
if (!manifest) {
|
||||
manifest = await installer.getManifest();
|
||||
}
|
||||
const archHasManifestEntries = manifest?.some(
|
||||
release =>
|
||||
release.files?.some(
|
||||
(file: {arch: string}) => file.arch === baseArchitecture
|
||||
)
|
||||
);
|
||||
|
||||
if (!archHasManifestEntries) {
|
||||
try {
|
||||
const sysInfo = await exec.getExecOutput('python3', [
|
||||
'-c',
|
||||
'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")'
|
||||
'import sys, os; print(sys.executable + "\\n" + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" + "\\n" + sys.prefix + "\\n" + os.path.dirname(sys.executable))'
|
||||
]);
|
||||
if (
|
||||
systemVersion.exitCode === 0 &&
|
||||
semver.satisfies(systemVersion.stdout.trim(), semanticVersionSpec)
|
||||
) {
|
||||
installDir = systemPrefix;
|
||||
core.warning(
|
||||
`Pre-built Python not available for architecture '${architecture}'. Using system Python ${systemVersion.stdout.trim()} at ${systemPrefix}.`
|
||||
);
|
||||
if (sysInfo.exitCode === 0) {
|
||||
const [sysExecutable, sysVersion, sysPrefix, sysBinDir] =
|
||||
sysInfo.stdout.trim().split('\n');
|
||||
if (semver.satisfies(sysVersion, semanticVersionSpec)) {
|
||||
core.warning(
|
||||
`Pre-built Python not available for architecture '${baseArchitecture}'. Using system Python ${sysVersion} at ${sysExecutable}.`
|
||||
);
|
||||
|
||||
if (updateEnvironment) {
|
||||
core.exportVariable('pythonLocation', sysPrefix);
|
||||
core.exportVariable(
|
||||
'PKG_CONFIG_PATH',
|
||||
sysPrefix + '/lib/pkgconfig'
|
||||
);
|
||||
core.exportVariable('Python_ROOT_DIR', sysPrefix);
|
||||
core.exportVariable('Python2_ROOT_DIR', sysPrefix);
|
||||
core.exportVariable('Python3_ROOT_DIR', sysPrefix);
|
||||
core.addPath(sysBinDir);
|
||||
}
|
||||
|
||||
core.setOutput('python-version', sysVersion);
|
||||
core.setOutput('python-path', sysExecutable);
|
||||
|
||||
return {impl: 'CPython', version: sysVersion};
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// System Python not available, fall through to error
|
||||
}
|
||||
} catch {
|
||||
// System Python not available, fall through to error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue