Browse Source

AutoloadGenerator: respect dependencies, when requiring files

Filip Procházka 12 years ago
parent
commit
9d8db4e148

+ 21 - 5
src/Composer/Autoload/AutoloadGenerator.php

@@ -170,13 +170,30 @@ EOF;
     {
         // build package => install path map
         $packageMap = array();
+        $packages[] = $mainPackage;
 
-        // add main package
-        $packageMap[] = array($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());
+        });
 
         foreach ($packages as $package) {
             if ($package instanceof AliasPackage) {
                 continue;
+            } elseif ($package === $mainPackage) {
+                $packageMap[] = array($mainPackage, '');
+                continue;
             }
             $packageMap[] = array(
                 $package,
@@ -217,9 +234,8 @@ EOF;
             }
         }
 
-        foreach ($autoloads as $type => $maps) {
-            krsort($autoloads[$type]);
-        }
+        krsort($autoloads['classmap']);
+        krsort($autoloads['psr-0']);
 
         return $autoloads;
     }

+ 47 - 0
tests/Composer/Test/Autoload/AutoloadGeneratorTest.php

@@ -13,6 +13,7 @@
 namespace Composer\Test\Autoload;
 
 use Composer\Autoload\AutoloadGenerator;
+use Composer\Package\Link;
 use Composer\Util\Filesystem;
 use Composer\Package\AliasPackage;
 use Composer\Package\Package;
@@ -317,6 +318,52 @@ class AutoloadGeneratorTest extends TestCase
         $this->assertTrue(function_exists('testFilesAutoloadGenerationRoot'));
     }
 
+    public function testFilesAutoloadOrderByDependencies()
+    {
+        $package = new Package('a', '1.0', '1.0');
+        $package->setAutoload(array('files' => array('root.php')));
+        $package->setRequires(array(new Link('a', 'a/foo')));
+
+        $packages = array();
+        $packages[] = $a = new Package('a/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');
+
+        $a->setAutoload(array('files' => array('testA.php')));
+        $a->setRequires(array(new Link('a/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')));
+
+        $this->repository->expects($this->once())
+            ->method('getPackages')
+            ->will($this->returnValue($packages));
+
+        $this->fs->ensureDirectoryExists($this->vendorDir . '/a/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() {}');
+        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->workingDir . '/root.php', '<?php function testFilesAutoloadOrderByDependencyRoot() {}');
+
+        $this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, 'FilesAutoloadOrder');
+        $this->assertFileEquals(__DIR__ . '/Fixtures/autoload_functions_by_dependency.php', $this->vendorDir . '/autoload.php');
+        $this->assertFileEquals(__DIR__ . '/Fixtures/autoload_real_files_by_dependency.php', $this->vendorDir . '/composer/autoload_realFilesAutoloadOrder.php');
+
+        // suppress the class loader to avoid fatals if the class is redefined
+        file_put_contents($this->vendorDir . '/composer/ClassLoader.php', '');
+
+        include $this->vendorDir . '/autoload.php';
+
+        $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency1'));
+        $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency2'));
+        $this->assertTrue(function_exists('testFilesAutoloadOrderByDependency3'));
+        $this->assertTrue(function_exists('testFilesAutoloadOrderByDependencyRoot'));
+    }
+
     public function testOverrideVendorsAutoloading()
     {
         $package = new Package('a', '1.0', '1.0');

+ 7 - 0
tests/Composer/Test/Autoload/Fixtures/autoload_functions_by_dependency.php

@@ -0,0 +1,7 @@
+<?php
+
+// autoload.php generated by Composer
+
+require_once __DIR__ . '/composer' . '/autoload_realFilesAutoloadOrder.php';
+
+return ComposerAutoloaderInitFilesAutoloadOrder::getLoader();

+ 34 - 0
tests/Composer/Test/Autoload/Fixtures/autoload_real_files_by_dependency.php

@@ -0,0 +1,34 @@
+<?php
+
+// autoload_realFilesAutoloadOrder.php generated by Composer
+
+require __DIR__ . '/ClassLoader.php';
+
+class ComposerAutoloaderInitFilesAutoloadOrder
+{
+    public static function getLoader()
+    {
+        $loader = new \Composer\Autoload\ClassLoader();
+        $vendorDir = dirname(__DIR__);
+        $baseDir = dirname($vendorDir);
+
+        $map = require __DIR__ . '/autoload_namespaces.php';
+        foreach ($map as $namespace => $path) {
+            $loader->add($namespace, $path);
+        }
+
+        $classMap = require __DIR__ . '/autoload_classmap.php';
+        if ($classMap) {
+            $loader->addClassMap($classMap);
+        }
+
+        $loader->register();
+
+        require $vendorDir . '/c/lorem/testC.php';
+        require $vendorDir . '/a/foo/testA.php';
+        require $baseDir . '/root.php';
+        require $vendorDir . '/b/bar/testB.php';
+
+        return $loader;
+    }
+}