Преглед изворни кода

Merge remote-tracking branch 'schmunk42/feature-create-project-events'

Jordi Boggiano пре 12 година
родитељ
комит
4b22d7582a

+ 3 - 0
doc/03-cli.md

@@ -317,6 +317,9 @@ If the directory does not currently exist, it will be created during installatio
 
     php composer.phar create-project doctrine/orm path 2.2.0
 
+It is also possible to run the command without params in a directory with an
+existing `composer.json` file to bootstrap a project.
+
 By default the command checks for the packages on packagist.org.
 
 ### Options

+ 4 - 1
doc/articles/scripts.md

@@ -34,7 +34,10 @@ Composer fires the following named events during its execution process:
   during `install`/`update`, or via the `dump-autoload` command.
 - **post-autoload-dump**: occurs after the autoloader is dumped, either
   during `install`/`update`, or via the `dump-autoload` command.
-
+- **post-root-package-install**: occurs after the root package has been
+  installed, during the `create-project` command.
+- **post-create-project-cmd**: occurs after the `create-project` command is
+  executed.
 
 ## Defining scripts
 

+ 8 - 0
res/composer-schema.json

@@ -290,6 +290,14 @@
                 "post-autoload-dump": {
                     "type": ["array", "string"],
                     "description": "Occurs after the autoloader is dumped, contains one or more Class::method callables or shell commands."
+                },
+                "post-root-package-install": {
+                    "type": ["array", "string"],
+                    "description": "Occurs after the root-package is installed, contains one or more Class::method callables or shell commands."
+                },
+                "post-create-project-cmd": {
+                    "type": ["array", "string"],
+                    "description": "Occurs after the create-project command is executed, contains one or more Class::method callables or shell commands."
                 }
             }
         },

+ 87 - 64
src/Composer/Command/CreateProjectCommand.php

@@ -26,6 +26,7 @@ use Composer\Repository\ComposerRepository;
 use Composer\Repository\CompositeRepository;
 use Composer\Repository\FilesystemRepository;
 use Composer\Repository\InstalledFilesystemRepository;
+use Composer\Script\ScriptEvents;
 use Symfony\Component\Console\Input\InputArgument;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputOption;
