@@ -775,7 +775,8 @@ async function ensureServicePackageInstalled(service: ServiceInstance): Promise<
775
775
return true
776
776
}
777
777
778
- if ( config . verbose ) console . warn ( `📦 Installing ${ definition . displayName } package...` )
778
+ if ( config . verbose )
779
+ console . warn ( `📦 Installing ${ definition . displayName } package...` )
779
780
780
781
try {
781
782
// Import install function to install service package with dependencies
@@ -786,7 +787,8 @@ async function ensureServicePackageInstalled(service: ServiceInstance): Promise<
786
787
const installPath = `${ process . env . HOME } /.local`
787
788
await install ( [ definition . packageDomain ] , installPath )
788
789
789
- if ( config . verbose ) console . log ( `✅ ${ definition . displayName } package installed successfully` )
790
+ if ( config . verbose )
791
+ console . log ( `✅ ${ definition . displayName } package installed successfully` )
790
792
791
793
// Verify installation worked by checking in the Launchpad environment
792
794
const binaryPath = findBinaryInEnvironment ( definition . executable , installPath )
@@ -805,7 +807,7 @@ async function ensureServicePackageInstalled(service: ServiceInstance): Promise<
805
807
/**
806
808
* Ensure PHP database extensions are available and configured
807
809
*/
808
- async function ensurePHPDatabaseExtensions ( service : ServiceInstance ) : Promise < boolean > {
810
+ async function ensurePHPDatabaseExtensions ( _service : ServiceInstance ) : Promise < boolean > {
809
811
// Skip PHP extension checks in test mode
810
812
if ( process . env . NODE_ENV === 'test' || process . env . LAUNCHPAD_TEST_MODE === 'true' ) {
811
813
console . warn ( `🧪 Test mode: Skipping PHP database extension checks` )
@@ -816,7 +818,8 @@ async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<bo
816
818
817
819
try {
818
820
// 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...` )
820
823
821
824
// Check what extensions are currently loaded
822
825
const phpProcess = spawn ( 'php' , [ '-m' ] , { stdio : [ 'pipe' , 'pipe' , 'pipe' ] } )
@@ -848,12 +851,15 @@ async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<bo
848
851
const missingExtensions = requiredExtensions . filter ( ext => ! loadedExtensions . includes ( ext ) )
849
852
850
853
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` )
852
856
return true
853
857
}
854
858
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.` )
857
863
// Do not attempt PECL here. Let binary-downloader pick the right PHP and shims load the project php.ini
858
864
return false
859
865
}
@@ -863,85 +869,6 @@ async function ensurePHPDatabaseExtensions(service: ServiceInstance): Promise<bo
863
869
}
864
870
}
865
871
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 ( / e x t e n s i o n _ d i r = > ( .+ ) / 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
-
945
872
/**
946
873
* Automatically set up SQLite for the current project
947
874
*/
@@ -1042,137 +969,6 @@ export async function setupSQLiteForProject(): Promise<boolean> {
1042
969
}
1043
970
}
1044
971
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
-
1176
972
/**
1177
973
* Auto-initialize databases on first start
1178
974
*/
0 commit comments