From 07f9700179da74b056485375652c3b26d6fbce0d Mon Sep 17 00:00:00 2001
From: Frederic Guillot <fred@kanboard.net>
Date: Sun, 8 Jan 2017 17:02:31 -0500
Subject: Offer the possibility to define version compatibility from plugins

---
 app/Core/Plugin/Base.php                     | 13 ++++++++
 app/Core/Plugin/Directory.php                | 13 +-------
 app/Core/Plugin/Loader.php                   | 48 +++++++++++++++++++++-------
 app/Core/Plugin/PluginException.php          | 15 +++++++++
 app/Core/Plugin/PluginInstallerException.php |  4 +--
 app/Core/Plugin/Version.php                  | 38 ++++++++++++++++++++++
 6 files changed, 104 insertions(+), 27 deletions(-)
 create mode 100644 app/Core/Plugin/PluginException.php
 create mode 100644 app/Core/Plugin/Version.php

(limited to 'app/Core/Plugin')

diff --git a/app/Core/Plugin/Base.php b/app/Core/Plugin/Base.php
index 9d8167a9..e0b5954a 100644
--- a/app/Core/Plugin/Base.php
+++ b/app/Core/Plugin/Base.php
@@ -131,4 +131,17 @@ abstract class Base extends \Kanboard\Core\Base
     {
         return '';
     }
+
+    /**
+     * Get application compatibility version
+     *
+     * Examples: >=1.0.36, 1.0.37, APP_VERSION
+     *
+     * @access public
+     * @return string
+     */
+    public function getCompatibleVersion()
+    {
+        return APP_VERSION;
+    }
 }
diff --git a/app/Core/Plugin/Directory.php b/app/Core/Plugin/Directory.php
index 27c3514e..dc32e655 100644
--- a/app/Core/Plugin/Directory.php
+++ b/app/Core/Plugin/Directory.php
@@ -36,18 +36,7 @@ class Directory extends BaseCore
      */
     public function isCompatible(array $plugin, $appVersion = APP_VERSION)
     {
-        if (strpos($appVersion, 'master') !== false) {
-            return true;
-        }
-
-        foreach (array('>=', '>') as $operator) {
-            if (strpos($plugin['compatible_version'], $operator) === 0) {
-                $pluginVersion = substr($plugin['compatible_version'], strlen($operator));
-                return version_compare($appVersion, $pluginVersion, $operator);
-            }
-        }
-
-        return $plugin['compatible_version'] === $appVersion;
+        return Version::isCompatible($plugin['compatible_version'], $appVersion);
     }
 
     /**
diff --git a/app/Core/Plugin/Loader.php b/app/Core/Plugin/Loader.php
index f2f6add7..38f41d39 100644
--- a/app/Core/Plugin/Loader.php
+++ b/app/Core/Plugin/Loader.php
@@ -4,6 +4,7 @@ namespace Kanboard\Core\Plugin;
 
 use Composer\Autoload\ClassLoader;
 use DirectoryIterator;
+use Exception;
 use LogicException;
 use Kanboard\Core\Tool;
 
@@ -22,6 +23,7 @@ class Loader extends \Kanboard\Core\Base
      * @var array
      */
     protected $plugins = array();
+    protected $incompatiblePlugins = array();
 
     /**
      * Get list of loaded plugins
@@ -34,6 +36,17 @@ class Loader extends \Kanboard\Core\Base
         return $this->plugins;
     }
 
+    /**
+     * Get list of not compatible plugins
+     *
+     * @access public
+     * @return Base[]
+     */
+    public function getIncompatiblePlugins()
+    {
+        return $this->incompatiblePlugins;
+    }
+
     /**
      * Scan plugin folder and load plugins
      *
@@ -51,8 +64,7 @@ class Loader extends \Kanboard\Core\Base
             foreach ($dir as $fileInfo) {
                 if ($fileInfo->isDir() && substr($fileInfo->getFilename(), 0, 1) !== '.') {
                     $pluginName = $fileInfo->getFilename();
-                    $this->loadSchema($pluginName);
-                    $this->initializePlugin($pluginName, $this->loadPlugin($pluginName));
+                    $this->initializePlugin($pluginName);
                 }
             }
         }
@@ -85,7 +97,7 @@ class Loader extends \Kanboard\Core\Base
         $className = '\Kanboard\Plugin\\'.$pluginName.'\\Plugin';
 
         if (! class_exists($className)) {
-            throw new LogicException('Unable to load this plugin class '.$className);
+            throw new LogicException('Unable to load this plugin class: '.$className);
         }
 
         return new $className($this->container);
@@ -96,18 +108,30 @@ class Loader extends \Kanboard\Core\Base
      *
      * @access public
      * @param  string $pluginName
-     * @param  Base   $plugin
      */
