packages feed

hakyll 4.7.5.2 → 4.8.0.0

raw patch · 39 files changed

+371/−262 lines, 39 filesdep +resourcetdep +unordered-containersdep +vectordep ~basedep ~data-defaultdep ~directoryPVP ok

version bump matches the API change (PVP)

Dependencies added: resourcet, unordered-containers, vector, yaml

Dependency ranges changed: base, data-default, directory, regex-tdfa, time

API changes (from Hackage documentation)

+ Hakyll.Core.Metadata: BinaryMetadata :: Metadata -> BinaryMetadata
+ Hakyll.Core.Metadata: [unBinaryMetadata] :: BinaryMetadata -> Metadata
+ Hakyll.Core.Metadata: instance Data.Binary.Class.Binary Hakyll.Core.Metadata.BinaryMetadata
+ Hakyll.Core.Metadata: instance Data.Binary.Class.Binary Hakyll.Core.Metadata.BinaryYaml
+ Hakyll.Core.Metadata: lookupString :: String -> Metadata -> Maybe String
+ Hakyll.Core.Metadata: lookupStringList :: String -> Metadata -> Maybe [String]
+ Hakyll.Core.Metadata: newtype BinaryMetadata
+ Hakyll.Web.Template.Context: snippetField :: Context String
- Hakyll.Core.Metadata: type Metadata = Map String String
+ Hakyll.Core.Metadata: type Metadata = Object

Files

