cabal-macosx-0.1.0: Distribution/MacOSX/DG.hs
-- | Dependency graph handling.
module Distribution.MacOSX.DG (
DG(..),
FDeps(..),
dgEmpty,
dgFDeps,
dgAddPaths,
dgAddFDeps
) where
import Data.Graph.Inductive.Graph as G
import Data.Graph.Inductive.Tree (Gr)
import Data.List
import Data.Maybe
-- | A dependency graph is an ordinary fgl graph with 'FilePath's on
-- its nodes, and directed edges. An edge from A to B indicates that
-- A depends on B.
data DG = DG (Gr FilePath ())
deriving Show
-- | An FDeps represents some file and its list of library
-- dependencies.
data FDeps = FDeps FilePath [FilePath]
deriving (Eq, Ord, Show)
-- | Add a file dependency to a dependency graph.
dgAddFDeps :: DG -> FDeps -> DG
dgAddFDeps dg (FDeps src tgts) = dgAddDeps src tgts $ dg `dgAddPaths` (src:tgts)
-- | Turn a dependency graph back into a list of FDeps.
dgFDeps :: DG -> [FDeps]
dgFDeps (DG g) = map mkFDep (G.labNodes g)
where mkFDep :: G.LNode FilePath -> FDeps
mkFDep (i, src) = FDeps src $ mapMaybe (G.lab g) (G.suc g i)
-- | Create an empty dependency graph.
dgEmpty :: DG
dgEmpty = DG G.empty
-- | Get the node number of a dependency graph node with a specified label.
dgPathIdx :: DG -> FilePath -> Maybe Int
dgPathIdx (DG g) p = case find (\x -> p == snd x) (G.labNodes g) of
Just (i, _) -> Just i
Nothing -> Nothing
-- | Check if a certain path is already in a dependency graph.
dgHasPath :: DG -> FilePath -> Bool
dgHasPath dg p = case dgPathIdx dg p of
Just _ -> True
Nothing -> False
-- | Add a list of paths as nodes to a dependency graph, dropping
-- duplicates.
dgAddPaths :: DG -> [FilePath] -> DG
dgAddPaths = foldl dgAddPath
-- | Add a single path as a node to a dependency graph, unless already
-- present.
dgAddPath :: DG -> FilePath -> DG
dgAddPath dg@(DG g) p = if dg `dgHasPath` p then dg
else DG $ G.insNode (head $ G.newNodes 1 g, p) g
-- | Given a source path and a list of target paths, add a list of
-- dependencies (ie edges) to a dependency graph.
dgAddDeps :: FilePath -> [FilePath] -> DG -> DG
dgAddDeps src tgts dg = foldl dgAddDep dg $ zip (repeat src) tgts
-- | Add a (src, tgt) dependency (ie edge) to a dependency graph.
dgAddDep :: DG -> (FilePath, FilePath) -> DG
dgAddDep dg@(DG g) (src, tgt) = DG $ G.insEdge (getI src, getI tgt, ()) g
where getI x = case dgPathIdx dg x of
Just x' -> x'
Nothing -> error "Can't happen" -- if called in context.