on master help sign in
Stuff works now (somewhat)
commit50f8f819f9b67822305350b77117d4cb7a00cf45 authorJasper Van der Jeugt <m@jaspervdj.be> dateTue 13 Nov 2012, 19:03 (14 years ago) parentf0af2a3
6 files changed+71−260
hakyll.cabal+1−1 src/Hakyll/Core/Run.hs−189 src/Hakyll/Core/Runtime.hs+6−2 src/Hakyll/Main.hs+11−11 src/Hakyll/Web/Template.hs+24−40 src/Hakyll/Web/Template/Context.hs+29−17
hakyll.cabal+1−1
@@ -93,7 +93,7 @@ Library
9393 Hakyll
9494 Hakyll.Core.Compiler
9595 Hakyll.Core.Configuration
96− Hakyll.Core.DependencyAnalyzer
96+ Hakyll.Core.Dependencies
9797 Hakyll.Core.Identifier
9898 Hakyll.Core.Identifier.Pattern
9999 Hakyll.Core.Logger
src/Hakyll/Core/Run.hsdeleted−189
@@ -1,189 +0,0 @@
1−--------------------------------------------------------------------------------
2−-- | This is the module which binds it all together
3−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4−{-# LANGUAGE OverloadedStrings #-}
5−module Hakyll.Core.Run
6− ( run
7− ) where
8−
9−
10−--------------------------------------------------------------------------------
11−import Control.Applicative (Applicative, (<$>))
12−import Control.DeepSeq (deepseq)
13−import Control.Monad (filterM, forM_)
14−import Control.Monad.Error (ErrorT, runErrorT, throwError)
15−import Control.Monad.Reader (ReaderT, ask, runReaderT)
16−import Control.Monad.Trans (liftIO)
17−import Data.Map (Map)
18−import qualified Data.Map as M
19−import Data.Monoid (mempty)
20−import qualified Data.Set as S
21−import Prelude hiding (reverse)
22−import System.FilePath ((</>))
23−
24−
25−--------------------------------------------------------------------------------
26−import Hakyll.Core.CompiledItem
27−import Hakyll.Core.Compiler
28−import Hakyll.Core.Compiler.Internal
29−import Hakyll.Core.Configuration
30−import Hakyll.Core.DependencyAnalyzer
31−import qualified Hakyll.Core.DirectedGraph as DG
32−import Hakyll.Core.Identifier
33−import Hakyll.Core.Logger
34−import Hakyll.Core.ResourceProvider
35−import Hakyll.Core.Routes
36−import Hakyll.Core.Rules.Internal
37−import Hakyll.Core.Store (Store)
38−import qualified Hakyll.Core.Store as Store
39−import Hakyll.Core.Util.File
40−import Hakyll.Core.Writable
41−
42−
43−--------------------------------------------------------------------------------
44−-- | Run all rules needed, return the rule set used
45−run :: HakyllConfiguration -> RulesM a -> IO RuleSet
46−run configuration rules = do
47− logger <- makeLogger putStrLn
48−
49− section logger "Initialising"
50− store <- timed logger "Creating store" $
51− Store.new (inMemoryCache configuration) $ storeDirectory configuration
52− provider <- timed logger "Creating provider" $ newResourceProvider
53− store (ignoreFile configuration) "."
54−
55− ruleSet <- timed logger "Running rules" $ runRules rules provider
56− let compilers = rulesCompilers ruleSet
57−
58− -- Extract the reader/state
59− reader = unRuntime analyzeAndBuild
60− errorT = runReaderT reader $ RuntimeEnvironment
61− { runtimeLogger = logger
62− , runtimeConfiguration = configuration
63− , runtimeRoutes = rulesRoutes ruleSet
64− , runtimeProvider = provider
65− , runtimeStore = store
66− , runtimeCompilers = M.fromList compilers
67− }
68−
69− -- Run the program and fetch the resulting state
70− result <- runErrorT errorT
71− case result of
72− Left e -> thrown logger e
73− _ -> return ()
74−
75− -- Flush and return
76− flushLogger logger
77− return ruleSet
78−
79−
80−--------------------------------------------------------------------------------
81−data RuntimeEnvironment = RuntimeEnvironment
82− { runtimeLogger :: Logger
83− , runtimeConfiguration :: HakyllConfiguration
84− , runtimeRoutes :: Routes
85− , runtimeProvider :: ResourceProvider
86− , runtimeStore :: Store
87− , runtimeCompilers :: Map (Identifier ()) (Compiler () CompiledItem)
88− }
89−
90−
91−--------------------------------------------------------------------------------
92−newtype Runtime a = Runtime
93− { unRuntime :: ReaderT RuntimeEnvironment (ErrorT String IO) a
94− } deriving (Functor, Applicative, Monad)
95−
96−
97−--------------------------------------------------------------------------------
98−analyzeAndBuild :: Runtime ()
99−analyzeAndBuild = Runtime $ do
100− -- Get some stuff
101− logger <- runtimeLogger <$> ask
102− provider <- runtimeProvider <$> ask
103− store <- runtimeStore <$> ask
104− compilers <- runtimeCompilers <$> ask
105−
106− -- Checking which items have been modified
107− let universe = M.keys compilers
108− modified <- timed logger "Checking for modified items" $
109− fmap S.fromList $ flip filterM universe $
110− liftIO . resourceModified provider
111−
112− -- Fetch the old graph from the store. If we don't find it, we consider this
113− -- to be the first run
114− mOldGraph <- liftIO $ Store.get store graphKey
115− let (firstRun, oldGraph) = case mOldGraph of Store.Found g -> (False, g)
116− _ -> (True, mempty)
117−
118− -- Create a new dependency graph
119− graph = DG.fromList $
120− flip map (M.toList compilers) $ \(id', compiler) ->
121− let deps = runCompilerDependencies compiler id' universe
122− in (id', S.toList deps)
123−
124− ood | firstRun = const True
125− | otherwise = (`S.member` modified)
126−
127− -- Check for cycles and analyze the graph
128− analysis = analyze oldGraph graph ood
129−
130− -- Make sure this stuff is evaluated
131− () <- timed logger "Analyzing dependency graph" $
132− oldGraph `deepseq` analysis `deepseq` return ()
133−
134− -- We want to save the new dependency graph for the next run
135− liftIO $ Store.set store graphKey graph
136−
137− case analysis of
138− Cycle c -> unRuntime $ dumpCycle c
139− Order o -> mapM_ (unRuntime . build) o
140− where
141− graphKey = ["Hakyll.Core.Run.run", "dependencies"]
142−
143−
144−--------------------------------------------------------------------------------
145−-- | Dump cyclic error and quit
146−dumpCycle :: [Identifier ()] -> Runtime ()
147−dumpCycle cycle' = Runtime $ do
148− logger <- runtimeLogger <$> ask
149− section logger "Dependency cycle detected! Conflict:"
150− forM_ (zip cycle' $ drop 1 cycle') $ \(x, y) ->
151− report logger $ show x ++ " -> " ++ show y
152−
153−
154−--------------------------------------------------------------------------------
155−build :: Identifier () -> Runtime ()
156−build id' = Runtime $ do
157− logger <- runtimeLogger <$> ask
158− routes <- runtimeRoutes <$> ask
159− provider <- runtimeProvider <$> ask
160− store <- runtimeStore <$> ask
161− compilers <- runtimeCompilers <$> ask
162−
163− section logger $ "Compiling " ++ show id'
164−
165− -- Fetch the right compiler from the map
166− let compiler = compilers M.! id'
167−
168− -- Check if the resource was modified
169− isModified <- liftIO $ resourceModified provider id'
170−
171− -- Run the compiler
172− result <- timed logger "Total compile time" $ liftIO $
173− runCompiler compiler id' provider (M.keys compilers) routes
174− store isModified logger
175−
176− case result of
177− -- Success
178− Right compiled -> do
179− case runRoutes routes id' of
180− Nothing -> return ()
181− Just url -> timed logger ("Routing to " ++ url) $ do
182− destination <-
183− destinationDirectory . runtimeConfiguration <$> ask
184− let path = destination </> url
185− liftIO $ makeDirectories path
186− liftIO $ write path compiled
187−
188− -- Some error happened, rethrow in Runtime monad
189− Left err -> throwError err
src/Hakyll/Core/Runtime.hs+6−2
@@ -132,7 +132,9 @@ scheduleOutOfDate = do
132132
133133 -- Update facts and todo items
134134 modify $ \s -> s
135− { runtimeTodo = todo `M.union` todo'
135+ { runtimeDone = runtimeDone s `S.union`
136+ (S.fromList identifiers `S.difference` ood)
137+ , runtimeTodo = todo `M.union` todo'
136138 , runtimeFacts = facts'
137139 }
138140
@@ -143,7 +145,9 @@ pickAndChase = do
143145 todo <- runtimeTodo <$> get
144146 case M.minViewWithKey todo of
145147 Nothing -> return ()
146− Just ((id', _), _) -> chase [] id'
148+ Just ((id', _), _) -> do
149+ chase [] id'
150+ pickAndChase
147151
148152
149153--------------------------------------------------------------------------------
src/Hakyll/Main.hs+11−11
@@ -13,7 +13,7 @@ import System.Process (system)
1313
1414import Hakyll.Core.Configuration
1515import Hakyll.Core.Identifier
16−import Hakyll.Core.Run
16+import Hakyll.Core.Runtime
1717import Hakyll.Core.Rules
1818
1919#ifdef PREVIEW_SERVER
@@ -28,13 +28,13 @@ import Hakyll.Web.Preview.Server
2828
2929-- | This usualy is the function with which the user runs the hakyll compiler
3030--
31−hakyll :: RulesM a -> IO ()
32−hakyll = hakyllWith defaultHakyllConfiguration
31+hakyll :: Rules a -> IO ()
32+hakyll = hakyllWith defaultConfiguration
3333
3434-- | A variant of 'hakyll' which allows the user to specify a custom
3535-- configuration
3636--
37−hakyllWith :: HakyllConfiguration -> RulesM a -> IO ()
37+hakyllWith :: Configuration -> Rules a -> IO ()
3838hakyllWith conf rules = do
3939 args <- getArgs
4040 case args of
@@ -51,14 +51,14 @@ hakyllWith conf rules = do
5151
5252-- | Build the site
5353--
54−build :: HakyllConfiguration -> RulesM a -> IO ()
54+build :: Configuration -> Rules a -> IO ()
5555build conf rules = do
5656 _ <- run conf rules
5757 return ()
5858
5959-- | Remove the output directories
6060--
61−clean :: HakyllConfiguration -> IO ()
61+clean :: Configuration -> IO ()
6262clean conf = do
6363 remove $ destinationDirectory conf
6464 remove $ storeDirectory conf
@@ -97,12 +97,12 @@ help = do
9797
9898-- | Preview the site
9999--
100−preview :: HakyllConfiguration -> RulesM a -> Int -> IO ()
100+preview :: Configuration -> Rules a -> Int -> IO ()
101101#ifdef PREVIEW_SERVER
102102preview conf rules port = do
103103 -- Fork a thread polling for changes
104104 _ <- forkIO $ previewPoll conf update
105−
105+
106106 -- Run the server in the main thread
107107 server conf port
108108 where
@@ -113,14 +113,14 @@ preview _ _ _ = previewServerDisabled
113113
114114-- | Rebuild the site
115115--
116−rebuild :: HakyllConfiguration -> RulesM a -> IO ()
116+rebuild :: Configuration -> Rules a -> IO ()
117117rebuild conf rules = do
118118 clean conf
119119 build conf rules
120120
121121-- | Start a server
122122--
123−server :: HakyllConfiguration -> Int -> IO ()
123+server :: Configuration -> Int -> IO ()
124124#ifdef PREVIEW_SERVER
125125server conf port = do
126126 let destination = destinationDirectory conf
@@ -133,7 +133,7 @@ server _ _ = previewServerDisabled
133133
134134-- | Upload the site
135135--
136−deploy :: HakyllConfiguration -> IO ()
136+deploy :: Configuration -> IO ()
137137deploy conf = do
138138 _ <- system $ deployCommand conf
139139 return ()
src/Hakyll/Web/Template.hs+24−40
@@ -58,8 +58,6 @@
5858-- > <a href="/about.html"> About
5959-- > <a href="/code.html"> Code
6060-- > #{body}
61−{-# LANGUAGE Arrows #-}
62−{-# LANGUAGE ScopedTypeVariables #-}
6361module Hakyll.Web.Template
6462 ( Template
6563 , applyTemplate
@@ -70,11 +68,7 @@ module Hakyll.Web.Template
7068
7169
7270--------------------------------------------------------------------------------
73−import Control.Arrow
74−import Control.Category (id)
75−import qualified Data.Map as M
76−import Data.Maybe (fromMaybe)
77−import Data.Tuple (swap)
71+import Control.Monad (forM, liftM)
7872import Prelude hiding (id)
7973import System.FilePath (takeExtension)
8074import Text.Hamlet (HamletSettings,
@@ -84,7 +78,6 @@ import Text.Hamlet (HamletSettings,
8478--------------------------------------------------------------------------------
8579import Hakyll.Core.Compiler
8680import Hakyll.Core.Identifier
87−import Hakyll.Core.Util.Arrow
8881import Hakyll.Web.Page.Internal
8982import Hakyll.Web.Template.Context
9083import Hakyll.Web.Template.Internal
@@ -92,53 +85,44 @@ import Hakyll.Web.Template.Read
9285
9386
9487--------------------------------------------------------------------------------
95−applyTemplate :: forall a b. (ArrowChoice a, ArrowMap a)
96− => a (String, b) String
97− -> a (Template, b) String
98−applyTemplate context =
99− arr (\(tpl, x) -> [(e, x) | e <- unTemplate tpl]) >>>
100− mapA applyElement >>^ concat
101− where
102− applyElement :: a (TemplateElement, b) String
103− applyElement = unElement >>> (id ||| context)
104−
105− unElement :: a (TemplateElement, b) (Either String (String, b))
106− unElement = arr $ \(e, x) -> case e of
107− Chunk c -> Left c
108− Escaped -> Left "$"
109− Key k -> Right (k, x)
88+applyTemplate :: Monad m
89+ => (String -> a -> m String)
90+ -> Template -> a -> m String
91+applyTemplate context tpl x = liftM concat $
92+ forM (unTemplate tpl) $ \e -> case e of
93+ Chunk c -> return c
94+ Escaped -> return "$"
95+ Key k -> context k x
11096
11197
11298--------------------------------------------------------------------------------
11399-- | Read a template. If the extension of the file we're compiling is
114100-- @.hml@ or @.hamlet@, it will be considered as a Hamlet template, and parsed
115101-- as such.
116−templateCompiler :: Compiler () Template
102+templateCompiler :: Compiler Template
117103templateCompiler = templateCompilerWith defaultHamletSettings
118104
119105
120106--------------------------------------------------------------------------------
121107-- | Version of 'templateCompiler' that enables custom settings.
122−templateCompilerWith :: HamletSettings -> Compiler () Template
108+templateCompilerWith :: HamletSettings -> Compiler Template
123109templateCompilerWith settings =
124− cached "Hakyll.Web.Template.templateCompilerWith" $
125− getIdentifier &&& getResourceString >>^ uncurry read'
126− where
127− read' identifier string =
110+ cached "Hakyll.Web.Template.templateCompilerWith" $ do
111+ identifier <- getIdentifier
112+ string <- getResourceString
128113 if takeExtension (toFilePath identifier) `elem` [".hml", ".hamlet"]
129114 -- Hamlet template
130− then readHamletTemplateWith settings string
115+ then return $ readHamletTemplateWith settings string
131116 -- Hakyll template
132− else readTemplate string
117+ else return $ readTemplate string
133118
134119
135120--------------------------------------------------------------------------------
136−applyTemplateCompiler :: Identifier Template -- ^ Template
137− -> Context Page -- ^ Context
138− -> Compiler Page Page -- ^ Compiler
139−applyTemplateCompiler identifier context = requireA identifier $
140− arr swap >>> applyTemplate context'
141− where
142− context' = proc (k, x) -> do
143− id' <- getIdentifier -< ()
144− context -< (k, (id', x))
121+applyTemplateCompiler :: Template -- ^ Template
122+ -> Context Page -- ^ Context
123+ -> Page -- ^ Page
124+ -> Compiler Page -- ^ Compiler
125+applyTemplateCompiler tpl context page = do
126+ identifier <- getIdentifier
127+ let context' k x = unContext context k identifier x
128+ applyTemplate context' tpl page
src/Hakyll/Web/Template/Context.hs+29−17
@@ -1,6 +1,7 @@
11--------------------------------------------------------------------------------
22module Hakyll.Web.Template.Context
3− ( Context
3+ ( Context (..)
4+ , mapContext
45 , field
56
67 , defaultContext
@@ -13,8 +14,8 @@ module Hakyll.Web.Template.Context
1314
1415
1516--------------------------------------------------------------------------------
16−import Control.Applicative (empty, (<|>))
17−import Control.Arrow
17+import Control.Applicative (Alternative (..), (<$>))
18+import Data.Monoid (Monoid (..))
1819import System.FilePath (takeBaseName, takeDirectory)
1920
2021
@@ -26,24 +27,35 @@ import Hakyll.Web.Urls
2627
2728
2829--------------------------------------------------------------------------------
29−type Context a = String -> Identifier -> a -> Compiler String
30+newtype Context a = Context
31+ { unContext :: String -> Identifier -> a -> Compiler String
32+ }
33+
34+
35+--------------------------------------------------------------------------------
36+instance Monoid (Context a) where
37+ mempty = Context $ \_ _ _ -> empty
38+ mappend (Context f) (Context g) = Context $ \k i x -> f k i x <|> g k i x
39+
40+
41+--------------------------------------------------------------------------------
42+mapContext :: (String -> String) -> Context a -> Context a
43+mapContext f (Context g) = Context $ \k i x -> f <$> g k i x
3044
3145
3246--------------------------------------------------------------------------------
3347field :: String -> (Identifier -> a -> Compiler String) -> Context a
34−field key value k' id' x
35− | k' == key = value id' x
36− | otherwise = empty
48+field key value = Context $ \k i x -> if k == key then value i x else empty
3749
3850
3951--------------------------------------------------------------------------------
4052defaultContext :: Context Page
4153defaultContext =
42− bodyField "body" <|>
43− urlField "url" <|>
44− pathField "path" <|>
45− categoryField "category" <|>
46− titleField "title" <|>
54+ bodyField "body" `mappend`
55+ urlField "url" `mappend`
56+ pathField "path" `mappend`
57+ categoryField "category" `mappend`
58+ titleField "title" `mappend`
4759 missingField
4860
4961
@@ -54,24 +66,24 @@ bodyField key = field key $ \_ x -> return x
5466
5567--------------------------------------------------------------------------------
5668urlField :: String -> Context a
57−urlField key = field key $ fst ^>> getRouteFor >>^ maybe empty toUrl
69+urlField key = field key $ \i _ -> maybe empty toUrl <$> getRouteFor i
5870
5971
6072--------------------------------------------------------------------------------
6173pathField :: String -> Context a
62−pathField key = field key $ arr $ toFilePath . fst
74+pathField key = field key $ \i _ -> return $ toFilePath i
6375
6476
6577--------------------------------------------------------------------------------
6678categoryField :: String -> Context a
67−categoryField key = pathField key >>^ (takeBaseName . takeDirectory)
79+categoryField key = mapContext (takeBaseName . takeDirectory) $ pathField key
6880
6981
7082--------------------------------------------------------------------------------
7183titleField :: String -> Context a
72−titleField key = pathField key >>^ takeBaseName
84+titleField key = mapContext takeBaseName $ pathField key
7385
7486
7587--------------------------------------------------------------------------------
7688missingField :: Context a
77−missingField = arr $ \(k, _) -> "$" ++ k ++ "$"
89+missingField = Context $ \k _ _ -> return $ "$" ++ k ++ "$"