[TASK] Extract package dependency sorting to separate class 01/27101/6
authorThomas Maroschik <tmaroschik@dfau.de>
Tue, 28 Jan 2014 17:17:42 +0000 (18:17 +0100)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Sat, 1 Feb 2014 21:36:26 +0000 (22:36 +0100)
The Package Manager got pretty big due to the custom
dependency resolving algorithm of CMS. Further the
algorithm relied upon the presence of package objects
which might not be fully present yet during bootstrapping.

This patch extracts the dependency handling from the
Package Manager and adapts it to work only on the
package states configuration.

Resolves: #55404
Releases: 6.2
Change-Id: I00e7a3769378b48bd3f3c285ea2b3c6d824dd061
Reviewed-on: https://review.typo3.org/27101
Tested-by: Thomas Maroschik
Reviewed-by: Markus Klein
Reviewed-by: Stefan Neufeind
Tested-by: Stefan Neufeind
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Classes/Package/DependencyResolver.php [new file with mode: 0644]
typo3/sysext/core/Classes/Package/PackageManager.php
typo3/sysext/core/Resources/PHP/TYPO3.Flow/Classes/TYPO3/Flow/Package/PackageManagerInterface.php
typo3/sysext/core/Tests/Unit/Package/DependencyResolverTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Package/PackageManagerTest.php

