diff --git a/Asset/AbstractAssetManager.php b/Asset/AbstractAssetManager.php index fc4772e..50c3dab 100644 --- a/Asset/AbstractAssetManager.php +++ b/Asset/AbstractAssetManager.php @@ -85,6 +85,16 @@ public function __construct( $this->fallback = $fallback; } + /** + * {@inheritdoc} + */ + public function isAvailable() + { + $this->executor->execute($this->getVersionCommand(), $version); + + return '' !== trim($version); + } + /** * {@inheritdoc} */ diff --git a/Asset/AssetManagerFinder.php b/Asset/AssetManagerFinder.php new file mode 100644 index 0000000..a1a4d36 --- /dev/null +++ b/Asset/AssetManagerFinder.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Foxy\Asset; + +use Foxy\Exception\RuntimeException; + +/** + * Asset Manager finder. + * + * @author François Pluchino + */ +class AssetManagerFinder +{ + /** + * @var AssetManagerInterface[] + */ + private $managers; + + /** + * Constructor. + * + * @param AssetManagerInterface[] $managers The asset managers + */ + public function __construct(array $managers = array()) + { + foreach ($managers as $manager) { + if ($manager instanceof AssetManagerInterface) { + $this->addManager($manager); + } + } + } + + public function addManager(AssetManagerInterface $manager) + { + $this->managers[$manager->getName()] = $manager; + } + + /** + * Find the asset manager. + * + * @param null|string $manager The name of the asset manager + * + * @throws RuntimeException When the asset manager does not exist + * @throws RuntimeException When the asset manager is not found + * + * @return AssetManagerInterface + */ + public function findManager($manager = null) + { + if (null !== $manager) { + if (isset($this->managers[$manager])) { + return $this->managers[$manager]; + } + + throw new RuntimeException(sprintf('The asset manager "%s" doesn\'t exist', $manager)); + } + + return $this->findAvailableManager(); + } + + /** + * Find the available asset manager. + * + * @throws RuntimeException When no asset manager is found + * + * @return AssetManagerInterface + */ + private function findAvailableManager() + { + // find asset manager by lockfile + foreach ($this->managers as $manager) { + if ($manager->hasLockFile()) { + return $manager; + } + } + + // find asset manager by availability + foreach ($this->managers as $manager) { + if ($manager->isAvailable()) { + return $manager; + } + } + + throw new RuntimeException('No asset manager is found'); + } +} diff --git a/Asset/AssetManagerInterface.php b/Asset/AssetManagerInterface.php index 4967e18..39a66bf 100644 --- a/Asset/AssetManagerInterface.php +++ b/Asset/AssetManagerInterface.php @@ -29,6 +29,13 @@ interface AssetManagerInterface */ public function getName(); + /** + * Check if the asset manager is available. + * + * @return bool + */ + public function isAvailable(); + /** * Get the filename of the asset package. * diff --git a/Foxy.php b/Foxy.php index 84d4737..b1f3b70 100644 --- a/Foxy.php +++ b/Foxy.php @@ -22,6 +22,7 @@ use Composer\Script\ScriptEvents; use Composer\Util\Filesystem; use Composer\Util\ProcessExecutor; +use Foxy\Asset\AssetManagerFinder; use Foxy\Asset\AssetManagerInterface; use Foxy\Config\Config; use Foxy\Config\ConfigBuilder; @@ -76,8 +77,8 @@ class Foxy implements PluginInterface, EventSubscriberInterface * The list of the classes of asset managers. */ private static $assetManagers = array( - 'Foxy\Asset\NpmManager', 'Foxy\Asset\YarnManager', + 'Foxy\Asset\NpmManager', ); /** @@ -85,7 +86,7 @@ class Foxy implements PluginInterface, EventSubscriberInterface */ private static $defaultConfig = array( 'enabled' => true, - 'manager' => 'npm', + 'manager' => null, 'manager-version' => array( 'npm' => '>=5.0.0', 'yarn' => '>=1.0.0', @@ -218,16 +219,12 @@ public function solveAssets(Event $event) */ protected function getAssetManager(IOInterface $io, Config $config, ProcessExecutor $executor, Filesystem $fs) { - $manager = $config->get('manager'); + $amf = new AssetManagerFinder(); foreach (self::$assetManagers as $class) { - $am = new $class($io, $config, $executor, $fs); - - if ($am instanceof AssetManagerInterface && $manager === $am->getName()) { - return $am; - } + $amf->addManager(new $class($io, $config, $executor, $fs)); } - throw new RuntimeException(sprintf('The asset manager "%s" doesn\'t exist', $manager)); + return $amf->findManager($config->get('manager')); } } diff --git a/Tests/Asset/AssetManagerFinderTest.php b/Tests/Asset/AssetManagerFinderTest.php new file mode 100644 index 0000000..e2f67f6 --- /dev/null +++ b/Tests/Asset/AssetManagerFinderTest.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Foxy\Tests\Asset; + +use Foxy\Asset\AssetManagerFinder; +use PHPUnit\Framework\TestCase; + +/** + * Asset manager finder tests. + * + * @author François Pluchino + * + * @internal + */ +final class AssetManagerFinderTest extends TestCase +{ + public function testFindManagerWithValidManager() + { + $am = $this->getMockBuilder('Foxy\Asset\AssetManagerInterface')->getMock(); + + $am->expects(static::once()) + ->method('getName') + ->willReturn('foo') + ; + + $amf = new AssetManagerFinder(array($am)); + $res = $amf->findManager('foo'); + + static::assertSame($am, $res); + } + + /** + * @expectedException \Foxy\Exception\RuntimeException + * @expectedExceptionMessage The asset manager "bar" doesn't exist + */ + public function testFindManagerWithInvalidManager() + { + $am = $this->getMockBuilder('Foxy\Asset\AssetManagerInterface')->getMock(); + + $am->expects(static::once()) + ->method('getName') + ->willReturn('foo') + ; + + $amf = new AssetManagerFinder(array($am)); + $amf->findManager('bar'); + } + + public function testFindManagerWithAutoManagerAndAvailableManagerByLockFile() + { + $am = $this->getMockBuilder('Foxy\Asset\AssetManagerInterface')->getMock(); + + $am->expects(static::once()) + ->method('getName') + ->willReturn('foo') + ; + + $am->expects(static::once()) + ->method('hasLockFile') + ->willReturn(true) + ; + + $am->expects(static::never()) + ->method('isAvailable') + ; + + $amf = new AssetManagerFinder(array($am)); + $res = $amf->findManager(null); + + static::assertSame($am, $res); + } + + public function testFindManagerWithAutoManagerAndAvailableManagerByAvailability() + { + $am = $this->getMockBuilder('Foxy\Asset\AssetManagerInterface')->getMock(); + + $am->expects(static::once()) + ->method('getName') + ->willReturn('foo') + ; + + $am->expects(static::once()) + ->method('hasLockFile') + ->willReturn(false) + ; + + $am->expects(static::once()) + ->method('isAvailable') + ->willReturn(true) + ; + + $amf = new AssetManagerFinder(array($am)); + $res = $amf->findManager(null); + + static::assertSame($am, $res); + } + + /** + * @expectedException \Foxy\Exception\RuntimeException + * @expectedExceptionMessage No asset manager is found + */ + public function testFindManagerWithAutoManagerAndNoAvailableManager() + { + $am = $this->getMockBuilder('Foxy\Asset\AssetManagerInterface')->getMock(); + + $am->expects(static::atLeastOnce()) + ->method('getName') + ->willReturn('foo') + ; + + $am->expects(static::once()) + ->method('hasLockFile') + ->willReturn(false) + ; + + $am->expects(static::once()) + ->method('isAvailable') + ->willReturn(false) + ; + + $amf = new AssetManagerFinder(array($am)); + $amf->findManager(null); + } +}