Add ability to call composer from scripts using @composer XXX, fixes #5153
parent
81df1b6cb0
commit
60ce2324bc
|
@ -216,3 +216,23 @@ one by prefixing the command name with `@`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Calling Composer commands
|
||||||
|
|
||||||
|
To call Composer commands, you can use `@composer` which will automatically
|
||||||
|
resolve to whatever composer.phar is currently being used:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"test": [
|
||||||
|
"@composer install",
|
||||||
|
"phpunit"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
One limitation of this is that you can not call multiple composer commands in
|
||||||
|
a row like `@composer install && @composer foo`. You must split them up in a
|
||||||
|
JSON array of commands.
|
||||||
|
|
|
@ -24,6 +24,7 @@ use Composer\Script;
|
||||||
use Composer\Script\CommandEvent;
|
use Composer\Script\CommandEvent;
|
||||||
use Composer\Script\PackageEvent;
|
use Composer\Script\PackageEvent;
|
||||||
use Composer\Util\ProcessExecutor;
|
use Composer\Util\ProcessExecutor;
|
||||||
|
use Symfony\Component\Process\PhpExecutableFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Event Dispatcher.
|
* The Event Dispatcher.
|
||||||
|
@ -172,10 +173,25 @@ class EventDispatcher
|
||||||
$scriptName = substr($callable, 1);
|
$scriptName = substr($callable, 1);
|
||||||
$args = $event->getArguments();
|
$args = $event->getArguments();
|
||||||
$flags = $event->getFlags();
|
$flags = $event->getFlags();
|
||||||
if (!$this->getListeners(new Event($scriptName))) {
|
if (substr($callable, 0, 10) === '@composer ') {
|
||||||
$this->io->writeError(sprintf('<warning>You made a reference to a non-existent script %s</warning>', $callable));
|
$finder = new PhpExecutableFinder();
|
||||||
|
$phpPath = $finder->find();
|
||||||
|
if (!$phpPath) {
|
||||||
|
throw new \RuntimeException('Failed to locate PHP binary to execute '.$scriptName);
|
||||||
|
}
|
||||||
|
$exec = $phpPath . ' ' . realpath($_SERVER['argv'][0]) . substr($callable, 9);
|
||||||
|
if (0 !== ($exitCode = $this->process->execute($exec))) {
|
||||||
|
$this->io->writeError(sprintf('<error>Script %s handling the %s event returned with an error</error>', $callable, $event->getName()));
|
||||||
|
|
||||||
|
throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$this->getListeners(new Event($scriptName))) {
|
||||||
|
$this->io->writeError(sprintf('<warning>You made a reference to a non-existent script %s</warning>', $callable));
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = $this->dispatch($scriptName, new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags));
|
||||||
}
|
}
|
||||||
$return = $this->dispatch($scriptName, new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags));
|
|
||||||
} elseif ($this->isPhpScript($callable)) {
|
} elseif ($this->isPhpScript($callable)) {
|
||||||
$className = substr($callable, 0, strpos($callable, '::'));
|
$className = substr($callable, 0, strpos($callable, '::'));
|
||||||
$methodName = substr($callable, strpos($callable, '::') + 2);
|
$methodName = substr($callable, strpos($callable, '::') + 2);
|
||||||
|
|
|
@ -171,6 +171,9 @@ class ArrayLoader implements LoaderInterface
|
||||||
foreach ($config['scripts'] as $event => $listeners) {
|
foreach ($config['scripts'] as $event => $listeners) {
|
||||||
$config['scripts'][$event] = (array) $listeners;
|
$config['scripts'][$event] = (array) $listeners;
|
||||||
}
|
}
|
||||||
|
if (isset($config['scripts']['composer'])) {
|
||||||
|
trigger_error('The `composer` script name is reserved for internal use, please avoid defining it', E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
$package->setScripts($config['scripts']);
|
$package->setScripts($config['scripts']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue