diff --git a/apps/Core/Packages/Adminltetags/Tags/Modal.php b/apps/Core/Packages/Adminltetags/Tags/Modal.php index 7f5a64653..335ab4ea5 100644 --- a/apps/Core/Packages/Adminltetags/Tags/Modal.php +++ b/apps/Core/Packages/Adminltetags/Tags/Modal.php @@ -150,6 +150,10 @@ protected function generateContent() $this->params['modalEscClose'] : 'false'; + if ($this->modalParams['modalEscClose'] === true) { + $this->modalParams['modalEscClose'] = 'true'; + } + $this->modalParams['modalType'] = isset($this->params['modalType']) ? $this->params['modalType'] : diff --git a/apps/Core/Views/Default/html/modules/analyse.html b/apps/Core/Views/Default/html/modules/analyse.html index cc90af274..d9c7a63c6 100644 --- a/apps/Core/Views/Default/html/modules/analyse.html +++ b/apps/Core/Views/Default/html/modules/analyse.html @@ -355,6 +355,11 @@ if (object === 'analyse_logs' || object === 'precheck_logs' || object === 'result_logs') { if (logObject[object] !== '-') { + if ($(this).data()['moduletype'] !== 'external') { + logObject[object] = JSON.parse(logObject[object]); + logObject[object] = BazHelpers.createHtmlList({'obj': logObject[object]}); + } + logObject[object] = '
' + logObject[object] + '
'; } } @@ -426,6 +431,8 @@ 'modalSize' : 'xl', 'modalHeader' : true, 'modalFooter' : true, + 'modalHeaderCloseButton' : true, + 'modalEscClose' : true, 'modalTitle' : ' LOGS' ] )}} diff --git a/system/Base/Helpers.php b/system/Base/Helpers.php index 1ac4bd396..9399360ae 100644 --- a/system/Base/Helpers.php +++ b/system/Base/Helpers.php @@ -465,6 +465,8 @@ function array_get_values_recursive($keys = [], array $arr) { return count($val) > 1 ? $val : array_pop($val); } +} + if (!function_exists('arraySqueeze')) { //$task = keep - Keep the data of defined keys, remove rest diff --git a/system/Base/Installer/Packages/Setup/Register/Modules/Packages/Providers/Core/package.json b/system/Base/Installer/Packages/Setup/Register/Modules/Packages/Providers/Core/package.json index f097cc9de..83ec5c01f 100644 --- a/system/Base/Installer/Packages/Setup/Register/Modules/Packages/Providers/Core/package.json +++ b/system/Base/Installer/Packages/Setup/Register/Modules/Packages/Providers/Core/package.json @@ -58,7 +58,8 @@ "wp-cli/php-cli-tools" : "^0.11.22", "react/event-loop" : "1.5.0", "mattiasgeniar/php-percentages" : "^1.3", - "spatie/server-side-rendering" : "^0.3.2" + "spatie/server-side-rendering" : "^0.3.2", + "xobotyi/rsync" : "^1.0" }, "config" : { @@ -75,11 +76,11 @@ { "phpv8.3 support" : "patches/react_socket_connection.patch" }, - "cboden/ratchet" : + "cboden/ratchet" : { "phpv8.3 support" : "patches/cboden_ratchet_ioconnection.patch" }, - "league/oauth2-server" : + "league/oauth2-server" : { "extract client_id" : "patches/league_oauth2_server_bearertokenvalidator.patch" } diff --git a/system/Base/Providers/ModulesServiceProvider/Installer.php b/system/Base/Providers/ModulesServiceProvider/Installer.php index 3c85b72c4..3526ba4ec 100644 --- a/system/Base/Providers/ModulesServiceProvider/Installer.php +++ b/system/Base/Providers/ModulesServiceProvider/Installer.php @@ -3,13 +3,16 @@ namespace System\Base\Providers\ModulesServiceProvider; use League\Flysystem\FilesystemException; +use League\Flysystem\UnableToCheckExistence; use League\Flysystem\UnableToCopyFile; +use League\Flysystem\UnableToDeleteDirectory; use League\Flysystem\UnableToDeleteFile; use League\Flysystem\UnableToMoveFile; use League\Flysystem\UnableToReadFile; use League\Flysystem\UnableToRetrieveMetadata; use League\Flysystem\UnableToWriteFile; use System\Base\BasePackage; +use xobotyi\rsync\Rsync; use z4kn4fein\SemVer\Version; class Installer extends BasePackage @@ -58,8 +61,12 @@ public function init($process = 'precheck') $this->zip = new \ZipArchive; - if (!$this->localContent->fileExists($this->downloadLocation)) { - $this->localContent->createDirectory($this->downloadLocation); + try { + if (!$this->localContent->directoryExists($this->downloadLocation)) { + $this->localContent->createDirectory($this->downloadLocation); + } + } catch (FilesystemException | UnableToCheckExistence | \throwable $e) { + throw $e; } $this->basepackages->progress->init(null, 'modulesinstaller'); @@ -524,16 +531,15 @@ protected function extractModulesDownloadedFromRepo() return false; } - $files = $this->basepackages->utils->scanDir($this->zipFile['location'], false); if ($files && isset($files['dirs'][0])) { try { $name = str_replace('.zip', '', $this->zipFile['name']); - $files['dirs'][0]; - $this->localContent->move($files['dirs'][0], $this->downloadLocation . $name . '/' . $name); + + $this->zip->close(); } catch (FilesystemException | UnableToMoveFile $e) { $this->addResponse('Error renaming extracted directory for : ' . $this->zipFile['name'], 1); @@ -548,6 +554,100 @@ protected function extractModulesDownloadedFromRepo() return false; } + protected function dryRunRsync($args) + { + $taskName = $args[0]; + $module = $args[1]; + + $this->queue['results'][$taskName][$module['module_type']][$module['id']]['precheck'] = 'fail'; + + $preCheckQueueLogs = &$this->queue['results'][$taskName][$module['module_type']][$module['id']]['precheck_logs']; + + try { + $rsync = new Rsync([ + Rsync::CONF_CWD => base_path('var/tmp/installer/' . $this->zipFile['name'] . '/' . $this->zipFile['name']), + Rsync::CONF_OPTIONS => + [ + Rsync::OPT_DRY_RUN => true, + Rsync::OPT_VERBOSE => true, + Rsync::OPT_ARCHIVE => true, + Rsync::OPT_HUMAN_READABLE => true, + Rsync::OPT_CHECKSUM => true, + Rsync::OPT_DELETE_AFTER => true, + Rsync::OPT_INCLUDE => + [ + 'public', + 'public/index.php', + 'public/.htaccess_example', + 'public/core/***', + 'external', + 'external/patches', + 'external/patches/***', + 'apps', + 'apps/Core/***', + 'system/***' + ], + Rsync::OPT_EXCLUDE => ['*'], + ] + ]); + + $rsync->sync('.', base_path('')); + + if ($rsync->getExitCode() == 0) { + $outputArr = explode(PHP_EOL, $rsync->getStdout()); + // trace([$outputArr], false, false, true); + $modifiedFiles = []; + $deleteFiles = []; + + array_walk($outputArr, function($output) use (&$modifiedFiles, &$deleteFiles) { + if (str_starts_with($output, 'apps') || + str_starts_with($output, 'system') || + str_starts_with($output, 'public') || + str_starts_with($output, 'external') + ) { + if (!str_ends_with($output, '/') && + !str_ends_with($output, '.git') + ) { + array_push($modifiedFiles, $output); + } + } + + if (str_starts_with($output, 'deleting')) { + if (!str_ends_with($output, '/') && + !str_ends_with($output, '.git') && + !str_ends_with($output, 'keys') + ) { + $output = str_replace('deleting ', '', $output); + array_push($deleteFiles, $output); + } + } + }); + } + + $this->queue['results'][$taskName][$module['module_type']][$module['id']]['precheck'] = 'pass'; + + $preCheckQueueLogs = $this->helper->encode(['modifiedFiles' => $modifiedFiles, 'deleteFiles' => $deleteFiles]); + // trace(varsToDump : [$modifiedFiles, $deleteFiles], object: true); + + return true; + } catch (\throwable $e) { + if (str_contains($e->getMessage(), 'No such file or directory')) { + $rsyncError = 'Incorrect directory : ' . $rsync->getCWD(); + } else { + $rsyncError = $e->getMessage(); + } + } + + if (!isset($rsyncError)) { + $rsyncError = $rsync->getStderr(); + } + + return $this->preCheckHasErrors( + $rsyncError, + $preCheckQueueLogs + ); + } + protected function checkDependencies() { if (count($this->modulesToProcess) === 0) { @@ -753,7 +853,7 @@ protected function checkRegisteredDependencies($dependencies) return $found; } - protected function cleanup(array $what) + public function cleanup(array $what) { if (in_array('composer', $what)) { $files = $this->basepackages->utils->scanDir('external', false); @@ -772,6 +872,16 @@ protected function cleanup(array $what) } } } + + if (in_array('downloads', $what)) { + try { + if ($this->localContent->directoryExists($this->downloadLocation)) { + $this->localContent->deleteDirectory($this->downloadLocation); + } + } catch (FilesystemException | UnableToCheckExistence | UnableToDeleteDirectory | \throwable $e) { + throw $e; + } + } } // protected function getLatestRepositoryModulesData() @@ -1022,7 +1132,7 @@ protected function rollBack() protected function registerRunProcessPrecheckProgressMethods() { $this->runProcessPrecheckProgressMethods = []; - // trace([$this->queue['tasks']['analysed']]); + foreach ($this->queue['tasks']['analysed'] as $taskName => $modulesTypes) { if (($taskName === 'first' || $taskName === 'install' || $taskName === 'update') && count($modulesTypes) > 0 @@ -1096,6 +1206,13 @@ protected function registerRunProcessPrecheckProgressMethods() 'text' => 'Extracting downloaded module ' . $module['name'] . ' (' . ucfirst($module['module_type']) . ')...' ] ); + array_push($this->runProcessPrecheckProgressMethods, + [ + 'method' => 'dryRunRsync-' . $module['id'] . '-' . strtolower(str_replace(' ', '', $module['name'])), + 'text' => 'Running rsync --dry-run for ' . $module['name'] . ' (' . ucfirst($module['module_type']) . ')...', + 'args' => [$taskName, $module], + ] + ); } } } diff --git a/system/Base/Providers/ModulesServiceProvider/Modules/Packages/PackagesData.php b/system/Base/Providers/ModulesServiceProvider/Modules/Packages/PackagesData.php index e9a78f517..353249e6d 100644 --- a/system/Base/Providers/ModulesServiceProvider/Modules/Packages/PackagesData.php +++ b/system/Base/Providers/ModulesServiceProvider/Modules/Packages/PackagesData.php @@ -36,4 +36,9 @@ public function __isset($key) { return array_key_exists($key, $this->packagesData); } + + public function reset() + { + $this->packagesData = []; + } } \ No newline at end of file diff --git a/system/Base/Providers/ModulesServiceProvider/Queues.php b/system/Base/Providers/ModulesServiceProvider/Queues.php index 6736b5649..c0e78a943 100644 --- a/system/Base/Providers/ModulesServiceProvider/Queues.php +++ b/system/Base/Providers/ModulesServiceProvider/Queues.php @@ -231,6 +231,10 @@ public function analyseQueue(&$queue = null, $reAnalyse = false) return true; } + if ($reAnalyse) { + $this->modules->installer->cleanup(['composer', 'downloads']); + } + $this->queueTasks = []; $this->results = []; $queue['tasks']['analysed'] = [];//Reset Analysed @@ -577,8 +581,12 @@ protected function checkComposerAndAddToQueue($composerPackages, $module) } if (isset($composerPackages['extra']['patches'][$composerPackage])) { - $composerJsonFile['extra']['patches'][$composerPackage][$this->helper->firstKey($composerPackages['extra']['patches'][$composerPackage])] = base_path($this->helper->first($composerPackages['extra']['patches'][$composerPackage])); - $hasPatch = true; + foreach ($composerPackages['extra']['patches'][$composerPackage] as $patchKey => $patchValue) { + if (!isset($composerJsonFile['extra']['patches'][$composerPackage][$patchKey])) { + $composerJsonFile['extra']['patches'][$composerPackage][$patchKey] = $patchValue; + $hasPatch = true; + } + } } if ($installExternal || $hasConfigChange || $hasPatch) {