index a4c50e5..182487a 100644 (file)
@@ -155,7 +155,7 @@ class Bootstrap {
         * @internal This is not a public API method, do not use in own extensions
         */
        public function baseSetup($relativePathPart = '') {
-               \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::run($relativePathPart);
+               SystemEnvironmentBuilder::run($relativePathPart);
                Utility\GeneralUtility::presetApplicationContext($this->applicationContext);
                return $this;
        }
@@ -262,7 +262,7 @@ class Bootstrap {
                $classLoader = new ClassLoader($this->applicationContext);
                $this->setEarlyInstance('TYPO3\\CMS\\Core\\Core\\ClassLoader', $classLoader);
                $classLoader->setRuntimeClassLoadingInformationFromAutoloadRegistry((array) include __DIR__ . '/../../ext_autoload.php');
-               $classAliasMap = new \TYPO3\CMS\Core\Core\ClassAliasMap();
+               $classAliasMap = new ClassAliasMap();
                $classAliasMap->injectClassLoader($classLoader);
                $this->setEarlyInstance('TYPO3\\CMS\\Core\\Core\\ClassAliasMap', $classAliasMap);
                $classLoader->injectClassAliasMap($classAliasMap);
@@ -316,6 +316,7 @@ class Bootstrap {
                Utility\ExtensionManagementUtility::setPackageManager($packageManager);
                $packageManager->injectClassLoader($this->getEarlyInstance('TYPO3\\CMS\\Core\\Core\\ClassLoader'));
                $packageManager->injectCoreCache($this->getEarlyInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_core'));
+               $packageManager->injectDependencyResolver(Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Package\\DependencyResolver'));
                $packageManager->initialize($this, PATH_site);
                Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Package\\PackageManager', $packageManager);
                $GLOBALS['TYPO3_LOADED_EXT'] = new \TYPO3\CMS\Core\Compatibility\LoadedExtensionsArray($packageManager);
@@ -363,7 +364,7 @@ class Bootstrap {
                $bootstrap = $this->getInstance();
                // Commented out for package management patch, method is still used in extensionmanager
                //              $bootstrap->populateTypo3LoadedExtGlobal(FALSE);
-               //              \TYPO3\CMS\Core\Core\ClassLoader::loadClassLoaderCache();
+               //              ClassLoader::loadClassLoaderCache();
                $bootstrap->loadAdditionalConfigurationFromExtensions(FALSE);
                return $this;
        }
diff --git a/typo3/sysext/core/Classes/Package/DependencyResolver.php b/typo3/sysext/core/Classes/Package/DependencyResolver.php
new file mode 100644 (file)
index 0000000..c72cc50
--- /dev/null
@@ -0,0 +1,257 @@
+<?php
+namespace TYPO3\CMS\Core\Package;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Markus Klein <klein.t3@mfc-linz.at>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * This class takes care about dependencies between packages.
+ * It provides functionality to resolve dependencies and to determine
+ * the crucial loading order of the packages.
+ *
+ * @author Markus Klein <klein.t3@mfc-linz.at>
+ */
+class DependencyResolver {
+
+       /**
+        * Folder with framework extensions
+        */
+       const SYSEXT_FOLDER = 'sysext';
+
+       /**
+        * @param array $packageStatesConfiguration
+        * @return array Returns the packageStatesConfiguration sorted by dependencies
+        * @throws \UnexpectedValueException
+        */
+       public function sortPackageStatesConfigurationByDependency(array $packageStatesConfiguration) {
+               // We just want to consider active packages
+               $activePackageStatesConfiguration = $this->removeInactivePackagesFromPackageStateConfiguration($packageStatesConfiguration);
+               $inactivePackageStatesConfiguration = array_diff_key($packageStatesConfiguration, $activePackageStatesConfiguration);
+
+               /*
+                * Adjacency matrix for the dependency graph (DAG)
+                *
+                * Example structure is:
+                *    A => (A => FALSE, B => TRUE,  C => FALSE)
+                *    B => (A => FALSE, B => FALSE, C => FALSE)
+                *    C => (A => TRUE,  B => FALSE, C => FALSE)
+                *
+                *    A depends on B, C depends on A, B is independent
+                */
+               $dependencyGraph = $this->buildDependencyGraph($activePackageStatesConfiguration);
+
+               // Filter extensions with no incoming edge
+               $rootPackageKeys = array();
+               foreach (array_keys($dependencyGraph) as $packageKey) {
+                       if (!$this->getIncomingEdgeCount($dependencyGraph, $packageKey)) {
+                               $rootPackageKeys[] = $packageKey;
+                       }
+               }
+
+               // This will contain our final result
+               $sortedPackageKeys = array();
+
+               // Walk through the graph
+               while (count($rootPackageKeys)) {
+                       $currentPackageKey = array_shift($rootPackageKeys);
+                       array_push($sortedPackageKeys, $currentPackageKey);
+
+                       $dependingPackageKeys = array_keys(array_filter($dependencyGraph[$currentPackageKey]));
+                       foreach ($dependingPackageKeys as $dependingPackageKey) {
+                               // Remove the edge to this dependency
+                               $dependencyGraph[$currentPackageKey][$dependingPackageKey] = FALSE;
+                               if (!$this->getIncomingEdgeCount($dependencyGraph, $dependingPackageKey)) {
+                                       // We found a new root, lets add it
+                                       array_unshift($rootPackageKeys, $dependingPackageKey);
+                               }
+                       }
+               }
+
+               // Check for remaining edges in the graph
+               $cycles = array();
+               array_walk($dependencyGraph, function($dependencies, $packageKeyFrom) use(&$cycles) {
+                       array_walk($dependencies, function($dependency, $packageKeyTo) use(&$cycles, $packageKeyFrom) {
+                               if ($dependency) {
+                                       $cycles[] = $packageKeyFrom . '->' . $packageKeyTo;
+                               }
+                       });
+               });
+               if (count($cycles)) {
+                       throw new \UnexpectedValueException('Your dependencies have cycles. That will not work out. Cycles found: ' . implode(', ', $cycles), 1381960493);
+               }
+
+               // We built now a list of dependencies
+               // Reverse the list to get the correct loading order
+               $sortedPackageKeys = array_reverse($sortedPackageKeys);
+
+               // Reorder the package states according to the loading order
+               $newPackageStatesConfiguration = array();
+               foreach ($sortedPackageKeys as $packageKey) {
+                       $newPackageStatesConfiguration[$packageKey] = $packageStatesConfiguration[$packageKey];
+               }
+
+               // Append the inactive configurations again
+               $newPackageStatesConfiguration = array_merge($newPackageStatesConfiguration, $inactivePackageStatesConfiguration);
+
+               return $newPackageStatesConfiguration;
+       }
+
+       /**
+        * Returns only active package state configurations
+        *
+        * @param array $packageStatesConfiguration
+        * @return array
+        */
+       protected function removeInactivePackagesFromPackageStateConfiguration(array $packageStatesConfiguration) {
+               return array_filter($packageStatesConfiguration, function($packageState) {
+                       return isset($packageState['state']) && $packageState['state'] === 'active';
+               });
+       }
+
+       /**
+        * Build the dependency graph for the given packages
+        *
+        * @param array $packageStatesConfiguration
+        * @param array $packageKeys
+        * @return array
+        * @throws \UnexpectedValueException
+        */
+       protected function buildDependencyGraphForPackages(array $packageStatesConfiguration, array $packageKeys) {
+               // Initialize the dependencies with FALSE
+               $dependencyGraph = array_fill_keys($packageKeys, array_fill_keys($packageKeys, FALSE));
+               foreach ($packageKeys as $packageKey) {
+                       $dependentPackageKeys = $packageStatesConfiguration[$packageKey]['dependencies'];
+                       foreach ($dependentPackageKeys as $dependentPackageKey) {
+                               if (!in_array($dependentPackageKey, $packageKeys)) {
+                                       throw new \UnexpectedValueException(
+                                               'The package "' . $packageKey .'" depends on "'
+                                               . $dependentPackageKey . '" which is not present in the system.',
+                                               1382276561);
+                               }
+                               $dependencyGraph[$packageKey][$dependentPackageKey] = TRUE;
+                       }
+               }
+               return $dependencyGraph;
+       }
+
+       /**
+        * Adds all root packages of current dependency graph as dependency
+        * to all extensions.
+        * This ensures that the framework extensions (aka sysext) are
+        * always loaded first, before any other external extension.
+        *
+        * @param array $packageStateConfiguration
+        * @param array $dependencyGraph
+        * @return array
+        */
+       protected function addDependencyToFrameworkToAllExtensions(array $packageStateConfiguration, array $dependencyGraph) {
+               $rootPackageKeys = array();
+               foreach (array_keys($dependencyGraph) as $packageKey) {
+                       if (!$this->getIncomingEdgeCount($dependencyGraph, $packageKey)) {
+                               $rootPackageKeys[] = $packageKey;
+                       }
+               }
+               $extensionPackageKeys = $this->getPackageKeysInBasePath($packageStateConfiguration, '', array(PATH_typo3 . self::SYSEXT_FOLDER));
+               $frameworkPackageKeys = $this->getPackageKeysInBasePath($packageStateConfiguration, PATH_typo3 . self::SYSEXT_FOLDER);
+               foreach ($extensionPackageKeys as $packageKey) {
+                       // Remove framework packages from list
+                       $packageKeysWithoutFramework = array_diff(
+                               $packageStateConfiguration[$packageKey]['dependencies'],
+                               $frameworkPackageKeys
+                       );
+                       // The order of the array_merge is crucial here,
+                       // we want the framework first
+                       $packageStateConfiguration[$packageKey]['dependencies'] = array_merge(
+                               $rootPackageKeys, $packageKeysWithoutFramework
+                       );
+               }
+               return $packageStateConfiguration;
+       }
+
+       /**
+        * Builds the dependency graph for all packages
+        *
+        * This method also introduces dependencies among the dependencies
+        * to ensure the loading order is exactly as specified in the list.
+        *
+        * @param array $packageStateConfiguration
+        * @return array
+        */
+       protected function buildDependencyGraph(array $packageStateConfiguration) {
+               $frameworkPackageKeys = $this->getPackageKeysInBasePath($packageStateConfiguration, PATH_typo3 . self::SYSEXT_FOLDER);
+               $dependencyGraph = $this->buildDependencyGraphForPackages($packageStateConfiguration, $frameworkPackageKeys);
+               $packageStateConfiguration = $this->addDependencyToFrameworkToAllExtensions($packageStateConfiguration, $dependencyGraph);
+
+               $packageKeys = array_keys($packageStateConfiguration);
+               $dependencyGraph = $this->buildDependencyGraphForPackages($packageStateConfiguration, $packageKeys);
+               return $dependencyGraph;
+       }
+
+
+
+       /**
+        * Get the number of incoming edges in the dependency graph
+        * for given package key.
+        *
+        * @param array $dependencyGraph
+        * @param string $packageKey
+        * @return integer
+        */
+       protected function getIncomingEdgeCount(array $dependencyGraph, $packageKey) {
+               $incomingEdgeCount = 0;
+               foreach ($dependencyGraph as $dependencies) {
+                       if ($dependencies[$packageKey]) {
+                               $incomingEdgeCount++;
+                       }
+               }
+               return $incomingEdgeCount;
+       }
+
+       /**
+        * Get packages of specific type
+        *
+        * @param array $packageStateConfiguration
+        * @param string $basePath Base path of package. Empty string for all types
+        * @param array $excludedPaths Array of package base paths to exclude
+        * @return array List of packages
+        */
+       protected function getPackageKeysInBasePath(array $packageStateConfiguration, $basePath, array $excludedPaths = array()) {
+               $packageKeys = array();
+               foreach ($packageStateConfiguration as $packageKey => $package) {
+                       if (($basePath === '' || strpos($package['packagePath'], $basePath) === 0)) {
+                               $isExcluded = FALSE;
+                               foreach ($excludedPaths as $excludedPath) {
+                                       if (strpos($package['packagePath'], $excludedPath) === 0) {
+                                               $isExcluded = TRUE;
+                                               break;
+                                       }
+                               }
+                               if (!$isExcluded) {
+                                       $packageKeys[] = $packageKey;
+                               }
+                       }
+               }
+               return $packageKeys;
+       }
+
+}
\ No newline at end of file
index 7b2d08b..6dfb31a 100644 (file)
@@ -22,13 +22,17 @@ use TYPO3\Flow\Annotations as Flow;
  */
 class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO3\CMS\Core\SingletonInterface {
 
-
        /**
         * @var \TYPO3\CMS\Core\Core\ClassLoader
         */
        protected $classLoader;
 
        /**
+        * @var \TYPO3\CMS\Core\Package\DependencyResolver
+        */
+       protected $dependencyResolver;
+
+       /**
         * @var \TYPO3\CMS\Core\Core\Bootstrap
         */
        protected $bootstrap;
@@ -64,20 +68,6 @@ class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO
        protected $runtimeActivatedPackages = array();
 
        /**
-        * Adjacency matrix for the dependency graph (DAG)
-        *
-        * Example structure is:
-        *    A => (A => FALSE, B => TRUE,  C => FALSE)
-        *    B => (A => FALSE, B => FALSE, C => FALSE)
-        *    C => (A => TRUE,  B => FALSE, C => FALSE)
-        *
-        *    A depends on B, C depends on A, B is independent
-        *
-        * @var array<array<boolean>>
-        */
-       protected $dependencyGraph;
-
-       /**
         * Constructor
         */
        public function __construct() {
@@ -104,9 +94,16 @@ class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO
        }
 
        /**
+        * @param DependencyResolver
+        */
+       public function injectDependencyResolver(DependencyResolver $dependencyResolver) {
+               $this->dependencyResolver = $dependencyResolver;
+       }
+
+       /**
         * Initializes the package manager
         *
-        * @param \TYPO3\CMS\Core\Core\Bootstrap $bootstrap The current bootstrap; Flow Bootstrap is here by intention to keep the PackageManager valid to the interface
+        * @param \TYPO3\CMS\Core\Core\Bootstrap|\TYPO3\Flow\Core\Bootstrap $bootstrap The current bootstrap; Flow Bootstrap is here by intention to keep the PackageManager valid to the interface
         * @param string $packagesBasePath Absolute path of the Packages directory
         * @param string $packageStatesPathAndFilename
         * @return void
@@ -218,6 +215,7 @@ class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO
         * Loads the states of available packages from the PackageStates.php file.
         * The result is stored in $this->packageStatesConfiguration.
         *
+        * @throws Exception\PackageStatesUnavailableException
         * @return void
         */
        protected function loadPackageStates() {
@@ -317,6 +315,7 @@ class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO
        }
 
        /**
+        * @param array $collectedExtensionPaths
         * @return array
         */
        protected function scanLegacyExtensions(&$collectedExtensionPaths = array()) {
@@ -601,167 +600,6 @@ class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO
        }
 
        /**
-        * Get packages of specific type
-        *
-        * @param string $type Type of package. Empty string for all types
-        * @param array $excludedTypes Array of package types to exclude
-        * @return array List of packages
-        */
-       protected function getActivePackageKeysOfType($type, array $excludedTypes = array()) {
-               $packageKeys = array();
-               foreach ($this->activePackages as $packageKey => $package) {
-                       $packageType = $package->getComposerManifest('type');
-                       if (($type === '' || $packageType === $type) && !in_array($packageType, $excludedTypes)) {
-                               $packageKeys[] = $packageKey;
-                       }
-               }
-               return $packageKeys;
-       }
-
-       /**
-        * Build the dependency graph for the given packages
-        *
-        * @param array $packageKeys
-        * @return void
-        * @throws \UnexpectedValueException
-        */
-       protected function buildDependencyGraphForPackages(array $packageKeys) {
-               // Initialize the dependencies with FALSE
-               $this->dependencyGraph = array_fill_keys($packageKeys, array_fill_keys($packageKeys, FALSE));
-               foreach ($packageKeys as $packageKey) {
-                       $dependentPackageKeys = $this->packageStatesConfiguration['packages'][$packageKey]['dependencies'];
-                       foreach ($dependentPackageKeys as $dependentPackageKey) {
-                               if (!in_array($dependentPackageKey, $packageKeys)) {
-                                       throw new \UnexpectedValueException(
-                                               'The package "' . $packageKey .'" depends on "'
-                                               . $dependentPackageKey . '" which is not present in the system.',
-                                               1382276561);
-                               }
-                               $this->dependencyGraph[$packageKey][$dependentPackageKey] = TRUE;
-                       }
-               }
-       }
-
-       /**
-        * Adds all root packages of current dependency graph as dependency
-        * to all extensions
-        *
-        * @return void
-        */
-       protected function addDependencyToFrameworkToAllExtensions() {
-               $rootPackageKeys = array();
-               foreach (array_keys($this->dependencyGraph) as $packageKey) {
-                       if (!$this->getIncomingEdgeCount($packageKey)) {
-                               $rootPackageKeys[] = $packageKey;
-                       }
-               }
-               $extensionPackageKeys = $this->getActivePackageKeysOfType('', array('typo3-cms-framework'));
-               $frameworkPackageKeys = $this->getActivePackageKeysOfType('typo3-cms-framework');
-               foreach ($extensionPackageKeys as $packageKey) {
-                       // Remove framework packages from list
-                       $packageKeysWithoutFramework = array_diff(
-                               $this->packageStatesConfiguration['packages'][$packageKey]['dependencies'],
-                               $frameworkPackageKeys
-                       );
-                       // The order of the array_merge is crucial here,
-                       // we want the framework first
-                       $this->packageStatesConfiguration['packages'][$packageKey]['dependencies'] = array_merge(
-                               $rootPackageKeys, $packageKeysWithoutFramework
-                       );
-               }
-       }
-
-       /**
-        * Builds the dependency graph for all packages
-        *
-        * This method also introduces dependencies among the dependencies
-        * to ensure the loading order is exactly as specified in the list.
-        *
-        * @return void
-        */
-       protected function buildDependencyGraph() {
-               $this->resolvePackageDependencies();
-
-               $frameworkPackageKeys = $this->getActivePackageKeysOfType('typo3-cms-framework');
-               $this->buildDependencyGraphForPackages($frameworkPackageKeys);
-
-               $this->addDependencyToFrameworkToAllExtensions();
-
-               $packageKeys = array_keys($this->packages);
-               $this->buildDependencyGraphForPackages($packageKeys);
-       }
-
-       /**
-        * Get the number of incoming edges in the dependency graph
-        * for given package key.
-        *
-        * @param string $packageKey
-        * @return integer
-        */
-       protected function getIncomingEdgeCount($packageKey) {
-               $incomingEdgeCount = 0;
-               foreach ($this->dependencyGraph as $dependencies) {
-                       if ($dependencies[$packageKey]) {
-                               $incomingEdgeCount++;
-                       }
-               }
-               return $incomingEdgeCount;
-       }
-
-       /**
-        * Get the loading order for packages
-        *
-        * @return array The properly sorted loading order
-        * @throws \UnexpectedValueException
-        */
-       protected function getAvailablePackageLoadingOrder() {
-               $this->buildDependencyGraph();
-
-               // This will contain our final result
-               $sortedPackageKeys = array();
-
-               $rootPackageKeys = array();
-               // Filter extensions with no incoming edge
-               foreach (array_keys($this->dependencyGraph) as $packageKey) {
-                       if (!$this->getIncomingEdgeCount($packageKey)) {
-                               $rootPackageKeys[] = $packageKey;
-                       }
-               }
-
-               while (count($rootPackageKeys)) {
-                       $currentPackageKey = array_shift($rootPackageKeys);
-                       array_push($sortedPackageKeys, $currentPackageKey);
-
-                       $dependingPackageKeys = array_keys(array_filter($this->dependencyGraph[$currentPackageKey]));
-                       foreach ($dependingPackageKeys as $dependingPackageKey) {
-                               // Remove the edge to this dependency
-                               $this->dependencyGraph[$currentPackageKey][$dependingPackageKey] = FALSE;
-                               if (!$this->getIncomingEdgeCount($dependingPackageKey)) {
-                                       // We found a new root, lets add it
-                                       array_unshift($rootPackageKeys, $dependingPackageKey);
-                               }
-                       }
-               }
-
-               // Check for remaining edges in the graph
-               $cycles = array();
-               array_walk($this->dependencyGraph, function($dependencies, $packageKeyFrom) use(&$cycles) {
-                       array_walk($dependencies, function($dependency, $packageKeyTo) use(&$cycles, $packageKeyFrom) {
-                               if ($dependency) {
-                                       $cycles[] = $packageKeyFrom . '->' . $packageKeyTo;
-                               }
-                       });
-               });
-               if (count($cycles)) {
-                       throw new \UnexpectedValueException('Your dependencies have cycles. That will not work out. Cycles found: ' . implode(', ', $cycles), 1381960493);
-               }
-
-               // We built now a list of dependencies
-               // Reverse the list to get the correct loading order
-               return array_reverse($sortedPackageKeys);
-       }
-
-       /**
         * Orders all packages by comparing their dependencies. By this, the packages
         * and package configurations arrays holds all packages in the correct
         * initialization order.
@@ -769,34 +607,16 @@ class PackageManager extends \TYPO3\Flow\Package\PackageManager implements \TYPO
         * @return void
         */
        protected function sortAvailablePackagesByDependencies() {
-               $newPackages = array();
-               $newPackageStatesConfiguration = array();
+               $this->resolvePackageDependencies();
 
-               $sortedPackageKeys = $this->getAvailablePackageLoadingOrder();
+               $this->packageStatesConfiguration['packages'] = $this->dependencyResolver->sortPackageStatesConfigurationByDependency($this->packageStatesConfiguration['packages']);
 
                // Reorder the packages according to the loading order
-               foreach ($sortedPackageKeys as $packageKey) {
+               $newPackages = array();
+               foreach (array_keys($this->packageStatesConfiguration['packages']) as $packageKey) {
                        $newPackages[$packageKey] = $this->packages[$packageKey];
-                       $newPackageStatesConfiguration[$packageKey] = $this->packageStatesConfiguration['packages'][$packageKey];
                }
-
                $this->packages = $newPackages;
-               $this->packageStatesConfiguration['packages'] = $newPackageStatesConfiguration;
        }
 
-       /**
-        * Resolves the dependent packages from the meta data of all packages recursively. The
-        * resolved direct or indirect dependencies of each package will put into the package
-        * states configuration array.
-        *
-        * @return void
-        */
-       protected function resolvePackageDependencies() {
-               foreach ($this->packages as $packageKey => $package) {
-                       $this->packageStatesConfiguration['packages'][$packageKey]['dependencies'] = array();
-               }
-               foreach ($this->activePackages as $packageKey => $package) {
-                       $this->packageStatesConfiguration['packages'][$packageKey]['dependencies'] = $this->getDependencyArrayForPackage($packageKey);
-               }
-       }
 }
index 106dedd..55a3dcf 100644 (file)
@@ -179,7 +179,7 @@ interface PackageManagerInterface {
        /**
         * Register a native Flow package
         *
-        * @param string $packageKey The Package to be registered
+        * @param PackageInterface $packageKey The Package to be registered
         * @param boolean $sortAndSave allows for not saving packagestates when used in loops etc.
         * @return PackageInterface
         * @throws Exception\CorruptPackageException
diff --git a/typo3/sysext/core/Tests/Unit/Package/DependencyResolverTest.php b/typo3/sysext/core/Tests/Unit/Package/DependencyResolverTest.php
new file mode 100644 (file)
index 0000000..2d86435
--- /dev/null
@@ -0,0 +1,770 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Package;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Markus Klein <klein.t3@mfc-linz.at>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\Package\DependencyResolver;
+
+/**
+ * Testcase for the dependency resolver class
+ *
+ * @author Markus Klein <klein.t3@mfc-linz.at>
+ */
+class DependencyResolverTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * @test
+        * @param array $unsortedPackageStatesConfiguration
+        * @param array $frameworkPackageKeys
+        * @param array $expectedGraph
+        * @dataProvider buildDependencyGraphBuildsCorrectGraphDataProvider
+        */
+       public function buildDependencyGraphBuildsCorrectGraph(array $unsortedPackageStatesConfiguration, array $frameworkPackageKeys, array $expectedGraph) {
+               $packageKeys = array_keys($unsortedPackageStatesConfiguration);
+
+               $basePathAssignment = array(
+                       array($unsortedPackageStatesConfiguration, '', array(PATH_typo3 . DependencyResolver::SYSEXT_FOLDER), array_diff($packageKeys, $frameworkPackageKeys)),
+                       array($unsortedPackageStatesConfiguration, PATH_typo3 . DependencyResolver::SYSEXT_FOLDER, array(), $frameworkPackageKeys),
+               );
+
+               $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('getPackageKeysInBasePath'));
+               $dependencyResolver->expects($this->any())->method('getPackageKeysInBasePath')->will($this->returnValueMap($basePathAssignment));
+               $dependencyGraph = $dependencyResolver->_call('buildDependencyGraph', $unsortedPackageStatesConfiguration);
+
+               $this->assertEquals($expectedGraph, $dependencyGraph);
+       }
+
+       /**
+        * @test
+        * @dataProvider packageSortingDataProvider
+        */
+       public function sortPackageStatesConfigurationByDependencyMakesSureThatDependantPackagesAreStandingBeforeAPackageInTheInternalPackagesAndPackagesConfigurationArrays($unsortedPackageStatesConfiguration, $frameworkPackageKeys, $expectedSortedPackageStatesConfiguration) {
+               $packageKeys = array_keys($unsortedPackageStatesConfiguration);
+
+               $basePathAssignment = array(
+                       array($unsortedPackageStatesConfiguration, '', array(PATH_typo3 . DependencyResolver::SYSEXT_FOLDER), array_diff($packageKeys, $frameworkPackageKeys)),
+                       array($unsortedPackageStatesConfiguration, PATH_typo3 . DependencyResolver::SYSEXT_FOLDER, array(), $frameworkPackageKeys),
+               );
+
+               $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('getPackageKeysInBasePath'));
+               $dependencyResolver->expects($this->any())->method('getPackageKeysInBasePath')->will($this->returnValueMap($basePathAssignment));
+               $sortedPackageStatesConfiguration = $dependencyResolver->_call('sortPackageStatesConfigurationByDependency', $unsortedPackageStatesConfiguration);
+
+               $this->assertEquals($expectedSortedPackageStatesConfiguration, $sortedPackageStatesConfiguration, 'The package states configurations have not been ordered according to their dependencies!');
+       }
+
+       /**
+        * @test
+        * @dataProvider buildDependencyGraphForPackagesBuildsCorrectGraphDataProvider
+        */
+       public function buildDependencyGraphForPackagesBuildsCorrectGraph($packages, $expectedGraph) {
+               $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('dummy'));
+               $dependencyGraph = $dependencyResolver->_call('buildDependencyGraphForPackages', $packages, array_keys($packages));
+
+               $this->assertEquals($expectedGraph, $dependencyGraph);
+       }
+
+       /**
+        * @test
+        * @expectedException \UnexpectedValueException
+        */
+       public function sortPackageStatesConfigurationByDependencyThrowsExceptionWhenCycleDetected() {
+               $unsortedPackageStatesConfiguration = array(
+                       'A' => array(
+                               'state' => 'active',
+                               'dependencies' => array('B'),
+                       ),
+                       'B' => array(
+                               'state' => 'active',
+                               'dependencies' => array('A')
+                       ),
+               );
+
+               $packageKeys = array_keys($unsortedPackageStatesConfiguration);
+
+               $basePathAssignment = array(
+                       array($unsortedPackageStatesConfiguration, '', array(PATH_typo3 . DependencyResolver::SYSEXT_FOLDER), $packageKeys),
+                       array($unsortedPackageStatesConfiguration, PATH_typo3 . DependencyResolver::SYSEXT_FOLDER, array(), array()),
+               );
+
+               $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('getActivePackageKeysOfType'));
+               $dependencyResolver->expects($this->any())->method('getActivePackageKeysOfType')->will($this->returnValueMap($basePathAssignment));
+               $dependencyResolver->_call('sortPackageStatesConfigurationByDependency', $unsortedPackageStatesConfiguration);
+       }
+
+       /**
+        * @test
+        * @expectedException \UnexpectedValueException
+        */
+       public function buildDependencyGraphForPackagesThrowsExceptionWhenDependencyOnUnavailablePackageDetected() {
+               $packages = array(
+                       'A' => array(
+                               'dependencies' => array('B'),
+                       )
+               );
+               $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('dummy'));
+               $dependencyResolver->_call('buildDependencyGraphForPackages', $packages, array_keys($packages));
+       }
+
+       /**
+        * @return array
+        */
+       public function buildDependencyGraphBuildsCorrectGraphDataProvider() {
+               return array(
+                       'TYPO3 Flow Packages' => array(
+                               array(
+                                       'TYPO3.Flow' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
+                                       ),
+                                       'Doctrine.ORM' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
+                                       ),
+                                       'Doctrine.Common' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'Doctrine.DBAL' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common')
+                                       ),
+                                       'Symfony.Component.Yaml' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                               ),
+                               array(
+                                       'Doctrine.Common'
+                               ),
+                               array(
+                                       'TYPO3.Flow' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => TRUE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => TRUE,
+                                               'Symfony.Component.Yaml' => TRUE,
+                                       ),
+                                       'Doctrine.ORM' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => TRUE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                                       'Doctrine.Common' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => FALSE,
+                                               'Doctrine.DBAL' => FALSE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                                       'Doctrine.DBAL' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => FALSE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                                       'Symfony.Component.Yaml' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => FALSE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                               ),
+                       ),
+                       'TYPO3 CMS Extensions' => array(
+                               array(
+                                       'core' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'setup' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'openid' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('core', 'setup')
+                                       ),
+                                       'news' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('extbase'),
+                                       ),
+                                       'extbase' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'pt_extbase' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('extbase'),
+                                       ),
+                                       'foo' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                               ),
+                               array(
+                                       'core', 'setup', 'openid', 'extbase'
+                               ),
+                               array(
+                                       'core' => array(
+                                               'core' => FALSE,
+                                               'setup' => FALSE,
+                                               'openid' => FALSE,
+                                               'news' => FALSE,
+                                               'extbase' => FALSE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                                       'setup' => array(
+                                               'core' => TRUE,
+                                               'setup' => FALSE,
+                                               'openid' => FALSE,
+                                               'news' => FALSE,
+                                               'extbase' => FALSE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                                       'openid' => array (
+                                               'core' => TRUE,
+                                               'setup' => TRUE,
+                                               'openid' => FALSE,
+                                               'news' => FALSE,
+                                               'extbase' => FALSE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                                       'news' => array (
+                                               'core' => FALSE,
+                                               'setup' => FALSE,
+                                               'openid' => TRUE,
+                                               'news' => FALSE,
+                                               'extbase' => TRUE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                                       'extbase' => array (
+                                               'core' => TRUE,
+                                               'setup' => FALSE,
+                                               'openid' => FALSE,
+                                               'news' => FALSE,
+                                               'extbase' => FALSE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                                       'pt_extbase' => array(
+                                               'core' => FALSE,
+                                               'setup' => FALSE,
+                                               'openid' => TRUE,
+                                               'news' => FALSE,
+                                               'extbase' => TRUE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                                       'foo' => array(
+                                               'core' => FALSE,
+                                               'setup' => FALSE,
+                                               'openid' => TRUE,
+                                               'news' => FALSE,
+                                               'extbase' => TRUE,
+                                               'pt_extbase' => FALSE,
+                                               'foo' => FALSE
+                                       ),
+                               ),
+                       ),
+                       'Dummy Packages' => array(
+                               array(
+                                       'A' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('B', 'D', 'C'),
+                                       ),
+                                       'B' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'C' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('E')
+                                       ),
+                                       'D' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('E'),
+                                       ),
+                                       'E' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'F' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                               ),
+                               array(
+                                       'B', 'C', 'E'
+                               ),
+                               array(
+                                       'A' => array(
+                                               'A' => FALSE,
+                                               'B' => TRUE,
+                                               'C' => TRUE,
+                                               'D' => TRUE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'B' => array(
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'C' => array(
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => TRUE,
+                                               'F' => FALSE,
+                                       ),
+                                       'D' => array (
+                                               'A' => FALSE,
+                                               'B' => TRUE,
+                                               'C' => TRUE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'E' => array (
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'F' => array (
+                                               'A' => FALSE,
+                                               'B' => TRUE,
+                                               'C' => TRUE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                               ),
+                       ),
+               );
+       }
+
+       /**
+        * @return array
+        */
+       public function packageSortingDataProvider() {
+               return array(
+                       'TYPO3 Flow Packages' => array(
+                               array(
+                                       'TYPO3.Flow' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
+                                       ),
+                                       'Doctrine.ORM' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
+                                       ),
+                                       'Doctrine.Common' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'Doctrine.DBAL' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common')
+                                       ),
+                                       'Symfony.Component.Yaml' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                               ),
+                               array(
+                                       'Doctrine.Common'
+                               ),
+                               array(
+                                       'Doctrine.Common' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'Doctrine.DBAL' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common')
+                                       ),
+                                       'Doctrine.ORM' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
+                                       ),
+                                       'Symfony.Component.Yaml' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'TYPO3.Flow' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
+                                       ),
+                               ),
+                       ),
+                       'TYPO3 CMS Extensions' => array(
+                               array(
+                                       'core' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'setup' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'openid' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('core', 'setup')
+                                       ),
+                                       'news' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('extbase'),
+                                       ),
+                                       'extbase' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'pt_extbase' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('extbase'),
+                                       ),
+                                       'foo' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                               ),
+                               array(
+                                       'core', 'setup', 'openid', 'extbase'
+                               ),
+                               array(
+                                       'core' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'setup' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'openid' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('core', 'setup')
+                                       ),
+                                       'extbase' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'foo' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'pt_extbase' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('extbase'),
+                                       ),
+                                       'news' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('extbase'),
+                                       ),
+                               ),
+                       ),
+                       'Dummy Packages' => array(
+                               array(
+                                       'A' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('B', 'D', 'C'),
+                                       ),
+                                       'B' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'C' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('E')
+                                       ),
+                                       'D' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('E'),
+                                       ),
+                                       'E' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'F' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                               ),
+                               array(
+                                       'B', 'C', 'E'
+                               ),
+                               array(
+                                       'B' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'E' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'C' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('E'),
+                                       ),
+                                       'F' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'D' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('E'),
+                                       ),
+                                       'A' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('B', 'D', 'C'),
+                                       ),
+                               ),
+                       ),
+               );
+       }
+
+       /**
+        * @return array
+        */
+       public function buildDependencyGraphForPackagesBuildsCorrectGraphDataProvider() {
+               return array(
+                       'TYPO3 Flow Packages' => array(
+                               array(
+                                       'TYPO3.Flow' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
+                                       ),
+                                       'Doctrine.ORM' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
+                                       ),
+                                       'Doctrine.Common' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'Doctrine.DBAL' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('Doctrine.Common')
+                                       ),
+                                       'Symfony.Component.Yaml' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                               ),
+                               array(
+                                       'TYPO3.Flow' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => TRUE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => TRUE,
+                                               'Symfony.Component.Yaml' => TRUE,
+                                       ),
+                                       'Doctrine.ORM' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => TRUE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                                       'Doctrine.Common' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => FALSE,
+                                               'Doctrine.DBAL' => FALSE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                                       'Doctrine.DBAL' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => TRUE,
+                                               'Doctrine.DBAL' => FALSE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                                       'Symfony.Component.Yaml' => array(
+                                               'TYPO3.Flow' => FALSE,
+                                               'Doctrine.ORM' => FALSE,
+                                               'Doctrine.Common' => FALSE,
+                                               'Doctrine.DBAL' => FALSE,
+                                               'Symfony.Component.Yaml' => FALSE,
+                                       ),
+                               ),
+                       ),
+                       'TYPO3 CMS Extensions' => array(
+                               array(
+                                       'core' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'openid' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('core', 'setup')
+                                       ),
+                                       'scheduler' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'setup' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                                       'sv' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('core'),
+                                       ),
+                               ),
+                               array(
+                                       'core' => array(
+                                               'core' => FALSE,
+                                               'setup' => FALSE,
+                                               'sv' => FALSE,
+                                               'scheduler' => FALSE,
+                                               'openid' => FALSE,
+                                       ),
+                                       'openid' => array(
+                                               'core' => TRUE,
+                                               'setup' => TRUE,
+                                               'sv' => FALSE,
+                                               'scheduler' => FALSE,
+                                               'openid' => FALSE,
+                                       ),
+                                       'scheduler' => array (
+                                               'core' => TRUE,
+                                               'setup' => FALSE,
+                                               'sv' => FALSE,
+                                               'scheduler' => FALSE,
+                                               'openid' => FALSE,
+                                       ),
+                                       'setup' => array (
+                                               'core' => TRUE,
+                                               'setup' => FALSE,
+                                               'sv' => FALSE,
+                                               'scheduler' => FALSE,
+                                               'openid' => FALSE,
+                                       ),
+                                       'sv' => array (
+                                               'core' => TRUE,
+                                               'setup' => FALSE,
+                                               'sv' => FALSE,
+                                               'scheduler' => FALSE,
+                                               'openid' => FALSE,
+                                       ),
+                               ),
+                       ),
+                       'Dummy Packages' => array(
+                               array(
+                                       'A' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('B', 'D', 'C'),
+                                       ),
+                                       'B' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array()
+                                       ),
+                                       'C' => array(
+                                               'state' => 'active',
+                                               'dependencies' => array('E')
+                                       ),
+                                       'D' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array('E'),
+                                       ),
+                                       'E' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                                       'F' => array (
+                                               'state' => 'active',
+                                               'dependencies' => array(),
+                                       ),
+                               ),
+                               array(
+                                       'A' => array(
+                                               'A' => FALSE,
+                                               'B' => TRUE,
+                                               'C' => TRUE,
+                                               'D' => TRUE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'B' => array(
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'C' => array(
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => TRUE,
+                                               'F' => FALSE,
+                                       ),
+                                       'D' => array (
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => TRUE,
+                                               'F' => FALSE,
+                                       ),
+                                       'E' => array (
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                                       'F' => array (
+                                               'A' => FALSE,
+                                               'B' => FALSE,
+                                               'C' => FALSE,
+                                               'D' => FALSE,
+                                               'E' => FALSE,
+                                               'F' => FALSE,
+                                       ),
+                               ),
+                       ),
+               );
+       }
+
+}
index 5559035..4a8a8c8 100644 (file)
@@ -75,6 +75,60 @@ class PackageManagerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->packageManager->getPackage('PrettyUnlikelyThatThisPackageExists');
        }
 
