UNPKG

cvm-cli

Version:

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

156 lines (125 loc) 6.03 kB
const BaseVersionManager = require('./baseVersionManager'); const fetch = require('node-fetch'); const fs = require('fs-extra'); const chalk = require('chalk'); const path = require('path'); const CVMUtils = require('./utils'); class PythonVersionManager extends BaseVersionManager { constructor() { super('python'); } async getAvailableVersions() { // For simplicity, return a list of commonly used Python versions // In a real implementation, you'd fetch from python.org or use pyenv's list return [ '3.12.0', '3.11.7', '3.11.6', '3.11.5', '3.11.4', '3.11.3', '3.11.2', '3.11.1', '3.11.0', '3.10.13', '3.10.12', '3.10.11', '3.10.10', '3.10.9', '3.10.8', '3.10.7', '3.10.6', '3.10.5', '3.10.4', '3.10.3', '3.10.2', '3.10.1', '3.10.0', '3.9.18', '3.9.17', '3.9.16', '3.9.15', '3.9.14', '3.9.13', '3.9.12', '3.9.11', '3.9.10', '3.9.9', '3.9.8', '3.9.7', '3.9.6', '3.9.5', '3.9.4', '3.9.3', '3.9.2', '3.9.1', '3.9.0', '3.8.18', '3.8.17', '3.8.16', '3.8.15', '3.8.14', '3.8.13', '3.8.12', '3.8.11', '3.8.10', '3.8.9', '3.8.8', '3.8.7', '3.8.6', '3.8.5', '3.8.4', '3.8.3', '3.8.2', '3.8.1', '3.8.0' ]; } async install(version) { if (await this.isVersionInstalled(version)) { console.log(chalk.yellow(`Python ${version} is already installed.`)); return true; } console.log(chalk.blue(`Installing Python ${version}...`)); const platform = this.getPlatform(); const versionDir = path.join(this.languageDir, version); try { if (platform === 'linux') { await this.installOnLinux(version, versionDir); } else if (platform === 'darwin') { await this.installOnMacOS(version, versionDir); } else if (platform === 'win32') { await this.installOnWindows(version, versionDir); } else { throw new Error(`Unsupported platform: ${platform}`); } console.log(chalk.green(`✓ Python ${version} installed successfully`)); return true; } catch (error) { console.error(chalk.red(`Failed to install Python ${version}:`), error.message); // Clean up partially installed version if (await fs.pathExists(versionDir)) { await fs.remove(versionDir); } return false; } } async installOnLinux(version, versionDir) { // For Linux, we'll compile from source const downloadUrl = `https://www.python.org/ftp/python/${version}/Python-${version}.tgz`; const downloadDir = path.join(this.languageDir, 'downloads'); const downloadPath = path.join(downloadDir, `Python-${version}.tgz`); const sourceDir = path.join(downloadDir, `Python-${version}`); console.log(chalk.yellow(' Downloading Python source...')); await this.downloadFile(downloadUrl, downloadPath); console.log(chalk.yellow(' Extracting source...')); await this.extractTarGz(downloadPath, sourceDir); console.log(chalk.yellow(' Configuring build...')); await this.executeCommand(`./configure --prefix="${versionDir}" --enable-optimizations`, { cwd: sourceDir }); console.log(chalk.yellow(' Building Python (this may take a while)...')); await this.executeCommand('make -j$(nproc)', { cwd: sourceDir }); console.log(chalk.yellow(' Installing Python...')); await this.executeCommand('make altinstall', { cwd: sourceDir }); // Clean up await fs.remove(downloadDir); } async installOnMacOS(version, versionDir) { // Similar to Linux but may need different configure options const downloadUrl = `https://www.python.org/ftp/python/${version}/Python-${version}.tgz`; const downloadDir = path.join(this.languageDir, 'downloads'); const downloadPath = path.join(downloadDir, `Python-${version}.tgz`); const sourceDir = path.join(downloadDir, `Python-${version}`); console.log(chalk.yellow(' Downloading Python source...')); await this.downloadFile(downloadUrl, downloadPath); console.log(chalk.yellow(' Extracting source...')); await this.extractTarGz(downloadPath, sourceDir); console.log(chalk.yellow(' Configuring build...')); await this.executeCommand(`./configure --prefix="${versionDir}" --enable-optimizations`, { cwd: sourceDir }); console.log(chalk.yellow(' Building Python (this may take a while)...')); await this.executeCommand('make -j$(sysctl -n hw.ncpu)', { cwd: sourceDir }); console.log(chalk.yellow(' Installing Python...')); await this.executeCommand('make altinstall', { cwd: sourceDir }); // Clean up await fs.remove(downloadDir); } async installOnWindows(version, versionDir) { // For Windows, we'll download the installer throw new Error('Windows Python installation not implemented yet. Please install manually.'); } getBinDir(versionDir) { return path.join(versionDir, 'bin'); } async createVirtualEnv(name, pythonVersion) { if (!pythonVersion) { pythonVersion = await this.getCurrentVersion(); } if (!pythonVersion || !await this.isVersionInstalled(pythonVersion)) { console.log(chalk.red('No Python version specified or installed')); return false; } const versionDir = path.join(this.languageDir, pythonVersion); const pythonBin = path.join(versionDir, 'bin', `python${pythonVersion.split('.').slice(0, 2).join('.')}`); const envDir = path.join(CVMUtils.getEnvironmentsDir(), name); if (await fs.pathExists(envDir)) { console.log(chalk.yellow(`Virtual environment '${name}' already exists`)); return false; } console.log(chalk.blue(`Creating virtual environment '${name}' with Python ${pythonVersion}...`)); try { await this.executeCommand(`"${pythonBin}" -m venv "${envDir}"`); console.log(chalk.green(`✓ Virtual environment '${name}' created successfully`)); return true; } catch (error) { console.error(chalk.red(`Failed to create virtual environment:`), error.message); return false; } } } module.exports = PythonVersionManager;