Fix Hadrian after Cabal changes (#498)
[hadrian.git] / src / Hadrian / Haskell / Cabal / Parse.hs
1 -----------------------------------------------------------------------------
2 -- |
3 -- Module : Hadrian.Haskell.Cabal.Parse
4 -- Copyright : (c) Andrey Mokhov 2014-2017
5 -- License : MIT (see the file LICENSE)
6 -- Maintainer : andrey.mokhov@gmail.com
7 -- Stability : experimental
8 --
9 -- Extracting Haskell package metadata stored in Cabal files.
10 -----------------------------------------------------------------------------
11 module Hadrian.Haskell.Cabal.Parse (Cabal (..), parseCabal) where
12
13 import Data.List.Extra
14 import Development.Shake
15 import Development.Shake.Classes
16 import qualified Distribution.Package as C
17 import qualified Distribution.PackageDescription as C
18 import qualified Distribution.PackageDescription.Parsec as C
19 import qualified Distribution.Text as C
20 import qualified Distribution.Types.CondTree as C
21 import qualified Distribution.Verbosity as C
22
23 import Hadrian.Package
24
25 -- TODO: Use fine-grain tracking instead of tracking the whole Cabal file.
26 -- | Haskell package metadata extracted from a Cabal file.
27 data Cabal = Cabal
28 { dependencies :: [PackageName]
29 , name :: PackageName
30 , synopsis :: String
31 , version :: String
32 } deriving (Eq, Read, Show, Typeable)
33
34 instance Binary Cabal where
35 put = put . show
36 get = fmap read get
37
38 instance Hashable Cabal where
39 hashWithSalt salt = hashWithSalt salt . show
40
41 instance NFData Cabal where
42 rnf (Cabal a b c d) = a `seq` b `seq` c `seq` d `seq` ()
43
44 -- | Parse a Cabal file.
45 parseCabal :: FilePath -> IO Cabal
46 parseCabal file = do
47 gpd <- liftIO $ C.readGenericPackageDescription C.silent file
48 let pd = C.packageDescription gpd
49 pkgId = C.package pd
50 name = C.unPackageName (C.pkgName pkgId)
51 version = C.display (C.pkgVersion pkgId)
52 libDeps = collectDeps (C.condLibrary gpd)
53 exeDeps = map (collectDeps . Just . snd) (C.condExecutables gpd)
54 allDeps = concat (libDeps : exeDeps)
55 sorted = sort [ C.unPackageName p | C.Dependency p _ <- allDeps ]
56 deps = nubOrd sorted \\ [name]
57 return $ Cabal deps name (C.synopsis pd) version
58
59 collectDeps :: Maybe (C.CondTree v [C.Dependency] a) -> [C.Dependency]
60 collectDeps Nothing = []
61 collectDeps (Just (C.CondNode _ deps ifs)) = deps ++ concatMap f ifs
62 where
63 f (C.CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt