Plugins are now updated according to their dependency definitions

This commit is contained in:
Sam Georges 2014-10-04 15:59:43 +10:00
parent eb886af176
commit 5c46dbec32
4 changed files with 117 additions and 56 deletions

View File

@ -9,7 +9,7 @@ use BackendAuth;
use Backend\Models\User;
use Backend\Models\AccessLog;
use Backend\Classes\Controller;
use System\Classes\VersionManager;
use System\Classes\UpdateManager;
use System\Classes\ApplicationException;
use October\Rain\Support\ValidationException;
use Exception;
@ -75,7 +75,7 @@ class Auth extends Controller
], true);
// Load version updates
VersionManager::instance()->updateAll();
UpdateManager::instance()->update();
// Log the sign in event
AccessLog::add($user);

View File

@ -9,6 +9,7 @@ use Config;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use Illuminate\Container\Container;
use ApplicationException;
/**
* Plugin manager
@ -105,34 +106,6 @@ class PluginManager
return $this->plugins;
}
/**
* Cross checks all plugins and their dependancies, if not met plugins
* are disabled and vice versa.
*/
protected function loadDependencies()
{
foreach ($this->plugins as $id => $plugin) {
if (!isset($plugin->require) || !$plugin->require)
continue;
$required = is_array($plugin->require) ? $plugin->require : [$plugin->require];
$disable = false;
foreach ($required as $require) {
if (!$this->hasPlugin($require))
$disable = true;
elseif (($pluginObj = $this->findByIdentifier($require)) && $pluginObj->disabled)
$disable = true;
}
if ($disable)
$this->disablePlugin($id);
else
$this->enablePlugin($id);
}
}
/**
* Runs the register() method on all plugins. Can only be called once.
*/
@ -227,6 +200,18 @@ class PluginManager
return $this->pathMap[$classId];
}
/**
* Check if a plugin exists and is enabled.
* @param string $id Plugin identifier, eg: Namespace.PluginName
* @return boolean
*/
public function exists($id)
{
return (!$this->findByIdentifier($id) || $this->isDisabled($id))
? false
: true;
}
/**
* Returns an array with all registered plugins
* The index is the plugin namespace, the value is the plugin information object.
@ -446,17 +431,108 @@ class PluginManager
return true;
}
//
// Dependencies
//
/**
* Check if a plugin exists and is enabled.
* @param string $id Plugin identifier, eg: Namespace.PluginName
* @return boolean
* Cross checks all plugins and their dependancies, if not met plugins
* are disabled and vice versa.
*/
public static function pluginExists($id)
protected function loadDependencies()
{
$instance = static::instance();
return (!$instance->findByIdentifier($id) || $instance->isDisabled($id))
? false
: true;
foreach ($this->plugins as $id => $plugin) {
if (!$required = $this->getDependencies($plugin))
continue;
$disable = false;
foreach ($required as $require) {
if (!$this->hasPlugin($require))
$disable = true;
elseif (($pluginObj = $this->findByIdentifier($require)) && $pluginObj->disabled)
$disable = true;
}
if ($disable)
$this->disablePlugin($id);
else
$this->enablePlugin($id);
}
}
/**
* Returns the plugin identifiers that are required by the supplied plugin.
* @param string $plugin Plugin identifier, object or class
* @return array
*/
public function getDependencies($plugin)
{
if (is_string($plugin) && (!$plugin = $this->findByIdentifier($identifer)))
return false;
if (!isset($plugin->require) || !$plugin->require)
return null;
return is_array($plugin->require) ? $plugin->require : [$plugin->require];
}
/**
* Sorts a collection of plugins, in the order that they should be actioned,
* according to their given dependencies. Least dependent come first.
* @param array $plugins Object collection to sort, or null to sort all.
* @return array Collection of sorted plugin identifiers
*/
public function sortByDependencies($plugins = null)
{
if (!is_array($plugins))
$plugins = $this->getPlugins();
$result = [];
$checklist = $plugins;
$loopCount = 0;
while (count($checklist)) {
if (++$loopCount > 999)
throw new ApplicationException('Too much recursion');
foreach ($checklist as $code => $plugin) {
/*
* Get dependencies and remove any aliens
*/
$depends = $this->getDependencies($plugin) ?: [];
$depends = array_filter($depends, function($pluginCode) use ($plugins) {
return isset($plugins[$pluginCode]);
});
/*
* No dependencies
*/
if (!$depends) {
array_push($result, $code);
unset($checklist[$code]);
continue;
}
/*
* Find dependencies that have not been checked
*/
$depends = array_diff($depends, $result);
if (count($depends) > 0)
continue;
/*
* All dependencies are checked
*/
array_push($result, $code);
unset($checklist[$code]);
}
}
return $result;
}
}

View File

@ -104,9 +104,9 @@ class UpdateManager
/*
* Update plugins
*/
$plugins = $this->pluginManager->getPlugins();
foreach ($plugins as $name => $plugin) {
$this->updatePlugin($name);
$plugins = $this->pluginManager->sortByDependencies();
foreach ($plugins as $plugin) {
$this->updatePlugin($plugin);
}
Parameters::set('system::update.count', 0);

View File

@ -67,21 +67,6 @@ class VersionManager
$this->pluginManager = PluginManager::instance();
}
/**
* Performs the update for all plugins
*/
public function updateAll()
{
$plugins = $this->pluginManager->getPlugins();
foreach ($plugins as $code => $plugin) {
if (!$this->hasVersionFile($code))
continue;
$this->updatePlugin($code);
}
}
/**
* Updates a single plugin by its code or object with it's latest changes.
*/