module Hakyll.Core.Store
( Store
, makeStore
, storeSet
, storeGet
) where
import Control.Concurrent.MVar (MVar, newMVar, readMVar, modifyMVar_)
import System.FilePath ((</>))
import System.Directory (doesFileExist)
import Data.Maybe (fromMaybe)
import Data.Map (Map)
import qualified Data.Map as M
import Data.Binary (Binary, encodeFile, decodeFile)
import Data.Typeable (Typeable, cast)
import Hakyll.Core.Identifier
import Hakyll.Core.Util.File
data Storable = forall a. (Binary a, Typeable a) => Storable a
data Store = Store
{
storeDirectory :: FilePath
,
storeMap :: MVar (Map FilePath Storable)
}
makeStore :: FilePath -> IO Store
makeStore directory = do
mvar <- newMVar M.empty
return Store
{ storeDirectory = directory
, storeMap = mvar
}
addToMap :: (Binary a, Typeable a) => Store -> FilePath -> a -> IO ()
addToMap store path value =
modifyMVar_ (storeMap store) $ return . M.insert path (Storable value)
makePath :: Store -> String -> Identifier -> FilePath
makePath store name identifier = storeDirectory store </> name
</> group </> toFilePath identifier </> "hakyllstore"
where
group = fromMaybe "" $ identifierGroup identifier
storeSet :: (Binary a, Typeable a)
=> Store -> String -> Identifier -> a -> IO ()
storeSet store name identifier value = do
makeDirectories path
encodeFile path value
addToMap store path value
where
path = makePath store name identifier
storeGet :: (Binary a, Typeable a)
=> Store -> String -> Identifier -> IO (Maybe a)
storeGet store name identifier = do
map' <- readMVar $ storeMap store
case M.lookup path map' of
Just (Storable s) -> return $ cast s
Nothing -> do
exists <- doesFileExist path
if not exists
then return Nothing
else do v <- decodeFile path
addToMap store path v
return $ Just v
where
path = makePath store name identifier