Skip to content
Snippets Groups Projects
Commit a25c064c authored by Duro Arezina's avatar Duro Arezina Committed by Duro Arezina
Browse files

Issue #3255883 by devad: Packages list improvements

parent 7ff9869c
No related branches found
No related tags found
No related merge requests found
......@@ -115,7 +115,7 @@ class PackageController implements ContainerInjectionInterface {
];
$missing = 0;
foreach ($this->packageManager->getPackages() as $package_name => $package) {
if ($package['installed'] === FALSE) {
if ($package['status'] == 'Missing') {
$missing++;
}
......@@ -150,7 +150,7 @@ class PackageController implements ContainerInjectionInterface {
'@read_more' => Link::fromTextAndUrl($this->t('Read more'), Url::fromUri($guide_link))->toString(),
]);
}
elseif (!$package['installed']) {
elseif ($package['status'] == 'Missing') {
$package['description'] = $this->t('@download the library and place it in @path', [
'@download' => Link::fromTextAndUrl($this->t('Download'), Url::fromUri($package['download_url']))->toString(),
'@path' => $package['path'],
......@@ -185,8 +185,41 @@ class PackageController implements ContainerInjectionInterface {
$required_by = $info[$package['provider']]['name'];
}
switch ($package['status']) {
case 'Installed':
$status = $this->t('Installed');
break;
case 'Missing':
$status = $this->t('Missing');
break;
case 'Not installed':
$status = $this->t('Not installed');
break;
case 'Not supported':
$status = $this->t('Not supported');
break;
case 'Overridden':
$status = $this->t('Overridden');
break;
case 'Unknown type':
$status = $this->t('Unknown type');
break;
case 'Inactive':
$status = $this->t('Inactive');
break;
default:
$status = $this->t('Unknown');
}
$build['packages']['#rows'][$package_name] = [
'class' => $package['installed'] ? [] : ['error'],
'class' => $package['status'] == 'Installed' ? [] : ['error'],
'data' => [
'package' => [
'data' => $package_column,
......@@ -195,7 +228,7 @@ class PackageController implements ContainerInjectionInterface {
'resource' => $package['resource'],
'version' => $package['version'],
'required_by' => $required_by,
'status' => $package['installed'] ? $this->t('Installed') : $this->t('Missing'),
'status' => $status,
],
];
}
......@@ -222,7 +255,7 @@ class PackageController implements ContainerInjectionInterface {
*/
public function download() {
$packages = array_filter($this->packageManager->getPackages(), function ($package) {
return empty($package['installed']);
return $package['status'] == 'Missing';
});
if (!empty($packages)) {
$logger = \Drupal::logger('ludwig');
......
......@@ -21,7 +21,7 @@ class LudwigServiceProvider extends ServiceProviderBase {
$package_manager = new PackageManager($root);
$namespaces = $container->getParameter('container.namespaces');
foreach ($package_manager->getPackages() as $package_name => $package) {
if ($package['installed']) {
if ($package['status'] == 'Installed') {
if ($package['resource'] == 'psr-4' || $package['resource'] == 'psr-0') {
$namespace = $package['namespace'];
// If this namespace exists already, convert it's path(s) to
......@@ -59,11 +59,6 @@ class LudwigServiceProvider extends ServiceProviderBase {
$namespaces[$namespace] = $return_paths;
}
}
// @todo Add support for 'classmap' autoload type.
// @todo Add support for 'files' autoload type.
// @todo Add support for 'exclude-from-classmap' autoload property.
// @todo Add support for 'target-dir' autoload property.
// @todo Add support for 'legacy' libraries (depricated type).
}
}
$container->setParameter('container.namespaces', $namespaces);
......
......@@ -55,21 +55,12 @@ class PackageManager implements PackageManagerInterface {
$config += [
'require' => [],
];
// Let's check if this module has .module file and
// load its content if it has. We will need it later.
if (is_file($this->root . '/' . $extension_path . '/' . $extension_name . '.module')) {
$module_file = file_get_contents($this->root . '/' . $extension_path . '/' . $extension_name . '.module');
$has_ludwig_service = strpos($module_file, 'ludwig.require_once') !== FALSE;
}
foreach ($config['require'] as $package_name => $package_data) {
// Multiple extensions can require the same package.
// We need the unique package name in such cases.
$package_name_unique = $extension_name . '_' . $package_name;
$package_path = $extension_path . '/lib/' . str_replace('/', '-', $package_name) . '/' . $package_data['version'];
$disable_warnings = isset($package_data['disable_warnings']) ? $package_data['disable_warnings'] : FALSE;
// Disable the 'classmap' or 'files' warning if this
// module's .module file is calling ludwig.require_once
// service with this package name as an argument.
if (!empty($has_ludwig_service) && !empty($module_file) && ((strpos($module_file, "requireOnce('".$package_name) !== FALSE) || (strpos($module_file, "requireOnce( '".$package_name) !== FALSE) || (strpos($module_file, 'requireOnce("'.$package_name) !== FALSE) || (strpos($module_file, 'requireOnce( "'.$package_name) !== FALSE))) {
$disable_warnings = TRUE;
}
$package = $this->jsonRead($this->root . '/' . $package_path . '/composer.json');
$description = !empty($package['description']) ? $package['description'] : '';
$homepage = !empty($package['homepage']) ? $package['homepage'] : '';
......@@ -86,24 +77,48 @@ class PackageManager implements PackageManagerInterface {
'path' => $package_path,
];
if (empty($package)) {
// Add new package. This one needs a download.
// Missing package. This one needs a download.
$package_append = [
'namespace' => '',
'paths' => [],
'installed' => FALSE,
'status' => 'Missing',
'resource' => '',
];
$packages[$package_name] = array_merge($package_base, $package_append);
$packages[$package_name_unique] = array_merge($package_base, $package_append);
continue;
}
if (!empty($package['autoload'])) {
$resources = array_keys($package['autoload']);
// Iterate through all autoload types.
// Iterate through all autoload types (resources).
foreach ($resources as $resource) {
// Making the package name unique for multi-resource packages.
$package_name_resource_unique = $package_name_unique . '_' . $resource;
if (!empty($package['autoload'][$resource])) {
$status = '';
if ($resource == 'files' || $resource == 'classmap' || $resource == 'exclude-from-classmap' || $resource == 'target-dir') {
$autoload = $package['autoload'];
$package_namespaces = [$resource];
if (empty($package_base['disable_warnings'])) {
if ($resource == 'classmap' || $resource == 'files') {
// Additional integration inside .module file is needed.
$status = 'Not installed';
// The .module file integration check.
if (is_file($this->root . '/' . $extension_path . '/' . $extension_name . '.module')) {
$module_file = file_get_contents($this->root . '/' . $extension_path . '/' . $extension_name . '.module');
}
// Mark back this package as 'Installed' if this
// module's .module file is calling ludwig.require_once
// service with this package name as an argument.
if (!empty($module_file) && (strpos($module_file, 'ludwig.require_once') !== FALSE) && ((strpos($module_file, "requireOnce('" . $package_name) !== FALSE) || (strpos($module_file, "requireOnce( '" . $package_name) !== FALSE) || (strpos($module_file, 'requireOnce("' . $package_name) !== FALSE) || (strpos($module_file, 'requireOnce( "' . $package_name) !== FALSE))) {
$status = 'Installed';
$package_base['disable_warnings'] = TRUE;
}
}
else {
// 'exclude-from-classmap' and 'target-dir' types.
$status = 'Not supported';
}
}
}
elseif ($resource == 'psr-4' || $resource == 'psr-0') {
$autoload = $package['autoload'][$resource];
......@@ -114,13 +129,14 @@ class PackageManager implements PackageManagerInterface {
$package_append = [
'namespace' => '',
'paths' => [],
'installed' => TRUE,
'status' => 'Unknown type',
'resource' => 'unknown',
];
$packages[$package_name] = array_merge($package_base, $package_append);
$packages[$package_name_resource_unique] = array_merge($package_base, $package_append);
continue;
}
// Iterate through all the resources inside single autoload type.
$status = !empty($status) ? $status : 'Installed';
// Iterate through all the records inside single autoload type.
foreach ($package_namespaces as $namespace) {
$paths_raw = $autoload[$namespace];
// Support for both single path (string) and multiple
......@@ -147,29 +163,14 @@ class PackageManager implements PackageManagerInterface {
$paths[$key] .= str_replace('\\', '/', $namespace);
}
}
// Combine $package_name an $paths into uniuqe $name_path value.
$name_path = $package_name . '_' . implode('-', $paths);
// Two versions of the same package are not possible.
// If multiple providers require the same package
// we keep the highest required version only, since it has
// the best probability to work for all providers, and
// it is the most secure.
if (!isset($packages[$name_path]) || $packages[$name_path]['version'] < $package_data['version']) {
// If the current item is going to be replaced with the new
// one, unset the current item first to keep all packages
// nicely sorted by provider name inside the 'Packages' table.
if (isset($packages[$name_path])) {
unset($packages[$name_path]);
}
// Add new package.
$package_append = [
'namespace' => $namespace,
'paths' => $paths,
'installed' => TRUE,
'resource' => $resource,
];
$packages[$name_path] = array_merge($package_base, $package_append);
}
// Add new package.
$package_append = [
'namespace' => $namespace,
'paths' => $paths,
'status' => $status,
'resource' => $resource,
];
$packages[$package_name_resource_unique] = array_merge($package_base, $package_append);
}
}
}
......@@ -181,25 +182,43 @@ class PackageManager implements PackageManagerInterface {
$package_append = [
'namespace' => '',
'paths' => [],
'installed' => TRUE,
'status' => 'Not supported',
'resource' => 'legacy',
];
$packages[$package_name] = array_merge($package_base, $package_append);
$packages[$package_name_unique] = array_merge($package_base, $package_append);
}
else {
// The library without the autoload section.
$package_append = [
'namespace' => '',
'paths' => [],
'installed' => TRUE,
'status' => 'Inactive',
'resource' => 'inactive',
];
$packages[$package_name] = array_merge($package_base, $package_append);
$packages[$package_name_unique] = array_merge($package_base, $package_append);
}
}
}
}
// Two versions of the same package are not possible.
// If multiple providers require the same package
// we keep the highest required version only, since it has
// the best probability to work for all providers, and
// it is the most secure. And we mark all lower package
// versions as 'Overriden'.
$loop1_packages = $packages;
$loop2_packages = $packages;
foreach ($loop1_packages as $loop1_name => $loop1_package) {
foreach ($loop2_packages as $loop2_name => $loop2_package) {
// Let's strip all non-numeric characters from the package
// versions in order to compare them successfully.
if (($loop2_package['name'] == $loop1_package['name']) && ($loop2_name != $loop1_name) && (preg_replace("/[^0-9.]/", "", $loop2_package['version']) < preg_replace("/[^0-9.]/", "", $loop1_package['version']))) {
$packages[$loop2_name]['status'] = 'Overridden';
}
}
}
return $packages;
}
......
......@@ -262,7 +262,7 @@ namespace Drupal\Tests\ludwig\Unit {
*/
public function testGetPackages() {
$expected_packages = [
'symfony/css-selector' => [
'lightning_symfony/css-selector' => [
'name' => 'symfony/css-selector',
'version' => 'v3.2.8',
'description' => '',
......@@ -274,10 +274,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'profiles/lightning/lib/symfony-css-selector/v3.2.8',
'namespace' => '',
'paths' => [],
'installed' => FALSE,
'status' => 'Missing',
'resource' => '',
],
'symfony/intl' => [
'test1_symfony/intl' => [
'name' => 'symfony/intl',
'version' => 'v3.2.8',
'description' => '',
......@@ -289,10 +289,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/test1/lib/symfony-intl/v3.2.8',
'namespace' => '',
'paths' => [],
'installed' => FALSE,
'status' => 'Missing',
'resource' => '',
],
'symfony/config_src' => [
'test2_symfony/config_psr-4' => [
'name' => 'symfony/config',
'version' => 'v3.2.8',
'description' => 'Symfony Config Component',
......@@ -304,10 +304,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'sites/all/modules/test2/lib/symfony-config/v3.2.8',
'namespace' => 'Symfony\\Component\\Config',
'paths' => ['src'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'psr-4',
],
'html2text/html2text_src-test' => [
'test3a_html2text/html2text_psr-4' => [
'name' => 'html2text/html2text',
'version' => 'v4.3.1',
'description' => 'Converts HTML to formatted plain text',
......@@ -319,10 +319,40 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/test3a/lib/html2text-html2text/v4.3.1',
'namespace' => 'Html2Text',
'paths' => ['src', 'test'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'psr-4',
],
'dompdf/dompdf_src' => [
'test3b_html2text/html2text_psr-4' => [
'name' => 'html2text/html2text',
'version' => 'v4.0.1',
'description' => 'Converts HTML to formatted plain text',
'homepage' => '',
'provider' => 'test3b',
'provider_path' => 'modules/test3b',
'download_url' => 'https://github.com/mtibben/html2text/archive/4.0.1.zip',
'disable_warnings' => FALSE,
'path' => 'modules/test3b/lib/html2text-html2text/v4.0.1',
'namespace' => 'Html2Text',
'paths' => ['src', 'test'],
'status' => 'Overridden',
'resource' => 'psr-4',
],
'test3c_html2text/html2text_psr-4' => [
'name' => 'html2text/html2text',
'version' => 'v4.3.1',
'description' => 'Converts HTML to formatted plain text',
'homepage' => '',
'provider' => 'test3c',
'provider_path' => 'modules/test3c',
'download_url' => 'https://github.com/mtibben/html2text/archive/4.3.1.zip',
'disable_warnings' => FALSE,
'path' => 'modules/test3c/lib/html2text-html2text/v4.3.1',
'namespace' => 'Html2Text',
'paths' => ['src', 'test'],
'status' => 'Installed',
'resource' => 'psr-4',
],
'entity_print_dompdf/dompdf_psr-4' => [
'name' => 'dompdf/dompdf',
'version' => 'v0.8.6',
'description' => 'DOMPDF is a CSS 2.1 compliant HTML to PDF converter',
......@@ -334,10 +364,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/entity_print/lib/dompdf-dompdf/v0.8.6',
'namespace' => 'Dompdf',
'paths' => ['src'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'psr-4',
],
'dompdf/dompdf_lib' => [
'entity_print_dompdf/dompdf_classmap' => [
'name' => 'dompdf/dompdf',
'version' => 'v0.8.6',
'description' => 'DOMPDF is a CSS 2.1 compliant HTML to PDF converter',
......@@ -349,10 +379,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/entity_print/lib/dompdf-dompdf/v0.8.6',
'namespace' => 'classmap',
'paths' => ['lib'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'classmap',
],
'querypath/QueryPath_src/QueryPath' => [
'feeds_ex_querypath/QueryPath_psr-0' => [
'name' => 'querypath/QueryPath',
'version' => 'v3.0.5',
'description' => 'HTML/XML querying (CSS 4 or XPath) and processing (like jQuery)',
......@@ -364,10 +394,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/feeds_ex/lib/querypath-QueryPath/v3.0.5',
'namespace' => 'QueryPath',
'paths' => ['src/QueryPath'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'psr-0',
],
'querypath/QueryPath_src/qp_functions.php' => [
'feeds_ex_querypath/QueryPath_files' => [
'name' => 'querypath/QueryPath',
'version' => 'v3.0.5',
'description' => 'HTML/XML querying (CSS 4 or XPath) and processing (like jQuery)',
......@@ -379,10 +409,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/feeds_ex/lib/querypath-QueryPath/v3.0.5',
'namespace' => 'files',
'paths' => ['src/qp_functions.php'],
'installed' => TRUE,
'status' => 'Not installed',
'resource' => 'files',
],
'maxmind/web-service-common_src/Exception' => [
'geoip_maxmind/web-service-common_psr-4' => [
'name' => 'maxmind/web-service-common',
'version' => 'v0.8.0',
'description' => 'Internal MaxMind Web Service API',
......@@ -394,10 +424,10 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/geoip/lib/maxmind-web-service-common/v0.8.0',
'namespace' => 'MaxMind\\Exception',
'paths' => ['src/Exception'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'psr-4',
],
'maxmind/web-service-common_src/WebService' => [
'geoip_maxmind/web-service-common_psr-4' => [
'name' => 'maxmind/web-service-common',
'version' => 'v0.8.0',
'description' => 'Internal MaxMind Web Service API',
......@@ -409,7 +439,7 @@ namespace Drupal\Tests\ludwig\Unit {
'path' => 'modules/geoip/lib/maxmind-web-service-common/v0.8.0',
'namespace' => 'MaxMind\\WebService',
'paths' => ['src/WebService'],
'installed' => TRUE,
'status' => 'Installed',
'resource' => 'psr-4',
],
];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment