cabal-ghci-0.1.1: Distribution/Dev/Interactive.hs
-- | Retrieve ghci options for your cabal project
module Distribution.Dev.Interactive (
-- * Installing into your .ghci
-- $install
-- * Arguments
-- $args
-- * Exported functions
cabalSet, packageOpts, loadCabal, lookForCabalFile, withOpts, LoadCabalRet(..)
) where
import Distribution.Text
import Distribution.Compiler
import Distribution.Verbosity
import Distribution.System
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Parse
import Distribution.PackageDescription.Configuration
import System.FilePath
import System.Directory
import System.Info
import Data.Maybe
-- | Return value for 'loadCabal'
data LoadCabalRet =
NoCabalFile | -- ^ No cabal file found
MissingDeps [Dependency] | -- ^ Missing dependencies
Pkg FilePath PackageDescription -- ^ Successful loading and parsing of cabal file
deriving Show
compiler ∷ CompilerId
compiler = CompilerId buildCompilerFlavor compilerVersion
-- | Build a list of ghci options needed to load files from a cabal project
packageOpts
∷ FilePath -- ^ path to the .cabal file
→ PackageDescription -- ^ parsed package description
→ String -- ^ name of executable
→ Maybe [String]
packageOpts path pkg executable =
maybe Nothing (\bi → Just $ includeOpts path bi ++ extensionOpts bi ++ customOpts bi) $
listToMaybe $
if executable == ""
then allBuildInfo pkg
else
fmap buildInfo .
filter (\x → exeName x == executable) .
executables $ pkg
customOpts ∷ BuildInfo → [String]
customOpts bi =
hcOptions buildCompilerFlavor bi
extensionOpts ∷ BuildInfo → [String]
extensionOpts bi =
map (\x → "-X" ++ display x) $ allExtensions bi
includeOpts ∷ FilePath → BuildInfo → [String]
includeOpts path bi =
["-i" ++ dir ++ "/dist/build/autogen"] ++
map (("-i"++) . combine dir) (hsSourceDirs bi)
where dir = takeDirectory path
-- | Load the current cabal project file and parse it
loadCabal
∷ FilePath -- ^ usually the current directory
→ FlagAssignment -- ^ list of cabal flag assignments
→ IO LoadCabalRet
loadCabal path flags = do
mCabalFile ← lookForCabalFile =<< canonicalizePath path
flip (maybe (return NoCabalFile))
mCabalFile $ \cabalFile → do
gdescr ← readPackageDescription normal cabalFile
case finalizePackageDescription flags (const True)
buildPlatform compiler [] gdescr of
Left deps → return $ MissingDeps deps
Right (descr, _) → return $ Pkg cabalFile descr
-- | Find a .cabal file in the path or any of it's parent directories
lookForCabalFile
∷ FilePath -- ^ canonicalised path
→ IO (Maybe FilePath)
lookForCabalFile "/" = return Nothing
lookForCabalFile path = do
files ← getDirectoryContents path
let cabals = filter (\f →
takeExtension f == ".cabal"
&& f /= ".cabal") files
case cabals of
[] → lookForCabalFile (takeDirectory path)
[a] → return $ Just $ combine path a
_ → return Nothing
-- | 'cabalSet' returns a list of ghci commands (seperated by newlines) that :set the 'packageOpts' of the current cabal project
cabalSet
∷ String -- ^ arguments seperated by spaces
→ IO String
cabalSet args =
withOpts (words args)
(\x → putStrLn x >> return "")
((\x → putStrLn x >> return x) .
unlines . (map (":set "++)) . map show )
-- | Generalised version of 'cabalSet'
withOpts
∷ [String] -- ^ List of cabal flag arguments and executable name
→ (String → IO a) -- ^ Error continuation. Recieves an error message.
→ ([String] → IO a) -- ^ Success continuation. Recieves a list of ghci arguments.
→ IO a
withOpts args err go = do
let (flags, executable) = parseArgs args
here ← getCurrentDirectory
ret ← loadCabal here flags
case ret of
NoCabalFile → err "Current directory is not a cabal project"
MissingDeps deps → err $ "Missing dependencies: " ++ unwords (map show deps)
Pkg path descr → do
let mopts = packageOpts path descr executable
case mopts of
Nothing → err (
if executable /= ""
then "No such executable in cabal file"
else "No library defined in cabal file")
Just opts → go opts
parseArgs ∷ [String] → (FlagAssignment, String)
parseArgs args =
(map (makeFlag . drop 2) . filter flag $ args,
fromMaybe "" . listToMaybe . filter (not . flag) $ args)
where
flag x = take 2 x == "-f"
makeFlag ∷ String → (FlagName, Bool)
makeFlag ('-':f) = (FlagName f, False)
makeFlag f = (FlagName f, True)
-- $install
-- @
-- $ head -n 4 >> ~/.ghci
-- :m + Distribution.Dev.Interactive
-- :def cabalset cabalSet
-- :cabalset
-- :m - Distribution.Dev.Interactive
-- @
-- $args
-- [@-fflag@] enable flag
--
-- [@-f-flag@] disable flag
--
-- [@exec@] load options for the exec executable