diff --git a/src/Composer/Command/AboutCommand.php b/src/Composer/Command/AboutCommand.php index d1472ba17..bf1fa0f9c 100644 --- a/src/Composer/Command/AboutCommand.php +++ b/src/Composer/Command/AboutCommand.php @@ -42,5 +42,7 @@ EOT See https://getcomposer.org/ for more information. EOT ); + + return 0; } } diff --git a/src/Composer/Command/BaseDependencyCommand.php b/src/Composer/Command/BaseDependencyCommand.php index 4c8766ba3..78fe0551e 100644 --- a/src/Composer/Command/BaseDependencyCommand.php +++ b/src/Composer/Command/BaseDependencyCommand.php @@ -62,7 +62,7 @@ class BaseDependencyCommand extends BaseCommand * @param InputInterface $input * @param OutputInterface $output * @param bool $inverted Whether to invert matching process (why-not vs why behaviour) - * @return int|null Exit code of the operation. + * @return int Exit code of the operation. */ protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false) { diff --git a/src/Composer/Command/ClearCacheCommand.php b/src/Composer/Command/ClearCacheCommand.php index ec51c56d3..08ec04701 100644 --- a/src/Composer/Command/ClearCacheCommand.php +++ b/src/Composer/Command/ClearCacheCommand.php @@ -70,5 +70,7 @@ EOT } $io->writeError('All caches cleared.'); + + return 0; } } diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 24e2bd3c3..ce6d2d0ba 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -464,13 +464,19 @@ EOT $this->getIO()->writeError('You are now running Composer with SSL/TLS protection enabled.'); } - return $this->configSource->removeConfigSetting($settingKey); + $this->configSource->removeConfigSetting($settingKey); + + return 0; } if (isset($uniqueConfigValues[$settingKey])) { - return $this->handleSingleValue($settingKey, $uniqueConfigValues[$settingKey], $values, 'addConfigSetting'); + $this->handleSingleValue($settingKey, $uniqueConfigValues[$settingKey], $values, 'addConfigSetting'); + + return 0; } if (isset($multiConfigValues[$settingKey])) { - return $this->handleMultiValue($settingKey, $multiConfigValues[$settingKey], $values, 'addConfigSetting'); + $this->handleMultiValue($settingKey, $multiConfigValues[$settingKey], $values, 'addConfigSetting'); + + return 0; } // handle properties @@ -531,38 +537,51 @@ EOT throw new \InvalidArgumentException('The '.$settingKey.' property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json'); } if ($input->getOption('unset') && (isset($uniqueProps[$settingKey]) || isset($multiProps[$settingKey]))) { - return $this->configSource->removeProperty($settingKey); + $this->configSource->removeProperty($settingKey); + + return 0; } if (isset($uniqueProps[$settingKey])) { - return $this->handleSingleValue($settingKey, $uniqueProps[$settingKey], $values, 'addProperty'); + $this->handleSingleValue($settingKey, $uniqueProps[$settingKey], $values, 'addProperty'); + + return 0; } if (isset($multiProps[$settingKey])) { - return $this->handleMultiValue($settingKey, $multiProps[$settingKey], $values, 'addProperty'); + $this->handleMultiValue($settingKey, $multiProps[$settingKey], $values, 'addProperty'); + + return 0; } // handle repositories if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { - return $this->configSource->removeRepository($matches[1]); + $this->configSource->removeRepository($matches[1]); + + return 0; } if (2 === count($values)) { - return $this->configSource->addRepository($matches[1], array( + $this->configSource->addRepository($matches[1], array( 'type' => $values[0], 'url' => $values[1], )); + + return 0; } if (1 === count($values)) { $value = strtolower($values[0]); if (true === $booleanValidator($value)) { if (false === $booleanNormalizer($value)) { - return $this->configSource->addRepository($matches[1], false); + $this->configSource->addRepository($matches[1], false); + + return 0; } } else { $value = JsonFile::parseJson($values[0]); + $this->configSource->addRepository($matches[1], $value); - return $this->configSource->addRepository($matches[1], $value); + return 0; } } @@ -572,22 +591,32 @@ EOT // handle extra if (preg_match('/^extra\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { - return $this->configSource->removeProperty($settingKey); + $this->configSource->removeProperty($settingKey); + + return 0; } - return $this->configSource->addProperty($settingKey, $values[0]); + $this->configSource->addProperty($settingKey, $values[0]); + + return 0; } // handle platform if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { - return $this->configSource->removeConfigSetting($settingKey); + $this->configSource->removeConfigSetting($settingKey); + + return 0; } - return $this->configSource->addConfigSetting($settingKey, $values[0]); + $this->configSource->addConfigSetting($settingKey, $values[0]); + + return 0; } if ($settingKey === 'platform' && $input->getOption('unset')) { - return $this->configSource->removeConfigSetting($settingKey); + $this->configSource->removeConfigSetting($settingKey); + + return 0; } // handle auth @@ -596,7 +625,7 @@ EOT $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]); $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); - return; + return 0; } if ($matches[1] === 'bitbucket-oauth') { @@ -619,16 +648,20 @@ EOT $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1])); } - return; + return 0; } // handle script if (preg_match('/^scripts\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { - return $this->configSource->removeProperty($settingKey); + $this->configSource->removeProperty($settingKey); + + return 0; } - return $this->configSource->addProperty($settingKey, count($values) > 1 ? $values : $values[0]); + $this->configSource->addProperty($settingKey, count($values) > 1 ? $values : $values[0]); + + return 0; } throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command'); diff --git a/src/Composer/Command/DependsCommand.php b/src/Composer/Command/DependsCommand.php index d6adec083..c350fde9b 100644 --- a/src/Composer/Command/DependsCommand.php +++ b/src/Composer/Command/DependsCommand.php @@ -48,7 +48,7 @@ EOT * * @param InputInterface $input * @param OutputInterface $output - * @return int|null + * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { diff --git a/src/Composer/Command/DumpAutoloadCommand.php b/src/Composer/Command/DumpAutoloadCommand.php index 3add15166..dbda29d63 100644 --- a/src/Composer/Command/DumpAutoloadCommand.php +++ b/src/Composer/Command/DumpAutoloadCommand.php @@ -84,5 +84,7 @@ EOT } else { $this->getIO()->overwriteError('Generated autoload files containing '. $numberOfClasses .' classes'); } + + return 0; } } diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index f4d6d99d3..496edcaaf 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -152,6 +152,8 @@ EOT if ($input->isInteractive() && $this->hasDependencies($options) && $io->askConfirmation($question, true)) { $this->installDependencies($output); } + + return 0; } /** diff --git a/src/Composer/Command/LicensesCommand.php b/src/Composer/Command/LicensesCommand.php index b3c30d63b..7537945e9 100644 --- a/src/Composer/Command/LicensesCommand.php +++ b/src/Composer/Command/LicensesCommand.php @@ -110,6 +110,8 @@ EOT default: throw new \RuntimeException(sprintf('Unsupported format "%s". See help for supported formats.', $format)); } + + return 0; } /** diff --git a/src/Composer/Command/OutdatedCommand.php b/src/Composer/Command/OutdatedCommand.php index ae26a7487..599087246 100644 --- a/src/Composer/Command/OutdatedCommand.php +++ b/src/Composer/Command/OutdatedCommand.php @@ -59,7 +59,7 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { $args = array( - 'show', + 'command' => 'show', '--latest' => true, ); if (!$input->getOption('all')) { diff --git a/src/Composer/Command/ProhibitsCommand.php b/src/Composer/Command/ProhibitsCommand.php index 9e5575c74..1e18e5e23 100644 --- a/src/Composer/Command/ProhibitsCommand.php +++ b/src/Composer/Command/ProhibitsCommand.php @@ -48,7 +48,7 @@ EOT * * @param InputInterface $input * @param OutputInterface $output - * @return int|null + * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { diff --git a/src/Composer/Command/SearchCommand.php b/src/Composer/Command/SearchCommand.php index 54aa4dcea..0e8aa60e4 100644 --- a/src/Composer/Command/SearchCommand.php +++ b/src/Composer/Command/SearchCommand.php @@ -79,5 +79,7 @@ EOT foreach ($results as $result) { $io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : '')); } + + return 0; } } diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 78b27460e..0dba48e28 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -254,6 +254,8 @@ TAGSPUBKEY } else { $io->writeError('A backup of the current version could not be written to '.$backupFile.', no rollback possible'); } + + return 0; } protected function fetchKeys(IOInterface $io, Config $config) diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index cd153fc58..116d5b99e 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -61,7 +61,7 @@ EOT /** * @param InputInterface $input * @param OutputInterface $output - * @return int|null + * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { diff --git a/src/Composer/Command/SuggestsCommand.php b/src/Composer/Command/SuggestsCommand.php index a7ec3dad8..0769f62f9 100644 --- a/src/Composer/Command/SuggestsCommand.php +++ b/src/Composer/Command/SuggestsCommand.php @@ -118,7 +118,7 @@ EOT $io->write(sprintf('%s', $suggestion)); } - return; + return 0; } // Grouped by package @@ -148,5 +148,7 @@ EOT $io->write(''); } } + + return 0; } } diff --git a/src/Composer/Repository/BaseRepository.php b/src/Composer/Repository/BaseRepository.php index 2b30b63cd..d668f43cb 100644 --- a/src/Composer/Repository/BaseRepository.php +++ b/src/Composer/Repository/BaseRepository.php @@ -67,6 +67,27 @@ abstract class BaseRepository implements RepositoryInterface // Replacements are considered valid reasons for a package to be installed during forward resolution if (!$invert) { $links += $package->getReplaces(); + + // On forward search, check if any replaced package was required and add the replaced + // packages to the list of needles. Contrary to the cross-reference link check below, + // replaced packages are the target of links. + foreach ($package->getReplaces() as $link) { + foreach ($needles as $needle) { + if ($link->getSource() === $needle) { + if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) { + // already displayed this node's dependencies, cutting short + if (in_array($link->getTarget(), $packagesInTree)) { + $results[] = array($package, $link, false); + continue; + } + $packagesInTree[] = $link->getTarget(); + $dependents = $recurse ? $this->getDependents($link->getTarget(), null, false, true, $packagesInTree) : array(); + $results[] = array($package, $link, $dependents); + $needles[] = $link->getTarget(); + } + } + } + } } // Require-dev is only relevant for the root package @@ -81,12 +102,12 @@ abstract class BaseRepository implements RepositoryInterface if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) { // already displayed this node's dependencies, cutting short if (in_array($link->getSource(), $packagesInTree)) { - $results[$link->getSource()] = array($package, $link, false); + $results[] = array($package, $link, false); continue; } $packagesInTree[] = $link->getSource(); $dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree) : array(); - $results[$link->getSource()] = array($package, $link, $dependents); + $results[] = array($package, $link, $dependents); } } } diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 3812e7a66..04a363442 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -71,7 +71,7 @@ class HgDriver extends VcsDriver return sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); }; - $hgUtils->runCommand($command, $this->url, $this->repoDir); + $hgUtils->runCommand($command, $this->url, null); } } diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index c025a6b8c..7cdad1df4 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -682,12 +682,14 @@ class Filesystem if (!Platform::isWindows()) { return false; } + + // Important to clear all caches first + clearstatcache(true, $junction); + if (!is_dir($junction) || is_link($junction)) { return false; } - // Important to clear all caches first - clearstatcache(true, $junction); $stat = lstat($junction); // S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask) diff --git a/tests/Composer/Test/Util/FilesystemTest.php b/tests/Composer/Test/Util/FilesystemTest.php index 9f684dbfb..f3fb30278 100644 --- a/tests/Composer/Test/Util/FilesystemTest.php +++ b/tests/Composer/Test/Util/FilesystemTest.php @@ -300,16 +300,16 @@ class FilesystemTest extends TestCase // Create and detect junction $fs->junction($target, $junction); - $this->assertTrue($fs->isJunction($junction)); - $this->assertFalse($fs->isJunction($target)); - $this->assertTrue($fs->isJunction($target . '/../../junction')); - $this->assertFalse($fs->isJunction($junction . '/../real')); - $this->assertTrue($fs->isJunction($junction . '/../junction')); + $this->assertTrue($fs->isJunction($junction), $junction . ': is a junction'); + $this->assertFalse($fs->isJunction($target), $target . ': is not a junction'); + $this->assertTrue($fs->isJunction($target . '/../../junction'), $target . '/../../junction: is a junction'); + $this->assertFalse($fs->isJunction($junction . '/../real'), $junction . '/../real: is not a junction'); + $this->assertTrue($fs->isJunction($junction . '/../junction'), $junction . '/../junction: is a junction'); // Remove junction - $this->assertTrue(is_dir($junction)); - $this->assertTrue($fs->removeJunction($junction)); - $this->assertFalse(is_dir($junction)); + $this->assertTrue(is_dir($junction), $junction . ' is a directory'); + $this->assertTrue($fs->removeJunction($junction), $junction . ' has been removed'); + $this->assertFalse(is_dir($junction), $junction . ' is not a directory'); } public function testCopy()