ert-0.0.1.0: Main.hs
import Paths_ert(version)
import Data.Version(showVersion)
import System.Console.GetOpt(getOpt, usageInfo, ArgOrder(Permute), ArgDescr(..), OptDescr(..))
import System.Environment(getArgs, getProgName)
import System.IO (hPutStrLn, stdin, stdout, stderr)
import System.Exit(exitWith, ExitCode(ExitSuccess, ExitFailure))
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import qualified Data.EasyTpl as ET
import qualified Data.Attoparsec.ByteString as AP
import qualified Data.Aeson as J
#ifdef WITH_YAML
import qualified Data.Yaml as Y
#endif
data Action = ShowUsage
| ShowVersion
| ProcessTemplate
deriving (Show, Eq)
data DataFile = NullData
| JsonFile FilePath
#ifdef WITH_YAML
| YamlFile FilePath
#endif
| NoneData
deriving (Show, Eq)
debugLog :: (Show s) => String -> s -> IO ()
#ifdef WITH_DEBUG
debugLog key val = hPutStrLn stderr $ "\n" ++ key ++ ">> " ++ show val
#else
debugLog _ _ = return ()
#endif
data Options =
Options
{ optTemplate :: FilePath
, optOutput :: FilePath
, optDataFile :: DataFile
, optAction :: Action
} deriving (Show, Eq)
defaults :: Options
defaults =
Options
{ optTemplate = ""
, optOutput = ""
, optDataFile = NoneData
, optAction = ShowUsage
}
options :: [OptDescr (Options -> Options)]
options =
[ Option ['h', '?'] ["help"]
(NoArg (\opts -> opts { optAction = ShowUsage }))
"This usage hint."
, Option ['V'] ["version"]
(NoArg (\opts -> opts { optAction = ShowVersion }))
"Version information."
, Option ['i', 't'] ["input", "template"]
(OptArg (\val opts -> opts { optTemplate = maybe "" id val
, optAction = ProcessTemplate }) "FILE")
("Read input template from FILE (default: " ++ (optTemplate defaults) ++ ", empty means stdin).")
, Option ['o', 'r'] ["output", "render-to"]
(OptArg (\val opts -> opts { optOutput = maybe "" id val
, optAction = ProcessTemplate }) "FILE")
("Output render result to FILE (default: " ++ (optOutput defaults) ++ ", empty means stdout).")
, Option ['s'] ["standalone"]
(NoArg (\opts -> opts { optDataFile = NullData
, optAction = ProcessTemplate }))
"Render template without data."
, Option ['j'] ["json", "json-data"]
(OptArg (\val opts -> opts { optDataFile = JsonFile $ maybe "" id val
, optAction = ProcessTemplate }) "FILE")
("Render template with JSON data from FILE (default: compile template only, empty means stdin).")
#ifdef WITH_YAML
, Option ['y'] ["yaml", "yaml-data"]
(OptArg (\val opts -> opts { optDataFile = YamlFile $ maybe "" id val
, optAction = ProcessTemplate }) "FILE")
("Render template with YAML data from FILE (default: compile template only, empty means stdin).")
#endif
]
parseArgs :: [String] -> String -> IO Options
parseArgs argv program =
case getOpt Permute options argv of
(args, fs, []) -> do
doAction' $ foldl (flip id) defaults
$ concat [ args
, map (\val opts -> opts { optTemplate = val
, optAction = ProcessTemplate }) fs
]
(_, _, errs) -> do
hPutStrLn stderr (concat errs ++ usageInfo usage options)
exitWith $ ExitFailure 1
where
-- usage :: String
usage = "Usage: " ++ program ++ " [options]"
-- verst :: String
verst = program ++ " " ++ showVersion version
-- doAction :: Options -> IO ()
doAction' opts = do
debugLog "CommandOptions" opts
case optAction opts of
ShowUsage -> do
hPutStrLn stderr (usageInfo usage options)
exitWith ExitSuccess
ShowVersion -> do
hPutStrLn stderr verst
exitWith ExitSuccess
_ -> return opts
doAction :: Options -> IO ()
doAction Options { optTemplate = template
, optOutput = output
, optDataFile = NoneData
} =
--BS.readFile template >>= AP.parseTest ET.parseTemplate
inputFile template >>= return . AP.parseOnly ET.parseTemplate >>= outputFile output . BSC.pack . (++ "\n") . show
doAction Options { optTemplate = template
, optOutput = output
, optDataFile = input
} = do
envData <- case input of
NullData -> return $ ET.defaultData
_ -> inputFile (dataFile input) >>= either error return . dataParse input
debugLog "InputData" envData
inputFile template >>=
either error return . ET.compile >>=
outputFile output . (flip ET.render envData)
where
dataFile :: DataFile -> FilePath
dataFile (JsonFile file) = file
#ifdef WITH_YAML
dataFile (YamlFile file) = file
#endif
dataFile _ = ""
dataParse :: DataFile -> BS.ByteString -> Either String ET.Value
dataParse (JsonFile _) = AP.parseOnly J.json'
#ifdef WITH_YAML
dataParse (YamlFile _) = Y.decodeEither
#endif
dataParse _ = \_ -> Left "Unknown data type"
inputFile :: FilePath -> IO ByteString
inputFile "" = BS.hGetContents stdin
inputFile path = BS.readFile path
outputFile :: FilePath -> ByteString -> IO ()
outputFile "" = BS.hPutStr stdout
outputFile path = BS.writeFile path
main :: IO ()
main = getArgs >>= parseArgs' >>= doAction
where
parseArgs' argv = getProgName >>= parseArgs argv