+
+       /**
+        * @test
+        */
+       public function getDependencyArrayForPackageReturnsCorrectResult() {
+               $mockFlowMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
+               $mockFlowMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
+                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'TYPO3.Fluid'),
+                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'Doctrine.ORM')
+               )));
+               $mockFlowPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
+               $mockFlowPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockFlowMetadata));
+
+               $mockFluidMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
+               $mockFluidMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
+                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'TYPO3.Flow')
+               )));
+               $mockFluidPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
+               $mockFluidPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockFluidMetadata));
+
+               $mockOrmMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
+               $mockOrmMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
+                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'Doctrine.DBAL')
+               )));
+               $mockOrmPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
+               $mockOrmPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockOrmMetadata));
+
+               $mockDbalMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
+               $mockDbalMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
+                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'Doctrine.Common')
+               )));
+               $mockDbalPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
+               $mockDbalPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockDbalMetadata));
+
+               $mockCommonMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
+               $mockCommonMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array()));
+               $mockCommonPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
+               $mockCommonPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockCommonMetadata));
+
+               $packages = array(
+                       'TYPO3.Flow' => $mockFlowPackage,
+                       'TYPO3.Fluid' => $mockFluidPackage,
+                       'Doctrine.ORM' => $mockOrmPackage,
+                       'Doctrine.DBAL' => $mockDbalPackage,
+                       'Doctrine.Common' => $mockCommonPackage
+               );
+
+               $packageManager = $this->getAccessibleMock('\TYPO3\Flow\Package\PackageManager', array('dummy'));
+               $packageManager->_set('packages', $packages);
+               $dependencyArray = $packageManager->_call('getDependencyArrayForPackage', 'TYPO3.Flow');
+
+               $this->assertEquals(array('Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM', 'TYPO3.Fluid'), $dependencyArray);
+       }
+
        /**
         * @test
         */
