packages feed

dependency 0.1.0.7 → 0.1.0.8

raw patch · 7 files changed

+108/−43 lines, 7 filesdep +tardisdep +transformersPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: tardis, transformers

API changes (from Hackage documentation)

- Data.Dependency: [_libConstraint] :: Dependency -> Constraint Version
+ Data.Dependency: Conflict :: [String] -> String -> ResolveError
+ Data.Dependency: ResolveStateM :: TardisT Mod ResMap m a -> ResolveStateM m a
+ Data.Dependency: [unResolve] :: ResolveStateM m a -> TardisT Mod ResMap m a
+ Data.Dependency: compatible :: (Ord a) => Constraint a -> Constraint a -> Bool
+ Data.Dependency: newtype ResolveStateM m a
+ Data.Dependency: type ResMap = Map String Dependency
+ Data.Dependency: type ResolveState = ResolveStateM (Either ResolveError)
- Data.Dependency: Dependency :: String -> Constraint Version -> [String] -> Version -> Dependency
+ Data.Dependency: Dependency :: String -> [(String, Constraint Version)] -> Version -> Dependency
- Data.Dependency: [_libDependencies] :: Dependency -> [String]
+ Data.Dependency: [_libDependencies] :: Dependency -> [(String, Constraint Version)]

Files

