on master help sign in
Pick Store from the develop branch
e5c97d9Jasper Van der Jeugt
src/Hakyll/Core/Compiler.hs+14−13
@@ -60,7 +60,7 @@
60-- Let's look at it in detail:
60-- Let's look at it in detail:
61--
61--
62-- > (Binary a, Typeable a, Writable a)
62-- > (Binary a, Typeable a, Writable a)
63−--
63+--
64-- These are constraints for the @a@ type. @a@ (the template) needs to have
64-- These are constraints for the @a@ type. @a@ (the template) needs to have
65-- certain properties for it to be required.
65-- certain properties for it to be required.
66--
66--
@@ -138,10 +138,11 @@ import Hakyll.Core.Writable
138import Hakyll.Core.Resource
138import Hakyll.Core.Resource
139import Hakyll.Core.Resource.Provider
139import Hakyll.Core.Resource.Provider
140import Hakyll.Core.Compiler.Internal
140import Hakyll.Core.Compiler.Internal
141−import Hakyll.Core.Store
141+import Hakyll.Core.Store (Store)
142import Hakyll.Core.Rules.Internal
142import Hakyll.Core.Rules.Internal
143import Hakyll.Core.Routes
143import Hakyll.Core.Routes
144import Hakyll.Core.Logger
144import Hakyll.Core.Logger
145+import qualified Hakyll.Core.Store as Store
145
146
146-- | Run a compiler, yielding the resulting target and it's dependencies. This
147-- | Run a compiler, yielding the resulting target and it's dependencies. This
147-- version of 'runCompilerJob' also stores the result
148-- version of 'runCompilerJob' also stores the result
@@ -167,8 +168,7 @@ runCompiler compiler id' provider universe routes store modified logger = do
167 -- before we return control. This makes sure the compiled item can later
168 -- before we return control. This makes sure the compiled item can later
168 -- be accessed by e.g. require.
169 -- be accessed by e.g. require.
169 Right (CompileRule (CompiledItem x)) ->
170 Right (CompileRule (CompiledItem x)) ->
170− storeSet store "Hakyll.Core.Compiler.runCompiler"
171+ Store.set store ["Hakyll.Core.Compiler.runCompiler", show id'] x
171− (castIdentifier id') x
172
172
173 -- Otherwise, we do nothing here
173 -- Otherwise, we do nothing here
174 _ -> return ()
174 _ -> return ()
@@ -227,12 +227,13 @@ getResourceWith reader = fromJob $ \r -> CompilerM $ do
227getDependency :: (Binary a, Writable a, Typeable a)
227getDependency :: (Binary a, Writable a, Typeable a)
228 => Identifier a -> CompilerM a
228 => Identifier a -> CompilerM a
229getDependency id' = CompilerM $ do
229getDependency id' = CompilerM $ do
230− store <- compilerStore <$> ask
230+ store <- compilerStore <$> ask
231+ result <- liftIO $
231− result <- liftIO $ storeGet store "Hakyll.Core.Compiler.runCompiler" id'
232+ Store.get store ["Hakyll.Core.Compiler.runCompiler", show id']
232 case result of
233 case result of
233− NotFound -> throwError notFound
234+ Store.NotFound -> throwError notFound
234− WrongType e r -> throwError $ wrongType e r
235+ Store.WrongType e r -> throwError $ wrongType e r
235− Found x -> return x
236+ Store.Found x -> return x
236 where
237 where
237 notFound =
238 notFound =
238 "Hakyll.Core.Compiler.getDependency: " ++ show id' ++ " was " ++
239 "Hakyll.Core.Compiler.getDependency: " ++ show id' ++ " was " ++
@@ -310,11 +311,11 @@ cached name (Compiler d j) = Compiler d $ const $ CompilerM $ do
310 report logger $ "Checking cache: " ++ if modified then "modified" else "OK"
311 report logger $ "Checking cache: " ++ if modified then "modified" else "OK"
311 if modified
312 if modified
312 then do v <- unCompilerM $ j $ fromIdentifier identifier
313 then do v <- unCompilerM $ j $ fromIdentifier identifier
313− liftIO $ storeSet store name identifier v
314+ liftIO $ Store.set store [name, show identifier] v
314 return v
315 return v
315− else do v <- liftIO $ storeGet store name identifier
316+ else do v <- liftIO $ Store.get store [name, show identifier]
316− case v of Found v' -> return v'
317+ case v of Store.Found v' -> return v'
317− _ -> throwError (error' progName)
318+ _ -> throwError (error' progName)
318 where
319 where
319 error' progName =
320 error' progName =
320 "Hakyll.Core.Compiler.cached: Cache corrupt! " ++
321 "Hakyll.Core.Compiler.cached: Cache corrupt! " ++
src/Hakyll/Core/Resource/Provider.hs+27−12
@@ -1,3 +1,4 @@
1+--------------------------------------------------------------------------------
1-- | This module provides an API for resource providers. Resource providers
2-- | This module provides an API for resource providers. Resource providers
2-- allow Hakyll to get content from resources; the type of resource depends on
3-- allow Hakyll to get content from resources; the type of resource depends on
3-- the concrete instance.
4-- the concrete instance.
@@ -19,22 +20,30 @@ module Hakyll.Core.Resource.Provider
19 , resourceModified
20 , resourceModified
20 ) where
21 ) where
21
22
23+
24+--------------------------------------------------------------------------------
22import Control.Applicative ((<$>))
25import Control.Applicative ((<$>))
23import Control.Concurrent (MVar, readMVar, modifyMVar_, newMVar)
26import Control.Concurrent (MVar, readMVar, modifyMVar_, newMVar)
24import Data.Map (Map)
27import Data.Map (Map)
25import qualified Data.Map as M
28import qualified Data.Map as M
26import qualified Data.Set as S
29import qualified Data.Set as S
27
30
31+
32+--------------------------------------------------------------------------------
28import Data.Time (UTCTime)
33import Data.Time (UTCTime)
29import qualified Crypto.Hash.MD5 as MD5
34import qualified Crypto.Hash.MD5 as MD5
30import qualified Data.ByteString as B
35import qualified Data.ByteString as B
31import qualified Data.ByteString.Lazy as LB
36import qualified Data.ByteString.Lazy as LB
32
37
38+
39+--------------------------------------------------------------------------------
33−import Hakyll.Core.Store
40+import Hakyll.Core.Store (Store)
34import Hakyll.Core.Resource
41import Hakyll.Core.Resource
42+import qualified Hakyll.Core.Store as Store
43+
35
44
45+--------------------------------------------------------------------------------
36-- | A value responsible for retrieving and listing resources
46-- | A value responsible for retrieving and listing resources
37−--
38data ResourceProvider = ResourceProvider
47data ResourceProvider = ResourceProvider
39 { -- | A set of all resources this provider is able to provide
48 { -- | A set of all resources this provider is able to provide
40 resourceSet :: S.Set Resource
49 resourceSet :: S.Set Resource
@@ -48,8 +57,9 @@ data ResourceProvider = ResourceProvider
48 resourceModifiedCache :: MVar (Map Resource Bool)
57 resourceModifiedCache :: MVar (Map Resource Bool)
49 }
58 }
50
59
60+
61+--------------------------------------------------------------------------------
51-- | Create a resource provider
62-- | Create a resource provider
52−--
53makeResourceProvider :: [Resource] -- ^ Resource list
63makeResourceProvider :: [Resource] -- ^ Resource list
54 -> (Resource -> IO String) -- ^ String reader
64 -> (Resource -> IO String) -- ^ String reader
55 -> (Resource -> IO LB.ByteString) -- ^ ByteString reader
65 -> (Resource -> IO LB.ByteString) -- ^ ByteString reader
@@ -58,22 +68,27 @@ makeResourceProvider :: [Resource] -- ^ Resource list
58makeResourceProvider l s b t =
68makeResourceProvider l s b t =
59 ResourceProvider (S.fromList l) s b t <$> newMVar M.empty
69 ResourceProvider (S.fromList l) s b t <$> newMVar M.empty
60
70
71+
72+--------------------------------------------------------------------------------
61-- | Get the list of all resources
73-- | Get the list of all resources
62resourceList :: ResourceProvider -> [Resource]
74resourceList :: ResourceProvider -> [Resource]
63resourceList = S.toList . resourceSet
75resourceList = S.toList . resourceSet
64
76
77+
78+--------------------------------------------------------------------------------
65-- | Check if a given identifier has a resource
79-- | Check if a given identifier has a resource
66−--
67resourceExists :: ResourceProvider -> Resource -> Bool
80resourceExists :: ResourceProvider -> Resource -> Bool
68resourceExists provider = flip S.member $ resourceSet provider
81resourceExists provider = flip S.member $ resourceSet provider
69
82
83+
84+--------------------------------------------------------------------------------
70-- | Retrieve a digest for a given resource
85-- | Retrieve a digest for a given resource
71−--
72resourceDigest :: ResourceProvider -> Resource -> IO B.ByteString
86resourceDigest :: ResourceProvider -> Resource -> IO B.ByteString
73resourceDigest provider = fmap MD5.hashlazy . resourceLBS provider
87resourceDigest provider = fmap MD5.hashlazy . resourceLBS provider
74
88
89+
90+--------------------------------------------------------------------------------
75-- | Check if a resource was modified
91-- | Check if a resource was modified
76−--
77resourceModified :: ResourceProvider -> Store -> Resource -> IO Bool
92resourceModified :: ResourceProvider -> Store -> Resource -> IO Bool
78resourceModified provider store r = do
93resourceModified provider store r = do
79 cache <- readMVar mvar
94 cache <- readMVar mvar
@@ -90,21 +105,21 @@ resourceModified provider store r = do
90 where
105 where
91 mvar = resourceModifiedCache provider
106 mvar = resourceModifiedCache provider
92
107
108+
109+--------------------------------------------------------------------------------
93-- | Check if a resource digest was modified
110-- | Check if a resource digest was modified
94−--
95digestModified :: ResourceProvider -> Store -> Resource -> IO Bool
111digestModified :: ResourceProvider -> Store -> Resource -> IO Bool
96digestModified provider store r = do
112digestModified provider store r = do
97 -- Get the latest seen digest from the store
113 -- Get the latest seen digest from the store
98− lastDigest <- storeGet store itemName identifier
114+ lastDigest <- Store.get store key
99 -- Calculate the digest for the resource
115 -- Calculate the digest for the resource
100 newDigest <- resourceDigest provider r
116 newDigest <- resourceDigest provider r
101 -- Check digests
117 -- Check digests
102− if Found newDigest == lastDigest
118+ if Store.Found newDigest == lastDigest
103 -- All is fine, not modified
119 -- All is fine, not modified
104 then return False
120 then return False
105 -- Resource modified; store new digest
121 -- Resource modified; store new digest
106− else do storeSet store itemName identifier newDigest
122+ else do Store.set store key newDigest
107 return True
123 return True
108 where
124 where
109− identifier = toIdentifier r
110− itemName = "Hakyll.Core.ResourceProvider.digestModified"
125+ key = ["Hakyll.Core.ResourceProvider.digestModified", unResource r]
src/Hakyll/Core/Run.hs+7−6
@@ -30,9 +30,10 @@ import Hakyll.Core.Resource.Provider
30import Hakyll.Core.Resource.Provider.File
30import Hakyll.Core.Resource.Provider.File
31import Hakyll.Core.Routes
31import Hakyll.Core.Routes
32import Hakyll.Core.Rules.Internal
32import Hakyll.Core.Rules.Internal
33−import Hakyll.Core.Store
33+import Hakyll.Core.Store (Store)
34import Hakyll.Core.Util.File
34import Hakyll.Core.Util.File
35import Hakyll.Core.Writable
35import Hakyll.Core.Writable
36+import qualified Hakyll.Core.Store as Store
36
37
37-- | Run all rules needed, return the rule set used
38-- | Run all rules needed, return the rule set used
38--
39--
@@ -42,15 +43,15 @@ run configuration rules = do
42
43
43 section logger "Initialising"
44 section logger "Initialising"
44 store <- timed logger "Creating store" $
45 store <- timed logger "Creating store" $
45− makeStore (inMemoryCache configuration) $ storeDirectory configuration
46+ Store.new (inMemoryCache configuration) $ storeDirectory configuration
46 provider <- timed logger "Creating provider" $
47 provider <- timed logger "Creating provider" $
47 fileResourceProvider configuration
48 fileResourceProvider configuration
48
49
49 -- Fetch the old graph from the store. If we don't find it, we consider this
50 -- Fetch the old graph from the store. If we don't find it, we consider this
50 -- to be the first run
51 -- to be the first run
51− graph <- storeGet store "Hakyll.Core.Run.run" "dependencies"
52+ graph <- Store.get store ["Hakyll.Core.Run.run", "dependencies"]
52− let (firstRun, oldGraph) = case graph of Found g -> (False, g)
53+ let (firstRun, oldGraph) = case graph of Store.Found g -> (False, g)
53− _ -> (True, mempty)
54+ _ -> (True, mempty)
54
55
55 let ruleSet = runRules rules provider
56 let ruleSet = runRules rules provider
56 compilers = rulesCompilers ruleSet
57 compilers = rulesCompilers ruleSet
@@ -77,7 +78,7 @@ run configuration rules = do
77 thrown logger e
78 thrown logger e
78 Right ((), state') ->
79 Right ((), state') ->
79 -- We want to save the final dependency graph for the next run
80 -- We want to save the final dependency graph for the next run
80− storeSet store "Hakyll.Core.Run.run" "dependencies" $
81+ Store.set store ["Hakyll.Core.Run.run", "dependencies"] $
81 analyzerGraph $ hakyllAnalyzer state'
82 analyzerGraph $ hakyllAnalyzer state'
82
83
83 -- Flush and return
84 -- Flush and return
src/Hakyll/Core/Store.hs+120−87
@@ -1,111 +1,120 @@
1+--------------------------------------------------------------------------------
1−-- | A store for stroing and retreiving items
2+-- | A store for storing and retreiving items
2−--
3−{-# LANGUAGE ExistentialQuantification, ScopedTypeVariables #-}
3+{-# LANGUAGE ExistentialQuantification #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
4module Hakyll.Core.Store
5module Hakyll.Core.Store
5 ( Store
6 ( Store
6− , StoreGet (..)
7+ , Result (..)
7− , makeStore
8+ , new
8− , storeSet
9+ , set
9− , storeGet
10+ , get
11+ , delete
10 ) where
12 ) where
11
13
12−import Control.Applicative ((<$>))
13−import System.FilePath ((</>))
14−import System.Directory (doesFileExist)
15−import Data.Maybe (fromMaybe)
16
14
15+--------------------------------------------------------------------------------
16+import Control.Applicative ((<$>))
17+import Control.Exception (IOException, handle)
18+import qualified Crypto.Hash.MD5 as MD5
17−import Data.Binary (Binary, encodeFile, decodeFile)
19+import Data.Binary (Binary, decodeFile, encodeFile)
18−import Data.Typeable (Typeable, TypeRep, cast, typeOf)
20+import qualified Data.ByteString as B
21+import qualified Data.Cache.LRU.IO as Lru
22+import Data.List (intercalate)
23+import qualified Data.Text as T
24+import qualified Data.Text.Encoding as T
25+import Data.Typeable (TypeRep, Typeable, cast, typeOf)
26+import System.Directory (createDirectoryIfMissing)
27+import System.Directory (doesFileExist, removeFile)
28+import System.FilePath ((</>))
29+import Text.Printf (printf)
19
30
20−import Hakyll.Core.Identifier
21−import Hakyll.Core.Util.File
22−import qualified Data.Cache.LRU.IO as LRU
23
31
24−-- | Items we can store
32+--------------------------------------------------------------------------------
25−--
33+-- | Simple wrapper type
26−data Storable = forall a. (Binary a, Typeable a) => Storable a
34+data Box = forall a. Typeable a => Box a
27
35
28−-- | Result when an item from the store
29−--
30−data StoreGet a = Found a
31− | NotFound
32− | WrongType TypeRep TypeRep
33− deriving (Show, Eq)
34
36
35−-- | Data structure used for the store
37+--------------------------------------------------------------------------------
36−--
37data Store = Store
38data Store = Store
38 { -- | All items are stored on the filesystem
39 { -- | All items are stored on the filesystem
39 storeDirectory :: FilePath
40 storeDirectory :: FilePath
40− , -- | And some items are also kept in-memory
41+ , -- | Optionally, items are also kept in-memory
41− storeLRU :: Maybe (LRU.AtomicLRU FilePath Storable)
42+ storeMap :: Maybe (Lru.AtomicLRU FilePath Box)
42 }
43 }
43
44
44−-- | The size of the in-memory cache to use in items.
45−storeLRUSize :: Maybe Integer
46−storeLRUSize = Just 500
47
45
46+--------------------------------------------------------------------------------
47+-- | Result of a store query
48+data Result a
49+ = Found a -- ^ Found, result
50+ | NotFound -- ^ Not found
51+ | WrongType TypeRep TypeRep -- ^ Expected, true type
52+ deriving (Show, Eq)
53+
54+
55+--------------------------------------------------------------------------------
48-- | Initialize the store
56-- | Initialize the store
49−--
50−makeStore :: Bool -- ^ Use in-memory caching
57+new :: Bool -- ^ Use in-memory caching
51− -> FilePath -- ^ Directory to use for hard disk storage
58+ -> FilePath -- ^ Directory to use for hard disk storage
52− -> IO Store -- ^ Store
59+ -> IO Store -- ^ Store
53−makeStore inMemory directory = do
60+new inMemory directory = do
54− lru <- if inMemory
61+ createDirectoryIfMissing True directory
55− then Just <$> LRU.newAtomicLRU storeLRUSize
56− else return Nothing
62+ ref <- if inMemory then Just <$> Lru.newAtomicLRU csize else return Nothing
57 return Store
63 return Store
58 { storeDirectory = directory
64 { storeDirectory = directory
59− , storeLRU = lru
65+ , storeMap = ref
60 }
66 }
61−
62−-- | Auxiliary: add an item to the map
63−--
64−cacheInsert :: (Binary a, Typeable a) => Store -> FilePath -> a -> IO ()
65−cacheInsert (Store _ Nothing) _ _ = return ()
66−cacheInsert (Store _ (Just lru)) path value =
67− LRU.insert path (Storable value) lru
68−
69−-- | Auxiliary: get an item from the cache
70−--
71−cacheLookup :: forall a. (Binary a, Typeable a)
72− => Store -> FilePath -> IO (StoreGet a)
73−cacheLookup (Store _ Nothing) _ = return NotFound
74−cacheLookup (Store _ (Just lru)) path = do
75− res <- LRU.lookup path lru
76− case res of
77− Nothing -> return NotFound
78− Just (Storable s) -> return $ case cast s of
79− Nothing -> WrongType (typeOf s) $ typeOf (undefined :: a)
80− Just s' -> Found s'
81−
82−-- | Create a path
83−--
84−makePath :: Store -> String -> Identifier a -> FilePath
85−makePath store name identifier = storeDirectory store </> name
86− </> group </> toFilePath identifier </> "hakyllstore"
87 where
67 where
88− group = fromMaybe "" $ identifierGroup identifier
68+ csize = Just 500
69+
70+
71+--------------------------------------------------------------------------------
72+-- | Auxiliary: add an item to the in-memory cache
73+cacheInsert :: Typeable a => Store -> String -> a -> IO ()
74+cacheInsert (Store _ Nothing) _ _ = return ()
75+cacheInsert (Store _ (Just lru)) key x =
76+ Lru.insert key (Box x) lru
77+
78+
79+--------------------------------------------------------------------------------
80+-- | Auxiliary: get an item from the in-memory cache
81+cacheLookup :: forall a. Typeable a => Store -> String -> IO (Result a)
82+cacheLookup (Store _ Nothing) _ = return NotFound
83+cacheLookup (Store _ (Just lru)) key = do
84+ res <- Lru.lookup key lru
85+ return $ case res of
86+ Nothing -> NotFound
87+ Just (Box x) -> case cast x of
88+ Just x' -> Found x'
89+ Nothing -> WrongType (typeOf (undefined :: a)) (typeOf x)
90+
91+
92+--------------------------------------------------------------------------------
93+-- | Auxiliary: delete an item from the in-memory cache
94+cacheDelete :: Store -> String -> IO ()
95+cacheDelete (Store _ Nothing) _ = return ()
96+cacheDelete (Store _ (Just lru)) key = do
97+ _ <- Lru.delete key lru
98+ return ()
89
99
100+
101+--------------------------------------------------------------------------------
90-- | Store an item
102-- | Store an item
91−--
92−storeSet :: (Binary a, Typeable a)
103+set :: (Binary a, Typeable a) => Store -> [String] -> a -> IO ()
93− => Store -> String -> Identifier a -> a -> IO ()
94−storeSet store name identifier value = do
104+set store identifier value = do
95− makeDirectories path
96− encodeFile path value
105+ encodeFile (storeDirectory store </> key) value
97− cacheInsert store path value
106+ cacheInsert store key value
98 where
107 where
99− path = makePath store name identifier
108+ key = hash identifier
109+
100
110
111+--------------------------------------------------------------------------------
101-- | Load an item
112-- | Load an item
102−--
103−storeGet :: (Binary a, Typeable a)
113+get :: (Binary a, Typeable a) => Store -> [String] -> IO (Result a)
104− => Store -> String -> Identifier a -> IO (StoreGet a)
105−storeGet store name identifier = do
114+get store identifier = do
106 -- First check the in-memory map
115 -- First check the in-memory map
107− mv <- cacheLookup store path
116+ ref <- cacheLookup store key
108− case mv of
117+ case ref of
109 -- Not found in the map, try the filesystem
118 -- Not found in the map, try the filesystem
110 NotFound -> do
119 NotFound -> do
111 exists <- doesFileExist path
120 exists <- doesFileExist path
@@ -113,10 +122,34 @@ storeGet store name identifier = do
113 -- Not found in the filesystem either
122 -- Not found in the filesystem either
114 then return NotFound
123 then return NotFound
115 -- Found in the filesystem
124 -- Found in the filesystem
125+ else do
116− else do v <- decodeFile path
126+ v <- decodeFile path
117− cacheInsert store path v
127+ cacheInsert store key v
118− return $ Found v
128+ return $ Found v
119− -- Found in the in-memory map, just return
129+ -- Found in the in-memory map (or wrong type), just return
120 s -> return s
130 s -> return s
121 where
131 where
132+ key = hash identifier
133+ path = storeDirectory store </> key
134+
135+
136+--------------------------------------------------------------------------------
137+-- | Delete an item
138+delete :: Store -> [String] -> IO ()
139+delete store identifier = do
140+ cacheDelete store key
141+ deleteFile $ storeDirectory store </> key
142+ where
122− path = makePath store name identifier
143+ key = hash identifier
144+
145+
146+--------------------------------------------------------------------------------
147+hash :: [String] -> String
148+hash = concatMap (printf "%02x") . B.unpack .
149+ MD5.hash . T.encodeUtf8 . T.pack . intercalate "/"
150+
151+
152+--------------------------------------------------------------------------------
153+-- | Delete a file unless it doesn't exist...
154+deleteFile :: FilePath -> IO ()
155+deleteFile = handle (\(_ :: IOException) -> return ()) . removeFile
tests/Hakyll/Core/Store/Tests.hs+41−40
@@ -1,67 +1,68 @@
1+--------------------------------------------------------------------------------
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
2module Hakyll.Core.Store.Tests
3module Hakyll.Core.Store.Tests
3 ( tests
4 ( tests
4 ) where
5 ) where
5
6
6−import Control.Applicative ((<$>))
7−import Control.Monad (replicateM)
8
7
8+--------------------------------------------------------------------------------
9+import Data.Typeable (typeOf)
10+import Test.Framework
9−import Test.Framework
11+import Test.Framework.Providers.HUnit
10−import Test.Framework.Providers.QuickCheck2
12+import Test.Framework.Providers.QuickCheck2
11−import Test.Framework.Providers.HUnit
12−import Test.QuickCheck
13−import Test.QuickCheck.Monadic
14−import qualified Test.HUnit as H
13+import qualified Test.HUnit as H
14+import Test.QuickCheck
15+import Test.QuickCheck.Monadic
15
16
16−import Hakyll.Core.Identifier
17−import Hakyll.Core.Store
18−import TestSuite.Util
19
17
18+--------------------------------------------------------------------------------
19+import qualified Hakyll.Core.Store as Store
20+import TestSuite.Util
21+
22+
23+--------------------------------------------------------------------------------
20tests :: [Test]
24tests :: [Test]
21tests =
25tests =
22− [ testProperty "simple storeGet . storeSet" simpleSetGet
26+ [ testProperty "simple get . set" simpleSetGet
23− , testProperty "persistent storeGet . storeSet" persistentSetGet
27+ , testProperty "persistent get . set" persistentSetGet
24− , testCase "WrongType storeGet . storeSet" wrongType
28+ , testCase "WrongType get . set" wrongType
25 ]
29 ]
26
30
31+
32+--------------------------------------------------------------------------------
27simpleSetGet :: Property
33simpleSetGet :: Property
28simpleSetGet = monadicIO $ do
34simpleSetGet = monadicIO $ do
29− identifier <- parseIdentifier . unFileName <$> pick arbitrary
30− FileName name <- pick arbitrary
35+ key <- pick arbitrary
31 value <- pick arbitrary
36 value <- pick arbitrary
32 store <- run $ makeStoreTest
37 store <- run $ makeStoreTest
33− run $ storeSet store name identifier (value :: String)
38+ run $ Store.set store key (value :: String)
34− value' <- run $ storeGet store name identifier
39+ value' <- run $ Store.get store key
35− assert $ Found value == value'
40+ assert $ Store.Found value == value'
41+
36
42
43+--------------------------------------------------------------------------------
37persistentSetGet :: Property
44persistentSetGet :: Property
38persistentSetGet = monadicIO $ do
45persistentSetGet = monadicIO $ do
39− identifier <- parseIdentifier . unFileName <$> pick arbitrary
40− FileName name <- pick arbitrary
46+ key <- pick arbitrary
41− value <- pick arbitrary
47+ value <- pick arbitrary
42 store1 <- run $ makeStoreTest
48 store1 <- run $ makeStoreTest
43− run $ storeSet store1 name identifier (value :: String)
49+ run $ Store.set store1 key (value :: String)
44 -- Now Create another store from the same dir to test persistence
50 -- Now Create another store from the same dir to test persistence
45 store2 <- run $ makeStoreTest
51 store2 <- run $ makeStoreTest
46− value' <- run $ storeGet store2 name identifier
52+ value' <- run $ Store.get store2 key
47− assert $ Found value == value'
53+ assert $ Store.Found value == value'
54+
48
55
56+--------------------------------------------------------------------------------
49wrongType :: H.Assertion
57wrongType :: H.Assertion
50wrongType = do
58wrongType = do
51 store <- makeStoreTest
59 store <- makeStoreTest
52 -- Store a string and try to fetch an int
60 -- Store a string and try to fetch an int
53− storeSet store "foo" "bar" ("qux" :: String)
61+ Store.set store ["foo", "bar"] ("qux" :: String)
54− value <- storeGet store "foo" "bar" :: IO (StoreGet Int)
62+ value <- Store.get store ["foo", "bar"] :: IO (Store.Result Int)
63+ print value
55− H.assert $ case value of WrongType _ _ -> True
64+ H.assert $ case value of
65+ Store.WrongType e t ->
66+ e == typeOf (undefined :: Int) &&
67+ t == typeOf (undefined :: String)
56− _ -> False
68+ _ -> False
57−
58−newtype FileName = FileName {unFileName :: String}
59− deriving (Show)
60−
61−instance Arbitrary FileName where
62− arbitrary = do
63− length' <- choose (5, 100)
64− str <- replicateM length' $ elements cs
65− return $ FileName str
66− where
67− cs = ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ ".- "
tests/TestSuite/Util.hs+3−2
@@ -16,7 +16,8 @@ import Hakyll.Core.Compiler.Internal
16import Hakyll.Core.Identifier
16import Hakyll.Core.Identifier
17import Hakyll.Core.Logger
17import Hakyll.Core.Logger
18import Hakyll.Core.Resource.Provider
18import Hakyll.Core.Resource.Provider
19−import Hakyll.Core.Store
19+import Hakyll.Core.Store (Store)
20+import qualified Hakyll.Core.Store as Store
20
21
21fromAssertions :: String -- ^ Name
22fromAssertions :: String -- ^ Name
22 -> [Assertion] -- ^ Cases
23 -> [Assertion] -- ^ Cases
@@ -28,7 +29,7 @@ fromAssertions name = zipWith testCase names
28-- | Create a store for testing
29-- | Create a store for testing
29--
30--
30makeStoreTest :: IO Store
31makeStoreTest :: IO Store
31−makeStoreTest = makeStore True "_store"
32+makeStoreTest = Store.new True "_store"
32
33
33-- | Testing for 'runCompilerJob'
34-- | Testing for 'runCompilerJob'
34--
35--