UNPKG

gitarsenal-cli

Version:

CLI tool for creating Modal sandboxes with GitHub repositories

256 lines (219 loc) 7.09 kB
const { promisify } = require('util'); const { exec } = require('child_process'); const which = require('which'); const chalk = require('chalk'); const path = require('path'); const fs = require('fs'); const execAsync = promisify(exec); /** * Get the Python executable path from the virtual environment * @returns {string} - Path to Python executable or 'python3' */ function getPythonExecutable() { // Check if PYTHON_EXECUTABLE is set by the virtual environment activation if (process.env.PYTHON_EXECUTABLE && fs.existsSync(process.env.PYTHON_EXECUTABLE)) { return process.env.PYTHON_EXECUTABLE; } // Try to find the virtual environment Python const venvPath = path.join(__dirname, '..', '.venv'); const isWindows = process.platform === 'win32'; // Check for uv-style virtual environment first const uvPythonPath = path.join(venvPath, 'bin', 'python'); // Check for traditional venv structure const traditionalPythonPath = isWindows ? path.join(venvPath, 'Scripts', 'python.exe') : path.join(venvPath, 'bin', 'python'); if (fs.existsSync(uvPythonPath)) { return uvPythonPath; } else if (fs.existsSync(traditionalPythonPath)) { return traditionalPythonPath; } // Fall back to system Python return isWindows ? 'python' : 'python3'; } /** * Check if a command is available in the system * @param {string} command - Command to check * @returns {Promise<boolean>} - True if command exists */ async function commandExists(command) { try { await which(command); return true; } catch (error) { return false; } } /** * Check Python version * @returns {Promise<{exists: boolean, version: string|null}>} */ async function checkPython() { const pythonExecutable = getPythonExecutable(); try { const { stdout } = await execAsync(`${pythonExecutable} --version`); const version = stdout.trim().split(' ')[1]; return { exists: true, version }; } catch (error) { try { const { stdout } = await execAsync('python3 --version'); const version = stdout.trim().split(' ')[1]; return { exists: true, version }; } catch (error) { return { exists: false, version: null }; } } } /** * Check if Modal is installed * @returns {Promise<boolean>} */ async function checkModal() { const pythonExecutable = getPythonExecutable(); try { // Check if modal is importable in the Python environment await execAsync(`${pythonExecutable} -c "import modal"`); return true; } catch (error) { try { // Fall back to checking the modal command await execAsync('modal --version'); return true; } catch (error) { return false; } } } /** * Check if E2B code interpreter is installed * @returns {Promise<boolean>} */ async function checkE2B() { const pythonExecutable = getPythonExecutable(); try { // Use a more reliable method to check if the module is importable const { stdout } = await execAsync(`${pythonExecutable} -c "import importlib.util; print(importlib.util.find_spec('e2b_code_interpreter') is not None)"`); return stdout.trim() === 'True'; } catch (error) { return false; } } /** * Check if Git is installed * @returns {Promise<boolean>} */ async function checkGit() { try { await execAsync('git --version'); return true; } catch (error) { return false; } } async function checkGitingest() { const pythonExecutable = getPythonExecutable(); try { // Check if gitingest is importable in the Python environment await execAsync(`${pythonExecutable} -c "import gitingest"`); return true; } catch (error) { try { // Fall back to checking the gitingest command await execAsync('gitingest --help'); return true; } catch (error) { return false; } } } /** * Check all required dependencies * @returns {Promise<boolean>} - True if all dependencies are met */ async function checkDependencies() { const pythonCheck = await checkPython(); const modalExists = await checkModal(); const e2bExists = await checkE2B(); const gitExists = await checkGit(); const gitingestExists = await checkGitingest(); let allDependenciesMet = true; console.log('\n--- Dependency Check ---'); if (pythonCheck.exists) { console.log(`${chalk.green('✓')} Python ${pythonCheck.version} found`); } else { console.log(`${chalk.red('✗')} Python not found. Please install Python 3.8 or newer.`); allDependenciesMet = false; } if (modalExists) { console.log(`${chalk.green('✓')} Modal CLI found`); } else { console.log(`${chalk.red('✗')} Modal CLI not found. Please install it with: pip install modal`); allDependenciesMet = false; } if (e2bExists) { console.log(`${chalk.green('✓')} E2B Code Interpreter found`); } else { console.log(`${chalk.red('✗')} E2B Code Interpreter not found. Please install it with: pip install e2b-code-interpreter`); allDependenciesMet = false; } if (gitingestExists) { console.log(`${chalk.green('✓')} Gitingest CLI found`); } else { console.log(`${chalk.red('✗')} Gitingest CLI not found. Please install it with: pip install gitingest`); allDependenciesMet = false; } if (gitExists) { console.log(`${chalk.green('✓')} Git found`); } else { console.log(`${chalk.red('✗')} Git not found. Please install Git.`); allDependenciesMet = false; } console.log('------------------------\n'); return allDependenciesMet; } /** * Check all required dependencies except E2B * @returns {Promise<boolean>} - True if all dependencies are met */ async function checkDependenciesExceptE2B() { const pythonCheck = await checkPython(); const modalExists = await checkModal(); const gitExists = await checkGit(); const gitingestExists = await checkGitingest(); let allDependenciesMet = true; console.log('\n--- Dependency Check ---'); if (pythonCheck.exists) { console.log(`${chalk.green('✓')} Python ${pythonCheck.version} found`); } else { console.log(`${chalk.red('✗')} Python not found. Please install Python 3.8 or newer.`); allDependenciesMet = false; } if (modalExists) { console.log(`${chalk.green('✓')} Modal CLI found`); } else { console.log(`${chalk.yellow('!')} Modal CLI not found. Not required for E2B sandbox.`); } if (gitingestExists) { console.log(`${chalk.green('✓')} Gitingest CLI found`); } else { console.log(`${chalk.red('✗')} Gitingest CLI not found. Please install it with: pip install gitingest`); allDependenciesMet = false; } if (gitExists) { console.log(`${chalk.green('✓')} Git found`); } else { console.log(`${chalk.red('✗')} Git not found. Please install Git.`); allDependenciesMet = false; } console.log('------------------------\n'); return allDependenciesMet; } module.exports = { checkDependencies, checkDependenciesExceptE2B, commandExists, checkPython, checkModal, checkE2B, checkGit };