summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJasper Van der Jeugt <jaspervdj@gmail.com>2014-01-23 01:29:01 -0800
committerJasper Van der Jeugt <jaspervdj@gmail.com>2014-01-23 01:29:01 -0800
commit63107a6f75335cabe828751d2bef4704667cad76 (patch)
tree36aebb3a2142deed11f5e0366c7092bb19cff82a
parentbc360a3f4654d0d32c00c408c170aaede24f1b17 (diff)
parentdbabe0325b9d7bca3b14c2b33e686b8151fa79aa (diff)
downloadhakyll-63107a6f75335cabe828751d2bef4704667cad76.tar.gz
Merge pull request #190 from krsch/master
Implemented per-directory metadata support
-rw-r--r--hakyll.cabal1
-rw-r--r--src/Hakyll/Core/Metadata.hs11
-rw-r--r--src/Hakyll/Core/Provider/Metadata.hs37
-rw-r--r--src/Hakyll/Core/Rules/Default.hs24
-rw-r--r--src/Hakyll/Core/Runtime.hs5
-rw-r--r--tests/Hakyll/Core/Provider/GlobalMetadata/Tests.hs31
-rw-r--r--tests/TestSuite.hs2
-rw-r--r--tests/data/metadata27
-rw-r--r--tests/data/posts/2013-10-18-metadata-test.md4
-rw-r--r--tests/data/posts/2013-10-18-metadata-test.md.metadata2
-rw-r--r--tests/data/posts/metadata20
11 files changed, 160 insertions, 4 deletions
diff --git a/hakyll.cabal b/hakyll.cabal
index cb8e8ed..9173bac 100644
--- a/hakyll.cabal
+++ b/hakyll.cabal
@@ -132,6 +132,7 @@ Library
Hakyll.Core.Provider.Metadata
Hakyll.Core.Provider.MetadataCache
Hakyll.Core.Rules.Internal
+ Hakyll.Core.Rules.Default
Hakyll.Core.Runtime
Hakyll.Core.Store
Hakyll.Core.Util.File
diff --git a/src/Hakyll/Core/Metadata.hs b/src/Hakyll/Core/Metadata.hs
index 7902b94..a123c18 100644
--- a/src/Hakyll/Core/Metadata.hs
+++ b/src/Hakyll/Core/Metadata.hs
@@ -5,6 +5,7 @@ module Hakyll.Core.Metadata
, getMetadataField
, getMetadataField'
, makePatternDependency
+ , metadataFiles
) where
@@ -12,6 +13,7 @@ module Hakyll.Core.Metadata
import Control.Monad (forM)
import Data.Map (Map)
import qualified Data.Map as M
+import System.FilePath.Posix ((</>), takeDirectory)
--------------------------------------------------------------------------------
@@ -61,3 +63,12 @@ makePatternDependency :: MonadMetadata m => Pattern -> m Dependency
makePatternDependency pattern = do
matches' <- getMatches pattern
return $ PatternDependency pattern matches'
+
+--------------------------------------------------------------------------------
+-- | Returns a list of all directory-wise metadata files, subdir first, global last
+metadataFiles :: Identifier -> [Identifier]
+metadataFiles identifier = local : go (takeDirectory $ toFilePath identifier) where
+ go "." = [fromFilePath "metadata"]
+ go dir = fromFilePath (dir </> "metadata") : go (takeDirectory dir)
+ local = fromFilePath $ toFilePath identifier ++ ".metadata"
+
diff --git a/src/Hakyll/Core/Provider/Metadata.hs b/src/Hakyll/Core/Provider/Metadata.hs
index 7e4d7ed..889291f 100644
--- a/src/Hakyll/Core/Provider/Metadata.hs
+++ b/src/Hakyll/Core/Provider/Metadata.hs
@@ -20,6 +20,8 @@ import System.IO as IO
import Text.Parsec ((<?>))
import qualified Text.Parsec as P
import Text.Parsec.String (Parser)
+import System.FilePath.Posix
+import Control.Monad (liftM)
--------------------------------------------------------------------------------
@@ -28,7 +30,7 @@ import Hakyll.Core.Metadata
import Hakyll.Core.Provider.Internal
import Hakyll.Core.Util.Parser
import Hakyll.Core.Util.String
-
+import Hakyll.Core.Identifier.Pattern
--------------------------------------------------------------------------------
loadMetadata :: Provider -> Identifier -> IO (Metadata, Maybe String)
@@ -42,7 +44,9 @@ loadMetadata p identifier = do
Nothing -> return M.empty
Just mi' -> loadMetadataFile $ resourceFilePath p mi'
- return (M.union md emd, body)
+ gmd <- loadGlobalMetadata p identifier
+
+ return (M.unions [md, gmd], body)
where
normal = setVersion Nothing identifier
fp = resourceFilePath p identifier
@@ -133,3 +137,32 @@ page = do
metadata' <- P.option [] metadataBlock
body <- P.many P.anyChar
return (metadata', body)
+
+
+--------------------------------------------------------------------------------
+-- | Load directory-wise metadata
+loadGlobalMetadata :: Provider -> Identifier -> IO Metadata
+loadGlobalMetadata p fp = liftM M.fromList $ loadgm fp where
+ loadgm :: Identifier -> IO [(String, String)]
+ loadgm = liftM concat . mapM loadOne . reverse . filter (resourceExists p) . metadataFiles
+ loadOne mfp =
+ let path = resourceFilePath p mfp
+ dir = takeDirectory $ toFilePath mfp
+ -- TODO: It might be better to print warning and continue
+ in either (error.show) (findMetadata dir) . P.parse namedMetadata path <$> readFile path
+ findMetadata dir =
+ concatMap snd . filter (flip matches fp . fromGlob . normalise . combine dir . fst)
+
+namedMetadata :: Parser [(String, [(String, String)])]
+namedMetadata = liftA2 (:) (namedMetadataBlock False) $ P.many $ namedMetadataBlock True
+
+namedMetadataBlock :: Bool -> Parser (String, [(String, String)])
+namedMetadataBlock isNamed = do
+ name <- if isNamed
+ then P.many1 (P.char '-') *> P.many inlineSpace *> P.manyTill P.anyChar newline
+ else pure "**"
+ metadata' <- metadata
+ P.skipMany P.space
+ return (name, metadata')
+
+
diff --git a/src/Hakyll/Core/Rules/Default.hs b/src/Hakyll/Core/Rules/Default.hs
new file mode 100644
index 0000000..fee78c5
--- /dev/null
+++ b/src/Hakyll/Core/Rules/Default.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Hakyll.Core.Rules.Default
+ ( internalRules
+ , addMetadataDependencies
+ )
+where
+import Hakyll.Core.Rules
+import Hakyll.Core.Compiler
+import Hakyll.Core.Compiler.Internal (compilerTellDependencies)
+import Hakyll.Core.Metadata (getMatches, metadataFiles)
+import Hakyll.Core.Identifier.Pattern(fromList)
+
+internalRules :: Rules ()
+internalRules = do
+ match "metadata" $ compile $ makeItem ()
+ match "**/metadata" $ compile $ makeItem ()
+ match "**.metadata" $ compile $ makeItem ()
+
+--------------------------------------------------------------------------------
+addMetadataDependencies :: Compiler ()
+addMetadataDependencies =
+ compilerTellDependencies . map IdentifierDependency =<< getMatches . fromList =<< fmap metadataFiles getUnderlying
+
+
diff --git a/src/Hakyll/Core/Runtime.hs b/src/Hakyll/Core/Runtime.hs
index 824d11b..12285ad 100644
--- a/src/Hakyll/Core/Runtime.hs
+++ b/src/Hakyll/Core/Runtime.hs
@@ -35,6 +35,7 @@ import qualified Hakyll.Core.Logger as Logger
import Hakyll.Core.Provider
import Hakyll.Core.Routes
import Hakyll.Core.Rules.Internal
+import Hakyll.Core.Rules.Default
import Hakyll.Core.Store (Store)
import qualified Hakyll.Core.Store as Store
import Hakyll.Core.Util.File
@@ -53,7 +54,7 @@ run config verbosity rules = do
provider <- newProvider store (shouldIgnoreFile config) $
providerDirectory config
Logger.message logger "Running rules..."
- ruleSet <- runRules rules provider
+ ruleSet <- runRules (rules >> internalRules) provider
-- Get old facts
mOldFacts <- Store.get store factsKey
@@ -186,7 +187,7 @@ chase trail id'
config <- runtimeConfiguration <$> ask
Logger.debug logger $ "Processing " ++ show id'
- let compiler = todo M.! id'
+ let compiler = addMetadataDependencies >> todo M.! id'
read' = CompilerRead
{ compilerConfig = config
, compilerUnderlying = id'
diff --git a/tests/Hakyll/Core/Provider/GlobalMetadata/Tests.hs b/tests/Hakyll/Core/Provider/GlobalMetadata/Tests.hs
new file mode 100644
index 0000000..289e2ac
--- /dev/null
+++ b/tests/Hakyll/Core/Provider/GlobalMetadata/Tests.hs
@@ -0,0 +1,31 @@
+--------------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+module Hakyll.Core.Provider.GlobalMetadata.Tests
+ ( tests
+ ) where
+
+--------------------------------------------------------------------------------
+import qualified Data.Map as M
+import Control.Monad (forM_)
+import Test.Framework (Test, testGroup)
+import Test.HUnit (Assertion, (@=?))
+
+
+--------------------------------------------------------------------------------
+import Hakyll.Core.Provider (resourceMetadata)
+import TestSuite.Util
+
+--------------------------------------------------------------------------------
+tests :: Test
+tests = testGroup "Hakyll.Core.Provider.GlobalMetadata.Tests" $
+ fromAssertions "page" [testPage]
+
+testPage :: Assertion
+testPage = do
+ store <- newTestStore
+ provider <- newTestProvider store
+
+ metadata <- resourceMetadata provider "posts/2013-10-18-metadata-test.md"
+ forM_ ["1", "2", "3", "4", "5", "6", "7", "8"] $ \a ->
+ Just a @=? M.lookup ('a':a) metadata
+
diff --git a/tests/TestSuite.hs b/tests/TestSuite.hs
index 3622301..9cc446e 100644
--- a/tests/TestSuite.hs
+++ b/tests/TestSuite.hs
@@ -12,6 +12,7 @@ import Test.Framework (defaultMain)
import qualified Hakyll.Core.Dependencies.Tests
import qualified Hakyll.Core.Identifier.Tests
import qualified Hakyll.Core.Provider.Metadata.Tests
+import qualified Hakyll.Core.Provider.GlobalMetadata.Tests
import qualified Hakyll.Core.Provider.Tests
import qualified Hakyll.Core.Routes.Tests
import qualified Hakyll.Core.Rules.Tests
@@ -32,6 +33,7 @@ main = defaultMain
[ Hakyll.Core.Dependencies.Tests.tests
, Hakyll.Core.Identifier.Tests.tests
, Hakyll.Core.Provider.Metadata.Tests.tests
+ , Hakyll.Core.Provider.GlobalMetadata.Tests.tests
, Hakyll.Core.Provider.Tests.tests
, Hakyll.Core.Routes.Tests.tests
, Hakyll.Core.Rules.Tests.tests
diff --git a/tests/data/metadata b/tests/data/metadata
new file mode 100644
index 0000000..1145976
--- /dev/null
+++ b/tests/data/metadata
@@ -0,0 +1,27 @@
+--- posts/2013-10-18-metadata-test.md
+a1: 8
+a2: 8
+a3: 8
+a4: 8
+a5: 8
+a6: 8
+a7: 8
+a8: 8
+
+--- posts/*
+a1: 7
+a2: 7
+a3: 7
+a4: 7
+a5: 7
+a6: 7
+a7: 7
+
+--- **
+a1: 6
+a2: 6
+a3: 6
+a4: 6
+a5: 6
+a6: 6
+
diff --git a/tests/data/posts/2013-10-18-metadata-test.md b/tests/data/posts/2013-10-18-metadata-test.md
new file mode 100644
index 0000000..86a3e67
--- /dev/null
+++ b/tests/data/posts/2013-10-18-metadata-test.md
@@ -0,0 +1,4 @@
+---
+a1: 1
+---
+Nothing interesting here.
diff --git a/tests/data/posts/2013-10-18-metadata-test.md.metadata b/tests/data/posts/2013-10-18-metadata-test.md.metadata
new file mode 100644
index 0000000..7ee78b6
--- /dev/null
+++ b/tests/data/posts/2013-10-18-metadata-test.md.metadata
@@ -0,0 +1,2 @@
+a1: 2
+a2: 2
diff --git a/tests/data/posts/metadata b/tests/data/posts/metadata
new file mode 100644
index 0000000..4a1be71
--- /dev/null
+++ b/tests/data/posts/metadata
@@ -0,0 +1,20 @@
+--- **
+a1: 5
+a2: 5
+a3: 5
+a4: 5
+a5: 5
+
+--- *
+a1: 4
+a2: 4
+a3: 4
+a4: 4
+
+--- 2013-10-18-metadata-test.md
+a1: 3
+a2: 3
+a3: 3
+
+--- nonexistent
+a3: 0