serverman/src/System/Term.hs

187 lines
6.5 KiB
Haskell
Raw Normal View History

2017-02-18 19:25:57 +00:00
{-# LANGUAGE NamedFieldPuns #-}
2017-03-13 15:37:07 +00:00
{-# LANGUAGE ScopedTypeVariables #-}
2017-02-18 19:25:57 +00:00
module System.Term ( initialize ) where
import qualified System.Serverman as S
import System.Serverman.Log
2017-02-18 19:25:57 +00:00
import System.Environment
import System.Directory
2017-02-18 19:25:57 +00:00
import Data.Monoid
import Data.Maybe
import Control.Monad
import Control.Monad.State
2017-03-13 15:37:07 +00:00
import Data.Default.Class
import System.FilePath
import Data.List
import System.Process
import Control.Concurrent
2017-03-13 15:37:07 +00:00
2017-03-21 10:05:17 +00:00
import System.Serverman.Utils hiding (liftIO)
import System.Serverman.Actions.Repository
2017-02-18 19:25:57 +00:00
initialize = do
-- read arguments
args <- getArgs
2017-03-13 15:37:07 +00:00
dir <- getAppUserDataDirectory "serverman"
2017-03-13 15:37:07 +00:00
-- parse parameters
2017-03-13 15:37:07 +00:00
let params = parseParams args
2017-04-09 12:34:09 +00:00
isHelp = any (`elem` args) ["help", "--help", "-h", "-?"]
2017-03-13 15:37:07 +00:00
-- Fetch repository first
S.runApp $ do
when (verboseM params) $ do
state <- get
put $ state { verboseMode = True }
verbose "verbose mode on"
verbose $ show params
-- fetch repository if running for the first time, set state
2017-04-09 12:34:09 +00:00
S.run S.fetchRepository
-- detect local operating system
2017-04-09 12:34:09 +00:00
S.run S.detectOS
2017-03-13 15:37:07 +00:00
2017-04-09 12:34:09 +00:00
state@S.AppState { S.repository } <- get
put $ state { arguments = rest params, helpArg = isHelp }
2017-03-13 15:37:07 +00:00
case params of
-- list services in repository
2017-04-09 12:34:09 +00:00
Params { listServices = True } ->
mapM_ (write . show) repository
-- install a service
2017-04-09 12:34:09 +00:00
p@Params { install = Just service } -> do
verbose $ "preparing to install " ++ service
ms <- findService service
case ms of
2017-03-21 10:05:17 +00:00
Just s -> handleRemote p $ S.install s
Nothing -> die $ "service not found: " ++ service
2017-04-09 12:34:09 +00:00
p@Params { update = True } -> S.run S.updateRepository
2017-04-09 12:34:09 +00:00
p@Params { manage = Just (act, service) } -> do
verbose $ "preparing to " ++ show act ++ " " ++ service
ms <- findService service
case ms of
2017-04-09 12:34:09 +00:00
Just s ->
case act of
Start ->
handleRemote p $ S.start s
Stop ->
handleRemote p $ S.stop s
Nothing ->
die $ "could not find any service matching " ++ service
-- install and call a service
2017-04-09 12:34:09 +00:00
p@Params { rest = (x:xs), remote } ->
case x of
(service, Nothing) -> do
verbose $ "preparing to call " ++ service
ms <- findService service
case ms of
2017-03-21 10:05:17 +00:00
Just s -> do
2017-04-09 12:34:09 +00:00
unless isHelp $
handleRemote p (S.install s)
2017-03-21 10:05:17 +00:00
S.run $ S.call s remote
2017-04-09 12:34:09 +00:00
Nothing ->
if isHelp then
servermanHelp
else
die $ "could not find any service matching " ++ service
_ -> servermanHelp
2017-03-13 15:37:07 +00:00
-- after the program is done, terminate remaining processes
-- and unmount/remove leftover temporary directories
2017-04-09 12:34:09 +00:00
state@S.AppState { S.processes, S.temps } <- get
put $ state { remoteMode = Nothing }
mapM_ (liftIO . terminateProcess) processes
mapM_ clearTemp temps
2017-02-18 19:25:57 +00:00
return ()
2017-03-13 15:37:07 +00:00
where
clearTemp path = execIfExists path $ do
execute "fusermount" ["-u", path] "" False
liftIO $ removeDirectoryRecursive path
-- if remote mode is set, read the file and run the action
-- on servers, otherwise run action locally
2017-04-09 12:34:09 +00:00
handleRemote Params { remote = Just file } action = do
list <- liftIO $ filter (not . null) . lines <$> readFile file
S.run (S.remote (map read list) action)
handleRemote Params { remote = Nothing } action = S.run action
2017-03-13 15:37:07 +00:00
servermanHelp = do
write "serverman [--options] [command/service] [--service-options]"
write $ mkHelp "commands"
[ ("install <service>", "install a service")
, ("repository list", "list services")
, ("repository update", "update repository")
, ("service start <service>", "start the service")
, ("service stop <service>", "stop the service")
, ("--remote <file>", "run in remote mode: takes a path to a file containing username@ip:port lines")]
write "to learn about a service's options, run |serverman <service> --help|"
2017-03-13 15:37:07 +00:00
data Manage = Start | Stop deriving (Eq, Show)
data Params = Params { listServices :: Bool
, install :: Maybe String
, manage :: Maybe (Manage, String)
, update :: Bool
, remote :: Maybe FilePath
, rest :: [(String, Maybe String)]
, verboseM :: Bool
}
instance Show Params where
2017-04-09 12:34:09 +00:00
show Params { listServices, install, manage, update, remote, rest, verboseM } =
keyvalue [ ("list-services", show listServices)
, ("install", show install)
, ("manage", show manage)
, ("update", show update)
, ("remote", show remote)
, ("rest", show rest)
, ("verbose", show verboseM)] ": "
2017-03-13 15:37:07 +00:00
instance Default Params where
def = Params { listServices = False
2017-03-21 10:05:17 +00:00
, install = Nothing
, manage = Nothing
, remote = Nothing
, update = False
, rest = []
, verboseM = False
2017-03-21 10:05:17 +00:00
}
2017-03-13 15:37:07 +00:00
parseParams :: [String] -> Params
parseParams ("repository":"list":xs) = (parseParams xs) { listServices = True }
parseParams ("repository":"update":xs) = (parseParams xs) { update = True }
parseParams ("service":"start":s:xs) = (parseParams xs) { manage = Just (Start, s) }
parseParams ("service":"stop":s:xs) = (parseParams xs) { manage = Just (Stop, s) }
parseParams ("install":s:xs) = (parseParams xs) { install = Just s }
parseParams ("--remote":s:xs) = (parseParams xs) { remote = Just s }
parseParams ("--verbose":xs) = (parseParams xs) { verboseM = True }
parseParams x = def { rest = toPairs x }
where
toPairs [] = []
toPairs [x] = [(getWord x, Nothing)]
toPairs (x:y:xs)
2017-04-09 12:34:09 +00:00
| flagName x && value y = (getWord x, Just y) : toPairs xs
| flagName y && value x = (getWord x, Nothing) : toPairs (y:xs)
| flagName x && flagName y = (getWord x, Nothing) : toPairs (y:xs)
| otherwise = toPairs xs
flagName = isPrefixOf "-"
value = not . flagName
getWord = dropWhile (== '-')