{-# LANGUAGE CPP #-}

module Development.Shake.Cabal ( getCabalDeps
                               , getCabalDepsV
                               , getCabalDepsA
                               , shakeVerbosityToCabalVerbosity
                               -- * Helper functions
                               , platform
                               -- * Reƫxports from "Distribution.Version"
                               , showVersion
                               ) where

import           Control.Arrow
import           Control.Composition
import           Control.Monad
import           Data.Foldable                         (toList)
import           Data.Maybe                            (catMaybes)
#if __GLASGOW_HASKELL__ < 804
import           Data.Semigroup
#endif
import           Development.Shake                     as Shake
import           Distribution.ModuleName
import           Distribution.PackageDescription
import           Distribution.PackageDescription.Parse
import           Distribution.Types.CondTree
import           Distribution.Types.PackageId
import           Distribution.Verbosity                as Distribution
import           Distribution.Version
import           System.Info                           (arch, os)

-- | E.g. @x86_64-linux@
platform :: String
platform = arch ++ "-" ++ os

libraryToFiles :: Library -> [FilePath]
libraryToFiles lib = cs <> is <> ((<> ".hs") . toFilePath <$> explicitLibModules lib)
    where (cs, is) = (cSources &&& includes) $ libBuildInfo lib

extract :: CondTree a b Library -> [Library]
extract (CondNode d _ []) = [d]
extract (CondNode d _ bs) = d : (g =<< bs)
    where g (CondBranch _ tb fb) = join $ catMaybes [Just $ extract tb, extract <$> fb]

shakeVerbosityToCabalVerbosity :: Shake.Verbosity -> Distribution.Verbosity
shakeVerbosityToCabalVerbosity Silent     = silent
shakeVerbosityToCabalVerbosity Quiet      = normal
shakeVerbosityToCabalVerbosity Normal     = normal
shakeVerbosityToCabalVerbosity Loud       = verbose
shakeVerbosityToCabalVerbosity Chatty     = verbose
shakeVerbosityToCabalVerbosity Diagnostic = deafening

getCabalDepsA :: FilePath -> Action (Version, [FilePath])
getCabalDepsA = join . (g <$> fmap shakeVerbosityToCabalVerbosity getVerbosity <*>) . pure
    where g = liftIO .* getCabalDepsV

-- | Get library dependencies from a @.cabal@ file. This will only work for
-- @.hs@ files; module signatures are not supported.
getCabalDeps :: FilePath -> IO (Version, [FilePath])
getCabalDeps = getCabalDepsV normal

getCabalDepsV :: Distribution.Verbosity -> FilePath -> IO (Version, [FilePath])
getCabalDepsV v p = do
    pkg <- readGenericPackageDescription v p
    let descr = packageDescription pkg
        extraSrc = extraSrcFiles descr
        vers = pkgVersion (package descr)
        libs = toList (condLibrary pkg)
        normalSrc = (libraryToFiles <=< extract) =<< libs
    pure (vers, extraSrc <> normalSrc)