src/Importify/Cabal/Module.hs
-- | Functions to operate with @exposed-modules@ and @other-modules@
-- parts of .cabal file.
module Importify.Cabal.Module
( modulePaths
, splitOnExposedAndOther
) where
import Universum hiding (fromString)
import Data.List (partition)
import Distribution.ModuleName (ModuleName, fromString, toFilePath)
import qualified Distribution.ModuleName as Cabal
import Distribution.PackageDescription (BuildInfo (..), Library (..))
import qualified Language.Haskell.Exts as HSE
import Path (Abs, Dir, File, Path, Rel, parseRelDir,
parseRelFile, (</>))
import Path.IO (doesFileExist)
import Importify.Syntax (getModuleTitle)
-- | Split list of modules into /exposed/ modules and /other/ modules for given library.
-- __First__ element of pair represents /exposed/ modules.
-- __Second__ element of paris represents /other/ modules.
splitOnExposedAndOther :: Library
-> [HSE.Module l]
-> ([HSE.Module l], [HSE.Module l])
splitOnExposedAndOther Library{..} =
partition ((`elem` exposedModules) . Cabal.fromString . getModuleTitle)
-- | Returns list of absolute paths to all modules inside given target.
modulePaths :: Path Abs Dir
-- ^ Absolute path to project directory
-> BuildInfo
-- ^ 'BuildInfo' for given target
-> Either [ModuleName] FilePath
-- ^ Modules for Library and path for others
-> IO [Path Abs File]
modulePaths packagePath BuildInfo{..} extra = do
let (cur, others) = partition (== ".") hsSourceDirs
case (cur, others) of
(_here, []) -> collectModulesHere
([] , paths) -> collectModulesThere paths
(_here, paths) -> liftA2 (++) collectModulesHere (collectModulesThere paths)
where
modulesToPaths :: [ModuleName] -> IO [Path Rel File]
modulesToPaths = mapM (parseRelFile . (++ ".hs") . toFilePath)
targetModulePaths :: IO [Path Rel File]
targetModulePaths = case extra of
Left modules -> modulesToPaths $ otherModules ++ modules
Right path -> liftA2 (:) (parseRelFile path) (modulesToPaths otherModules)
addDir :: Path Abs Dir -> [Path Rel File] -> [Path Abs File]
addDir dir = map (dir </>)
collectModulesHere :: IO [Path Abs File]
collectModulesHere = do
paths <- targetModulePaths
let packagePaths = addDir packagePath paths
keepExistingModules packagePaths
collectModulesThere :: [FilePath] -> IO [Path Abs File]
collectModulesThere dirs = do
dirPaths <- mapM parseRelDir dirs
modPaths <- targetModulePaths
concatForM dirPaths $ \dir ->
keepExistingModules $ addDir (packagePath </> dir) modPaths
keepExistingModules :: [Path Abs File] -> IO [Path Abs File]
keepExistingModules = filterM doesFileExist