diff --git a/src/Composer/Package/Loader/InvalidPackageException.php b/src/Composer/Package/Loader/InvalidPackageException.php new file mode 100644 index 000000000..c409327c8 --- /dev/null +++ b/src/Composer/Package/Loader/InvalidPackageException.php @@ -0,0 +1,39 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Package\Loader; + +/** + * @author Jordi Boggiano + */ +class InvalidPackageException extends \Exception +{ + private $errors; + private $data; + + public function __construct(array $errors, array $data) + { + $this->errors = $errors; + $this->data = $data; + parent::__construct("Invalid package information: \n".implode("\n", $errors)); + } + + public function getData() + { + return $this->data; + } + + public function getErrors() + { + return $this->errors; + } +} diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php index d48d853fd..f2e8e38ef 100644 --- a/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -13,6 +13,7 @@ namespace Composer\Package\Loader; use Composer\Package; +use Composer\Package\BasePackage; use Composer\Package\Version\VersionParser; /** @@ -42,12 +43,12 @@ class ValidatingArrayLoader implements LoaderInterface $this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true); - if (!empty($config['version'])) { + if (!empty($this->config['version'])) { try { - $this->versionParser->normalize($config['version']); + $this->versionParser->normalize($this->config['version']); } catch (\Exception $e) { unset($this->config['version']); - $this->errors[] = 'version : invalid value ('.$config['version'].'): '.$e->getMessage(); + $this->errors[] = 'version : invalid value ('.$this->config['version'].'): '.$e->getMessage(); } } @@ -60,8 +61,8 @@ class ValidatingArrayLoader implements LoaderInterface $this->validateUrl('homepage'); $this->validateFlatArray('keywords', '[A-Za-z0-9 -]+'); - if (isset($config['license'])) { - if (is_string($config['license'])) { + if (isset($this->config['license'])) { + if (is_string($this->config['license'])) { $this->validateRegex('license', '[A-Za-z0-9+. ()-]+'); } else { $this->validateFlatArray('license', '[A-Za-z0-9+. ()-]+'); @@ -71,7 +72,7 @@ class ValidatingArrayLoader implements LoaderInterface $this->validateString('time'); if (!empty($this->config['time'])) { try { - $date = new \DateTime($config['time']); + $date = new \DateTime($this->config['time']); } catch (\Exception $e) { $this->errors[] = 'time : invalid value ('.$this->config['time'].'): '.$e->getMessage(); unset($this->config['time']); @@ -136,15 +137,49 @@ class ValidatingArrayLoader implements LoaderInterface } } - // TODO validate require/require-dev/replace/provide - // TODO validate suggest + foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) { + if (isset($this->config[$linkType])) { + foreach ($this->config[$linkType] as $package => $constraint) { + if (!is_string($constraint)) { + $this->errors[] = $linkType.'.'.$package.' : invalid value, must be a string containing a version constraint'; + unset($this->config[$linkType][$package]); + } elseif ('self.version' !== $constraint) { + try { + $this->versionParser->parseConstraints($constraint); + } catch (\Exception $e) { + $this->errors[] = $linkType.'.'.$package.' : invalid version constraint ('.$e->getMessage().')'; + unset($this->config[$linkType][$package]); + } + } + } + } + } + + $this->validateArray('suggest'); + if (!empty($this->config['suggest'])) { + foreach ($this->config['suggest'] as $package => $description) { + if (!is_string($description)) { + $this->errors[] = 'suggest.'.$package.' : invalid value, must be a string describing why the package is suggested'; + unset($this->config['suggest'][$package]); + } + } + } + + $this->validateString('minimum-stability'); + if (!empty($this->config['minimum-stability'])) { + if (!isset(BasePackage::$stabilities[$this->config['minimum-stability']])) { + $this->errors[] = 'minimum-stability : invalid value, must be one of '.implode(', ', array_keys(BasePackage::$stabilities)); + unset($this->config['minimum-stability']); + } + } + // TODO validate autoload - // TODO validate minimum-stability // TODO validate dist // TODO validate source // TODO validate repositories + // TODO validate package repositories' packages using this recursively $this->validateFlatArray('include-path'); @@ -173,7 +208,7 @@ class ValidatingArrayLoader implements LoaderInterface } if ($this->errors && !$this->ignoreErrors) { - throw new \Exception(implode("\n", $this->errors)); + throw new InvalidPackageException($this->errors, $config); } $package = $this->loader->load($this->config, $class); diff --git a/src/Composer/Util/ConfigValidator.php b/src/Composer/Util/ConfigValidator.php index 3a2f24e50..a2310611d 100644 --- a/src/Composer/Util/ConfigValidator.php +++ b/src/Composer/Util/ConfigValidator.php @@ -14,6 +14,7 @@ namespace Composer\Util; use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ValidatingArrayLoader; +use Composer\Package\Loader\InvalidPackageException; use Composer\Json\JsonValidationException; use Composer\IO\IOInterface; use Composer\Json\JsonFile; @@ -95,7 +96,6 @@ class ConfigValidator ); } - // TODO validate package repositories' packages using the same technique as below try { $loader = new ValidatingArrayLoader(new ArrayLoader(), false); if (!isset($manifest['version'])) { @@ -105,8 +105,8 @@ class ConfigValidator $manifest['name'] = 'dummy/dummy'; } $loader->load($manifest); - } catch (\Exception $e) { - $errors = array_merge($errors, explode("\n", $e->getMessage())); + } catch (InvalidPackageException $e) { + $errors = array_merge($errors, $e->getErrors()); } return array($errors, $publishErrors, $warnings); diff --git a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php index e9a00e34a..5d7ba98e4 100644 --- a/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/ValidatingArrayLoaderTest.php @@ -14,6 +14,7 @@ namespace Composer\Test\Package\Loader; use Composer\Package; use Composer\Package\Loader\ValidatingArrayLoader; +use Composer\Package\Loader\InvalidPackageException; class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase { @@ -156,8 +157,8 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase try { $loader->load($config); $this->fail('Expected exception to be thrown'); - } catch (\Exception $e) { - $errors = explode("\n", $e->getMessage()); + } catch (InvalidPackageException $e) { + $errors = $e->getErrors(); sort($expectedErrors); sort($errors); $this->assertEquals($expectedErrors, $errors);