bench/Bench.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TupleSections #-}+ module Main where  import           Control.Arrow@@ -7,22 +9,22 @@ import qualified Data.Set        as S  free :: Dependency-free = Dependency "free" mempty mempty defV+free = Dependency "free" mempty defV  comonad :: Dependency-comonad = Dependency "comonad" mempty mempty defV+comonad = Dependency "comonad" mempty defV  lens :: Dependency-lens = Dependency "lens" mempty ["free", "comonad"] defV+lens = Dependency "lens" ((,mempty) <$> ["free", "comonad"]) defV  defV :: Version defV = Version [0,1,0]  microlens :: Dependency-microlens = Dependency "microlens" mempty mempty defV+microlens = Dependency "microlens" mempty defV  bifunctors :: Dependency-bifunctors = Dependency "bifunctors" mempty ["comonad"] defV+bifunctors = Dependency "bifunctors" ((,mempty) <$> ["comonad"]) defV  deps :: [Dependency] deps = [free, lens, comonad]
dependency.cabal view
@@ -1,5 +1,5 @@ name:                dependency-version:             0.1.0.7+version:             0.1.0.8 synopsis:            Dependency resolution for package management description:         A library for resolving dependencies; uses a topological sort to construct a build plan and then allows choice between all compatible plans. license:             BSD3@@ -29,9 +29,11 @@                      , containers                      , recursion-schemes                      , microlens+                     , transformers                      , deepseq                      , binary                      , deepseq+                     , tardis   default-language:    Haskell2010   if flag(development)     ghc-options:       -Werror
src/Data/Dependency.hs view
@@ -3,6 +3,7 @@       resolveDependencies     , buildSequence     , satisfies+    , compatible     -- * Types     , Dependency (..)     , PackageSet (..)@@ -10,35 +11,52 @@     , DepM     , ResolveError (..)     , Constraint (..)+    , ResolveStateM (..)+    , ResolveState+    , ResMap     ) where  import           Control.Monad+import           Control.Monad.Tardis+import           Control.Monad.Trans.Class import           Data.Dependency.Error import           Data.Dependency.Sort import           Data.Dependency.Type-import           Data.Foldable         (toList)-import           Data.List             (groupBy)-import qualified Data.Map              as M-import qualified Data.Set              as S+import           Data.Foldable             (toList)+import           Data.List                 (groupBy)+import qualified Data.Map                  as M+import qualified Data.Set                  as S  lookupMap :: String -> M.Map String a -> DepM a lookupMap k ps = case M.lookup k ps of     Just x  -> Right x     Nothing -> Left (NotPresent k) -lookupSet :: S.Set a -> DepM a-lookupSet s = case S.lookupMax s of-    Just x  -> Right x-    Nothing -> Left InternalError+checkWith :: Dependency -> [Dependency] -> S.Set Dependency -> DepM Dependency+checkWith x ds s+    | check x ds = Right x+    | otherwise = lookupSet ds (S.deleteMax s) -latest :: (Ord a) => PackageSet a -> Dependency -> DepM (String, a)-latest (PackageSet ps) (Dependency ln _ _ _) = do-    s <- lookupMap ln ps-    (,) ln <$> lookupSet s+lookupSet :: [Dependency] -- ^ Dependencies already added+          -> S.Set Dependency -- ^ Set of dependencies+          -> DepM Dependency+lookupSet ds s = case S.lookupMax s of+    Just x  -> checkWith x ds s+    Nothing -> g s +    where g s'+            | S.size s' > 0 = Left (Conflict (_libName <$> ds) (_libName . head . toList $ s'))+            | otherwise = Left InternalError++latest :: PackageSet Dependency -> Dependency -> ResolveState (String, Dependency)+latest (PackageSet ps) (Dependency ln _ _) = do+    st <- getPast+    s <- lift $ lookupMap ln ps+    (,) ln <$> lift (lookupSet (toList st) s)+ buildSequence :: [Dependency] -> [[Dependency]] buildSequence = reverse . groupBy independent . sortDeps-    where independent (Dependency ln _ ls _) (Dependency ln' _ ls' _) = ln' `notElem` ls && ln `notElem` ls'+    where independent (Dependency ln ls _) (Dependency ln' ls' _) = ln' `notElem` (fst <$> ls) && ln `notElem` (fst <$> ls')  iterateM :: (Monad m) => Int -> (a -> m a) -> a -> m [a] iterateM 0 _ _ = pure []@@ -52,10 +70,13 @@  saturateDeps' :: PackageSet Dependency -> Dependency -> DepM (S.Set Dependency) saturateDeps' (PackageSet ps) dep = do-    deps <- sequence [ lookupMap lib ps | lib <- _libDependencies dep ]-    list <- (:) dep <$> traverse lookupSet deps+    deps <- sequence [ lookupMap lib ps | lib <- fst <$> _libDependencies dep ]+    list <- (:) dep <$> traverse (lookupSet mempty) deps     pure $ S.fromList list +run :: ResolveState a -> DepM a+run = flip evalTardisT (id, mempty) . unResolve+ -- | Heuristics: -- -- 1. Always use a newer version when possible@@ -73,4 +94,4 @@ resolveDependencies ps = select . getLatest <=< fmap (buildSequence . toList) . saturated     where select = fmap (fmap (fmap snd))           saturated dep = S.unions <$> traverse (saturateDeps ps) dep-          getLatest = traverse (traverse (latest ps))+          getLatest = run . traverse (traverse (latest ps))
src/Data/Dependency/Error.hs view
@@ -15,6 +15,7 @@ -- | An error that can occur during package resolution. data ResolveError = InternalError                   | NotPresent String+                  | Conflict [String] String                   deriving (Show, Eq, NFData, Generic)                   -- CircularDependencies String String                   -- Conflict String String (Constraint Version) (Constraint Version)@@ -22,3 +23,4 @@ instance Pretty ResolveError where     pretty InternalError = red "Error:" <+> "the" <+> squotes "dependency" <+> "package enountered an internal error. Please report this as a bug:\n" <> hang 2 "https://hub.darcs.net/vmchale/ats/issues"     pretty (NotPresent s) = red "Error:" <+> "the package" <+> squotes (text s) <+> "could not be found.\n"+    pretty (Conflict ss s) = red "Error:" <+> "the package" <+> squotes (text s) <+> "conflicts with already in-scope packages: " <+> pretty ss
src/Data/Dependency/Sort.hs view
@@ -8,7 +8,7 @@  asGraph :: [Dependency] -> (Graph, Vertex -> Dependency) asGraph ds = (f triple, keys)-    where triple = graphFromEdges (zip3 ds (_libName <$> ds) (_libDependencies <$> ds))+    where triple = graphFromEdges (zip3 ds (_libName <$> ds) (fmap fst . _libDependencies <$> ds))           f = view _1           s = view _2           keys = view _1 . s triple
src/Data/Dependency/Type.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE DeriveGeneric              #-} {-# LANGUAGE DeriveTraversable          #-} {-# LANGUAGE DerivingStrategies         #-}+{-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures             #-} {-# LANGUAGE OverloadedStrings          #-}@@ -16,12 +17,21 @@                             , Version (..)                             , Constraint (..)                             , PackageSet (..)+                            , ResMap+                            , ResolveStateM (..)+                            , ResolveState                             -- * Helper functions                             , satisfies+                            , compatible+                            , check                             ) where  import           Control.DeepSeq              (NFData)+import           Control.Monad.Fix+import           Control.Monad.Tardis+import           Control.Monad.Trans.Class import           Data.Binary+import           Data.Dependency.Error import           Data.Functor.Foldable import           Data.Functor.Foldable.TH import           Data.List                    (intercalate)@@ -33,6 +43,17 @@ import           GHC.Generics                 (Generic) import           Text.PrettyPrint.ANSI.Leijen hiding ((<$>), (<>)) +type Mod = ResMap -> ResMap+type ResMap = M.Map String Dependency+type ResolveState = ResolveStateM (Either ResolveError)++newtype ResolveStateM m a = ResolveStateM { unResolve :: TardisT Mod ResMap m a }+    deriving (Functor)+    deriving newtype (Applicative, Monad, MonadFix, MonadTardis Mod ResMap)++instance MonadTrans ResolveStateM where+    lift = ResolveStateM . lift+ newtype PackageSet a = PackageSet (M.Map String (S.Set a))     deriving (Eq, Ord, Foldable, Generic)     deriving newtype Binary@@ -75,15 +96,15 @@     mempty = None     mappend = (<>) -makeBaseFunctor ''Constraint+data Dependency = Dependency { _libName         :: String+                             , _libDependencies :: [(String, Constraint Version)]+                             , _libVersion      :: Version+                             }+                             deriving (Show, Eq, Ord, Generic, NFData) -instance Pretty a => Pretty (Constraint a) where-    pretty = cata a where-        a (LessThanEqF v)    = "≤" <+> pretty v-        a (GreaterThanEqF v) = "≥" <+> pretty v-        a (EqF v)            = "≡" <+> pretty v-        a (BoundedF c c')    = c <+> "∧" <+> c'-        a NoneF              = mempty+check :: Dependency -> [Dependency] -> Bool+check (Dependency ln _ v) ds = and [ g v ds' | (Dependency _ ds' _) <- ds ]+    where g v' = all (`satisfies` v') . fmap snd . filter ((== ln) . fst)  satisfies :: (Ord a) => Constraint a -> a -> Bool satisfies (LessThanEq x) y    = x <= y@@ -92,10 +113,22 @@ satisfies (Bounded x y) z     = satisfies x z && satisfies y z satisfies None _              = True --- FIXME make version first-data Dependency = Dependency { _libName         :: String-                             , _libConstraint   :: Constraint Version-                             , _libDependencies :: [String]-                             , _libVersion      :: Version-                             }-                             deriving (Show, Eq, Ord, Generic, NFData)+compatible :: (Ord a) => Constraint a -> Constraint a -> Bool+compatible LessThanEq{} LessThanEq{}        = True+compatible (LessThanEq x) (GreaterThanEq y) = y <= x+compatible (Eq x) (Eq y)                    = x == y+compatible (Bounded x y) z                  = compatible x z && compatible y z+compatible GreaterThanEq{} GreaterThanEq{}  = True+compatible (LessThanEq x) (Eq y)            = y <= x+compatible None _                           = True+compatible x y                              = compatible y x++makeBaseFunctor ''Constraint++instance Pretty a => Pretty (Constraint a) where+    pretty = cata a where+        a (LessThanEqF v)    = "≤" <+> pretty v+        a (GreaterThanEqF v) = "≥" <+> pretty v+        a (EqF v)            = "≡" <+> pretty v+        a (BoundedF c c')    = c <+> "∧" <+> c'+        a NoneF              = mempty
test/Spec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TupleSections #-}+ import           Control.Arrow import           Data.Dependency import qualified Data.Map        as M@@ -5,13 +7,16 @@ import           Test.Hspec  free :: Dependency-free = Dependency "free" mempty mempty defV+free = Dependency "free" mempty defV  comonad :: Dependency-comonad = Dependency "comonad" mempty mempty defV+comonad = Dependency "comonad" mempty defV +newLens :: Dependency+newLens = Dependency "lens" ((,mempty) <$> ["free", "comonad"]) (Version [0,2,0])+ lens :: Dependency-lens = Dependency "lens" mempty ["free", "comonad"] defV+lens = Dependency "lens" ((,mempty) <$> ["free", "comonad"]) defV  defV :: Version defV = Version [0,1,0]@@ -23,7 +28,7 @@ mapSingles = fmap (second S.singleton)  set :: PackageSet Dependency-set = PackageSet $ M.fromList (mapSingles [("lens", lens), ("comonad", comonad), ("free", free)])+set = PackageSet $ M.fromList (("lens", S.fromList [lens, newLens]) : mapSingles [("comonad", comonad), ("free", free)])  main :: IO () main = hspec $ parallel $ do@@ -32,4 +37,4 @@             buildSequence deps `shouldBe` [[free, comonad], [lens]]     describe "resolveDependencies" $         it "correctly resolves dependencies in a package set" $-            resolveDependencies set [lens] `shouldBe` Right [[free, comonad], [lens]]+            resolveDependencies set [lens] `shouldBe` Right [[free, comonad], [newLens]]