90 if ($bearsamppRoot->getProcs() !==
false) {
98 foreach ($listProcs as
$proc) {
101 Util::logTrace(
'Found ' . count($listProcs) .
' running processes');
103 Util::logTrace(
'No processes found or unable to retrieve process list');
108 $this->
writeLog(
'List bins modules:');
109 foreach ($bearsamppBins->getAll() as $module) {
110 if (!$module->isEnable()) {
112 Util::logTrace(
'Bin module ' . $module->getName() .
' is disabled');
114 $this->
writeLog(
'-> ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
115 Util::logTrace(
'Bin module ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
120 $this->
writeLog(
'List tools modules:');
121 foreach ($bearsamppTools->getAll() as $module) {
122 if (!$module->isEnable()) {
124 Util::logTrace(
'Tool module ' . $module->getName() .
' is disabled');
126 $this->
writeLog(
'-> ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
127 Util::logTrace(
'Tool module ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
132 $this->
writeLog(
'List apps modules:');
133 foreach ($bearsamppApps->getAll() as $module) {
134 if (!$module->isEnable()) {
136 Util::logTrace(
'App module ' . $module->getName() .
' is disabled');
138 $this->
writeLog(
'-> ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
139 Util::logTrace(
'App module ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
202 if (!$this->restart && empty($this->error)) {
203 Util::logTrace(
'Startup completed successfully - refreshing Git repositories');
206 $this->
writeLog(
'Started in ' . $startupTime .
's');
207 Util::logTrace(
'Application started successfully in ' . $startupTime .
' seconds');
209 Util::logTrace(
'Startup issues detected - incrementing progress bar');
210 $this->splash->incrProgressBar(2);
213 if ($this->restart) {
214 Util::logTrace(
'Restart required - preparing to restart application');
216 $this->splash->setTextLoading(
233 if (!empty($this->error)) {
234 Util::logTrace(
'Errors occurred during startup: ' . $this->error);
235 $this->
writeLog(
'Error: ' . $this->error);
251 $bearsamppWinbinder->reset();
269 $this->splash->incrProgressBar();
272 if (!is_dir($archivesPath)) {
274 mkdir($archivesPath, 0777,
true);
278 $date = date(
'Y-m-d-His', time());
279 $archiveLogsPath = $archivesPath .
'/' . $date;
280 $archiveScriptsPath = $archiveLogsPath .
'/scripts';
283 Util::logTrace(
"Creating archive directories for current rotation");
284 if (!is_dir($archiveLogsPath)) {
285 Util::logTrace(
"Creating logs archive directory: " . $archiveLogsPath);
286 mkdir($archiveLogsPath, 0777,
true);
288 Util::logTrace(
"Logs archive directory already exists: " . $archiveLogsPath);
291 if (!is_dir($archiveScriptsPath)) {
292 Util::logTrace(
"Creating scripts archive directory: " . $archiveScriptsPath);
293 mkdir($archiveScriptsPath, 0777,
true);
295 Util::logTrace(
"Scripts archive directory already exists: " . $archiveScriptsPath);
301 $handle = @opendir($archivesPath);
303 Util::logTrace(
"Failed to open archives directory: " . $archivesPath);
307 while (
false !== ($file = readdir($handle))) {
308 if ($file ==
'.' || $file ==
'..') {
311 $archives[] = $archivesPath .
'/' . $file;
315 Util::logTrace(
"Found " . count($archives) .
" existing archives");
321 for ($i = 0; $i < $total; $i++) {
328 $isFileLocked =
function($filePath) {
329 if (!file_exists($filePath)) {
333 $handle = @fopen($filePath,
'r+');
334 if ($handle ===
false) {
346 $handle = @opendir($srcPath);
355 while (
false !== ($file = readdir($handle))) {
356 if ($file ==
'.' || $file ==
'..' || is_dir($srcPath .
'/' . $file)) {
360 $sourceFile = $srcPath .
'/' . $file;
361 $destFile = $archiveLogsPath .
'/' . $file;
364 if ($isFileLocked($sourceFile)) {
371 if (copy($sourceFile, $destFile)) {
378 }
catch (Exception $e) {
380 Util::logTrace(
"Exception copying log file " . $file .
": " . $e->getMessage());
384 Util::logTrace(
"Logs archived: " . $logsCopied .
" copied, " . $logsSkipped .
" skipped");
389 $handle = @opendir($srcPath);
398 while (
false !== ($file = readdir($handle))) {
399 if ($file ==
'.' || $file ==
'..' || is_dir($srcPath .
'/' . $file)) {
403 $sourceFile = $srcPath .
'/' . $file;
404 $destFile = $archiveScriptsPath .
'/' . $file;
407 if ($isFileLocked($sourceFile)) {
414 if (copy($sourceFile, $destFile)) {
421 }
catch (Exception $e) {
423 Util::logTrace(
"Exception copying script file " . $file .
": " . $e->getMessage());
427 Util::logTrace(
"Scripts archived: " . $scriptsCopied .
" copied, " . $scriptsSkipped .
" skipped");
432 $handle = @opendir($logsPath);
434 Util::logTrace(
"Failed to open logs directory for purging: " . $logsPath);
439 $logsPurgeSkipped = 0;
441 while (
false !== ($file = readdir($handle))) {
442 if ($file ==
'.' || $file ==
'..' || $file ==
'archives' || $file ==
'.gitignore' || is_dir($logsPath .
'/' . $file)) {
446 $filePath = $logsPath .
'/' . $file;
449 if ($isFileLocked($filePath)) {
450 Util::logTrace(
"Skipping locked log file during purge: " . $file);
456 if (unlink($filePath)) {
463 }
catch (Exception $e) {
465 Util::logTrace(
"Exception purging log file " . $file .
": " . $e->getMessage());
469 Util::logTrace(
"Logs purged: " . $logsDeleted .
" deleted, " . $logsPurgeSkipped .
" skipped");
761 $this->splash->incrProgressBar();
764 $this->
writeLog(
'Current system PATH: ' . $currentSysPathRegKey );
769 $this->
writeLog(
'New system PATH: ' . $newSysPathRegKey );
771 if ( $currentSysPathRegKey != $newSysPathRegKey ) {
773 if ( !empty( $this->error ) ) {
774 $this->error .= PHP_EOL . PHP_EOL;
777 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
780 $this->
writeLog(
'Need restart: checkSystemPathRegKey' );
781 $this->restart =
true;
785 $this->
writeLog(
'Refresh system PATH: ' . $currentSysPathRegKey );
835 if (!$this->restart) {
840 $serviceRestart =
false;
841 $serviceAlreadyInstalled =
false;
842 $serviceToRemove =
false;
847 $syntaxCheckCmd =
null;
870 if (!file_exists($bin->getDataDir()) || count(glob($bin->getDataDir() .
'/*')) === 0) {
890 $name = $bin->getName() .
' ' . $bin->getVersion() .
' (' . $service->getName() .
')';
893 $this->splash->incrProgressBar();
899 $serviceCheckStartTime = microtime(
true);
900 $serviceCheckTimeout = 15;
911 if ($serviceInfos ===
false && $service->isInstalled()) {
912 Util::logTrace(
'MySQL service appears to be hanging, forcing restart');
915 $serviceToRemove =
true;
920 $serviceInfos = $service->infos();
923 if (microtime(
true) - $serviceCheckStartTime > $serviceCheckTimeout) {
924 Util::logTrace(
"Service check timeout exceeded, assuming service is not installed");
925 $serviceInfos =
false;
927 }
catch (\Exception $e) {
928 Util::logTrace(
"Exception during service check: " . $e->getMessage() .
", assuming service is not installed");
929 $serviceInfos =
false;
930 }
catch (\Throwable $e) {
931 Util::logTrace(
"Throwable during service check: " . $e->getMessage() .
", assuming service is not installed");
932 $serviceInfos =
false;
935 if ($serviceInfos !==
false) {
936 $serviceAlreadyInstalled =
true;
937 $this->
writeLog($name .
' service already installed');
940 foreach ($serviceInfos as $key => $value) {
941 $this->
writeLog(
'-> ' . $key .
': ' . $value);
948 $serviceGenPathName = trim(str_replace(
'"',
'', $service->getBinPath()));
950 $serviceVbsPathName = trim(str_replace(
'"',
'', $installedPathParts[0]));
952 Util::logTrace(
'PostgreSQL service - comparing only executable paths');
957 $serviceGenPathName = trim(str_replace(
'"',
'', $service->getBinPath() . ($service->getParams() ?
' ' . $service->getParams() :
'')));
960 Util::logTrace(
'Comparing service paths - Generated: ' . $serviceGenPathName .
' vs Installed: ' . $serviceVbsPathName);
963 Util::logTrace(
'Generated path length: ' . strlen($serviceGenPathName));
964 Util::logTrace(
'Installed path length: ' . strlen($serviceVbsPathName));
967 $genChars =
'Generated path char codes: ';
968 for ($i = 0; $i < strlen($serviceGenPathName); $i++) {
969 $genChars .= ord($serviceGenPathName[$i]) .
' ';
973 $instChars =
'Installed path char codes: ';
974 for ($i = 0; $i < strlen($serviceVbsPathName); $i++) {
975 $instChars .= ord($serviceVbsPathName[$i]) .
' ';
981 $normalizedGenPath = preg_replace(
'/\s+/',
' ', $serviceGenPathName);
982 $normalizedVbsPath = preg_replace(
'/\s+/',
' ', $serviceVbsPathName);
984 if ($normalizedGenPath === $normalizedVbsPath) {
985 Util::logTrace(
'Paths match after normalizing whitespace - skipping service reinstall');
986 }
else if ($serviceGenPathName != $serviceVbsPathName) {
987 $serviceToRemove =
true;
988 $this->
writeLog($name .
' service has to be removed');
989 $this->
writeLog(
'-> serviceGenPathName: ' . $serviceGenPathName);
990 $this->
writeLog(
'-> serviceVbsPathName: ' . $serviceVbsPathName);
991 Util::logTrace(
"Service paths don't match - service will be removed and reinstalled");
997 $this->splash->incrProgressBar();
998 if ($serviceToRemove) {
1000 if (!$service->delete()) {
1002 $serviceRestart =
true;
1008 if (!$serviceRestart) {
1011 if ($isPortInUse ===
false) {
1013 $this->splash->incrProgressBar();
1014 if (!$serviceAlreadyInstalled || $serviceToRemove) {
1017 if (!$service->create()) {
1019 Util::logTrace(
'Service creation failed: ' . $service->getError());
1025 $this->splash->incrProgressBar();
1029 if (!$service->start()) {
1030 if (!empty($serviceError)) {
1031 $serviceError .= PHP_EOL;
1036 if (!empty($syntaxCheckCmd)) {
1040 $syntaxCheckStartTime = microtime(
true);
1041 $syntaxCheckTimeout = 5;
1044 $cmdSyntaxCheck = $bin->getCmdLineOutput($syntaxCheckCmd);
1047 if (microtime(
true) - $syntaxCheckStartTime > $syntaxCheckTimeout) {
1048 Util::logTrace(
'Syntax check timeout exceeded, assuming syntax is OK');
1049 $cmdSyntaxCheck = [
'syntaxOk' =>
true];
1052 if (!$cmdSyntaxCheck[
'syntaxOk']) {
1054 Util::logTrace(
'Syntax check failed: ' . $cmdSyntaxCheck[
'content']);
1056 Util::logTrace(
'Syntax check passed but service still failed to start');
1058 }
catch (\Exception $e) {
1059 Util::logTrace(
'Exception during syntax check: ' . $e->getMessage());
1061 }
catch (\Throwable $e) {
1062 Util::logTrace(
'Throwable during syntax check: ' . $e->getMessage());
1069 $this->splash->incrProgressBar();
1072 if (!empty($serviceError)) {
1073 $serviceError .= PHP_EOL;
1076 $this->splash->incrProgressBar(3);
1079 $this->
writeLog(
'Need restart: installService ' . $bin->getName());
1080 Util::logTrace(
'Restart required for service: ' . $bin->getName());
1081 $this->restart =
true;
1082 $this->splash->incrProgressBar(3);
1085 if (!empty($serviceError)) {
1087 if (!empty($this->error)) {
1088 $this->error .= PHP_EOL . PHP_EOL;
1093 $this->
writeLog($name .
' service installed in ' . $installTime .
's');
1094 Util::logTrace(
'Service ' . $name .
' installed successfully in ' . $installTime .
' seconds');
1099 $this->splash->incrProgressBar(self::GAUGE_SERVICES * count(
$bearsamppBins->getServices()));