{-# LANGUAGE OverloadedStrings #-} module Keter ( keter ) where import Data.Yaml import qualified Data.HashMap.Strict as Map import qualified Data.Text as T import System.Exit import System.Process import Control.Monad import System.Directory import Data.Maybe (mapMaybe) import qualified Filesystem.Path.CurrentOS as F import qualified Filesystem as F import qualified Codec.Archive.Tar as Tar import Control.Exception import qualified Data.ByteString.Lazy as L import Codec.Compression.GZip (compress) import qualified Data.Foldable as Fold import Control.Monad.Trans.Writer (tell, execWriter) run :: String -> [String] -> IO () run a b = do ec <- rawSystem a b unless (ec == ExitSuccess) $ exitWith ec keter :: String -- ^ cabal command -> Bool -- ^ no build? -> IO () keter cabal noBuild = do ketercfg <- keterConfig mvalue <- decodeFile ketercfg value <- case mvalue of Nothing -> error "No config/keter.yaml found" Just (Object value) -> case Map.lookup "host" value of Just (String s) | "<<" `T.isPrefixOf` s -> error $ "Please set your hostname in " ++ ketercfg _ -> case Map.lookup "user-edited" value of Just (Bool False) -> error $ "Please edit your Keter config file at " ++ ketercfg _ -> return value Just _ -> error $ ketercfg ++ " is not an object" files <- getDirectoryContents "." project <- case mapMaybe (T.stripSuffix ".cabal" . T.pack) files of [x] -> return x [] -> error "No cabal file found" _ -> error "Too many cabal files found" let findExecs (Object v) = mapM_ go $ Map.toList v where go ("exec", String s) = tell [F.collapse $ "config" F. F.fromText s] go (_, v') = findExecs v' findExecs (Array v) = Fold.mapM_ findExecs v findExecs _ = return () execs = execWriter $ findExecs $ Object value unless noBuild $ do run cabal ["clean"] run cabal ["configure"] run cabal ["build"] _ <- try' $ F.removeTree "static/tmp" archive <- Tar.pack "" $ "config" : "static" : map F.encodeString execs let fp = T.unpack project ++ ".keter" L.writeFile fp $ compress $ Tar.write archive case Map.lookup "copy-to" value of Just (String s) -> case parseMaybe (.: "copy-to-port") value of Just i -> run "scp" ["-P" ++ show (i :: Int), fp, T.unpack s] Nothing -> run "scp" [fp, T.unpack s] _ -> return () where -- Test for alternative config file extension (yaml or yml). keterConfig = do let yml = "config/keter.yml" ymlExists <- doesFileExist yml return $ if ymlExists then yml else "config/keter.yaml" try' :: IO a -> IO (Either SomeException a) try' = try