diff --git a/Distribution/Simple/PackageIndex.hs b/Distribution/Simple/PackageIndex.hs index c45285fc807a40a74ee3d8b71f12fdd75fed6567..eebb2cf2b3465b96b43229ec96dd78119b24cb41 100644 --- a/Distribution/Simple/PackageIndex.hs +++ b/Distribution/Simple/PackageIndex.hs @@ -44,6 +44,7 @@ module Distribution.Simple.PackageIndex ( dependencyClosure, dependencyInconsistencies, dependencyCycles, + dependencyGraph, ) where import Prelude hiding (lookup) @@ -51,6 +52,8 @@ import Control.Exception (assert) import qualified Data.Map as Map import Data.Map (Map) import qualified Data.Graph as Graph +import qualified Data.Array as Array +import Data.Array ((!)) import Data.List (nubBy, group, sort, groupBy, sortBy, find) import Data.Monoid (Monoid(..)) import Data.Maybe (isNothing) @@ -329,3 +332,34 @@ dependencyCycles index = where adjacencyList = [ (pkg, packageId pkg, depends pkg) | pkg <- allPackages index ] + +-- | Builds a graph of the package dependencies. +-- +-- Dependencies on other packages that are in the index are discarded. +-- You can check if there are any such dependencies with 'brokenPackages'. +-- +dependencyGraph :: PackageFixedDeps pkg + => PackageIndex pkg + -> (Graph.Graph, + Graph.Vertex -> PackageIdentifier, + PackageIdentifier -> Maybe Graph.Vertex) +dependencyGraph index = (graph, vertexToPkgId, pkgIdToVertex) + where + graph = Array.listArray bounds + [ [ v | Just v <- map pkgIdToVertex (depends pkg) ] + | pkg <- pkgs ] + vertexToPkgId vertex = pkgIdTable ! vertex + pkgIdToVertex = binarySearch 0 topBound + + pkgIdTable = Array.listArray bounds (map packageId pkgs) + pkgs = sortBy (comparing packageId) (allPackages index) + topBound = length pkgs - 1 + bounds = (0, topBound) + + binarySearch a b key + | a > b = Nothing + | otherwise = case compare key (pkgIdTable ! mid) of + LT -> binarySearch a (mid-1) key + EQ -> Just mid + GT -> binarySearch (mid+1) b key + where mid = (a + b) `div` 2