浏览代码

Merge remote-tracking branch 'hason/classgenerator'

Jordi Boggiano 12 年之前
父节点
当前提交
e79e7dcd8d

+ 87 - 42
src/Composer/Autoload/AutoloadGenerator.php

@@ -117,8 +117,6 @@ EOF;
 
         // flatten array
         $classMap = array();
-        $autoloads['classmap'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['classmap']));
-
         if ($scanPsr0Packages) {
             foreach ($autoloads['psr-0'] as $namespace => $paths) {
                 foreach ($paths as $dir) {
@@ -139,12 +137,16 @@ EOF;
                 }
             }
         }
+
+        $autoloads['classmap'] = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($autoloads['classmap']));
         foreach ($autoloads['classmap'] as $dir) {
             foreach (ClassMapGenerator::createMap($dir) as $class => $path) {
                 $path = '/'.$filesystem->findShortestPath(getcwd(), $path, true);
                 $classMap[$class] = '$baseDir . '.var_export($path, true).",\n";
             }
         }
+
+        ksort($classMap);
         foreach ($classMap as $class => $code) {
             $classmapFile .= '    '.var_export($class, true).' => '.$code;
         }
@@ -170,28 +172,13 @@ EOF;
     {
         // build package => install path map
         $packageMap = array();
-        $packages[] = $mainPackage;
-
-        // sort packages by dependencies
-        usort($packages, function (PackageInterface $a, PackageInterface $b) {
-            foreach (array_merge($a->getRequires(), $a->getDevRequires()) as $link) {
-                if (in_array($link->getTarget(), $b->getNames())) {
-                    return 1;
-                }
-            }
-            foreach (array_merge($b->getRequires(), $b->getDevRequires()) as $link) {
-                if (in_array($link->getTarget(), $a->getNames())) {
-                    return -1;
-                }
-            }
-
-            return strcmp($a->getName(), $b->getName());
-        });
+        array_unshift($packages, $mainPackage);
 
         foreach ($packages as $package) {
             if ($package instanceof AliasPackage) {
                 continue;
             }
+
             if ($package === $mainPackage) {
                 $packageMap[] = array($mainPackage, '');
                 continue;
@@ -213,32 +200,15 @@ EOF;
      */
     public function parseAutoloads(array $packageMap)
     {
-        $autoloads = array('classmap' => array(), 'psr-0' => array(), 'files' => array());
-        foreach ($packageMap as $item) {
-            list($package, $installPath) = $item;
+        $sortedPackageMap = $this->sortPackageMap($packageMap);
 
-            if (null !== $package->getTargetDir()) {
-                $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
-            }
+        $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0');
+        $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap');
+        $files = $this->parseAutoloadsType($sortedPackageMap, 'files');
 
-            foreach ($package->getAutoload() as $type => $mapping) {
-                // skip misconfigured packages
-                if (!is_array($mapping)) {
-                    continue;
-                }
-
-                foreach ($mapping as $namespace => $paths) {
-                    foreach ((array) $paths as $path) {
-                        $autoloads[$type][$namespace][] = empty($installPath) ? $path : $installPath.'/'.$path;
-                    }
-                }
-            }
-        }
-
-        krsort($autoloads['classmap']);
-        krsort($autoloads['psr-0']);
+        krsort($psr0);
 
-        return $autoloads;
+        return array('psr-0' => $psr0, 'classmap' => $classmap, 'files' => $files);
     }
 
     /**
@@ -445,4 +415,79 @@ FOOTER;
 
     }
 
+    protected function parseAutoloadsType(array $packageMap, $type)
+    {
+        $autoloads = array();
+        foreach ($packageMap as $item) {
+            list($package, $installPath) = $item;
+
+            $autoload = $package->getAutoload();
+            // skip misconfigured packages
+            if (!isset($autoload[$type]) || !is_array($autoload[$type])) {
+                continue;
+            }
+
+            if (null !== $package->getTargetDir()) {
+                $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
+            }
+
+            foreach ($autoload[$type] as $namespace => $paths) {
+                foreach ((array) $paths as $path) {
+                    $autoloads[$namespace][] = empty($installPath) ? $path : $installPath.'/'.$path;
+                }
+            }
+        }
+
+        return $autoloads;
+    }
+
+    protected function sortPackageMap(array $packageMap)
+    {
+        $groups = array();
+        $names = array();
+        foreach ($packageMap as $key => $item) {
+            $groups[$key] = array($item);
+            $mainName = $item[0]->getName();
+            foreach ($item[0]->getNames() as $name) {
+                if (!isset($names[$name])) {
+                    $names[$name] = $name == $mainName ? $key : $mainName;
+                }
+            }
+        }
+
+        foreach ($packageMap as $item) {
+            foreach (array_merge($item[0]->getRequires(), $item[0]->getDevRequires()) as $link) {
+                $target = $link->getTarget();
+                if (!isset($names[$target])) {
+                    continue;
+                }
+
+                $targetKey = $names[$target];
+                if (is_string($targetKey)) {
+                    if (!isset($names[$targetKey])) {
+                        continue;
+                    }
+                    $targetKey = $names[$targetKey];
+                }
+
+                $packageKey = $names[$item[0]->getName()];
+                if ($targetKey <= $packageKey || !isset($groups[$packageKey])) {
+                    continue;
+                }
+
+                foreach ($groups[$packageKey] as $originalItem) {
+                    $groups[$targetKey][] = $originalItem;
+                    $names[$originalItem[0]->getName()] = $targetKey;
+                }
+                unset($groups[$packageKey]);
+            }
+        }
+
+        $sortedPackageMap = array();
+        foreach ($groups as $group) {
+            $sortedPackageMap = array_merge($sortedPackageMap, $group);
+        }
+
+        return $sortedPackageMap;
+    }
 }

+ 30 - 11
tests/Composer/Test/Autoload/AutoloadGeneratorTest.php

@@ -238,9 +238,9 @@ class AutoloadGeneratorTest extends TestCase
         $this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
         $this->assertEquals(
             array(
-                'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
                 'ClassMapBar' => $this->workingDir.'/composer-test-autoload/b/b/src/b.php',
                 'ClassMapBaz' => $this->workingDir.'/composer-test-autoload/b/b/lib/c.php',
+                'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
             ),
             include ($this->vendorDir.'/composer/autoload_classmap.php')
         );
@@ -275,9 +275,9 @@ class AutoloadGeneratorTest extends TestCase
         $this->assertTrue(file_exists($this->vendorDir.'/composer/autoload_classmap.php'), "ClassMap file needs to be generated.");
         $this->assertEquals(
             array(
-                'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
                 'ClassMapBar' => $this->workingDir.'/composer-test-autoload/b/b/test.php',
                 'ClassMapBaz' => $this->workingDir.'/composer-test-autoload/c/c/foo/test.php',
+                'ClassMapFoo' => $this->workingDir.'/composer-test-autoload/a/a/src/a.php',
             ),
             include ($this->vendorDir.'/composer/autoload_classmap.php')
         );
@@ -322,31 +322,42 @@ class AutoloadGeneratorTest extends TestCase
     {
         $package = new Package('a', '1.0', '1.0');
         $package->setAutoload(array('files' => array('root.php')));
-        $package->setRequires(array(new Link('a', 'a/foo')));
+        $package->setRequires(array(new Link('a', 'z/foo')));
 
         $packages = array();
-        $packages[] = $a = new Package('a/foo', '1.0', '1.0');
+        $packages[] = $z = new Package('z/foo', '1.0', '1.0');
         $packages[] = $b = new Package('b/bar', '1.0', '1.0');
         $packages[] = $c = new Package('c/lorem', '1.0', '1.0');
+        $packages[] = $d = new Package('d/d', '1.0', '1.0');
+        $packages[] = $e = new Package('e/e', '1.0', '1.0');
 
-        $a->setAutoload(array('files' => array('testA.php')));
-        $a->setRequires(array(new Link('a/foo', 'c/lorem')));
+        $z->setAutoload(array('files' => array('testA.php')));
+        $z->setRequires(array(new Link('z/foo', 'c/lorem')));
 
         $b->setAutoload(array('files' => array('testB.php')));
         $b->setRequires(array(new Link('b/bar', 'c/lorem')));
 
         $c->setAutoload(array('files' => array('testC.php')));
 
+        $d->setAutoload(array('files' => array('testD.php')));
+
+        $e->setAutoload(array('files' => array('testE.php')));
+        $e->setRequires(array(new Link('e/e', 'c/lorem')));
+
         $this->repository->expects($this->once())
             ->method('getPackages')
             ->will($this->returnValue($packages));
 
-        $this->fs->ensureDirectoryExists($this->vendorDir . '/a/foo');
+        $this->fs->ensureDirectoryExists($this->vendorDir . '/z/foo');
         $this->fs->ensureDirectoryExists($this->vendorDir . '/b/bar');
         $this->fs->ensureDirectoryExists($this->vendorDir . '/c/lorem');
-        file_put_contents($this->vendorDir . '/a/foo/testA.php', '<?php function testFilesAutoloadOrderByDependency1() {}');
+        $this->fs->ensureDirectoryExists($this->vendorDir . '/d/d');
+        $this->fs->ensureDirectoryExists($this->vendorDir . '/e/e');
+        file_put_contents($this->vendorDir . '/z/foo/testA.php', '<?php function testFilesAutoloadOrderByDependency1() {}');
         file_put_contents($this->vendorDir . '/b/bar/testB.php', '<?php function testFilesAutoloadOrderByDependency2() {}');
         file_put_contents($this->vendorDir . '/c/lorem/testC.php', '<?php function testFilesAutoloadOrderByDependency3() {}');
+        file_put_contents($this->vendorDir . '/d/d/testD.php', '<?php function testFilesAutoloadOrderByDependency4() {}');
+        file_put_contents($this->vendorDir . '/e/e/testE.php', '<?php function testFilesAutoloadOrderByDependency5() {}');
         file_put_contents($this->workingDir . '/root.php', '<?php function testFilesAutoloadOrderByDependencyRoot() {}');
 
         $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, 'FilesAutoloadOrder');
@@ -361,18 +372,21 @@ class AutoloadGeneratorTest extends TestCase
         $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency1'));
         $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency2'));
         $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency3'));
+        $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency4'));
+        $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency5'));
         $this->assertTrue(function_exists('testFilesAutoloadOrderByDependencyRoot'));
     }
 
     public function testOverrideVendorsAutoloading()
     {
-        $package = new Package('a', '1.0', '1.0');
-        $package->setAutoload(array('psr-0' => array('A\\B' => $this->workingDir.'/lib')));
+        $package = new Package('z', '1.0', '1.0');
+        $package->setAutoload(array('psr-0' => array('A\\B' => $this->workingDir.'/lib'), 'classmap' => array($this->workingDir.'/src')));
+        $package->setRequires(array(new Link('z', 'a/a')));
 
         $packages = array();
         $packages[] = $a = new Package('a/a', '1.0', '1.0');
         $packages[] = $b = new Package('b/b', '1.0', '1.0');
-        $a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/')));
+        $a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/'), 'classmap' => array('classmap')));
         $b->setAutoload(array('psr-0' => array('B\\Sub\\Name' => 'src/')));
 
         $this->repository->expects($this->once())
@@ -380,12 +394,16 @@ class AutoloadGeneratorTest extends TestCase
             ->will($this->returnValue($packages));
 
         $this->fs->ensureDirectoryExists($this->workingDir.'/lib/A/B');
+        $this->fs->ensureDirectoryExists($this->workingDir.'/src/');
         $this->fs->ensureDirectoryExists($this->vendorDir.'/composer');
+        $this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/classmap');
         $this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/src');
         $this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/lib/A/B');
         $this->fs->ensureDirectoryExists($this->vendorDir.'/b/b/src');
         file_put_contents($this->workingDir.'/lib/A/B/C.php', '<?php namespace A\\B; class C {}');
+        file_put_contents($this->workingDir.'/src/classes.php', '<?php namespace Foo; class Bar {}');
         file_put_contents($this->vendorDir.'/a/a/lib/A/B/C.php', '<?php namespace A\\B; class C {}');
+        file_put_contents($this->vendorDir.'/a/a/classmap/classes.php', '<?php namespace Foo; class Bar {}');
 
         $workDir = strtr($this->workingDir, '\\', '/');
         $expectedNamespace = <<<EOF
@@ -414,6 +432,7 @@ EOF;
 
 return array(
     'A\\\\B\\\\C' => \$baseDir . '/lib/A/B/C.php',
+    'Foo\\\\Bar' => \$baseDir . '/src/classes.php',
 );
 
 EOF;

+ 1 - 1
tests/Composer/Test/Autoload/Fixtures/autoload_classmap3.php

@@ -6,6 +6,6 @@ $vendorDir = dirname(__DIR__);
 $baseDir = $vendorDir;
 
 return array(
-    'Main\\Foo' => $baseDir . '/src/Main/Foo.php',
     'ClassMapFoo' => $baseDir . '/composersrc/foo.php',
+    'Main\\Foo' => $baseDir . '/src/Main/Foo.php',
 );

+ 1 - 1
tests/Composer/Test/Autoload/Fixtures/autoload_classmap4.php

@@ -6,7 +6,7 @@ $vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
+    'ClassMapBar' => $baseDir . '/composer-test-autoload/b/b/src/b.php',
     'ClassMapBaz' => $baseDir . '/composer-test-autoload/b/b/lib/c.php',
     'ClassMapFoo' => $baseDir . '/composer-test-autoload/a/a/src/a.php',
-    'ClassMapBar' => $baseDir . '/composer-test-autoload/b/b/src/b.php',
 );

+ 1 - 1
tests/Composer/Test/Autoload/Fixtures/autoload_classmap5.php

@@ -6,7 +6,7 @@ $vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
-    'ClassMapFoo' => $baseDir . '/composer-test-autoload/a/a/src/a.php',
     'ClassMapBar' => $baseDir . '/composer-test-autoload/b/b/test.php',
     'ClassMapBaz' => $baseDir . '/composer-test-autoload/c/c/foo/test.php',
+    'ClassMapFoo' => $baseDir . '/composer-test-autoload/a/a/src/a.php',
 );

+ 3 - 1
tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php

@@ -31,9 +31,11 @@ class ComposerAutoloaderInitFilesAutoloadOrder
         $loader->register();
 
         require $vendorDir . '/c/lorem/testC.php';
-        require $vendorDir . '/a/foo/testA.php';
+        require $vendorDir . '/z/foo/testA.php';
         require $baseDir . '/root.php';
         require $vendorDir . '/b/bar/testB.php';
+        require $vendorDir . '/d/d/testD.php';
+        require $vendorDir . '/e/e/testE.php';
 
         return $loader;
     }