hakyll.cabal view
@@ -1,5 +1,5 @@ Name:    hakyll-Version: 4.7.5.2+Version: 4.8.0.0  Synopsis: A static website compiler library Description:@@ -121,6 +121,8 @@     Hakyll.Web.Template.List    Other-Modules:+    Data.List.Extended+    Data.Yaml.Extended     Hakyll.Check     Hakyll.Commands     Hakyll.Core.Compiler.Internal@@ -140,33 +142,37 @@     Paths_hakyll    Build-Depends:-    base               >= 4       && < 5,-    binary             >= 0.5     && < 0.8,-    blaze-html         >= 0.5     && < 0.9,-    blaze-markup       >= 0.5.1   && < 0.8,-    bytestring         >= 0.9     && < 0.11,-    cmdargs            >= 0.10    && < 0.11,-    containers         >= 0.3     && < 0.6,-    cryptohash         >= 0.7     && < 0.12,-    data-default       >= 0.4     && < 0.6,-    deepseq            >= 1.3     && < 1.5,-    directory          >= 1.0     && < 1.3,-    filepath           >= 1.0     && < 1.5,-    lrucache           >= 1.1.1   && < 1.3,-    mtl                >= 1       && < 2.3,-    network            >= 2.6     && < 2.7,-    network-uri        >= 2.6     && < 2.7,-    pandoc             >= 1.14    && < 1.18,-    pandoc-citeproc    >= 0.4     && < 0.10,-    parsec             >= 3.0     && < 3.2,-    process            >= 1.0     && < 1.3,-    random             >= 1.0     && < 1.2,-    regex-base         >= 0.93    && < 0.94,-    regex-tdfa         >= 1.1     && < 1.3,-    tagsoup            >= 0.13.1  && < 0.14,-    text               >= 0.11    && < 1.3,-    time               >= 1.4     && < 1.6,-    time-locale-compat >= 0.1     && < 0.2+    base                 >= 4.8    && < 5,+    binary               >= 0.5    && < 0.8,+    blaze-html           >= 0.5    && < 0.9,+    blaze-markup         >= 0.5.1  && < 0.8,+    bytestring           >= 0.9    && < 0.11,+    cmdargs              >= 0.10   && < 0.11,+    containers           >= 0.3    && < 0.6,+    cryptohash           >= 0.7    && < 0.12,+    data-default         >= 0.4    && < 0.7,+    deepseq              >= 1.3    && < 1.5,+    directory            >= 1.0    && < 1.3,+    filepath             >= 1.0    && < 1.5,+    lrucache             >= 1.1.1  && < 1.3,+    mtl                  >= 1      && < 2.3,+    network              >= 2.6    && < 2.7,+    network-uri          >= 2.6    && < 2.7,+    pandoc               >= 1.14   && < 1.18,+    pandoc-citeproc      >= 0.4    && < 0.10,+    parsec               >= 3.0    && < 3.2,+    process              >= 1.0    && < 1.3,+    random               >= 1.0    && < 1.2,+    regex-base           >= 0.93   && < 0.94,+    regex-tdfa           >= 1.1    && < 1.3,+    resourcet            >= 1.1    && < 1.2,+    tagsoup              >= 0.13.1 && < 0.14,+    text                 >= 0.11   && < 1.3,+    time                 >= 1.4    && < 1.6,+    time-locale-compat   >= 0.1    && < 0.2,+    unordered-containers >= 0.2    && < 0.3,+    vector               >= 0.11   && < 0.12,+    yaml                 >= 0.8    && < 0.9    If flag(previewServer)     Build-depends:@@ -226,33 +232,37 @@     test-framework-hunit       >= 0.3 && < 0.4,     test-framework-quickcheck2 >= 0.3 && < 0.4,     -- Copy pasted from hakyll dependencies:-    base               >= 4       && < 5,-    binary             >= 0.5     && < 0.8,-    blaze-html         >= 0.5     && < 0.9,-    blaze-markup       >= 0.5.1   && < 0.8,-    bytestring         >= 0.9     && < 0.11,-    cmdargs            >= 0.10    && < 0.11,-    containers         >= 0.3     && < 0.6,-    cryptohash         >= 0.7     && < 0.12,-    data-default       >= 0.4     && < 0.6,-    deepseq            >= 1.3     && < 1.5,-    directory          >= 1.0     && < 1.3,-    filepath           >= 1.0     && < 1.5,-    lrucache           >= 1.1.1   && < 1.3,-    mtl                >= 1       && < 2.3,-    network            >= 2.6     && < 2.7,-    network-uri        >= 2.6     && < 2.7,-    pandoc             >= 1.14    && < 1.18,-    pandoc-citeproc    >= 0.4     && < 0.10,-    parsec             >= 3.0     && < 3.2,-    process            >= 1.0     && < 1.3,-    random             >= 1.0     && < 1.2,-    regex-base         >= 0.93    && < 0.94,-    regex-tdfa         >= 1.1     && < 1.3,-    tagsoup            >= 0.13.1  && < 0.14,-    text               >= 0.11    && < 1.3,-    time               >= 1.5     && < 1.6,-    time-locale-compat >= 0.1     && < 0.2+    base                 >= 4.8    && < 5,+    binary               >= 0.5    && < 0.8,+    blaze-html           >= 0.5    && < 0.9,+    blaze-markup         >= 0.5.1  && < 0.8,+    bytestring           >= 0.9    && < 0.11,+    cmdargs              >= 0.10   && < 0.11,+    containers           >= 0.3    && < 0.6,+    cryptohash           >= 0.7    && < 0.12,+    data-default         >= 0.4    && < 0.7,+    deepseq              >= 1.3    && < 1.5,+    directory            >= 1.0    && < 1.3,+    filepath             >= 1.0    && < 1.5,+    lrucache             >= 1.1.1  && < 1.3,+    mtl                  >= 1      && < 2.3,+    network              >= 2.6    && < 2.7,+    network-uri          >= 2.6    && < 2.7,+    pandoc               >= 1.14   && < 1.18,+    pandoc-citeproc      >= 0.4    && < 0.10,+    parsec               >= 3.0    && < 3.2,+    process              >= 1.0    && < 1.3,+    random               >= 1.0    && < 1.2,+    regex-base           >= 0.93   && < 0.94,+    regex-tdfa           >= 1.1    && < 1.3,+    resourcet            >= 1.1    && < 1.2,+    tagsoup              >= 0.13.1 && < 0.14,+    text                 >= 0.11   && < 1.3,+    time                 >= 1.4    && < 1.6,+    time-locale-compat   >= 0.1    && < 0.2,+    unordered-containers >= 0.2    && < 0.3,+    vector               >= 0.11   && < 0.12,+    yaml                 >= 0.8    && < 0.9    If flag(previewServer)     Build-depends:@@ -291,3 +301,7 @@     base      >= 4   && < 5,     directory >= 1.0 && < 1.3,     filepath  >= 1.0 && < 1.5++  Other-modules:+    Hakyll.Core.Util.File+    Paths_hakyll
+ src/Data/List/Extended.hs view
@@ -0,0 +1,15 @@+module Data.List.Extended+    ( module Data.List+    , breakWhen+    ) where++import           Data.List++-- | Like 'break', but can act on the entire tail of the list.+breakWhen :: ([a] -> Bool) -> [a] -> ([a], [a])+breakWhen predicate = go []+  where+    go buf []                = (reverse buf, [])+    go buf (x : xs)+        | predicate (x : xs) = (reverse buf, x : xs)+        | otherwise          = go (x : buf) xs
+ src/Data/Yaml/Extended.hs view
@@ -0,0 +1,20 @@+module Data.Yaml.Extended+    ( module Data.Yaml+    , toString+    , toList+    ) where++import qualified Data.Text   as T+import qualified Data.Vector as V+import           Data.Yaml++toString :: Value -> Maybe String+toString (String t)     = Just (T.unpack t)+toString (Bool   True)  = Just "true"+toString (Bool   False) = Just "false"+toString (Number d)     = Just (show d)+toString _              = Nothing++toList :: Value -> Maybe [Value]+toList (Array a) = Just (V.toList a)+toList _         = Nothing
src/Hakyll/Check.hs view
@@ -8,42 +8,44 @@   ---------------------------------------------------------------------------------import           Control.Applicative       ((<$>))-import           Control.Monad             (forM_)-import           Control.Monad.Reader      (ask)-import           Control.Monad.RWS         (RWST, runRWST)-import           Control.Monad.Trans       (liftIO)-import           Control.Monad.Writer      (tell)-import           Data.List                 (isPrefixOf)-import           Data.Monoid               (Monoid (..))-import           Data.Set                  (Set)-import qualified Data.Set                  as S-import           Network.URI               (unEscapeString)-import           System.Directory          (doesDirectoryExist, doesFileExist)-import           System.Exit               (ExitCode (..))-import           System.FilePath           (takeDirectory, takeExtension, (</>))-import qualified Text.HTML.TagSoup         as TS+import           Control.Monad                (forM_)+import           Control.Monad.Reader         (ask)+import           Control.Monad.RWS            (RWST, runRWST)+import           Control.Monad.Trans          (liftIO)+import           Control.Monad.Trans.Resource (runResourceT)+import           Control.Monad.Writer         (tell)+import           Data.List                    (isPrefixOf)+import           Data.Set                     (Set)+import qualified Data.Set                     as S+import           Network.URI                  (unEscapeString)+import           System.Directory             (doesDirectoryExist,+                                               doesFileExist)+import           System.Exit                  (ExitCode (..))+import           System.FilePath              (takeDirectory, takeExtension,+                                               (</>))+import qualified Text.HTML.TagSoup            as TS   -------------------------------------------------------------------------------- #ifdef CHECK_EXTERNAL-import           Control.Exception         (AsyncException (..),-                                            SomeException (..), handle, throw)-import           Control.Monad.State       (get, modify)-import           Data.List                 (intercalate)-import           Data.Typeable             (cast)-import           Data.Version              (versionBranch)-import           GHC.Exts                  (fromString)-import qualified Network.HTTP.Conduit      as Http-import qualified Network.HTTP.Types        as Http-import qualified Paths_hakyll              as Paths_hakyll+import           Control.Exception            (AsyncException (..),+                                               SomeException (..), handle,+                                               throw)+import           Control.Monad.State          (get, modify)+import           Data.List                    (intercalate)+import           Data.Typeable                (cast)+import           Data.Version                 (versionBranch)+import           GHC.Exts                     (fromString)+import qualified Network.HTTP.Conduit         as Http+import qualified Network.HTTP.Types           as Http+import qualified Paths_hakyll                 as Paths_hakyll #endif   -------------------------------------------------------------------------------- import           Hakyll.Core.Configuration-import           Hakyll.Core.Logger        (Logger)-import qualified Hakyll.Core.Logger        as Logger+import           Hakyll.Core.Logger           (Logger)+import qualified Hakyll.Core.Logger           as Logger import           Hakyll.Core.Util.File import           Hakyll.Web.Html @@ -196,8 +198,9 @@     if not needsCheck || checked         then Logger.debug logger "Already checked, skipping"         else do-            isOk <- liftIO $ handle (failure logger) $-                Http.withManager $ \mgr -> do+            isOk <- liftIO $ handle (failure logger) $ do+                mgr <- Http.newManager Http.tlsManagerSettings+                runResourceT $ do                     request  <- Http.parseUrl urlToCheck                     response <- Http.http (settings request) mgr                     let code = Http.statusCode (Http.responseStatus response)
src/Hakyll/Commands.hs view
@@ -14,11 +14,8 @@   ---------------------------------------------------------------------------------import           Control.Applicative import           Control.Concurrent-import           Control.Monad              (void) import           System.Exit                (ExitCode, exitWith)-import           System.IO.Error            (catchIOError)  -------------------------------------------------------------------------------- import qualified Hakyll.Check               as Check
src/Hakyll/Core/Compiler.hs view
@@ -28,7 +28,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative           ((<$>)) import           Control.Monad                 (when) import           Data.Binary                   (Binary) import           Data.ByteString.Lazy          (ByteString)
src/Hakyll/Core/Compiler/Internal.hs view
@@ -28,12 +28,10 @@   ---------------------------------------------------------------------------------import           Control.Applicative            (Alternative (..),-                                                 Applicative (..), (<$>))+import           Control.Applicative            (Alternative (..)) import           Control.Exception              (SomeException, handle) import           Control.Monad                  (forM_)-import           Control.Monad.Error            (MonadError (..))-import           Data.Monoid                    (Monoid (..))+import           Control.Monad.Except            (MonadError (..)) import           Data.Set                       (Set) import qualified Data.Set                       as S 
src/Hakyll/Core/Compiler/Require.hs view
@@ -13,7 +13,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative            ((<$>)) import           Control.Monad                  (when) import           Data.Binary                    (Binary) import qualified Data.Set                       as S
src/Hakyll/Core/Dependencies.hs view
@@ -8,7 +8,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative            ((<$>), (<*>)) import           Control.Monad                  (foldM, forM_, unless, when) import           Control.Monad.Reader           (ask) import           Control.Monad.RWS              (RWS, runRWS)
src/Hakyll/Core/File.hs view
@@ -11,7 +11,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative           ((<$>)) import           Data.Binary                   (Binary (..)) import           Data.Typeable                 (Typeable) import           System.Directory              (copyFile, doesFileExist,
src/Hakyll/Core/Identifier.hs view
@@ -19,7 +19,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative ((<$>), (<*>)) import           Control.DeepSeq     (NFData (..)) import           Data.List           (intercalate) import           System.FilePath     (dropTrailingPathSeparator, splitPath)
src/Hakyll/Core/Identifier/Pattern.hs view
@@ -57,13 +57,11 @@   ---------------------------------------------------------------------------------import           Control.Applicative    (pure, (<$>), (<*>)) import           Control.Arrow          ((&&&), (>>>)) import           Control.Monad          (msum) import           Data.Binary            (Binary (..), getWord8, putWord8) import           Data.List              (inits, isPrefixOf, tails) import           Data.Maybe             (isJust)-import           Data.Monoid            (Monoid, mappend, mempty) import           Data.Set               (Set) import qualified Data.Set               as S 
src/Hakyll/Core/Item.hs view
@@ -10,10 +10,8 @@   ---------------------------------------------------------------------------------import           Control.Applicative           ((<$>), (<*>)) import           Data.Binary                   (Binary (..)) import           Data.Foldable                 (Foldable (..))-import           Data.Traversable              (Traversable (..)) import           Data.Typeable                 (Typeable) import           Prelude                       hiding (foldr) 
src/Hakyll/Core/Logger.hs view
@@ -13,7 +13,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative     (pure, (<$>), (<*>)) import           Control.Concurrent      (forkIO) import           Control.Concurrent.Chan (Chan, newChan, readChan, writeChan) import           Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
src/Hakyll/Core/Metadata.hs view
@@ -1,31 +1,49 @@ -------------------------------------------------------------------------------- module Hakyll.Core.Metadata     ( Metadata+    , lookupString+    , lookupStringList+     , MonadMetadata (..)     , getMetadataField     , getMetadataField'     , makePatternDependency++    , BinaryMetadata (..)     ) where   --------------------------------------------------------------------------------+import           Control.Arrow                  (second) import           Control.Monad                  (forM)-import           Data.Map                       (Map)-import qualified Data.Map                       as M+import           Data.Binary                    (Binary (..), getWord8,+                                                 putWord8, Get)+import qualified Data.HashMap.Strict            as HMS import qualified Data.Set                       as S-----------------------------------------------------------------------------------+import qualified Data.Text                      as T+import qualified Data.Vector                    as V+import qualified Data.Yaml.Extended                      as Yaml import           Hakyll.Core.Dependencies import           Hakyll.Core.Identifier import           Hakyll.Core.Identifier.Pattern   ---------------------------------------------------------------------------------type Metadata = Map String String+type Metadata = Yaml.Object   --------------------------------------------------------------------------------+lookupString :: String -> Metadata -> Maybe String+lookupString key meta = HMS.lookup (T.pack key) meta >>= Yaml.toString+++--------------------------------------------------------------------------------+lookupStringList :: String -> Metadata -> Maybe [String]+lookupStringList key meta =+    HMS.lookup (T.pack key) meta >>= Yaml.toList >>= mapM Yaml.toString+++-------------------------------------------------------------------------------- class Monad m => MonadMetadata m where     getMetadata    :: Identifier -> m Metadata     getMatches     :: Pattern -> m [Identifier]@@ -42,7 +60,7 @@ getMetadataField :: MonadMetadata m => Identifier -> String -> m (Maybe String) getMetadataField identifier key = do     metadata <- getMetadata identifier-    return $ M.lookup key metadata+    return $ lookupString key metadata   --------------------------------------------------------------------------------@@ -62,3 +80,59 @@ makePatternDependency pattern = do     matches' <- getMatches pattern     return $ PatternDependency pattern (S.fromList matches')+++--------------------------------------------------------------------------------+-- | Newtype wrapper for serialization.+newtype BinaryMetadata = BinaryMetadata+    {unBinaryMetadata :: Metadata}+++instance Binary BinaryMetadata where+    put (BinaryMetadata obj) = put (BinaryYaml $ Yaml.Object obj)+    get = do+        BinaryYaml (Yaml.Object obj) <- get+        return $ BinaryMetadata obj+++--------------------------------------------------------------------------------+newtype BinaryYaml = BinaryYaml {unBinaryYaml :: Yaml.Value}+++--------------------------------------------------------------------------------+instance Binary BinaryYaml where+    put (BinaryYaml yaml) = case yaml of+        Yaml.Object obj -> do+            putWord8 0+            let list :: [(T.Text, BinaryYaml)]+                list = map (second BinaryYaml) $ HMS.toList obj+            put list++        Yaml.Array arr -> do+            putWord8 1+            let list = map BinaryYaml (V.toList arr) :: [BinaryYaml]+            put list++        Yaml.String s -> putWord8 2 >> put s+        Yaml.Number n -> putWord8 3 >> put n+        Yaml.Bool   b -> putWord8 4 >> put b+        Yaml.Null     -> putWord8 5++    get = do+        tag <- getWord8+        case tag of+            0 -> do+                list <- get :: Get [(T.Text, BinaryYaml)]+                return $ BinaryYaml $ Yaml.Object $+                    HMS.fromList $ map (second unBinaryYaml) list++            1 -> do+                list <- get :: Get [BinaryYaml]+                return $ BinaryYaml $+                    Yaml.Array $ V.fromList $ map unBinaryYaml list++            2 -> BinaryYaml . Yaml.String <$> get+            3 -> BinaryYaml . Yaml.Number <$> get+            4 -> BinaryYaml . Yaml.Bool   <$> get+            5 -> return $ BinaryYaml Yaml.Null+            _ -> fail "Data.Binary.get: Invalid Binary Metadata"
src/Hakyll/Core/Provider/Internal.hs view
@@ -20,7 +20,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative    ((<$>), (<*>)) import           Control.DeepSeq        (NFData (..), deepseq) import           Control.Monad          (forM) import           Data.Binary            (Binary (..))@@ -28,7 +27,6 @@ import           Data.Map               (Map) import qualified Data.Map               as M import           Data.Maybe             (fromMaybe)-import           Data.Monoid            (mempty) import           Data.Set               (Set) import qualified Data.Set               as S import           Data.Time              (Day (..), UTCTime (..))
src/Hakyll/Core/Provider/Metadata.hs view
@@ -1,33 +1,31 @@ -------------------------------------------------------------------------------- -- | Internal module to parse metadata+{-# LANGUAGE BangPatterns    #-}+{-# LANGUAGE RecordWildCards #-} module Hakyll.Core.Provider.Metadata     ( loadMetadata-    , metadata-    , page+    , parsePage -      -- This parser can be reused in some places-    , metadataKey+    , MetadataException (..)     ) where   ---------------------------------------------------------------------------------import           Control.Applicative import           Control.Arrow                 (second)+import           Control.Exception             (Exception, throwIO)+import           Control.Monad                 (guard) import qualified Data.ByteString.Char8         as BC-import           Data.List                     (intercalate)+import           Data.List.Extended            (breakWhen) import qualified Data.Map                      as M-import           System.IO                     as IO-import           Text.Parsec                   ((<?>))-import qualified Text.Parsec                   as P-import           Text.Parsec.String            (Parser)-----------------------------------------------------------------------------------+import           Data.Maybe                    (fromMaybe)+import           Data.Monoid                   ((<>))+import qualified Data.Text                     as T+import qualified Data.Text.Encoding            as T+import qualified Data.Yaml                     as Yaml import           Hakyll.Core.Identifier import           Hakyll.Core.Metadata import           Hakyll.Core.Provider.Internal-import           Hakyll.Core.Util.Parser-import           Hakyll.Core.Util.String+import           System.IO                     as IO   --------------------------------------------------------------------------------@@ -36,13 +34,13 @@     hasHeader  <- probablyHasMetadataHeader fp     (md, body) <- if hasHeader         then second Just <$> loadMetadataHeader fp-        else return (M.empty, Nothing)+        else return (mempty, Nothing)      emd <- case mi of-        Nothing  -> return M.empty+        Nothing  -> return mempty         Just mi' -> loadMetadataFile $ resourceFilePath p mi' -    return (M.union md emd, body)+    return (md <> emd, body)   where     normal = setVersion Nothing identifier     fp     = resourceFilePath p identifier@@ -52,19 +50,17 @@ -------------------------------------------------------------------------------- loadMetadataHeader :: FilePath -> IO (Metadata, String) loadMetadataHeader fp = do-    contents <- readFile fp-    case P.parse page fp contents of-        Left err      -> error (show err)-        Right (md, b) -> return (M.fromList md, b)+    fileContent <- readFile fp+    case parsePage fileContent of+        Right x   -> return x+        Left  err -> throwIO $ MetadataException fp err   -------------------------------------------------------------------------------- loadMetadataFile :: FilePath -> IO Metadata loadMetadataFile fp = do-    contents <- readFile fp-    case P.parse metadata fp contents of-        Left err  -> error (show err)-        Right md  -> return $ M.fromList md+    errOrMeta <- Yaml.decodeFileEither fp+    either (fail . show) return errOrMeta   --------------------------------------------------------------------------------@@ -83,53 +79,71 @@   ----------------------------------------------------------------------------------- | Space or tab, no newline-inlineSpace :: Parser Char-inlineSpace = P.oneOf ['\t', ' '] <?> "space"+-- | Parse the page metadata and body.+splitMetadata :: String -> (Maybe String, String)+splitMetadata str0 = fromMaybe (Nothing, str0) $ do+    guard $ leading >= 3+    let !str1 = drop leading str0+    guard $ all isNewline (take 1 str1)+    let !(!meta, !content0) = breakWhen isTrailing str1+    guard $ not $ null content0+    let !content1 = drop (leading + 1) content0+        !content2 = dropWhile isNewline $ dropWhile isInlineSpace content1+    -- Adding this newline fixes the line numbers reported by the YAML parser.+    -- It's a bit ugly but it works.+    return (Just ('\n' : meta), content2)+  where+    -- Parse the leading "---"+    !leading = length $ takeWhile (== '-') str0 +    -- Predicate to recognize the trailing "---" or "..."+    isTrailing []       = False+    isTrailing (x : xs) =+        isNewline x && length (takeWhile isDash xs) == leading +    -- Characters+    isNewline     c = c == '\n' || c == '\r'+    isDash        c = c == '-'  || c == '.'+    isInlineSpace c = c == '\t' || c == ' '++ ----------------------------------------------------------------------------------- | Parse Windows newlines as well (i.e. "\n" or "\r\n")-newline :: Parser String-newline = P.string "\n" <|> P.string "\r\n"+parseMetadata :: String -> Either Yaml.ParseException Metadata+parseMetadata = Yaml.decodeEither' . T.encodeUtf8 . T.pack   ----------------------------------------------------------------------------------- | Parse a single metadata field-metadataField :: Parser (String, String)-metadataField = do-    key <- metadataKey-    _   <- P.char ':'-    P.skipMany1 inlineSpace <?> "space followed by metadata for: " ++ key-    value     <- P.manyTill P.anyChar newline-    trailing' <- P.many trailing-    return (key, trim $ intercalate " " $ value : trailing')+parsePage :: String -> Either Yaml.ParseException (Metadata, String)+parsePage fileContent = case mbMetaBlock of+    Nothing        -> return (mempty, content)+    Just metaBlock -> case parseMetadata metaBlock of+        Left  err  -> Left   err+        Right meta -> return (meta, content)   where-    trailing = P.many1 inlineSpace *> P.manyTill P.anyChar newline+    !(!mbMetaBlock, !content) = splitMetadata fileContent   ----------------------------------------------------------------------------------- | Parse a metadata block-metadata :: Parser [(String, String)]-metadata = P.many metadataField+-- | Thrown in the IO monad if things go wrong. Provides a nice-ish error+-- message.+data MetadataException = MetadataException FilePath Yaml.ParseException   ----------------------------------------------------------------------------------- | Parse a metadata block, including delimiters and trailing newlines-metadataBlock :: Parser [(String, String)]-metadataBlock = do-    open      <- P.many1 (P.char '-') <* P.many inlineSpace <* newline-    metadata' <- metadata-    _         <- P.choice $ map (P.string . replicate (length open)) ['-', '.']-    P.skipMany inlineSpace-    P.skipMany1 newline-    return metadata'+instance Exception MetadataException   ----------------------------------------------------------------------------------- | Parse a page consisting of a metadata header and a body-page :: Parser ([(String, String)], String)-page = do-    metadata' <- P.option [] metadataBlock-    body      <- P.many P.anyChar-    return (metadata', body)+instance Show MetadataException where+    show (MetadataException fp err) =+        fp ++ ": " ++ Yaml.prettyPrintParseException err ++ hint++      where+        hint = case err of+            Yaml.InvalidYaml (Just (Yaml.YamlParseException {..}))+                | yamlProblem == problem -> "\n" +++                    "Hint: if the metadata value contains characters such\n" +++                    "as ':' or '-', try enclosing it in quotes."+            _ -> ""++        problem = "mapping values are not allowed in this context"
src/Hakyll/Core/Provider/MetadataCache.hs view
@@ -8,9 +8,6 @@  -------------------------------------------------------------------------------- import           Control.Monad                 (unless)-import qualified Data.Map                      as M---------------------------------------------------------------------------------- import           Hakyll.Core.Identifier import           Hakyll.Core.Metadata import           Hakyll.Core.Provider.Internal@@ -21,11 +18,11 @@ -------------------------------------------------------------------------------- resourceMetadata :: Provider -> Identifier -> IO Metadata resourceMetadata p r-    | not (resourceExists p r) = return M.empty+    | not (resourceExists p r) = return mempty     | otherwise                = do         -- TODO keep time in md cache         load p r-        Store.Found md <- Store.get (providerStore p)+        Store.Found (BinaryMetadata md) <- Store.get (providerStore p)             [name, toFilePath r, "metadata"]         return md @@ -52,7 +49,7 @@     mmof <- Store.isMember store mdk     unless mmof $ do         (md, body) <- loadMetadata p r-        Store.set store mdk md+        Store.set store mdk (BinaryMetadata md)         Store.set store bk  body   where     store = providerStore p
src/Hakyll/Core/Routes.hs view
@@ -42,7 +42,6 @@   ---------------------------------------------------------------------------------import           Data.Monoid                    (Monoid, mappend, mempty) import           System.FilePath                (replaceExtension)  
src/Hakyll/Core/Rules.hs view
@@ -33,13 +33,11 @@   ---------------------------------------------------------------------------------import           Control.Applicative            ((<$>)) import           Control.Monad.Reader           (ask, local) import           Control.Monad.State            (get, modify, put) import           Control.Monad.Trans            (liftIO) import           Control.Monad.Writer           (censor, tell) import           Data.Maybe                     (fromMaybe)-import           Data.Monoid                    (mempty) import qualified Data.Set                       as S  
src/Hakyll/Core/Rules/Internal.hs view
@@ -12,12 +12,10 @@   ---------------------------------------------------------------------------------import           Control.Applicative            (Applicative, (<$>)) import           Control.Monad.Reader           (ask) import           Control.Monad.RWS              (RWST, runRWST) import           Control.Monad.Trans            (liftIO) import qualified Data.Map                       as M-import           Data.Monoid                    (Monoid, mappend, mempty) import           Data.Set                       (Set)  
src/Hakyll/Core/Runtime.hs view
@@ -5,9 +5,8 @@   ---------------------------------------------------------------------------------import           Control.Applicative           ((<$>)) import           Control.Monad                 (unless)-import           Control.Monad.Error           (ErrorT, runErrorT, throwError)+import           Control.Monad.Except          (ExceptT, runExceptT, throwError) import           Control.Monad.Reader          (ask) import           Control.Monad.RWS             (RWST, runRWST) import           Control.Monad.State           (get, modify)@@ -15,7 +14,6 @@ import           Data.List                     (intercalate) import           Data.Map                      (Map) import qualified Data.Map                      as M-import           Data.Monoid                   (mempty) import           Data.Set                      (Set) import qualified Data.Set                      as S import           System.Exit                   (ExitCode (..))@@ -77,7 +75,7 @@             }      -- Run the program and fetch the resulting state-    result <- runErrorT $ runRWST build read' state+    result <- runExceptT $ runRWST build read' state     case result of         Left e          -> do             Logger.error logger e@@ -117,7 +115,7 @@   ---------------------------------------------------------------------------------type Runtime a = RWST RuntimeRead () RuntimeState (ErrorT String IO) a+type Runtime a = RWST RuntimeRead () RuntimeState (ExceptT String IO) a   --------------------------------------------------------------------------------
src/Hakyll/Core/Store.hs view
@@ -16,7 +16,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative  ((<$>)) import           Control.Exception    (IOException, handle) import qualified Crypto.Hash.MD5      as MD5 import           Data.Binary          (Binary, decode, encodeFile)
src/Hakyll/Core/UnixFilter.hs view
@@ -16,7 +16,6 @@ import           Data.ByteString.Lazy    (ByteString) import qualified Data.ByteString.Lazy    as LB import           Data.IORef              (newIORef, readIORef, writeIORef)-import           Data.Monoid             (Monoid, mempty) import           System.Exit             (ExitCode (..)) import           System.IO               (Handle, hClose, hFlush, hGetContents,                                           hPutStr, hSetEncoding, localeEncoding)
src/Hakyll/Core/Util/File.hs view
@@ -8,7 +8,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative ((<$>)) import           Control.Monad       (filterM, forM, when) import           System.Directory    (createDirectoryIfMissing,                                       doesDirectoryExist, getDirectoryContents,
src/Hakyll/Core/Util/Parser.hs view
@@ -7,7 +7,7 @@   ---------------------------------------------------------------------------------import           Control.Applicative ((<$>), (<*>), (<|>))+import           Control.Applicative ((<|>)) import           Control.Monad       (mzero) import qualified Text.Parsec         as P import           Text.Parsec.String  (Parser)
src/Hakyll/Web/CompressCss.hs view
@@ -8,7 +8,6 @@   ---------------------------------------------------------------------------------import           Control.Applicative     ((<$>)) import           Data.Char               (isSpace) import           Data.List               (isPrefixOf) 
src/Hakyll/Web/Feed.hs view
@@ -25,7 +25,6 @@  -------------------------------------------------------------------------------- import           Control.Monad                 ((<=<))-import           Data.Monoid                   (mconcat)   --------------------------------------------------------------------------------
src/Hakyll/Web/Paginate.hs view
@@ -13,7 +13,6 @@ -------------------------------------------------------------------------------- import           Control.Monad                  (forM_) import qualified Data.Map                       as M-import           Data.Monoid                    (mconcat) import qualified Data.Set                       as S  
src/Hakyll/Web/Pandoc.hs view
@@ -22,9 +22,7 @@   ---------------------------------------------------------------------------------import           Control.Applicative        ((<$>)) import qualified Data.Set                   as S-import           Data.Traversable           (traverse) import           Text.Pandoc import           Text.Pandoc.Error          (PandocError (..)) 
src/Hakyll/Web/Pandoc/Biblio.hs view
@@ -23,22 +23,19 @@   ---------------------------------------------------------------------------------import           Control.Applicative    ((<$>))-import           Control.Monad          (replicateM, liftM)-import           Data.Binary            (Binary (..))-import           Data.Default           (def)-import           Data.Typeable          (Typeable)-import qualified Text.CSL               as CSL-import           Text.CSL.Pandoc        (processCites)-import           Text.Pandoc            (Pandoc, ReaderOptions (..))----------------------------------------------------------------------------------+import           Control.Monad            (liftM, replicateM)+import           Data.Binary              (Binary (..))+import           Data.Default             (def)+import           Data.Typeable            (Typeable) import           Hakyll.Core.Compiler import           Hakyll.Core.Identifier import           Hakyll.Core.Item import           Hakyll.Core.Writable import           Hakyll.Web.Pandoc import           Hakyll.Web.Pandoc.Binary ()+import qualified Text.CSL                 as CSL+import           Text.CSL.Pandoc          (processCites)+import           Text.Pandoc              (Pandoc, ReaderOptions (..))   --------------------------------------------------------------------------------
src/Hakyll/Web/Tags.hs view
@@ -63,13 +63,12 @@  -------------------------------------------------------------------------------- import           Control.Arrow                   ((&&&))-import           Control.Monad                   (foldM, forM, forM_)+import           Control.Monad                   (foldM, forM, forM_, mplus) import           Data.Char                       (toLower) import           Data.List                       (intercalate, intersperse,                                                   sortBy) import qualified Data.Map                        as M import           Data.Maybe                      (catMaybes, fromMaybe)-import           Data.Monoid                     (mconcat) import           Data.Ord                        (comparing) import qualified Data.Set                        as S import           System.FilePath                 (takeBaseName, takeDirectory)@@ -88,8 +87,8 @@ import           Hakyll.Core.Metadata import           Hakyll.Core.Rules import           Hakyll.Core.Util.String-import           Hakyll.Web.Template.Context import           Hakyll.Web.Html+import           Hakyll.Web.Template.Context   --------------------------------------------------------------------------------@@ -103,11 +102,14 @@  -------------------------------------------------------------------------------- -- | Obtain tags from a page in the default way: parse them from the @tags@--- metadata field.+-- metadata field. This can either be a list or a comma-separated string. getTags :: MonadMetadata m => Identifier -> m [String] getTags identifier = do     metadata <- getMetadata identifier-    return $ maybe [] (map trim . splitAll ",") $ M.lookup "tags" metadata+    return $ fromMaybe [] $+        (lookupStringList "tags" metadata) `mplus`+        (map trim . splitAll "," <$> lookupString "tags" metadata)+  -------------------------------------------------------------------------------- -- | Obtain categories from a page.
src/Hakyll/Web/Template.hs view
@@ -54,7 +54,7 @@ -- The @for@ macro is used for enumerating 'Context' elements that are -- lists, i.e. constructed using the 'listField' function. Assume that -- in a context we have an element @listField \"key\" c itms@. Then--- the snippet +-- the snippet -- -- > $for(key)$ -- >   $x$@@ -70,21 +70,21 @@ -- -- > listField "things" (field "thing" (return . itemBody)) -- >    (sequence [makeItem "fruits", makeItem "vegetables"])--- +-- -- and a template -- -- >  I like -- >  $for(things)$--- >    fresh $thing$$sep$, and +-- >    fresh $thing$$sep$, and -- >  $endfor$ -- -- the resulting page would look like -- -- > <p> -- >  I like--- > --- >   fresh fruits, and --- > +-- >+-- >   fresh fruits, and+-- > -- >   fresh vegetables -- > </p> --@@ -129,9 +129,8 @@  -------------------------------------------------------------------------------- import           Control.Monad                (liftM)-import           Control.Monad.Error          (MonadError (..))+import           Control.Monad.Except         (MonadError (..)) import           Data.List                    (intercalate)-import           Data.Monoid                  (mappend) import           Prelude                      hiding (id)  
src/Hakyll/Web/Template/Context.hs view
@@ -18,6 +18,7 @@     , urlField     , pathField     , titleField+    , snippetField     , dateField     , dateFieldWith     , getItemUTC@@ -31,18 +32,13 @@   ---------------------------------------------------------------------------------import           Control.Applicative           (Alternative (..), pure, (<$>))+import           Control.Applicative           (Alternative (..)) import           Control.Monad                 (msum) import           Data.List                     (intercalate)-import qualified Data.Map                      as M-import           Data.Monoid                   (Monoid (..)) import           Data.Time.Clock               (UTCTime (..)) import           Data.Time.Format              (formatTime) import qualified Data.Time.Format              as TF import           Data.Time.Locale.Compat       (TimeLocale, defaultTimeLocale)-import           System.FilePath               (splitDirectories, takeBaseName)---------------------------------------------------------------------------------- import           Hakyll.Core.Compiler import           Hakyll.Core.Compiler.Internal import           Hakyll.Core.Identifier@@ -51,6 +47,7 @@ import           Hakyll.Core.Provider import           Hakyll.Core.Util.String       (needlePrefix, splitAll) import           Hakyll.Web.Html+import           System.FilePath               (splitDirectories, takeBaseName)   --------------------------------------------------------------------------------@@ -147,6 +144,22 @@             "Hakyll.Web.Template.Context.mapContext: " ++             "can't map over a ListField!" +--------------------------------------------------------------------------------+-- | A context that allows snippet inclusion. In processed file, use as:+--+-- > ...+-- > $snippet("path/to/snippet/")$+-- > ...+--+-- The contents of the included file will not be interpolated.+--+snippetField :: Context String+snippetField = functionField "snippet" f+  where+    f [contentsPath] _ = loadBody (fromFilePath contentsPath)+    f _              i = error $+        "Too many arguments to function 'snippet()' in item " +++            show (itemIdentifier i)  -------------------------------------------------------------------------------- -- | A context that contains (in that order)@@ -274,7 +287,7 @@            -> m UTCTime         -- ^ Parsed UTCTime getItemUTC locale id' = do     metadata <- getMetadata id'-    let tryField k fmt = M.lookup k metadata >>= parseTime' fmt+    let tryField k fmt = lookupString k metadata >>= parseTime' fmt         paths          = splitDirectories $ toFilePath id'      maybe empty' return $ msum $
src/Hakyll/Web/Template/Internal.hs view
@@ -12,7 +12,7 @@   ---------------------------------------------------------------------------------import           Control.Applicative     (pure, (<$), (<$>), (<*>), (<|>))+import           Control.Applicative     ((<|>)) import           Control.Monad           (void) import           Data.Binary             (Binary, get, getWord8, put, putWord8) import           Data.Typeable           (Typeable)
tests/Hakyll/Core/Provider/Metadata/Tests.hs view
@@ -5,14 +5,13 @@   --------------------------------------------------------------------------------+import qualified Data.HashMap.Strict           as HMS+import qualified Data.Text                     as T+import qualified Data.Yaml                     as Yaml+import           Hakyll.Core.Metadata+import           Hakyll.Core.Provider.Metadata import           Test.Framework                (Test, testGroup) import           Test.HUnit                    (Assertion, (@=?))-import           Text.Parsec                   as P-import           Text.Parsec.String            (Parser)------------------------------------------------------------------------------------import           Hakyll.Core.Provider.Metadata import           TestSuite.Util  @@ -22,9 +21,11 @@     fromAssertions "page" [testPage01, testPage02]  + -------------------------------------------------------------------------------- testPage01 :: Assertion-testPage01 = testParse page ([("foo", "bar")], "qux\n")+testPage01 =+    Right (meta [("foo", "bar")], "qux\n") @=? parsePage     "---\n\     \foo: bar\n\     \---\n\@@ -33,21 +34,21 @@  -------------------------------------------------------------------------------- testPage02 :: Assertion-testPage02 = testParse page-    ([("description", descr)], "Hello I am dog\n")+testPage02 =+    Right (meta [("description", descr)], "Hello I am dog\n") @=?+    parsePage     "---\n\     \description: A long description that would look better if it\n\     \             spanned multiple lines and was indented\n\     \---\n\     \Hello I am dog\n"   where+    descr :: String     descr =         "A long description that would look better if it \         \spanned multiple lines and was indented"   ---------------------------------------------------------------------------------testParse :: (Eq a, Show a) => Parser a -> a -> String -> Assertion-testParse parser expected input = case P.parse parser "<inline>" input of-    Left err -> error $ show err-    Right x  -> expected @=? x+meta :: Yaml.ToJSON a => [(String, a)] -> Metadata+meta pairs = HMS.fromList [(T.pack k, Yaml.toJSON v) | (k, v) <- pairs]
tests/Hakyll/Core/Provider/Tests.hs view
@@ -6,14 +6,11 @@   ---------------------------------------------------------------------------------import qualified Data.Map                       as M+import           Hakyll.Core.Metadata+import           Hakyll.Core.Provider import           Test.Framework                 (Test, testGroup) import           Test.Framework.Providers.HUnit (testCase) import           Test.HUnit                     (Assertion, assert, (@=?))------------------------------------------------------------------------------------import           Hakyll.Core.Provider import           TestSuite.Util  @@ -32,9 +29,9 @@     assert $ resourceExists provider "example.md"      metadata <- resourceMetadata provider "example.md"-    Just "An example"    @=? M.lookup "title"    metadata-    Just "External data" @=? M.lookup "external" metadata+    Just "An example"    @=? lookupString "title"    metadata+    Just "External data" @=? lookupString "external" metadata      doesntExist <- resourceMetadata provider "doesntexist.md"-    M.empty @=? doesntExist+    mempty @=? doesntExist     cleanTestEnv
tests/Hakyll/Core/Routes/Tests.hs view
@@ -6,15 +6,13 @@   ---------------------------------------------------------------------------------import qualified Data.Map               as M+import           Data.Maybe             (fromMaybe)+import           Hakyll.Core.Identifier+import           Hakyll.Core.Metadata+import           Hakyll.Core.Routes import           System.FilePath        ((</>)) import           Test.Framework         (Test, testGroup) import           Test.HUnit             (Assertion, (@=?))------------------------------------------------------------------------------------import           Hakyll.Core.Identifier-import           Hakyll.Core.Routes import           TestSuite.Util  @@ -37,7 +35,7 @@         "tags/rss/bar"      , testRoutes "food/example.md" (metadataRoute $ \md -> customRoute $ \id' ->-        M.findWithDefault "?" "subblog" md </> toFilePath id')+        fromMaybe "?" (lookupString "subblog" md) </> toFilePath id')         "example.md"     ] 
tests/Hakyll/Core/Rules/Tests.hs view
@@ -8,22 +8,19 @@ -------------------------------------------------------------------------------- import           Data.IORef                     (IORef, newIORef, readIORef,                                                  writeIORef)-import qualified Data.Map                       as M import qualified Data.Set                       as S-import           System.FilePath                ((</>))-import           Test.Framework                 (Test, testGroup)-import           Test.HUnit                     (Assertion, assert, (@=?))----------------------------------------------------------------------------------- import           Hakyll.Core.Compiler import           Hakyll.Core.File import           Hakyll.Core.Identifier import           Hakyll.Core.Identifier.Pattern+import           Hakyll.Core.Metadata import           Hakyll.Core.Routes import           Hakyll.Core.Rules import           Hakyll.Core.Rules.Internal import           Hakyll.Web.Pandoc+import           System.FilePath                ((</>))+import           Test.Framework                 (Test, testGroup)+import           Test.HUnit                     (Assertion, assert, (@=?)) import           TestSuite.Util  @@ -89,7 +86,7 @@         compile getResourceString      version "metadataMatch" $-        matchMetadata "*.md" (\md -> M.lookup "subblog" md == Just "food") $ do+        matchMetadata "*.md" (\md -> lookupString "subblog" md == Just "food") $ do             route $ customRoute $ \id' -> "food" </> toFilePath id'             compile getResourceString