import { existsSync } from 'node:fs'; import { delimiter, dirname, isAbsolute, join, resolve } from 'node:path'; export type PythonRuntimeSource = 'configured' | 'bundled' | 'system'; export type PythonRuntime = { executable: string; binDir: string; source: PythonRuntimeSource; }; export type PythonRuntimeOptions = { isPackaged: boolean; resourcesPath: string; appPath: string; platform: NodeJS.Platform; arch: string; configuredPath?: string; }; function configuredRuntime(configuredPath: string | undefined, appPath: string): PythonRuntime | null { const trimmed = configuredPath?.trim(); if (!trimmed) return null; const executable = isAbsolute(trimmed) ? trimmed : resolve(appPath, trimmed); if (!existsSync(executable)) return null; return { executable, binDir: dirname(executable), source: 'configured' }; } function bundledExecutable(resourcesPath: string, platform: NodeJS.Platform): string { return platform === 'win32' ? join(resourcesPath, 'python', 'python.exe') : join(resourcesPath, 'python', 'bin', 'python3'); } export function resolvePythonRuntime(options: PythonRuntimeOptions): PythonRuntime { const configured = configuredRuntime(options.configuredPath, options.appPath); if (configured) return configured; const executable = bundledExecutable(options.resourcesPath, options.platform); if (existsSync(executable)) { return { executable, binDir: dirname(executable), source: 'bundled' }; } if (options.isPackaged) { throw new Error(`Bundled Python runtime is missing: ${executable}`); } return { executable: options.platform === 'win32' ? 'python' : 'python3', binDir: '', source: 'system', }; } export function prependPythonToPath( environment: Record, runtime: PythonRuntime, platform: NodeJS.Platform = process.platform, ): Record { const result = { ...environment, NIANCODE_PYTHON_PATH: runtime.executable }; if (!runtime.binDir) return result; const existingKey = Object.keys(result).find((key) => key.toLowerCase() === 'path'); const pathKey = platform === 'win32' && existingKey ? existingKey : 'PATH'; const existingPath = result[pathKey]; result[pathKey] = existingPath ? `${runtime.binDir}${delimiter}${existingPath}` : runtime.binDir; return result; }