summaryrefslogtreecommitdiff
path: root/src/Hakyll/Core/Resource
diff options
context:
space:
mode:
authorJasper Van der Jeugt <jaspervdj@gmail.com>2011-04-06 14:05:29 +0200
committerJasper Van der Jeugt <jaspervdj@gmail.com>2011-04-06 14:05:29 +0200
commit80596b1f56b7d6f2d4ff64d566ae845b7c7a01f6 (patch)
treebf6b02d68833821f7b57f40edc8dd8a60543fa09 /src/Hakyll/Core/Resource
parentc3dbb0ca77f65461e60cb801b867fff18afda2be (diff)
parentce444a426ac037c2b32568d8e6325aa5762bf913 (diff)
downloadhakyll-80596b1f56b7d6f2d4ff64d566ae845b7c7a01f6.tar.gz
Merge branch 'master' into dependency-analyzer
Diffstat (limited to 'src/Hakyll/Core/Resource')
-rw-r--r--src/Hakyll/Core/Resource/Provider.hs91
-rw-r--r--src/Hakyll/Core/Resource/Provider/File.hs36
2 files changed, 127 insertions, 0 deletions
diff --git a/src/Hakyll/Core/Resource/Provider.hs b/src/Hakyll/Core/Resource/Provider.hs
new file mode 100644
index 0000000..90e93f8
--- /dev/null
+++ b/src/Hakyll/Core/Resource/Provider.hs
@@ -0,0 +1,91 @@
+-- | 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.
+--
+module Hakyll.Core.Resource.Provider
+ ( ResourceProvider (..)
+ , resourceExists
+ , resourceDigest
+ , resourceModified
+ ) where
+
+import Control.Concurrent (MVar, readMVar, modifyMVar_)
+import Control.Monad ((<=<))
+import Data.Word (Word8)
+import Data.Map (Map)
+import qualified Data.Map as M
+
+import qualified Data.ByteString.Lazy as LB
+import OpenSSL.Digest.ByteString.Lazy (digest)
+import OpenSSL.Digest (MessageDigest (MD5))
+
+import Hakyll.Core.Identifier
+import Hakyll.Core.Store
+import Hakyll.Core.Resource
+
+-- | A value responsible for retrieving and listing resources
+--
+data ResourceProvider = ResourceProvider
+ { -- | A list of all resources this provider is able to provide
+ resourceList :: [Resource]
+ , -- | Retrieve a certain resource as string
+ resourceString :: Resource -> IO String
+ , -- | Retrieve a certain resource as lazy bytestring
+ resourceLazyByteString :: Resource -> IO LB.ByteString
+ , -- | Cache keeping track of modified items
+ resourceModifiedCache :: MVar (Map Resource Bool)
+ }
+
+-- | Check if a given identifier has a resource
+--
+resourceExists :: ResourceProvider -> Identifier -> Bool
+resourceExists provider = flip elem $ map unResource $ resourceList provider
+
+-- | Retrieve a digest for a given resource
+--
+resourceDigest :: ResourceProvider -> Resource -> IO [Word8]
+resourceDigest provider = digest MD5 <=< resourceLazyByteString provider
+
+-- | Check if a resource was modified
+--
+resourceModified :: ResourceProvider -> Resource -> Store -> IO Bool
+resourceModified provider resource store = do
+ cache <- readMVar mvar
+ case M.lookup resource 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 (unResource resource)
+ then digestModified provider resource store
+ else return False
+ modifyMVar_ mvar (return . M.insert resource m)
+ return m
+ where
+ mvar = resourceModifiedCache provider
+
+-- | Check if a resource digest was modified
+--
+digestModified :: ResourceProvider -> Resource -> Store -> IO Bool
+digestModified provider resource store = do
+ -- Get the latest seen digest from the store
+ lastDigest <- storeGet store itemName $ unResource resource
+ -- Calculate the digest for the resource
+ newDigest <- resourceDigest provider resource
+ -- Check digests
+ if Just newDigest == lastDigest
+ -- All is fine, not modified
+ then return False
+ -- Resource modified; store new digest
+ else do storeSet store itemName (unResource resource) newDigest
+ return True
+ where
+ itemName = "Hakyll.Core.ResourceProvider.digestModified"
diff --git a/src/Hakyll/Core/Resource/Provider/File.hs b/src/Hakyll/Core/Resource/Provider/File.hs
new file mode 100644
index 0000000..953d61c
--- /dev/null
+++ b/src/Hakyll/Core/Resource/Provider/File.hs
@@ -0,0 +1,36 @@
+-- | A concrete 'ResourceProvider' that gets it's resources from the filesystem
+--
+module Hakyll.Core.Resource.Provider.File
+ ( fileResourceProvider
+ ) where
+
+import Control.Applicative ((<$>))
+import Control.Concurrent (newMVar)
+import qualified Data.Map as M
+
+import qualified Data.ByteString.Lazy as LB
+
+import Hakyll.Core.Resource
+import Hakyll.Core.Resource.Provider
+import Hakyll.Core.Identifier
+import Hakyll.Core.Util.File
+import Hakyll.Core.Configuration
+
+-- | Create a filesystem-based 'ResourceProvider'
+--
+fileResourceProvider :: HakyllConfiguration -> IO ResourceProvider
+fileResourceProvider configuration = do
+ -- Retrieve a list of identifiers
+ list <- map parseIdentifier . filter (not . ignoreFile configuration) <$>
+ getRecursiveContents False "."
+
+ -- MVar for the cache
+ mvar <- newMVar M.empty
+
+ -- Construct a resource provider
+ return ResourceProvider
+ { resourceList = map Resource list
+ , resourceString = readFile . toFilePath . unResource
+ , resourceLazyByteString = LB.readFile . toFilePath . unResource
+ , resourceModifiedCache = mvar
+ }