-    public function initializePlugin($pluginName, Base $plugin)
+    public function initializePlugin($pluginName)
     {
-        if (method_exists($plugin, 'onStartup')) {
-            $this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
-        }
+        try {
+            $plugin = $this->loadPlugin($pluginName);
 
-        Tool::buildDIC($this->container, $plugin->getClasses());
-        Tool::buildDICHelpers($this->container, $plugin->getHelpers());
+            if (Version::isCompatible($plugin->getCompatibleVersion(), APP_VERSION)) {
+                $this->loadSchema($pluginName);
+
+                if (method_exists($plugin, 'onStartup')) {
+                    $this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
+                }
 
-        $plugin->initialize();
-        $this->plugins[$pluginName] = $plugin;
+                Tool::buildDIC($this->container, $plugin->getClasses());
+                Tool::buildDICHelpers($this->container, $plugin->getHelpers());
+
+                $plugin->initialize();
+                $this->plugins[$pluginName] = $plugin;
+            } else {
+                $this->incompatiblePlugins[$pluginName] = $plugin;
+                $this->logger->error($pluginName.' is not compatible with this version');
+            }
+        } catch (Exception $e) {
+            $this->logger->critical($pluginName.': '.$e->getMessage());
+        }
     }
 }
diff --git a/app/Core/Plugin/PluginException.php b/app/Core/Plugin/PluginException.php
new file mode 100644
index 00000000..fae7de35
--- /dev/null
+++ b/app/Core/Plugin/PluginException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+use Exception;
+
+/**
+ * Class PluginException
+ *
+ * @package Kanboard\Core\Plugin
+ * @author  Frederic Guillot
+ */
+class PluginException extends Exception
+{
+}
diff --git a/app/Core/Plugin/PluginInstallerException.php b/app/Core/Plugin/PluginInstallerException.php
index 7d356c9b..31745f22 100644
--- a/app/Core/Plugin/PluginInstallerException.php
+++ b/app/Core/Plugin/PluginInstallerException.php
@@ -2,14 +2,12 @@
 
 namespace Kanboard\Core\Plugin;
 
-use Exception;
-
 /**
  * Class PluginInstallerException
  *
  * @package Kanboard\Core\Plugin
  * @author  Frederic Guillot
  */
-class PluginInstallerException extends Exception
+class PluginInstallerException extends PluginException
 {
 }
diff --git a/app/Core/Plugin/Version.php b/app/Core/Plugin/Version.php
new file mode 100644
index 00000000..ba5e0443
--- /dev/null
+++ b/app/Core/Plugin/Version.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+/**
+ * Class Version
+ *
+ * @package Kanboard\Core\Plugin
+ * @author  Frederic Guillot
+ */
+class Version
+{
+    /**
+     * Check plugin version compatibility with application version
+     *
+     * @param  string $pluginCompatibleVersion
+     * @param  string $appVersion
+     * @return bool
+     */
+    public static function isCompatible($pluginCompatibleVersion, $appVersion = APP_VERSION)
+    {
+        if (strpos($appVersion, 'master') !== false) {
+            return true;
+        }
+
+        $appVersion = str_replace('v', '', $appVersion);
+        $pluginCompatibleVersion = str_replace('v', '', $pluginCompatibleVersion);
+
+        foreach (array('>=', '>', '<=', '<') as $operator) {
+            if (strpos($pluginCompatibleVersion, $operator) === 0) {
+                $pluginVersion = substr($pluginCompatibleVersion, strlen($operator));
+                return version_compare($appVersion, $pluginVersion, $operator);
+            }
+        }
+
+        return $pluginCompatibleVersion === $appVersion;
+    }
+}
-- 
cgit v1.2.3