From f6dc5c62465b2bb2a5f39c9b4b896f7fd6e9323a Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Wed, 3 Jun 2020 22:14:24 +0200 Subject: [PATCH] Allow specifying a metadata provider In addition to parsing metadata header & metadata files it will allow any custom routine to extract metadata from the resource files, for example with Pandoc --- lib/Hakyll/Core/Configuration.hs | 20 +++++++++++++------- lib/Hakyll/Core/Provider.hs | 16 +++++++++++++--- lib/Hakyll/Core/Provider/Internal.hs | 10 +++++++--- lib/Hakyll/Core/Provider/Metadata.hs | 5 +++-- lib/Hakyll/Core/Runtime.hs | 4 ++-- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/lib/Hakyll/Core/Configuration.hs b/lib/Hakyll/Core/Configuration.hs index 52b23ec40..4e32caaf1 100644 --- a/lib/Hakyll/Core/Configuration.hs +++ b/lib/Hakyll/Core/Configuration.hs @@ -8,14 +8,15 @@ module Hakyll.Core.Configuration -------------------------------------------------------------------------------- -import Data.Default (Default (..)) -import Data.List (isPrefixOf, isSuffixOf) -import System.Directory (canonicalizePath) -import System.Exit (ExitCode) -import System.FilePath (isAbsolute, normalise, takeFileName) -import System.IO.Error (catchIOError) -import System.Process (system) +import Data.Default (Default (..)) +import Data.List (isPrefixOf, isSuffixOf) +import System.Directory (canonicalizePath) +import System.Exit (ExitCode) +import System.FilePath (isAbsolute, normalise, takeFileName) +import System.IO.Error (catchIOError) +import System.Process (system) +import Hakyll.Core.Metadata -------------------------------------------------------------------------------- data Configuration = Configuration @@ -78,6 +79,10 @@ data Configuration = Configuration -- One can also override the port as a command line argument: -- ./site preview -p 1234 previewPort :: Int + , -- | Function to extract metadata from the files + -- + -- By default it returns empty metadata + provideMetadata :: FilePath -> IO Metadata } -------------------------------------------------------------------------------- @@ -98,6 +103,7 @@ defaultConfiguration = Configuration , inMemoryCache = True , previewHost = "127.0.0.1" , previewPort = 8000 + , provideMetadata = const (return mempty) } where ignoreFile' path diff --git a/lib/Hakyll/Core/Provider.hs b/lib/Hakyll/Core/Provider.hs index 384f5b1d0..65e150713 100644 --- a/lib/Hakyll/Core/Provider.hs +++ b/lib/Hakyll/Core/Provider.hs @@ -5,6 +5,7 @@ module Hakyll.Core.Provider ( -- * Constructing resource providers Internal.Provider , newProvider + , newProvider' -- * Querying resource properties , Internal.resourceList @@ -24,20 +25,29 @@ module Hakyll.Core.Provider -------------------------------------------------------------------------------- +import Hakyll.Core.Metadata import qualified Hakyll.Core.Provider.Internal as Internal import qualified Hakyll.Core.Provider.MetadataCache as Internal import Hakyll.Core.Store (Store) -------------------------------------------------------------------------------- --- | Create a resource provider +-- | Create a resource provider with the void metadata provider newProvider :: Store -- ^ Store to use -> (FilePath -> IO Bool) -- ^ Should we ignore this file? -> FilePath -- ^ Search directory -> IO Internal.Provider -- ^ Resulting provider -newProvider store ignore directory = do +newProvider store ignore = newProvider' store ignore (const $ return mempty) + +-- | Create a resource provider +newProvider' :: Store -- ^ Store to use + -> (FilePath -> IO Bool) -- ^ Should we ignore this file? + -> (FilePath -> IO Metadata) -- ^ Metadata provider + -> FilePath -- ^ Search directory + -> IO Internal.Provider -- ^ Resulting provider +newProvider' store ignore metadata directory = do -- Delete metadata cache where necessary - p <- Internal.newProvider store ignore directory + p <- Internal.newProvider store ignore metadata directory mapM_ (Internal.resourceInvalidateMetadataCache p) $ filter (Internal.resourceModified p) $ Internal.resourceList p return p diff --git a/lib/Hakyll/Core/Provider/Internal.hs b/lib/Hakyll/Core/Provider/Internal.hs index c298653af..777decbaa 100644 --- a/lib/Hakyll/Core/Provider/Internal.hs +++ b/lib/Hakyll/Core/Provider/Internal.hs @@ -45,6 +45,7 @@ import System.Time (formatCalendarTime, toCalendarTime) -------------------------------------------------------------------------------- import Hakyll.Core.Identifier +import Hakyll.Core.Metadata import Hakyll.Core.Store (Store) import qualified Hakyll.Core.Store as Store import Hakyll.Core.Util.File @@ -95,16 +96,19 @@ data Provider = Provider providerOldFiles :: Map Identifier ResourceInfo , -- | Underlying persistent store for caching providerStore :: Store - } deriving (Show) + -- | A custom function to extract metadata from files + , providerMetadata :: FilePath -> IO Metadata + } -------------------------------------------------------------------------------- -- | Create a resource provider newProvider :: Store -- ^ Store to use -> (FilePath -> IO Bool) -- ^ Should we ignore this file? + -> (FilePath -> IO Metadata) -- ^ Metadata provider -> FilePath -- ^ Search directory -> IO Provider -- ^ Resulting provider -newProvider store ignore directory = do +newProvider store ignore metadata directory = do list <- map fromFilePath <$> getRecursiveContents ignore directory let universe = S.fromList list files <- fmap (maxmtime . M.fromList) $ forM list $ \identifier -> do @@ -116,7 +120,7 @@ newProvider store ignore directory = do oldFiles <- fromMaybe mempty . Store.toMaybe <$> Store.get store oldKey oldFiles `deepseq` Store.set store oldKey files - return $ Provider directory files oldFiles store + return $ Provider directory files oldFiles store metadata where oldKey = ["Hakyll.Core.Provider.Internal.newProvider", "oldFiles"] diff --git a/lib/Hakyll/Core/Provider/Metadata.hs b/lib/Hakyll/Core/Provider/Metadata.hs index c74627b6e..1630b0c70 100644 --- a/lib/Hakyll/Core/Provider/Metadata.hs +++ b/lib/Hakyll/Core/Provider/Metadata.hs @@ -27,7 +27,7 @@ import Hakyll.Core.Identifier import Hakyll.Core.Metadata import Hakyll.Core.Provider.Internal import System.IO as IO -import System.IO.Error (modifyIOError, ioeSetLocation) +import System.IO.Error (ioeSetLocation, modifyIOError) -------------------------------------------------------------------------------- @@ -42,7 +42,8 @@ loadMetadata p identifier = do Nothing -> return mempty Just mi' -> loadMetadataFile $ resourceFilePath p mi' - return (md <> emd, body) + mdp <- providerMetadata p fp + return (md <> emd <> mdp, body) where normal = setVersion Nothing identifier fp = resourceFilePath p identifier diff --git a/lib/Hakyll/Core/Runtime.hs b/lib/Hakyll/Core/Runtime.hs index 922b6767e..68970cd90 100644 --- a/lib/Hakyll/Core/Runtime.hs +++ b/lib/Hakyll/Core/Runtime.hs @@ -47,8 +47,8 @@ run config logger rules = do Logger.message logger "Creating store..." store <- Store.new (inMemoryCache config) $ storeDirectory config Logger.message logger "Creating provider..." - provider <- newProvider store (shouldIgnoreFile config) $ - providerDirectory config + provider <- newProvider' store (shouldIgnoreFile config) (provideMetadata config) + (providerDirectory config) Logger.message logger "Running rules..." ruleSet <- runRules rules provider