summaryrefslogtreecommitdiff
path: root/src/Hakyll/Core
diff options
context:
space:
mode:
authorJasper Van der Jeugt <m@jaspervdj.be>2012-11-13 17:31:03 +0100
committerJasper Van der Jeugt <m@jaspervdj.be>2012-11-13 17:31:03 +0100
commitf0af2a3b79ea7eea3f521f79fd903f9023ec85df (patch)
treebbc460b65ab52879c616dffce1bb32fe8d8df2ac /src/Hakyll/Core
parentd2e913f42434841c584b97ae9d5417ff2737c0ce (diff)
downloadhakyll-f0af2a3b79ea7eea3f521f79fd903f9023ec85df.tar.gz
WIP
Diffstat (limited to 'src/Hakyll/Core')
-rw-r--r--src/Hakyll/Core/Compiler.hs408
-rw-r--r--src/Hakyll/Core/Compiler/Internal.hs33
-rw-r--r--src/Hakyll/Core/Compiler/Require.hs63
-rw-r--r--src/Hakyll/Core/Runtime.hs20
-rw-r--r--src/Hakyll/Core/UnixFilter.hs69
-rw-r--r--src/Hakyll/Core/Writable/CopyFile.hs21
-rw-r--r--src/Hakyll/Core/Writable/WritableTuple.hs37
7 files changed, 222 insertions, 429 deletions
diff --git a/src/Hakyll/Core/Compiler.hs b/src/Hakyll/Core/Compiler.hs
index ef9b03c..e59506f 100644
--- a/src/Hakyll/Core/Compiler.hs
+++ b/src/Hakyll/Core/Compiler.hs
@@ -1,97 +1,8 @@
--- | A Compiler manages targets and dependencies between targets
---
--- The most distinguishing property of a 'Compiler' is that it is an Arrow. A
--- compiler of the type @Compiler a b@ is simply a compilation phase which takes
--- an @a@ as input, and produces a @b@ as output.
---
--- Compilers are chained using the '>>>' arrow operation. If we have a compiler
---
--- > getResourceString :: Compiler Resource String
---
--- which reads the resource, and a compiler
---
--- > readPage :: Compiler String (Page String)
---
--- we can chain these two compilers to get a
---
--- > (getResourceString >>> readPage) :: Compiler Resource (Page String)
---
--- Most compilers can be created by combining smaller compilers using '>>>'.
---
--- More advanced constructions are also possible using arrow, and sometimes
--- these are needed. For a good introduction to arrow, you can refer to
---
--- <http://en.wikibooks.org/wiki/Haskell/Understanding_arrows>
---
--- A construction worth writing a few paragraphs about here are the 'require'
--- functions. Different variants of this function are exported here, but they
--- all serve more or less the same goal.
---
--- When you use only '>>>' to chain your compilers, you get a linear pipeline --
--- it is not possible to add extra items from other compilers along the way.
--- This is where the 'require' functions come in.
---
--- This function allows you to reference other items, which are then added to
--- the pipeline. Let's look at this crappy ASCII illustration which represents
--- a pretty common scenario:
---
--- > read resource >>> pandoc render >>> layout >>> relativize URL's
--- >
--- > @templates/fancy.html@
---
--- We want to construct a pipeline of compilers to go from our resource to a
--- proper webpage. However, the @layout@ compiler takes more than just the
--- rendered page as input: it needs the @templates/fancy.html@ template as well.
---
--- This is an example of where we need the @require@ function. We can solve
--- this using a construction that looks like:
---
--- > ... >>> pandoc render >>> require >>> layout >>> ...
--- > |
--- > @templates/fancy.html@ ------/
---
--- This illustration can help us understand the type signature of 'require'.
---
--- > require :: (Binary a, Typeable a, Writable a)
--- > => Identifier a
--- > -> (b -> a -> c)
--- > -> Compiler b c
---
--- Let's look at it in detail:
---
--- > (Binary a, Typeable a, Writable a)
---
--- These are constraints for the @a@ type. @a@ (the template) needs to have
--- certain properties for it to be required.
---
--- > Identifier a
---
--- This is simply @templates/fancy.html@: the 'Identifier' of the item we want
--- to 'require', in other words, the name of the item we want to add to the
--- pipeline somehow.
---
--- > (b -> a -> c)
---
--- This is a function given by the user, specifying /how/ the two items shall be
--- merged. @b@ is the output of the previous compiler, and @a@ is the item we
--- just required -- the template. This means @c@ will be the final output of the
--- 'require' combinator.
---
--- > Compiler b c
---
--- Indeed, we have now constructed a compiler which takes a @b@ and produces a
--- @c@. This means that we have a linear pipeline again, thanks to the 'require'
--- function. So, the 'require' function actually helps to reduce to complexity
--- of Hakyll applications!
---
--- Note that require will fetch a previously compiled item: in our example of
--- the type @a@. It is /very/ important that the compiler which produced this
--- value, produced the right type as well!
---
-{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables #-}
+--------------------------------------------------------------------------------
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE ScopedTypeVariables #-}
module Hakyll.Core.Compiler
( Compiler
- , runCompiler
, getIdentifier
, getRoute
, getRouteFor
@@ -99,95 +10,52 @@ module Hakyll.Core.Compiler
, getResourceString
, getResourceLBS
, getResourceWith
- , fromDependency
- , require_
, require
- , requireA
- , requireAll_
, requireAll
- , requireAllA
, cached
, unsafeCompiler
- , traceShowCompiler
+ , logCompiler
, timedCompiler
- , byPattern
- , byExtension
) where
-import Prelude hiding ((.), id)
-import Control.Arrow ((>>>), (&&&), arr, first)
-import Control.Applicative ((<$>), (*>))
-import Control.Exception (SomeException, handle)
-import Control.Monad.Reader (ask)
-import Control.Monad.Trans (liftIO)
-import Control.Monad.Error (throwError)
-import Control.Category (Category, (.), id)
-import Data.List (find)
-import System.Environment (getProgName)
-import System.FilePath (takeExtension)
-import Data.Binary (Binary)
-import Data.Typeable (Typeable)
-import Data.ByteString.Lazy (ByteString)
-
-import Hakyll.Core.Identifier
-import Hakyll.Core.Identifier.Pattern
-import Hakyll.Core.CompiledItem
-import Hakyll.Core.Writable
-import Hakyll.Core.ResourceProvider
-import Hakyll.Core.Compiler.Internal
-import Hakyll.Core.Store (Store)
-import Hakyll.Core.Routes
-import Hakyll.Core.Logger
-import qualified Hakyll.Core.Store as Store
-
--- | Run a compiler, yielding the resulting target and it's dependencies. This
--- version of 'runCompilerJob' also stores the result
---
-runCompiler :: Compiler CompiledItem -- ^ Compiler to run
- -> Identifier () -- ^ Target identifier
- -> ResourceProvider -- ^ Resource provider
- -> [Identifier ()] -- ^ Universe
- -> Routes -- ^ Route
- -> Store -- ^ Store
- -> Bool -- ^ Was the resource modified?
- -> Logger -- ^ Logger
- -> IO (Throwing CompiledItem) -- ^ Resulting item
-runCompiler compiler id' provider universe routes store modified logger = do
- -- Run the compiler job
- result <- handle (\(e :: SomeException) -> return $ Left $ show e) $
- runCompilerJob compiler id' provider universe routes store modified
- logger
+--------------------------------------------------------------------------------
+import Control.Applicative ((<$>))
+import Data.Binary (Binary)
+import Data.ByteString.Lazy (ByteString)
+import Data.Typeable (Typeable)
+import Prelude hiding (id, (.))
+import System.Environment (getProgName)
- -- Inspect the result
- case result of
- -- In case we compiled an item, we will store a copy in the cache first,
- -- before we return control. This makes sure the compiled item can later
- -- be accessed by e.g. require.
- Right (CompiledItem x) ->
- Store.set store ["Hakyll.Core.Compiler.runCompiler", show id'] x
- -- Otherwise, we do nothing here
- _ -> return ()
+--------------------------------------------------------------------------------
+import Hakyll.Core.Compiler.Internal
+import Hakyll.Core.Compiler.Require
+import Hakyll.Core.Identifier
+import Hakyll.Core.Logger
+import Hakyll.Core.ResourceProvider
+import Hakyll.Core.Routes
+import qualified Hakyll.Core.Store as Store
+import Hakyll.Core.Writable
- return result
+--------------------------------------------------------------------------------
-- | Get the identifier of the item that is currently being compiled
---
-getIdentifier :: Compiler (Identifier b)
-getIdentifier = fromJob $ const $ CompilerM $
- castIdentifier . compilerIdentifier <$> ask
+getIdentifier :: Compiler Identifier
+getIdentifier = compilerIdentifier <$> compilerAsk
+
+--------------------------------------------------------------------------------
-- | Get the route we are using for this item
---
getRoute :: Compiler (Maybe FilePath)
-getRoute = getIdentifier >>> getRouteFor
+getRoute = getIdentifier >>= getRouteFor
+
+--------------------------------------------------------------------------------
-- | Get the route for a specified item
---
-getRouteFor :: Compiler (Identifier a -> Maybe FilePath)
-getRouteFor = fromJob $ \identifier -> CompilerM $ do
- routes <- compilerRoutes <$> ask
+getRouteFor :: Identifier -> Compiler (Maybe FilePath)
+getRouteFor identifier = do
+ routes <- compilerRoutes <$> compilerAsk
return $ runRoutes routes identifier
@@ -197,7 +65,6 @@ getResourceBody :: Compiler String
getResourceBody = getResourceWith resourceBody
-
--------------------------------------------------------------------------------
-- | Get the resource we are compiling as a string
getResourceString :: Compiler String
@@ -213,188 +80,65 @@ getResourceLBS = getResourceWith $ const resourceLBS
--------------------------------------------------------------------------------
-- | Overloadable function for 'getResourceString' and 'getResourceLBS'
-getResourceWith :: (ResourceProvider -> Identifier a -> IO b) -> Compiler b
-getResourceWith reader = fromJob $ \_ -> CompilerM $ do
- provider <- compilerResourceProvider <$> ask
- r <- compilerIdentifier <$> ask
- let filePath = toFilePath r
- if resourceExists provider r
- then liftIO $ reader provider $ castIdentifier r
- else throwError $ error' filePath
- where
- error' id' = "Hakyll.Core.Compiler.getResourceWith: resource "
- ++ show id' ++ " not found"
-
--- | Auxiliary: get a dependency
---
-getDependency :: (Binary a, Writable a, Typeable a)
- => Identifier a -> CompilerM a
-getDependency id' = CompilerM $ do
- store <- compilerStore <$> ask
- result <- liftIO $
- Store.get store ["Hakyll.Core.Compiler.runCompiler", show id']
- case result of
- Store.NotFound -> throwError notFound
- Store.WrongType e r -> throwError $ wrongType e r
- Store.Found x -> return x
- where
- notFound =
- "Hakyll.Core.Compiler.getDependency: " ++ show id' ++ " was " ++
- "not found in the cache, the cache might be corrupted or " ++
- "the item you are referring to might not exist"
- wrongType e r =
- "Hakyll.Core.Compiler.getDependency: " ++ show id' ++ " was found " ++
- "in the cache, but does not have the right type: expected " ++ show e ++
- " but got " ++ show r
-
--- | Variant of 'require' which drops the current value
---
-require_ :: (Binary a, Typeable a, Writable a)
- => Identifier a
- -> Compiler a
-require_ identifier =
- fromDependency identifier >>> fromJob (const $ getDependency identifier)
-
--- | Require another target. Using this function ensures automatic handling of
--- dependencies
---
-{-
-require :: (Binary a, Typeable a, Writable a)
- => Identifier a
- -> (b -> a -> c)
- -> Compiler b c
-require identifier = requireA identifier . arr . uncurry
-
--- | Arrow-based variant of 'require'
---
-requireA :: (Binary a, Typeable a, Writable a)
- => Identifier a
- -> Compiler (b, a) c
- -> Compiler b c
-requireA identifier = (id &&& require_ identifier >>>)
--}
-
--- | Variant of 'requireAll' which drops the current value
---
-requireAll_ :: (Binary a, Typeable a, Writable a)
- => Pattern a
- -> Compiler [a]
-requireAll_ pattern = fromDependencies (const getDeps) *> fromJob requireAll_'
+getResourceWith :: (ResourceProvider -> Identifier -> IO a) -> Compiler a
+getResourceWith reader = do
+ provider <- compilerProvider <$> compilerAsk
+ id' <- compilerIdentifier <$> compilerAsk
+ let filePath = toFilePath id'
+ if resourceExists provider id'
+ then compilerUnsafeIO $ reader provider id'
+ else compilerThrow $ error' filePath
where
- getDeps = map castIdentifier . filterMatches pattern . map castIdentifier
- requireAll_' = const $ CompilerM $ do
- deps <- getDeps . compilerUniverse <$> ask
- mapM (unCompilerM . getDependency) deps
+ error' fp = "Hakyll.Core.Compiler.getResourceWith: resource " ++
+ show fp ++ " not found"
--- | Require a number of targets. Using this function ensures automatic handling
--- of dependencies
---
-{-
-requireAll :: (Binary a, Typeable a, Writable a)
- => Pattern a
- -> (b -> [a] -> c)
- -> Compiler b c
-requireAll pattern = requireAllA pattern . arr . uncurry
-
--- | Arrow-based variant of 'requireAll'
---
-requireAllA :: (Binary a, Typeable a, Writable a)
- => Pattern a
- -> Compiler (b, [a]) c
- -> Compiler b c
-requireAllA pattern = (id &&& requireAll_ pattern >>>)
--}
+--------------------------------------------------------------------------------
cached :: (Binary a, Typeable a, Writable a)
=> String
-> Compiler a
-> Compiler a
-cached name (Compiler d j) = Compiler d $ CompilerM $ do
- logger <- compilerLogger <$> ask
- identifier <- castIdentifier . compilerIdentifier <$> ask
- store <- compilerStore <$> ask
- modified <- compilerResourceModified <$> ask
- progName <- liftIO getProgName
- report logger $ "Checking cache: " ++ if modified then "modified" else "OK"
+cached name compiler = do
+ logger <- compilerLogger <$> compilerAsk
+ id' <- compilerIdentifier <$> compilerAsk
+ store <- compilerStore <$> compilerAsk
+ provider <- compilerProvider <$> compilerAsk
+ modified <- compilerUnsafeIO $ resourceModified provider id'
+ compilerUnsafeIO $ report logger $
+ "Checking cache: " ++ if modified then "modified" else "OK"
if modified
- then do v <- unCompilerM $ j ()
- liftIO $ Store.set store [name, show identifier] v
- return v
- else do v <- liftIO $ Store.get store [name, show identifier]
- case v of Store.Found v' -> return v'
- _ -> throwError (error' progName)
+ then do
+ x <- compiler
+ compilerUnsafeIO $ Store.set store [name, show id'] x
+ return x
+ else do
+ x <- compilerUnsafeIO $ Store.get store [name, show id']
+ progName <- compilerUnsafeIO getProgName
+ case x of Store.Found x' -> return x'
+ _ -> compilerThrow (error' progName)
where
error' progName =
"Hakyll.Core.Compiler.cached: Cache corrupt! " ++
"Try running: " ++ progName ++ " clean"
--- | Create an unsafe compiler from a function in IO
---
-unsafeCompiler :: (a -> IO b) -- ^ Function to lift
- -> Compiler (a -> b) -- ^ Resulting compiler
-unsafeCompiler f = fromJob $ CompilerM . liftIO . f
--- | Compiler for debugging purposes
---
-traceShowCompiler :: Show a => Compiler a a
-traceShowCompiler = fromJob $ \x -> CompilerM $ do
- logger <- compilerLogger <$> ask
- report logger $ show x
- return x
+--------------------------------------------------------------------------------
+unsafeCompiler :: IO a -> Compiler a
+unsafeCompiler = compilerUnsafeIO
--- | Log and time a compiler
---
-timedCompiler :: String -- ^ Message
- -> Compiler a b -- ^ Compiler to time
- -> Compiler a b -- ^ Resulting compiler
-timedCompiler msg (Compiler d j) = Compiler d $ \x -> CompilerM $ do
- logger <- compilerLogger <$> ask
- timed logger msg $ unCompilerM $ j x
--- | Choose a compiler by identifier
---
--- For example, assume that most content files need to be compiled
--- normally, but a select few need an extra step in the pipeline:
---
--- > compile $ pageCompiler >>> byPattern id
--- > [ ("projects.md", addProjectListCompiler)
--- > , ("sitemap.md", addSiteMapCompiler)
--- > ]
---
-byPattern :: Compiler a b -- ^ Default compiler
- -> [(Pattern (), Compiler a b)] -- ^ Choices
- -> Compiler a b -- ^ Resulting compiler
-byPattern defaultCompiler choices = Compiler deps job
- where
- -- Lookup the compiler, give an error when it is not found
- lookup' identifier = maybe defaultCompiler snd $
- find (\(p, _) -> matches p identifier) choices
- -- Collect the dependencies of the choice
- deps = do
- identifier <- castIdentifier . dependencyIdentifier <$> ask
- compilerDependencies $ lookup' identifier
- -- Collect the job of the choice
- job x = CompilerM $ do
- identifier <- castIdentifier . compilerIdentifier <$> ask
- unCompilerM $ compilerJob (lookup' identifier) x
+--------------------------------------------------------------------------------
+-- | Compiler for debugging purposes
+logCompiler :: String -> Compiler ()
+logCompiler msg = do
+ logger <- compilerLogger <$> compilerAsk
+ compilerUnsafeIO $ report logger msg
--- | Choose a compiler by extension
---
--- Example:
---
--- > match "css/*" $ do
--- > route $ setExtension "css"
--- > compile $ byExtension (error "Not a (S)CSS file")
--- > [ (".css", compressCssCompiler)
--- > , (".scss", sass)
--- > ]
---
--- This piece of code will select the @compressCssCompiler@ for @.css@ files,
--- and the @sass@ compiler (defined elsewhere) for @.scss@ files.
---
-byExtension :: Compiler a b -- ^ Default compiler
- -> [(String, Compiler a b)] -- ^ Choices
- -> Compiler a b -- ^ Resulting compiler
-byExtension defaultCompiler = byPattern defaultCompiler . map (first extPattern)
- where
- extPattern c = predicate $ (== c) . takeExtension . toFilePath
+
+--------------------------------------------------------------------------------
+-- | Log and time a compiler
+timedCompiler :: String -- ^ Message
+ -> Compiler a -- ^ Compiler to time
+ -> Compiler a -- ^ Resulting compiler
+timedCompiler msg compiler = Compiler $ \r ->
+ timed (compilerLogger r) msg $ unCompiler compiler r
diff --git a/src/Hakyll/Core/Compiler/Internal.hs b/src/Hakyll/Core/Compiler/Internal.hs
index f211367..5b7fb51 100644
--- a/src/Hakyll/Core/Compiler/Internal.hs
+++ b/src/Hakyll/Core/Compiler/Internal.hs
@@ -5,19 +5,21 @@
module Hakyll.Core.Compiler.Internal
( CompilerRead (..)
, CompilerResult (..)
- , Compiler
+ , Compiler (..)
, runCompiler
, compilerTell
, compilerAsk
, compilerThrow
, compilerCatch
, compilerResult
+ , compilerUnsafeIO
) where
--------------------------------------------------------------------------------
import Control.Applicative (Alternative (..),
Applicative (..))
+import Control.Exception (SomeException, handle)
import Data.Monoid (mappend, mempty)
@@ -34,19 +36,17 @@ import Hakyll.Core.Store
-- | Environment in which a compiler runs
data CompilerRead = CompilerRead
{ -- | Target identifier
- compilerIdentifier :: Identifier
+ compilerIdentifier :: Identifier
, -- | Resource provider
- compilerResourceProvider :: ResourceProvider
+ compilerProvider :: ResourceProvider
, -- | List of all known identifiers
- compilerUniverse :: [Identifier]
+ compilerUniverse :: [Identifier]
, -- | Site routes
- compilerRoutes :: Routes
+ compilerRoutes :: Routes
, -- | Compiler store
- compilerStore :: Store
- , -- | Flag indicating if the underlying resource was modified
- compilerResourceModified :: Bool
+ compilerStore :: Store
, -- | Logger
- compilerLogger :: Logger
+ compilerLogger :: Logger
}
@@ -111,7 +111,10 @@ instance Applicative Compiler where
--------------------------------------------------------------------------------
runCompiler :: Compiler a -> CompilerRead -> IO (CompilerResult a)
-runCompiler = unCompiler
+runCompiler compiler read' = handle handler $ unCompiler compiler read'
+ where
+ handler :: SomeException -> IO (CompilerResult a)
+ handler e = return $ CompilerError $ show e
--------------------------------------------------------------------------------
@@ -128,7 +131,7 @@ compilerAsk = Compiler $ \r -> return $ CompilerDone r mempty
--------------------------------------------------------------------------------
-compilerTell :: [Dependency] -> Compiler ()
+compilerTell :: CompilerWrite -> Compiler ()
compilerTell deps = Compiler $ \_ -> return $ CompilerDone () deps
{-# INLINE compilerTell #-}
@@ -154,3 +157,11 @@ compilerCatch (Compiler x) f = Compiler $ \r -> do
compilerResult :: CompilerResult a -> Compiler a
compilerResult x = Compiler $ \_ -> return x
{-# INLINE compilerResult #-}
+
+
+--------------------------------------------------------------------------------
+compilerUnsafeIO :: IO a -> Compiler a
+compilerUnsafeIO io = Compiler $ \_ -> do
+ x <- io
+ return $ CompilerDone x mempty
+{-# INLINE compilerUnsafeIO #-}
diff --git a/src/Hakyll/Core/Compiler/Require.hs b/src/Hakyll/Core/Compiler/Require.hs
new file mode 100644
index 0000000..1dc96e7
--- /dev/null
+++ b/src/Hakyll/Core/Compiler/Require.hs
@@ -0,0 +1,63 @@
+--------------------------------------------------------------------------------
+module Hakyll.Core.Compiler.Require
+ ( save
+ , require
+ , requireAll
+ ) where
+
+
+--------------------------------------------------------------------------------
+import Control.Applicative ((<$>))
+import Data.Binary (Binary)
+import Data.Typeable
+
+
+--------------------------------------------------------------------------------
+import Hakyll.Core.Compiler.Internal
+import Hakyll.Core.Dependencies
+import Hakyll.Core.Identifier
+import Hakyll.Core.Identifier.Pattern
+import Hakyll.Core.Store (Store)
+import qualified Hakyll.Core.Store as Store
+
+
+--------------------------------------------------------------------------------
+save :: (Binary a, Typeable a) => Store -> Identifier -> a -> IO ()
+save store identifier x = Store.set store (key identifier) x
+
+
+--------------------------------------------------------------------------------
+require :: (Binary a, Typeable a) => Identifier -> Compiler a
+require id' = do
+ store <- compilerStore <$> compilerAsk
+
+ compilerTell [Identifier id']
+ compilerResult $ CompilerRequire id' $ do
+ result <- compilerUnsafeIO $ Store.get store (key id')
+ case result of
+ Store.NotFound -> compilerThrow notFound
+ Store.WrongType e r -> compilerThrow $ wrongType e r
+ Store.Found x -> return x
+ where
+ notFound =
+ "Hakyll.Core.Compiler.Require.require: " ++ show id' ++ " was " ++
+ "not found in the cache, the cache might be corrupted or " ++
+ "the item you are referring to might not exist"
+ wrongType e r =
+ "Hakyll.Core.Compiler.Require.require: " ++ show id' ++ " was found " ++
+ "in the cache, but does not have the right type: expected " ++ show e ++
+ " but got " ++ show r
+
+
+--------------------------------------------------------------------------------
+requireAll :: (Binary a, Typeable a) => Pattern -> Compiler [a]
+requireAll pattern = do
+ universe <- compilerUniverse <$> compilerAsk
+ let matching = filterMatches pattern universe
+ compilerTell [Pattern pattern matching]
+ mapM require matching
+
+
+--------------------------------------------------------------------------------
+key :: Identifier -> [String]
+key identifier = ["Hakyll.Core.Compiler.Require", show identifier]
diff --git a/src/Hakyll/Core/Runtime.hs b/src/Hakyll/Core/Runtime.hs
index e9fb6cd..7354119 100644
--- a/src/Hakyll/Core/Runtime.hs
+++ b/src/Hakyll/Core/Runtime.hs
@@ -23,6 +23,7 @@ import System.FilePath ((</>))
--------------------------------------------------------------------------------
import Hakyll.Core.CompiledItem
import Hakyll.Core.Compiler.Internal
+import Hakyll.Core.Compiler.Require
import Hakyll.Core.Configuration
import Hakyll.Core.Dependencies
import Hakyll.Core.Identifier
@@ -159,16 +160,14 @@ chase trail id'
config <- runtimeConfiguration <$> ask
section logger $ "Processing " ++ show id'
- isModified <- liftIO $ resourceModified provider id'
let compiler = todo M.! id'
read' = CompilerRead
- { compilerIdentifier = id'
- , compilerResourceProvider = provider
- , compilerUniverse = map fst universe
- , compilerRoutes = routes
- , compilerStore = store
- , compilerResourceModified = isModified
- , compilerLogger = logger
+ { compilerIdentifier = id'
+ , compilerProvider = provider
+ , compilerUniverse = map fst universe
+ , compilerRoutes = routes
+ , compilerStore = store
+ , compilerLogger = logger
}
result <- timed logger "Compiling" $ liftIO $ runCompiler compiler read'
@@ -177,7 +176,7 @@ chase trail id'
CompilerError e -> throwError e
-- Huge success
- CompilerDone compiled facts -> do
+ CompilerDone (CompiledItem compiled) facts -> do
-- Write if necessary
case runRoutes routes id' of
Nothing -> return ()
@@ -186,6 +185,9 @@ chase trail id'
liftIO $ makeDirectories path
liftIO $ write path compiled
+ -- Save! (For require)
+ liftIO $ save store id' compiled
+
-- Update state
modify $ \s -> s
{ runtimeDone = S.insert id' (runtimeDone s)
diff --git a/src/Hakyll/Core/UnixFilter.hs b/src/Hakyll/Core/UnixFilter.hs
index dcbbaaf..e86c58a 100644
--- a/src/Hakyll/Core/UnixFilter.hs
+++ b/src/Hakyll/Core/UnixFilter.hs
@@ -1,29 +1,32 @@
+--------------------------------------------------------------------------------
-- | A Compiler that supports unix filters.
---
module Hakyll.Core.UnixFilter
( unixFilter
, unixFilterLBS
) where
-import Control.Concurrent (forkIO)
-import System.Posix.Process (executeFile, forkProcess)
-import System.Posix.IO ( dupTo, createPipe, stdInput
- , stdOutput, closeFd, fdToHandle
- )
-import System.IO ( Handle, hPutStr, hClose, hGetContents
- , hSetEncoding, localeEncoding
- )
-import Data.ByteString.Lazy (ByteString)
+--------------------------------------------------------------------------------
+import Control.Concurrent (forkIO)
+import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as LB
+import System.IO (Handle, hClose, hGetContents, hPutStr,
+ hSetEncoding, localeEncoding)
+import System.Posix.IO (closeFd, createPipe, dupTo, fdToHandle,
+ stdInput, stdOutput)
+import System.Posix.Process (executeFile, forkProcess)
+
+
+--------------------------------------------------------------------------------
+import Hakyll.Core.Compiler
-import Hakyll.Core.Compiler
+--------------------------------------------------------------------------------
-- | Use a unix filter as compiler. For example, we could use the 'rev' program
-- as a compiler.
--
--- > rev :: Compiler Resource String
--- > rev = getResourceString >>> unixFilter "rev" []
+-- > rev :: Compiler String
+-- > rev = getResourceString >>= unixFilter "rev" []
--
-- A more realistic example: one can use this to call, for example, the sass
-- compiler on CSS files. More information about sass can be found here:
@@ -34,12 +37,13 @@ import Hakyll.Core.Compiler
--
-- > match "style.scss" $ do
-- > route $ setExtension "css"
--- > compile $ getResourceString >>> unixFilter "sass" ["-s", "--scss"]
--- > >>> arr compressCss
---
-unixFilter :: String -- ^ Program name
- -> [String] -- ^ Program args
- -> Compiler String String -- ^ Resulting compiler
+-- > compile $ getResourceString >>=
+-- > unixFilter "sass" ["-s", "--scss"] >>=
+-- > compressCssCompiler
+unixFilter :: String -- ^ Program name
+ -> [String] -- ^ Program args
+ -> String -- ^ Program input
+ -> Compiler String -- ^ Program output
unixFilter = unixFilterWith writer reader
where
writer handle input = do
@@ -49,30 +53,35 @@ unixFilter = unixFilterWith writer reader
hSetEncoding handle localeEncoding
hGetContents handle
+
+--------------------------------------------------------------------------------
-- | Variant of 'unixFilter' that should be used for binary files
--
-- > match "music.wav" $ do
-- > route $ setExtension "ogg"
--- > compile $ getResourceLBS >>> unixFilter "oggenc" ["-"]
---
-unixFilterLBS :: String -- ^ Program name
- -> [String] -- ^ Program args
- -> Compiler ByteString ByteString -- ^ Resulting compiler
+-- > compile $ getResourceLBS >>= unixFilter "oggenc" ["-"]
+unixFilterLBS :: String -- ^ Program name
+ -> [String] -- ^ Program args
+ -> ByteString -- ^ Program input
+ -> Compiler ByteString -- ^ Program output
unixFilterLBS = unixFilterWith LB.hPutStr LB.hGetContents
+
+--------------------------------------------------------------------------------
-- | Overloaded compiler
---
unixFilterWith :: (Handle -> i -> IO ()) -- ^ Writer
-> (Handle -> IO o) -- ^ Reader
-> String -- ^ Program name
-> [String] -- ^ Program args
- -> Compiler i o -- ^ Resulting compiler
-unixFilterWith writer reader programName args =
+ -> i -- ^ Program input
+ -> Compiler o -- ^ Program output
+unixFilterWith writer reader programName args input =
timedCompiler ("Executing external program " ++ programName) $
- unsafeCompiler $ unixFilterIO writer reader programName args
+ unsafeCompiler $ unixFilterIO writer reader programName args input
+
+--------------------------------------------------------------------------------
-- | Internally used function
---
unixFilterIO :: (Handle -> i -> IO ())
-> (Handle -> IO o)
-> String
@@ -83,7 +92,7 @@ unixFilterIO writer reader programName args input = do
-- Create pipes
(stdinRead, stdinWrite) <- createPipe
(stdoutRead, stdoutWrite) <- createPipe
-
+
-- Fork the child
_ <- forkProcess $ do
-- Copy our pipes over the regular stdin/stdout
diff --git a/src/Hakyll/Core/Writable/CopyFile.hs b/src/Hakyll/Core/Writable/CopyFile.hs
index 6cc08f2..2d92891 100644
--- a/src/Hakyll/Core/Writable/CopyFile.hs
+++ b/src/Hakyll/Core/Writable/CopyFile.hs
@@ -1,6 +1,7 @@
--------------------------------------------------------------------------------
-- | Exports simple compilers to just copy files
-{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Hakyll.Core.Writable.CopyFile
( CopyFile (..)
, copyFileCompiler
@@ -8,16 +9,16 @@ module Hakyll.Core.Writable.CopyFile
--------------------------------------------------------------------------------
-import Control.Arrow ((>>^))
-import System.Directory (copyFile)
-import Data.Typeable (Typeable)
-import Data.Binary (Binary)
+import Control.Applicative ((<$>))
+import Data.Binary (Binary)
+import Data.Typeable (Typeable)
+import System.Directory (copyFile)
--------------------------------------------------------------------------------
-import Hakyll.Core.Writable
-import Hakyll.Core.Compiler
-import Hakyll.Core.Identifier
+import Hakyll.Core.Compiler
+import Hakyll.Core.Identifier
+import Hakyll.Core.Writable
--------------------------------------------------------------------------------
@@ -32,5 +33,5 @@ instance Writable CopyFile where
--------------------------------------------------------------------------------
-copyFileCompiler :: Compiler a CopyFile
-copyFileCompiler = getIdentifier >>^ CopyFile . toFilePath
+copyFileCompiler :: Compiler CopyFile
+copyFileCompiler = CopyFile . toFilePath <$> getIdentifier
diff --git a/src/Hakyll/Core/Writable/WritableTuple.hs b/src/Hakyll/Core/Writable/WritableTuple.hs
deleted file mode 100644
index 741d2c7..0000000
--- a/src/Hakyll/Core/Writable/WritableTuple.hs
+++ /dev/null
@@ -1,37 +0,0 @@
--- | This module exposes a writable type 'WritableTuple' which is a simple
--- newtype wrapper around a tuple.
---
--- The idea is that, given a tuple @(a, b)@, @a@ is the value you actually want
--- to save to the disk, and @b@ is some additional info that you /don't/ want to
--- save, but that you need later, for example in a 'require' clause.
---
-{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
-module Hakyll.Core.Writable.WritableTuple
- ( WritableTuple (..)
- , writableTupleFst
- , writableTupleSnd
- , writableTupleCompiler
- ) where
-
-import Control.Arrow (arr)
-
-import Data.Typeable (Typeable)
-import Data.Binary (Binary)
-
-import Hakyll.Core.Writable
-import Hakyll.Core.Compiler
-
-newtype WritableTuple a b = WritableTuple {unWritableTuple :: (a, b)}
- deriving (Show, Eq, Ord, Binary, Typeable)
-
-instance Writable a => Writable (WritableTuple a b) where
- write dst (WritableTuple (x, _)) = write dst x
-
-writableTupleFst :: WritableTuple a b -> a
-writableTupleFst = fst . unWritableTuple
-
-writableTupleSnd :: WritableTuple a b -> b
-writableTupleSnd = snd . unWritableTuple
-
-writableTupleCompiler :: Compiler (a, b) (WritableTuple a b)
-writableTupleCompiler = arr WritableTuple