From 73f8b99ec74d3ebbb196540a6115584e72f9a640 Mon Sep 17 00:00:00 2001
From: Ryan Jacobs <rjacobs@422459.no-reply.drupal.org>
Date: Fri, 24 Feb 2017 17:18:09 -0600
Subject: [PATCH] Issue #2774313 by rjacobs, tstoeckler: More gracefully deal
 with library-specific errors at runtime.

Squashed commit of the following:

commit cbd3b2f37baebd02b33648e92c31e59376d80e22
Author: Ryan Jacobs <rjacobs@422459.no-reply.drupal.org>
Date:   Thu Feb 2 21:47:51 2017 -0600

    Issue #2774313: Add exception handling to libraries_library_info_build().

commit 6f4f6a5f85d0bee12d474ab147fc2c9d7d1e49a1
Author: Ryan Jacobs <rjacobs@422459.no-reply.drupal.org>
Date:   Mon Jan 30 22:30:53 2017 -0600

    Issue #2774313: Skip local version detection for uninstalled local library.
---
 libraries.module                              | 33 ++++++++++++++++---
 .../InvalidLibraryDependencyException.php     |  3 +-
 .../LibraryDefinitionNotFoundException.php    |  3 +-
 .../LibraryNotInstalledException.php          |  3 +-
 .../LibraryTypeNotFoundException.php          |  3 +-
 .../UnknownLibraryVersionException.php        |  3 +-
 .../Remote/RemoteLibraryTrait.php             |  2 +-
 src/ExternalLibrary/Type/LibraryTypeBase.php  |  7 ++--
 .../Utility/LibraryAccessorInterface.php      | 18 ++++++++++
 .../Utility/LibraryIdAccessorInterface.php    | 18 ++++++++++
 10 files changed, 79 insertions(+), 14 deletions(-)
 create mode 100644 src/ExternalLibrary/Utility/LibraryAccessorInterface.php
 create mode 100644 src/ExternalLibrary/Utility/LibraryIdAccessorInterface.php

