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

43
dist/setup/index.js vendored
View file

@ -82997,23 +82997,37 @@ 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
// 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 { try {
const { exitCode, stdout } = await exec.getExecOutput('python3', [ const sysInfo = await exec.getExecOutput('python3', [
'-c', '-c',
'import sys; print(sys.prefix)' '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 (exitCode === 0) { if (sysInfo.exitCode === 0) {
const systemPrefix = stdout.trim(); const [sysExecutable, sysVersion, sysPrefix, sysBinDir] = sysInfo.stdout.trim().split('\n');
const systemVersion = await exec.getExecOutput('python3', [ if (semver.satisfies(sysVersion, semanticVersionSpec)) {
'-c', core.warning(`Pre-built Python not available for architecture '${baseArchitecture}'. Using system Python ${sysVersion} at ${sysExecutable}.`);
'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")' if (updateEnvironment) {
]); core.exportVariable('pythonLocation', sysPrefix);
if (systemVersion.exitCode === 0 && core.exportVariable('PKG_CONFIG_PATH', sysPrefix + '/lib/pkgconfig');
semver.satisfies(systemVersion.stdout.trim(), semanticVersionSpec)) { core.exportVariable('Python_ROOT_DIR', sysPrefix);
installDir = systemPrefix; core.exportVariable('Python2_ROOT_DIR', sysPrefix);
core.warning(`Pre-built Python not available for architecture '${architecture}'. Using system Python ${systemVersion.stdout.trim()} at ${systemPrefix}.`); core.exportVariable('Python3_ROOT_DIR', sysPrefix);
core.addPath(sysBinDir);
}
core.setOutput('python-version', sysVersion);
core.setOutput('python-path', sysExecutable);
return { impl: 'CPython', version: sysVersion };
} }
} }
} }
@ -83021,6 +83035,7 @@ async function useCpythonVersion(version, architecture, updateEnvironment, check
// System Python not available, fall through to error // System Python not available, fall through to error
} }
} }
}
if (!installDir) { if (!installDir) {
const osInfo = await (0, utils_1.getOSInfo)(); const osInfo = await (0, utils_1.getOSInfo)();
const msg = [ const msg = [

View file

@ -122,33 +122,59 @@ 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(
'-c', release =>
'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")' release.files?.some(
]); (file: {arch: string}) => file.arch === baseArchitecture
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 (!archHasManifestEntries) {
try {
const sysInfo = await exec.getExecOutput('python3', [
'-c',
'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 (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 { } catch {
// System Python not available, fall through to error // System Python not available, fall through to error
} }
} }
}
if (!installDir) { if (!installDir) {
const osInfo = await getOSInfo(); const osInfo = await getOSInfo();