module Shaker.Cabal.CabalInfo(
defaultCabalInput
)
where
import Shaker.Type
import Shaker.Config
import Distribution.Simple.Configure (getPersistBuildConfig)
import Distribution.Simple.LocalBuildInfo (LocalBuildInfo, localPkgDescr)
import Distribution.ModuleName
import Distribution.PackageDescription(
BuildInfo,targetBuildDepends,options,libBuildInfo,library,Library,hsSourceDirs,exposedModules, extensions,
Executable,buildInfo, modulePath, executables, exeName
)
import DynFlags(
DynFlags, verbosity, ghcLink, packageFlags, outputFile, hiDir, objectDir ,importPaths
,PackageFlag (ExposePackage)
,GhcLink (NoLink)
)
import System.FilePath ( (</>))
import System.Directory (doesFileExist)
import Distribution.Compiler(CompilerFlavor(GHC))
import Distribution.Package (Dependency(Dependency), PackageName(PackageName))
import Data.Maybe
import Data.List(nub,isSuffixOf)
import Control.Monad
defaultCabalInput :: IO ShakerInput
defaultCabalInput = readConf >>= localBuildInfoToShakerInput >>= checkInvalidMain
readConf :: IO LocalBuildInfo
readConf = getPersistBuildConfig "dist"
localBuildInfoToShakerInput :: LocalBuildInfo -> IO ShakerInput
localBuildInfoToShakerInput lbi = do
defInput <- defaultInputInitialized
return defInput {
compileInputs = cplInputs
,listenerInput = compileInputsToListenerInput cplInputs
}
where cplInputs = localBuildInfoToCompileInputs lbi
compileInputsToListenerInput :: [CompileInput] -> ListenerInput
compileInputsToListenerInput cplInputs = defaultListenerInput {
fileListenInfo = nub $ map (\a -> FileListenInfo a defaultExclude defaultHaskellPatterns) concatSources
}
where concatSources = concatMap cfSourceDirs cplInputs
localBuildInfoToCompileInputs :: LocalBuildInfo -> [CompileInput]
localBuildInfoToCompileInputs lbi = executableAndLibToCompileInput (library pkgDescription) (executables pkgDescription)
where pkgDescription = localPkgDescr lbi
executableAndLibToCompileInput :: Maybe Library -> [Executable] -> [CompileInput]
executableAndLibToCompileInput Nothing exes =
map executableToCompileInput exes
executableAndLibToCompileInput (Just lib) exes =
libraryToCompileInput lib : map executableToCompileInput exes
executableToCompileInput :: Executable -> CompileInput
executableToCompileInput executable = defaultCompileInput {
cfSourceDirs = mySourceDir
,cfDescription = "Executable : " ++ exeName executable
,cfCommandLineFlags = getCompileOptions bldInfo
,cfTargetFiles = map (</> modulePath executable ) mySourceDir
,cfDynFlags = toDynFlags mySourceDir (getLibDependencies bldInfo)
}
where bldInfo = buildInfo executable
mySourceDir = hsSourceDirs bldInfo
libraryToCompileInput :: Library -> CompileInput
libraryToCompileInput lib = defaultCompileInput {
cfSourceDirs = mySourceDir
,cfDescription = "Library : " ++ show myModules
,cfCommandLineFlags = getCompileOptions bldInfo
,cfTargetFiles = myModules
,cfDynFlags = toDynFlags mySourceDir (getLibDependencies bldInfo)
}
where bldInfo = libBuildInfo lib
myModules = map convertModuleNameToString $ exposedModules lib
mySourceDir = hsSourceDirs bldInfo
toDynFlags :: [String] -> [String] -> DynFlags -> DynFlags
toDynFlags sourceDirs packagesToExpose dnFlags = dnFlags {
importPaths = sourceDirs
,outputFile = Just "target/Main"
,objectDir = Just "target"
,hiDir = Just "target"
,verbosity = 1
,ghcLink = NoLink
,packageFlags = map ExposePackage packagesToExpose
}
getCompileOptions :: BuildInfo -> [String]
getCompileOptions myLibBuildInfo = ghcOptions ++ ghcExtensions
where ghcOptions = fromMaybe [] $ lookup GHC (options myLibBuildInfo)
ghcExtensions = map (\a -> "-X"++ show a) (extensions myLibBuildInfo)
getLibDependencies :: BuildInfo -> [String]
getLibDependencies bi = map getPackageName $ targetBuildDepends bi
getPackageName :: Dependency -> String
getPackageName (Dependency (PackageName pn) _) = pn
convertModuleNameToString :: ModuleName -> String
convertModuleNameToString modName
| null modArr = ""
| otherwise = foldr1 (\w s -> w ++ '.':s) modArr
where modArr = components modName
checkInvalidMain :: ShakerInput -> IO ShakerInput
checkInvalidMain shIn = mapM checkInvalidMain' (compileInputs shIn) >>= \newCplInp ->
return $ shIn {compileInputs = newCplInp }
checkInvalidMain' :: CompileInput -> IO CompileInput
checkInvalidMain' cplInput
| any (".hs" `isSuffixOf`) oldTargets = do
newTargets <- filterM doesFileExist oldTargets
return cplInput {cfTargetFiles = newTargets}
| otherwise = return cplInput
where oldTargets = cfTargetFiles cplInput