diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index a5b6281a3..d7dcf293d 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -14,6 +14,7 @@ namespace Composer\Package\Loader; use Composer\Package; use Composer\Package\BasePackage; +use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Package\Version\VersionParser; /** @@ -142,6 +143,8 @@ class ValidatingArrayLoader implements LoaderInterface } } + $unboundConstraint = new VersionConstraint('=', $this->versionParser->normalize('dev-master')); + foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) { if ($this->validateArray($linkType) && isset($this->config[$linkType])) { foreach ($this->config[$linkType] as $package => $constraint) { @@ -153,13 +156,27 @@ class ValidatingArrayLoader implements LoaderInterface unset($this->config[$linkType][$package]); } elseif ('self.version' !== $constraint) { try { - $this->versionParser->parseConstraints($constraint); + $linkConstraint = $this->versionParser->parseConstraints($constraint); } catch (\Exception $e) { $this->errors[] = $linkType.'.'.$package.' : invalid version constraint ('.$e->getMessage().')'; unset($this->config[$linkType][$package]); + continue; + } + + if ('conflict' === $linkType || 'require-dev' === $linkType) { + continue; // conflict can be unbound, and require-dev constraints will not impact shared libraries as they are root-only + } + + if ($linkConstraint->matches($unboundConstraint)) { + $this->warnings[] = $linkType.'.'.$package.' : unbound version constraint detected ('.$constraint.')'; + unset($this->config[$linkType][$package]); } } } + + if (empty($this->config[$linkType])) { + unset($this->config[$linkType]); + } } } diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index 262c24bf6..6bc3b5e25 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -73,14 +73,17 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase ), 'require' => array( 'a/b' => '1.*', + 'b/c' => '~2', 'example' => '>2.0-dev,<2.4-dev', ), 'require-dev' => array( 'a/b' => '1.*', + 'b/c' => '*', 'example' => '>2.0-dev,<2.4-dev', ), 'conflict' => array( 'a/b' => '1.*', + 'b/c' => '>2.7', 'example' => '>2.0-dev,<2.4-dev', ), 'replace' => array( @@ -288,6 +291,27 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase 'support.wiki : invalid value (foo:bar), must be an http/https URL', ) ), + array( + array( + 'name' => 'foo/bar', + 'require' => array( + 'foo/baz' => '*', + 'bar/baz' => '>=1.0', + ), + 'provide' => array( + 'bar/foo' => 'dev-master', + ), + 'replace' => array( + 'bar/hacked' => '@stable', + ) + ), + array( + 'require.foo/baz : unbound version constraint detected (*)', + 'require.bar/baz : unbound version constraint detected (>=1.0)', + 'provide.bar/foo : unbound version constraint detected (dev-master)', + 'replace.bar/hacked : unbound version constraint detected (@stable)', + ) + ), ); } }