#!/usr/bin/env node /** * @file check-electron-prerequisites.js * @description Verifies and installs required dependencies for Electron builds * * This script checks if Python's distutils module is available, which is required * by node-gyp when compiling native Node.js modules during Electron packaging. * Without distutils, builds will fail with "ModuleNotFoundError: No module named 'distutils'". * * The script performs the following actions: * 1. Checks if Python's distutils module is available * 2. If missing, offers to install setuptools package which provides distutils * 3. Attempts installation through pip or pip3 * 4. Provides manual installation instructions if automated installation fails * * Usage: * - Direct execution: node scripts/check-electron-prerequisites.js * - As npm script: npm run check:electron * - Before builds: npm run check:electron && electron-builder * * Exit codes: * - 0: All prerequisites are met or were successfully installed * - 1: Prerequisites are missing and weren't installed * * @author [YOUR_NAME] * @version 1.0.0 * @license MIT */ const { execSync } = require('child_process'); const readline = require('readline'); const chalk = require('chalk'); // You might need to add this to your dependencies console.log(chalk.blue('🔍 Checking Electron build prerequisites...')); /** * Checks if Python's distutils module is available * * This function attempts to import the distutils module in Python. * If successful, it means node-gyp will be able to compile native modules. * If unsuccessful, the Electron build will likely fail when compiling native dependencies. * * @returns {boolean} True if distutils is available, false otherwise * * @example * if (checkDistutils()) { * console.log('Ready to build Electron app'); * } */ function checkDistutils() { try { // Attempt to import distutils using Python // We use stdio: 'ignore' to suppress any Python output execSync('python -c "import distutils"', { stdio: 'ignore' }); console.log(chalk.green('✅ Python distutils is available')); return true; } catch (e) { // This error occurs if either Python is not found or if distutils is missing console.log(chalk.red('❌ Python distutils is missing')); return false; } } /** * Installs the setuptools package which provides distutils * * This function attempts to install setuptools using pip or pip3. * Setuptools is a package that provides the distutils module needed by node-gyp. * In Python 3.12+, distutils was moved out of the standard library into setuptools. * * The function tries multiple installation methods: * 1. First attempts with pip * 2. If that fails, tries with pip3 * 3. If both fail, provides instructions for manual installation * * @returns {Promise} True if installation succeeded, false otherwise * * @example * const success = await installSetuptools(); * if (success) { * console.log('Ready to proceed with build'); * } else { * console.log('Please fix prerequisites manually'); * } */ async function installSetuptools() { console.log(chalk.yellow('📦 Attempting to install setuptools...')); try { // First try with pip, commonly used on all platforms execSync('pip install setuptools', { stdio: 'inherit' }); console.log(chalk.green('✅ Successfully installed setuptools')); return true; } catch (pipError) { try { // If pip fails, try with pip3 (common on Linux distributions) console.log(chalk.yellow('⚠️ Trying with pip3...')); execSync('pip3 install setuptools', { stdio: 'inherit' }); console.log(chalk.green('✅ Successfully installed setuptools using pip3')); return true; } catch (pip3Error) { // If both methods fail, provide manual installation guidance console.log(chalk.red('❌ Failed to install setuptools automatically')); console.log(chalk.yellow('📝 Please install it manually with:')); console.log(' pip install setuptools'); console.log(' or'); console.log(' sudo apt install python3-setuptools (on Debian/Ubuntu)'); console.log(' sudo pacman -S python-setuptools (on Arch Linux)'); console.log(' sudo dnf install python3-setuptools (on Fedora)'); console.log(' brew install python-setuptools (on macOS with Homebrew)'); return false; } } } /** * Main execution function * * This function orchestrates the checking and installation process: * 1. Checks if distutils is already available * 2. If not, informs the user and prompts for installation * 3. Based on user input, attempts to install or exits * * The function handles interactive user prompts and orchestrates * the overall flow of the script. * * @returns {Promise} * @throws Will exit process with code 1 if prerequisites aren't met */ async function main() { // First check if distutils is already available if (checkDistutils()) { // All prerequisites are met, exit successfully process.exit(0); } // Inform the user about the missing prerequisite console.log(chalk.yellow('⚠️ Python distutils is required for Electron builds')); console.log(chalk.yellow('⚠️ This is needed to compile native modules during the build process')); // Set up readline interface for user interaction const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Prompt the user for installation permission const answer = await new Promise(resolve => { rl.question(chalk.blue('Would you like to install setuptools now? (y/n) '), resolve); }); // Clean up readline interface rl.close(); if (answer.toLowerCase() === 'y') { // User agreed to installation const success = await installSetuptools(); if (success) { // Installation succeeded, exit successfully process.exit(0); } else { // Installation failed, exit with error process.exit(1); } } else { // User declined installation console.log(chalk.yellow('⚠️ Build may fail without distutils')); process.exit(1); } } // Execute the main function and handle any uncaught errors main().catch(error => { console.error(chalk.red('Error during prerequisites check:'), error); process.exit(1); });