dependency-0.1.0.2: src/Data/Dependency.hs
module Data.Dependency
( -- * Functions
resolveDependencies
, isPresent
, buildSequence
, asGraph
-- * Types
, Dependency (..)
, PackageSet (..)
, Version (..)
) where
import Control.Monad
import Data.Dependency.Sort
import Data.Dependency.Type
import Data.List (groupBy)
import qualified Data.Map as M
import qualified Data.Set as S
isPresent :: PackageSet Version -> Dependency -> Bool
isPresent (PackageSet ps) (Dependency ln _ _) = g (M.lookup ln ps)
where g (Just x) = not (S.null x)
g Nothing = False
latest :: (Ord a) => PackageSet a -> Dependency -> Maybe (String, a)
latest (PackageSet ps) (Dependency ln _ _) = do
s <- M.lookup ln ps
(,) ln <$> S.lookupMax s
buildSequence :: [Dependency] -> [[Dependency]]
buildSequence = reverse . groupBy independent . sortDeps
where independent (Dependency ln _ ls) (Dependency ln' _ ls') = ln' `notElem` ls && ln `notElem` ls'
saturateDeps :: PackageSet Dependency -> Dependency -> Maybe [Dependency]
saturateDeps (PackageSet ps) dep = do
let libDeps = _libDependencies dep
deps <- sequence [ M.lookup lib ps | lib <- libDeps ]
(:) dep <$> traverse S.lookupMax deps
-- | Heuristics:
--
-- 1. Always use a newer version when possible
--
-- 2. Obey constraints
--
-- 3. Specify an error for circular dependencies
--
-- 4. Specify an error for overconstrained builds
--
-- 5. Specify an error if a package is not present.
--
-- This doesn't do any package resolution beyond versioning.
resolveDependencies :: PackageSet Dependency -> [[Dependency]] -> Maybe [[Dependency]]
resolveDependencies ps = select . getLatest <=< fmap buildSequence . saturated
where select = fmap (fmap (fmap snd))
saturated dep = join . join <$> traverse (traverse (saturateDeps ps)) dep
getLatest = sequence . fmap (traverse (latest ps))