diff --git a/libraries.module b/libraries.module
index 709e562..3006c34 100644
--- a/libraries.module
+++ b/libraries.module
@@ -8,23 +8,46 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\ModuleHandler;
 use Drupal\libraries\ExternalLibrary\Asset\AttachableAssetLibraryRegistrationInterface;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorInterface;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryIdAccessorInterface;
 use Symfony\Component\Yaml\Parser;
 
 /**
  * Implements hook_library_info_build().
+ *
+ * Register external asset libraries with Drupal core's library APIs.
  */
 function libraries_library_info_build() {
   /** @var \Drupal\libraries\ExternalLibrary\LibraryManagerInterface $library_manager */
   $library_manager = \Drupal::service('libraries.manager');
-
   $attachable_libraries = [];
+  $libraries_with_errors = [];
   foreach ($library_manager->getRequiredLibraryIds() as $external_library_id) {
-    $external_library = $library_manager->getLibrary($external_library_id);
-    $library_type = $external_library->getType();
-    if ($library_type instanceof AttachableAssetLibraryRegistrationInterface) {
-      $attachable_libraries += $library_type->getAttachableAssetLibraries($external_library, $library_manager);
+    try {
+      $external_library = $library_manager->getLibrary($external_library_id);
+      $library_type = $external_library->getType();
+      if ($library_type instanceof AttachableAssetLibraryRegistrationInterface) {
+        $attachable_libraries += $library_type->getAttachableAssetLibraries($external_library, $library_manager);
+      }
+    }
+    catch (\Exception $e) {
+      // Library-specific exceptions should not be allowed to kill the rest of
+      // the build process, but should be logged.
+      if ($e instanceof LibraryIdAccessorInterface || $e instanceof LibraryAccessorInterface) {
+        $libraries_with_errors[] = $external_library_id;
+        watchdog_exception('libraries', $e);
+      }
+      else {
+        // Re-throw exceptions that are not library-specific.
+        throw $e;
+      }
     }
   }
+  // If we had library specific errors also log an informative message to
+  // tell admins that detection will not be run again without a cache clear.
+  if ($libraries_with_errors) {
+    \Drupal::logger('libraries')->error('The following external libraries could not successfully be registered with Drupal core: @libs. See earlier log entries for more details. Once these issues are addressed please be sure to clear your Drupal library cache to ensure external library detection is run again.', ['@libs' => implode(',', $libraries_with_errors)]);
+  }
   return $attachable_libraries;
 }
 
diff --git a/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php b/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php
index 9b741e1..7ab3eeb 100644
--- a/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php
+++ b/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php
@@ -5,11 +5,12 @@ namespace Drupal\libraries\ExternalLibrary\Exception;
 use Drupal\libraries\ExternalLibrary\Utility\DependencyAccessorTrait;
 use Drupal\libraries\ExternalLibrary\LibraryInterface;
 use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorTrait;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorInterface;
 
 /**
  * Provides an exception for an invalid library exception.
  */
-class InvalidLibraryDependencyException extends \UnexpectedValueException {
+class InvalidLibraryDependencyException extends \UnexpectedValueException implements LibraryAccessorInterface {
 
   use LibraryAccessorTrait;
   use DependencyAccessorTrait;
diff --git a/src/ExternalLibrary/Exception/LibraryDefinitionNotFoundException.php b/src/ExternalLibrary/Exception/LibraryDefinitionNotFoundException.php
index 0e5e338..c274302 100644
--- a/src/ExternalLibrary/Exception/LibraryDefinitionNotFoundException.php
+++ b/src/ExternalLibrary/Exception/LibraryDefinitionNotFoundException.php
@@ -3,11 +3,12 @@
 namespace Drupal\libraries\ExternalLibrary\Exception;
 
 use Drupal\libraries\ExternalLibrary\Utility\LibraryIdAccessorTrait;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryIdAccessorInterface;
 
 /**
  * Provides an exception for a library definition that cannot be found.
  */
-class LibraryDefinitionNotFoundException extends \RuntimeException {
+class LibraryDefinitionNotFoundException extends \RuntimeException implements LibraryIdAccessorInterface {
 
   use LibraryIdAccessorTrait;
 
diff --git a/src/ExternalLibrary/Exception/LibraryNotInstalledException.php b/src/ExternalLibrary/Exception/LibraryNotInstalledException.php
index c65821f..ed48a62 100644
--- a/src/ExternalLibrary/Exception/LibraryNotInstalledException.php
+++ b/src/ExternalLibrary/Exception/LibraryNotInstalledException.php
@@ -4,11 +4,12 @@ namespace Drupal\libraries\ExternalLibrary\Exception;
 
 use Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface;
 use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorTrait;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorInterface;
 
 /**
  * Provides an exception for a library that is not installed.
  */
-class LibraryNotInstalledException extends \RuntimeException {
+class LibraryNotInstalledException extends \RuntimeException implements LibraryAccessorInterface {
 
   use LibraryAccessorTrait;
 
diff --git a/src/ExternalLibrary/Exception/LibraryTypeNotFoundException.php b/src/ExternalLibrary/Exception/LibraryTypeNotFoundException.php
index 7531bf3..b5655bb 100644
--- a/src/ExternalLibrary/Exception/LibraryTypeNotFoundException.php
+++ b/src/ExternalLibrary/Exception/LibraryTypeNotFoundException.php
@@ -3,11 +3,12 @@
 namespace Drupal\libraries\ExternalLibrary\Exception;
 
 use Drupal\libraries\ExternalLibrary\Utility\LibraryIdAccessorTrait;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryIdAccessorInterface;
 
 /**
  * Provides an exception for a library definition without a type declaration.
  */
-class LibraryTypeNotFoundException extends \RuntimeException {
+class LibraryTypeNotFoundException extends \RuntimeException implements LibraryAccessorInterface {
 
   use LibraryIdAccessorTrait;
 
diff --git a/src/ExternalLibrary/Exception/UnknownLibraryVersionException.php b/src/ExternalLibrary/Exception/UnknownLibraryVersionException.php
index 72bd153..4afe059 100644
--- a/src/ExternalLibrary/Exception/UnknownLibraryVersionException.php
+++ b/src/ExternalLibrary/Exception/UnknownLibraryVersionException.php
@@ -3,12 +3,13 @@
 namespace Drupal\libraries\ExternalLibrary\Exception;
 
 use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorTrait;
+use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorInterface;
 use Drupal\libraries\ExternalLibrary\Version\VersionedLibraryInterface;
 
 /**
  * Provides an exception for libraries whose version has not been detected.
  */
-class UnknownLibraryVersionException extends \RuntimeException {
+class UnknownLibraryVersionException extends \RuntimeException implements LibraryAccessorInterface {
 
   use LibraryAccessorTrait;
 
diff --git a/src/ExternalLibrary/Remote/RemoteLibraryTrait.php b/src/ExternalLibrary/Remote/RemoteLibraryTrait.php
index 0fb82c0..d55f3c2 100644
--- a/src/ExternalLibrary/Remote/RemoteLibraryTrait.php
+++ b/src/ExternalLibrary/Remote/RemoteLibraryTrait.php
@@ -26,7 +26,7 @@ trait RemoteLibraryTrait {
    * @see \Drupal\libraries\ExternalLibrary\Remote\RemoteLibraryInterface::hasRemoteUrl()
    */
   public function hasRemoteUrl() {
-    return isset($this->remoteUrl);
+    return !empty($this->remoteUrl);
   }
 
   /**
diff --git a/src/ExternalLibrary/Type/LibraryTypeBase.php b/src/ExternalLibrary/Type/LibraryTypeBase.php
index 08cd61a..9774e97 100644
--- a/src/ExternalLibrary/Type/LibraryTypeBase.php
+++ b/src/ExternalLibrary/Type/LibraryTypeBase.php
@@ -74,9 +74,10 @@ abstract class LibraryTypeBase implements
       if (!$library->isInstalled()) {
         $this->locatorFactory->createInstance('global')->locate($library);
       }
-    }
-    if ($library instanceof VersionedLibraryInterface) {
-      $library->getVersionDetector($this->detectorFactory)->detectVersion($library);
+      // Also fetch version information.
+      if ($library->isInstalled() && $library instanceof VersionedLibraryInterface) {
+        $library->getVersionDetector($this->detectorFactory)->detectVersion($library);
+      }
     }
   }
 
diff --git a/src/ExternalLibrary/Utility/LibraryAccessorInterface.php b/src/ExternalLibrary/Utility/LibraryAccessorInterface.php
new file mode 100644
index 0000000..72b0093
--- /dev/null
+++ b/src/ExternalLibrary/Utility/LibraryAccessorInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\libraries\ExternalLibrary\Utility;
+
+/**
+ * Provides an interface for classes giving access to a library.
+ */
+interface LibraryAccessorInterface {
+
+  /**
+   * Returns the library.
+   *
+   * @return \Drupal\libraries\ExternalLibrary\LibraryInterface
+   *   The library.
+   */
+  public function getLibrary();
+
+}
diff --git a/src/ExternalLibrary/Utility/LibraryIdAccessorInterface.php b/src/ExternalLibrary/Utility/LibraryIdAccessorInterface.php
new file mode 100644
index 0000000..98928e9
--- /dev/null
+++ b/src/ExternalLibrary/Utility/LibraryIdAccessorInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\libraries\ExternalLibrary\Utility;
+
+/**
+ * Provides an interface for classes giving access to a library ID.
+ */
+interface LibraryAccessorIdInterface {
+
+  /**
+   * Returns the ID of the library.
+   *
+   * @return string
+   *   The library ID.
+   */
+  public function getLibraryId();
+
+}
-- 
GitLab