/ .setup / macos / validate-setup.mjs
validate-setup.mjs
 1  import { execSync } from 'child_process';
 2  import { ErrorWithRemedy } from '../error-with-remedy.mjs';
 3  import { formatExample } from '../format.mjs';
 4  import { getPythonPath } from './python-path.mjs';
 5  import { logInfo } from '../log.mjs';
 6  import { validateExecutable } from './validate-executable.mjs';
 7  
 8  /**
 9   * On macOS, this script checks if Python 3.10 is installed and accessible to node-gyp.
10   *
11   * I ran into a problem trying to `yarn` install, with a system Python version of `3.12.2`,
12   * but ran into the error `ModuleNotFoundError: No module named 'distutils'`.
13   * Since node-gyp relies on `distutils`, which is removed in Python `3.12`,
14   * you need to use a Python version that still includes `distutils`.
15   */
16  export function validateMacSetup() {
17    logInfo('Installing on macOS');
18    const pythonPath = getPythonPath();
19    validateExecutable(pythonPath);
20  
21    let error;
22    try {
23      const pythonVersionOutput = execSync(`${pythonPath} --version`).toString().trim();
24      logInfo(`${pythonPath} == (${pythonVersionOutput})`);
25  
26      const pythonVersion = pythonVersionOutput.split(' ')[1].trim();
27      const majorVersion = parseInt(pythonVersion.split('.')[0]);
28      const minorVersion = parseInt(pythonVersion.split('.')[1]);
29      const noCompatiblePythonVersionFound = !(majorVersion === 3 && (minorVersion >= 10 && minorVersion < 12));
30  
31      if (noCompatiblePythonVersionFound) {
32        error = `Incompatible Python version ${pythonVersion} found. Python 3.10 is required.`;
33      }
34  
35    } catch (caughtError) {
36      error = `Python 3.10 was not found with error: ${caughtError?.message || caughtError}`;
37    }
38    if (error) {
39      const checkForPythonInstall = 'Check for versions of python installed on your system. For example, if you use brew:';
40      const displayBrewPythonVersionsExample = formatExample('brew list --versions | grep python');
41  
42      const pleaseInstallPython = 'If python 3.10 was not found, install it. For example:';
43      const installPythonExample = formatExample('brew install python@3.10');
44  
45      const configureNodeGypPython = 'Ensure you have an environment variable for NODE_GYP_FORCE_PYTHON pointing to your python 3.10 path.\n          For example, assuming you installed python@3.10 with brew:';
46      const exportNodeGypPythonEnvVariable = formatExample('export NODE_GYP_FORCE_PYTHON=$(brew --prefix python@3.10)/bin/python3.10');
47  
48      throw new ErrorWithRemedy(error, `  STEP 1: ${checkForPythonInstall} ${displayBrewPythonVersionsExample}
49                                              \n  STEP 2: ${pleaseInstallPython} ${installPythonExample}
50                                              \n  STEP 3: ${configureNodeGypPython} ${exportNodeGypPythonEnvVariable}`
51      );
52    }
53  }