瀏覽代碼

Refactor scripts

Jordi Boggiano 13 年之前
父節點
當前提交
7add1001ae

+ 9 - 7
src/Composer/Command/InstallCommand.php

@@ -12,8 +12,8 @@
 
 namespace Composer\Command;
 
-use Composer\Trigger\TriggerEvents;
-use Composer\Trigger\TriggerDispatcher;
+use Composer\Script\ScriptEvents;
+use Composer\Script\EventDispatcher;
 use Composer\Autoload\AutoloadGenerator;
 use Composer\DependencyResolver;
 use Composer\DependencyResolver\Pool;
@@ -68,7 +68,7 @@ EOT
         $verbose = $dryRun || $input->getOption('verbose');
         $composer = $this->getComposer();
         $io = $this->getApplication()->getIO();
-        $dispatcher = new TriggerDispatcher($this->getComposer(), $io);
+        $dispatcher = new EventDispatcher($this->getComposer(), $io);
 
         if ($preferSource) {
             $composer->getDownloadManager()->setPreferSource(true);
@@ -88,8 +88,8 @@ EOT
 
         // dispatch pre event
         if (!$dryRun) {
-            $eventName = $update ? TriggerEvents::PRE_UPDATE : TriggerEvents::PRE_INSTALL;
-            $dispatcher->dispatch($eventName);
+            $eventName = $update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
+            $dispatcher->dispatchCommandEvent($eventName);
         }
 
         // creating requirements request
@@ -172,7 +172,9 @@ EOT
                 $output->writeln((string) $operation);
             }
             if (!$dryRun) {
+                $dispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
                 $installationManager->execute($operation);
+                $dispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation);
             }
         }
 
@@ -189,8 +191,8 @@ EOT
             $generator->dump($localRepo, $composer->getPackage(), $installationManager, $installationManager->getVendorPath().'/.composer');
 
             // dispatch post event
-            $eventName = $update ? TriggerEvents::POST_UPDATE : TriggerEvents::POST_INSTALL;
-            $dispatcher->dispatch($eventName);
+            $eventName = $update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
+            $dispatcher->dispatchCommandEvent($eventName);
         }
     }
 

+ 17 - 0
src/Composer/Package/MemoryPackage.php

@@ -40,6 +40,7 @@ class MemoryPackage extends BasePackage
     protected $homepage;
     protected $extra = array();
     protected $binaries = array();
+    protected $scripts = array();
 
     protected $requires = array();
     protected $conflicts = array();
@@ -128,6 +129,22 @@ class MemoryPackage extends BasePackage
         return $this->binaries;
     }
 
