on master help sign in
Stuff works now (somewhat)
50f8f81Jasper Van der Jeugt
hakyll.cabal+1−1
@@ -93,7 +93,7 @@ Library
93 Hakyll
93 Hakyll
94 Hakyll.Core.Compiler
94 Hakyll.Core.Compiler
95 Hakyll.Core.Configuration
95 Hakyll.Core.Configuration
96− Hakyll.Core.DependencyAnalyzer
96+ Hakyll.Core.Dependencies
97 Hakyll.Core.Identifier
97 Hakyll.Core.Identifier
98 Hakyll.Core.Identifier.Pattern
98 Hakyll.Core.Identifier.Pattern
99 Hakyll.Core.Logger
99 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
132
132
133 -- Update facts and todo items
133 -- Update facts and todo items
134 modify $ \s -> s
134 modify $ \s -> s
135+ { runtimeDone = runtimeDone s `S.union`
136+ (S.fromList identifiers `S.difference` ood)
135− { runtimeTodo = todo `M.union` todo'
137+ , runtimeTodo = todo `M.union` todo'
136 , runtimeFacts = facts'
138 , runtimeFacts = facts'
137 }
139 }
138
140
@@ -143,7 +145,9 @@ pickAndChase = do
143 todo <- runtimeTodo <$> get
145 todo <- runtimeTodo <$> get
144 case M.minViewWithKey todo of
146 case M.minViewWithKey todo of
145 Nothing -> return ()
147 Nothing -> return ()
146− Just ((id', _), _) -> chase [] id'
148+ Just ((id', _), _) -> do
149+ chase [] id'
150+ pickAndChase
147
151
148
152
149--------------------------------------------------------------------------------
153--------------------------------------------------------------------------------
src/Hakyll/Main.hs+11−11
@@ -13,7 +13,7 @@ import System.Process (system)
13
13
14import Hakyll.Core.Configuration
14import Hakyll.Core.Configuration
15import Hakyll.Core.Identifier
15import Hakyll.Core.Identifier
16−import Hakyll.Core.Run
16+import Hakyll.Core.Runtime
17import Hakyll.Core.Rules
17import Hakyll.Core.Rules
18
18
19#ifdef PREVIEW_SERVER
19#ifdef PREVIEW_SERVER
@@ -28,13 +28,13 @@ import Hakyll.Web.Preview.Server
28
28
29-- | This usualy is the function with which the user runs the hakyll compiler
29-- | This usualy is the function with which the user runs the hakyll compiler
30--
30--
31−hakyll :: RulesM a -> IO ()
31+hakyll :: Rules a -> IO ()
32−hakyll = hakyllWith defaultHakyllConfiguration
32+hakyll = hakyllWith defaultConfiguration
33
33
34-- | A variant of 'hakyll' which allows the user to specify a custom
34-- | A variant of 'hakyll' which allows the user to specify a custom
35-- configuration
35-- configuration
36--
36--
37−hakyllWith :: HakyllConfiguration -> RulesM a -> IO ()
37+hakyllWith :: Configuration -> Rules a -> IO ()
38hakyllWith conf rules = do
38hakyllWith conf rules = do
39 args <- getArgs
39 args <- getArgs
40 case args of
40 case args of
@@ -51,14 +51,14 @@ hakyllWith conf rules = do
51
51
52-- | Build the site
52-- | Build the site
53--
53--
54−build :: HakyllConfiguration -> RulesM a -> IO ()
54+build :: Configuration -> Rules a -> IO ()
55build conf rules = do
55build conf rules = do
56 _ <- run conf rules
56 _ <- run conf rules
57 return ()
57 return ()
58
58
59-- | Remove the output directories
59-- | Remove the output directories
60--
60--
61−clean :: HakyllConfiguration -> IO ()
61+clean :: Configuration -> IO ()
62clean conf = do
62clean conf = do
63 remove $ destinationDirectory conf
63 remove $ destinationDirectory conf
64 remove $ storeDirectory conf
64 remove $ storeDirectory conf
@@ -97,12 +97,12 @@ help = do
97
97
98-- | Preview the site
98-- | Preview the site
99--
99--
100−preview :: HakyllConfiguration -> RulesM a -> Int -> IO ()
100+preview :: Configuration -> Rules a -> Int -> IO ()
101#ifdef PREVIEW_SERVER
101#ifdef PREVIEW_SERVER
102preview conf rules port = do
102preview conf rules port = do
103 -- Fork a thread polling for changes
103 -- Fork a thread polling for changes
104 _ <- forkIO $ previewPoll conf update
104 _ <- forkIO $ previewPoll conf update
105−
105+
106 -- Run the server in the main thread
106 -- Run the server in the main thread
107 server conf port
107 server conf port
108 where
108 where
@@ -113,14 +113,14 @@ preview _ _ _ = previewServerDisabled
113
113
114-- | Rebuild the site
114-- | Rebuild the site
115--
115--
116−rebuild :: HakyllConfiguration -> RulesM a -> IO ()
116+rebuild :: Configuration -> Rules a -> IO ()
117rebuild conf rules = do
117rebuild conf rules = do
118 clean conf
118 clean conf
119 build conf rules
119 build conf rules
120
120
121-- | Start a server
121-- | Start a server
122--
122--
123−server :: HakyllConfiguration -> Int -> IO ()
123+server :: Configuration -> Int -> IO ()
124#ifdef PREVIEW_SERVER
124#ifdef PREVIEW_SERVER
125server conf port = do
125server conf port = do
126 let destination = destinationDirectory conf
126 let destination = destinationDirectory conf
@@ -133,7 +133,7 @@ server _ _ = previewServerDisabled
133
133
134-- | Upload the site
134-- | Upload the site
135--
135--
136−deploy :: HakyllConfiguration -> IO ()
136+deploy :: Configuration -> IO ()
137deploy conf = do
137deploy conf = do
138 _ <- system $ deployCommand conf
138 _ <- system $ deployCommand conf
139 return ()
139 return ()
src/Hakyll/Web/Template.hs+24−40
@@ -58,8 +58,6 @@
58-- > <a href="/about.html"> About
58-- > <a href="/about.html"> About
59-- > <a href="/code.html"> Code
59-- > <a href="/code.html"> Code
60-- > #{body}
60-- > #{body}
61−{-# LANGUAGE Arrows #-}
62−{-# LANGUAGE ScopedTypeVariables #-}
63module Hakyll.Web.Template
61module Hakyll.Web.Template
64 ( Template
62 ( Template
65 , applyTemplate
63 , applyTemplate
@@ -70,11 +68,7 @@ module Hakyll.Web.Template
70
68
71
69
72--------------------------------------------------------------------------------
70--------------------------------------------------------------------------------
73−import Control.Arrow
71+import Control.Monad (forM, liftM)
74−import Control.Category (id)
75−import qualified Data.Map as M
76−import Data.Maybe (fromMaybe)
77−import Data.Tuple (swap)
78import Prelude hiding (id)
72import Prelude hiding (id)
79import System.FilePath (takeExtension)
73import System.FilePath (takeExtension)
80import Text.Hamlet (HamletSettings,
74import Text.Hamlet (HamletSettings,
@@ -84,7 +78,6 @@ import Text.Hamlet (HamletSettings,
84--------------------------------------------------------------------------------
78--------------------------------------------------------------------------------
85import Hakyll.Core.Compiler
79import Hakyll.Core.Compiler
86import Hakyll.Core.Identifier
80import Hakyll.Core.Identifier
87−import Hakyll.Core.Util.Arrow
88import Hakyll.Web.Page.Internal
81import Hakyll.Web.Page.Internal
89import Hakyll.Web.Template.Context
82import Hakyll.Web.Template.Context
90import Hakyll.Web.Template.Internal
83import Hakyll.Web.Template.Internal
@@ -92,53 +85,44 @@ import Hakyll.Web.Template.Read
92
85
93
86
94--------------------------------------------------------------------------------
87--------------------------------------------------------------------------------
95−applyTemplate :: forall a b. (ArrowChoice a, ArrowMap a)
88+applyTemplate :: Monad m
96− => a (String, b) String
89+ => (String -> a -> m String)
97− -> a (Template, b) String
90+ -> Template -> a -> m String
98−applyTemplate context =
91+applyTemplate context tpl x = liftM concat $
99− arr (\(tpl, x) -> [(e, x) | e <- unTemplate tpl]) >>>
92+ forM (unTemplate tpl) $ \e -> case e of
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
93+ Chunk c -> return c
108− Escaped -> Left "$"
94+ Escaped -> return "$"
109− Key k -> Right (k, x)
95+ Key k -> context k x
110
96
111
97
112--------------------------------------------------------------------------------
98--------------------------------------------------------------------------------
113-- | Read a template. If the extension of the file we're compiling is
99-- | Read a template. If the extension of the file we're compiling is
114-- @.hml@ or @.hamlet@, it will be considered as a Hamlet template, and parsed
100-- @.hml@ or @.hamlet@, it will be considered as a Hamlet template, and parsed
115-- as such.
101-- as such.
116−templateCompiler :: Compiler () Template
102+templateCompiler :: Compiler Template
117templateCompiler = templateCompilerWith defaultHamletSettings
103templateCompiler = templateCompilerWith defaultHamletSettings
118
104
119
105
120--------------------------------------------------------------------------------
106--------------------------------------------------------------------------------
121-- | Version of 'templateCompiler' that enables custom settings.
107-- | Version of 'templateCompiler' that enables custom settings.
122−templateCompilerWith :: HamletSettings -> Compiler () Template
108+templateCompilerWith :: HamletSettings -> Compiler Template
123templateCompilerWith settings =
109templateCompilerWith settings =
124− cached "Hakyll.Web.Template.templateCompilerWith" $
110+ cached "Hakyll.Web.Template.templateCompilerWith" $ do
111+ identifier <- getIdentifier
125− getIdentifier &&& getResourceString >>^ uncurry read'
112+ string <- getResourceString
126− where
127− read' identifier string =
128 if takeExtension (toFilePath identifier) `elem` [".hml", ".hamlet"]
113 if takeExtension (toFilePath identifier) `elem` [".hml", ".hamlet"]
129 -- Hamlet template
114 -- Hamlet template
130− then readHamletTemplateWith settings string
115+ then return $ readHamletTemplateWith settings string
131 -- Hakyll template
116 -- Hakyll template
132− else readTemplate string
117+ else return $ readTemplate string
133
118
134
119
135--------------------------------------------------------------------------------
120--------------------------------------------------------------------------------
136−applyTemplateCompiler :: Identifier Template -- ^ Template
121+applyTemplateCompiler :: Template -- ^ Template
137− -> Context Page -- ^ Context
122+ -> Context Page -- ^ Context
138− -> Compiler Page Page -- ^ Compiler
123+ -> Page -- ^ Page
139−applyTemplateCompiler identifier context = requireA identifier $
124+ -> Compiler Page -- ^ Compiler
140− arr swap >>> applyTemplate context'
125+applyTemplateCompiler tpl context page = do
141− where
142− context' = proc (k, x) -> do
143− id' <- getIdentifier -< ()
126+ identifier <- getIdentifier
144− context -< (k, (id', x))
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 @@
1--------------------------------------------------------------------------------
1--------------------------------------------------------------------------------
2module Hakyll.Web.Template.Context
2module Hakyll.Web.Template.Context
3− ( Context
3+ ( Context (..)
4+ , mapContext
4 , field
5 , field
5
6
6 , defaultContext
7 , defaultContext
@@ -13,8 +14,8 @@ module Hakyll.Web.Template.Context
13
14
14
15
15--------------------------------------------------------------------------------
16--------------------------------------------------------------------------------
16−import Control.Applicative (empty, (<|>))
17+import Control.Applicative (Alternative (..), (<$>))
17−import Control.Arrow
18+import Data.Monoid (Monoid (..))
18import System.FilePath (takeBaseName, takeDirectory)
19import System.FilePath (takeBaseName, takeDirectory)
19
20
20
21
@@ -26,24 +27,35 @@ import Hakyll.Web.Urls
26
27
27
28
28--------------------------------------------------------------------------------
29--------------------------------------------------------------------------------
30+newtype Context a = Context
29−type Context a = String -> Identifier -> a -> Compiler String
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
30
44
31
45
32--------------------------------------------------------------------------------
46--------------------------------------------------------------------------------
33field :: String -> (Identifier -> a -> Compiler String) -> Context a
47field :: String -> (Identifier -> a -> Compiler String) -> Context a
34−field key value k' id' x
48+field key value = Context $ \k i x -> if k == key then value i x else empty
35− | k' == key = value id' x
36− | otherwise = empty
37
49
38
50
39--------------------------------------------------------------------------------
51--------------------------------------------------------------------------------
40defaultContext :: Context Page
52defaultContext :: Context Page
41defaultContext =
53defaultContext =
42− bodyField "body" <|>
54+ bodyField "body" `mappend`
43− urlField "url" <|>
55+ urlField "url" `mappend`
44− pathField "path" <|>
56+ pathField "path" `mappend`
45− categoryField "category" <|>
57+ categoryField "category" `mappend`
46− titleField "title" <|>
58+ titleField "title" `mappend`
47 missingField
59 missingField
48
60
49
61
@@ -54,24 +66,24 @@ bodyField key = field key $ \_ x -> return x
54
66
55--------------------------------------------------------------------------------
67--------------------------------------------------------------------------------
56urlField :: String -> Context a
68urlField :: String -> Context a
57−urlField key = field key $ fst ^>> getRouteFor >>^ maybe empty toUrl
69+urlField key = field key $ \i _ -> maybe empty toUrl <$> getRouteFor i
58
70
59
71
60--------------------------------------------------------------------------------
72--------------------------------------------------------------------------------
61pathField :: String -> Context a
73pathField :: String -> Context a
62−pathField key = field key $ arr $ toFilePath . fst
74+pathField key = field key $ \i _ -> return $ toFilePath i
63
75
64
76
65--------------------------------------------------------------------------------
77--------------------------------------------------------------------------------
66categoryField :: String -> Context a
78categoryField :: String -> Context a
67−categoryField key = pathField key >>^ (takeBaseName . takeDirectory)
79+categoryField key = mapContext (takeBaseName . takeDirectory) $ pathField key
68
80
69
81
70--------------------------------------------------------------------------------
82--------------------------------------------------------------------------------
71titleField :: String -> Context a
83titleField :: String -> Context a
72−titleField key = pathField key >>^ takeBaseName
84+titleField key = mapContext takeBaseName $ pathField key
73
85
74
86
75--------------------------------------------------------------------------------
87--------------------------------------------------------------------------------
76missingField :: Context a
88missingField :: Context a
77−missingField = arr $ \(k, _) -> "$" ++ k ++ "$"
89+missingField = Context $ \k _ _ -> return $ "$" ++ k ++ "$"