mirror of
https://github.com/commercialhaskell/stackage.git
synced 2026-01-12 15:28:29 +01:00
156 lines
5.3 KiB
Haskell
156 lines
5.3 KiB
Haskell
{-# LANGUAGE NoImplicitPrelude #-}
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
|
{-# LANGUAGE RecordWildCards #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE DeriveFunctor #-}
|
|
{-# LANGUAGE DeriveFoldable #-}
|
|
{-# LANGUAGE DeriveTraversable #-}
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
-- | Manipulate @GenericPackageDescription@ from Cabal into something more
|
|
-- useful for us.
|
|
module Stackage2.PackageDescription
|
|
( FlatComponent (..)
|
|
, getFlattenedComponent
|
|
, SimpleExtra (..)
|
|
, CheckCond (..)
|
|
) where
|
|
|
|
import Distribution.Package (Dependency (..))
|
|
import Distribution.PackageDescription
|
|
import Distribution.Version (withinRange, intersectVersionRanges)
|
|
import Stackage2.CorePackages
|
|
import Stackage2.PackageConstraints
|
|
import Stackage2.PackageIndex
|
|
import Stackage2.Prelude
|
|
import Stackage2.GithubPings
|
|
import Control.Monad.State.Strict (execState, get, put)
|
|
import qualified Data.Map as Map
|
|
import qualified Data.Set as Set
|
|
import Data.Aeson
|
|
import Distribution.System (OS, Arch)
|
|
import Distribution.Compiler (CompilerFlavor)
|
|
|
|
data SimpleTree = SimpleTree
|
|
{ stDeps :: Map PackageName VersionRange
|
|
, stConds :: [(Condition ConfVar, SimpleTree, Maybe SimpleTree)]
|
|
, stExtra :: SimpleExtra
|
|
}
|
|
deriving Show
|
|
instance Monoid SimpleTree where
|
|
mempty = SimpleTree mempty mempty mempty
|
|
mappend (SimpleTree a b c) (SimpleTree x y z) = SimpleTree
|
|
(unionWith intersectVersionRanges a x)
|
|
(b ++ y)
|
|
(c ++ z)
|
|
|
|
data SimpleExtra = SimpleExtra
|
|
{ seTools :: Map ExeName VersionRange
|
|
, seProvidedExes :: Set ExeName
|
|
}
|
|
deriving Show
|
|
instance Monoid SimpleExtra where
|
|
mempty = SimpleExtra mempty mempty
|
|
mappend (SimpleExtra a b) (SimpleExtra x y) = SimpleExtra
|
|
(unionWith intersectVersionRanges a x)
|
|
(b ++ y)
|
|
|
|
getFlattenedComponent
|
|
:: MonadThrow m
|
|
=> CheckCond
|
|
-> Bool -- ^ include test suites?
|
|
-> Bool -- ^ include benchmarks?
|
|
-> GenericPackageDescription
|
|
-> m FlatComponent
|
|
getFlattenedComponent checkCond' includeTests includeBench gpd =
|
|
liftM fold
|
|
$ mapM (flattenComponent checkCond')
|
|
$ getSimpleTrees includeTests includeBench gpd
|
|
|
|
getSimpleTrees :: Bool -- ^ include test suites?
|
|
-> Bool -- ^ include benchmarks?
|
|
-> GenericPackageDescription
|
|
-> [SimpleTree]
|
|
getSimpleTrees includeTests includeBench gpd = concat
|
|
[ maybe [] (return . go libBuildInfo mempty) $ condLibrary gpd
|
|
, map (\(x, y) -> go buildInfo (singletonSet $ ExeName $ pack x) y)
|
|
$ condExecutables gpd
|
|
, if includeTests
|
|
then map (go testBuildInfo mempty . snd) $ condTestSuites gpd
|
|
else []
|
|
, if includeBench
|
|
then map (go benchmarkBuildInfo mempty . snd) $ condBenchmarks gpd
|
|
else []
|
|
]
|
|
where
|
|
go getBI exes (CondNode dat deps comps) = SimpleTree
|
|
{ stDeps = unionsWith intersectVersionRanges
|
|
$ map (\(Dependency x y) -> singletonMap x y) deps
|
|
, stConds = map (goComp getBI exes) comps
|
|
, stExtra = toSimpleExtra (getBI dat) exes
|
|
}
|
|
|
|
goComp getBI exes (cond, tree1, mtree2) =
|
|
(cond, go getBI exes tree1, go getBI exes <$> mtree2)
|
|
|
|
toSimpleExtra bi exes = SimpleExtra
|
|
{ seTools = unionsWith intersectVersionRanges $ flip map (buildTools bi)
|
|
$ \(Dependency name range) -> singletonMap
|
|
(ExeName $ unPackageName name)
|
|
range
|
|
, seProvidedExes = exes
|
|
}
|
|
|
|
data FlatComponent = FlatComponent
|
|
{ fcDeps :: Map PackageName VersionRange
|
|
, fcExtra :: SimpleExtra
|
|
}
|
|
deriving Show
|
|
instance Monoid FlatComponent where
|
|
mempty = FlatComponent mempty mempty
|
|
mappend (FlatComponent a b) (FlatComponent x y) = FlatComponent
|
|
(unionWith intersectVersionRanges a x)
|
|
(b ++ y)
|
|
|
|
flattenComponent :: MonadThrow m => CheckCond -> SimpleTree -> m FlatComponent
|
|
flattenComponent checkCond' (SimpleTree deps conds extra) = do
|
|
conds' <- mapM goCond conds
|
|
return $ mconcat $ here : conds'
|
|
where
|
|
here = FlatComponent { fcDeps = deps, fcExtra = extra }
|
|
goCond (cond, tree1, mtree2) = do
|
|
b <- checkCond checkCond' cond
|
|
if b
|
|
then flattenComponent checkCond' tree1
|
|
else maybe (return mempty) (flattenComponent checkCond') mtree2
|
|
|
|
checkCond :: MonadThrow m => CheckCond -> Condition ConfVar -> m Bool
|
|
checkCond CheckCond {..} cond0 =
|
|
go cond0
|
|
where
|
|
go (Var (OS os)) = return $ os == ccOS
|
|
go (Var (Arch arch)) = return $ arch == ccArch
|
|
go (Var (Flag flag)) =
|
|
case lookup flag ccFlags of
|
|
Nothing -> throwM $ FlagNotDefined ccPackageName flag cond0
|
|
Just b -> return b
|
|
go (Var (Impl flavor range)) = return
|
|
$ flavor == ccCompilerFlavor
|
|
&& ccCompilerVersion `withinRange` range
|
|
go (Lit b) = return b
|
|
go (CNot c) = not `liftM` go c
|
|
go (CAnd x y) = (&&) `liftM` go x `ap` go y
|
|
go (COr x y) = (||) `liftM` go x `ap` go y
|
|
|
|
data CheckCondException = FlagNotDefined PackageName FlagName (Condition ConfVar)
|
|
deriving (Show, Typeable)
|
|
instance Exception CheckCondException
|
|
|
|
data CheckCond = CheckCond
|
|
{ ccPackageName :: PackageName -- for debugging only
|
|
, ccOS :: OS
|
|
, ccArch :: Arch
|
|
, ccFlags :: Map FlagName Bool
|
|
, ccCompilerFlavor :: CompilerFlavor
|
|
, ccCompilerVersion :: Version
|
|
}
|