Browse Source

Add validators for package links and minimum-stability

Jordi Boggiano 12 years ago
parent
commit
4b531771bd

+ 39 - 0
src/Composer/Package/Loader/InvalidPackageException.php

@@ -0,0 +1,39 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * 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 <j.boggiano@seld.be>
+ */
+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;
+    }
+}

+ 45 - 10
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);

+ 3 - 3
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);

+ 3 - 2
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);