diff --git a/build/travis/script.sh b/build/travis/script.sh
index 2eaa08ea..859985b9 100644
--- a/build/travis/script.sh
+++ b/build/travis/script.sh
@@ -21,4 +21,4 @@ if [[ "$PHPUNIT" = true ]]; then
}
fi
done
-fi
+fi
\ No newline at end of file
diff --git a/src/Automatic/AbstractConfigurator.php b/src/Automatic/AbstractConfigurator.php
index 83592f66..e2d8bc03 100644
--- a/src/Automatic/AbstractConfigurator.php
+++ b/src/Automatic/AbstractConfigurator.php
@@ -7,6 +7,7 @@
use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract;
use Narrowspark\Automatic\Common\Contract\Exception\InvalidArgumentException;
use Narrowspark\Automatic\Common\Contract\Package as PackageContract;
+use Narrowspark\Automatic\Common\Contract\Resettable as ResettableContract;
abstract class AbstractConfigurator
{
@@ -130,11 +131,9 @@ public function getConfigurators(): array
}
/**
- * Clear all configurators.
- *
- * @return void
+ * {@inheritdoc}
*/
- public function clear(): void
+ public function reset(): void
{
$this->configurators = [];
}
diff --git a/src/Automatic/Automatic.php b/src/Automatic/Automatic.php
index 049cd6b4..0758ce58 100644
--- a/src/Automatic/Automatic.php
+++ b/src/Automatic/Automatic.php
@@ -34,6 +34,7 @@
use Composer\Script\ScriptEvents;
use FilesystemIterator;
use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract;
+use Narrowspark\Automatic\Common\Contract\Resettable as ResettableContract;
use Narrowspark\Automatic\Common\Contract\Exception\InvalidArgumentException;
use Narrowspark\Automatic\Common\Contract\Exception\RuntimeException;
use Narrowspark\Automatic\Common\Contract\Package as PackageContract;
@@ -52,7 +53,7 @@
use ReflectionClass;
use Symfony\Component\Console\Input\ArgvInput;
-class Automatic implements PluginInterface, EventSubscriberInterface
+class Automatic implements PluginInterface, EventSubscriberInterface, ResettableContract
{
use ExpandTargetDirTrait;
use GetGenericPropertyReaderTrait;
@@ -295,12 +296,12 @@ public function onPostUpdate(Event $event, array $operations = []): void
$this->operations = $operations;
}
+ /** @var \Narrowspark\Automatic\Lock $lock */
+ /** @var \Composer\IO\IOInterface $io */
$automaticOptions = $this->container->get('composer-extra')[Util::COMPOSER_EXTRA_KEY];
$allowInstall = $automaticOptions['allow-auto-install'] ?? false;
$packages = $this->container->get(OperationsResolver::class)->resolve($this->operations);
- /** @var \Narrowspark\Automatic\Lock $lock */
$lock = $this->container->get(Lock::class);
- /** @var \Composer\IO\IOInterface $io */
$io = $this->container->get(IOInterface::class);
$io->writeError(\sprintf(
@@ -524,6 +525,15 @@ public function onFileDownload(PreFileDownloadEvent $event): void
}
}
+ /**
+ * {@inheritdoc}
+ */
+ public function reset(): void
+ {
+ $this->operations = [];
+ $this->container->get(Configurator::class)->reset();
+ }
+
/**
* Add found legacy tags to the tags manager.
*
@@ -661,7 +671,7 @@ private function doActionOnPackageOperation(PackageContract $package): void
$this->doUninstall($package, $packageConfigurator);
}
- $packageConfigurator->clear();
+ $packageConfigurator->reset();
}
/**
@@ -679,7 +689,15 @@ private function doInstall(PackageContract $package, PackageConfigurator $packag
/** @var \Narrowspark\Automatic\Lock $lock */
$lock = $this->container->get(Lock::class);
- $this->writeScriptExtenderToLock($package, $lock);
+ if ($package->hasConfig(ScriptExecutor::TYPE)) {
+ $extenders = [];
+
+ foreach ((array) $package->getConfig(ScriptExecutor::TYPE) as $extender) {
+ $extenders[$extender] = $package->getName() . \DIRECTORY_SEPARATOR . '';
+ }
+
+ $lock->addSub(ScriptExecutor::TYPE, $package->getName(), $extenders);
+ }
/** @var \Narrowspark\Automatic\Configurator $configurator */
$configurator = $this->container->get(Configurator::class);
@@ -697,13 +715,7 @@ private function doInstall(PackageContract $package, PackageConfigurator $packag
$this->postInstallOutput[] = '';
}
- $lock->add(
- self::LOCK_PACKAGES,
- \array_merge(
- (array) $lock->get(self::LOCK_PACKAGES),
- [$package->getName() => $package->toArray()]
- )
- );
+ $lock->addSub(self::LOCK_PACKAGES, $package->getName(), $package->toArray());
}
/**
@@ -730,54 +742,10 @@ private function doUninstall(PackageContract $package, PackageConfigurator $pack
$lock = $this->container->get(Lock::class);
if ($package->hasConfig(ScriptExecutor::TYPE)) {
- $extenders = (array) $lock->get(ScriptExecutor::TYPE);
-
- /** @var \Narrowspark\Automatic\Common\Contract\ScriptExtender $extender */
- foreach ((array) $package->getConfig(ScriptExecutor::TYPE) as $extender) {
- $type = $extender::getType();
-
- if (isset($extenders[$type])) {
- unset($extenders[$type]);
- }
- }
-
- $lock->add(ScriptExecutor::TYPE, $extenders);
+ $lock->remove(ScriptExecutor::TYPE, $package->getName());
}
- $lock->remove($package->getName());
- }
-
- /**
- * Looks if the package has a extra section for script extender.
- *
- * @param \Narrowspark\Automatic\Common\Contract\Package $package
- * @param \Narrowspark\Automatic\Lock $lock
- *
- * @throws \Narrowspark\Automatic\Common\Contract\Exception\InvalidArgumentException
- *
- * @return void
- */
- private function writeScriptExtenderToLock(PackageContract $package, Lock $lock): void
- {
- if ($package->hasConfig(ScriptExecutor::TYPE)) {
- $extenders = (array) $lock->get(ScriptExecutor::TYPE);
-
- foreach ((array) $package->getConfig(ScriptExecutor::TYPE) as $extender) {
- /** @var \Narrowspark\Automatic\Common\Contract\ScriptExtender $extender */
- if (isset($extenders[$extender::getType()])) {
- throw new InvalidArgumentException(\sprintf('Script executor extender with the name [%s] already exists.', $extender::getType()));
- }
-
- if (! \is_subclass_of($extender, ScriptExtenderContract::class)) {
- throw new InvalidArgumentException(\sprintf('The class [%s] must implement the interface [%s].', $extender, ScriptExtenderContract::class));
- }
-
- /** @var \Narrowspark\Automatic\Common\Contract\ScriptExtender $extender */
- $extenders[$extender::getType()] = $extender;
- }
-
- $lock->add(ScriptExecutor::TYPE, $extenders);
- }
+ $lock->remove(self::LOCK_PACKAGES, $package->getName());
}
/**
@@ -794,20 +762,17 @@ private function runSkeletonGenerator(): void
$lock->read();
- if ($lock->has(SkeletonInstaller::LOCK_KEY) && $this->container->get(IOInterface::class)->isInteractive()) {
- // Clear old operations if a skeleton is generated.
- $this->operations = [];
- $this->container->get(Configurator::class)->clear();
+ if ($lock->has(SkeletonInstaller::LOCK_KEY)) {
+ $this->reset();
/** @var \Narrowspark\Automatic\SkeletonGenerator $skeletonGenerator */
$skeletonGenerator = $this->container->get(SkeletonGenerator::class);
- $skeletonGenerator->run();
-
- $skeletonGenerator->remove();
+ $skeletonGenerator->run()
+ ->selfRemove();
}
- $lock->clear();
+ $lock->reset();
}
/**
diff --git a/src/Automatic/PathClassLoader.php b/src/Automatic/ClassLoader.php
similarity index 91%
rename from src/Automatic/PathClassLoader.php
rename to src/Automatic/ClassLoader.php
index 7af14b9a..765299ae 100644
--- a/src/Automatic/PathClassLoader.php
+++ b/src/Automatic/ClassLoader.php
@@ -2,9 +2,10 @@
declare(strict_types=1);
namespace Narrowspark\Automatic;
+use Narrowspark\Automatic\Common\Contract\Resettable as ResettableContract;
use Symfony\Component\Finder\Finder;
-final class PathClassLoader
+final class ClassLoader implements ResettableContract
{
/**
* List of traits.
@@ -49,6 +50,10 @@ public function find($dirs): void
->in($dirs)
->name('*.php');
+ if ($this->filter !== null) {
+ $finder = $finder->filter($this->filter);
+ }
+
/** @var \SplFileInfo $file */
foreach ($finder as $file) {
$realPath = (string) $file->getRealPath();
@@ -133,6 +138,17 @@ public function getAll(): array
);
}
+ /**
+ * {@inheritdoc}
+ */
+ public function reset(): void
+ {
+ $this->interfaces = [];
+ $this->traits = [];
+ $this->abstractClasses = [];
+ $this->classes = [];
+ }
+
/**
* Find the namespace in the tokens starting at a given key.
*
diff --git a/src/Automatic/Configurator.php b/src/Automatic/Configurator.php
index 3af217f5..db955963 100644
--- a/src/Automatic/Configurator.php
+++ b/src/Automatic/Configurator.php
@@ -32,7 +32,7 @@ final class Configurator extends AbstractConfigurator
/**
* {@inheritdoc}
*/
- public function clear(): void
+ public function reset(): void
{
$this->configurators = [];
$this->cache = [];
diff --git a/src/Automatic/Container.php b/src/Automatic/Container.php
index 7e1390de..b45c3aea 100644
--- a/src/Automatic/Container.php
+++ b/src/Automatic/Container.php
@@ -87,7 +87,7 @@ public function __construct(Composer $composer, IOInterface $io)
$container->get(IOInterface::class),
$container->get(Composer::class),
$container->get(Lock::class),
- new PathClassLoader()
+ new ClassLoader()
);
},
SkeletonInstaller::class => static function (Container $container) {
@@ -95,7 +95,7 @@ public function __construct(Composer $composer, IOInterface $io)
$container->get(IOInterface::class),
$container->get(Composer::class),
$container->get(Lock::class),
- new PathClassLoader()
+ new ClassLoader()
);
},
Configurator::class => static function (Container $container) {
@@ -150,8 +150,8 @@ public function __construct(Composer $composer, IOInterface $io)
$container->get('composer-extra')
);
- $scriptExecutor->addExtender(ScriptExtender::class);
- $scriptExecutor->addExtender(PhpScriptExtender::class);
+ $scriptExecutor->addExtender(ScriptExtender::getType(), ScriptExtender::class);
+ $scriptExecutor->addExtender(PhpScriptExtender::getType(),PhpScriptExtender::class);
return $scriptExecutor;
},
diff --git a/src/Automatic/Installer/AbstractInstaller.php b/src/Automatic/Installer/AbstractInstaller.php
index f8c86177..11ba58aa 100644
--- a/src/Automatic/Installer/AbstractInstaller.php
+++ b/src/Automatic/Installer/AbstractInstaller.php
@@ -8,9 +8,9 @@
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Narrowspark\Automatic\Automatic;
+use Narrowspark\Automatic\ClassLoader;
use Narrowspark\Automatic\Common\Contract\Exception\UnexpectedValueException;
use Narrowspark\Automatic\Lock;
-use Narrowspark\Automatic\PathClassLoader;
abstract class AbstractInstaller extends LibraryInstaller
{
@@ -34,19 +34,19 @@ abstract class AbstractInstaller extends LibraryInstaller
/**
* A path class loader instance.
*
- * @var \Narrowspark\Automatic\PathClassLoader
+ * @var \Narrowspark\Automatic\ClassLoader
*/
protected $loader;
/**
* Create a new Installer instance.
*
- * @param \Composer\IO\IOInterface $io
- * @param \Composer\Composer $composer
- * @param \Narrowspark\Automatic\Lock $lock
- * @param \Narrowspark\Automatic\PathClassLoader $loader
+ * @param \Composer\IO\IOInterface $io
+ * @param \Composer\Composer $composer
+ * @param \Narrowspark\Automatic\Lock $lock
+ * @param \Narrowspark\Automatic\ClassLoader $loader
*/
- public function __construct(IOInterface $io, Composer $composer, Lock $lock, PathClassLoader $loader)
+ public function __construct(IOInterface $io, Composer $composer, Lock $lock, ClassLoader $loader)
{
parent::__construct($io, $composer, static::TYPE);
@@ -124,10 +124,17 @@ protected function findClasses(array $autoload, PackageInterface $package): ?arr
{
$name = $package->getPrettyName();
$classes = [];
-
- $psr4 = \array_map(function ($path) use ($name) {
- return \rtrim(\rtrim($this->vendorDir, '/') . \DIRECTORY_SEPARATOR . $name . \DIRECTORY_SEPARATOR . $path, '/');
- }, (array) $autoload['psr-4']);
+ $psr4 = [];
+
+ foreach ((array) $autoload['psr-4'] as $path) {
+ if (\is_array($path)) {
+ foreach ($path as $p) {
+ $psr4[] = \rtrim($this->vendorDir . \DIRECTORY_SEPARATOR . $name . \DIRECTORY_SEPARATOR . $p, '/');
+ }
+ } else {
+ $psr4[] = \rtrim($this->vendorDir . \DIRECTORY_SEPARATOR . $name . \DIRECTORY_SEPARATOR . $path, '/');
+ }
+ }
$this->loader->find($psr4);
diff --git a/src/Automatic/Lock.php b/src/Automatic/Lock.php
index 205cf1d1..ab91e9d3 100644
--- a/src/Automatic/Lock.php
+++ b/src/Automatic/Lock.php
@@ -3,8 +3,9 @@
namespace Narrowspark\Automatic;
use Composer\Json\JsonFile;
+use Narrowspark\Automatic\Common\Contract\Resettable as ResettableContract;
-class Lock
+class Lock implements ResettableContract
{
/**
* Instance of JsonFile.
@@ -141,7 +142,7 @@ public function write(): void
$this->json->write($this->lock);
- $this->clear();
+ $this->reset();
}
/**
@@ -159,11 +160,9 @@ public function read(): array
}
/**
- * Clear the lock.
- *
- * @return void
+ * {@inheritdoc}
*/
- public function clear(): void
+ public function reset(): void
{
$this->lock = [];
}
diff --git a/src/Automatic/ScriptExecutor.php b/src/Automatic/ScriptExecutor.php
index 25594faa..c25dd82f 100644
--- a/src/Automatic/ScriptExecutor.php
+++ b/src/Automatic/ScriptExecutor.php
@@ -6,6 +6,8 @@
use Composer\EventDispatcher\ScriptExecutionException;
use Composer\IO\IOInterface;
use Composer\Util\ProcessExecutor;
+use Narrowspark\Automatic\Common\Contract\Exception\InvalidArgumentException;
+use Narrowspark\Automatic\Common\Contract\ScriptExtender as ScriptExtenderContract;
use Narrowspark\Automatic\Common\Traits\ExpandTargetDirTrait;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
@@ -47,7 +49,7 @@ final class ScriptExecutor
/**
* A list of the registered extenders.
*
- * @var \Narrowspark\Automatic\Common\Contract\ScriptExtender[]
+ * @var string[]
*/
private $extenders = [];
@@ -59,8 +61,12 @@ final class ScriptExecutor
* @param \Composer\Util\ProcessExecutor $executor
* @param array $options
*/
- public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $executor, array $options)
- {
+ public function __construct(
+ Composer $composer,
+ IOInterface $io,
+ ProcessExecutor $executor,
+ array $options
+ ) {
$this->composer = $composer;
$this->io = $io;
$this->executor = $executor;
@@ -70,14 +76,22 @@ public function __construct(Composer $composer, IOInterface $io, ProcessExecutor
/**
* Register a cmd extender.
*
+ * @param string $name
* @param string $extender
*
* @return void
*/
- public function addExtender(string $extender): void
+ public function addExtender(string $name, string $extender): void
{
- /** @var \Narrowspark\Automatic\Common\Contract\ScriptExtender $extender */
- $this->extenders[$extender::getType()] = new $extender($this->composer, $this->io, $this->options);
+ if (isset($this->extenders[$name])) {
+ throw new InvalidArgumentException(\sprintf('Script executor extender with the name [%s] already exists.', $name));
+ }
+
+ if (! \is_subclass_of($extender, ScriptExtenderContract::class)) {
+ throw new InvalidArgumentException(\sprintf('The class [%s] must implement the interface [%s].', $extender, ScriptExtenderContract::class));
+ }
+
+ $this->extenders[$name] = $extender;
}
/**
@@ -111,7 +125,10 @@ public function execute(string $type, string $cmd): void
$this->io->writeError(\sprintf('Executing script [%s]', $parsedCmd), $isVerbose);
- $exitCode = $this->executor->execute($this->extenders[$type]->expand($parsedCmd), $outputHandler);
+ /** @var \Narrowspark\Automatic\Common\Contract\ScriptExtender $extender */
+ $extender = new $this->extenders[$type]($this->composer, $this->io, $this->options);
+
+ $exitCode = $this->executor->execute($extender->expand($parsedCmd), $outputHandler);
if ($isVerbose) {
$this->io->writeError(\sprintf('Executed script [%s] %s', $cmd, $exitCode === 0 ? '[OK]' : '[KO]'));
diff --git a/src/Automatic/SkeletonGenerator.php b/src/Automatic/SkeletonGenerator.php
index 7c48ad4d..72975a54 100644
--- a/src/Automatic/SkeletonGenerator.php
+++ b/src/Automatic/SkeletonGenerator.php
@@ -74,9 +74,9 @@ public function __construct(
*
* @throws \Exception
*
- * @return void
+ * @return \Narrowspark\Automatic\SkeletonGenerator
*/
- public function run(): void
+ public function run(): self
{
$generators = $this->prepareGenerators();
@@ -114,6 +114,8 @@ public function run(): void
$this->installationManager->run();
$generator->generate();
+
+ return $this;
}
/**
@@ -123,7 +125,7 @@ public function run(): void
*
* @return void
*/
- public function remove(): void
+ public function selfRemove(): void
{
$requires = [];
diff --git a/src/Common/Contract/Resettable.php b/src/Common/Contract/Resettable.php
new file mode 100644
index 00000000..f2acae47
--- /dev/null
+++ b/src/Common/Contract/Resettable.php
@@ -0,0 +1,18 @@
+configurator->has(MockConfigurator::getName()));
- $this->configurator->clear();
+ $this->configurator->reset();
static::assertFalse($this->configurator->has(MockConfigurator::getName()));
}
diff --git a/tests/Automatic/PathClassLoaderTest.php b/tests/Automatic/ClassLoaderTest.php
similarity index 90%
rename from tests/Automatic/PathClassLoaderTest.php
rename to tests/Automatic/ClassLoaderTest.php
index 099c51f7..8d0558ec 100644
--- a/tests/Automatic/PathClassLoaderTest.php
+++ b/tests/Automatic/ClassLoaderTest.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Narrowspark\Automatic\Test;
-use Narrowspark\Automatic\PathClassLoader;
+use Narrowspark\Automatic\ClassLoader;
use Narrowspark\Automatic\Test\Fixture\Finder\AbstractClass;
use Narrowspark\Automatic\Test\Fixture\Finder\DummyClass;
use Narrowspark\Automatic\Test\Fixture\Finder\DummyClassTwo;
@@ -13,12 +13,12 @@
/**
* @internal
*/
-final class PathClassLoaderTest extends TestCase
+final class ClassLoaderTest extends TestCase
{
/**
* A path class loader instance.
*
- * @var \Narrowspark\Automatic\PathClassLoader
+ * @var \Narrowspark\Automatic\ClassLoader
*/
private $loader;
@@ -29,7 +29,7 @@ protected function setUp()
{
parent::setUp();
- $this->loader = new PathClassLoader();
+ $this->loader = new ClassLoader();
}
public function testItFindsAllClassesInDirectoryWithGivenNamespace(): void
diff --git a/tests/Automatic/Installer/AbstractInstallerTest.php b/tests/Automatic/Installer/AbstractInstallerTest.php
index dba486a3..306f6527 100644
--- a/tests/Automatic/Installer/AbstractInstallerTest.php
+++ b/tests/Automatic/Installer/AbstractInstallerTest.php
@@ -6,9 +6,9 @@
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Narrowspark\Automatic\Automatic;
+use Narrowspark\Automatic\ClassLoader;
use Narrowspark\Automatic\Common\Contract\Exception\UnexpectedValueException;
use Narrowspark\Automatic\Lock;
-use Narrowspark\Automatic\PathClassLoader;
use Narrowspark\Automatic\Test\Traits\ArrangeComposerClasses;
use Narrowspark\TestingHelper\Phpunit\MockeryTestCase;
@@ -95,7 +95,7 @@ protected function setUp(): void
->once()
->andReturn($this->downloadManagerMock);
- $this->configuratorInstaller = new $this->installerClass($this->ioMock, $this->composerMock, $this->lockMock, new PathClassLoader());
+ $this->configuratorInstaller = new $this->installerClass($this->ioMock, $this->composerMock, $this->lockMock, new ClassLoader());
$this->repositoryMock = $this->mock(InstalledRepositoryInterface::class);
$this->packageMock = $this->mock(PackageInterface::class);
diff --git a/tests/Automatic/SkeletonGeneratorTest.php b/tests/Automatic/SkeletonGeneratorTest.php
index b645b7e2..07b98923 100644
--- a/tests/Automatic/SkeletonGeneratorTest.php
+++ b/tests/Automatic/SkeletonGeneratorTest.php
@@ -163,7 +163,7 @@ public function testRemove(): void
$this->lockMock->shouldReceive('write')
->once();
- $this->skeletonGenerator->remove();
+ $this->skeletonGenerator->selfRemove();
}
/**