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:
Bruno Verachten 2026-03-19 14:31:03 +01:00
parent 156786c425
commit 02cd31ab13
No known key found for this signature in database
GPG key ID: E7EAD7209D3ECCD3
2 changed files with 80 additions and 39 deletions

51
dist/setup/index.js vendored
View file

@ -82997,28 +82997,43 @@ async function useCpythonVersion(version, architecture, updateEnvironment, check
installDir = tc.find('Python', semanticVersionSpec, architecture); installDir = tc.find('Python', semanticVersionSpec, architecture);
} }
} }
if (!installDir) { if (!installDir && !freethreaded) {
// Try system Python as fallback (e.g., on architectures without pre-built binaries) // Try system Python as fallback, but only for architectures that have
try { // no pre-built binaries in the manifest at all. This prevents the
const { exitCode, stdout } = await exec.getExecOutput('python3', [ // fallback from firing when a specific version is missing on a
'-c', // supported architecture (e.g., requesting Python 3.99 on x86_64).
'import sys; print(sys.prefix)' const baseArchitecture = architecture.replace('-freethreaded', '');
]); if (!manifest) {
if (exitCode === 0) { manifest = await installer.getManifest();
const systemPrefix = stdout.trim(); }
const systemVersion = await exec.getExecOutput('python3', [ const archHasManifestEntries = manifest?.some(release => release.files?.some((file) => file.arch === baseArchitecture));
if (!archHasManifestEntries) {
try {
const sysInfo = await exec.getExecOutput('python3', [
'-c', '-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 && if (sysInfo.exitCode === 0) {
semver.satisfies(systemVersion.stdout.trim(), semanticVersionSpec)) { const [sysExecutable, sysVersion, sysPrefix, sysBinDir] = sysInfo.stdout.trim().split('\n');
installDir = systemPrefix; if (semver.satisfies(sysVersion, semanticVersionSpec)) {
core.warning(`Pre-built Python not available for architecture '${architecture}'. Using system Python ${systemVersion.stdout.trim()} at ${systemPrefix}.`); 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 {
catch { // System Python not available, fall through to error
// System Python not available, fall through to error }
} }
} }
if (!installDir) { if (!installDir) {

View file

@ -122,31 +122,57 @@ export async function useCpythonVersion(
} }
} }
if (!installDir) { if (!installDir && !freethreaded) {
// Try system Python as fallback (e.g., on architectures without pre-built binaries) // Try system Python as fallback, but only for architectures that have
try { // no pre-built binaries in the manifest at all. This prevents the
const {exitCode, stdout} = await exec.getExecOutput('python3', [ // fallback from firing when a specific version is missing on a
'-c', // supported architecture (e.g., requesting Python 3.99 on x86_64).
'import sys; print(sys.prefix)' const baseArchitecture = architecture.replace('-freethreaded', '');
]); if (!manifest) {
if (exitCode === 0) { manifest = await installer.getManifest();
const systemPrefix = stdout.trim(); }
const systemVersion = await exec.getExecOutput('python3', [ const archHasManifestEntries = manifest?.some(
release =>
release.files?.some(
(file: {arch: string}) => file.arch === baseArchitecture
)
);
if (!archHasManifestEntries) {
try {
const sysInfo = await exec.getExecOutput('python3', [
'-c', '-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 ( if (sysInfo.exitCode === 0) {
systemVersion.exitCode === 0 && const [sysExecutable, sysVersion, sysPrefix, sysBinDir] =
semver.satisfies(systemVersion.stdout.trim(), semanticVersionSpec) sysInfo.stdout.trim().split('\n');
) { if (semver.satisfies(sysVersion, semanticVersionSpec)) {
installDir = systemPrefix; core.warning(
core.warning( `Pre-built Python not available for architecture '${baseArchitecture}'. Using system Python ${sysVersion} at ${sysExecutable}.`
`Pre-built Python not available for architecture '${architecture}'. Using system Python ${systemVersion.stdout.trim()} at ${systemPrefix}.` );
);
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
} }
} }