Skip to content

Commit 84c5454

Browse files
committed
chore: wip
1 parent ac4f619 commit 84c5454

File tree

1 file changed

+13
-217
lines changed

1 file changed

+13
-217
lines changed

packages/launchpad/src/services/manager.ts

Lines changed: 13 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,8 @@ async function ensureServicePackageInstalled(service: ServiceInstance): Promise<
775775
return true
776776
}
777777

778-
if (config.verbose) console.warn(`📦 Installing ${definition.displayName} package...`)
778+
if (config.verbose)
779+
console.warn(`📦 Installing ${definition.displayName} package...`)
779780

780781
try {
781782
// Import install function to install service package with dependencies
@@ -786,7 +787,8 @@ async function ensureServicePackageInstalled(service: ServiceInstance): Promise<
786787
const installPath = `${process.env.HOME}/.local`
787788
await install([definition.packageDomain], installPath)
788789

789-
if (config.verbose) console.log(`✅ ${definition.displayName} package installed successfully`)
790+
if (config.verbose)
791+
console.log(`✅ ${definition.displayName} package installed successfully`)
790792

791793
// Verify installation worked by checking in the Launchpad environment
792794
const binaryPath = findBinaryInEnvironment(definition.executable, installPath)
@@ -805,7 +807,7 @@ async function ensureServicePackageInstalled(service: ServiceInstance): Promise<
805807
/**
806808
* Ensure PHP database extensions are available and configured
807809
*/
808-
async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<boolean> {
810+
async function ensurePHPDatabaseExtensions(_service: ServiceInstance): Promise<boolean> {
809811
// Skip PHP extension checks in test mode
810812
if (process.env.NODE_ENV === 'test' || process.env.LAUNCHPAD_TEST_MODE === 'true') {
811813
console.warn(`🧪 Test mode: Skipping PHP database extension checks`)
@@ -816,7 +818,8 @@ async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<bo
816818

817819
try {
818820
// Quietly check PHP modules; do not try to install via PECL
819-
if (config.verbose) console.warn(`🔧 Checking PHP database extensions...`)
821+
if (config.verbose)
822+
console.warn(`🔧 Checking PHP database extensions...`)
820823

821824
// Check what extensions are currently loaded
822825
const phpProcess = spawn('php', ['-m'], { stdio: ['pipe', 'pipe', 'pipe'] })
@@ -848,12 +851,15 @@ async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<bo
848851
const missingExtensions = requiredExtensions.filter(ext => !loadedExtensions.includes(ext))
849852

850853
if (missingExtensions.length === 0) {
851-
if (config.verbose) console.log(`✅ All required PHP database extensions are available`)
854+
if (config.verbose)
855+
console.log(`✅ All required PHP database extensions are available`)
852856
return true
853857
}
854858

855-
if (config.verbose) console.warn(`⚠️ Missing PHP extensions: ${missingExtensions.join(', ')}`)
856-
if (config.verbose) console.warn(`💡 Launchpad ships precompiled PHP binaries with common DB extensions. We'll select the correct binary for your project automatically.`)
859+
if (config.verbose)
860+
console.warn(`⚠️ Missing PHP extensions: ${missingExtensions.join(', ')}`)
861+
if (config.verbose)
862+
console.warn(`💡 Launchpad ships precompiled PHP binaries with common DB extensions. We'll select the correct binary for your project automatically.`)
857863
// Do not attempt PECL here. Let binary-downloader pick the right PHP and shims load the project php.ini
858864
return false
859865
}
@@ -863,85 +869,6 @@ async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<bo
863869
}
864870
}
865871

866-
/**
867-
* Install missing PHP extensions via PECL
868-
*/
869-
async function installMissingExtensionsViaPECL(_service: ServiceInstance, _missingExtensions: string[]): Promise<boolean> {
870-
try {
871-
// Hard-disable PECL install path; always return false
872-
return false
873-
}
874-
catch (error) {
875-
return false
876-
}
877-
}
878-
879-
/**
880-
* Update PHP configuration to load newly installed extensions
881-
*/
882-
async function updatePHPConfigWithInstalledExtensions(service: ServiceInstance, installedExtensions: string[]): Promise<void> {
883-
// Skip PHP config updates in test mode
884-
if (process.env.NODE_ENV === 'test' || process.env.LAUNCHPAD_TEST_MODE === 'true') {
885-
console.warn(`🧪 Test mode: Skipping PHP configuration updates`)
886-
return
887-
}
888-
889-
try {
890-
if (!service.definition?.configFile) {
891-
return
892-
}
893-
894-
// Get the PHP extension directory
895-
const { spawn } = await import('node:child_process')
896-
const extDir = await new Promise<string>((resolve) => {
897-
const phpProcess = spawn('php', ['-i'], { stdio: ['pipe', 'pipe', 'pipe'] })
898-
let output = ''
899-
900-
phpProcess.stdout.on('data', (data) => {
901-
output += data.toString()
902-
})
903-
904-
phpProcess.on('close', () => {
905-
const match = output.match(/extension_dir => (.+)/i)
906-
resolve(match ? match[1].trim() : '')
907-
})
908-
})
909-
910-
if (!extDir) {
911-
console.warn(`⚠️ Could not determine PHP extension directory`)
912-
return
913-
}
914-
915-
// Read current php.ini
916-
let phpIniContent = ''
917-
try {
918-
phpIniContent = await fs.promises.readFile(service.definition.configFile, 'utf8')
919-
}
920-
catch {
921-
// File doesn't exist, create it
922-
phpIniContent = createDefaultServiceConfig('php') || ''
923-
}
924-
925-
// Add extension entries for newly installed extensions
926-
if (!phpIniContent.includes('extension_dir')) {
927-
phpIniContent = `extension_dir = "${extDir}"\n\n${phpIniContent}`
928-
}
929-
930-
// Add the new extensions if they're not already there
931-
for (const ext of installedExtensions) {
932-
if (!phpIniContent.includes(`extension=${ext}`)) {
933-
phpIniContent += `\nextension=${ext}.so`
934-
}
935-
}
936-
937-
await fs.promises.writeFile(service.definition.configFile, phpIniContent, 'utf8')
938-
console.warn(`📝 Updated PHP configuration to load new extensions`)
939-
}
940-
catch (error) {
941-
console.warn(`⚠️ Could not update PHP configuration: ${error instanceof Error ? error.message : String(error)}`)
942-
}
943-
}
944-
945872
/**
946873
* Automatically set up SQLite for the current project
947874
*/
@@ -1042,137 +969,6 @@ export async function setupSQLiteForProject(): Promise<boolean> {
1042969
}
1043970
}
1044971

1045-
/**
1046-
* Suggest SQLite as an alternative when PostgreSQL extensions are missing
1047-
*/
1048-
async function suggestSQLiteAlternative(): Promise<void> {
1049-
try {
1050-
// Check if this is a Laravel project
1051-
if (fs.existsSync('artisan')) {
1052-
console.warn(`💡 For Laravel projects, you can use SQLite with these commands:`)
1053-
console.warn(` php artisan migrate:fresh --seed --database=sqlite`)
1054-
console.warn(` Or configure SQLite in .env:`)
1055-
console.warn(` DB_CONNECTION=sqlite`)
1056-
console.warn(` DB_DATABASE=database/database.sqlite`)
1057-
1058-
// Check if SQLite database file exists, create if not
1059-
const sqliteDbPath = 'database/database.sqlite'
1060-
if (!fs.existsSync(sqliteDbPath)) {
1061-
try {
1062-
await fs.promises.mkdir('database', { recursive: true })
1063-
await fs.promises.writeFile(sqliteDbPath, '', 'utf8')
1064-
console.log(`✅ Created SQLite database file: ${sqliteDbPath}`)
1065-
}
1066-
catch (error) {
1067-
console.warn(`⚠️ Could not create SQLite database file: ${error instanceof Error ? error.message : String(error)}`)
1068-
}
1069-
}
1070-
}
1071-
}
1072-
catch (error) {
1073-
console.warn(`⚠️ Could not suggest SQLite alternative: ${error instanceof Error ? error.message : String(error)}`)
1074-
}
1075-
}
1076-
1077-
/**
1078-
* Create PHP configuration file with database extensions enabled
1079-
*/
1080-
async function createPHPConfigWithExtensions(service: ServiceInstance, _missingExtensions: string[]): Promise<boolean> {
1081-
try {
1082-
if (!service.definition?.configFile) {
1083-
return false
1084-
}
1085-
1086-
const configDir = path.dirname(service.definition.configFile)
1087-
await fs.promises.mkdir(configDir, { recursive: true })
1088-
1089-
// Create sessions and tmp directories
1090-
const sessionsDir = path.join(configDir, 'sessions')
1091-
const tmpDir = path.join(configDir, 'tmp')
1092-
await fs.promises.mkdir(sessionsDir, { recursive: true })
1093-
await fs.promises.mkdir(tmpDir, { recursive: true })
1094-
1095-
// Generate php.ini with extensions
1096-
const phpIniContent = createDefaultServiceConfig('php')
1097-
if (phpIniContent && service.definition.configFile) {
1098-
await fs.promises.writeFile(service.definition.configFile, phpIniContent, 'utf8')
1099-
1100-
// Set PHP to use our custom php.ini file
1101-
process.env.PHPRC = path.dirname(service.definition.configFile)
1102-
1103-
console.warn(`📝 Created PHP configuration at: ${service.definition.configFile}`)
1104-
return true
1105-
}
1106-
1107-
return false
1108-
}
1109-
catch (error) {
1110-
console.error(`❌ Failed to create PHP configuration: ${error instanceof Error ? error.message : String(error)}`)
1111-
return false
1112-
}
1113-
}
1114-
1115-
/**
1116-
* Check if PHP is installed and install PostgreSQL extensions if needed
1117-
*/
1118-
async function checkAndInstallPHPPostgreSQLExtensions(): Promise<void> {
1119-
// Skip PHP PostgreSQL extension checks in test mode
1120-
if (process.env.NODE_ENV === 'test' || process.env.LAUNCHPAD_TEST_MODE === 'true') {
1121-
console.warn(`🧪 Test mode: Skipping PHP PostgreSQL extension checks`)
1122-
return
1123-
}
1124-
1125-
try {
1126-
const { findBinaryInPath } = await import('../utils')
1127-
1128-
// Check if PHP is installed
1129-
if (!findBinaryInPath('php')) {
1130-
return // PHP not installed, nothing to do
1131-
}
1132-
1133-
// Check if PHP is missing PostgreSQL extensions
1134-
const { spawn } = await import('node:child_process')
1135-
1136-
const phpProcess = spawn('php', ['-m'], { stdio: ['pipe', 'pipe', 'pipe'] })
1137-
let output = ''
1138-
1139-
phpProcess.stdout.on('data', (data) => {
1140-
output += data.toString()
1141-
})
1142-
1143-
const checkResult = await new Promise<boolean>((resolve) => {
1144-
phpProcess.on('close', (code) => {
1145-
resolve(code === 0)
1146-
})
1147-
})
1148-
1149-
if (!checkResult) {
1150-
return
1151-
}
1152-
1153-
const loadedExtensions = output.toLowerCase().split('\n').map(line => line.trim())
1154-
const missingPgsqlExtensions = ['pdo_pgsql', 'pgsql'].filter(ext => !loadedExtensions.includes(ext))
1155-
1156-
// We ship PHP binaries with the correct extensions via the precompiled downloader.
1157-
// Do not attempt PECL installs here; just warn if user-provided PHP lacks extensions.
1158-
if (missingPgsqlExtensions.length > 0) {
1159-
if (config.verbose) {
1160-
console.warn(`⚠️ PHP appears to be missing PostgreSQL extensions: ${missingPgsqlExtensions.join(', ')}`)
1161-
console.warn(`💡 Launchpad's precompiled PHP includes these extensions. If you installed PHP externally,`
1162-
+ ` consider switching to Launchpad-managed PHP or use SQLite (DB_CONNECTION=sqlite).`)
1163-
}
1164-
// Continue without blocking; extensions are best-effort
1165-
}
1166-
else {
1167-
if (config.verbose)
1168-
console.log(`✅ PHP already has PostgreSQL extensions installed`)
1169-
}
1170-
}
1171-
catch (error) {
1172-
console.warn(`⚠️ Could not check PHP PostgreSQL extensions: ${error instanceof Error ? error.message : String(error)}`)
1173-
}
1174-
}
1175-
1176972
/**
1177973
* Auto-initialize databases on first start
1178974
*/

0 commit comments

Comments
 (0)