Add plugins update stuff

This commit is contained in:
Dmitriy Simushev 2014-11-28 14:20:47 +00:00
parent 459f75727a
commit 772aa904d9
5 changed files with 157 additions and 2 deletions

View File

@ -570,6 +570,13 @@ plugin_uninstall:
_access_check: Mibew\AccessControl\Check\PermissionsCheck _access_check: Mibew\AccessControl\Check\PermissionsCheck
_access_permissions: [CAN_ADMINISTRATE] _access_permissions: [CAN_ADMINISTRATE]
plugin_update:
path: /operator/plugin/{plugin_name}/update
defaults:
_controller: Mibew\Controller\PluginController::updateAction
_access_check: Mibew\AccessControl\Check\PermissionsCheck
_access_permissions: [CAN_ADMINISTRATE]
plugins: plugins:
path: /operator/plugin path: /operator/plugin
defaults: defaults:

View File

@ -158,6 +158,40 @@ class PluginController extends AbstractController
return $this->redirect($this->generateUrl('plugins')); return $this->redirect($this->generateUrl('plugins'));
} }
/**
* Updates a plugin.
*
* @param Request $request Incoming request.
* @return string Rendered page content.
* @throws NotFoundException If the plugin with specified name is not found
* in the system.
*/
public function updateAction(Request $request)
{
csrf_check_token($request);
$plugin_name = $request->attributes->get('plugin_name');
if (!PluginUtils::pluginExists($plugin_name)) {
throw new NotFoundException('The plugin is not found.');
}
// Update the plugin
if (!PluginManager::getInstance()->update($plugin_name)) {
$error = getlocal(
'Plugin "{0}" cannot be updated.',
array($plugin_name)
);
$request->attributes->set('errors', array($error));
// The plugin cannot be updated by some reasons. Just rebuild
// index page and show errors there.
return $this->indexAction($request);
}
return $this->redirect($this->generateUrl('plugins'));
}
/** /**
* Builds plugins list that will be passed to templates engine. * Builds plugins list that will be passed to templates engine.
* *
@ -170,13 +204,15 @@ class PluginController extends AbstractController
$plugin = new PluginInfo($plugin_name); $plugin = new PluginInfo($plugin_name);
$plugins[] = array( $plugins[] = array(
'name' => $plugin_name, 'name' => $plugin_name,
'version' => $plugin->getInstalledVersion() ?: $plugin->getVersion(), 'version' => $plugin->isInstalled() ? $plugin->getInstalledVersion() : $plugin->getVersion(),
'dependencies' => $plugin->getDependencies(), 'dependencies' => $plugin->getDependencies(),
'enabled' => $plugin->isEnabled(), 'enabled' => $plugin->isEnabled(),
'installed' => $plugin->isInstalled(), 'installed' => $plugin->isInstalled(),
'needsUpdate' => $plugin->needsUpdate(),
'canBeEnabled' => $plugin->canBeEnabled(), 'canBeEnabled' => $plugin->canBeEnabled(),
'canBeDisabled' => $plugin->canBeDisabled(), 'canBeDisabled' => $plugin->canBeDisabled(),
'canBeUninstalled' => $plugin->canBeUninstalled(), 'canBeUninstalled' => $plugin->canBeUninstalled(),
'canBeUpdated' => $plugin->canBeUpdated(),
); );
} }

View File

@ -217,6 +217,17 @@ class PluginInfo
return $this->getState()->installed; return $this->getState()->installed;
} }
/**
* Checks if the plugin needs to be updated.
*
* @return bool
*/
public function needsUpdate()
{
return $this->isInstalled()
&& (version_compare($this->getVersion(), $this->getInstalledVersion()) > 0);
}
/** /**
* Checks if the plugin can be enabled. * Checks if the plugin can be enabled.
* *
@ -294,6 +305,27 @@ class PluginInfo
return true; return true;
} }
/**
* Checks if the plugin can be updated.
*
* @return boolean
*/
public function canBeUpdated()
{
if (!$this->needsUpdate()) {
return false;
}
foreach (array_keys($this->getDependencies()) as $dependency_name) {
$dependency = new PluginInfo($dependency_name);
if ($dependency->needsUpdate()) {
return false;
}
}
return true;
}
/** /**
* Creates plugin info object based on a state object. * Creates plugin info object based on a state object.
* *

View File

@ -19,6 +19,9 @@
namespace Mibew\Plugin; namespace Mibew\Plugin;
use Mibew\Plugin\Utils as PluginUtils;
use Mibew\Maintenance\Utils as MaintenanceUtils;
/** /**
* Manage plugins. * Manage plugins.
* *
@ -102,7 +105,7 @@ class PluginManager
// Builds Dependency graph with available plugins. // Builds Dependency graph with available plugins.
$graph = new DependencyGraph(); $graph = new DependencyGraph();
foreach (State::loadAllEnabled() as $plugin_state) { foreach (State::loadAllEnabled() as $plugin_state) {
if (!Utils::pluginExists($plugin_state->pluginName)) { if (!PluginUtils::pluginExists($plugin_state->pluginName)) {
trigger_error( trigger_error(
sprintf( sprintf(
'Plugin "%s" exists in database base but is not found in file system!', 'Plugin "%s" exists in database base but is not found in file system!',
@ -266,4 +269,74 @@ class PluginManager
return true; return true;
} }
/**
* Tries to update a plugin.
*
* @param string $plugin_name Name of the plugin to update.
* @return boolean Indicates if the plugin has been updated or not.
*/
public function update($plugin_name)
{
$plugin = new PluginInfo($plugin_name);
if (!$plugin->needsUpdate()) {
// There is no need to update the plugin
return true;
}
if (!$plugin->canBeUpdated()) {
// The plugin cannot be updated.
return false;
}
try {
// Perform incremental updates
$updates = MaintenanceUtils::getUpdates($plugin->getClass());
foreach ($updates as $version => $method) {
// Skip updates to lower versions.
if (version_compare($version, $plugin->getInstalledVersion()) <= 0) {
continue;
}
// Skip updates to versions that greater then the current plugin
// version.
if (version_compare($version, $plugin->getVersion()) > 0) {
break;
}
// Run the update
if (!$method()) {
// By some reasons we cannot update to the next version.
// Stop the process here.
return false;
}
// Store new version number in the database. With this info
// we can rerun the updating process if one of pending
// updates fails.
$plugin->getState()->version = $version;
$plugin->getState()->save();
}
} catch (\Exception $e) {
// Something went wrong
trigger_error(
sprintf(
'Update of "%s" plugin failed: %s',
$plugin->getName(),
$e->getMessage()
),
E_USER_WARNING
);
return false;
}
// All updates are done. Make sure the state of the plugin contains
// current plugin version.
$plugin->getState()->version = $plugin->getVersion();
$plugin->getState()->save();
return true;
}
} }

View File

@ -48,6 +48,13 @@
{{/if}} {{/if}}
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#if needsUpdate}}
{{#if canBeUpdated}}
<a href="{{csrfProtectedRoute "plugin_update" plugin_name=name}}">{{l10n "update"}}</a>
{{else}}
<span class="disabled-link" title="{{l10n "Update all the dependencies first"}}">{{l10n "update"}}</span>
{{/if}}
{{/if}}
</td> </td>
</tr> </tr>
{{else}} {{else}}