packages feed

craft-0.0.0.1: src/Craft/Config.hs

module Craft.Config where

import           Control.Lens
import qualified Data.ByteString.Char8 as B8

import           Craft
import qualified Craft.File            as File


data Config a
  = Config
    { _configFile :: File
    , _configs    :: a
    }


config :: ConfigFormat a => Path Abs FileP -> a -> Config a
config fp cfg =
  Config
  { _configFile = file fp & strContent .~ showConfig cfg
  , _configs    = cfg
  }


class ConfigFormat a where
  showConfig :: a -> String

  parseConfig :: Path Abs FileP -> String -> Craft a

  configFromFile :: File -> Craft (Config a)
  configFromFile f = do
    bs <- case f ^. fileContent of
            Nothing -> fileRead (f ^. path)
            Just bs -> return bs
    cfgs <- parseConfig (f^.path) (B8.unpack bs)
    return Config { _configFile = f
                  , _configs    = cfgs
                  }

  fileFromConfig :: Config a -> Craft File
  fileFromConfig cfg =
    return $ _configFile cfg & strContent .~ showConfig (_configs cfg) ++ "\n"


  {-# MINIMAL showConfig, parseConfig #-}

makeLenses ''Config


instance FileLike (Config a) where
  type FileLikePath (Config a) = Path Abs FileP
  path = configFile . filePath
  mode = configFile . fileMode
  ownerID = configFile . fileOwnerID
  groupID = configFile . fileGroupID


instance ConfigFormat a => Craftable (Config a) (Config a) where
  watchCraft cfg = do
    w <- watchCraft_ =<< fileFromConfig cfg
    return (w, cfg)


instance ConfigFormat a => Show (Config a) where
  show cfg = "Config "
          ++ "{ _configFile = " ++ show (_configFile cfg)
          ++ ", _configs = \"" ++ showConfig (_configs cfg) ++ "\""
          ++ "}"


get :: ConfigFormat a => Path Abs FileP -> Craft (Maybe (Config a))
get fp = File.getWithContent fp >>= \case
  Nothing -> return Nothing
  Just f  -> Just <$> configFromFile f