{-# OPTIONS -Wall #-}
module Language.C.Test.Environment (
TestConfig(..),
envHelpDoc,
getEnvFlag,exitFailureEnvVar,
getEnvConfig,
isPreprocessedFile,MungeResult(..),mungeCcArgs,
)
where
import Control.Exception (catch)
import Control.Monad (liftM)
import Data.Char (toLower)
import Data.List (isPrefixOf, isSuffixOf)
import qualified Data.Map as Map
import System.Environment
import System.FilePath (combine)
import System.IO
import Text.PrettyPrint
envHelpDoc :: [(String, (String, Maybe String ))] -> Doc
envHelpDoc addEnvHelp
= text "Influental environment variables:" $+$
(nest 4 . vcat . map varInfo) (envHelp ++ addEnvHelp)
where
varInfo (var, (descr, def)) = text var $$ nest 30 (prettyDescr descr def)
prettyDescr descr def = text descr <> prettyDef def
prettyDef Nothing = empty
prettyDef (Just def) = text $ " [default = " ++ def ++ "]"
envHelp :: [(String, (String, Maybe String))]
envHelp = [ vi tmpdirEnvVar "the temporary directory to write test reports to" Nothing,
vi logfileEnvVar "the log file" (Just "<stderr>"),
vi reportFileEnvVar "file to write test reports to" (Just (tmpdirEnvVar++"/report.dat")),
vi debugEnvVar "whether to print debug messages" (Just ("False")),
vi keepImEnvVar "whether to keep intermediate files" (Just ("False")),
vi exitFailureEnvVar "whether to exit with failure if one test fails" (Just ("False"))
]
where vi envVar varDescr varDef = (envVar, (varDescr, varDef))
data TestConfig = TestConfig
{
debug :: String -> IO (),
logger :: String -> IO (),
keepIntermediate :: Bool,
tmpDir :: FilePath
}
tmpdirEnvVar :: String
tmpdirEnvVar = "CTEST_TMPDIR"
logfileEnvVar :: String
logfileEnvVar = "CTEST_LOGFILE"
reportFileEnvVar :: String
reportFileEnvVar = "CTEST_REPORT_FILE"
debugEnvVar :: String
debugEnvVar = "CTEST_DEBUG"
keepImEnvVar :: String
keepImEnvVar = "CTEST_KEEP_INTERMEDIATE"
exitFailureEnvVar :: String
exitFailureEnvVar = "CTEST_EXIT_FAILURE"
defaultReportFile :: String
defaultReportFile = "report.dat"
getEnvConfig :: IO (TestConfig, FilePath)
getEnvConfig = do
environ <- liftM Map.fromList getEnvironment
tmpdir <- getEnv tmpdirEnvVar
let resultFile = maybe (combine tmpdir defaultReportFile) id $ Map.lookup reportFileEnvVar environ
let debugFlag = maybe False (const True) $ Map.lookup debugEnvVar environ
let keepIm = maybe False (const True) $ Map.lookup keepImEnvVar environ
let logFile = maybe Nothing Just $ Map.lookup logfileEnvVar environ
let config = TestConfig {
debug = debugAction debugFlag,
logger = logAction logFile,
tmpDir = tmpdir,
keepIntermediate = keepIm
}
return (config,resultFile)
where
debugAction False = \_ -> return ()
debugAction True = hPutStr stderr . ("[DEBUG] "++)
logAction Nothing = hPutStr stderr
logAction (Just logFile) = appendFile logFile
getEnvFlag :: String -> IO Bool
getEnvFlag envVar = do
envFlag <- getEnv envVar `catch` (\e -> return ((e :: IOError) `seq` "0"))
return $ case envFlag of
_ | envFlag == "" || envFlag == "0" || "f" `isPrefixOf` (map toLower envFlag) -> False
| otherwise -> True
isPreprocessedFile :: String -> Bool
isPreprocessedFile = (".i" `isSuffixOf`)
data MungeResult = Unknown String | Ignore | Groked [FilePath] [String]
mungeCcArgs :: [String] -> MungeResult
mungeCcArgs = mungeArgs [] []
mungeArgs :: [String] -> [String] -> [String] -> MungeResult
mungeArgs _accum [] [] = Unknown "No .c / .hc / .i source file given"
mungeArgs accum cfiles [] = Groked cfiles (reverse accum)
mungeArgs _accum _cfiles ("-E":_) = Ignore
mungeArgs _accum _cfiles ("-M":_) = Ignore
mungeArgs accum cfiles ("-o":_outfile:args) = mungeArgs accum cfiles args
mungeArgs accum cfiles (cfile':args)
| ".c" `isSuffixOf` cfile'
|| ".hc" `isSuffixOf` cfile'
|| ".i" `isSuffixOf` cfile' =
mungeArgs accum (cfile':cfiles) args
mungeArgs _accum _cfiles (cfile':_)
| ".S" `isSuffixOf` cfile' = Ignore
mungeArgs accum cfiles (arg:args) = mungeArgs (arg:accum) cfiles args