phoityne-0.0.2.0: app/Phoityne/IO/Main.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiWayIf #-}
module Phoityne.IO.Main (run) where
-- モジュール
import Phoityne.Constant
import qualified Phoityne.Argument as A
import qualified Phoityne.IO.Control as CTRL
-- システム
import System.IO
import Data.Either.Utils
import Safe
import qualified Control.Exception as E
import qualified System.IO.Error as E
import qualified Data.ConfigFile as C
import qualified System.Console.CmdArgs as CMD
import qualified System.Log.Logger as L
import qualified System.Log.Formatter as L
import qualified System.Log.Handler as LH
import qualified System.Log.Handler.Simple as LHS
-- |
-- アプリケーションメイン
--
run :: IO Int
run = flip E.catches handlers $ do
-- コマンドライン引数設定
args <- getArgs
-- INI設定ファイルのRead
iniSet <- loadIniFile args
-- Loggerのセットアップ
setupLogger iniSet
-- ロジック実行
flip E.finally finalProc $ do
CTRL.run args iniSet
where
handlers = [ E.Handler helpExcept
, E.Handler ioExcept
, E.Handler someExcept
]
finalProc = L.removeAllHandlers
helpExcept (_ :: A.HelpExitException) = return 0
ioExcept (e :: E.IOException) = print e >> return 1
someExcept (e :: E.SomeException) = print e >> return 1
-- |
-- 引数データの取得
--
getArgs :: IO A.ArgData
getArgs = E.catches (CMD.cmdArgs A.config) handlers
where
handlers = [E.Handler someExcept]
someExcept (e :: E.SomeException) = if
| "ExitSuccess" == show e -> E.throw A.HelpExitException
| otherwise -> E.throwIO e
-- |
-- INI設定ファイルデータの取得
--
loadIniFile :: A.ArgData -- コマンドライン引数
-> IO C.ConfigParser -- INI設定
loadIniFile args = do
cp <- if null (A.file args) then return $ forceEither $ C.readstring C.emptyCP defaultIniSetting
else forceEither <$> C.readfile C.emptyCP (A.file args)
return cp{ C.accessfunc = C.interpolatingAccess 5 }
-- |
-- デフォルトINI設定
--
defaultIniSetting :: String
defaultIniSetting = unlines [
"[DEFAULT]"
, "work_dir = ./"
, ""
, "[LOG]"
, "file = %(work_dir)sphoityne.log"
, "level = INFO"
, ""
, "[PHOITYNE]"
, "target = ."
, "ghci_auto_start = True"
]
-- |
-- Loggerのセットアップ
--
setupLogger :: C.ConfigParser -- INI設定
-> IO () -- なし
setupLogger cp = do
let logFile = forceEither $ C.get cp _INI_SEC_LOG _INI_LOG_FILE
logLevel = forceEither $ C.get cp _INI_SEC_LOG _INI_LOG_LEVEL
level <- case readMay logLevel of
Just a -> return a
Nothing -> E.throwIO . E.userError $ "invalid log level[" ++ logLevel ++ "]"
logStream <- openFile logFile AppendMode
hSetEncoding logStream utf8
logH <- LHS.streamHandler logStream level
logSTD <- LHS.streamHandler stdout level
let logHandle = logH {LHS.closeFunc = hClose}
logFormat = L.tfLogFormatter _LOG_FORMAT_DATE _LOG_FORMAT
logHandler = LH.setFormatter logHandle logFormat
logHndlerSTD = LH.setFormatter logSTD logFormat
L.updateGlobalLogger L.rootLoggerName $ L.setHandlers ([] :: [LHS.GenericHandler Handle])
L.updateGlobalLogger _LOG_NAME $ L.setHandlers [logHandler, logHndlerSTD]
L.updateGlobalLogger _LOG_NAME $ L.setLevel level