precis-0.5.0: src/Precis/Cabal/InterimDatatypes.hs
{-# OPTIONS -Wall #-}
--------------------------------------------------------------------------------
-- |
-- Module : Precis.Cabal.InterimDatatypes
-- Copyright : (c) Stephen Tetley 2010
-- License : BSD3
--
-- Maintainer : Stephen Tetley <stephen.tetley@gmail.com>
-- Stability : highly unstable
-- Portability : to be determined.
--
-- Datatype for working with Cabal files...
--
--------------------------------------------------------------------------------
module Precis.Cabal.InterimDatatypes
(
FileExtension
, CabalFilePath
, cabalFilePath
, pathToCabalFile
, directoriesToCabalFile
, ExeMainPath(..)
, CabalSourceDir
, cabalSourceDir
, directoriesToSource
, ModName
, modName
, getModName
, ModuleDesc
, moduleDesc
, moduleDescName
, moduleDirectories
, CabalPrecis(..)
, CabalLibrary(..)
, CabalExe(..)
) where
import qualified Distribution.ModuleName as D
import Data.List ( intersperse )
import System.FilePath
type FileExtension = String
-- | 'CabalFilePath' is both the full, normalized path to the
-- cabal file and the directory parts to the file.
--
-- This is an opaque type - construct with 'cabalFilePath'.
--
data CabalFilePath = CabalFilePath
{ cabal_full_loc :: FilePath
, cabal_path_to_split :: [FilePath]
}
deriving (Eq,Ord,Show)
-- | Constructor for 'CabalFilePath' - the input FilePath is
-- normalized before constructing the data type.
--
cabalFilePath :: FilePath -> CabalFilePath
cabalFilePath path =
CabalFilePath { cabal_full_loc = full, cabal_path_to_split = parts }
where
full = normalise path
parts = splitPath $ dropFileName full
pathToCabalFile :: CabalFilePath -> FilePath
pathToCabalFile = cabal_full_loc
directoriesToCabalFile :: CabalFilePath -> [FilePath]
directoriesToCabalFile = cabal_path_to_split
newtype ExeMainPath = ExeMainPath { relPathToExeMain :: FilePath }
deriving (Eq,Ord,Show)
data CabalSourceDir = CabalSourceDir
{ srcdir_rel_loc :: FilePath
, srcdir_path_to_split :: [FilePath]
}
deriving (Eq,Ord,Show)
cabalSourceDir :: FilePath -> CabalSourceDir
cabalSourceDir path =
CabalSourceDir { srcdir_rel_loc = rel, srcdir_path_to_split = parts }
where
rel = normalise path
parts = splitPath rel
directoriesToSource :: CabalSourceDir -> [FilePath]
directoriesToSource = srcdir_path_to_split
newtype ModName = ModName { mod_name :: String }
deriving (Eq,Ord,Show)
modName :: D.ModuleName -> ModName
modName = ModName . concat . intersperse "." . D.components
getModName :: ModName -> String
getModName = mod_name
data ModuleDesc = ModuleDesc
{ module_desc_name :: ModName
, module_components :: [FilePath]
}
deriving (Eq,Ord,Show)
moduleDesc :: D.ModuleName -> ModuleDesc
moduleDesc mname =
ModuleDesc { module_desc_name = name, module_components = parts }
where
xs = D.components mname
name = ModName $ concat $ intersperse "." xs
-- Add separator to inits but not last...
parts = foldr fn [] xs where fn e [] = [e]
fn e ac = (e++[pathSeparator]):ac
moduleDescName :: ModuleDesc -> ModName
moduleDescName = module_desc_name
moduleDirectories :: ModuleDesc -> [FilePath]
moduleDirectories = module_components
-- Do we want /resolution/ during the building
-- the CabalPrecis or afterwards?
--
-- i.e. when do we query the file system to locate the modules?
-- Because of CondTree/Conditional a Cabal file can appear as
-- though it contains more than one Library, some normalization
-- has to be performed on this structure...
--
data CabalPrecis = CabalPrecis
{ pkg_name :: String
, pkg_version :: String
, path_to_cabal_file :: CabalFilePath
, cond_libraries :: [CabalLibrary]
, cond_exes :: [CabalExe]
}
deriving (Eq,Show)
-- One library per cabal file / package.
data CabalLibrary = CabalLibrary
{ library_src_dirs :: [CabalSourceDir]
, public_modules :: [ModuleDesc]
, private_modules :: [ModuleDesc]
}
deriving (Eq,Ord,Show)
-- Zero / one or more exe per cabal file / package.
-- The executable file will include the extension...
data CabalExe = CabalExe
{ exe_main_module :: ExeMainPath
, exe_src_dirs :: [CabalSourceDir]
, exe_other_modules :: [ModuleDesc]
}
deriving (Eq,Ord,Show)