Browse Source

CS tweaks and cleanups, allow "" to set fallback dirs, refs #2459

Jordi Boggiano 11 years ago
parent
commit
3c5000ad7f

+ 1 - 1
res/composer-schema.json

@@ -209,7 +209,7 @@
                 },
                 "psr-4": {
                     "type": "object",
-                    "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can be found into (values, can be arrays of paths) by the autoloader.",
+                    "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
                     "additionalProperties": true
                 },
                 "classmap": {

+ 29 - 47
src/Composer/Autoload/AutoloadGenerator.php

@@ -99,9 +99,6 @@ EOF;
 
         // Process the 'psr-4' base directories.
         foreach ($autoloads['psr-4'] as $namespace => $paths) {
-            if ('\\' !== $namespace[strlen($namespace) - 1]) {
-                throw new \Exception("PSR-4 namespaces must end with a namespace separator. '$namespace' does not.");
-            }
             $exportedPaths = array();
             foreach ($paths as $path) {
                 $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
@@ -160,47 +157,25 @@ EOF;
         // flatten array
         $classMap = array();
         if ($scanPsr0Packages) {
-            // Scan the PSR-0 directories for class files, and add them to the
-            // class map.
-            foreach ($autoloads['psr-0'] as $namespace => $paths) {
-                foreach ($paths as $dir) {
-                    $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
-                    if (!is_dir($dir)) {
-                        continue;
-                    }
-                    $whitelist = sprintf(
-                        '{%s/%s.+(?<!(?<!/)Test\.php)$}',
-                        preg_quote($dir),
-                        strpos($namespace, '_') === false ? preg_quote(strtr($namespace, '\\', '/')) : ''
-                    );
-                    foreach (ClassMapGenerator::createMap($dir, $whitelist) as $class => $path) {
-                        if ('' === $namespace || 0 === strpos($class, $namespace)) {
-                            if (!isset($classMap[$class])) {
-                                $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
-                                $classMap[$class] = $path.",\n";
-                            }
+            // Scan the PSR-0/4 directories for class files, and add them to the class map
+            foreach (array('psr-0', 'psr-4') as $psrType) {
+                foreach ($autoloads[$psrType] as $namespace => $paths) {
+                    foreach ($paths as $dir) {
+                        $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
+                        if (!is_dir($dir)) {
+                            continue;
                         }
-                    }
-                }
-            }
-            // Scan the PSR-4 directories for class files, and add them to the
-            // class map.
-            foreach ($autoloads['psr-4'] as $namespace => $paths) {
-                foreach ($paths as $dir) {
-                    $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
-                    if (!is_dir($dir)) {
-                        continue;
-                    }
-                    $whitelist = sprintf(
-                        '{%s/%s.+(?<!(?<!/)Test\.php)$}',
-                        preg_quote($dir),
-                        strpos($namespace, '_') === false ? preg_quote(strtr($namespace, '\\', '/')) : ''
-                    );
-                    foreach (ClassMapGenerator::createMap($dir, $whitelist) as $class => $path) {
-                        if ('' === $namespace || 0 === strpos($class, $namespace)) {
-                            if (!isset($classMap[$class])) {
-                                $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
-                                $classMap[$class] = $path.",\n";
+                        $whitelist = sprintf(
+                            '{%s/%s.+(?<!(?<!/)Test\.php)$}',
+                            preg_quote($dir),
+                            ($psrType === 'psr-4' || strpos($namespace, '_') === false) ? preg_quote(strtr($namespace, '\\', '/')) : ''
+                        );
+                        foreach (ClassMapGenerator::createMap($dir, $whitelist) as $class => $path) {
+                            if ('' === $namespace || 0 === strpos($class, $namespace)) {
+                                if (!isset($classMap[$class])) {
+                                    $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
+                                    $classMap[$class] = $path.",\n";
+                                }
                             }
                         }
                     }
@@ -273,15 +248,22 @@ EOF;
     /**
      * @param PackageInterface $package
      *
-     * @throws \Exception
-     *   Throws an exception, if the package has illegal settings.
+     * @throws \InvalidArgumentException Throws an exception, if the package has illegal settings.
      */
-    protected function validatePackage(PackageInterface $package) {
+    protected function validatePackage(PackageInterface $package)
+    {
         $autoload = $package->getAutoload();
         if (!empty($autoload['psr-4']) && null !== $package->getTargetDir()) {
             $name = $package->getName();
             $package->getTargetDir();
-            throw new \Exception("The ['autoload']['psr-4'] setting is incompatible with the ['target-dir'] setting, in package '$name'.");
+            throw new \InvalidArgumentException("PSR-4 autoloading is incompatible with the target-dir property, remove the target-dir in package '$name'.");
+        }
+        if (!empty($autoload['psr-4'])) {
+            foreach ($autoload['psr-4'] as $namespace => $dirs) {
+                if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
+                    throw new \InvalidArgumentException("psr-4 namespaces must end with a namespace separator, '$namespace' does not, use '$namespace\\'.");
+                }
+            }
         }
     }
 

+ 4 - 6
src/Composer/Autoload/ClassLoader.php

@@ -163,7 +163,7 @@ class ClassLoader
             // Register directories for a new namespace.
             $length = strlen($prefix);
             if ('\\' !== $prefix[$length - 1]) {
-                throw new \Exception("A non-empty PSR-4 prefix must end with a namespace separator.");
+                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
             }
             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
             $this->prefixDirsPsr4[$prefix] = (array) $paths;
@@ -211,7 +211,7 @@ class ClassLoader
         } else {
             $length = strlen($prefix);
             if ('\\' !== $prefix[$length - 1]) {
-                throw new \Exception("A non-empty PSR-4 prefix must end with a namespace separator.");
+                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
             }
             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
             $this->prefixDirsPsr4[$prefix] = (array) $paths;
@@ -317,10 +317,8 @@ class ClassLoader
         // PSR-0 lookup
         if (false !== $pos = strrpos($class, '\\')) {
             // namespaced class name
-            $logicalPathPsr0
-              = substr($logicalPathPsr4, 0, $pos + 1)
-              . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR)
-            ;
+            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
         } else {
             // PEAR-like class name
             $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';

+ 8 - 1
src/Composer/Package/Loader/ValidatingArrayLoader.php

@@ -186,11 +186,18 @@ class ValidatingArrayLoader implements LoaderInterface
                     $this->errors[] = 'autoload : invalid value ('.$type.'), must be one of '.implode(', ', $types);
                     unset($this->config['autoload'][$type]);
                 }
+                if ($type === 'psr-4') {
+                    foreach ($typeConfig as $namespace => $dirs) {
+                        if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
+                            $this->errors[] = 'autoload.psr-4 : invalid value ('.$namespace.'), namespaces must end with a namespace separator, should be '.$namespace.'\\';
+                        }
+                    }
+                }
             }
         }
 
         if (!empty($this->config['autoload']['psr-4']) && !empty($this->config['target-dir'])) {
-            $this->errors[] = "The ['autoload']['psr-4'] setting is incompatible with the ['target-dir'] setting.";
+            $this->errors[] = 'target-dir : this can not be used together with the autoload.psr-4 setting, remove target-dir to upgrade to psr-4';
             // Unset the psr-4 setting, since unsetting target-dir might
             // interfere with other settings.
             unset($this->config['autoload']['psr-4']);

+ 5 - 2
tests/Composer/Test/Autoload/AutoloadGeneratorTest.php

@@ -252,11 +252,14 @@ class AutoloadGeneratorTest extends TestCase
         $this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated, even if empty.");
     }
 
-    public function testPSR0ToClassMapIgnoresNonExistingDir()
+    public function testPSRToClassMapIgnoresNonExistingDir()
     {
         $package = new Package('a', '1.0', '1.0');
 
-        $package->setAutoload(array('psr-0' => array('foo/bar/non/existing/')));
+        $package->setAutoload(array(
+            'psr-0' => array('Prefix' => 'foo/bar/non/existing/'),
+            'psr-4' => array('Prefix\\' => 'foo/bar/non/existing2/')
+        ));
 
         $this->repository->expects($this->once())
             ->method('getCanonicalPackages')

+ 12 - 19
tests/Composer/Test/Autoload/ClassLoaderTest.php

@@ -14,13 +14,9 @@ class ClassLoaderTest extends \PHPUnit_Framework_TestCase
      *
      * @dataProvider getLoadClassTests
      *
-     * @param string $class
-     *   The fully-qualified class name to test,
-     *   without preceding namespace separator.
-     * @param bool $prependSeparator
-     *   Whether to call ->loadClass() with a class name with preceding
-     *   namespace separator, as it happens in PHP 5.3.0 - 5.3.2.
-     *   See https://bugs.php.net/50731
+     * @param string $class The fully-qualified class name to test, without preceding namespace separator.
+     * @param bool $prependSeparator Whether to call ->loadClass() with a class name with preceding
+     *                               namespace separator, as it happens in PHP 5.3.0 - 5.3.2. See https://bugs.php.net/50731
      */
     public function testLoadClass($class, $prependSeparator = FALSE)
     {
@@ -30,12 +26,11 @@ class ClassLoaderTest extends \PHPUnit_Framework_TestCase
         $loader->addPsr4('ShinyVendor\\ShinyPackage\\', __DIR__ . '/Fixtures');
 
         if ($prependSeparator) {
-          $prepend = '\\';
-          $message = "->loadClass() loads '$class'.";
-        }
-        else {
-          $prepend = '';
-          $message = "->loadClass() loads '\\$class', as required in PHP 5.3.0 - 5.3.2.";
+            $prepend = '\\';
+            $message = "->loadClass() loads '$class'.";
+        } else {
+            $prepend = '';
+            $message = "->loadClass() loads '\\$class', as required in PHP 5.3.0 - 5.3.2.";
         }
 
         $loader->loadClass($prepend . $class);
@@ -45,8 +40,7 @@ class ClassLoaderTest extends \PHPUnit_Framework_TestCase
     /**
      * Provides arguments for ->testLoadClass().
      *
-     * @return array
-     *   Array of parameter sets to test with.
+     * @return array Array of parameter sets to test with.
      */
     public function getLoadClassTests()
     {
@@ -56,10 +50,9 @@ class ClassLoaderTest extends \PHPUnit_Framework_TestCase
             array('ShinyVendor\\ShinyPackage\\SubNamespace\\Foo'),
             // "Bar" would not work here, since it is defined in a ".inc" file,
             // instead of a ".php" file. So, use "Baz" instead.
-            array('Namespaced\\Baz', '\\'),
-            array('Pearlike_Bar', '\\'),
-            array('ShinyVendor\\ShinyPackage\\SubNamespace\\Bar', '\\'),
+            array('Namespaced\\Baz', true),
+            array('Pearlike_Bar', true),
+            array('ShinyVendor\\ShinyPackage\\SubNamespace\\Bar', true),
         );
     }
-
 }