@@ -376,757 +430,6 @@ class PackageManagerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        }
 
        /**
-        * @test
-        */
-       public function getDependencyArrayForPackageReturnsCorrectResult() {
-               $mockFlowMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
-               $mockFlowMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
-                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'TYPO3.Fluid'),
-                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'Doctrine.ORM')
-               )));
-               $mockFlowPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
-               $mockFlowPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockFlowMetadata));
-
-               $mockFluidMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
-               $mockFluidMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
-                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'TYPO3.Flow')
-               )));
-               $mockFluidPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
-               $mockFluidPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockFluidMetadata));
-
-               $mockOrmMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
-               $mockOrmMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
-                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'Doctrine.DBAL')
-               )));
-               $mockOrmPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
-               $mockOrmPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockOrmMetadata));
-
-               $mockDbalMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
-               $mockDbalMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array(
-                       new \TYPO3\Flow\Package\MetaData\PackageConstraint('depends', 'Doctrine.Common')
-               )));
-               $mockDbalPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
-               $mockDbalPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockDbalMetadata));
-
-               $mockCommonMetadata = $this->getMock('TYPO3\Flow\Package\MetaDataInterface');
-               $mockCommonMetadata->expects($this->any())->method('getConstraintsByType')->will($this->returnValue(array()));
-               $mockCommonPackage = $this->getMock('TYPO3\Flow\Package\PackageInterface');
-               $mockCommonPackage->expects($this->any())->method('getPackageMetaData')->will($this->returnValue($mockCommonMetadata));
-
-               $packages = array(
-                       'TYPO3.Flow' => $mockFlowPackage,
-                       'TYPO3.Fluid' => $mockFluidPackage,
-                       'Doctrine.ORM' => $mockOrmPackage,
-                       'Doctrine.DBAL' => $mockDbalPackage,
-                       'Doctrine.Common' => $mockCommonPackage
-               );
-
-               $packageManager = $this->getAccessibleMock('\TYPO3\Flow\Package\PackageManager', array('dummy'));
-               $packageManager->_set('packages', $packages);
-               $dependencyArray = $packageManager->_call('getDependencyArrayForPackage', 'TYPO3.Flow');
-
-               $this->assertEquals(array('Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM', 'TYPO3.Fluid'), $dependencyArray);
-       }
-
-       /**
-        * @return array
-        */
-       public function buildDependencyGraphBuildsCorrectGraphDataProvider() {
-               return array(
-                       'TYPO3 Flow Packages' => array(
-                               array(
-                                       'TYPO3.Flow' => array(
-                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
-                                       ),
-                                       'Doctrine.ORM' => array(
-                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
-                                       ),
-                                       'Doctrine.Common' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'Doctrine.DBAL' => array(
-                                               'dependencies' => array('Doctrine.Common')
-                                       ),
-                                       'Symfony.Component.Yaml' => array(
-                                               'dependencies' => array()
-                                       ),
-                               ),
-                               array(
-                                       'Doctrine.Common'
-                               ),
-                               array(
-                                       'TYPO3.Flow' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => TRUE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => TRUE,
-                                               'Symfony.Component.Yaml' => TRUE,
-                                       ),
-                                       'Doctrine.ORM' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => TRUE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                                       'Doctrine.Common' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => FALSE,
-                                               'Doctrine.DBAL' => FALSE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                                       'Doctrine.DBAL' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => FALSE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                                       'Symfony.Component.Yaml' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => FALSE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                               ),
-                       ),
-                       'TYPO3 CMS Extensions' => array(
-                               array(
-                                       'core' => array(
-                                               'dependencies' => array(),
-                                       ),
-                                       'setup' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'openid' => array(
-                                               'dependencies' => array('core', 'setup')
-                                       ),
-                                       'news' => array (
-                                               'dependencies' => array('extbase'),
-                                       ),
-                                       'extbase' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'pt_extbase' => array (
-                                               'dependencies' => array('extbase'),
-                                       ),
-                                       'foo' => array (
-                                               'dependencies' => array(),
-                                       ),
-                               ),
-                               array(
-                                       'core', 'setup', 'openid', 'extbase'
-                               ),
-                               array(
-                                       'core' => array(
-                                               'core' => FALSE,
-                                               'setup' => FALSE,
-                                               'openid' => FALSE,
-                                               'news' => FALSE,
-                                               'extbase' => FALSE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                                       'setup' => array(
-                                               'core' => TRUE,
-                                               'setup' => FALSE,
-                                               'openid' => FALSE,
-                                               'news' => FALSE,
-                                               'extbase' => FALSE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                                       'openid' => array (
-                                               'core' => TRUE,
-                                               'setup' => TRUE,
-                                               'openid' => FALSE,
-                                               'news' => FALSE,
-                                               'extbase' => FALSE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                                       'news' => array (
-                                               'core' => FALSE,
-                                               'setup' => FALSE,
-                                               'openid' => TRUE,
-                                               'news' => FALSE,
-                                               'extbase' => TRUE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                                       'extbase' => array (
-                                               'core' => TRUE,
-                                               'setup' => FALSE,
-                                               'openid' => FALSE,
-                                               'news' => FALSE,
-                                               'extbase' => FALSE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                                       'pt_extbase' => array(
-                                               'core' => FALSE,
-                                               'setup' => FALSE,
-                                               'openid' => TRUE,
-                                               'news' => FALSE,
-                                               'extbase' => TRUE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                                       'foo' => array(
-                                               'core' => FALSE,
-                                               'setup' => FALSE,
-                                               'openid' => TRUE,
-                                               'news' => FALSE,
-                                               'extbase' => TRUE,
-                                               'pt_extbase' => FALSE,
-                                               'foo' => FALSE
-                                       ),
-                               ),
-                       ),
-                       'Dummy Packages' => array(
-                               array(
-                                       'A' => array(
-                                               'dependencies' => array('B', 'D', 'C'),
-                                       ),
-                                       'B' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'C' => array(
-                                               'dependencies' => array('E')
-                                       ),
-                                       'D' => array (
-                                               'dependencies' => array('E'),
-                                       ),
-                                       'E' => array (
-                                               'dependencies' => array(),
-                                       ),
-                                       'F' => array (
-                                               'dependencies' => array(),
-                                       ),
-                               ),
-                               array(
-                                       'B', 'C', 'E'
-                               ),
-                               array(
-                                       'A' => array(
-                                               'A' => FALSE,
-                                               'B' => TRUE,
-                                               'C' => TRUE,
-                                               'D' => TRUE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'B' => array(
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'C' => array(
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => TRUE,
-                                               'F' => FALSE,
-                                       ),
-                                       'D' => array (
-                                               'A' => FALSE,
-                                               'B' => TRUE,
-                                               'C' => TRUE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'E' => array (
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'F' => array (
-                                               'A' => FALSE,
-                                               'B' => TRUE,
-                                               'C' => TRUE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                               ),
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @param array $unsorted
-        * @param array $frameworkPackageKeys
-        * @param array $expectedGraph
-        * @dataProvider buildDependencyGraphBuildsCorrectGraphDataProvider
-        */
-       public function buildDependencyGraphBuildsCorrectGraph(array $unsorted, array $frameworkPackageKeys, array $expectedGraph) {
-               $unsortedPackageStatesConfiguration = array('packages' => $unsorted);
-
-               $packageKeys = array_keys($unsorted);
-               $unsortedPackages = array();
-               foreach ($packageKeys as $packageKey) {
-                       $packageMock = $this->getMock('\TYPO3\Flow\Package\PackageInterface');
-                       $packageMock->expects($this->any())->method('getPackageKey')->will($this->returnValue($packageKey));
-                       $unsortedPackages[$packageKey] = $packageMock;
-               }
-
-               $typeAssignment = array(
-                       array('', array('typo3-cms-framework'), array_diff($packageKeys, $frameworkPackageKeys)),
-                       array('typo3-cms-framework', array(), $frameworkPackageKeys),
-               );
-
-               $packageManager = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\PackageManager', array('resolvePackageDependencies','getActivePackageKeysOfType'));
-               $packageManager->expects($this->any())->method('getActivePackageKeysOfType')->will($this->returnValueMap($typeAssignment));
-               $packageManager->_set('packages', $unsortedPackages);
-               $packageManager->_set('packageStatesConfiguration', $unsortedPackageStatesConfiguration);
-               $packageManager->_call('buildDependencyGraph');
-
-               $this->assertEquals($expectedGraph, $packageManager->_get('dependencyGraph'));
-       }
-
-       /**
-        * @return array
-        */
-       public function packageSortingDataProvider() {
-               return array(
-                       'TYPO3 Flow Packages' => array(
-                               array(
-                                       'TYPO3.Flow' => array(
-                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
-                                       ),
-                                       'Doctrine.ORM' => array(
-                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
-                                       ),
-                                       'Doctrine.Common' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'Doctrine.DBAL' => array(
-                                               'dependencies' => array('Doctrine.Common')
-                                       ),
-                                       'Symfony.Component.Yaml' => array(
-                                               'dependencies' => array()
-                                       ),
-                               ),
-                               array(
-                                       'Doctrine.Common'
-                               ),
-                               array(
-                                       'Doctrine.Common' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'Doctrine.DBAL' => array(
-                                               'dependencies' => array('Doctrine.Common')
-                                       ),
-                                       'Doctrine.ORM' => array(
-                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
-                                       ),
-                                       'Symfony.Component.Yaml' => array(
-                                               'dependencies' => array('Doctrine.Common')
-                                       ),
-                                       'TYPO3.Flow' => array(
-                                               'dependencies' => array('Doctrine.Common', 'Symfony.Component.Yaml', 'Doctrine.DBAL', 'Doctrine.ORM')
-                                       ),
-                               ),
-                       ),
-                       'TYPO3 CMS Extensions' => array(
-                               array(
-                                       'core' => array(
-                                               'dependencies' => array(),
-                                       ),
-                                       'setup' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'openid' => array(
-                                               'dependencies' => array('core', 'setup')
-                                       ),
-                                       'news' => array (
-                                               'dependencies' => array('extbase'),
-                                       ),
-                                       'extbase' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'pt_extbase' => array (
-                                               'dependencies' => array('extbase'),
-                                       ),
-                                       'foo' => array (
-                                               'dependencies' => array(),
-                                       ),
-                               ),
-                               array(
-                                       'core', 'setup', 'openid', 'extbase'
-                               ),
-                               array(
-                                       'core' => array(
-                                               'dependencies' => array(),
-                                       ),
-                                       'setup' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'openid' => array(
-                                               'dependencies' => array('core', 'setup')
-                                       ),
-                                       'extbase' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'foo' => array (
-                                               'dependencies' => array('openid', 'extbase'),
-                                       ),
-                                       'pt_extbase' => array (
-                                               'dependencies' => array('openid', 'extbase'),
-                                       ),
-                                       'news' => array (
-                                               'dependencies' => array('openid', 'extbase'),
-                                       ),
-                               ),
-                       ),
-                       'Dummy Packages' => array(
-                               array(
-                                       'A' => array(
-                                               'dependencies' => array('B', 'D', 'C'),
-                                       ),
-                                       'B' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'C' => array(
-                                               'dependencies' => array('E')
-                                       ),
-                                       'D' => array (
-                                               'dependencies' => array('E'),
-                                       ),
-                                       'E' => array (
-                                               'dependencies' => array(),
-                                       ),
-                                       'F' => array (
-                                               'dependencies' => array(),
-                                       ),
-                               ),
-                               array(
-                                       'B', 'C', 'E'
-                               ),
-                               array(
-                                       'B' => array(
-                                               'dependencies' => array(),
-                                       ),
-                                       'E' => array (
-                                               'dependencies' => array(),
-                                       ),
-                                       'C' => array (
-                                               'dependencies' => array('E'),
-                                       ),
-                                       'F' => array (
-                                               'dependencies' => array('B', 'C'),
-                                       ),
-                                       'D' => array(
-                                               'dependencies' => array('B', 'C'),
-                                       ),
-                                       'A' => array(
-                                               'dependencies' => array('B', 'C', 'D'),
-                                       ),
-                               ),
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider packageSortingDataProvider
-        */
-       public function sortAvailablePackagesByDependenciesMakesSureThatDependantPackagesAreStandingBeforeAPackageInTheInternalPackagesAndPackagesConfigurationArrays($unsorted, $frameworkPackageKeys, $expected) {
-               $unsortedPackageStatesConfiguration = array('packages' => $unsorted);
-               $expectedSortedPackageStatesConfiguration = array('packages' => $expected);
-
-               $unsortedPackages = array();
-               $packageKeys = array_keys($unsorted);
-               foreach ($packageKeys as $packageKey) {
-                       $packageMock = $this->getMock('\TYPO3\Flow\Package\PackageInterface');
-                       $packageMock->expects($this->any())->method('getPackageKey')->will($this->returnValue($packageKey));
-                       $unsortedPackages[$packageKey] = $packageMock;
-               }
-
-               $typeAssignment = array(
-                       array('', array('typo3-cms-framework'), array_diff($packageKeys, $frameworkPackageKeys)),
-                       array('typo3-cms-framework', array(), $frameworkPackageKeys),
-               );
-
-               $packageManager = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\PackageManager', array('resolvePackageDependencies','getActivePackageKeysOfType'));
-               $packageManager->expects($this->any())->method('getActivePackageKeysOfType')->will($this->returnValueMap($typeAssignment));
-               $packageManager->_set('packages', $unsortedPackages);
-               $packageManager->_set('packageStatesConfiguration', $unsortedPackageStatesConfiguration);
-               $packageManager->_call('sortAvailablePackagesByDependencies');
-
-               $expectedSortedPackageKeys = array_keys($expected);
-
-               $this->assertEquals($expectedSortedPackageKeys, array_keys($packageManager->_get('packages')), 'The packages have not been ordered according to their dependencies!');
-               $this->assertEquals($expectedSortedPackageStatesConfiguration, $packageManager->_get('packageStatesConfiguration'), 'The package states configurations have not been ordered according to their dependencies!');
-       }
-
-       /**
-        * @return array
-        */
-       public function buildDependencyGraphForPackagesBuildsCorrectGraphDataProvider() {
-               return array(
-                       'TYPO3 Flow Packages' => array(
-                               array(
-                                       'TYPO3.Flow' => array(
-                                               'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
-                                       ),
-                                       'Doctrine.ORM' => array(
-                                               'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
-                                       ),
-                                       'Doctrine.Common' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'Doctrine.DBAL' => array(
-                                               'dependencies' => array('Doctrine.Common')
-                                       ),
-                                       'Symfony.Component.Yaml' => array(
-                                               'dependencies' => array()
-                                       ),
-                               ),
-                               array(
-                                       'TYPO3.Flow' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => TRUE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => TRUE,
-                                               'Symfony.Component.Yaml' => TRUE,
-                                       ),
-                                       'Doctrine.ORM' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => TRUE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                                       'Doctrine.Common' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => FALSE,
-                                               'Doctrine.DBAL' => FALSE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                                       'Doctrine.DBAL' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => TRUE,
-                                               'Doctrine.DBAL' => FALSE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                                       'Symfony.Component.Yaml' => array(
-                                               'TYPO3.Flow' => FALSE,
-                                               'Doctrine.ORM' => FALSE,
-                                               'Doctrine.Common' => FALSE,
-                                               'Doctrine.DBAL' => FALSE,
-                                               'Symfony.Component.Yaml' => FALSE,
-                                       ),
-                               ),
-                       ),
-                       'TYPO3 CMS Extensions' => array(
-                               array(
-                                       'core' => array(
-                                               'dependencies' => array(),
-                                       ),
-                                       'openid' => array(
-                                               'dependencies' => array('core', 'setup')
-                                       ),
-                                       'scheduler' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'setup' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                                       'sv' => array (
-                                               'dependencies' => array('core'),
-                                       ),
-                               ),
-                               array(
-                                       'core' => array(
-                                               'core' => FALSE,
-                                               'setup' => FALSE,
-                                               'sv' => FALSE,
-                                               'scheduler' => FALSE,
-                                               'openid' => FALSE,
-                                       ),
-                                       'openid' => array(
-                                               'core' => TRUE,
-                                               'setup' => TRUE,
-                                               'sv' => FALSE,
-                                               'scheduler' => FALSE,
-                                               'openid' => FALSE,
-                                       ),
-                                       'scheduler' => array (
-                                               'core' => TRUE,
-                                               'setup' => FALSE,
-                                               'sv' => FALSE,
-                                               'scheduler' => FALSE,
-                                               'openid' => FALSE,
-                                       ),
-                                       'setup' => array (
-                                               'core' => TRUE,
-                                               'setup' => FALSE,
-                                               'sv' => FALSE,
-                                               'scheduler' => FALSE,
-                                               'openid' => FALSE,
-                                       ),
-                                       'sv' => array (
-                                               'core' => TRUE,
-                                               'setup' => FALSE,
-                                               'sv' => FALSE,
-                                               'scheduler' => FALSE,
-                                               'openid' => FALSE,
-                                       ),
-                               ),
-                       ),
-                       'Dummy Packages' => array(
-                               array(
-                                       'A' => array(
-                                               'dependencies' => array('B', 'D', 'C'),
-                                       ),
-                                       'B' => array(
-                                               'dependencies' => array()
-                                       ),
-                                       'C' => array(
-                                               'dependencies' => array('E')
-                                       ),
-                                       'D' => array (
-                                               'dependencies' => array('E'),
-                                       ),
-                                       'E' => array (
-                                               'dependencies' => array(),
-                                       ),
-                                       'F' => array (
-                                               'dependencies' => array(),
-                                       ),
-                               ),
-                               array(
-                                       'A' => array(
-                                               'A' => FALSE,
-                                               'B' => TRUE,
-                                               'C' => TRUE,
-                                               'D' => TRUE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'B' => array(
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'C' => array(
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => TRUE,
-                                               'F' => FALSE,
-                                       ),
-                                       'D' => array (
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => TRUE,
-                                               'F' => FALSE,
-                                       ),
-                                       'E' => array (
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                                       'F' => array (
-                                               'A' => FALSE,
-                                               'B' => FALSE,
-                                               'C' => FALSE,
-                                               'D' => FALSE,
-                                               'E' => FALSE,
-                                               'F' => FALSE,
-                                       ),
-                               ),
-                       ),
-               );
-       }
-
-       /**
-        * @test
-        * @dataProvider buildDependencyGraphForPackagesBuildsCorrectGraphDataProvider
-        */
-       public function buildDependencyGraphForPackagesBuildsCorrectGraph($packages, $expectedGraph) {
-               $packageManager = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\PackageManager', array('dummy'));
-               $packageManager->_set('packageStatesConfiguration', array('packages' => $packages));
-               $packageManager->_call('buildDependencyGraphForPackages', array_keys($packages));
-
-               $this->assertEquals($expectedGraph, $packageManager->_get('dependencyGraph'));
-       }
-
-
-       /**
-        * @test
-        * @expectedException \UnexpectedValueException
-        */
-       public function getAvailablePackageLoadingOrderThrowsExceptionWhenCycleDetected() {
-               $unsorted = array(
-                       'A' => array(
-                               'dependencies' => array('B'),
-                       ),
-                       'B' => array(
-                               'dependencies' => array('A')
-                       ),
-               );
-               $unsortedPackageStatesConfiguration = array('packages' => $unsorted);
-
-               $unsortedPackages = array();
-               $packageKeys = array_keys($unsorted);
-               foreach ($packageKeys as $packageKey) {
-                       $packageMock = $this->getMock('\TYPO3\Flow\Package\PackageInterface');
-                       $packageMock->expects($this->any())->method('getPackageKey')->will($this->returnValue($packageKey));
-                       $unsortedPackages[$packageKey] = $packageMock;
-               }
-
-               $typeAssignment = array(
-                       array('', array('typo3-cms-framework'), $packageKeys),
-                       array('typo3-cms-framework', array(), array()),
-               );
-
-               $packageManager = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\PackageManager', array('resolvePackageDependencies','getActivePackageKeysOfType'));
-               $packageManager->expects($this->any())->method('getActivePackageKeysOfType')->will($this->returnValueMap($typeAssignment));
-               $packageManager->_set('packages', $unsortedPackages);
-               $packageManager->_set('packageStatesConfiguration', $unsortedPackageStatesConfiguration);
-               $packageManager->_call('getAvailablePackageLoadingOrder');
-       }
-
-       /**
-        * @test
-        * @expectedException \UnexpectedValueException
-        */
-       public function buildDependencyGraphForPackagesThrowsExceptionWhenDependencyOnUnavailablePackageDetected() {
-               $packages = array(
-                       'A' => array(
-                               'dependencies' => array('B'),
-                       )
-               );
-               $packageManager = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\PackageManager', array('dummy'));
-               $packageManager->_set('packageStatesConfiguration', array('packages' => $packages));
-               $packageManager->_call('buildDependencyGraphForPackages', array_keys($packages));
-       }
-
-       /**
         * @return array
         */
        public function composerNamesAndPackageKeys() {