module CabalCargs.BuildInfo
( buildInfosOfLib
, buildInfosOfExe
, buildInfosOfTest
, buildInfosOfBenchmark
, buildInfosOf
, buildInfos
, field
) where
import Distribution.PackageDescription
import Distribution.Compiler
import Distribution.Package (Dependency)
import Language.Haskell.Extension
import Control.Lens
import Data.List (find)
import qualified CabalCargs.Sections as S
import qualified CabalCargs.Field as F
import qualified CabalCargs.CondVars as CV
makeLensesFor [ ("hsSourceDirs" , "hsSourceDirsL")
, ("options" , "optionsL")
, ("defaultLanguage" , "defaultLanguageL")
, ("cppOptions" , "cppOptionsL")
, ("cSources" , "cSourcesL")
, ("ccOptions" , "ccOptionsL")
, ("extraLibDirs" , "extraLibDirsL")
, ("extraLibs" , "extraLibsL")
, ("ldOptions" , "ldOptionsL")
, ("includeDirs" , "includeDirsL")
, ("includes" , "includesL")
] ''BuildInfo
buildInfosOf :: S.Section -> CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOf S.Library = buildInfosOfLib
buildInfosOf (S.Executable name) = buildInfosOfExe name
buildInfosOf (S.TestSuite name) = buildInfosOfTest name
buildInfosOf (S.Benchmark name) = buildInfosOfBenchmark name
buildInfos :: CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfos vars pkgDescrp =
concat [ buildInfosOfLib vars pkgDescrp
, buildInfosOfAllExes vars pkgDescrp
, buildInfosOfAllTests vars pkgDescrp
, buildInfosOfAllBenchmarks vars pkgDescrp
]
buildInfosOfLib :: CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfLib vars pkgDescrp
| Just condLib <- condLibrary pkgDescrp
= map libBuildInfo $ condTreeDatas vars condLib
| otherwise
= []
buildInfosOfExe :: String -> CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfExe name vars pkgDescrp
| Just (_, condExe) <- find ((== name) . fst) $ condExecutables pkgDescrp
= map buildInfo $ condTreeDatas vars condExe
| otherwise
= []
buildInfosOfAllExes :: CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfAllExes vars pkgDescrp =
concat $ map ((map buildInfo) . (condTreeDatas vars) . snd) (condExecutables pkgDescrp)
buildInfosOfTest :: String -> CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfTest name vars pkgDescrp
| Just (_, condTest) <- find ((== name) . fst) $ condTestSuites pkgDescrp
= map testBuildInfo $ condTreeDatas vars condTest
| otherwise
= []
buildInfosOfAllTests :: CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfAllTests vars pkgDescrp =
concat $ map ((map testBuildInfo) . (condTreeDatas vars) . snd) (condTestSuites pkgDescrp)
buildInfosOfBenchmark :: String -> CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfBenchmark name vars pkgDescrp
| Just (_, condBench) <- find ((== name) . fst) $ condBenchmarks pkgDescrp
= map benchmarkBuildInfo $ condTreeDatas vars condBench
| otherwise
= []
buildInfosOfAllBenchmarks :: CV.CondVars -> GenericPackageDescription -> [BuildInfo]
buildInfosOfAllBenchmarks vars pkgDescrp =
concat $ map ((map benchmarkBuildInfo) . (condTreeDatas vars) . snd) (condBenchmarks pkgDescrp)
condTreeDatas :: CV.CondVars -> CondTree ConfVar [Dependency] a -> [a]
condTreeDatas vars tree = go (condTreeComponents tree) [condTreeData tree]
where
go [] dats = dats
go ((cond, ifTree, elseTree) : comps) dats
| CV.eval vars cond
= go comps $ go (condTreeComponents ifTree) (condTreeData ifTree : dats)
| Just tree <- elseTree
= go comps $ go (condTreeComponents tree) (condTreeData tree : dats)
| otherwise
= go comps dats
field :: F.Field -> Traversal' BuildInfo [String]
field F.Hs_Source_Dirs = hsSourceDirsL
field F.Ghc_Options = optionsL . traversed . filtered ((== GHC) . fst) . _2
field F.Default_Extensions = oldAndDefaultExtensionsL . extsToStrings
field F.Default_Language = defaultLanguageL . langToString
field F.Cpp_Options = cppOptionsL
field F.C_Sources = cSourcesL
field F.Cc_Options = ccOptionsL
field F.Extra_Lib_Dirs = extraLibDirsL
field F.Extra_Libraries = extraLibsL
field F.Ld_Options = ldOptionsL
field F.Include_Dirs = includeDirsL
field F.Includes = includesL
field F.Package_Db = nopLens
field F.Autogen_Hs_Source_Dirs = nopLens
field F.Autogen_Include_Dirs = nopLens
field F.Autogen_Includes = nopLens
oldAndDefaultExtensionsL :: Lens' BuildInfo [Extension]
oldAndDefaultExtensionsL = lens getter setter
where
getter buildInfo = (oldExtensions buildInfo) ++ (defaultExtensions buildInfo)
setter buildInfo exts = buildInfo { defaultExtensions = exts }
extsToStrings :: Iso' [Extension] [String]
extsToStrings = iso (map toString) (map toExt)
where
toString ext =
case ext of
EnableExtension knownExt -> show knownExt
DisableExtension knownExt -> "No" ++ show knownExt
UnknownExtension unknownExt -> unknownExt
toExt ('N':'o':rest)
| [(ext, _)] <- reads rest :: [(KnownExtension, String)]
= DisableExtension ext
toExt str
| [(ext, _)] <- reads str :: [(KnownExtension, String)]
= EnableExtension ext
| otherwise
= UnknownExtension str
langToString :: Iso' (Maybe Language) [String]
langToString = iso toString toLang
where
toString Nothing = []
toString (Just lang) =
case lang of
UnknownLanguage l -> [l]
_ -> [show lang]
toLang (str:[])
| [(lang, _)] <- reads str :: [(Language, String)]
= Just lang
| otherwise
= Just $ UnknownLanguage str
toLang _ = Nothing
nopLens :: Lens' BuildInfo [String]
nopLens = lens (const []) (\buildInfo _ -> buildInfo)