diff --git a/apps/Core/Views/Default/html/modules/analyse.html b/apps/Core/Views/Default/html/modules/analyse.html index 8214d3bb9..cc90af274 100644 --- a/apps/Core/Views/Default/html/modules/analyse.html +++ b/apps/Core/Views/Default/html/modules/analyse.html @@ -1,4 +1,4 @@ - + {% set queueTasksCounterInstall = 0 %} {% set queueTasksCounterUpdate = 0 %} {% set queueTasksCounterUninstall = 0 %} @@ -69,7 +69,7 @@ {% if task === 'first' or task === 'install' or task === 'uninstall' or task === 'update' or task === 'remove' %} {% if queueTaskModules|length > 0 %} {% for modulesType, modules in queueTaskModules %} - {% if modules|length > 0 %} + {% if is_array(modules) and modules|length > 0 %} {% for moduleId, module in modules %} {% set error = 'false' %} {% set color = 'primary' %} @@ -430,4 +430,3 @@ ] )}} - \ No newline at end of file diff --git a/external/patches/generatepatches.info b/external/patches/generatepatches.info index c6f9a9a42..7b1f0098a 100644 --- a/external/patches/generatepatches.info +++ b/external/patches/generatepatches.info @@ -1,7 +1,7 @@ If in case you want to generate a patch: 1) Modify file and save it as {filename}New.php, example, Connection.php and ConnectionNew.php 2) Execute Command: -diff -Naur Connection.php ConnectionNew.php > {project}_{name}_{filename}.patch. Example: react_socket_connection.patch +diff -Naur Connection.php ConnectionNew.php > {project}_{name}_{filename}.patch. Example: react/socket Connection.php -> react_socket_connection.patch 3) Move the patch file to external/patches folder 4) Modify Core Package.json file to install the new patch on next composer run. Example: diff --git a/external/patches/oauth2_server_bearertokenvalidator.patch b/external/patches/league_oauth2_server_bearertokenvalidator.patch similarity index 100% rename from external/patches/oauth2_server_bearertokenvalidator.patch rename to external/patches/league_oauth2_server_bearertokenvalidator.patch diff --git a/system/Base/Helpers.php b/system/Base/Helpers.php index 05b7140ef..1ac4bd396 100644 --- a/system/Base/Helpers.php +++ b/system/Base/Helpers.php @@ -465,4 +465,49 @@ 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 + //$task = unset - remove data of defined keys + function arraySqueeze($array, array $keys, $task = 'keep') + { + array_walk($array, function($value, $key) use (&$array, $keys, $task) { + if ($task === 'keep') { + if (!in_array($key, $keys)) { + unset($array[$key]); + } + } else if ($task === 'unset') { + if (in_array($key, $keys)) { + unset($array[$key]); + } + } + }); + + return $array; + } +} + +if (!function_exists('arrayFilterKeywords')) { + //$task = keep - Keep the data of defined keys, remove rest + //$task = unset - remove data of defined keys + function arrayFilterKeywords($array, array $keywords, $task = 'keep') + { + array_walk($array, function($value, $key) use (&$array, $keywords, $task) { + if ($task === 'keep') { + foreach ($keywords as $keyword) { + if (!str_contains($value, $keyword)) { + unset($array[$key]); + } + } + } else if ($task === 'unset') { + foreach ($keywords as $keyword) { + if (str_contains($value, $keyword)) { + unset($array[$key]); + } + } + } + }); + + return $array; + } } \ No newline at end of file diff --git a/system/Base/Providers/ModulesServiceProvider/Installer.php b/system/Base/Providers/ModulesServiceProvider/Installer.php index f355b1d11..3c85b72c4 100644 --- a/system/Base/Providers/ModulesServiceProvider/Installer.php +++ b/system/Base/Providers/ModulesServiceProvider/Installer.php @@ -4,6 +4,7 @@ use League\Flysystem\FilesystemException; use League\Flysystem\UnableToCopyFile; +use League\Flysystem\UnableToDeleteFile; use League\Flysystem\UnableToMoveFile; use League\Flysystem\UnableToReadFile; use League\Flysystem\UnableToRetrieveMetadata; @@ -206,6 +207,8 @@ protected function precheckExternalPackages($args) if (isset($module['hasPatch']) && $module['hasPatch'] === true) { if (!isset($module['composerJsonFile']['extra']['patches'][$module['name']])) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors( 'External packages should have package defined, but are missing from the composer json file for : ' . $module['name'], $preCheckQueueLogs @@ -220,14 +223,23 @@ protected function precheckExternalPackages($args) false ); + $patches['files'] = arrayFilterKeywords($patches['files'], ['.patch']); + if (count($patches['files']) === 0) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors( 'External package requires a patch which is missing from the repository : ' . $module['root_module']['repo'], $preCheckQueueLogs ); } + $modulePatchName = str_replace(['/','-'], ['_','_'], $module['name']); + $patches['files'] = arrayFilterKeywords($patches['files'], [$modulePatchName]); + if (count($patches['files']) !== count($module['composerJsonFile']['extra']['patches'][$module['name']])) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors( 'External package number of patches do not match what is defined in the composer json file for repository : ' . $module['root_module']['repo'], $preCheckQueueLogs @@ -246,6 +258,8 @@ protected function precheckExternalPackages($args) } if (in_array('false', $foundAll)) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors( 'External package all patches not found in the external/patches directory as per the composer json file for repository : ' . $module['root_module']['repo'], $preCheckQueueLogs @@ -259,6 +273,8 @@ protected function precheckExternalPackages($args) $this->localContent->copy($file, 'external/patches/' . $fileName); } } catch (FilesystemException | UnableToCopyFile $e) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors('Error copying file : ' . $fileName, $preCheckQueueLogs); } } @@ -268,6 +284,8 @@ protected function precheckExternalPackages($args) $this->localContent->write('external/' . $externalComposerFileName, $this->helper->encode($module['composerJsonFile'])); } catch (FilesystemException | UnableToWriteFile $e) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors( 'Error writing file external package composer file : ' . $externalComposerFileName, $preCheckQueueLogs @@ -292,13 +310,19 @@ protected function precheckExternalPackages($args) $this->queue['results']['first']['external'][explode('/', $module['name'])[1]]['precheck'] = 'pass'; $this->queue['results']['first']['external'][explode('/', $module['name'])[1]]['precheck_logs'] = $precheckLog; } catch (\throwable | UnableToReadFile $e) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors($e->getMessage(), $preCheckQueueLogs); } if ($app !== 0) { + $this->cleanup(['composer']); + return $this->preCheckHasErrors('Precheck for composer package failed : ' . $module['name'], $preCheckQueueLogs); } } else { + $this->cleanup(['composer']); + return $this->preCheckHasErrors('Incorrect external package type: ' . $module['name'], $preCheckQueueLogs); } @@ -729,6 +753,27 @@ protected function checkRegisteredDependencies($dependencies) return $found; } + protected function cleanup(array $what) + { + if (in_array('composer', $what)) { + $files = $this->basepackages->utils->scanDir('external', false); + + foreach ($files['files'] as $file) { + if ($file === 'external/composer.json' || $file === 'external/composer.install') { + continue; + } + + if (str_contains($file, '.json')) { + try { + $this->localContent->delete($file); + } catch (UnableToDeleteFile | FilesystemException | \throwable $e) { + throw $e; + } + } + } + } + } + // protected function getLatestRepositoryModulesData() // { // $repositories = getAllArr($this->repositories->getAll()); diff --git a/system/Base/Providers/ModulesServiceProvider/Manager.php b/system/Base/Providers/ModulesServiceProvider/Manager.php index a48c44dcc..d75811f9d 100644 --- a/system/Base/Providers/ModulesServiceProvider/Manager.php +++ b/system/Base/Providers/ModulesServiceProvider/Manager.php @@ -516,7 +516,8 @@ protected function getRemoteModules() $names = explode('-', $module['name']); - if ($names[0] === 'core') { + if ($names && count($names) === 1 && $names[0] === 'core') { + $this->remoteModules['packages'] = []; $this->remoteModules['packages'] = [$module]; return true; diff --git a/system/Base/Providers/ModulesServiceProvider/Queues.php b/system/Base/Providers/ModulesServiceProvider/Queues.php index 5bfa7f4a4..6736b5649 100644 --- a/system/Base/Providers/ModulesServiceProvider/Queues.php +++ b/system/Base/Providers/ModulesServiceProvider/Queues.php @@ -233,6 +233,7 @@ public function analyseQueue(&$queue = null, $reAnalyse = false) $this->queueTasks = []; $this->results = []; + $queue['tasks']['analysed'] = [];//Reset Analysed foreach ($queue['tasks'] as $taskName => $tasks) { if (isset($queue['tasks']['analysed']) && @@ -244,6 +245,7 @@ public function analyseQueue(&$queue = null, $reAnalyse = false) if (!isset($this->queueTasks[$taskName])) { $this->queueTasks[$taskName] = []; } + if (!isset($this->results[$taskName])) { $this->results[$taskName] = []; } @@ -412,9 +414,12 @@ public function analyseQueue(&$queue = null, $reAnalyse = false) $queue['results'] = $this->results; //Rearrange tasks to make sure we install externals first and then update core and then execute rest of the tasks. - if (isset($this->queueTasks['first'])) { + if (isset($this->queueTasks['first']['packages']) && count($this->queueTasks['first']['packages']) > 0) { $this->queueTasks = array_merge(array_flip(['first', 'update', 'install', 'uninstall', 'remove']), $this->queueTasks); - $this->queueTasks['first'] = array_merge(array_flip(['external', 'packages']), $this->queueTasks['first']); + + if (isset($this->queueTasks['first']['external']) && count($this->queueTasks['first']['external']) > 0) { + $this->queueTasks['first'] = array_merge(array_flip(['external', 'packages']), $this->queueTasks['first']); + } } $queue['tasks']['analysed'] = $this->queueTasks; @@ -539,7 +544,7 @@ protected function checkComposerAndAddToQueue($composerPackages, $module) if (isset($composerPackages['composer']['require']) && count($composerPackages['composer']['require']) > 0) { $composerRequire = $composerPackages['composer']['require']; - } else if (isset($composerPackages['require']) && count($composerPackages['require']) === 0) { + } else if (isset($composerPackages['require']) && count($composerPackages['require']) > 0) { $composerRequire = $composerPackages['require']; } @@ -564,18 +569,16 @@ protected function checkComposerAndAddToQueue($composerPackages, $module) $installExternal = true; } - if (isset($composerPackages['config'])) { - if (isset($composerPackages['config']['allow-plugins'][$composerPackage])) { - $composerJsonFile['config']['allow-plugins'][$composerPackage] = $composerPackages['config']['allow-plugins'][$composerPackage]; - $hasConfigChange = true; - } + if (isset($composerPackages['config']['allow-plugins'][$composerPackage]) && + !isset($composerJsonFile['config']['allow-plugins'][$composerPackage]) + ) { + $composerJsonFile['config']['allow-plugins'][$composerPackage] = $composerPackages['config']['allow-plugins'][$composerPackage]; + $hasConfigChange = true; } - if (isset($composerPackages['extra'])) { - 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; - } + 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; } if ($installExternal || $hasConfigChange || $hasPatch) { @@ -636,6 +639,22 @@ protected function addToQueueTasksAndResults($taskName, $moduleType, $module, $v $this->queueTasks[$taskName][$moduleType][$module['id']]['hasPatch'] = true; } if (isset($module['root_module'])) { + $module['root_module'] = + arraySqueeze( + $module['root_module'], + ['id', 'name', 'display_name', 'module_type', 'repo', 'repo_details'] + ); + $module['root_module']['repo_details']['details'] = + arraySqueeze( + $module['root_module']['repo_details']['details'], + ['name', 'internal', 'private'] + ); + $module['root_module']['repo_details']['latestRelease'] = + arraySqueeze( + $module['root_module']['repo_details']['latestRelease'], + ['name', 'tag_name', 'published_at', 'zipball_url'] + ); + $this->queueTasks[$taskName][$moduleType][$module['id']]['root_module'] = $module['root_module']; } }