cvm-cli
Version:
A unified CLI tool for managing PHP, Node.js, and Python versions with virtual environment and dependency management support.
195 lines (160 loc) • 7.14 kB
JavaScript
const BaseVersionManager = require('./baseVersionManager');
const fetch = require('node-fetch');
const fs = require('fs-extra');
const chalk = require('chalk');
const path = require('path');
class PHPVersionManager extends BaseVersionManager {
constructor() {
super('php');
}
async getAvailableVersions() {
// For simplicity, return a list of commonly used PHP versions
// In a real implementation, you'd fetch from php.net or use phpenv's list
return [
'8.3.0', '8.2.14', '8.2.13', '8.2.12', '8.2.11', '8.2.10', '8.2.9', '8.2.8', '8.2.7', '8.2.6', '8.2.5', '8.2.4', '8.2.3', '8.2.2', '8.2.1', '8.2.0',
'8.1.27', '8.1.26', '8.1.25', '8.1.24', '8.1.23', '8.1.22', '8.1.21', '8.1.20', '8.1.19', '8.1.18', '8.1.17', '8.1.16', '8.1.15', '8.1.14', '8.1.13', '8.1.12', '8.1.11', '8.1.10', '8.1.9', '8.1.8', '8.1.7', '8.1.6', '8.1.5', '8.1.4', '8.1.3', '8.1.2', '8.1.1', '8.1.0',
'8.0.30', '8.0.29', '8.0.28', '8.0.27', '8.0.26', '8.0.25', '8.0.24', '8.0.23', '8.0.22', '8.0.21', '8.0.20', '8.0.19', '8.0.18', '8.0.17', '8.0.16', '8.0.15', '8.0.14', '8.0.13', '8.0.12', '8.0.11', '8.0.10', '8.0.9', '8.0.8', '8.0.7', '8.0.6', '8.0.5', '8.0.3', '8.0.2', '8.0.1', '8.0.0',
'7.4.33', '7.4.32', '7.4.30', '7.4.29', '7.4.28', '7.4.27', '7.4.26', '7.4.25', '7.4.24', '7.4.23', '7.4.22', '7.4.21', '7.4.20', '7.4.19', '7.4.18', '7.4.16', '7.4.15', '7.4.14', '7.4.13', '7.4.12', '7.4.11', '7.4.10', '7.4.9', '7.4.8', '7.4.7', '7.4.6', '7.4.5', '7.4.4', '7.4.3', '7.4.2', '7.4.1', '7.4.0'
];
}
async install(version) {
if (await this.isVersionInstalled(version)) {
console.log(chalk.yellow(`PHP ${version} is already installed.`));
return true;
}
console.log(chalk.blue(`Installing PHP ${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(`✓ PHP ${version} installed successfully`));
return true;
} catch (error) {
console.error(chalk.red(`Failed to install PHP ${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.php.net/distributions/php-${version}.tar.gz`;
const downloadDir = path.join(this.languageDir, 'downloads');
const downloadPath = path.join(downloadDir, `php-${version}.tar.gz`);
const sourceDir = path.join(downloadDir, `php-${version}`);
console.log(chalk.yellow(' Downloading PHP source...'));
await this.downloadFile(downloadUrl, downloadPath);
console.log(chalk.yellow(' Extracting source...'));
await this.extractTarGz(downloadPath, sourceDir);
console.log(chalk.yellow(' Configuring build...'));
const configureFlags = [
`--prefix="${versionDir}"`,
'--enable-fpm',
'--enable-opcache',
'--enable-mbstring',
'--enable-soap',
'--enable-zip',
'--enable-calendar',
'--enable-bcmath',
'--enable-exif',
'--enable-intl',
'--with-curl',
'--with-pdo-mysql',
'--with-pdo-pgsql',
'--with-readline',
'--with-openssl',
'--with-zlib',
'--with-bz2',
'--with-gd'
].join(' ');
await this.executeCommand(`./configure ${configureFlags}`, {
cwd: sourceDir
});
console.log(chalk.yellow(' Building PHP (this may take a while)...'));
await this.executeCommand('make -j$(nproc)', { cwd: sourceDir });
console.log(chalk.yellow(' Installing PHP...'));
await this.executeCommand('make install', { 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.php.net/distributions/php-${version}.tar.gz`;
const downloadDir = path.join(this.languageDir, 'downloads');
const downloadPath = path.join(downloadDir, `php-${version}.tar.gz`);
const sourceDir = path.join(downloadDir, `php-${version}`);
console.log(chalk.yellow(' Downloading PHP source...'));
await this.downloadFile(downloadUrl, downloadPath);
console.log(chalk.yellow(' Extracting source...'));
await this.extractTarGz(downloadPath, sourceDir);
console.log(chalk.yellow(' Configuring build...'));
const configureFlags = [
`--prefix="${versionDir}"`,
'--enable-fpm',
'--enable-opcache',
'--enable-mbstring',
'--enable-soap',
'--enable-zip',
'--enable-calendar',
'--enable-bcmath',
'--enable-exif',
'--with-curl',
'--with-pdo-mysql',
'--with-readline',
'--with-openssl',
'--with-zlib',
'--with-bz2'
].join(' ');
await this.executeCommand(`./configure ${configureFlags}`, {
cwd: sourceDir
});
console.log(chalk.yellow(' Building PHP (this may take a while)...'));
await this.executeCommand('make -j$(sysctl -n hw.ncpu)', { cwd: sourceDir });
console.log(chalk.yellow(' Installing PHP...'));
await this.executeCommand('make install', { cwd: sourceDir });
// Clean up
await fs.remove(downloadDir);
}
async installOnWindows(version, versionDir) {
// For Windows, we'd download pre-compiled binaries
throw new Error('Windows PHP installation not implemented yet. Please install manually.');
}
getBinDir(versionDir) {
return path.join(versionDir, 'bin');
}
async installComposer(version) {
const versionDir = path.join(this.languageDir, version);
const binDir = this.getBinDir(versionDir);
const composerPath = path.join(binDir, 'composer');
if (await fs.pathExists(composerPath)) {
console.log(chalk.yellow('Composer is already installed for this PHP version'));
return;
}
console.log(chalk.blue('Installing Composer...'));
try {
// Download composer installer
const installerUrl = 'https://getcomposer.org/installer';
const installerPath = path.join(versionDir, 'composer-installer.php');
await this.downloadFile(installerUrl, installerPath);
// Install composer
const phpBin = path.join(binDir, 'php');
await this.executeCommand(`"${phpBin}" "${installerPath}" --install-dir="${binDir}" --filename=composer`);
// Clean up installer
await fs.remove(installerPath);
console.log(chalk.green('✓ Composer installed successfully'));
} catch (error) {
console.error(chalk.red('Failed to install Composer:'), error.message);
}
}
}
module.exports = PHPVersionManager;