@@ -42,6 +43,7 @@ use Composer\Package\Version\VersionParser;
  *
  * @author Benjamin Eberlei <kontakt@beberlei.de>
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Tobias Munk <schmunk@usrbin.de>
  */
 class CreateProjectCommand extends Command
 {
@@ -51,7 +53,7 @@ class CreateProjectCommand extends Command
             ->setName('create-project')
             ->setDescription('Create new project from a package into given directory.')
             ->setDefinition(array(
-                new InputArgument('package', InputArgument::REQUIRED, 'Package name to be installed'),
+                new InputArgument('package', InputArgument::OPTIONAL, 'Package name to be installed'),
                 new InputArgument('directory', InputArgument::OPTIONAL, 'Directory where the files should be created'),
                 new InputArgument('version', InputArgument::OPTIONAL, 'Version, will defaults to latest'),
                 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum-stability allowed (unless a version is specified).', 'stable'),
@@ -66,9 +68,11 @@ class CreateProjectCommand extends Command
             ))
             ->setHelp(<<<EOT
 The <info>create-project</info> command creates a new project from a given
-package into a new directory. You can use this command to bootstrap new
-projects or setup a clean version-controlled installation
-for developers of your project.
+package into a new directory. If executed without params and in a directory
+with a composer.json file it installs the packages for the current project.
+
+You can use this command to bootstrap new projects or setup a clean
+version-controlled installation for developers of your project.
 
 <info>php composer.phar create-project vendor/project target-directory [version]</info>
 
@@ -133,6 +137,84 @@ EOT
 
     public function installProject(IOInterface $io, $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disableCustomInstallers = false, $noScripts = false, $keepVcs = false, $noProgress = false)
     {
+        if ($packageName !== null) {
+            $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositoryUrl, $disableCustomInstallers, $noScripts, $keepVcs, $noProgress);
+        } else {
+            $installedFromVcs = false;
+        }
+
+        if ($noScripts === false) {
+            // dispatch event
+            $this->getComposer()->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages);
+        }
+        // install dependencies of the created project
+        $composer = Factory::create($io);
+        $installer = Installer::create($io, $composer);
+
+        $installer->setPreferSource($preferSource)
+            ->setPreferDist($preferDist)
+            ->setDevMode($installDevPackages)
+            ->setRunScripts( ! $noScripts);
+
+        if ($disableCustomInstallers) {
+            $installer->disableCustomInstallers();
+        }
+
+        if (!$installer->run()) {
+            return 1;
+        }
+
+        if ($noScripts === false) {
+            // dispatch event
+            $this->getComposer()->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages);
+        }
+
+        $hasVcs = $installedFromVcs;
+        if (!$keepVcs && $installedFromVcs
+            && (
+                !$io->isInteractive()
+                || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true)
+            )
+        ) {
+            $finder = new Finder();
+            $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false);
+            foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg') as $vcsName) {
+                $finder->name($vcsName);
+            }
+
+            try {
+                $fs = new Filesystem();
+                $dirs = iterator_to_array($finder);
+                unset($finder);
+                foreach ($dirs as $dir) {
+                    if (!$fs->removeDirectory($dir)) {
+                        throw new \RuntimeException('Could not remove '.$dir);
+                    }
+                }
+            } catch (\Exception $e) {
+                $io->write('<error>An error occurred while removing the VCS metadata: '.$e->getMessage().'</error>');
+            }
+
+            $hasVcs = false;
+        }
+
+        // rewriting self.version dependencies with explicit version numbers if the package's vcs metadata is gone
+        if (!$hasVcs) {
+            $package = $composer->getPackage();
+            $configSource = new JsonConfigSource(new JsonFile('composer.json'));
+            foreach (BasePackage::$supportedLinkTypes as $type => $meta) {
+                foreach ($package->{'get'.$meta['method']}() as $link) {
+                    if ($link->getPrettyConstraint() === 'self.version') {
+                        $configSource->addLink($type, $link->getTarget(), $package->getPrettyVersion());
+                    }
+                }
+            }
+        }
+
+        return 0;
+    }
+
+    protected function installRootPackage(IOInterface $io, $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disableCustomInstallers = false, $noScripts = false, $keepVcs = false, $noProgress = false) {
         $stability = strtolower($stability);
         if ($stability === 'rc') {
             $stability = 'RC';
@@ -219,66 +301,7 @@ EOT
         // clean up memory
         unset($dm, $im, $config, $projectInstaller, $sourceRepo, $package);
 
-        // install dependencies of the created project
-        $composer = Factory::create($io);
-        $installer = Installer::create($io, $composer);
-
-        $installer->setPreferSource($preferSource)
-            ->setPreferDist($preferDist)
-            ->setDevMode($installDevPackages)
-            ->setRunScripts( ! $noScripts);
-
-        if ($disableCustomInstallers) {
-            $installer->disableCustomInstallers();
-        }
-
-        if (!$installer->run()) {
-            return 1;
-        }
-
-        $hasVcs = $installedFromVcs;
-        if (!$keepVcs && $installedFromVcs
-            && (
-                !$io->isInteractive()
-                || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true)
-            )
-        ) {
-            $finder = new Finder();
-            $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false);
-            foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg') as $vcsName) {
-                $finder->name($vcsName);
-            }
-
-            try {
-                $fs = new Filesystem();
-                $dirs = iterator_to_array($finder);
-                unset($finder);
-                foreach ($dirs as $dir) {
-                    if (!$fs->removeDirectory($dir)) {
-                        throw new \RuntimeException('Could not remove '.$dir);
-                    }
-                }
-            } catch (\Exception $e) {
-                $io->write('<error>An error occurred while removing the VCS metadata: '.$e->getMessage().'</error>');
-            }
-
-            $hasVcs = false;
-        }
-
-        // rewriting self.version dependencies with explicit version numbers if the package's vcs metadata is gone
-        if (!$hasVcs) {
-            $package = $composer->getPackage();
-            $configSource = new JsonConfigSource(new JsonFile('composer.json'));
-            foreach (BasePackage::$supportedLinkTypes as $type => $meta) {
-                foreach ($package->{'get'.$meta['method']}() as $link) {
-                    if ($link->getPrettyConstraint() === 'self.version') {
-                        $configSource->addLink($type, $link->getTarget(), $package->getPrettyVersion());
-                    }
-                }
-            }
-        }
-
-        return 0;
+        return $installedFromVcs;
     }
 
     protected function createDownloadManager(IOInterface $io, Config $config)

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

@@ -127,4 +127,24 @@ class ScriptEvents
      * @var string
      */
     const POST_AUTOLOAD_DUMP = 'post-autoload-dump';
+
+    /**
+     * The POST_ROOT_PACKAGE_INSTALL event occurs after the root package has been installed.
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const POST_ROOT_PACKAGE_INSTALL = 'post-root-package-install';
+
+    /**
+     * The POST_CREATE_PROJECT event occurs after the create-project command has been executed.
+     * Note: Event occurs after POST_INSTALL_CMD
+     *
+     * The event listener method receives a Composer\Script\PackageEvent instance.
+     *
+     * @var string
+     */
+    const POST_CREATE_PROJECT_CMD = 'post-create-project-cmd';
+
 }