diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md
index ffcb1589e..4981542e8 100644
--- a/doc/01-basic-usage.md
+++ b/doc/01-basic-usage.md
@@ -9,13 +9,13 @@ a logging library. If you have not yet installed Composer, refer to the
> **Note:** for the sake of simplicity, this introduction will assume you
> have performed a [local](00-intro.md#locally) install of Composer.
-## `composer.json`: Project Setup
+## `composer.json`: Project setup
To start using Composer in your project, all you need is a `composer.json`
file. This file describes the dependencies of your project and may contain
other metadata as well.
-### The `require` Key
+### The `require` key
The first (and often only) thing you specify in `composer.json` is the
[`require`](04-schema.md#require) key. You are simply telling Composer which
@@ -41,7 +41,7 @@ assumed that the `monolog/monolog` package is registered on Packagist. (See more
about Packagist [below](#packagist), or read more about repositories
[here](05-repositories.md)).
-### Package Names
+### Package names
The package name consists of a vendor name and the project's name. Often these
will be identical - the vendor name only exists to prevent naming clashes. For
@@ -53,7 +53,7 @@ Read more about publishing packages and package naming [here](02-libraries.md).
you to require certain versions of server software. See
[platform packages](#platform-packages) below.)
-### Package Version Constraints
+### Package version constraints
In our example, we are requesting the Monolog package with the version constraint
[`1.0.*`](https://semver.mwl.be/#?package=monolog%2Fmonolog&version=1.0.*).
@@ -84,7 +84,7 @@ versions, how versions relate to each other, and on version constraints.
> versions of a package. Read more about stability flags and the `minimum-stability`
> key on the [schema page](04-schema.md).
-## Installing Dependencies
+## Installing dependencies
To install the defined dependencies for your project, run the
[`install`](03-cli.md#install) command.
@@ -95,7 +95,7 @@ php composer.phar install
When you run this command, one of two things may happen:
-### Installing Without `composer.lock`
+### Installing without `composer.lock`
If you have never run the command before and there is also no `composer.lock` file present,
Composer simply resolves all dependencies listed in your `composer.json` file and downloads
@@ -114,7 +114,7 @@ of them that it downloaded to the `composer.lock` file, locking the project to t
versions. You should commit the `composer.lock` file to your project repo so that all people
working on the project are locked to the same versions of dependencies (more below).
-### Installing With `composer.lock`
+### Installing with `composer.lock`
This brings us to the second scenario. If there is already a `composer.lock` file as well as a
`composer.json` file when you run `composer install`, it means either you ran the
@@ -130,7 +130,7 @@ working on your project. As a result you will have all dependencies requested by
the file was created). This is by design, it ensures that your project does not break because of
unexpected changes in dependencies.
-### Commit Your `composer.lock` File to Version Control
+### Commit your `composer.lock` file to version control
Committing this file to VC is important because it will cause anyone who sets
up the project to use the exact same
@@ -142,7 +142,7 @@ reinstalling the project you can feel confident the dependencies installed are
still working even if your dependencies released many new versions since then.
(See note below about using the `update` command.)
-## Updating Dependencies to their Latest Versions
+## Updating dependencies to their latest versions
As mentioned above, the `composer.lock` file prevents you from automatically getting
the latest versions of your dependencies. To update to the latest versions, use the
diff --git a/doc/03-cli.md b/doc/03-cli.md
index 8c1dfee70..54cf7642f 100644
--- a/doc/03-cli.md
+++ b/doc/03-cli.md
@@ -140,7 +140,7 @@ php composer.phar update vendor/package vendor/package2
You can also use wildcards to update a bunch of packages at once:
```sh
-php composer.phar update vendor/*
+php composer.phar update "vendor/*"
```
### Options
diff --git a/doc/articles/aliases.md b/doc/articles/aliases.md
index 98a6d1335..d36eb11ff 100644
--- a/doc/articles/aliases.md
+++ b/doc/articles/aliases.md
@@ -89,6 +89,12 @@ Add this to your project's root `composer.json`:
}
```
+Or let composer add it for you with:
+
+```
+php composer.phar require monolog/monolog:"dev-bugfix as 1.0.x-dev"
+```
+
That will fetch the `dev-bugfix` version of `monolog/monolog` from your GitHub
and alias it to `1.0.x-dev`.
diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php
index 49cb138d8..89ba495cf 100644
--- a/src/Composer/Command/ConfigCommand.php
+++ b/src/Composer/Command/ConfigCommand.php
@@ -21,6 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Composer\Config;
use Composer\Config\JsonConfigSource;
use Composer\Factory;
+use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Semver\VersionParser;
use Composer\Package\BasePackage;
@@ -284,7 +285,7 @@ EOT
$value = json_encode($value);
}
- $this->getIO()->write($value);
+ $this->getIO()->write($value, true, IOInterface::QUIET);
return 0;
}
@@ -710,9 +711,9 @@ EOT
}
if (is_string($rawVal) && $rawVal != $value) {
- $io->write('[' . $k . $key . '] ' . $rawVal . ' (' . $value . ')');
+ $io->write('[' . $k . $key . '] ' . $rawVal . ' (' . $value . ')', true, IOInterface::QUIET);
} else {
- $io->write('[' . $k . $key . '] ' . $value . '');
+ $io->write('[' . $k . $key . '] ' . $value . '', true, IOInterface::QUIET);
}
}
}
diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php
index f15308bad..a28007a6b 100644
--- a/src/Composer/Command/RequireCommand.php
+++ b/src/Composer/Command/RequireCommand.php
@@ -194,7 +194,7 @@ EOT
$status = $install->run();
if ($status !== 0) {
- $this->revertComposerFile();
+ $this->revertComposerFile(false);
}
return $status;
@@ -225,7 +225,7 @@ EOT
return;
}
- public function revertComposerFile()
+ public function revertComposerFile($hardExit = true)
{
$io = $this->getIO();
@@ -237,6 +237,8 @@ EOT
file_put_contents($this->json->getPath(), $this->composerBackup);
}
- exit(1);
+ if ($hardExit) {
+ exit(1);
+ }
}
}
diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php
index 7cd3a9813..271c7261f 100644
--- a/src/Composer/DependencyResolver/Problem.php
+++ b/src/Composer/DependencyResolver/Problem.php
@@ -106,7 +106,7 @@ class Problem
$msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but ';
- if (defined('HHVM_VERSION')) {
+ if (defined('HHVM_VERSION') || count($available)) {
return $msg . 'your HHVM version does not satisfy that requirement.';
}
diff --git a/src/Composer/DependencyResolver/Rule.php b/src/Composer/DependencyResolver/Rule.php
index 22e5cec25..4533a6b61 100644
--- a/src/Composer/DependencyResolver/Rule.php
+++ b/src/Composer/DependencyResolver/Rule.php
@@ -175,13 +175,18 @@ abstract class Rule
return $text . ' -> your HHVM version does not satisfy that requirement.';
}
- if ($targetName === 'hhvm') {
- return $text . ' -> you are running this with PHP and not HHVM.';
- }
-
$packages = $pool->whatProvides($targetName);
$package = count($packages) ? current($packages) : phpversion();
+ if ($targetName === 'hhvm') {
+ if ($package instanceof CompletePackage) {
+ return $text . ' -> your HHVM version ('.$package->getPrettyVersion().') does not satisfy that requirement.';
+ } else {
+ return $text . ' -> you are running this with PHP and not HHVM.';
+ }
+ }
+
+
if (!($package instanceof CompletePackage)) {
return $text . ' -> your PHP version ('.phpversion().') does not satisfy that requirement.';
}
diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php
index 66a43c37b..2188d99ce 100644
--- a/src/Composer/DependencyResolver/Solver.php
+++ b/src/Composer/DependencyResolver/Solver.php
@@ -58,6 +58,9 @@ class Solver
/** @var array */
protected $learnedWhy = array();
+ /** @var bool */
+ public $testFlagLearnedPositiveLiteral = false;
+
/** @var IOInterface */
protected $io;
@@ -478,6 +481,9 @@ class Solver
unset($seen[abs($literal)]);
if ($num && 0 === --$num) {
+ if ($literal < 0) {
+ $this->testFlagLearnedPositiveLiteral = true;
+ }
$learnedLiterals[0] = -$literal;
if (!$l1num) {
diff --git a/src/Composer/Installer/BinaryInstaller.php b/src/Composer/Installer/BinaryInstaller.php
index a14755bf1..0a7b97149 100644
--- a/src/Composer/Installer/BinaryInstaller.php
+++ b/src/Composer/Installer/BinaryInstaller.php
@@ -196,9 +196,13 @@ class BinaryInstaller
dir=\$(cd "\${0%[/\\\\]*}" > /dev/null; cd $binDir && pwd)
-if [ -d /proc/cygdrive ] && [[ \$(which php) == \$(readlink -n /proc/cygdrive)/* ]]; then
- # We are in Cygwin using Windows php, so the path must be translated
- dir=\$(cygpath -m "\$dir");
+if [ -d /proc/cygdrive ]; then
+ case \$(which php) in
+ \$(readlink -n /proc/cygdrive)/*)
+ # We are in Cygwin using Windows php, so the path must be translated
+ dir=\$(cygpath -m "\$dir");
+ ;;
+ esac
fi
"\${dir}/$binFile" "\$@"
diff --git a/src/Composer/Package/Dumper/ArrayDumper.php b/src/Composer/Package/Dumper/ArrayDumper.php
index 6593143d5..b1e20dbf5 100644
--- a/src/Composer/Package/Dumper/ArrayDumper.php
+++ b/src/Composer/Package/Dumper/ArrayDumper.php
@@ -48,7 +48,9 @@ class ArrayDumper
if ($package->getSourceType()) {
$data['source']['type'] = $package->getSourceType();
$data['source']['url'] = $package->getSourceUrl();
- $data['source']['reference'] = $package->getSourceReference();
+ if (null !== ($value = $package->getSourceReference())) {
+ $data['source']['reference'] = $value;
+ }
if ($mirrors = $package->getSourceMirrors()) {
$data['source']['mirrors'] = $mirrors;
}
@@ -57,8 +59,12 @@ class ArrayDumper
if ($package->getDistType()) {
$data['dist']['type'] = $package->getDistType();
$data['dist']['url'] = $package->getDistUrl();
- $data['dist']['reference'] = $package->getDistReference();
- $data['dist']['shasum'] = $package->getDistSha1Checksum();
+ if (null !== ($value = $package->getDistReference())) {
+ $data['dist']['reference'] = $value;
+ }
+ if (null !== ($value = $package->getDistSha1Checksum())) {
+ $data['dist']['shasum'] = $value;
+ }
if ($mirrors = $package->getDistMirrors()) {
$data['dist']['mirrors'] = $mirrors;
}
diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php
index 9fed111e0..c5edd0d68 100644
--- a/src/Composer/Package/Loader/ArrayLoader.php
+++ b/src/Composer/Package/Loader/ArrayLoader.php
@@ -152,7 +152,7 @@ class ArrayLoader implements LoaderInterface
}
$package->setSourceType($config['source']['type']);
$package->setSourceUrl($config['source']['url']);
- $package->setSourceReference($config['source']['reference']);
+ $package->setSourceReference(isset($config['source']['reference']) ? $config['source']['reference'] : null);
if (isset($config['source']['mirrors'])) {
$package->setSourceMirrors($config['source']['mirrors']);
}
diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php
index 7d5e047dd..3c21139e8 100644
--- a/src/Composer/Repository/PlatformRepository.php
+++ b/src/Composer/Repository/PlatformRepository.php
@@ -16,15 +16,18 @@ use Composer\Package\CompletePackage;
use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser;
use Composer\Plugin\PluginInterface;
+use Composer\Util\ProcessExecutor;
use Composer\Util\Silencer;
+use Composer\Util\Platform;
use Composer\XdebugHandler\XdebugHandler;
+use Symfony\Component\Process\ExecutableFinder;
/**
* @author Jordi Boggiano
*/
class PlatformRepository extends ArrayRepository
{
- const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit|-ipv6|-zts|-debug)?|hhvm|(?:ext|lib)-[a-z0-9](?:[_.-]?[a-z0-9]+)*)$}iD';
+ const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit|-ipv6|-zts|-debug)?|hhvm|(?:ext|lib)-[a-z0-9](?:[_.-]?[a-z0-9]+)*|composer-plugin-api)$}iD';
private $versionParser;
@@ -37,8 +40,11 @@ class PlatformRepository extends ArrayRepository
*/
private $overrides = array();
- public function __construct(array $packages = array(), array $overrides = array())
+ private $process;
+
+ public function __construct(array $packages = array(), array $overrides = array(), ProcessExecutor $process = null)
{
+ $this->process = $process === null ? (new ProcessExecutor()) : $process;
foreach ($overrides as $name => $version) {
$this->overrides[strtolower($name)] = array('name' => $name, 'version' => $version);
}
@@ -220,12 +226,27 @@ class PlatformRepository extends ArrayRepository
$this->addPackage($lib);
}
- if (defined('HHVM_VERSION')) {
+ $hhvmVersion = defined('HHVM_VERSION') ? HHVM_VERSION : null;
+ if ($hhvmVersion === null && !Platform::isWindows()) {
+ $finder = new ExecutableFinder();
+ $hhvm = $finder->find('hhvm');
+ if ($hhvm !== null) {
+ $exitCode = $this->process->execute(
+ ProcessExecutor::escape($hhvm).
+ ' --php -d hhvm.jit=0 -r "echo HHVM_VERSION;" 2>/dev/null',
+ $hhvmVersion
+ );
+ if ($exitCode !== 0) {
+ $hhvmVersion = null;
+ }
+ }
+ }
+ if ($hhvmVersion) {
try {
- $prettyVersion = HHVM_VERSION;
+ $prettyVersion = $hhvmVersion;
$version = $this->versionParser->normalize($prettyVersion);
} catch (\UnexpectedValueException $e) {
- $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', HHVM_VERSION);
+ $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', $hhvmVersion);
$version = $this->versionParser->normalize($prettyVersion);
}
diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php
index ccb1810de..b80e7c61d 100644
--- a/tests/Composer/Test/DependencyResolver/SolverTest.php
+++ b/tests/Composer/Test/DependencyResolver/SolverTest.php
@@ -899,6 +899,9 @@ class SolverTest extends TestCase
$this->request->install('A');
+ // check correct setup for assertion later
+ $this->assertFalse($this->solver->testFlagLearnedPositiveLiteral);
+
$this->checkSolverResult(array(
array('job' => 'install', 'package' => $packageF1),
array('job' => 'install', 'package' => $packageD),
@@ -908,6 +911,10 @@ class SolverTest extends TestCase
array('job' => 'install', 'package' => $packageB),
array('job' => 'install', 'package' => $packageA),
));
+
+ // verify that the code path leading to a negative literal resulting in a positive learned literal is actually
+ // executed
+ $this->assertTrue($this->solver->testFlagLearnedPositiveLiteral);
}
protected function reposComplete()
diff --git a/tests/Composer/Test/Fixtures/installer/install-dev-using-dist.test b/tests/Composer/Test/Fixtures/installer/install-dev-using-dist.test
index ccc9ead1a..5846d13c0 100644
--- a/tests/Composer/Test/Fixtures/installer/install-dev-using-dist.test
+++ b/tests/Composer/Test/Fixtures/installer/install-dev-using-dist.test
@@ -35,8 +35,7 @@ install --prefer-dist
"dist": {
"type": "zip",
"url": "http://www.example.com/dist.zip",
- "reference": "459720ff3b74ee0c0d159277c6f2f5df89d8a4f6",
- "shasum": null
+ "reference": "459720ff3b74ee0c0d159277c6f2f5df89d8a4f6"
},
"type": "library"
}
diff --git a/tests/Composer/Test/Fixtures/installer/update-changes-url.test b/tests/Composer/Test/Fixtures/installer/update-changes-url.test
index 70294c8e6..d774ea188 100644
--- a/tests/Composer/Test/Fixtures/installer/update-changes-url.test
+++ b/tests/Composer/Test/Fixtures/installer/update-changes-url.test
@@ -101,43 +101,43 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
{
"name": "a/a", "version": "dev-master",
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/a/newa", "type": "git" },
- "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/a/newa/zipball/2222222222222222222222222222222222222222", "type": "zip", "shasum": null },
+ "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/a/newa/zipball/2222222222222222222222222222222222222222", "type": "zip" },
"type": "library"
},
{
"name": "b/b", "version": "2.0.3",
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/b/newb", "type": "git" },
- "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/b/newb/zipball/2222222222222222222222222222222222222222", "type": "zip", "shasum": null },
+ "dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/b/newb/zipball/2222222222222222222222222222222222222222", "type": "zip" },
"type": "library"
},
{
"name": "c/c", "version": "1.0.0",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/newc", "type": "git" },
- "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/newc/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": null },
+ "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/newc/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
"name": "d/d", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/newd", "type": "git" },
- "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/newd/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": null },
+ "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/newd/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
"name": "e/e", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/e/newe", "type": "git" },
- "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/e/newe/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": null },
+ "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/e/newe/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
"name": "f/f", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/newf", "type": "git" },
- "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/newf/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": null },
+ "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/newf/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
},
{
"name": "g/g", "version": "dev-master",
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/g/newg", "type": "git" },
- "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/g/newg/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": null },
+ "dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/g/newg/zipball/1111111111111111111111111111111111111111", "type": "zip" },
"type": "library"
}
],
diff --git a/tests/Composer/Test/Repository/PlatformRepositoryTest.php b/tests/Composer/Test/Repository/PlatformRepositoryTest.php
new file mode 100644
index 000000000..aa51a2fc6
--- /dev/null
+++ b/tests/Composer/Test/Repository/PlatformRepositoryTest.php
@@ -0,0 +1,70 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Test\Repository;
+
+use Composer\Repository\PlatformRepository;
+use Composer\Test\TestCase;
+use Composer\Util\Platform;
+use Symfony\Component\Process\ExecutableFinder;
+
+class PlatformRepositoryTest extends TestCase {
+ public function testHHVMVersionWhenExecutingInHHVM() {
+ if (!defined('HHVM_VERSION_ID')) {
+ $this->markTestSkipped('Not running with HHVM');
+ return;
+ }
+ $repository = new PlatformRepository();
+ $package = $repository->findPackage('hhvm', '*');
+ $this->assertNotNull($package, 'failed to find HHVM package');
+ $this->assertSame(
+ sprintf('%d.%d.%d',
+ HHVM_VERSION_ID / 10000,
+ (HHVM_VERSION_ID / 100) % 100,
+ HHVM_VERSION_ID % 100
+ ),
+ $package->getPrettyVersion()
+ );
+ }
+
+ public function testHHVMVersionWhenExecutingInPHP() {
+ if (defined('HHVM_VERSION_ID')) {
+ $this->markTestSkipped('Running with HHVM');
+ return;
+ }
+ if (PHP_VERSION_ID < 50400) {
+ $this->markTestSkipped('Test only works on PHP 5.4+');
+ return;
+ }
+ if (Platform::isWindows()) {
+ $this->markTestSkipped('Test does not run on Windows');
+ return;
+ }
+ $finder = new ExecutableFinder();
+ $hhvm = $finder->find('hhvm');
+ if ($hhvm === null) {
+ $this->markTestSkipped('HHVM is not installed');
+ }
+ $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
+ $process->expects($this->once())->method('execute')->will($this->returnCallback(
+ function($command, &$out) {
+ $this->assertContains('HHVM_VERSION', $command);
+ $out = '4.0.1-dev';
+ return 0;
+ }
+ ));
+ $repository = new PlatformRepository(array(), array(), $process);
+ $package = $repository->findPackage('hhvm', '*');
+ $this->assertNotNull($package, 'failed to find HHVM package');
+ $this->assertSame('4.0.1.0-dev', $package->getVersion());
+ }
+}