Browse Source

Fixed topological sorting of packages in AutoloadGenerator

Martin Hasoň 12 years ago
parent
commit
03e355f063

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

@@ -179,17 +179,12 @@ EOF;
     {
         // build package => install path map
         $packageMap = array();
-        array_unshift($packages, $mainPackage);
 
         foreach ($packages as $package) {
             if ($package instanceof AliasPackage) {
                 continue;
             }
 
-            if ($package === $mainPackage) {
-                $packageMap[] = array($mainPackage, '');
-                continue;
-            }
             $packageMap[] = array(
                 $package,
                 $installationManager->getInstallPath($package)
@@ -209,6 +204,8 @@ EOF;
     public function parseAutoloads(array $packageMap, PackageInterface $mainPackage)
     {
         $sortedPackageMap = $this->sortPackageMap($packageMap);
+        $sortedPackageMap[] = array($mainPackage, '');
+        array_unshift($packageMap, array($mainPackage, ''));
 
         $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
         $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage);
@@ -434,6 +431,7 @@ FOOTER;
     protected function parseAutoloadsType(array $packageMap, $type, PackageInterface $mainPackage)
     {
         $autoloads = array();
+
         foreach ($packageMap as $item) {
             list($package, $installPath) = $item;
 
@@ -465,49 +463,45 @@ FOOTER;
 
     protected function sortPackageMap(array $packageMap)
     {
-        $groups = array();
+        $positions = array();
         $names = array();
-        foreach ($packageMap as $key => $item) {
-            $groups[$key] = array($item);
+        $indexes = array();
+
+        foreach ($packageMap as $position => $item) {
             $mainName = $item[0]->getName();
-            foreach ($item[0]->getNames() as $name) {
-                if (!isset($names[$name])) {
-                    $names[$name] = $name == $mainName ? $key : $mainName;
-                }
-            }
+            $names = array_merge(array_fill_keys($item[0]->getNames(), $mainName), $names);
+            $names[$mainName] = $mainName;
+            $indexes[$mainName] = $positions[$mainName] = $position;
         }
 
         foreach ($packageMap as $item) {
+            $position = $positions[$item[0]->getName()];
             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])) {
+                $target = $names[$target];
+                if ($positions[$target] <= $position) {
                     continue;
                 }
 
-                foreach ($groups[$packageKey] as $originalItem) {
-                    $groups[$targetKey][] = $originalItem;
-                    $names[$originalItem[0]->getName()] = $targetKey;
+                foreach ($positions as $key => $value) {
+                    if ($value >= $position) {
+                        break;
+                    }
+                    $positions[$key]--;
                 }
-                unset($groups[$packageKey]);
+
+                $positions[$target] = $position - 1;
             }
+            asort($positions);
         }
 
         $sortedPackageMap = array();
-        foreach ($groups as $group) {
-            $sortedPackageMap = array_merge($sortedPackageMap, $group);
+        foreach (array_keys($positions) as $packageName) {
+            $sortedPackageMap[] = $packageMap[$indexes[$packageName]];
         }
 
         return $sortedPackageMap;

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

@@ -338,23 +338,26 @@ 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', 'z/foo')));
+        $package->setRequires(array(new Link('a', 'd/d')));
+        $package->setRequires(array(new Link('a', 'e/e')));
 
         $packages = array();
         $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[] = $c = new Package('c/lorem', '1.0', '1.0');
         $packages[] = $e = new Package('e/e', '1.0', '1.0');
 
         $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')));
+        $b->setRequires(array(new Link('b/bar', 'c/lorem'), new Link('b/bar', 'd/d')));
 
         $c->setAutoload(array('files' => array('testC.php')));
 
         $d->setAutoload(array('files' => array('testD.php')));
+        $d->setRequires(array(new Link('d/d', 'c/lorem')));
 
         $e->setAutoload(array('files' => array('testE.php')));
         $e->setRequires(array(new Link('e/e', 'c/lorem')));

+ 2 - 2
tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php

@@ -40,10 +40,10 @@ class ComposerAutoloaderInitFilesAutoloadOrder
 
         require $vendorDir . '/c/lorem/testC.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 . '/b/bar/testB.php';
         require $vendorDir . '/e/e/testE.php';
+        require $baseDir . '/root.php';
 
         return $loader;
     }

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

@@ -38,9 +38,9 @@ class ComposerAutoloaderInitFilesAutoload
 
         $loader->register();
 
-        require $baseDir . '/root.php';
         require $vendorDir . '/a/a/test.php';
         require $vendorDir . '/b/b/test2.php';
+        require $baseDir . '/root.php';
 
         return $loader;
     }