From 3071ece7ba7094fd777d4796d6ef693d14d06165 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Mon, 12 Aug 2019 17:37:52 +0800 Subject: [PATCH] Refactor plugin system (part 6) --- app/Services/Plugin.php | 5 ++ app/Services/PluginManager.php | 37 ++++++++++++-- tests/ServicesTest/PluginManagerTest.php | 61 +++++++++++++++++++++++- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/app/Services/Plugin.php b/app/Services/Plugin.php index 4c3ddefe..b3b17238 100644 --- a/app/Services/Plugin.php +++ b/app/Services/Plugin.php @@ -85,6 +85,11 @@ class Plugin return Arr::get($this->packageInfo, $name); } + public function getManifest() + { + return $this->packageInfo; + } + public function assets(string $relativeUri): string { $baseUrl = config('plugins.url') ?: url('plugins'); diff --git a/app/Services/PluginManager.php b/app/Services/PluginManager.php index 0c63c0f5..e01f3661 100644 --- a/app/Services/PluginManager.php +++ b/app/Services/PluginManager.php @@ -62,6 +62,7 @@ class PluginManager $this->option = $option; $this->dispatcher = $dispatcher; $this->filesystem = $filesystem; + $this->enabled = collect(); } /** @@ -95,6 +96,10 @@ class PluginManager } $plugin = new Plugin($directory, $manifest); + $plugins->put($name, $plugin); + if ($this->getUnsatisfied($plugin)->isNotEmpty()) { + $this->disable($plugin); + } if ($this->enabled->contains('name', $name)) { $plugin->setEnabled(true); if (Comparator::notEqualTo( @@ -104,11 +109,8 @@ class PluginManager $this->dispatcher->dispatch(new Events\PluginVersionChanged($plugin)); } } - $plugins->put($name, $plugin); }); - // disable unsatisfied here - $enabled = $plugins->filter(function ($plugin) { return $plugin->isEnabled(); }); @@ -484,6 +486,35 @@ class PluginManager return in_array($pluginName, $this->getEnabled()); } + /** + * @param Plugin $plugin + * @return Collection + */ + public function getUnsatisfied(Plugin $plugin) + { + return collect(Arr::get($plugin->getManifest(), 'require', [])) + ->mapWithKeys(function ($constraint, $name) { + if ($name == 'blessing-skin-server') { + $version = config('app.version'); + return (! Semver::satisfies($version, $constraint)) + ? [$name => compact('version', 'constraint')] + : []; + } elseif ($name == 'php') { + $version = PHP_VERSION; + return (! Semver::satisfies($version, $constraint)) + ? [$name => compact('version', 'constraint')] + : []; + } elseif (! $this->enabled->contains('name', $name)) { + return [$name => ['version' => null, 'constraint' => $constraint]]; + } else { + $version = $this->enabled->firstWhere('name', $name)['version']; + return (! Semver::satisfies($version, $constraint)) + ? [$name => compact('version', 'constraint')] + : []; + } + }); + } + /** * Get the unsatisfied requirements of plugin. * diff --git a/tests/ServicesTest/PluginManagerTest.php b/tests/ServicesTest/PluginManagerTest.php index f4f66758..d1526c03 100644 --- a/tests/ServicesTest/PluginManagerTest.php +++ b/tests/ServicesTest/PluginManagerTest.php @@ -31,7 +31,7 @@ class PluginManagerTest extends TestCase app('plugins')->boot(); } - public function testDoNotLoadDisabled() + public function testNotLoadDisabled() { $dir = config('plugins.directory'); config(['plugins.directory' => storage_path('mocks')]); @@ -42,6 +42,34 @@ class PluginManagerTest extends TestCase config(['plugins.directory' => $dir]); } + public function testNotLoadUnsatisfied() + { + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('directories') + ->with(base_path('plugins')) + ->once() + ->andReturn(collect(['/nano'])); + + $mock->shouldReceive('exists') + ->with('/nano'.DIRECTORY_SEPARATOR.'package.json') + ->once() + ->andReturn(true); + + $mock->shouldReceive('get') + ->with('/nano'.DIRECTORY_SEPARATOR.'package.json') + ->once() + ->andReturn(json_encode([ + 'name' => 'fake', + 'version' => '0.0.0', + 'require' => ['blessing-skin-server' => '0.0.0'], + ])); + + $mock->shouldNotReceive('getRequire'); + }); + + $manager = $this->rebootPluginManager(app('plugins')); + } + public function testReportDuplicatedPlugins() { $this->mock(Filesystem::class, function ($mock) { @@ -316,4 +344,35 @@ class PluginManagerTest extends TestCase config(['plugins.directory' => $dir]); option(['plugins_enabled' => '[]']); } + + public function testGetUnsatisfied() + { + $manager = app('plugins'); + + $plugin = new Plugin('', ['require' => ['blessing-skin-server' => '^0.0.0']]); + $info = $manager->getUnsatisfied($plugin)->get('blessing-skin-server'); + $this->assertEquals(config('app.version'), $info['version']); + $this->assertEquals('^0.0.0', $info['constraint']); + + $plugin = new Plugin('', ['require' => ['php' => '^0.0.0']]); + $info = $manager->getUnsatisfied($plugin)->get('php'); + $this->assertEquals(PHP_VERSION, $info['version']); + $this->assertEquals('^0.0.0', $info['constraint']); + + $plugin = new Plugin('', ['require' => ['another-plugin' => '0.0.*']]); + $info = $manager->getUnsatisfied($plugin)->get('another-plugin'); + $this->assertNull($info['version']); + $this->assertEquals('0.0.*', $info['constraint']); + + $reflection = new ReflectionClass($manager); + $property = $reflection->getProperty('enabled'); + $property->setAccessible(true); + $property->setValue($manager, collect([['name' => 'another-plugin', 'version' => '1.2.3']])); + $info = $manager->getUnsatisfied($plugin)->get('another-plugin'); + $this->assertEquals('1.2.3', $info['version']); + $this->assertEquals('0.0.*', $info['constraint']); + + $plugin = new Plugin('', ['require' => ['another-plugin' => '^1.0.0']]); + $this->assertFalse($manager->getUnsatisfied($plugin)->has('another-plugin')); + } }