+    /**
+     * @param array $scripts
+     */
+    public function setScripts(array $scripts)
+    {
+        $this->scripts = $scripts;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getScripts()
+    {
+        return $this->scripts;
+    }
+
     /**
      * {@inheritDoc}
      */

+ 7 - 0
src/Composer/Package/PackageInterface.php

@@ -152,6 +152,13 @@ interface PackageInterface
      */
     function getDistSha1Checksum();
 
+    /**
+     * Returns the scripts of this package
+     *
+     * @return array array('script name' => array('listeners'))
+     */
+    function getScripts();
+
     /**
      * Returns the version of this package
      *

+ 26 - 0
src/Composer/Script/CommandEvent.php

@@ -0,0 +1,26 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Script;
+
+use Composer\Composer;
+use Composer\IO\IOInterface;
+use Composer\Package\PackageInterface;
+
+/**
+ * The Command Event.
+ *
+ * @author François Pluchino <francois.pluchino@opendisplay.com>
+ */
+class CommandEvent extends Event
+{
+}

+ 83 - 83
src/Composer/Trigger/TriggerEvent.php → src/Composer/Script/Event.php

@@ -1,83 +1,83 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Trigger;
-
-use Composer\Composer;
-use Composer\IO\IOInterface;
-
-/**
- * The Trigger Event.
- *
- * @author François Pluchino <francois.pluchino@opendisplay.com>
- */
-class TriggerEvent
-{
-    /**
-     * @var string This event's name
-     */
-    private $name;
-
-    /**
-     * @var Composer The composer instance
-     */
-    private $composer;
-
-    /**
-     * @var IOInterface The IO instance
-     */
-    private $io;
-
-    /**
-     * Constructor.
-     *
-     * @param string      $name     The event name
-     * @param Composer    $composer The composer objet
-     * @param IOInterface $io       The IOInterface object
-     */
-    public function __construct($name, Composer $composer, IOInterface $io)
-    {
-        $this->name = $name;
-        $this->composer = $composer;
-        $this->io = $io;
-    }
-
-    /**
-     * Returns the event's name.
-     *
-     * @return string The event name
-     */
-    public function getName()
-    {
-        return $this->name;
-    }
-
-    /**
-     * Returns the composer instance.
-     *
-     * @return Composer
-     */
-    public function getComposer()
-    {
-        return $this->composer;
-    }
-
-    /**
-     * Returns the IO instance.
-     *
-     * @return IOInterface
-     */
-    public function getIO()
-    {
-        return $this->io;
-    }
-}
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Script;
+
+use Composer\Composer;
+use Composer\IO\IOInterface;
+
+/**
+ * The base event class
+ *
+ * @author François Pluchino <francois.pluchino@opendisplay.com>
+ */
+class Event
+{
+    /**
+     * @var string This event's name
+     */
+    private $name;
+
+    /**
+     * @var Composer The composer instance
+     */
+    private $composer;
+
+    /**
+     * @var IOInterface The IO instance
+     */
+    private $io;
+
+    /**
+     * Constructor.
+     *
+     * @param string      $name     The event name
+     * @param Composer    $composer The composer objet
+     * @param IOInterface $io       The IOInterface object
+     */
+    public function __construct($name, Composer $composer, IOInterface $io)
+    {
+        $this->name = $name;
+        $this->composer = $composer;
+        $this->io = $io;
+    }
+
+    /**
+     * Returns the event's name.
+     *
+     * @return string The event name
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Returns the composer instance.
+     *
+     * @return Composer
+     */
+    public function getComposer()
+    {
+        return $this->composer;
+    }
+
+    /**
+     * Returns the IO instance.
+     *
+     * @return IOInterface
+     */
+    public function getIO()
+    {
+        return $this->io;
+    }
+}

+ 120 - 0
src/Composer/Script/EventDispatcher.php

@@ -0,0 +1,120 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Script;
+
+use Composer\Json\JsonFile;
+use Composer\Repository\FilesystemRepository;
+use Composer\Autoload\ClassLoader;
+use Composer\Package\PackageInterface;
+use Composer\IO\IOInterface;
+use Composer\Composer;
+use Composer\DependencyResolver\Operation\OperationInterface;
+
+/**
+ * The Event Dispatcher.
+ *
+ * Example in command:
+ *     $dispatcher = new EventDispatcher($this->getComposer(), $this->getApplication()->getIO());
+ *     // ...
+ *     $dispatcher->dispatch(ScriptEvents::POST_INSTALL_CMD);
+ *     // ...
+ *
+ * @author François Pluchino <francois.pluchino@opendisplay.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class EventDispatcher
+{
+    protected $composer;
+    protected $io;
+    protected $loader;
+
+    /**
+     * Constructor.
+     *
+     * @param Composer    $composer The composer instance
+     * @param IOInterface $io       The IOInterface instance
+     */
+    public function __construct(Composer $composer, IOInterface $io)
+    {
+        $this->composer = $composer;
+        $this->io = $io;
+        $this->loader = new ClassLoader();
+        $this->loader->register();
+    }
+
+    /**
+     * Dispatch a package event.
+     *
+     * @param string $eventName The constant in ScriptEvents
+     * @param OperationInterface $operation The package being installed/updated/removed
+     */
+    public function dispatchPackageEvent($eventName, OperationInterface $operation)
+    {
+        $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $operation));
+    }
+
+    /**
+     * Dispatch a command event.
+     *
+     * @param string $eventName The constant in ScriptEvents
+     */
+    public function dispatchCommandEvent($eventName)
+    {
+        $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io));
+    }
+
+    /**
+     * Triggers the listeners of an event.
+     *
+     * @param Event $event The event object to pass to the event handlers/listeners.
+     */
+    protected function doDispatch(Event $event)
+    {
+        $listeners = $this->getListeners($event);
+
+        foreach ($listeners as $callable) {
+            $className = substr($callable, 0, strpos($callable, '::'));
+            $methodName = substr($callable, strpos($callable, '::') + 2);
+
+            if (!class_exists($className)) {
+                throw new \UnexpectedValueException('Class '.$className.' is not autoloadable, can not call '.$event->getName().' script');
+            }
+            if (!is_callable($callable)) {
+                throw new \UnexpectedValueException('Method '.$callable.' is not callable, can not call '.$event->getName().' script');
+            }
+
+            $className::$methodName($event);
+        }
+    }
+
+    /**
+     * @param Event $event Event object
+     * @return array Listeners
+     */
+    protected function getListeners(Event $event)
+    {
+        $package = $this->composer->getPackage();
+        $scripts = $package->getScripts();
+        $autoload = $package->getAutoload();
+
+        // get namespaces in composer.json project
+        if (!$this->loader->getPrefixes() && isset($autoload['psr-0'])) {
+            krsort($autoload['psr-0']);
+            foreach ($autoload['psr-0'] as $ns => $path) {
+                $this->loader->add($ns, rtrim(getcwd().'/'.$path, '/'));
+            }
+        }
+
+        return isset($scripts[$event->getName()]) ? $scripts[$event->getName()] : array();
+    }
+}

