Improve infrastructure for Cabal file parsing
[ghc.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.Parse 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.Haskell.Package
24
25 -- | Haskell package metadata extracted from a @.cabal@ file.
26 data Cabal = Cabal
27 { name :: PackageName
28 , version :: String
29 , dependencies :: [PackageName]
30 } deriving (Eq, Read, Show, Typeable)
31
32 instance Binary Cabal where
33 put = put . show
34 get = fmap read get
35
36 instance Hashable Cabal where
37 hashWithSalt salt = hashWithSalt salt . show
38
39 instance NFData Cabal where
40 rnf (Cabal a b c) = a `seq` b `seq` c `seq` ()
41
42 -- | Parse a @.cabal@ file.
43 parseCabal :: FilePath -> IO Cabal
44 parseCabal file = do
45 gpd <- liftIO $ C.readGenericPackageDescription C.silent file
46 let pkgId = C.package (C.packageDescription gpd)
47 libDeps = collectDeps (C.condLibrary gpd)
48 exeDeps = map (collectDeps . Just . snd) (C.condExecutables gpd)
49 allDeps = concat (libDeps : exeDeps)
50 sorted = sort [ C.unPackageName p | C.Dependency p _ <- allDeps ]
51 return $ Cabal
52 (C.unPackageName $ C.pkgName pkgId)
53 (C.display $ C.pkgVersion pkgId)
54 (nubOrd sorted)
55
56 collectDeps :: Maybe (C.CondTree v [C.Dependency] a) -> [C.Dependency]
57 collectDeps Nothing = []
58 collectDeps (Just (C.CondNode _ deps ifs)) = deps ++ concatMap f ifs
59 where
60 f (C.CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt