packages feed

hakyll 3.0.2.2 → 3.1.0.0

raw patch · 21 files changed

+313/−197 lines, 21 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Hakyll.Core.Identifier.Pattern: doesMatch :: Pattern -> Identifier -> Bool
- Hakyll.Core.Identifier.Pattern: instance Eq Pattern
- Hakyll.Core.Identifier.Pattern: instance Eq PatternComponent
- Hakyll.Core.Identifier.Pattern: instance Show Pattern
- Hakyll.Core.Identifier.Pattern: instance Show PatternComponent
- Hakyll.Core.Identifier.Pattern: match :: Pattern -> Identifier -> Maybe [Identifier]
- Hakyll.Core.Identifier.Pattern: parsePattern :: String -> Pattern
- Hakyll.Core.ResourceProvider: Resource :: Identifier -> Resource
- Hakyll.Core.ResourceProvider: ResourceProvider :: [Resource] -> (Resource -> IO String) -> (Resource -> IO ByteString) -> ResourceProvider
- Hakyll.Core.ResourceProvider: data ResourceProvider
- Hakyll.Core.ResourceProvider: instance Eq Resource
- Hakyll.Core.ResourceProvider: instance Ord Resource
- Hakyll.Core.ResourceProvider: instance Show Resource
- Hakyll.Core.ResourceProvider: newtype Resource
- Hakyll.Core.ResourceProvider: resourceDigest :: ResourceProvider -> Resource -> IO [Word8]
- Hakyll.Core.ResourceProvider: resourceExists :: ResourceProvider -> Identifier -> Bool
- Hakyll.Core.ResourceProvider: resourceLazyByteString :: ResourceProvider -> Resource -> IO ByteString
- Hakyll.Core.ResourceProvider: resourceList :: ResourceProvider -> [Resource]
- Hakyll.Core.ResourceProvider: resourceModified :: ResourceProvider -> Resource -> Store -> IO Bool
- Hakyll.Core.ResourceProvider: resourceString :: ResourceProvider -> Resource -> IO String
- Hakyll.Core.ResourceProvider: unResource :: Resource -> Identifier
- Hakyll.Core.ResourceProvider.FileResourceProvider: fileResourceProvider :: HakyllConfiguration -> IO ResourceProvider
- Hakyll.Core.Routes: ifMatch :: Pattern -> Routes -> Routes
+ Hakyll.Core.Identifier.Pattern: capture :: Pattern -> Identifier -> Maybe [Identifier]
+ Hakyll.Core.Identifier.Pattern: filterMatches :: Pattern -> [Identifier] -> [Identifier]
+ Hakyll.Core.Identifier.Pattern: instance Eq GlobComponent
+ Hakyll.Core.Identifier.Pattern: instance Monoid Pattern
+ Hakyll.Core.Identifier.Pattern: instance Show GlobComponent
+ Hakyll.Core.Identifier.Pattern: parseGlob :: String -> Pattern
+ Hakyll.Core.Identifier.Pattern: predicate :: (Identifier -> Bool) -> Pattern
+ Hakyll.Core.Identifier.Pattern: regex :: String -> Pattern
+ Hakyll.Core.Resource: Resource :: Identifier -> Resource
+ Hakyll.Core.Resource: instance Eq Resource
+ Hakyll.Core.Resource: instance Ord Resource
+ Hakyll.Core.Resource: instance Show Resource
+ Hakyll.Core.Resource: newtype Resource
+ Hakyll.Core.Resource: unResource :: Resource -> Identifier
+ Hakyll.Core.Resource.Provider: ResourceProvider :: [Resource] -> (Resource -> IO String) -> (Resource -> IO ByteString) -> MVar (Map Resource Bool) -> ResourceProvider
+ Hakyll.Core.Resource.Provider: data ResourceProvider
+ Hakyll.Core.Resource.Provider: resourceDigest :: ResourceProvider -> Resource -> IO [Word8]
+ Hakyll.Core.Resource.Provider: resourceExists :: ResourceProvider -> Identifier -> Bool
+ Hakyll.Core.Resource.Provider: resourceLazyByteString :: ResourceProvider -> Resource -> IO ByteString
+ Hakyll.Core.Resource.Provider: resourceList :: ResourceProvider -> [Resource]
+ Hakyll.Core.Resource.Provider: resourceModified :: ResourceProvider -> Resource -> Store -> IO Bool
+ Hakyll.Core.Resource.Provider: resourceModifiedCache :: ResourceProvider -> MVar (Map Resource Bool)
+ Hakyll.Core.Resource.Provider: resourceString :: ResourceProvider -> Resource -> IO String
+ Hakyll.Core.Resource.Provider.File: fileResourceProvider :: HakyllConfiguration -> IO ResourceProvider
+ Hakyll.Core.Routes: matchRoute :: Pattern -> Routes -> Routes
+ Hakyll.Core.Rules: match :: Pattern -> Rules -> Rules
- Hakyll.Core.Identifier.Pattern: matches :: Pattern -> [Identifier] -> [Identifier]
+ Hakyll.Core.Identifier.Pattern: matches :: Pattern -> Identifier -> Bool
- Hakyll.Core.Rules: compile :: (Binary a, Typeable a, Writable a) => Pattern -> Compiler Resource a -> Rules
+ Hakyll.Core.Rules: compile :: (Binary a, Typeable a, Writable a) => Compiler Resource a -> Rules
- Hakyll.Core.Rules: route :: Pattern -> Routes -> Rules
+ Hakyll.Core.Rules: route :: Routes -> Rules
- Hakyll.Web.Tags: Tags :: Map String [Page a] -> Tags a
+ Hakyll.Web.Tags: Tags :: [(String, [Page a])] -> Tags a
- Hakyll.Web.Tags: tagsMap :: Tags a -> Map String [Page a]
+ Hakyll.Web.Tags: tagsMap :: Tags a -> [(String, [Page a])]

