on master help sign in
Remove metacompilation
commit9eda3425a3153e0f226cc0e32b38c82cc7c806ef authorJasper Van der Jeugt <m@jaspervdj.be> dateSat 10 Nov 2012, 19:56 (14 years ago) parent141e761
6 files changed+45−120
hakyll.cabal+1−1 src/Hakyll/Core/CompiledItem.hs+24−16 src/Hakyll/Core/Compiler.hs+10−11 src/Hakyll/Core/Rules.hs+3−69 src/Hakyll/Core/Rules/Internal.hs+2−14 src/Hakyll/Core/Run.hs+5−9
hakyll.cabal+1−1
@@ -90,7 +90,6 @@ Library
9090
9191 Exposed-Modules:
9292 Hakyll
93− Hakyll.Core.CompiledItem
9493 Hakyll.Core.Compiler
9594 Hakyll.Core.Configuration
9695 Hakyll.Core.DependencyAnalyzer
@@ -129,6 +128,7 @@ Library
129128 Hakyll.Web.Util.Html
130129
131130 Other-Modules:
131+ Hakyll.Core.CompiledItem
132132 Hakyll.Core.Compiler.Internal
133133 Hakyll.Core.DirectedGraph.Internal
134134 Hakyll.Core.ResourceProvider.Internal
src/Hakyll/Core/CompiledItem.hs+24−16
@@ -1,3 +1,4 @@
1+--------------------------------------------------------------------------------
12-- | A module containing a box datatype representing a compiled item. This
23-- item can be of any type, given that a few restrictions hold:
34--
@@ -6,42 +7,49 @@
67-- * we need a 'Binary' instance so we can serialize these items to the cache;
78--
89-- * we need a 'Writable' instance so the results can be saved.
9−--
10−{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-}
10+{-# LANGUAGE DeriveDataTypeable #-}
11+{-# LANGUAGE ExistentialQuantification #-}
1112module Hakyll.Core.CompiledItem
1213 ( CompiledItem (..)
1314 , compiledItem
1415 , unCompiledItem
1516 ) where
1617
17−import Data.Binary (Binary)
18−import Data.Typeable (Typeable, cast, typeOf)
19−import Data.Maybe (fromMaybe)
2018
21−import Hakyll.Core.Writable
19+--------------------------------------------------------------------------------
20+import Data.Binary (Binary)
21+import Data.Maybe (fromMaybe)
22+import Data.Typeable (Typeable, cast, typeOf)
23+
24+
25+--------------------------------------------------------------------------------
26+import Hakyll.Core.Writable
2227
28+
29+--------------------------------------------------------------------------------
2330-- | Box type for a compiled item
2431--
2532data CompiledItem = forall a. (Binary a, Typeable a, Writable a)
2633 => CompiledItem a
2734 deriving (Typeable)
2835
36+
37+--------------------------------------------------------------------------------
2938instance Writable CompiledItem where
3039 write p (CompiledItem x) = write p x
3140
41+
42+--------------------------------------------------------------------------------
3243-- | Box a value into a 'CompiledItem'
33−--
34−compiledItem :: (Binary a, Typeable a, Writable a)
35− => a
36− -> CompiledItem
44+compiledItem :: (Binary a, Typeable a, Writable a) => a -> CompiledItem
3745compiledItem = CompiledItem
3846
47+
48+--------------------------------------------------------------------------------
3949-- | Unbox a value from a 'CompiledItem'
40−--
41−unCompiledItem :: (Binary a, Typeable a, Writable a)
42− => CompiledItem
43− -> a
50+unCompiledItem :: (Binary a, Typeable a, Writable a) => CompiledItem -> a
4451unCompiledItem (CompiledItem x) = fromMaybe error' $ cast x
4552 where
46− error' = error $ "Hakyll.Core.CompiledItem.unCompiledItem: "
47− ++ "unsupported type (got " ++ show (typeOf x) ++ ")"
53+ error' = error $
54+ "Hakyll.Core.CompiledItem.unCompiledItem: " ++
55+ "unsupported type (got " ++ show (typeOf x) ++ ")"
src/Hakyll/Core/Compiler.hs+10−11
@@ -137,7 +137,6 @@ import Hakyll.Core.Writable
137137import Hakyll.Core.ResourceProvider
138138import Hakyll.Core.Compiler.Internal
139139import Hakyll.Core.Store (Store)
140−import Hakyll.Core.Rules.Internal
141140import Hakyll.Core.Routes
142141import Hakyll.Core.Logger
143142import qualified Hakyll.Core.Store as Store
@@ -145,15 +144,15 @@ import qualified Hakyll.Core.Store as Store
145144-- | Run a compiler, yielding the resulting target and it's dependencies. This
146145-- version of 'runCompilerJob' also stores the result
147146--
148−runCompiler :: Compiler () CompileRule -- ^ Compiler to run
149− -> Identifier () -- ^ Target identifier
150− -> ResourceProvider -- ^ Resource provider
151− -> [Identifier ()] -- ^ Universe
152− -> Routes -- ^ Route
153− -> Store -- ^ Store
154− -> Bool -- ^ Was the resource modified?
155− -> Logger -- ^ Logger
156− -> IO (Throwing CompileRule) -- ^ Resulting item
147+runCompiler :: Compiler () CompiledItem -- ^ Compiler to run
148+ -> Identifier () -- ^ Target identifier
149+ -> ResourceProvider -- ^ Resource provider
150+ -> [Identifier ()] -- ^ Universe
151+ -> Routes -- ^ Route
152+ -> Store -- ^ Store
153+ -> Bool -- ^ Was the resource modified?
154+ -> Logger -- ^ Logger
155+ -> IO (Throwing CompiledItem) -- ^ Resulting item
157156runCompiler compiler id' provider universe routes store modified logger = do
158157 -- Run the compiler job
159158 result <- handle (\(e :: SomeException) -> return $ Left $ show e) $
@@ -165,7 +164,7 @@ runCompiler compiler id' provider universe routes store modified logger = do
165164 -- In case we compiled an item, we will store a copy in the cache first,
166165 -- before we return control. This makes sure the compiled item can later
167166 -- be accessed by e.g. require.
168− Right (CompileRule (CompiledItem x)) ->
167+ Right (CompiledItem x) ->
169168 Store.set store ["Hakyll.Core.Compiler.runCompiler", show id'] x
170169
171170 -- Otherwise, we do nothing here
src/Hakyll/Core/Rules.hs+3−69
@@ -25,15 +25,13 @@ module Hakyll.Core.Rules
2525 , create
2626 , route
2727 , resources
28− , metaCompile
29− , metaCompileWith
3028 , freshIdentifier
3129 ) where
3230
3331
3432--------------------------------------------------------------------------------
3533import Control.Applicative ((<$>))
36−import Control.Arrow (arr, (***), (>>>), (>>^))
34+import Control.Arrow (arr, (***), (>>>))
3735import Control.Monad.Reader (ask, local)
3836import Control.Monad.State (get, put)
3937import Control.Monad.Writer (tell)
@@ -73,7 +71,7 @@ tellCompilers compilers = RulesM $ do
7371 let compilers' = map (castIdentifier *** boxCompiler) compilers
7472 tell $ RuleSet mempty compilers' mempty
7573 where
76− boxCompiler = (>>> arr compiledItem >>> arr CompileRule)
74+ boxCompiler = (>>> arr compiledItem)
7775
7876
7977--------------------------------------------------------------------------------
@@ -187,73 +185,9 @@ resources = RulesM $ do
187185 return $ filterMatches pattern $ map (setGroup g) $ resourceList provider
188186
189187
190−--------------------------------------------------------------------------------
191−-- | Apart from regular compilers, one is also able to specify metacompilers.
192−-- Metacompilers are a special class of compilers: they are compilers which
193−-- produce other compilers.
194−--
195−-- This is needed when the list of compilers depends on something we cannot know
196−-- before actually running other compilers. The most typical example is if we
197−-- have a blogpost using tags.
198−--
199−-- Every post has a collection of tags. For example,
200−--
201−-- > post1: code, haskell
202−-- > post2: code, random
203−--
204−-- Now, we want to create a list of posts for every tag. We cannot write this
205−-- down in our 'Rules' DSL directly, since we don't know what tags the different
206−-- posts will have -- we depend on information that will only be available when
207−-- we are actually compiling the pages.
208−--
209−-- The solution is simple, using 'metaCompile', we can add a compiler that will
210−-- parse the pages and produce the compilers needed for the different tag pages.
211−--
212−-- And indeed, we can see that the first argument to 'metaCompile' is a
213−-- 'Compiler' which produces a list of ('Identifier', 'Compiler') pairs. The
214−-- idea is simple: 'metaCompile' produces a list of compilers, and the
215−-- corresponding identifiers.
216−--
217−-- For simple hakyll systems, it is no need for this construction. More
218−-- formally, it is only needed when the content of one or more items determines
219−-- which items must be rendered.
220−metaCompile :: (Binary a, Typeable a, Writable a)
221− => Compiler () [(Identifier a, Compiler () a)]
222− -- ^ Compiler generating the other compilers
223− -> Rules
224− -- ^ Resulting rules
225−metaCompile compiler = do
226− id' <- freshIdentifier "Hakyll.Core.Rules.metaCompile"
227− metaCompileWith id' compiler
228−
229−
230−--------------------------------------------------------------------------------
231−-- | Version of 'metaCompile' that allows you to specify a custom identifier for
232−-- the metacompiler.
233−metaCompileWith :: (Binary a, Typeable a, Writable a)
234− => Identifier ()
235− -- ^ Identifier for this compiler
236− -> Compiler () [(Identifier a, Compiler () a)]
237− -- ^ Compiler generating the other compilers
238− -> Rules
239− -- ^ Resulting rules
240−metaCompileWith identifier compiler = RulesM $ do
241− group' <- rulesGroup <$> ask
242−
243− let -- Set the correct group on the identifier
244− id' = setGroup group' identifier
245− -- Function to box an item into a rule
246− makeRule = MetaCompileRule . map (castIdentifier *** box)
247− -- Entire boxing function
248− box = (>>> fromDependency id' >>^ CompileRule . compiledItem)
249− -- Resulting compiler list
250− compilers = [(id', compiler >>> arr makeRule )]
251−
252− tell $ RuleSet mempty compilers mempty
253−
254−
255188--------------------------------------------------------------------------------
256189-- | Generate a fresh Identifier with a given prefix
190+-- TODO: remove?
257191freshIdentifier :: String -- ^ Prefix
258192 -> RulesM (Identifier a) -- ^ Fresh identifier
259193freshIdentifier prefix = RulesM $ do
src/Hakyll/Core/Rules/Internal.hs+2−14
@@ -3,8 +3,7 @@
33{-# LANGUAGE GeneralizedNewtypeDeriving #-}
44{-# LANGUAGE Rank2Types #-}
55module Hakyll.Core.Rules.Internal
6− ( CompileRule (..)
7− , RuleSet (..)
6+ ( RuleSet (..)
87 , RuleState (..)
98 , RuleEnvironment (..)
109 , RulesM (..)
@@ -30,24 +29,13 @@ import Hakyll.Core.ResourceProvider
3029import Hakyll.Core.Routes
3130
3231
33−--------------------------------------------------------------------------------
34−-- | Output of a compiler rule
35−--
36−-- * The compiler will produce a simple item. This is the most common case.
37−--
38−-- * The compiler will produce more compilers. These new compilers need to be
39−-- added to the runtime if possible, since other items might depend upon them.
40−data CompileRule = CompileRule CompiledItem
41− | MetaCompileRule [(Identifier (), Compiler () CompileRule)]
42−
43−
4432--------------------------------------------------------------------------------
4533-- | A collection of rules for the compilation process
4634data RuleSet = RuleSet
4735 { -- | Routes used in the compilation structure
4836 rulesRoutes :: Routes
4937 , -- | Compilation rules
50− rulesCompilers :: [(Identifier (), Compiler () CompileRule)]
38+ rulesCompilers :: [(Identifier (), Compiler () CompiledItem)]
5139 , -- | A set of the actually used files
5240 rulesResources :: Set (Identifier ())
5341 }
src/Hakyll/Core/Run.hs+5−9
@@ -18,6 +18,7 @@ import System.FilePath ((</>))
1818import qualified Data.Map as M
1919import qualified Data.Set as S
2020
21+import Hakyll.Core.CompiledItem
2122import Hakyll.Core.Compiler
2223import Hakyll.Core.Compiler.Internal
2324import Hakyll.Core.Configuration
@@ -94,7 +95,7 @@ data RuntimeEnvironment = RuntimeEnvironment
9495
9596data RuntimeState = RuntimeState
9697 { hakyllAnalyzer :: DependencyAnalyzer (Identifier ())
97− , hakyllCompilers :: Map (Identifier ()) (Compiler () CompileRule)
98+ , hakyllCompilers :: Map (Identifier ()) (Compiler () CompiledItem)
9899 }
99100
100101newtype Runtime a = Runtime
@@ -104,7 +105,7 @@ newtype Runtime a = Runtime
104105
105106-- | Add a number of compilers and continue using these compilers
106107--
107−addNewCompilers :: [(Identifier (), Compiler () CompileRule)]
108+addNewCompilers :: [(Identifier (), Compiler () CompiledItem)]
108109 -- ^ Compilers to add
109110 -> Runtime ()
110111addNewCompilers newCompilers = Runtime $ do
@@ -190,8 +191,8 @@ build id' = Runtime $ do
190191 store isModified logger
191192
192193 case result of
193− -- Compile rule for one item, easy stuff
194− Right (CompileRule compiled) -> do
194+ -- Success
195+ Right compiled -> do
195196 case runRoutes routes id' of
196197 Nothing -> return ()
197198 Just url -> timed logger ("Routing to " ++ url) $ do
@@ -204,10 +205,5 @@ build id' = Runtime $ do
204205 -- Continue for the remaining compilers
205206 unRuntime stepAnalyzer
206207
207− -- Metacompiler, slightly more complicated
208− Right (MetaCompileRule newCompilers) ->
209− -- Actually I was just kidding, it's not hard at all
210− unRuntime $ addNewCompilers newCompilers
211−
212208 -- Some error happened, rethrow in Runtime monad
213209 Left err -> throwError err