packages feed

steeloverseer-0.5.0.0: src/Main.hs

{-#LANGUAGE RecordWildCards #-}
module Main where

import System.Environment        (getArgs)
import System.Console.GetOpt 
import System.Posix.Daemon
import Data.List
import Control.Monad
import Filesystem.Path.CurrentOS hiding (concat, null)
import Data.Text as T            hiding (foldl, concat, intercalate, null)
import Prelude                   hiding (FilePath)
import SOS

main :: IO ()
main = do
    args <- getArgs
    case getOpt Permute options args of
        (   [],    _,   []) -> error $ usageInfo header options
        ( opts,    _,   []) -> startWithOpts $ foldl (flip id) defaultOptions opts
        (    _,    _, msgs) -> error $ concat msgs ++ usageInfo header options

data Options = Options { optShowVersion :: Bool
                       , optCommands    :: [String]
                       , optPatterns    :: [String]
                       , optDirectory   :: FilePath
                       , optIsDaemon    :: Bool
                       , optDaemonCmd   :: String
                       } deriving (Show, Eq)

defaultOptions :: Options
defaultOptions = Options { optShowVersion = False
                         , optCommands    = []
                         , optPatterns    = []
                         , optDirectory   = fromText $ T.pack "."
                         , optIsDaemon    = False
                         , optDaemonCmd   = "start"  
                         }

options :: [OptDescr (Options -> Options)]
options = [ Option "v" ["version"]
              (NoArg (\opts -> opts { optShowVersion = True }))
              "Show version info."
          , Option "c" ["command"]
              (ReqArg (\c opts -> opts { optCommands = optCommands opts ++ [c] }) "command")
              "Add command to run on file event."
          , Option "p" ["pattern"]
              (ReqArg (\e opts -> opts { optPatterns = optPatterns opts ++ [e] }) "pattern")
              "Add pattern to match on file path." 
          , Option "d" ["directory"]
              (ReqArg (\d opts -> opts { optDirectory = decodeString d }) "directory")
              "Set directory to watch for changes (default is ./)."
          , Option "b" ["daemon"]
              (ReqArg (\s opts -> opts { optIsDaemon = True, optDaemonCmd = s }) "start|stop")
              "Attempt to run in the background as a daemon. When a previous daemon is running from your working directory this option will kill that process."
          ]
                         
header :: String
header = "Usage: sos [vb] -c command -p pattern"

version :: String
version = "\nSteel Overseer 1.0.0.0\n"

startWithOpts :: Options -> IO ()
startWithOpts opts = do
    let Options{..} = opts
        haveOptions   = not (null optPatterns)
        patternsValid = and $ fmap (not . null) optPatterns
        daemonValid   = optDaemonCmd == "start" || optDaemonCmd == "stop"
    when optShowVersion $ putStrLn version
    unless patternsValid $ error "One or more patterns are empty."
    unless daemonValid $ error "The argument to -b,--daemon must be one of start or stop."
    didKill <- if optIsDaemon && optDaemonCmd == "stop"
                 then do shouldKillPrev <- isRunning pIdFile
                         if shouldKillPrev
                           then do putStrLn "Killing previous steeloverseer daemon..."
                                   killAndWait pIdFile 
                                   putStrLn "Done."
                           else putStrLn "There is no previous daemon to kill."
                         return shouldKillPrev
                 else return False
    let runSteelOverseer = steelOverseer optDirectory optCommands optPatterns optIsDaemon
    when (haveOptions && patternsValid && daemonValid) $ 
        if not optIsDaemon 
          then runSteelOverseer 
          else unless didKill $ do
                   putStrLn "Running in the background as a daemon, logging output to sos.log."
                   runDetached (Just pIdFile) (ToFile logFile) runSteelOverseer