+ 54 - 0
src/Composer/Script/PackageEvent.php

@@ -0,0 +1,54 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Script;
+
+use Composer\Composer;
+use Composer\IO\IOInterface;
+use Composer\DependencyResolver\Operation\OperationInterface;
+
+/**
+ * The Package Event.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class PackageEvent extends Event
+{
+    /**
+     * @var OperationInterface The package instance
+     */
+    private $operation;
+
+    /**
+     * Constructor.
+     *
+     * @param string      $name     The event name
+     * @param Composer    $composer The composer objet
+     * @param IOInterface $io       The IOInterface object
+     * @param OperationInterface $operation The operation object
+     */
+    public function __construct($name, Composer $composer, IOInterface $io, OperationInterface $operation)
+    {
+        parent::__construct($name, $composer, $io);
+        $this->operation = $operation;
+    }
+
+    /**
+     * Returns the package instance.
+     *
+     * @return OperationInterface
+     */
+    public function getOperation()
+    {
+        return $this->operation;
+    }
+}

+ 112 - 0
src/Composer/Script/ScriptEvents.php

@@ -0,0 +1,112 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Script;
+
+/**
+ * The Script Events.
+ *
+ * @author François Pluchino <francois.pluchino@opendisplay.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class ScriptEvents
+{
+    /**
+     * The PRE_INSTALL_CMD event occurs before the install command is executed.
+     *
+     * The event listener method receives a Composer\Script\CommandEvent instance.
+     *
+     * @var string
+     */
+    const PRE_INSTALL_CMD = 'pre-install-cmd';
+
+    /**
+     * The POST_INSTALL_CMD event occurs after the install command is executed.
+     *
+     * The event listener method receives a Composer\Script\CommandEvent instance.
+     *
+     * @var string
+     */
+    const POST_INSTALL_CMD = 'post-install-cmd';
+
+    /**
+     * The PRE_UPDATE_CMD event occurs before the update command is executed.
+     *
+     * The event listener method receives a Composer\Script\CommandEvent instance.
+     *
+     * @var string
+     */
+    const PRE_UPDATE_CMD = 'pre-update-cmd';
+
+    /**
+     * The POST_UPDATE_CMD event occurs after the update command is executed.
+     *
+     * The event listener method receives a Composer\Script\CommandEvent instance.
+     *
+     * @var string
+     */
+    const POST_UPDATE_CMD = 'post-update-cmd';
+
+    /**
+     * The PRE_PACKAGE_INSTALL event occurs before a package is installed.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const PRE_PACKAGE_INSTALL = 'pre-package-install';
+
+    /**
+     * The POST_PACKAGE_INSTALL event occurs after a package is installed.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const POST_PACKAGE_INSTALL = 'post-package-install';
+
+    /**
+     * The PRE_PACKAGE_UPDATE event occurs before a package is updated.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const PRE_PACKAGE_UPDATE = 'pre-package-update';
+
+    /**
+     * The POST_PACKAGE_UPDATE event occurs after a package is updated.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const POST_PACKAGE_UPDATE = 'post-package-update';
+
+    /**
+     * The PRE_PACKAGE_UNINSTALL event occurs before a package has been uninstalled.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
+
+    /**
+     * The POST_PACKAGE_UNINSTALL event occurs after a package has been uninstalled.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
+}

+ 0 - 147
src/Composer/Trigger/TriggerDispatcher.php

@@ -1,147 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Trigger;
-
-use Composer\Json\JsonFile;
-use Composer\Repository\FilesystemRepository;
-use Composer\Autoload\ClassLoader;
-use Composer\Package\PackageInterface;
-use Composer\IO\IOInterface;
-use Composer\Composer;
-
-/**
- * The Trigger Dispatcher.
- *
- * Example in command:
- *     $dispatcher = new TriggerDispatcher($this->getComposer(), $this->getApplication()->getIO());
- *     // ...
- *     $dispatcher->dispatch(TriggerEvents::POST_INSTALL);
- *     // ...
- *
- * @author François Pluchino <francois.pluchino@opendisplay.com>
- */
-class TriggerDispatcher
-{
-    protected $composer;
-    protected $io;
-    protected $loader;
-
-    /**
-     * Constructor.
-     *
-     * @param Composer    $composer The composer instance
-     * @param IOInterface $io       The IOInterface instance
-     */
-    public function __construct(Composer $composer, IOInterface $io)
-    {
-        $this->composer = $composer;
-        $this->io = $io;
-        $this->loader = new ClassLoader();
-    }
-
-    /**
-     * Dispatch the event.
-     *
-     * @param string $eventName The constant in TriggerEvents
-     */
-    public function dispatch($eventName)
-    {
-        $event = new TriggerEvent($eventName, $this->composer, $this->io);
-
-        $this->doDispatch($event);
-    }
-
-    /**
-     * Triggers the listeners of an event.
-     *
-     * @param TriggerEvent $event The event object to pass to the event handlers/listeners.
-     */
-    protected function doDispatch(TriggerEvent $event)
-    {
-        $listeners = $this->getListeners($event);
-
-        foreach ($listeners as $method) {
-            $className = substr($method, 0, strpos($method, '::'));
-            $methodName = substr($method, strpos($method, '::') + 2);
-
-            try {
-                $refMethod = new \ReflectionMethod($className, $methodName);
-
-                // execute only if all conditions are validates
-                if ($refMethod->isPublic()
-                        && $refMethod->isStatic()
-                        && !$refMethod->isAbstract()
-                        && 1 === $refMethod->getNumberOfParameters()) {
-                    $className::$methodName($event);
-                }
-
-            } catch (\ReflectionException $ex) {}//silent execpetion
-        }
-    }
-
-    /**
-     * Register namespaces in ClassLoader.
-     *
-     * @param TriggerEvent $event The event object
-     *
-     * @return array The listener classes with event type
-     */
-    protected function getListeners(TriggerEvent $event)
-    {
-        $package = $this->composer->getPackage();
-        $vendorDir = $this->composer->getInstallationManager()->getVendorPath(true);
-        $autoloadFile = $vendorDir . '/.composer/autoload.php';
-        $ex = $package->getExtra();
-        $al = $package->getAutoload();
-        $searchListeners = array();
-        $listeners = array();
-        $namespaces = array();
-
-        // get classes
-        if (isset($ex['triggers'][$event->getName()])) {
-            foreach ($ex['triggers'][$event->getName()] as $method) {
-                $searchListeners[] = $method;
-            }
-        }
-
-        // get autoload namespaces
-        if (file_exists($autoloadFile)) {
-            $this->loader = require $autoloadFile;
-        }
-
-        $namespaces = $this->loader->getPrefixes();
-
-        // get namespaces in composer.json project
-        if (isset($al['psr-0'])) {
-            foreach ($al['psr-0'] as $ns => $path) {
-                if (!isset($namespaces[str_replace('\\', '\\\\', $ns)])) {
-                    $this->loader->add($ns, trim(realpath('.').'/'.$path, '/'));
-                }
-            }
-
-            $this->loader->register();
-            $namespaces = $this->loader->getPrefixes();
-        }
-
-        // filter class::method have not a namespace registered
-        foreach ($namespaces as $ns => $path) {
-            foreach ($searchListeners as $method) {
-                if (0 === strpos($method, $ns)) {
-                    $listeners[] = $method;
-                }
-            }
-        }
-
-        return $listeners;
-    }
-}

