packages feed

hackport-0.2.1: Action.hs

module Action where

import Config
import Error

import Control.Monad.State
import Control.Monad.Error
import Network.URI (parseURI)
import System.IO
import System.Environment

type HPAction = ErrorT HackPortError (StateT HPState IO)

data HPState = HPState
	{ config :: Config
	, indention :: Int
	}

verbose :: HPAction a -> (String,a->String) -> HPAction a
verbose action (premsg,postmsg) = do
	echoIndent
	echo premsg
	flush
	res <- indent action
	echoLn (postmsg res)
	return res

sayNormal :: HPAction a -> (String,a->String) -> HPAction a
sayNormal action strs = do
	cfg <- getCfg
	case verbosity cfg of
		Silent -> action
		_ -> action `verbose` strs

sayDebug :: HPAction a -> (String,a->String) -> HPAction a
sayDebug action strs = do
	cfg <- getCfg
	case verbosity cfg of
		Debug -> action `verbose` strs
		_ -> action

info :: String -> HPAction ()
info str = do
	cfg <- getCfg
	case verbosity cfg of
		Silent -> return ()
		_ -> echoLn str

-- | Prints a string iff in debug output mode
whisper :: String -> HPAction ()
whisper str = do
	cfg <- getCfg
	case verbosity cfg of
		Debug -> echoLn str
		_ -> return ()

getCfg :: HPAction Config
getCfg = gets config

setOverlayPath :: Maybe String -> HPAction ()
setOverlayPath mt = modify $ \hps ->
    hps { config = (config hps) { overlayPath = mt } }

setPortagePath :: Maybe String -> HPAction ()
setPortagePath mt = modify $ \hps ->
    hps { config = (config hps) { portagePath = mt } }

lessIndent :: HPAction ()
lessIndent = modify $ \s -> s { indention = indention s - 1 }

moreIndent :: HPAction ()
moreIndent = modify $ \s -> s { indention = indention s + 1 }

echoIndent :: HPAction ()
echoIndent = do
	ind <- gets indention
	echo (replicate ind '\t')

indent :: HPAction a -> HPAction a
indent action = do
	moreIndent
	res <- action
	lessIndent
	return res

echo :: String -> HPAction ()
echo str = liftIO $ hPutStr stderr str

flush :: HPAction ()
flush = liftIO (hFlush stderr)

echoLn :: String -> HPAction ()
echoLn str = echoIndent >> echo str >> liftIO (hPutChar stderr '\n')

loadConfig :: HPAction OperationMode
loadConfig = do
	args <- liftIO getArgs
	case parseConfig args of
		Left errmsg -> throwError (ArgumentError errmsg)
		Right (opts,opmode) -> do
			cfg <- foldM optionToConfig defaultConfig opts
			modify $ \s -> s { config = cfg }
			return opmode

optionToConfig :: Config -> HackPortOptions -> HPAction Config
optionToConfig cfg opt = case opt of
	OverlayPath str -> return cfg { overlayPath = Just str }
        PortagePath str -> return cfg { portagePath = Just str }
	Server str -> case parseURI str of
		Nothing -> throwError (InvalidServer str)
		Just uri -> return cfg { server = uri }
	TempDir str -> return cfg { tmp = str }
	Verbosity str -> case parseVerbosity str of
		Nothing -> throwError (UnknownVerbosityLevel str)
		Just verb -> return cfg { verbosity=verb }
	Help -> return cfg
        RefreshCache -> return cfg { refreshCache = True }

performHPAction :: HPAction a -> IO (Either HackPortError a)
performHPAction action =
    evalStateT (runErrorT action) (HPState defaultConfig 0)