hakyll/src/Hakyll/Core/Resource/Provider.hs

126 lines
4.9 KiB
Haskell
Raw Normal View History

2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
2010-12-24 07:42:05 +00:00
-- | This module provides an API for resource providers. Resource providers
-- allow Hakyll to get content from resources; the type of resource depends on
-- the concrete instance.
--
-- A resource is represented by the 'Resource' type. This is basically just a
-- newtype wrapper around 'Identifier' -- but it has an important effect: it
-- guarantees that a resource with this identifier can be provided by one or
-- more resource providers.
--
-- Therefore, it is not recommended to read files directly -- you should use the
-- provided 'Resource' methods.
--
2011-04-05 20:14:49 +00:00
module Hakyll.Core.Resource.Provider
( ResourceProvider (..)
, resourceList
2011-04-12 09:43:12 +00:00
, makeResourceProvider
2010-12-31 12:28:31 +00:00
, resourceExists
2010-12-26 15:22:05 +00:00
, resourceDigest
, resourceModified
2010-12-24 07:42:05 +00:00
) where
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
2011-04-12 09:43:12 +00:00
import Control.Applicative ((<$>))
import Control.Concurrent (MVar, readMVar, modifyMVar_, newMVar)
import Data.Map (Map)
import qualified Data.Map as M
import qualified Data.Set as S
2010-12-24 07:42:05 +00:00
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
import Data.Time (UTCTime)
2011-08-27 10:16:03 +00:00
import qualified Crypto.Hash.MD5 as MD5
import qualified Data.ByteString as B
2010-12-26 15:12:24 +00:00
import qualified Data.ByteString.Lazy as LB
2010-12-26 15:22:05 +00:00
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
import Hakyll.Core.Store (Store)
2011-04-05 20:14:49 +00:00
import Hakyll.Core.Resource
2012-10-29 14:01:58 +00:00
import qualified Hakyll.Core.Store as Store
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
2010-12-24 07:42:05 +00:00
-- | A value responsible for retrieving and listing resources
data ResourceProvider = ResourceProvider
2012-08-08 00:37:23 +00:00
{ -- | A set of all resources this provider is able to provide
resourceSet :: S.Set Resource
2010-12-24 07:42:05 +00:00
, -- | Retrieve a certain resource as string
resourceString :: Resource -> IO String
2010-12-26 15:12:24 +00:00
, -- | Retrieve a certain resource as lazy bytestring
resourceLBS :: Resource -> IO LB.ByteString
, -- | Check when a resource was last modified
resourceModificationTime :: Resource -> IO UTCTime
, -- | Cache keeping track of modified items
resourceModifiedCache :: MVar (Map Resource Bool)
2010-12-24 07:42:05 +00:00
}
2010-12-26 15:22:05 +00:00
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
2011-04-12 09:43:12 +00:00
-- | Create a resource provider
makeResourceProvider :: [Resource] -- ^ Resource list
-> (Resource -> IO String) -- ^ String reader
-> (Resource -> IO LB.ByteString) -- ^ ByteString reader
-> (Resource -> IO UTCTime) -- ^ Time checker
2011-04-12 09:43:12 +00:00
-> IO ResourceProvider -- ^ Resulting provider
2012-08-08 00:37:23 +00:00
makeResourceProvider l s b t =
ResourceProvider (S.fromList l) s b t <$> newMVar M.empty
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
-- | Get the list of all resources
resourceList :: ResourceProvider -> [Resource]
resourceList = S.toList . resourceSet
2011-04-12 09:43:12 +00:00
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
-- | Check if a given identifier has a resource
resourceExists :: ResourceProvider -> Resource -> Bool
resourceExists provider = flip S.member $ resourceSet provider
2010-12-31 12:28:31 +00:00
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
2010-12-26 15:22:05 +00:00
-- | Retrieve a digest for a given resource
2011-08-27 10:16:03 +00:00
resourceDigest :: ResourceProvider -> Resource -> IO B.ByteString
resourceDigest provider = fmap MD5.hashlazy . resourceLBS provider
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
-- | Check if a resource was modified
2011-04-06 12:40:36 +00:00
resourceModified :: ResourceProvider -> Store -> Resource -> IO Bool
resourceModified provider store r = do
cache <- readMVar mvar
case M.lookup r cache of
-- Already in the cache
Just m -> return m
-- Not yet in the cache, check digests (if it exists)
Nothing -> do
m <- if resourceExists provider r
then digestModified provider store r
else return False
modifyMVar_ mvar (return . M.insert r m)
return m
where
mvar = resourceModifiedCache provider
2012-10-29 14:01:58 +00:00
--------------------------------------------------------------------------------
-- | Check if a resource digest was modified
2011-04-06 12:40:36 +00:00
digestModified :: ResourceProvider -> Store -> Resource -> IO Bool
digestModified provider store r = do
-- Get the latest seen digest from the store
2012-10-29 14:01:58 +00:00
lastDigest <- Store.get store key
-- Calculate the digest for the resource
newDigest <- resourceDigest provider r
-- Check digests
2012-10-29 14:01:58 +00:00
if Store.Found newDigest == lastDigest
-- All is fine, not modified
then return False
-- Resource modified; store new digest
2012-10-29 14:01:58 +00:00
else do Store.set store key newDigest
return True
where
2012-10-29 14:01:58 +00:00
key = ["Hakyll.Core.ResourceProvider.digestModified", unResource r]