gitarsenal-cli
Version:
CLI tool for creating Modal sandboxes with GitHub repositories
164 lines (135 loc) • 4.05 kB
JavaScript
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 { runE2BSandbox } = require('./e2b-sandbox');
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 path.join(os.homedir(), '.gitarsenal', 'python', 'test_modalSandboxScript.py');
}
/**
* Run a container with the given options
* @param {Object} options - Container options
* @returns {Promise<void>}
*/
async function runContainer(options = {}) {
const {
showExamples = false,
repoUrl = '',
gpuType = 'A10G',
gpuCount = 1,
volumeName = '',
setupCommands = [],
yes = false,
userId = '',
userName = '',
userEmail = '',
apiKeys = {},
analysisData = null,
sandboxProvider = 'modal'
} = options;
// Check if this is just a request to show examples
if (showExamples) {
const scriptPath = getPythonScriptPath();
const pythonProcess = spawn('python', [
scriptPath,
'--show-examples'
], { stdio: 'inherit' });
return new Promise((resolve, reject) => {
pythonProcess.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Process exited with code ${code}`));
}
});
});
}
// Choose sandbox provider
if (sandboxProvider === 'e2b') {
console.log(chalk.blue('🚀 Using E2B sandbox provider'));
return runE2BSandbox({
repoUrl,
setupCommands,
userId,
userName,
userEmail,
apiKeys
});
}
console.log(chalk.blue('🚀 Using Modal sandbox provider'));
// Get the path to the Python script
const scriptPath = getPythonScriptPath();
if (!fs.existsSync(scriptPath)) {
throw new Error(`Python script not found at ${scriptPath}`);
}
console.log('Launching container...');
// Convert setup commands to JSON for passing to Python
const setupCommandsJson = JSON.stringify(setupCommands);
// Convert analysis data to JSON for passing to Python
const analysisDataJson = analysisData ? JSON.stringify(analysisData) : '';
// Convert API keys to JSON for passing to Python
const apiKeysJson = JSON.stringify(apiKeys);
// Build the command arguments
const args = [
scriptPath,
'--gpu', gpuType,
];
if (gpuCount && gpuCount > 1) {
args.push('--gpu-count', gpuCount.toString());
}
if (repoUrl) {
args.push('--repo-url', repoUrl);
}
if (volumeName) {
args.push('--volume-name', volumeName);
}
if (setupCommands && setupCommands.length > 0) {
args.push('--setup-commands-json', setupCommandsJson);
}
if (userId) {
args.push('--user-id', userId);
}
if (userName) {
args.push('--user-name', userName);
}
if (userEmail) {
args.push('--display-name', userEmail);
}
if (analysisDataJson) {
args.push('--analysis-data', analysisDataJson);
}
if (yes) {
args.push('--yes');
}
// Use system Python instead of virtual env Python
const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
// Run the Python script
const pythonProcess = spawn(pythonCmd, args, { stdio: 'inherit' });
return new Promise((resolve, reject) => {
pythonProcess.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Process exited with code ${code}`));
}
});
});
}
module.exports = {
runContainer
};