Plugin system: allow to define conflicts

This commit is contained in:
Pig Fang 2019-08-21 11:48:42 +08:00
parent 3481dc75fc
commit 937186e34b
6 changed files with 59 additions and 13 deletions

View File

@ -34,7 +34,7 @@ class PluginController extends Controller
if ($result === true) {
return json(trans('admin.plugins.operations.enabled', ['plugin' => $plugin->title]), 0);
} else {
$reason = $result['unsatisfied']->map(function ($detail, $name) {
$unsatisfied = $result['unsatisfied']->map(function ($detail, $name) {
$constraint = $detail['constraint'];
if (! $detail['version']) {
return trans('admin.plugins.operations.unsatisfied.disabled', compact('name'));
@ -43,6 +43,12 @@ class PluginController extends Controller
}
})->values()->all();
$conflicts = $result['conflicts']->map(function ($detail, $name) {
return trans('admin.plugins.operations.unsatisfied.conflict', compact('name'));
})->values()->all();
$reason = array_merge($unsatisfied, $conflicts);
return json(trans('admin.plugins.operations.unsatisfied.notice'), 1, compact('reason'));
}

View File

@ -269,8 +269,9 @@ class PluginManager
$plugin = is_string($plugin) ? $this->get($plugin) : $plugin;
if ($plugin && ! $plugin->isEnabled()) {
$unsatisfied = $this->getUnsatisfied($plugin);
if ($unsatisfied->isNotEmpty()) {
return compact('unsatisfied');
$conflicts = $this->getConflicts($plugin);
if ($unsatisfied->isNotEmpty() || $conflicts->isNotEmpty()) {
return compact('unsatisfied', 'conflicts');
}
$this->enabled->put($plugin->name, ['version' => $plugin->version]);
@ -335,7 +336,6 @@ class PluginManager
}
/**
* @param Plugin $plugin
* @return Collection
*/
public function getUnsatisfied(Plugin $plugin)
@ -366,6 +366,22 @@ class PluginManager
});
}
/**
* @return Collection
*/
public function getConflicts(Plugin $plugin)
{
return collect($plugin->getManifestAttr('enchants.conflicts', []))
->mapWithKeys(function ($constraint, $name) {
$info = $this->enabled->get($name);
if ($info && Semver::satisfies($info['version'], $constraint)) {
return [$name => ['version' => $info['version'], 'constraint' => $constraint]];
} else {
return [];
}
});
}
/**
* The plugins path.
*

View File

@ -95,9 +95,10 @@ plugins:
title: Operations
enabled: :plugin has been enabled.
unsatisfied:
notice: There are unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below.
disabled: "The `:name` plugin is not enabled"
version: "The version of `:name` does not satisfies the constraint `:constraint`"
notice: There are conflicts or unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below, and disable those have conflicts.
disabled: 'The :name plugin is not enabled.'
version: 'The version of :name does not satisfies the constraint `:constraint`.'
conflict: 'The :name plugin cannot run with this plugin at the same time.'
disabled: :plugin has been disabled.
deleted: The plugin was deleted successfully.
no-config-notice: The plugin is not installed or doesn't provide a configuration page.

View File

@ -100,9 +100,10 @@ plugins:
title: 操作
enabled: :plugin 已启用
unsatisfied:
notice: 无法启用此插件,因为其仍有未满足的依赖关系。请检查以下插件的版本,更新或安装它们:
disabled: "`:name` 插件未启用"
version: "`:name` 的版本不符合要求 `:constraint`"
notice: 无法启用此插件,因为其仍有冲突或未满足的依赖关系。请检查以下插件的版本,更新或安装它们并禁用存在冲突的插件:
disabled: ':name 插件未启用'
version: ':name 的版本不符合要求 `:constraint`'
conflict: ':name 插件与此插件不能同时运行'
disabled: :plugin 已禁用
deleted: 插件已被成功删除
no-config-notice: 插件未安装或未提供配置页面

View File

@ -97,6 +97,9 @@ class PluginControllerTest extends TestCase
'dep' => ['version' => '0.0.0', 'constraint' => '^6.6.6'],
'whatever' => ['version' => null, 'constraint' => '^1.2.3'],
]),
'conflicts' => collect([
'conf' => ['version' => '1.2.3', 'constraint' => '^1.0.0'],
]),
]);
$mock->shouldReceive('get')
@ -152,9 +155,8 @@ class PluginControllerTest extends TestCase
'name' => 'dep',
'constraint' => '^6.6.6',
]),
trans('admin.plugins.operations.unsatisfied.disabled', [
'name' => 'whatever',
]),
trans('admin.plugins.operations.unsatisfied.disabled', ['name' => 'whatever']),
trans('admin.plugins.operations.unsatisfied.conflict', ['name' => 'conf']),
],
],
]);

View File

@ -393,6 +393,26 @@ class PluginManagerTest extends TestCase
$this->assertFalse($manager->getUnsatisfied($plugin)->has('another-plugin'));
}
public function testGetConflicts()
{
$manager = app('plugins');
$plugin = new Plugin('/', ['enchants' => ['conflicts' => ['a' => '*', 'b' => '^1.2.0']]]);
$reflection = new ReflectionClass($manager);
$property = $reflection->getProperty('enabled');
$property->setAccessible(true);
$property->setValue($manager, collect(['b' => ['version' => '1.2.3']]));
$conflicts = $manager->getConflicts($plugin);
$this->assertNull($conflicts->get('a'));
$info = $conflicts->get('b');
$this->assertEquals('1.2.3', $info['version']);
$this->assertEquals('^1.2.0', $info['constraint']);
$plugin = new Plugin('/', ['enchants' => ['conflicts' => ['b' => '^0.0.0']]]);
$this->assertNull($manager->getConflicts($plugin)->get('b'));
}
public function testEnable()
{
Event::fake();