diff --git a/composer.lock b/composer.lock index 771fca79c..e8e9944be 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "943b2c4fcad1ef178d16a713c2468bf7e579c288" + "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/943b2c4fcad1ef178d16a713c2468bf7e579c288", - "reference": "943b2c4fcad1ef178d16a713c2468bf7e579c288", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d2c0a83b7533d6912e8d516756ebd34f893e9169", + "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169", "shasum": "" }, "require": { @@ -26,7 +26,7 @@ "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", "psr/log": "^1.0", "symfony/process": "^2.5 || ^3.0 || ^4.0" }, @@ -60,7 +60,7 @@ "ssl", "tls" ], - "time": "2017-11-29T09:37:33+00:00" + "time": "2018-03-29T19:57:20+00:00" }, { "name": "composer/semver", @@ -187,16 +187,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.6", + "version": "5.2.7", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "d283e11b6e14c6f4664cf080415c4341293e5bbd" + "reference": "8560d4314577199ba51bf2032f02cd1315587c23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/d283e11b6e14c6f4664cf080415c4341293e5bbd", - "reference": "d283e11b6e14c6f4664cf080415c4341293e5bbd", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/8560d4314577199ba51bf2032f02cd1315587c23", + "reference": "8560d4314577199ba51bf2032f02cd1315587c23", "shasum": "" }, "require": { @@ -205,7 +205,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^2.1", "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.22" + "phpunit/phpunit": "^4.8.35" }, "bin": [ "bin/validate-json" @@ -249,7 +249,7 @@ "json", "schema" ], - "time": "2017-10-21T13:15:38+00:00" + "time": "2018-02-14T22:26:30+00:00" }, { "name": "psr/log", @@ -348,16 +348,16 @@ }, { "name": "seld/jsonlint", - "version": "1.7.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9b355654ea99460397b89c132b5c1087b6bf4473" + "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9b355654ea99460397b89c132b5c1087b6bf4473", - "reference": "9b355654ea99460397b89c132b5c1087b6bf4473", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", + "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", "shasum": "" }, "require": { @@ -393,7 +393,7 @@ "parser", "validator" ], - "time": "2018-01-03T12:13:57+00:00" + "time": "2018-01-24T12:46:19+00:00" }, { "name": "seld/phar-utils", @@ -441,16 +441,16 @@ }, { "name": "symfony/console", - "version": "v2.8.32", + "version": "v2.8.38", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "46270f1ca44f08ebc134ce120fd2c2baf5fd63de" + "reference": "7f78892d900c72a40acd1fe793c856ef0c110f26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/46270f1ca44f08ebc134ce120fd2c2baf5fd63de", - "reference": "46270f1ca44f08ebc134ce120fd2c2baf5fd63de", + "url": "https://api.github.com/repos/symfony/console/zipball/7f78892d900c72a40acd1fe793c856ef0c110f26", + "reference": "7f78892d900c72a40acd1fe793c856ef0c110f26", "shasum": "" }, "require": { @@ -498,20 +498,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-11-29T09:33:18+00:00" + "time": "2018-04-03T05:20:27+00:00" }, { "name": "symfony/debug", - "version": "v2.8.32", + "version": "v2.8.38", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "e72a0340dc2e273b3c4398d8eef9157ba51d8b95" + "reference": "4486d2be5e068b51fece4c8551c14e709f573c8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/e72a0340dc2e273b3c4398d8eef9157ba51d8b95", - "reference": "e72a0340dc2e273b3c4398d8eef9157ba51d8b95", + "url": "https://api.github.com/repos/symfony/debug/zipball/4486d2be5e068b51fece4c8551c14e709f573c8d", + "reference": "4486d2be5e068b51fece4c8551c14e709f573c8d", "shasum": "" }, "require": { @@ -555,20 +555,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2017-11-19T19:05:05+00:00" + "time": "2018-04-03T05:20:27+00:00" }, { "name": "symfony/filesystem", - "version": "v2.8.32", + "version": "v2.8.38", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "15ceb6736a9eebd0d99f9e05a62296ab6ce1cf2b" + "reference": "125403a59e4cb4e3ebf46d0162fabcde613d2b97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/15ceb6736a9eebd0d99f9e05a62296ab6ce1cf2b", - "reference": "15ceb6736a9eebd0d99f9e05a62296ab6ce1cf2b", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/125403a59e4cb4e3ebf46d0162fabcde613d2b97", + "reference": "125403a59e4cb4e3ebf46d0162fabcde613d2b97", "shasum": "" }, "require": { @@ -604,20 +604,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-11-19T18:39:05+00:00" + "time": "2018-02-19T16:23:47+00:00" }, { "name": "symfony/finder", - "version": "v2.8.32", + "version": "v2.8.38", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "efeceae6a05a9b2fcb3391333f1d4a828ff44ab8" + "reference": "423746fc18ccf31f9abec43e4f078bb6e024b2d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/efeceae6a05a9b2fcb3391333f1d4a828ff44ab8", - "reference": "efeceae6a05a9b2fcb3391333f1d4a828ff44ab8", + "url": "https://api.github.com/repos/symfony/finder/zipball/423746fc18ccf31f9abec43e4f078bb6e024b2d5", + "reference": "423746fc18ccf31f9abec43e4f078bb6e024b2d5", "shasum": "" }, "require": { @@ -653,20 +653,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-11-05T15:25:56+00:00" + "time": "2018-04-04T13:38:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", - "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", "shasum": "" }, "require": { @@ -678,7 +678,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -712,20 +712,20 @@ "portable", "shim" ], - "time": "2017-10-11T12:05:26+00:00" + "time": "2018-01-30T19:27:44+00:00" }, { "name": "symfony/process", - "version": "v2.8.32", + "version": "v2.8.38", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d25449e031f600807949aab7cadbf267712f4eee" + "reference": "ee2c91470ff262b1a00aec27875d38594aa87629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d25449e031f600807949aab7cadbf267712f4eee", - "reference": "d25449e031f600807949aab7cadbf267712f4eee", + "url": "https://api.github.com/repos/symfony/process/zipball/ee2c91470ff262b1a00aec27875d38594aa87629", + "reference": "ee2c91470ff262b1a00aec27875d38594aa87629", "shasum": "" }, "require": { @@ -761,7 +761,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-11-05T15:25:56+00:00" + "time": "2018-04-03T05:20:27+00:00" } ], "packages-dev": [ @@ -870,16 +870,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.3", + "version": "1.7.5", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", - "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", "shasum": "" }, "require": { @@ -891,7 +891,7 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" }, "type": "library", "extra": { @@ -929,7 +929,7 @@ "spy", "stub" ], - "time": "2017-11-24T13:59:53+00:00" + "time": "2018-02-19T10:16:54+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1681,16 +1681,16 @@ }, { "name": "symfony/yaml", - "version": "v2.8.32", + "version": "v2.8.38", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "968ef42161e4bc04200119da473077f9e7015128" + "reference": "be720fcfae4614df204190d57795351059946a77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/968ef42161e4bc04200119da473077f9e7015128", - "reference": "968ef42161e4bc04200119da473077f9e7015128", + "url": "https://api.github.com/repos/symfony/yaml/zipball/be720fcfae4614df204190d57795351059946a77", + "reference": "be720fcfae4614df204190d57795351059946a77", "shasum": "" }, "require": { @@ -1726,7 +1726,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-11-29T09:33:18+00:00" + "time": "2018-01-03T07:36:31+00:00" } ], "aliases": [], diff --git a/src/Composer/Command/BaseDependencyCommand.php b/src/Composer/Command/BaseDependencyCommand.php index 980ca9282..a0c358add 100644 --- a/src/Composer/Command/BaseDependencyCommand.php +++ b/src/Composer/Command/BaseDependencyCommand.php @@ -89,7 +89,7 @@ class BaseDependencyCommand extends BaseCommand ); // Find packages that are or provide the requested package first - $packages = $pool->whatProvides($needle); + $packages = $pool->whatProvides(strtolower($needle)); if (empty($packages)) { throw new \InvalidArgumentException(sprintf('Could not find package "%s" in your project', $needle)); } diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 53be20035..802c65218 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -319,11 +319,16 @@ EOT $io->writeError(array('', 'Define your dependencies.', '')); + // prepare to resolve dependencies + $repos = $this->getRepos(); + $preferredStability = $minimumStability ?: 'stable'; + $phpVersion = $repos->findPackage('php', '*')->getPrettyVersion(); + $question = 'Would you like to define your dependencies (require) interactively [yes]? '; $require = $input->getOption('require'); $requirements = array(); if ($require || $io->askConfirmation($question, true)) { - $requirements = $this->determineRequirements($input, $output, $require); + $requirements = $this->determineRequirements($input, $output, $require, $phpVersion, $preferredStability); } $input->setOption('require', $requirements); @@ -331,7 +336,7 @@ EOT $requireDev = $input->getOption('require-dev'); $devRequirements = array(); if ($requireDev || $io->askConfirmation($question, true)) { - $devRequirements = $this->determineRequirements($input, $output, $requireDev); + $devRequirements = $this->determineRequirements($input, $output, $requireDev, $phpVersion, $preferredStability); } $input->setOption('require-dev', $devRequirements); } diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index ff0c79361..3b8e4e3ad 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -114,10 +114,14 @@ EOT $io->writeError('scripts:'); $table = array(); foreach ($scripts as $name => $script) { - $cmd = $this->getApplication()->find($name); $description = ''; - if ($cmd instanceof ScriptAliasCommand) { - $description = $cmd->getDescription(); + try { + $cmd = $this->getApplication()->find($name); + if ($cmd instanceof ScriptAliasCommand) { + $description = $cmd->getDescription(); + } + } catch (\Symfony\Component\Console\Exception\CommandNotFoundException $e) { + // ignore scripts that have no command associated, like native Composer script listeners } $table[] = array(' '.$name, $description); } diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php index e45d7b7c7..83d646e39 100644 --- a/src/Composer/Command/StatusCommand.php +++ b/src/Composer/Command/StatusCommand.php @@ -40,7 +40,7 @@ class StatusCommand extends BaseCommand { $this ->setName('status') - ->setDescription('Shows a list of locally modified packages.') + ->setDescription('Shows a list of locally modified packages, for packages installed from source.') ->setDefinition(array( new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Show modified files for each directory that contains changes.'), )) diff --git a/src/Composer/Downloader/FossilDownloader.php b/src/Composer/Downloader/FossilDownloader.php index 0b2c0181d..6dd4c0c42 100644 --- a/src/Composer/Downloader/FossilDownloader.php +++ b/src/Composer/Downloader/FossilDownloader.php @@ -87,7 +87,7 @@ class FossilDownloader extends VcsDownloader */ protected function getCommitLogs($fromReference, $toReference, $path) { - $command = sprintf('fossil timeline -t ci -W 0 -n 0 before %s', $toReference); + $command = sprintf('fossil timeline -t ci -W 0 -n 0 before %s', ProcessExecutor::escape($toReference)); if (0 !== $this->process->execute($command, $output, realpath($path))) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 626676894..740c4e3ec 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -423,7 +423,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface protected function getCommitLogs($fromReference, $toReference, $path) { $path = $this->normalizePath($path); - $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"', $fromReference, $toReference); + $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"', ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference)); if (0 !== $this->process->execute($command, $output, $path)) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index a7a42e62c..32074be71 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -82,7 +82,7 @@ class HgDownloader extends VcsDownloader */ protected function getCommitLogs($fromReference, $toReference, $path) { - $command = sprintf('hg log -r %s:%s --style compact', $fromReference, $toReference); + $command = sprintf('hg log -r %s:%s --style compact', ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference)); if (0 !== $this->process->execute($command, $output, realpath($path))) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index 54d9718be..e23958164 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -57,11 +57,10 @@ class SvnDownloader extends VcsDownloader throw new \RuntimeException('The .svn directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } + $util = new SvnUtil($url, $this->io, $this->config); $flags = ""; - if (0 === $this->process->execute('svn --version', $output)) { - if (preg_match('{(\d+(?:\.\d+)+)}', $output, $match) && version_compare($match[1], '1.7.0', '>=')) { - $flags .= ' --ignore-ancestry'; - } + if (version_compare($util->binaryVersion(), '1.7.0', '>=')) { + $flags .= ' --ignore-ancestry'; } $this->io->writeError(" Checking out " . $ref); @@ -193,7 +192,7 @@ class SvnDownloader extends VcsDownloader $fromRevision = preg_replace('{.*@(\d+)$}', '$1', $fromReference); $toRevision = preg_replace('{.*@(\d+)$}', '$1', $toReference); - $command = sprintf('svn log -r%s:%s --incremental', $fromRevision, $toRevision); + $command = sprintf('svn log -r%s:%s --incremental', ProcessExecutor::escape($fromRevision), ProcessExecutor::escape($toRevision)); $util = new SvnUtil($baseUrl, $this->io, $this->config); $util->setCacheCredentials($this->cacheCredentials); diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index bef7cea9f..55c80e29c 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/src/Composer/IO/ConsoleIO.php @@ -291,6 +291,10 @@ class ConsoleIO extends BaseIO $result = $helper->ask($this->input, $this->getErrorOutput(), $question); + if (!is_array($result)) { + return (string) array_search($result, $choices, true); + } + $results = array(); foreach ($choices as $index => $choice) { if (in_array($choice, $result, true)) { diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index dbdcb048d..0d842bb53 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -1184,9 +1184,9 @@ class Installer $package->setSourceReference($sourceReference); } - // only update dist url for github/bitbucket dists as they use a combination of dist url + dist reference to install + // only update dist url for github/bitbucket/gitlab dists as they use a combination of dist url + dist reference to install // but for other urls this is ambiguous and could result in bad outcomes - if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com)/}i', $distUrl)) { + if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $distUrl)) { $package->setDistUrl($distUrl); $this->updateInstallReferences($package, $sourceReference); } @@ -1204,9 +1204,9 @@ class Installer $package->setSourceReference($reference); - if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com)/}i', $package->getDistUrl())) { + if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $package->getDistUrl())) { $package->setDistReference($reference); - $package->setDistUrl(preg_replace('{(?<=/)[a-f0-9]{40}(?=/|$)}i', $reference, $package->getDistUrl())); + $package->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $package->getDistUrl())); } elseif ($package->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it $package->setDistReference($reference); } diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index 02297a1e6..e6ff84965 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -184,7 +184,7 @@ class VersionGuesser $isFeatureBranch = 0 === strpos($version, 'dev-'); if ('9999999-dev' === $version) { - $version = 'dev-' . $branch; + return array('version' => $version, 'commit' => null, 'pretty_version' => 'dev-'.$branch); } if (!$isFeatureBranch) { @@ -240,9 +240,6 @@ class VersionGuesser $length = strlen($output); $version = $this->versionParser->normalizeBranch($candidate); $prettyVersion = 'dev-' . $match[1]; - if ('9999999-dev' === $version) { - $version = $prettyVersion; - } } } } @@ -260,10 +257,6 @@ class VersionGuesser $branch = trim($output); $version = $this->versionParser->normalizeBranch($branch); $prettyVersion = 'dev-' . $branch; - - if ('9999999-dev' === $version) { - $version = $prettyVersion; - } } // try to fetch current version from fossil tags @@ -295,9 +288,6 @@ class VersionGuesser // we are in a branches path $version = $this->versionParser->normalizeBranch($matches[3]); $prettyVersion = 'dev-' . $matches[3]; - if ('9999999-dev' === $version) { - $version = $prettyVersion; - } return array('version' => $version, 'commit' => '', 'pretty_version' => $prettyVersion); } diff --git a/src/Composer/Repository/BaseRepository.php b/src/Composer/Repository/BaseRepository.php index f5233e197..2b30b63cd 100644 --- a/src/Composer/Repository/BaseRepository.php +++ b/src/Composer/Repository/BaseRepository.php @@ -39,7 +39,7 @@ abstract class BaseRepository implements RepositoryInterface */ public function getDependents($needle, $constraint = null, $invert = false, $recurse = true, $packagesFound = null) { - $needles = (array) $needle; + $needles = array_map('strtolower', (array) $needle); $results = array(); // initialize the array with the needles before any recursion occurs diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index 0ce3e90d2..ee5d702fa 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -155,7 +155,7 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn if (!isset($package['version'])) { $versionData = $this->versionGuesser->guessVersion($package, $path); - $package['version'] = $versionData['version'] ?: 'dev-master'; + $package['version'] = $versionData['pretty_version'] ?: 'dev-master'; } $output = ''; diff --git a/src/Composer/Repository/Vcs/SvnDriver.php b/src/Composer/Repository/Vcs/SvnDriver.php index 2c31f8173..1faba8195 100644 --- a/src/Composer/Repository/Vcs/SvnDriver.php +++ b/src/Composer/Repository/Vcs/SvnDriver.php @@ -353,7 +353,7 @@ class SvnDriver extends VcsDriver try { return $this->util->execute($command, $url); } catch (\RuntimeException $e) { - if (0 !== $this->process->execute('svn --version', $ignoredOutput)) { + if (null === $this->util->binaryVersion()) { throw new \RuntimeException('Failed to load '.$this->url.', svn was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput()); } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 06fb8b80b..80d6ecc32 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -175,6 +175,24 @@ class RemoteFilesystem return $value; } + /** + * @param array $headers array of returned headers like from getLastHeaders() + * @return string|null + */ + public function findStatusMessage(array $headers) + { + $value = null; + foreach ($headers as $header) { + if (preg_match('{^HTTP/\S+ \d+}i', $header)) { + // In case of redirects, http_response_headers contains the headers of all responses + // so we can not return directly and need to keep iterating + $value = $header; + } + } + + return $value; + } + /** * Get file content or copy action. * @@ -299,6 +317,20 @@ class RemoteFilesystem try { list($http_response_header, $result) = $this->getRemoteContents($originUrl, $fileUrl, $ctx); + if (!empty($http_response_header[0])) { + $statusCode = $this->findStatusCode($http_response_header); + if (in_array($statusCode, array(401, 403)) && $this->retryAuthFailure) { + $warning = null; + if ($this->findHeaderValue($http_response_header, 'content-type') === 'application/json') { + $data = json_decode($result, true); + if (!empty($data['warning'])) { + $warning = $data['warning']; + } + } + $this->promptAuthAndRetry($statusCode, $this->findStatusMessage($http_response_header), $warning); + } + } + $contentLength = !empty($http_response_header[0]) ? $this->findHeaderValue($http_response_header, 'content-length') : null; if ($contentLength && Platform::strlen($result) < $contentLength) { // alas, this is not possible via the stream callback because STREAM_NOTIFY_COMPLETED is documented, but not implemented anywhere in PHP @@ -574,29 +606,6 @@ class RemoteFilesystem // but you do not send an appropriate certificate throw new TransportException("The '" . $this->fileUrl . "' URL could not be accessed: " . $message, $messageCode); } - // intentional fallthrough to the next case as the notificationCode - // isn't always consistent and we should inspect the messageCode for 401s - - case STREAM_NOTIFY_AUTH_REQUIRED: - if (401 === $messageCode) { - // Bail if the caller is going to handle authentication failures itself. - if (!$this->retryAuthFailure) { - break; - } - - $this->promptAuthAndRetry($messageCode); - } - break; - - case STREAM_NOTIFY_AUTH_RESULT: - if (403 === $messageCode) { - // Bail if the caller is going to handle authentication failures itself. - if (!$this->retryAuthFailure) { - break; - } - - $this->promptAuthAndRetry($messageCode, $message); - } break; case STREAM_NOTIFY_FILE_SIZE_IS: @@ -619,7 +628,7 @@ class RemoteFilesystem } } - protected function promptAuthAndRetry($httpStatus, $reason = null) + protected function promptAuthAndRetry($httpStatus, $reason = null, $warning = null) { if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) { $message = "\n".'Could not fetch '.$this->fileUrl.', please create a GitHub OAuth token '.($httpStatus === 404 ? 'to access private repos' : 'to go over the API rate limit'); @@ -690,6 +699,9 @@ class RemoteFilesystem } $this->io->overwriteError(''); + if ($warning) { + $this->io->writeError(' '.$warning.''); + } $this->io->writeError(' Authentication required ('.parse_url($this->fileUrl, PHP_URL_HOST).'):'); $username = $this->io->ask(' Username: '); $password = $this->io->askAndHideAnswer(' Password: '); diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php index 082ece691..898fadce0 100644 --- a/src/Composer/Util/Svn.php +++ b/src/Composer/Util/Svn.php @@ -63,6 +63,11 @@ class Svn */ protected $config; + /** + * @var string|null + */ + static private $version; + /** * @param string $url * @param \Composer\IO\IOInterface $io @@ -102,9 +107,7 @@ class Svn // Ensure we are allowed to use this URL by config $this->config->prohibitUrlByConfig($url, $this->io); - $svnCommand = $this->getCommand($command, $url, $path); - - return $this->executeWithAuthRetry($svnCommand, $cwd, $path, $verbose); + return $this->executeWithAuthRetry($command, $cwd, $url, $path, $verbose); } /** @@ -121,18 +124,15 @@ class Svn */ public function executeLocal($command, $path, $cwd = null, $verbose = false) { - $svnCommand = sprintf('%s %s%s %s', - $command, - '--non-interactive ', - $this->getCredentialString(), - ProcessExecutor::escape($path) - ); - - return $this->executeWithAuthRetry($svnCommand, $cwd, $path, $verbose); + // A local command has no remote url + return $this->executeWithAuthRetry($command, $cwd, '', $path, $verbose); } - private function executeWithAuthRetry($command, $cwd, $path, $verbose) + private function executeWithAuthRetry($svnCommand, $cwd, $url, $path, $verbose) { + // Regenerate the command at each try, to use the newly user-provided credentials + $command = $this->getCommand($svnCommand, $url, $path); + $output = null; $io = $this->io; $handler = function ($type, $buffer) use (&$output, $io, $verbose) { @@ -170,7 +170,7 @@ class Svn // try to authenticate if maximum quantity of tries not reached if ($this->qtyAuthTries++ < self::MAX_QTY_AUTH_TRIES) { // restart the process - return $this->executeWithAuthRetry($command, $cwd, $path, $verbose); + return $this->executeWithAuthRetry($svnCommand, $cwd, $url, $path, $verbose); } throw new \RuntimeException( @@ -359,4 +359,22 @@ class Svn return $this->hasAuth = true; } + + /** + * Returns the version of the svn binary contained in PATH + * + * @return string|null + */ + public function binaryVersion() + { + if (!self::$version) { + if (0 === $this->process->execute('svn --version', $output)) { + if (preg_match('{(\d+(?:\.\d+)+)}', $output, $match)) { + self::$version = $match[1]; + } + } + } + + return self::$version; + } } diff --git a/tests/Composer/Test/Package/Version/VersionGuesserTest.php b/tests/Composer/Test/Package/Version/VersionGuesserTest.php index c0b6346c8..fe229d679 100644 --- a/tests/Composer/Test/Package/Version/VersionGuesserTest.php +++ b/tests/Composer/Test/Package/Version/VersionGuesserTest.php @@ -89,7 +89,8 @@ class VersionGuesserTest extends TestCase $guesser = new VersionGuesser($config, $executor, new VersionParser()); $versionArray = $guesser->guessVersion(array(), 'dummy/path'); - $this->assertEquals('dev-' . $branch, $versionArray['version']); + $this->assertEquals("9999999-dev", $versionArray['version']); + $this->assertEquals("dev-".$branch, $versionArray['pretty_version']); $this->assertEmpty($versionArray['commit']); }