185 lines
4.7 KiB
PHP
185 lines
4.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Bamarni\Composer\Bin;
|
|
|
|
use Bamarni\Composer\Bin\Command\BinCommand;
|
|
use Bamarni\Composer\Bin\CommandProvider as BamarniCommandProvider;
|
|
use Bamarni\Composer\Bin\Config\Config;
|
|
use Bamarni\Composer\Bin\Input\BinInputFactory;
|
|
use Composer\Composer;
|
|
use Composer\Console\Application;
|
|
use Composer\EventDispatcher\EventSubscriberInterface;
|
|
use Composer\IO\ConsoleIO;
|
|
use Composer\IO\IOInterface;
|
|
use Composer\Plugin\CommandEvent;
|
|
use Composer\Plugin\PluginEvents;
|
|
use Composer\Plugin\PluginInterface;
|
|
use Composer\Plugin\Capable;
|
|
use Composer\Script\Event;
|
|
use Composer\Script\ScriptEvents;
|
|
use Symfony\Component\Console\Command\Command;
|
|
use Composer\Plugin\Capability\CommandProvider as ComposerPluginCommandProvider;
|
|
use Symfony\Component\Console\Input\InputInterface;
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
|
use Throwable;
|
|
use function count;
|
|
use function in_array;
|
|
use function sprintf;
|
|
|
|
/**
|
|
* @final Will be final in 2.x.
|
|
*/
|
|
class BamarniBinPlugin implements PluginInterface, Capable, EventSubscriberInterface
|
|
{
|
|
private const FORWARDED_COMMANDS = ['install', 'update'];
|
|
|
|
/**
|
|
* @var Composer
|
|
*/
|
|
protected $composer;
|
|
|
|
/**
|
|
* @var IOInterface
|
|
*/
|
|
protected $io;
|
|
|
|
/**
|
|
* @var Logger
|
|
*/
|
|
private $logger;
|
|
|
|
private $forwarded = false;
|
|
|
|
public function activate(Composer $composer, IOInterface $io): void
|
|
{
|
|
$this->composer = $composer;
|
|
$this->io = $io;
|
|
$this->logger = new Logger($io);
|
|
}
|
|
|
|
public function getCapabilities(): array
|
|
{
|
|
return [
|
|
ComposerPluginCommandProvider::class => BamarniCommandProvider::class,
|
|
];
|
|
}
|
|
|
|
public function deactivate(Composer $composer, IOInterface $io): void
|
|
{
|
|
}
|
|
|
|
public function uninstall(Composer $composer, IOInterface $io): void
|
|
{
|
|
}
|
|
|
|
public static function getSubscribedEvents(): array
|
|
{
|
|
return [
|
|
PluginEvents::COMMAND => 'onCommandEvent',
|
|
ScriptEvents::POST_AUTOLOAD_DUMP => 'onPostAutoloadDump',
|
|
];
|
|
}
|
|
|
|
public function onPostAutoloadDump(Event $event): void
|
|
{
|
|
$this->logger->logDebug('Calling onPostAutoloadDump().');
|
|
|
|
$eventIO = $event->getIO();
|
|
|
|
if (!($eventIO instanceof ConsoleIO)) {
|
|
return;
|
|
}
|
|
|
|
// This is a bit convoluted but Event does not expose the input unlike
|
|
// CommandEvent.
|
|
$publicIO = PublicIO::fromConsoleIO($eventIO);
|
|
$eventInput = $publicIO->getInput();
|
|
|
|
$this->onEvent(
|
|
$eventInput->getArgument('command'),
|
|
$eventInput,
|
|
$publicIO->getOutput()
|
|
);
|
|
}
|
|
|
|
public function onCommandEvent(CommandEvent $event): bool
|
|
{
|
|
$this->logger->logDebug('Calling onCommandEvent().');
|
|
|
|
return $this->onEvent(
|
|
$event->getCommandName(),
|
|
$event->getInput(),
|
|
$event->getOutput()
|
|
);
|
|
}
|
|
|
|
private function onEvent(
|
|
string $commandName,
|
|
InputInterface $input,
|
|
OutputInterface $output
|
|
): bool {
|
|
$config = Config::fromComposer($this->composer);
|
|
|
|
$deprecations = $config->getDeprecations();
|
|
|
|
if (count($deprecations) > 0) {
|
|
foreach ($deprecations as $deprecation) {
|
|
$this->logger->logStandard($deprecation);
|
|
}
|
|
}
|
|
|
|
if ($config->isCommandForwarded()
|
|
&& in_array($commandName, self::FORWARDED_COMMANDS, true)
|
|
) {
|
|
return $this->onForwardedCommand($input, $output);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected function onForwardedCommand(
|
|
InputInterface $input,
|
|
OutputInterface $output
|
|
): bool {
|
|
if ($this->forwarded) {
|
|
$this->logger->logDebug('Command already forwarded within the process: skipping.');
|
|
|
|
return true;
|
|
}
|
|
|
|
$this->forwarded = true;
|
|
|
|
$this->logger->logStandard('The command is being forwarded.');
|
|
$this->logger->logDebug(
|
|
sprintf(
|
|
'Original input: <comment>%s</comment>.',
|
|
$input->__toString()
|
|
)
|
|
);
|
|
|
|
// Note that the input & output of $io should be the same as the event
|
|
// input & output.
|
|
$io = $this->io;
|
|
|
|
$application = new Application();
|
|
|
|
$command = new BinCommand();
|
|
$command->setComposer($this->composer);
|
|
$command->setApplication($application);
|
|
$command->setIO($io);
|
|
|
|
$forwardedCommandInput = BinInputFactory::createForwardedCommandInput($input);
|
|
|
|
try {
|
|
return Command::SUCCESS === $command->run(
|
|
$forwardedCommandInput,
|
|
$output
|
|
);
|
|
} catch (Throwable $throwable) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|