diff --git a/bin/composer b/bin/composer index 823f87a4b..88566e170 100755 --- a/bin/composer +++ b/bin/composer @@ -48,6 +48,8 @@ if (function_exists('ini_set')) { unset($memoryInBytes, $memoryLimit); } +putenv('COMPOSER_BINARY='.realpath($_SERVER['argv'][0])); + // run the command application $application = new Application(); $application->run(null, $output); diff --git a/doc/05-repositories.md b/doc/05-repositories.md index 732198bf0..a85f31d1a 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -58,7 +58,7 @@ The main repository type is the `composer` repository. It uses a single This is also the repository type that packagist uses. To reference a `composer` repository, just supply the path before the `packages.json` file. -In case of packagist, that file is located at `/packages.json`, so the URL of +In the case of packagist, that file is located at `/packages.json`, so the URL of the repository would be `packagist.org`. For `example.org/packages.json` the repository URL would be `example.org`. diff --git a/src/Composer/Command/ArchiveCommand.php b/src/Composer/Command/ArchiveCommand.php index 419a7bfb4..b23e4df91 100644 --- a/src/Composer/Command/ArchiveCommand.php +++ b/src/Composer/Command/ArchiveCommand.php @@ -45,6 +45,7 @@ class ArchiveCommand extends BaseCommand new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'Write the archive to this directory'), new InputOption('file', null, InputOption::VALUE_REQUIRED, 'Write the archive with the given file name.' .' Note that the format will be appended.'), + new InputOption('ignore-filters', false, InputOption::VALUE_NONE, 'Ignore filters when saving package') )) ->setHelp(<<archive command creates an archive of the specified format @@ -82,7 +83,8 @@ EOT $input->getArgument('version'), $input->getOption('format'), $input->getOption('dir'), - $input->getOption('file') + $input->getOption('file'), + $input->getOption('ignore-filters') ); if (0 === $returnCode && $composer) { @@ -92,7 +94,7 @@ EOT return $returnCode; } - protected function archive(IOInterface $io, Config $config, $packageName = null, $version = null, $format = 'tar', $dest = '.', $fileName = null) + protected function archive(IOInterface $io, Config $config, $packageName = null, $version = null, $format = 'tar', $dest = '.', $fileName = null, $ignoreFilters) { $factory = new Factory; $downloadManager = $factory->createDownloadManager($io, $config); @@ -109,7 +111,7 @@ EOT } $io->writeError('Creating the archive into "'.$dest.'".'); - $packagePath = $archiveManager->archive($package, $format, $dest, $fileName); + $packagePath = $archiveManager->archive($package, $format, $dest, $fileName, $ignoreFilters); $fs = new Filesystem; $shortPath = $fs->findShortestPath(getcwd(), $packagePath, true); diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 796dbdeb9..4e443d337 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -23,6 +23,7 @@ use Composer\Package\BasePackage; use Composer\DependencyResolver\Pool; use Composer\DependencyResolver\Operation\InstallOperation; use Composer\Package\Version\VersionSelector; +use Composer\Package\AliasPackage; use Composer\Repository\RepositoryFactory; use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; @@ -330,6 +331,10 @@ EOT $io->writeError('Plugins have been disabled.'); } + if ($package instanceof AliasPackage) { + $package = $package->getAliasOf(); + } + if (0 === strpos($package->getPrettyVersion(), 'dev-') && in_array($package->getSourceType(), array('git', 'hg'))) { $package->setSourceReference(substr($package->getPrettyVersion(), 4)); } diff --git a/src/Composer/Command/OutdatedCommand.php b/src/Composer/Command/OutdatedCommand.php index 3b6808cd3..80a574455 100644 --- a/src/Composer/Command/OutdatedCommand.php +++ b/src/Composer/Command/OutdatedCommand.php @@ -39,13 +39,13 @@ class OutdatedCommand extends ShowCommand ->setHelp(<<green: Dependency is in the latest version and is up to date. -- yellow: Dependency has a new version available that includes backwards +- green (=): Dependency is in the latest version and is up to date. +- yellow (~): Dependency has a new version available that includes backwards compatibility breaks according to semver, so upgrade when you can but it may involve work. -- red: Dependency has a new version that is semver-compatible and you should upgrade it. +- red (!): Dependency has a new version that is semver-compatible and you should upgrade it. EOT diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 43e566fc2..b90ba2edc 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -173,7 +173,7 @@ EOT } $io->writeError('Package ' . $packageFilter . ' not found in ' . $options['working-dir'] . '/composer.json'); - return; + return 1; } } else { $versions = array($package->getPrettyVersion() => $package->getVersion()); @@ -317,6 +317,9 @@ EOT $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion && ($nameLength + $versionLength + 3 <= $width); $writeLatest = $writeVersion && $showLatest && ($nameLength + $versionLength + $latestLength + 3 <= $width); $writeDescription = !$input->getOption('name-only') && !$input->getOption('path') && ($nameLength + $versionLength + $latestLength + 24 <= $width); + if ($writeLatest && !$io->isDecorated()) { + $latestLength += 2; + } $hasOutdatedPackages = false; foreach ($packages[$type] as $package) { if (is_object($package)) { @@ -339,6 +342,9 @@ EOT if ($writeLatest && $latestPackackage) { $latestVersion = $latestPackackage->getFullPrettyVersion(); $style = $this->getVersionStyle($latestPackackage, $package); + if (!$io->isDecorated()) { + $latestVersion = str_replace(array('info', 'highlight', 'comment'), array('=', '!', '~'), $style) . ' ' . $latestVersion; + } $io->write(' <'.$style.'>' . str_pad($latestVersion, $latestLength, ' ') . '', false); } diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 892c0af9d..a2165ea76 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -166,7 +166,7 @@ class Application extends BaseApplication $io->writeError('Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.'); } - if (extension_loaded('xdebug') && (!getenv('COMPOSER_DISABLE_XDEBUG_WARN') || getenv('COMPOSER_ALLOW_XDEBUG'))) { + if (extension_loaded('xdebug') && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) { $io->writeError('You are running composer with xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug'); } diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index e6cc378a0..b74d34858 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -175,12 +175,7 @@ class EventDispatcher $args = $event->getArguments(); $flags = $event->getFlags(); if (substr($callable, 0, 10) === '@composer ') { - $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); + $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($callable, 9); if (0 !== ($exitCode = $this->process->execute($exec))) { $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName())); @@ -234,12 +229,7 @@ class EventDispatcher } if (substr($exec, 0, 5) === '@php ') { - $finder = new PhpExecutableFinder(); - $phpPath = $finder->find(); - if (!$phpPath) { - throw new \RuntimeException('Failed to locate PHP binary to execute "'.$exec.'"'); - } - $exec = $phpPath . ' ' . substr($exec, 5); + $exec = $this->getPhpExecCommand() . ' ' . substr($exec, 5); } if (0 !== ($exitCode = $this->process->execute($exec))) { @@ -259,6 +249,19 @@ class EventDispatcher return $return; } + protected function getPhpExecCommand() + { + $finder = new PhpExecutableFinder(); + $phpPath = $finder->find(); + if (!$phpPath) { + throw new \RuntimeException('Failed to locate PHP binary to execute '.$scriptName); + } + + $memoryFlag = ' -d memory_limit='.ini_get('memory_limit'); + + return ProcessExecutor::escape($phpPath) . $memoryFlag; + } + /** * @param string $className * @param string $methodName diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index ec8157456..9f6fa5d04 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -605,7 +605,7 @@ class Installer $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation); } - if ($this->executeOperations) { + if ($this->executeOperations || $this->writeLock) { $localRepo->write(); } } diff --git a/src/Composer/Package/Archiver/ArchivableFilesFinder.php b/src/Composer/Package/Archiver/ArchivableFilesFinder.php index f80724da7..e99f5343f 100644 --- a/src/Composer/Package/Archiver/ArchivableFilesFinder.php +++ b/src/Composer/Package/Archiver/ArchivableFilesFinder.php @@ -37,18 +37,23 @@ class ArchivableFilesFinder extends \FilterIterator * * @param string $sources Path to source files to be archived * @param array $excludes Composer's own exclude rules from composer.json + * @param boolean $ignoreFilters Ignore filters when looking for files */ - public function __construct($sources, array $excludes) + public function __construct($sources, array $excludes, $ignoreFilters = false) { $fs = new Filesystem(); $sources = $fs->normalizePath($sources); - $filters = array( - new HgExcludeFilter($sources), - new GitExcludeFilter($sources), - new ComposerExcludeFilter($sources, $excludes), - ); + if ($ignoreFilters) { + $filters = array(); + } else { + $filters = array( + new HgExcludeFilter($sources), + new GitExcludeFilter($sources), + new ComposerExcludeFilter($sources, $excludes), + ); + } $this->finder = new Finder(); diff --git a/src/Composer/Package/Archiver/ArchiveManager.php b/src/Composer/Package/Archiver/ArchiveManager.php index 52fe7bed3..e1558c1dd 100644 --- a/src/Composer/Package/Archiver/ArchiveManager.php +++ b/src/Composer/Package/Archiver/ArchiveManager.php @@ -99,11 +99,12 @@ class ArchiveManager * @param string $targetDir The directory where to build the archive * @param string|null $fileName The relative file name to use for the archive, or null to generate * the package name. Note that the format will be appended to this name + * @param boolean $ignoreFilters Ignore filters when looking for files in the package * @throws \InvalidArgumentException * @throws \RuntimeException * @return string The path of the created archive */ - public function archive(PackageInterface $package, $format, $targetDir, $fileName = null) + public function archive(PackageInterface $package, $format, $targetDir, $fileName = null, $ignoreFilters = false) { if (empty($format)) { throw new \InvalidArgumentException('Format must be specified'); @@ -163,7 +164,7 @@ class ArchiveManager $tempTarget = sys_get_temp_dir().'/composer_archive'.uniqid().'.'.$format; $filesystem->ensureDirectoryExists(dirname($tempTarget)); - $archivePath = $usableArchiver->archive($sourcePath, $tempTarget, $format, $package->getArchiveExcludes()); + $archivePath = $usableArchiver->archive($sourcePath, $tempTarget, $format, $package->getArchiveExcludes(), $ignoreFilters); $filesystem->rename($archivePath, $target); // cleanup temporary download diff --git a/src/Composer/Package/Archiver/ArchiverInterface.php b/src/Composer/Package/Archiver/ArchiverInterface.php index a625f5c07..4e5fa54f9 100644 --- a/src/Composer/Package/Archiver/ArchiverInterface.php +++ b/src/Composer/Package/Archiver/ArchiverInterface.php @@ -29,7 +29,7 @@ interface ArchiverInterface * * @return string The path to the written archive file */ - public function archive($sources, $target, $format, array $excludes = array()); + public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false); /** * Format supported by the archiver. diff --git a/src/Composer/Package/Archiver/PharArchiver.php b/src/Composer/Package/Archiver/PharArchiver.php index 5c9afe336..7f64c343e 100644 --- a/src/Composer/Package/Archiver/PharArchiver.php +++ b/src/Composer/Package/Archiver/PharArchiver.php @@ -34,7 +34,7 @@ class PharArchiver implements ArchiverInterface /** * {@inheritdoc} */ - public function archive($sources, $target, $format, array $excludes = array()) + public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false) { $sources = realpath($sources); @@ -53,7 +53,7 @@ class PharArchiver implements ArchiverInterface } $phar = new \PharData($target, null, null, static::$formats[$format]); - $files = new ArchivableFilesFinder($sources, $excludes); + $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters); $filesOnly = new ArchivableFilesFilter($files); $phar->buildFromIterator($filesOnly, $sources); $filesOnly->addEmptyDir($phar, $sources); diff --git a/src/Composer/Package/Archiver/ZipArchiver.php b/src/Composer/Package/Archiver/ZipArchiver.php index 87337558e..aaa41aea3 100644 --- a/src/Composer/Package/Archiver/ZipArchiver.php +++ b/src/Composer/Package/Archiver/ZipArchiver.php @@ -27,7 +27,7 @@ class ZipArchiver implements ArchiverInterface /** * {@inheritdoc} */ - public function archive($sources, $target, $format, array $excludes = array()) + public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false) { $fs = new Filesystem(); $sources = $fs->normalizePath($sources); @@ -35,7 +35,7 @@ class ZipArchiver implements ArchiverInterface $zip = new ZipArchive(); $res = $zip->open($target, ZipArchive::CREATE); if ($res === true) { - $files = new ArchivableFilesFinder($sources, $excludes); + $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters); foreach ($files as $file) { /** @var $file \SplFileInfo */ $filepath = strtr($file->getPath()."/".$file->getFilename(), '\\', '/'); diff --git a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php index 76629276d..669ec7a3f 100644 --- a/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchivableFilesFinderTest.php @@ -235,6 +235,61 @@ class ArchivableFilesFinderTest extends TestCase $this->assertArchivableFiles($expectedFiles); } + public function testSkipExcludes() + { + $excludes = array( + 'prefixB.foo', + ); + + $this->finder = new ArchivableFilesFinder($this->sources, $excludes, true); + + $this->assertArchivableFiles(array( + '/!important!.txt', + '/!important_too!.txt', + '/#weirdfile', + '/A/prefixA.foo', + '/A/prefixB.foo', + '/A/prefixC.foo', + '/A/prefixD.foo', + '/A/prefixE.foo', + '/A/prefixF.foo', + '/B/sub/prefixA.foo', + '/B/sub/prefixB.foo', + '/B/sub/prefixC.foo', + '/B/sub/prefixD.foo', + '/B/sub/prefixE.foo', + '/B/sub/prefixF.foo', + '/C/prefixA.foo', + '/C/prefixB.foo', + '/C/prefixC.foo', + '/C/prefixD.foo', + '/C/prefixE.foo', + '/C/prefixF.foo', + '/D/prefixA', + '/D/prefixB', + '/D/prefixC', + '/D/prefixD', + '/D/prefixE', + '/D/prefixF', + '/E/subtestA.foo', + '/F/subtestA.foo', + '/G/subtestA.foo', + '/H/subtestA.foo', + '/I/J/subtestA.foo', + '/K/dirJ/subtestA.foo', + '/parameters.yml', + '/parameters.yml.dist', + '/prefixA.foo', + '/prefixB.foo', + '/prefixC.foo', + '/prefixD.foo', + '/prefixE.foo', + '/prefixF.foo', + '/toplevelA.foo', + '/toplevelB.foo', + )); + } + protected function getArchivableFiles() { $files = array();