UNPKG

gitarsenal-cli

Version:

CLI tool for creating Modal sandboxes with GitHub repositories

174 lines (149 loc) 5.51 kB
const path = require('path'); const fs = require('fs-extra'); const { spawn } = require('child_process'); const chalk = require('chalk'); const ora = require('ora'); const { promisify } = require('util'); const { exec } = require('child_process'); const os = require('os'); const execAsync = promisify(exec); /** * Get the path to the Python script * @returns {string} - Path to the Python script */ function getPythonScriptPath() { // First check if the script exists in the package directory const packageScriptPath = path.join(__dirname, '..', 'python', 'test_modalSandboxScript.py'); if (fs.existsSync(packageScriptPath)) { return packageScriptPath; } // If not found, return the path where it will be copied during installation return packageScriptPath; } /** * Run the container with the given options * @param {Object} options - Container options * @param {string} options.repoUrl - GitHub repository URL * @param {string} options.gpuType - GPU type * @param {string} options.volumeName - Volume name * @param {Array<string>} options.setupCommands - Setup commands * @param {boolean} options.useApi - Whether to use the API to fetch setup commands * @param {boolean} options.showExamples - Whether to show usage examples * @returns {Promise<void>} */ async function runContainer(options) { const { repoUrl, gpuType, volumeName, setupCommands = [], useApi = true, showExamples = false, yes = false, userId, userName, userEmail } = options; // Get the path to the Python script const scriptPath = getPythonScriptPath(); // Check if the script exists if (!fs.existsSync(scriptPath)) { throw new Error(`Python script not found at ${scriptPath}. Please reinstall the package.`); } // Prepare command arguments const args = [ scriptPath ]; // If show examples is true, only pass that flag if (showExamples) { args.push('--show-examples'); // Log the command being executed // console.log(chalk.dim(`\nExecuting: python ${args.join(' ')}`)); // Run the Python script with show examples flag const pythonExecutable = process.env.PYTHON_EXECUTABLE || 'python'; const pythonProcess = spawn(pythonExecutable, ['-u', ...args], { stdio: 'inherit', // Inherit stdio to show real-time output env: { ...process.env, PYTHONUNBUFFERED: '1' } // Force unbuffered output }); return new Promise((resolve, reject) => { pythonProcess.on('close', (code) => { if (code === 0) { resolve(); } else { reject(new Error(`Process exited with code ${code}`)); } }); pythonProcess.on('error', (error) => { reject(error); }); }); } // Add normal arguments if (gpuType) args.push('--gpu', gpuType); if (repoUrl) args.push('--repo-url', repoUrl); if (volumeName) { args.push('--volume-name', volumeName); } // Always use the API to fetch setup commands unless explicitly disabled if (useApi) { args.push('--use-api'); } // Add --yes flag to skip confirmation prompts if (yes) { args.push('--yes'); console.log(chalk.gray(`🔍 Debug: Adding --yes flag to Python script`)); } // Add user credentials if provided if (userId && userEmail && userName) { args.push('--user-id', userEmail); args.push('--user-name', userId); args.push('--display-name', userName); // console.log(chalk.gray(`🔍 Debug: Passing user credentials to Python script`)); } // Handle manual setup commands if provided if (setupCommands.length > 0) { // Create a temporary file to store setup commands const tempCommandsFile = path.join(os.tmpdir(), `gitarsenal-commands-${Date.now()}.txt`); fs.writeFileSync(tempCommandsFile, setupCommands.join('\n')); args.push('--commands-file', tempCommandsFile); // Ensure Python skips auto-detection via GitIngest when commands are provided args.push('--no-gitingest'); } // Log the command being executed // console.log(chalk.dim(`\nExecuting: python ${args.join(' ')}`)); // console.log(chalk.gray(`🔍 Debug: yes parameter = ${yes}`)); // Run the Python script without spinner to avoid terminal interference console.log(chalk.dim('Launching container...')); try { // Run the Python script const pythonExecutable = process.env.PYTHON_EXECUTABLE || 'python'; const pythonProcess = spawn(pythonExecutable, ['-u', ...args], { stdio: 'inherit', // Inherit stdio to show real-time output env: { ...process.env, PYTHONUNBUFFERED: '1' } // Force unbuffered output }); // Handle process completion return new Promise((resolve, reject) => { pythonProcess.on('close', (code) => { if (code === 0) { console.log(chalk.green('✅ Container launched successfully')); resolve(); } else { console.log(chalk.red(`❌ Container launch failed with exit code ${code}`)); reject(new Error(`Process exited with code ${code}`)); } }); // Handle process errors pythonProcess.on('error', (error) => { console.log(chalk.red(`❌ Failed to start Python process: ${error.message}`)); reject(error); }); }); } catch (error) { console.log(chalk.red(`❌ Error launching container: ${error.message}`)); throw error; } } module.exports = { runContainer, getPythonScriptPath };