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
|
2017-03-30 18:30:40 +00:00
|
|
|
import System.Serverman.Log
|
2017-02-18 19:25:57 +00:00
|
|
|
|
|
|
|
import System.Environment
|
2017-02-22 09:28:34 +00:00
|
|
|
import System.Directory
|
2017-02-18 19:25:57 +00:00
|
|
|
import Data.Monoid
|
|
|
|
import Data.Maybe
|
2017-02-22 09:55:17 +00:00
|
|
|
import Control.Monad
|
2017-03-11 10:21:38 +00:00
|
|
|
import Control.Monad.State
|
2017-03-13 15:37:07 +00:00
|
|
|
import Data.Default.Class
|
|
|
|
import System.FilePath
|
|
|
|
import Data.List
|
2017-03-30 18:30:40 +00:00
|
|
|
import System.Process
|
2017-04-01 07:30:22 +00:00
|
|
|
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)
|
2017-03-18 14:34:56 +00:00
|
|
|
import System.Serverman.Actions.Repository
|
2017-02-18 19:25:57 +00:00
|
|
|
|
|
|
|
initialize = do
|
2017-03-30 18:30:40 +00:00
|
|
|
-- read arguments
|
2017-02-19 12:47:37 +00:00
|
|
|
args <- getArgs
|
2017-03-13 15:37:07 +00:00
|
|
|
|
2017-03-30 18:30:40 +00:00
|
|
|
dir <- getAppUserDataDirectory "serverman"
|
2017-03-13 15:37:07 +00:00
|
|
|
|
2017-03-30 18:30:40 +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
|
2017-03-30 18:30:40 +00:00
|
|
|
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
|
2017-03-30 18:30:40 +00:00
|
|
|
|
|
|
|
-- 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
|
2017-03-30 18:30:40 +00:00
|
|
|
put $ state { arguments = rest params, helpArg = isHelp }
|
2017-03-13 15:37:07 +00:00
|
|
|
|
|
|
|
case params of
|
2017-03-30 18:30:40 +00:00
|
|
|
-- list services in repository
|
2017-04-09 12:34:09 +00:00
|
|
|
Params { listServices = True } ->
|
2017-03-30 18:30:40 +00:00
|
|
|
mapM_ (write . show) repository
|
|
|
|
|
|
|
|
-- install a service
|
2017-04-09 12:34:09 +00:00
|
|
|
p@Params { install = Just service } -> do
|
2017-03-30 18:30:40 +00:00
|
|
|
verbose $ "preparing to install " ++ service
|
2017-03-18 14:34:56 +00:00
|
|
|
ms <- findService service
|
|
|
|
case ms of
|
2017-03-21 10:05:17 +00:00
|
|
|
Just s -> handleRemote p $ S.install s
|
2017-03-30 18:30:40 +00:00
|
|
|
Nothing -> die $ "service not found: " ++ service
|
|
|
|
|
2017-04-09 12:34:09 +00:00
|
|
|
p@Params { update = True } -> S.run S.updateRepository
|
2017-03-30 18:30:40 +00:00
|
|
|
|
2017-04-09 12:34:09 +00:00
|
|
|
p@Params { manage = Just (act, service) } -> do
|
2017-03-30 18:30:40 +00:00
|
|
|
verbose $ "preparing to " ++ show act ++ " " ++ service
|
|
|
|
ms <- findService service
|
|
|
|
case ms of
|
2017-04-09 12:34:09 +00:00
|
|
|
Just s ->
|
2017-03-30 18:30:40 +00:00
|
|
|
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 } ->
|
2017-03-18 14:34:56 +00:00
|
|
|
case x of
|
|
|
|
(service, Nothing) -> do
|
2017-03-30 18:30:40 +00:00
|
|
|
verbose $ "preparing to call " ++ service
|
|
|
|
|
2017-03-18 14:34:56 +00:00
|
|
|
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-30 18:30:40 +00:00
|
|
|
|
2017-03-21 10:05:17 +00:00
|
|
|
S.run $ S.call s remote
|
|
|
|
|
2017-04-09 12:34:09 +00:00
|
|
|
Nothing ->
|
2017-03-30 18:30:40 +00:00
|
|
|
if isHelp then
|
|
|
|
servermanHelp
|
|
|
|
else
|
|
|
|
die $ "could not find any service matching " ++ service
|
|
|
|
_ -> servermanHelp
|
2017-03-13 15:37:07 +00:00
|
|
|
|
2017-03-30 18:30:40 +00:00
|
|
|
-- after the program is done, terminate remaining processes
|
2017-04-01 07:30:22 +00:00
|
|
|
-- and unmount/remove leftover temporary directories
|
2017-04-09 12:34:09 +00:00
|
|
|
state@S.AppState { S.processes, S.temps } <- get
|
2017-04-01 07:30:22 +00:00
|
|
|
put $ state { remoteMode = Nothing }
|
|
|
|
|
2017-03-30 18:30:40 +00:00
|
|
|
mapM_ (liftIO . terminateProcess) processes
|
2017-04-01 07:30:22 +00:00
|
|
|
mapM_ clearTemp temps
|
2017-02-18 19:25:57 +00:00
|
|
|
|
|
|
|
return ()
|
|
|
|
|
2017-03-13 15:37:07 +00:00
|
|
|
where
|
2017-04-01 07:30:22 +00:00
|
|
|
clearTemp path = execIfExists path $ do
|
|
|
|
execute "fusermount" ["-u", path] "" False
|
|
|
|
liftIO $ removeDirectoryRecursive path
|
2017-03-30 18:30:40 +00:00
|
|
|
-- 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
|
|
|
|
2017-03-30 18:30:40 +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
|
2017-03-18 14:34:56 +00:00
|
|
|
, rest :: [(String, Maybe String)]
|
2017-03-30 18:30:40 +00:00
|
|
|
, verboseM :: Bool
|
|
|
|
}
|
|
|
|
|
|
|
|
instance Show Params where
|
2017-04-09 12:34:09 +00:00
|
|
|
show Params { listServices, install, manage, update, remote, rest, verboseM } =
|
2017-03-30 18:30:40 +00:00
|
|
|
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 = []
|
2017-03-30 18:30:40 +00:00
|
|
|
, 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 }
|
2017-03-30 18:30:40 +00:00
|
|
|
parseParams ("--verbose":xs) = (parseParams xs) { verboseM = True }
|
2017-03-18 14:34:56 +00:00
|
|
|
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)
|
2017-03-18 14:34:56 +00:00
|
|
|
| otherwise = toPairs xs
|
|
|
|
|
|
|
|
flagName = isPrefixOf "-"
|
|
|
|
value = not . flagName
|
|
|
|
getWord = dropWhile (== '-')
|