Files

hakyll.cabal view
@@ -1,5 +1,5 @@ Name:               hakyll-Version:            3.0.2.2+Version:            3.1.0.0  Synopsis:           A simple static site generator library. Description:        A simple static site generator library, mainly aimed at@@ -81,14 +81,15 @@                       Hakyll.Web.RelativizeUrls                       Hakyll.Web.Page.Read                       Hakyll.Web.Page.Metadata-                      Hakyll.Core.ResourceProvider.FileResourceProvider                       Hakyll.Core.Configuration                       Hakyll.Core.Identifier.Pattern                       Hakyll.Core.UnixFilter                       Hakyll.Core.Util.Arrow                       Hakyll.Core.Util.File                       Hakyll.Core.Util.String-                      Hakyll.Core.ResourceProvider+                      Hakyll.Core.Resource+                      Hakyll.Core.Resource.Provider+                      Hakyll.Core.Resource.Provider.File                       Hakyll.Core.CompiledItem                       Hakyll.Core.Compiler                       Hakyll.Core.Run
src-inotify/Hakyll/Web/Preview/Poll.hs view
@@ -13,7 +13,7 @@ import System.INotify  import Hakyll.Core.Configuration-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource import Hakyll.Core.Identifier  -- | Calls the given callback when the directory tree changes
src-interval/Hakyll/Web/Preview/Poll.hs view
@@ -15,7 +15,7 @@  import Hakyll.Core.Configuration import Hakyll.Core.Identifier-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource  -- | A preview thread that periodically recompiles the site. --
src/Hakyll.hs view
@@ -5,7 +5,8 @@     , module Hakyll.Core.Configuration     , module Hakyll.Core.Identifier     , module Hakyll.Core.Identifier.Pattern-    , module Hakyll.Core.ResourceProvider+    , module Hakyll.Core.Resource+    , module Hakyll.Core.Resource.Provider     , module Hakyll.Core.Routes     , module Hakyll.Core.Rules     , module Hakyll.Core.UnixFilter@@ -34,7 +35,8 @@ import Hakyll.Core.Configuration import Hakyll.Core.Identifier import Hakyll.Core.Identifier.Pattern-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource+import Hakyll.Core.Resource.Provider import Hakyll.Core.Routes import Hakyll.Core.Rules import Hakyll.Core.UnixFilter
src/Hakyll/Core/Compiler.hs view
@@ -124,7 +124,8 @@ import Hakyll.Core.Identifier.Pattern import Hakyll.Core.CompiledItem import Hakyll.Core.Writable-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource+import Hakyll.Core.Resource.Provider import Hakyll.Core.Compiler.Internal import Hakyll.Core.Store import Hakyll.Core.Rules.Internal@@ -237,7 +238,7 @@             -> Compiler b [a] requireAll_ pattern = fromDependencies (const getDeps) >>> fromJob requireAll_'   where-    getDeps = matches pattern . map unResource . resourceList+    getDeps = filterMatches pattern . map unResource . resourceList     requireAll_' = const $ CompilerM $ do         deps <- getDeps . compilerResourceProvider <$> ask         mapM (unCompilerM . getDependency) deps
src/Hakyll/Core/Compiler/Internal.hs view
@@ -26,7 +26,7 @@ import Control.Arrow (Arrow, ArrowChoice, arr, first, left)  import Hakyll.Core.Identifier-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource.Provider import Hakyll.Core.Store import Hakyll.Core.Routes import Hakyll.Core.Logger
src/Hakyll/Core/Identifier/Pattern.hs view
@@ -1,5 +1,13 @@ -- | Module providing pattern matching and capturing on 'Identifier's.+-- 'Pattern's come in two kinds: --+-- * Simple glob patterns, like @foo\/*@;+--+-- * Custom, arbitrary predicates of the type @Identifier -> Bool@.+--+-- They both have advantages and disadvantages. By default, globs are used,+-- unless you construct your 'Pattern' using the 'predicate' function.+-- -- A very simple pattern could be, for example, @foo\/bar@. This pattern will -- only match the exact @foo\/bar@ identifier. --@@ -20,15 +28,17 @@ -- -- * @foo\/*.html@ will match all HTML files in the @foo\/@ directory. ----- The 'match' function allows the user to get access to the elements captured+-- The 'capture' function allows the user to get access to the elements captured -- by the capture elements in the pattern. -- module Hakyll.Core.Identifier.Pattern     ( Pattern-    , parsePattern-    , match-    , doesMatch+    , parseGlob+    , predicate+    , regex     , matches+    , filterMatches+    , capture     , fromCapture     , fromCaptureString     , fromCaptures@@ -37,32 +47,39 @@ import Data.List (isPrefixOf, inits, tails) import Control.Arrow ((&&&), (>>>)) import Control.Monad (msum)-import Data.Maybe (isJust)-import Data.Monoid (mempty, mappend)+import Data.Maybe (isJust, fromMaybe)+import Data.Monoid (Monoid, mempty, mappend)  import GHC.Exts (IsString, fromString)+import Text.Regex.PCRE ((=~~))  import Hakyll.Core.Identifier  -- | One base element of a pattern ---data PatternComponent = Capture-                      | CaptureMany-                      | Literal String-                      deriving (Eq, Show)+data GlobComponent = Capture+                   | CaptureMany+                   | Literal String+                   deriving (Eq, Show)  -- | Type that allows matching on identifiers ---newtype Pattern = Pattern {unPattern :: [PatternComponent]}-                deriving (Eq, Show)+data Pattern = Glob [GlobComponent]+             | Predicate (Identifier -> Bool)  instance IsString Pattern where-    fromString = parsePattern+    fromString = parseGlob +instance Monoid Pattern where+    mempty = Predicate (const True)+    g@(Glob _)  `mappend` x           = Predicate (matches g) `mappend` x+    x           `mappend` g@(Glob _)  = x `mappend` Predicate (matches g)+    Predicate f `mappend` Predicate g = Predicate $ \i -> f i && g i+ -- | Parse a pattern from a string ---parsePattern :: String -> Pattern-parsePattern = Pattern . parse' -- undefined -- Pattern . map toPattern . unIdentifier . parseIdentifier+parseGlob :: String -> Pattern+parseGlob = Glob . parse'   where     parse' str =         let (chunk, rest) = break (`elem` "\\*") str@@ -72,20 +89,34 @@             ('*'  : xs)       -> Literal chunk : Capture : parse' xs             xs                -> Literal chunk : Literal xs : [] --- | Match an identifier against a pattern, generating a list of captures+-- | Create a 'Pattern' from an arbitrary predicate ---match :: Pattern -> Identifier -> Maybe [Identifier]-match p (Identifier i) = fmap (map Identifier) $ match' (unPattern p) i+-- Example:+--+-- > predicate (\i -> matches "foo/*" i && not (matches "foo/bar" i))+--+predicate :: (Identifier -> Bool) -> Pattern+predicate = Predicate +-- | Create a 'Pattern' from a regex+--+-- Example:+--+-- > regex "^foo/[^x]*$+--+regex :: String -> Pattern+regex str = predicate $ fromMaybe False . (=~~ str) . toFilePath+ -- | Check if an identifier matches a pattern ---doesMatch :: Pattern -> Identifier -> Bool-doesMatch p = isJust . match p+matches :: Pattern -> Identifier -> Bool+matches (Glob p)      = isJust . capture (Glob p)+matches (Predicate p) = (p $)  -- | Given a list of identifiers, retain only those who match the given pattern ---matches :: Pattern -> [Identifier] -> [Identifier]-matches p = filter (doesMatch p)+filterMatches :: Pattern -> [Identifier] -> [Identifier]+filterMatches = filter . matches  -- | Split a list at every possible point, generate a list of (init, tail) -- cases. The result is sorted with inits decreasing in length.@@ -93,30 +124,35 @@ splits :: [a] -> [([a], [a])] splits = inits &&& tails >>> uncurry zip >>> reverse --- | Internal verion of 'match'+-- | Match a glob against a pattern, generating a list of captures ---match' :: [PatternComponent] -> String -> Maybe [String]-match' [] [] = Just []  -- An empty match-match' [] _  = Nothing  -- No match--- match' _  [] = Nothing   -- No match-match' (Literal l : ms) str+capture :: Pattern -> Identifier -> Maybe [Identifier]+capture (Glob p) (Identifier i) = fmap (map Identifier) $ capture' p i+capture (Predicate _) _         = Nothing++-- | Internal verion of 'capture'+--+capture' :: [GlobComponent] -> String -> Maybe [String]+capture' [] [] = Just []  -- An empty match+capture' [] _  = Nothing  -- No match+capture' (Literal l : ms) str     -- Match the literal against the string-    | l `isPrefixOf` str = match' ms $ drop (length l) str+    | l `isPrefixOf` str = capture' ms $ drop (length l) str     | otherwise          = Nothing-match' (Capture : ms) str =+capture' (Capture : ms) str =     -- Match until the next /     let (chunk, rest) = break (== '/') str-    in msum $ [ fmap (i :) (match' ms (t ++ rest)) | (i, t) <- splits chunk ]-match' (CaptureMany : ms) str =+    in msum $ [ fmap (i :) (capture' ms (t ++ rest)) | (i, t) <- splits chunk ]+capture' (CaptureMany : ms) str =     -- Match everything-    msum $ [ fmap (i :) (match' ms t) | (i, t) <- splits str ]+    msum $ [ fmap (i :) (capture' ms t) | (i, t) <- splits str ]      -- | Create an identifier from a pattern by filling in the captures with a given -- string -- -- Example: ----- > fromCapture (parsePattern "tags/*") (parseIdentifier "foo")+-- > fromCapture (parseGlob "tags/*") (parseIdentifier "foo") -- -- Result: --@@ -128,7 +164,7 @@ -- | Simplified version of 'fromCapture' which takes a 'String' instead of an -- 'Identifier' ----- > fromCaptureString (parsePattern "tags/*") "foo"+-- > fromCaptureString (parseGlob "tags/*") "foo" -- -- Result: --@@ -141,11 +177,19 @@ -- given list of strings -- fromCaptures :: Pattern -> [Identifier] -> Identifier-fromCaptures (Pattern []) _ = mempty-fromCaptures (Pattern (m : ms)) [] = case m of-    Literal l -> Identifier l `mappend` fromCaptures (Pattern ms) []-    _         -> error $  "Hakyll.Core.Identifier.Pattern.fromCaptures: "+fromCaptures (Glob p)      = fromCaptures' p+fromCaptures (Predicate _) = error $+    "Hakyll.Core.Identifier.Pattern.fromCaptures: fromCaptures called on a " +++    "predicate instead of a glob"++-- | Internally used version of 'fromCaptures'+--+fromCaptures' :: [GlobComponent] -> [Identifier] -> Identifier+fromCaptures' []        _ = mempty+fromCaptures' (m : ms) [] = case m of+    Literal l -> Identifier l `mappend` fromCaptures' ms []+    _         -> error $  "Hakyll.Core.Identifier.Pattern.fromCaptures': "                        ++ "identifier list exhausted"-fromCaptures (Pattern (m : ms)) ids@(i : is) = case m of-    Literal l -> Identifier l `mappend` fromCaptures (Pattern ms) ids-    _         -> i `mappend` fromCaptures (Pattern ms) is+fromCaptures' (m : ms) ids@(i : is) = case m of+    Literal l -> Identifier l `mappend` fromCaptures' ms ids+    _         -> i `mappend` fromCaptures' ms is
+ src/Hakyll/Core/Resource.hs view
@@ -0,0 +1,14 @@+-- | Module exporting the simple 'Resource' type+--+module Hakyll.Core.Resource+    ( Resource (..)+    ) where++import Hakyll.Core.Identifier++-- | A resource+--+-- Invariant: the resource specified by the given identifier must exist+--+newtype Resource = Resource {unResource :: Identifier}+                 deriving (Eq, Show, Ord)
+ src/Hakyll/Core/Resource/Provider.hs view
@@ -0,0 +1,91 @@+-- | This module provides an API for resource providers. Resource providers+-- allow Hakyll to get content from resources; the type of resource depends on+-- the concrete instance.+--+-- A resource is represented by the 'Resource' type. This is basically just a+-- newtype wrapper around 'Identifier' -- but it has an important effect: it+-- guarantees that a resource with this identifier can be provided by one or+-- more resource providers.+--+-- Therefore, it is not recommended to read files directly -- you should use the+-- provided 'Resource' methods.+--+module Hakyll.Core.Resource.Provider+    ( ResourceProvider (..)+    , resourceExists+    , resourceDigest+    , resourceModified+    ) where++import Control.Concurrent (MVar, readMVar, modifyMVar_)+import Control.Monad ((<=<))+import Data.Word (Word8)+import Data.Map (Map)+import qualified Data.Map as M++import qualified Data.ByteString.Lazy as LB+import OpenSSL.Digest.ByteString.Lazy (digest)+import OpenSSL.Digest (MessageDigest (MD5))++import Hakyll.Core.Identifier+import Hakyll.Core.Store+import Hakyll.Core.Resource++-- | A value responsible for retrieving and listing resources+--+data ResourceProvider = ResourceProvider+    { -- | A list of all resources this provider is able to provide+      resourceList           :: [Resource]+    , -- | Retrieve a certain resource as string+      resourceString         :: Resource -> IO String+    , -- | Retrieve a certain resource as lazy bytestring+      resourceLazyByteString :: Resource -> IO LB.ByteString+    , -- | Cache keeping track of modified items+      resourceModifiedCache  :: MVar (Map Resource Bool)+    }++-- | Check if a given identifier has a resource+--+resourceExists :: ResourceProvider -> Identifier -> Bool+resourceExists provider = flip elem $ map unResource $ resourceList provider++-- | Retrieve a digest for a given resource+--+resourceDigest :: ResourceProvider -> Resource -> IO [Word8]+resourceDigest provider = digest MD5 <=< resourceLazyByteString provider++-- | Check if a resource was modified+--+resourceModified :: ResourceProvider -> Resource -> Store -> IO Bool+resourceModified provider resource store = do+    cache <- readMVar mvar+    case M.lookup resource cache of+        -- Already in the cache+        Just m  -> return m+        -- Not yet in the cache, check digests (if it exists)+        Nothing -> do+            m <- if resourceExists provider (unResource resource)+                        then digestModified provider resource store+                        else return False+            modifyMVar_ mvar (return . M.insert resource m)+            return m+  where+    mvar = resourceModifiedCache provider++-- | Check if a resource digest was modified+--+digestModified :: ResourceProvider -> Resource -> Store -> IO Bool+digestModified provider resource store = do+    -- Get the latest seen digest from the store+    lastDigest <- storeGet store itemName $ unResource resource+    -- Calculate the digest for the resource+    newDigest <- resourceDigest provider resource+    -- Check digests+    if Just newDigest == lastDigest+        -- All is fine, not modified+        then return False+        -- Resource modified; store new digest+        else do storeSet store itemName (unResource resource) newDigest+                return True+  where+    itemName = "Hakyll.Core.ResourceProvider.digestModified"
+ src/Hakyll/Core/Resource/Provider/File.hs view
@@ -0,0 +1,36 @@+-- | A concrete 'ResourceProvider' that gets it's resources from the filesystem+--+module Hakyll.Core.Resource.Provider.File+    ( fileResourceProvider+    ) where++import Control.Applicative ((<$>))+import Control.Concurrent (newMVar)+import qualified Data.Map as M++import qualified Data.ByteString.Lazy as LB++import Hakyll.Core.Resource+import Hakyll.Core.Resource.Provider+import Hakyll.Core.Identifier+import Hakyll.Core.Util.File+import Hakyll.Core.Configuration++-- | Create a filesystem-based 'ResourceProvider'+--+fileResourceProvider :: HakyllConfiguration -> IO ResourceProvider+fileResourceProvider configuration = do+    -- Retrieve a list of identifiers+    list <- map parseIdentifier . filter (not . ignoreFile configuration) <$>+        getRecursiveContents False "."++    -- MVar for the cache+    mvar <- newMVar M.empty++    -- Construct a resource provider+    return ResourceProvider+        { resourceList           = map Resource list+        , resourceString         = readFile . toFilePath . unResource+        , resourceLazyByteString = LB.readFile . toFilePath . unResource+        , resourceModifiedCache  = mvar+        }
− src/Hakyll/Core/ResourceProvider.hs
@@ -1,75 +0,0 @@--- | This module provides an API for resource providers. Resource providers--- allow Hakyll to get content from resources; the type of resource depends on--- the concrete instance.------ A resource is represented by the 'Resource' type. This is basically just a--- newtype wrapper around 'Identifier' -- but it has an important effect: it--- guarantees that a resource with this identifier can be provided by one or--- more resource providers.------ Therefore, it is not recommended to read files directly -- you should use the--- provided 'Resource' methods.----module Hakyll.Core.ResourceProvider-    ( Resource (..)-    , ResourceProvider (..)-    , resourceExists-    , resourceDigest-    , resourceModified-    ) where--import Control.Monad ((<=<))-import Data.Word (Word8)--import qualified Data.ByteString.Lazy as LB-import OpenSSL.Digest.ByteString.Lazy (digest)-import OpenSSL.Digest (MessageDigest (MD5))--import Hakyll.Core.Identifier-import Hakyll.Core.Store---- | A resource------ Invariant: the resource specified by the given identifier must exist----newtype Resource = Resource {unResource :: Identifier}-                 deriving (Eq, Show, Ord)---- | A value responsible for retrieving and listing resources----data ResourceProvider = ResourceProvider-    { -- | A list of all resources this provider is able to provide-      resourceList           :: [Resource]-    , -- | Retrieve a certain resource as string-      resourceString         :: Resource -> IO String-    , -- | Retrieve a certain resource as lazy bytestring-      resourceLazyByteString :: Resource -> IO LB.ByteString-    }---- | Check if a given identifier has a resource----resourceExists :: ResourceProvider -> Identifier -> Bool-resourceExists provider = flip elem $ map unResource $ resourceList provider---- | Retrieve a digest for a given resource----resourceDigest :: ResourceProvider -> Resource -> IO [Word8]-resourceDigest provider = digest MD5 <=< resourceLazyByteString provider---- | Check if a resource was modified----resourceModified :: ResourceProvider -> Resource -> Store -> IO Bool-resourceModified provider resource store = do-    -- Get the latest seen digest from the store-    lastDigest <- storeGet store itemName $ unResource resource-    -- Calculate the digest for the resource-    newDigest <- resourceDigest provider resource-    -- Check digests-    if Just newDigest == lastDigest-        -- All is fine, not modified-        then return False-        -- Resource modified; store new digest-        else do storeSet store itemName (unResource resource) newDigest-                return True-  where-    itemName = "Hakyll.Core.ResourceProvider.resourceModified"
− src/Hakyll/Core/ResourceProvider/FileResourceProvider.hs
@@ -1,29 +0,0 @@--- | A concrete 'ResourceProvider' that gets it's resources from the filesystem----module Hakyll.Core.ResourceProvider.FileResourceProvider-    ( fileResourceProvider-    ) where--import Control.Applicative ((<$>))--import qualified Data.ByteString.Lazy as LB--import Hakyll.Core.ResourceProvider-import Hakyll.Core.Identifier-import Hakyll.Core.Util.File-import Hakyll.Core.Configuration---- | Create a filesystem-based 'ResourceProvider'----fileResourceProvider :: HakyllConfiguration -> IO ResourceProvider-fileResourceProvider configuration = do-    -- Retrieve a list of identifiers-    list <- map parseIdentifier . filter (not . ignoreFile configuration) <$>-        getRecursiveContents False "."--    -- Construct a resource provider-    return ResourceProvider-        { resourceList           = map Resource list-        , resourceString         = readFile . toFilePath . unResource-        , resourceLazyByteString = LB.readFile . toFilePath . unResource-        }
src/Hakyll/Core/Routes.hs view
@@ -30,7 +30,7 @@     , runRoutes     , idRoute     , setExtension-    , ifMatch+    , matchRoute     , customRoute     , gsubRoute     , composeRoutes@@ -85,15 +85,15 @@ setExtension extension = Routes $ fmap (`replaceExtension` extension)                                 . unRoutes idRoute --- | Modify a route: apply the route if the identifier matches the given--- pattern, fail otherwise.+-- | Apply the route if the identifier matches the given pattern, fail+-- otherwise ---ifMatch :: Pattern -> Routes -> Routes-ifMatch pattern (Routes route) = Routes $ \id' ->-    if doesMatch pattern id' then route id'-                             else Nothing+matchRoute :: Pattern -> Routes -> Routes+matchRoute pattern (Routes route) = Routes $ \id' ->+    if matches pattern id' then route id' else Nothing --- | Create a custom route. This should almost always be used with 'ifMatch'.+-- | Create a custom route. This should almost always be used with+-- 'matchRoute' -- customRoute :: (Identifier -> FilePath) -> Routes customRoute f = Routes $ Just . f
src/Hakyll/Core/Rules.hs view
@@ -7,13 +7,18 @@ -- A typical usage example would be: -- -- > main = hakyll $ do--- >     route   "posts/*" (setExtension "html")--- >     compile "posts/*" someCompiler+-- >     match "posts/*" $ do+-- >         route   (setExtension "html")+-- >         compile someCompiler+-- >     match "css/*" $ do+-- >         route   idRoute+-- >         compile compressCssCompiler -- {-# LANGUAGE GeneralizedNewtypeDeriving, OverloadedStrings #-} module Hakyll.Core.Rules     ( RulesM     , Rules+    , match     , compile     , create     , route@@ -23,16 +28,17 @@  import Control.Applicative ((<$>)) import Control.Monad.Writer (tell)-import Control.Monad.Reader (ask)+import Control.Monad.Reader (ask, local) import Control.Arrow (second, (>>>), arr, (>>^)) import Control.Monad.State (get, put)-import Data.Monoid (mempty)+import Data.Monoid (mempty, mappend) import qualified Data.Set as S  import Data.Typeable (Typeable) import Data.Binary (Binary) -import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource+import Hakyll.Core.Resource.Provider import Hakyll.Core.Identifier import Hakyll.Core.Identifier.Pattern import Hakyll.Core.Compiler.Internal@@ -63,21 +69,32 @@               -> Rules tellResources resources = RulesM $ tell $ RuleSet mempty mempty $ S.fromList resources +-- | Only compile/route items satisfying the given predicate+--+match :: Pattern -> Rules -> Rules+match pattern = RulesM . local addPredicate . unRulesM+  where+    addPredicate env = env+        { rulesPattern = rulesPattern env `mappend` pattern+        }+ -- | Add a compilation rule to the rules. ----- This instructs all resources matching the given pattern to be compiled using--- the given compiler. When no resources match the given pattern, nothing will--- happen. In this case, you might want to have a look at 'create'.+-- This instructs all resources to be compiled using the given compiler. When+-- no resources match the current selection, nothing will happen. In this case,+-- you might want to have a look at 'create'. -- compile :: (Binary a, Typeable a, Writable a)-        => Pattern -> Compiler Resource a -> Rules-compile pattern compiler = RulesM $ do-    identifiers <- matches pattern . map unResource . resourceList <$> ask+        => Compiler Resource a -> Rules+compile compiler = RulesM $ do+    pattern <- rulesPattern <$> ask+    provider <- rulesResourceProvider <$> ask+    let ids = filterMatches pattern $ map unResource $ resourceList provider     unRulesM $ do-        tellCompilers $ flip map identifiers $ \identifier ->+        tellCompilers $ flip map ids $ \identifier ->             (identifier, constA (Resource identifier) >>> compiler)-        tellResources $ map Resource identifiers-+        tellResources $ map Resource ids+                    -- | Add a compilation rule -- -- This sets a compiler for the given identifier. No resource is needed, since@@ -91,10 +108,12 @@  -- | Add a route. ----- This adds a route for all items matching the given pattern.+-- This adds a route for all items matching the current pattern. ---route :: Pattern -> Routes -> Rules-route pattern route' = tellRoute $ ifMatch pattern route'+route :: Routes -> Rules+route route' = RulesM $ do+    pattern <- rulesPattern <$> ask+    unRulesM $ tellRoute $ matchRoute pattern route'  -- | Apart from regular compilers, one is also able to specify metacompilers. -- Metacompilers are a special class of compilers: they are compilers which
src/Hakyll/Core/Rules/Internal.hs view
@@ -5,6 +5,7 @@     ( CompileRule (..)     , RuleSet (..)     , RuleState (..)+    , RuleEnvironment (..)     , RulesM (..)     , Rules     , runRules@@ -17,8 +18,10 @@ import Data.Monoid (Monoid, mempty, mappend) import Data.Set (Set) -import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource+import Hakyll.Core.Resource.Provider import Hakyll.Core.Identifier+import Hakyll.Core.Identifier.Pattern import Hakyll.Core.Compiler.Internal import Hakyll.Core.Routes import Hakyll.Core.CompiledItem@@ -55,10 +58,17 @@     { rulesMetaCompilerIndex :: Int     } deriving (Show) +-- | Rule environment+--+data RuleEnvironment = RuleEnvironment+    { rulesResourceProvider :: ResourceProvider+    , rulesPattern          :: Pattern+    }+ -- | The monad used to compose rules -- newtype RulesM a = RulesM-    { unRulesM :: ReaderT ResourceProvider (WriterT RuleSet (State RuleState)) a+    { unRulesM :: ReaderT RuleEnvironment (WriterT RuleSet (State RuleState)) a     } deriving (Monad, Functor, Applicative)  -- | Simplification of the RulesM type; usually, it will not return any@@ -70,6 +80,9 @@ -- runRules :: Rules -> ResourceProvider -> RuleSet runRules rules provider =-    evalState (execWriterT $ runReaderT (unRulesM rules) provider) state+    evalState (execWriterT $ runReaderT (unRulesM rules) env) state   where     state = RuleState {rulesMetaCompilerIndex = 0}+    env = RuleEnvironment { rulesResourceProvider = provider+                          , rulesPattern          = mempty+                          }
src/Hakyll/Core/Run.hs view
@@ -23,8 +23,9 @@ import Hakyll.Core.Util.File import Hakyll.Core.Compiler import Hakyll.Core.Compiler.Internal-import Hakyll.Core.ResourceProvider-import Hakyll.Core.ResourceProvider.FileResourceProvider+import Hakyll.Core.Resource+import Hakyll.Core.Resource.Provider+import Hakyll.Core.Resource.Provider.File import Hakyll.Core.Rules.Internal import Hakyll.Core.DirectedGraph import Hakyll.Core.DirectedGraph.DependencySolver@@ -99,9 +100,7 @@          -> [Identifier]         -- ^ Identifiers to check          -> IO (Set Identifier)  -- ^ Modified resources modified provider store ids = fmap S.fromList $ flip filterM ids $ \id' ->-    if resourceExists provider id'-        then resourceModified provider (Resource id') store-        else return False+    resourceModified provider (Resource id') store  -- | Add a number of compilers and continue using these compilers --
src/Hakyll/Core/Writable/CopyFile.hs view
@@ -12,7 +12,7 @@ import Data.Typeable (Typeable) import Data.Binary (Binary) -import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource import Hakyll.Core.Writable import Hakyll.Core.Compiler import Hakyll.Core.Identifier
src/Hakyll/Web/CompressCss.hs view
@@ -11,7 +11,7 @@ import Control.Arrow ((>>^))  import Hakyll.Core.Compiler-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource import Hakyll.Core.Util.String  -- | Compiler form of 'compressCss'
src/Hakyll/Web/Page.hs view
@@ -67,7 +67,7 @@  import Hakyll.Core.Identifier import Hakyll.Core.Compiler-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource import Hakyll.Web.Page.Internal import Hakyll.Web.Page.Read import Hakyll.Web.Page.Metadata
src/Hakyll/Web/Tags.hs view
@@ -40,7 +40,6 @@ import Prelude hiding (id) import Control.Category (id) import Control.Applicative ((<$>))-import Data.Map (Map) import qualified Data.Map as M import Data.List (intersperse, intercalate) import Control.Arrow (arr, (&&&), (>>>), (***), (<<^), returnA)@@ -65,7 +64,7 @@ -- | Data about tags -- data Tags a = Tags-    { tagsMap :: Map String [Page a]+    { tagsMap :: [(String, [Page a])]     } deriving (Show, Typeable)  instance Binary a => Binary (Tags a) where@@ -91,7 +90,8 @@              -> [Page a]              -- ^ Pages              -> Tags a                -- ^ Resulting tags readTagsWith f pages = Tags-    { tagsMap = foldl (M.unionWith (++)) M.empty (map readTagsWith' pages)+    { tagsMap = M.toList $+        foldl (M.unionWith (++)) M.empty (map readTagsWith' pages)     }   where     -- Create a tag map for one page@@ -122,7 +122,7 @@ renderTags makeUrl makeItem concatItems = proc (Tags tags) -> do     -- In tags' we create a list: [((tag, route), count)]     tags' <- mapCompiler ((id &&& (getRouteFor <<^ makeUrl)) *** arr length)-                -< M.toList tags+                -< tags      let -- Absolute frequencies of the pages         freqs = map snd tags'
src/Hakyll/Web/Template.hs view
@@ -59,7 +59,7 @@  import Hakyll.Core.Compiler import Hakyll.Core.Identifier-import Hakyll.Core.ResourceProvider+import Hakyll.Core.Resource import Hakyll.Web.Template.Internal import Hakyll.Web.Template.Read import Hakyll.Web.Page.Internal