+ 0 - 89
src/Composer/Trigger/TriggerEvents.php

@@ -1,89 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Trigger;
-
-/**
- * The Trigger Events.
- *
- * @author François Pluchino <francois.pluchino@opendisplay.com>
- */
-class TriggerEvents
-{
-    /**
-     * The PRE_INSTALL event occurs at begging installation packages.
-     *
-     * This event allows you to execute a trigger before any other code in the
-     * composer is executed. The event listener method receives a
-     * Composer\Trigger\GetTriggerEvent instance.
-     *
-     * @var string
-     */
-    const PRE_INSTALL = 'pre_install';
-
-    /**
-     * The POST_INSTALL event occurs at end installation packages.
-     *
-     * This event allows you to execute a trigger after any other code in the
-     * composer is executed. The event listener method receives a
-     * Composer\Trigger\GetTriggerEvent instance.
-     *
-     * @var string
-     */
-    const POST_INSTALL = 'post_install';
-
-    /**
-     * The PRE_UPDATE event occurs at begging update packages.
-     *
-     * This event allows you to execute a trigger before any other code in the
-     * composer is executed. The event listener method receives a
-     * Composer\Trigger\GetTriggerEvent instance.
-     *
-     * @var string
-     */
-    const PRE_UPDATE = 'pre_update';
-
-    /**
-     * The POST_UPDATE event occurs at end update packages.
-     *
-     * This event allows you to execute a trigger after any other code in the
-     * composer is executed. The event listener method receives a
-     * Composer\Trigger\GetTriggerEvent instance.
-     *
-     * @var string
-     */
-    const POST_UPDATE = 'post_update';
-
-    /**
-     * The PRE_UNINSTALL event occurs at begging uninstallation packages.
-     *
-     * This event allows you to execute a trigger after any other code in the
-     * composer is executed. The event listener method receives a
-     * Composer\Trigger\TriggerEvent instance.
-     *
-     * @var string
-     */
-    const PRE_UNINSTALL = 'pre_uninstall';
-    //TODO add the dispatcher when the uninstall command will be doing
-
-    /**
-     * The PRE_UNINSTALL event occurs at end uninstallation packages.
-     *
-     * This event allows you to execute a trigger after any other code in the
-     * composer is executed. The event listener method receives a
-     * Composer\Trigger\TriggerEvent instance.
-     *
-     * @var string
-     */
-    const POST_UNINSTALL = 'post_uninstall';
-    //TODO add the dispatcher when the uninstall command will be doing
-}