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 <$> traverse (saturateDeps ps) dep getLatest = traverse (traverse (latest ps))