diff --git a/doc/03-cli.md b/doc/03-cli.md index f179e4720..bfef27c55 100644 --- a/doc/03-cli.md +++ b/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 diff --git a/doc/articles/scripts.md b/doc/articles/scripts.md index 0c5d85343..7e6f9f41b 100644 --- a/doc/articles/scripts.md +++ b/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 diff --git a/res/composer-schema.json b/res/composer-schema.json index 972d01dac..343b1bf9f 100644 --- a/res/composer-schema.json +++ b/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." } } }, diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 59cd51fa7..d56c33328 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/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 * @author Jordi Boggiano + * @author Tobias Munk */ 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(<<create-project 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. php composer.phar create-project vendor/project target-directory [version] @@ -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('Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? ', 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('An error occurred while removing the VCS metadata: '.$e->getMessage().''); + } + + $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('Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? ', 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('An error occurred while removing the VCS metadata: '.$e->getMessage().''); - } - - $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) diff --git a/src/Composer/Script/ScriptEvents.php b/src/Composer/Script/ScriptEvents.php index 377c56a67..0a608e301 100644 --- a/src/Composer/Script/ScriptEvents.php +++ b/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'; + }