UNPKG

cvm-cli

Version:

A unified CLI tool for managing PHP, Node.js, and Python versions with virtual environment and dependency management support.

237 lines (198 loc) • 7.34 kB
const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); const inquirer = require('inquirer'); const { spawn } = require('child_process'); const CVMUtils = require('./utils'); const templates = require('./templates'); class ProjectManager { static getAvailableTemplates() { return Object.keys(templates).sort(); } static getTemplate(templateName) { return templates[templateName]; } static getTemplatesByLanguage(language) { return Object.keys(templates).filter(key => templates[key].language === language ); } static async listTemplates() { console.log(chalk.blue('\nšŸ“‹ Available Project Templates:\n')); const templatesByLanguage = {}; Object.keys(templates).forEach(key => { const template = templates[key]; if (!templatesByLanguage[template.language]) { templatesByLanguage[template.language] = []; } templatesByLanguage[template.language].push({ name: key, description: template.description }); }); Object.keys(templatesByLanguage).sort().forEach(language => { console.log(chalk.yellow(`\n${language.toUpperCase()}:`)); templatesByLanguage[language].forEach(template => { console.log(` ${chalk.green(template.name.padEnd(15))} - ${template.description}`); }); }); console.log(chalk.cyan('\nUsage: cpm make <template> <project-name>\n')); } static async createProject(templateName, projectName, options = {}) { const template = this.getTemplate(templateName); if (!template) { console.log(chalk.red(`āŒ Template '${templateName}' not found.`)); console.log(chalk.yellow('Run "cpm list" to see available templates.')); return false; } console.log(chalk.blue(`\nšŸš€ Creating ${template.description} project: ${projectName}\n`)); try { // Check if project directory already exists const projectPath = path.resolve(projectName); if (await fs.pathExists(projectPath)) { console.log(chalk.red(`āŒ Directory '${projectName}' already exists.`)); return false; } // Check requirements await this.checkRequirements(template); // Run setup commands if needed if (template.setup) { console.log(chalk.yellow('šŸ“¦ Installing dependencies...')); for (const setupCmd of template.setup) { await this.executeCommand(setupCmd); } } // Create the project const fullCommand = `${template.command} ${projectName}`; console.log(chalk.blue(`Executing: ${fullCommand}`)); await this.executeCommand(fullCommand); // Run post-setup commands if needed if (template.postSetup) { console.log(chalk.yellow('āš™ļø Running post-setup commands...')); const oldCwd = process.cwd(); process.chdir(projectPath); for (const postCmd of template.postSetup) { await this.executeCommand(postCmd); } process.chdir(oldCwd); } console.log(chalk.green(`\nāœ… Successfully created ${template.description} project: ${projectName}`)); console.log(chalk.cyan(`\nNext steps:`)); console.log(chalk.white(` cd ${projectName}`)); // Add template-specific next steps this.showNextSteps(template, projectName); return true; } catch (error) { console.log(chalk.red(`āŒ Error creating project: ${error.message}`)); return false; } } static async checkRequirements(template) { console.log(chalk.yellow('šŸ” Checking requirements...')); for (const requirement of template.requirements) { try { await this.executeCommand(`${requirement} --version`, { silent: true }); console.log(chalk.green(` āœ“ ${requirement} is available`)); } catch (error) { console.log(chalk.red(` āŒ ${requirement} is not installed or not in PATH`)); throw new Error(`Missing requirement: ${requirement}`); } } } static executeCommand(command, options = {}) { return new Promise((resolve, reject) => { const child = spawn(command, [], { shell: true, stdio: options.silent ? 'pipe' : 'inherit', ...options }); let stdout = ''; let stderr = ''; if (options.silent && child.stdout) { child.stdout.on('data', (data) => { stdout += data.toString(); }); } if (options.silent && child.stderr) { child.stderr.on('data', (data) => { stderr += data.toString(); }); } child.on('close', (code) => { if (code === 0) { resolve({ stdout, stderr, code }); } else { reject(new Error(`Command failed with exit code ${code}: ${stderr}`)); } }); child.on('error', (error) => { reject(error); }); }); } static showNextSteps(template, projectName) { switch (template.language) { case 'php': if (template.command.includes('laravel')) { console.log(chalk.white(` php artisan serve`)); } else if (template.command.includes('symfony')) { console.log(chalk.white(` symfony server:start`)); } break; case 'python': if (template.command.includes('django')) { console.log(chalk.white(` python manage.py runserver`)); } else if (template.command.includes('flask')) { console.log(chalk.white(` flask run`)); } else if (template.command.includes('fastapi')) { console.log(chalk.white(` uvicorn main:app --reload`)); } break; case 'node': console.log(chalk.white(` npm install`)); if (template.command.includes('next')) { console.log(chalk.white(` npm run dev`)); } else if (template.command.includes('react')) { console.log(chalk.white(` npm start`)); } else if (template.command.includes('vue')) { console.log(chalk.white(` npm run dev`)); } else if (template.command.includes('angular')) { console.log(chalk.white(` ng serve`)); } else { console.log(chalk.white(` npm run dev`)); } break; } } static async interactiveCreate() { console.log(chalk.blue('šŸŽÆ Interactive Project Creator\n')); const answers = await inquirer.prompt([ { type: 'list', name: 'template', message: 'Select a project template:', choices: Object.keys(templates).map(key => ({ name: `${key} - ${templates[key].description}`, value: key })).sort((a, b) => a.name.localeCompare(b.name)), pageSize: 15 }, { type: 'input', name: 'projectName', message: 'Enter project name:', validate: (input) => { if (!input.trim()) { return 'Project name is required'; } if (!/^[a-zA-Z0-9-_]+$/.test(input)) { return 'Project name can only contain letters, numbers, hyphens, and underscores'; } return true; } } ]); return this.createProject(answers.template, answers.projectName); } } module.exports = ProjectManager;