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()