on master help sign in
Rules will be in IO...
commitdac3fac342c2fb8610b6f1d83cbfd97a70cf17f1 authorJasper Van der Jeugt <m@jaspervdj.be> dateThu 8 Nov 2012, 13:50 (14 years ago) parent89f324f
5 files changed+112−78
hakyll.cabal+4−4 src/Hakyll/Core/Resource/Modified.hs+1−1 src/Hakyll/Core/Rules.hs+57−38 src/Hakyll/Core/Rules/Internal.hs+48−33 src/Hakyll/Core/Run.hs+2−2
hakyll.cabal+4−4
@@ -101,10 +101,6 @@ Library
101101 Hakyll.Core.Logger
102102 Hakyll.Core.Resource
103103 Hakyll.Core.Resource.Provider
104− Hakyll.Core.Resource.Provider.Internal
105− Hakyll.Core.Resource.Metadata
106− Hakyll.Core.Resource.MetadataCache
107− Hakyll.Core.Resource.Modified
108104 Hakyll.Core.Routes
109105 Hakyll.Core.Rules
110106 Hakyll.Core.Run
@@ -136,6 +132,10 @@ Library
136132 Other-Modules:
137133 Hakyll.Core.Compiler.Internal
138134 Hakyll.Core.DirectedGraph.Internal
135+ Hakyll.Core.Resource.Metadata
136+ Hakyll.Core.Resource.MetadataCache
137+ Hakyll.Core.Resource.Modified
138+ Hakyll.Core.Resource.Provider.Internal
139139 Hakyll.Core.Rules.Internal
140140 Hakyll.Web.Page.Internal
141141 Hakyll.Web.Template.Internal
src/Hakyll/Core/Resource/Modified.hs+1−1
@@ -42,7 +42,7 @@ resourceModified rp r
4242 <*> resourceModified rp (resourceMetadataResource r)
4343 modifyIORef cacheRef (M.insert r m)
4444
45− -- Important!
45+ -- Important! (But ugly)
4646 when m $ resourceInvalidateMetadataCache rp r
4747
4848 return m
src/Hakyll/Core/Rules.hs+57−38
@@ -1,3 +1,4 @@
1+--------------------------------------------------------------------------------
12-- | This module provides a declarative DSL in which the user can specify the
23-- different rules used to run the compilers.
34--
@@ -13,8 +14,8 @@
1314-- > match "css/*" $ do
1415-- > route idRoute
1516-- > compile compressCssCompiler
16−--
17−{-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings #-}
17+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18+{-# LANGUAGE OverloadedStrings #-}
1819module Hakyll.Core.Rules
1920 ( RulesM
2021 , Rules
@@ -29,35 +30,43 @@ module Hakyll.Core.Rules
2930 , freshIdentifier
3031 ) where
3132
32−import Control.Applicative ((<$>))
33−import Control.Monad.Writer (tell)
34−import Control.Monad.Reader (ask, local)
35−import Control.Arrow ((>>>), arr, (>>^), (***))
36−import Control.Monad.State (get, put)
37−import Data.Monoid (mempty, mappend)
38−import qualified Data.Set as S
39−
40−import Data.Typeable (Typeable)
41−import Data.Binary (Binary)
42−
43−import Hakyll.Core.Resource
44−import Hakyll.Core.Resource.Provider
45−import Hakyll.Core.Identifier
46−import Hakyll.Core.Identifier.Pattern
47−import Hakyll.Core.Compiler.Internal
48−import Hakyll.Core.Routes
49−import Hakyll.Core.CompiledItem
50−import Hakyll.Core.Writable
51−import Hakyll.Core.Rules.Internal
52−import Hakyll.Core.Util.Arrow
5333
34+--------------------------------------------------------------------------------
35+import Control.Applicative ((<$>))
36+import Control.Arrow (arr, (***), (>>>), (>>^))
37+import Control.Monad.Reader (ask, local)
38+import Control.Monad.State (get, put)
39+import Control.Monad.Writer (tell)
40+import Data.Monoid (mappend, mempty)
41+import qualified Data.Set as S
42+
43+
44+--------------------------------------------------------------------------------
45+import Data.Binary (Binary)
46+import Data.Typeable (Typeable)
47+
48+
49+--------------------------------------------------------------------------------
50+import Hakyll.Core.CompiledItem
51+import Hakyll.Core.Compiler.Internal
52+import Hakyll.Core.Identifier
53+import Hakyll.Core.Identifier.Pattern
54+import Hakyll.Core.Resource
55+import Hakyll.Core.Resource.Provider
56+import Hakyll.Core.Routes
57+import Hakyll.Core.Rules.Internal
58+import Hakyll.Core.Util.Arrow
59+import Hakyll.Core.Writable
60+
61+
62+--------------------------------------------------------------------------------
5463-- | Add a route
55−--
5664tellRoute :: Routes -> Rules
5765tellRoute route' = RulesM $ tell $ RuleSet route' mempty mempty
5866
67+
68+--------------------------------------------------------------------------------
5969-- | Add a number of compilers
60−--
6170tellCompilers :: (Binary a, Typeable a, Writable a)
6271 => [(Identifier a, Compiler () a)]
6372 -> Rules
@@ -68,15 +77,17 @@ tellCompilers compilers = RulesM $ do
6877 where
6978 boxCompiler = (>>> arr compiledItem >>> arr CompileRule)
7079
80+
81+--------------------------------------------------------------------------------
7182-- | Add resources
72−--
7383tellResources :: [Resource]
7484 -> Rules
7585tellResources resources' = RulesM $ tell $
7686 RuleSet mempty mempty $ S.fromList resources'
7787
88+
89+--------------------------------------------------------------------------------
7890-- | Only compile/route items satisfying the given predicate
79−--
8091match :: Pattern a -> RulesM b -> RulesM b
8192match pattern = RulesM . local addPredicate . unRulesM
8293 where
@@ -84,8 +95,9 @@ match pattern = RulesM . local addPredicate . unRulesM
8495 { rulesPattern = rulesPattern env `mappend` castPattern pattern
8596 }
8697
98+
99+--------------------------------------------------------------------------------
87100-- | Greate a group of compilers
88−--
89101-- Imagine you have a page that you want to render, but you also want the raw
90102-- content available on your site.
91103--
@@ -114,18 +126,18 @@ match pattern = RulesM . local addPredicate . unRulesM
114126--
115127-- This will put the compiler for the raw content in a separate group
116128-- (@\"raw\"@), which causes it to be compiled as well.
117−--
118129group :: String -> RulesM a -> RulesM a
119130group g = RulesM . local setGroup' . unRulesM
120131 where
121132 setGroup' env = env { rulesGroup = Just g }
122133
134+
135+--------------------------------------------------------------------------------
123136-- | Add a compilation rule to the rules.
124137--
125138-- This instructs all resources to be compiled using the given compiler. When
126139-- no resources match the current selection, nothing will happen. In this case,
127140-- you might want to have a look at 'create'.
128−--
129141compile :: (Binary a, Typeable a, Writable a)
130142 => Compiler Resource a -> RulesM (Pattern a)
131143compile compiler = do
@@ -134,7 +146,9 @@ compile compiler = do
134146 (identifier, constA (fromIdentifier identifier) >>> compiler)
135147 tellResources $ map fromIdentifier ids
136148 return $ list ids
137−
149+
150+
151+--------------------------------------------------------------------------------
138152-- | Add a compilation rule
139153--
140154-- This sets a compiler for the given identifier. No resource is needed, since
@@ -143,7 +157,6 @@ compile compiler = do
143157-- actual content itself. Note that the group of the given identifier is
144158-- replaced by the group set via 'group' (or 'Nothing', if 'group' has not been
145159-- used).
146−--
147160create :: (Binary a, Typeable a, Writable a)
148161 => Identifier a -> Compiler () a -> RulesM (Identifier a)
149162create id' compiler = RulesM $ do
@@ -152,10 +165,11 @@ create id' compiler = RulesM $ do
152165 unRulesM $ tellCompilers [(id'', compiler)]
153166 return id''
154167
168+
169+--------------------------------------------------------------------------------
155170-- | Add a route.
156171--
157172-- This adds a route for all items matching the current pattern.
158−--
159173route :: Routes -> Rules
160174route route' = RulesM $ do
161175 -- We want the route only to be applied if we match the current pattern and
@@ -164,9 +178,10 @@ route route' = RulesM $ do
164178 group' <- rulesGroup <$> ask
165179 unRulesM $ tellRoute $ matchRoute (pattern `mappend` inGroup group') route'
166180
181+
182+--------------------------------------------------------------------------------
167183-- | Get a list of resources matching the current pattern. This will also set
168184-- the correct group to the identifiers.
169−--
170185resources :: RulesM [Identifier a]
171186resources = RulesM $ do
172187 pattern <- rulesPattern <$> ask
@@ -176,6 +191,8 @@ resources = RulesM $ do
176191 where
177192 toId g = setGroup g . toIdentifier
178193
194+
195+--------------------------------------------------------------------------------
179196-- | Apart from regular compilers, one is also able to specify metacompilers.
180197-- Metacompilers are a special class of compilers: they are compilers which
181198-- produce other compilers.
@@ -205,9 +222,8 @@ resources = RulesM $ do
205222-- For simple hakyll systems, it is no need for this construction. More
206223-- formally, it is only needed when the content of one or more items determines
207224-- which items must be rendered.
208−--
209225metaCompile :: (Binary a, Typeable a, Writable a)
210− => Compiler () [(Identifier a, Compiler () a)]
226+ => Compiler () [(Identifier a, Compiler () a)]
211227 -- ^ Compiler generating the other compilers
212228 -> Rules
213229 -- ^ Resulting rules
@@ -215,13 +231,14 @@ metaCompile compiler = do
215231 id' <- freshIdentifier "Hakyll.Core.Rules.metaCompile"
216232 metaCompileWith id' compiler
217233
234+
235+--------------------------------------------------------------------------------
218236-- | Version of 'metaCompile' that allows you to specify a custom identifier for
219237-- the metacompiler.
220−--
221238metaCompileWith :: (Binary a, Typeable a, Writable a)
222239 => Identifier ()
223240 -- ^ Identifier for this compiler
224− -> Compiler () [(Identifier a, Compiler () a)]
241+ -> Compiler () [(Identifier a, Compiler () a)]
225242 -- ^ Compiler generating the other compilers
226243 -> Rules
227244 -- ^ Resulting rules
@@ -239,6 +256,8 @@ metaCompileWith identifier compiler = RulesM $ do
239256
240257 tell $ RuleSet mempty compilers mempty
241258
259+
260+--------------------------------------------------------------------------------
242261-- | Generate a fresh Identifier with a given prefix
243262freshIdentifier :: String -- ^ Prefix
244263 -> RulesM (Identifier a) -- ^ Fresh identifier
src/Hakyll/Core/Rules/Internal.hs+48−33
@@ -1,6 +1,7 @@
1+--------------------------------------------------------------------------------
12-- | Internal rules module for types which are not exposed to the user
2−--
3−{-# LANGUAGE GeneralizedNewtypeDeriving, Rank2Types #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE Rank2Types #-}
45module Hakyll.Core.Rules.Internal
56 ( CompileRule (..)
67 , RuleSet (..)
@@ -11,34 +12,38 @@ module Hakyll.Core.Rules.Internal
1112 , runRules
1213 ) where
1314
14−import Control.Applicative (Applicative)
15−import Control.Monad.Writer (WriterT, execWriterT)
16−import Control.Monad.Reader (ReaderT, runReaderT)
17−import Control.Monad.State (State, evalState)
18−import Data.Monoid (Monoid, mempty, mappend)
19−import Data.Set (Set)
20−import qualified Data.Map as M
21−
22−import Hakyll.Core.Resource
23−import Hakyll.Core.Resource.Provider
24−import Hakyll.Core.Identifier
25−import Hakyll.Core.Identifier.Pattern
26−import Hakyll.Core.Compiler.Internal
27−import Hakyll.Core.Routes
28−import Hakyll.Core.CompiledItem
2915
16+--------------------------------------------------------------------------------
17+import Control.Applicative (Applicative)
18+import Control.Monad.RWS (RWST, runRWST)
19+import qualified Data.Map as M
20+import Data.Monoid (Monoid, mappend, mempty)
21+import Data.Set (Set)
22+
23+
24+--------------------------------------------------------------------------------
25+import Hakyll.Core.CompiledItem
26+import Hakyll.Core.Compiler.Internal
27+import Hakyll.Core.Identifier
28+import Hakyll.Core.Identifier.Pattern
29+import Hakyll.Core.Resource
30+import Hakyll.Core.Resource.Provider
31+import Hakyll.Core.Routes
32+
33+
34+--------------------------------------------------------------------------------
3035-- | Output of a compiler rule
3136--
3237-- * The compiler will produce a simple item. This is the most common case.
3338--
3439-- * The compiler will produce more compilers. These new compilers need to be
3540-- added to the runtime if possible, since other items might depend upon them.
36−--
3741data CompileRule = CompileRule CompiledItem
3842 | MetaCompileRule [(Identifier (), Compiler () CompileRule)]
3943
44+
45+--------------------------------------------------------------------------------
4046-- | A collection of rules for the compilation process
41−--
4247data RuleSet = RuleSet
4348 { -- | Routes used in the compilation structure
4449 rulesRoutes :: Routes
@@ -48,51 +53,61 @@ data RuleSet = RuleSet
4853 rulesResources :: Set Resource
4954 }
5055
56+
57+--------------------------------------------------------------------------------
5158instance Monoid RuleSet where
5259 mempty = RuleSet mempty mempty mempty
5360 mappend (RuleSet r1 c1 s1) (RuleSet r2 c2 s2) =
5461 RuleSet (mappend r1 r2) (mappend c1 c2) (mappend s1 s2)
5562
63+
64+--------------------------------------------------------------------------------
5665-- | Rule state
57−--
5866data RuleState = RuleState
5967 { rulesNextIdentifier :: Int
6068 } deriving (Show)
6169
70+
71+--------------------------------------------------------------------------------
6272-- | Rule environment
63−--
6473data RuleEnvironment = RuleEnvironment
6574 { rulesResourceProvider :: ResourceProvider
6675 , rulesPattern :: forall a. Pattern a
6776 , rulesGroup :: Maybe String
6877 }
6978
79+
80+--------------------------------------------------------------------------------
7081-- | The monad used to compose rules
71−--
7282newtype RulesM a = RulesM
73− { unRulesM :: ReaderT RuleEnvironment (WriterT RuleSet (State RuleState)) a
83+ { unRulesM :: RWST RuleEnvironment RuleSet RuleState IO a
7484 } deriving (Monad, Functor, Applicative)
7585
86+
87+--------------------------------------------------------------------------------
7688-- | Simplification of the RulesM type; usually, it will not return any
7789-- result.
78−--
7990type Rules = RulesM ()
8091
92+
93+--------------------------------------------------------------------------------
8194-- | Run a Rules monad, resulting in a 'RuleSet'
82−--
83−runRules :: RulesM a -> ResourceProvider -> RuleSet
84−runRules rules provider = nubCompilers $
85− evalState (execWriterT $ runReaderT (unRulesM rules) env) state
95+runRules :: RulesM a -> ResourceProvider -> IO RuleSet
96+runRules rules provider = do
97+ (_, _, ruleSet) <- runRWST (unRulesM rules) env state
98+ return $ nubCompilers ruleSet
8699 where
87100 state = RuleState {rulesNextIdentifier = 0}
88− env = RuleEnvironment { rulesResourceProvider = provider
89− , rulesPattern = mempty
90− , rulesGroup = Nothing
91− }
101+ env = RuleEnvironment
102+ { rulesResourceProvider = provider
103+ , rulesPattern = mempty
104+ , rulesGroup = Nothing
105+ }
92106
107+
108+--------------------------------------------------------------------------------
93109-- | Remove duplicate compilers from the 'RuleSet'. When two compilers match an
94110-- item, we prefer the first one
95−--
96111nubCompilers :: RuleSet -> RuleSet
97112nubCompilers set = set { rulesCompilers = nubCompilers' (rulesCompilers set) }
98113 where
src/Hakyll/Core/Run.hs+2−2
@@ -52,8 +52,8 @@ run configuration rules = do
5252 let (firstRun, oldGraph) = case graph of Store.Found g -> (False, g)
5353 _ -> (True, mempty)
5454
55− let ruleSet = runRules rules provider
56− compilers = rulesCompilers ruleSet
55+ ruleSet <- timed logger "Running rules" $ runRules rules provider
56+ let compilers = rulesCompilers ruleSet
5757
5858 -- Extract the reader/state
5959 reader = unRuntime $ addNewCompilers compilers