1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
--------------------------------------------------------------------------------
{-# LANGUAGE CPP #-}
module Hakyll.Core.Metadata
( Metadata
, lookupString
, lookupStringList
, MonadMetadata (..)
, getMetadataField
, getMetadataField'
, makePatternDependency
, BinaryMetadata (..)
) where
--------------------------------------------------------------------------------
import Control.Monad (forM)
#if !MIN_VERSION_base(4,13,0)
import Control.Monad.Fail (MonadFail)
#endif
import Data.Binary (Binary (..), getWord8,
putWord8, Get)
#if MIN_VERSION_aeson(2,0,0)
import qualified Data.Aeson.KeyMap as KeyMap
import qualified Data.Aeson.Key as AK
#else
import qualified Data.HashMap.Strict as KeyMap
#endif
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 = Yaml.Object
--------------------------------------------------------------------------------
lookupString :: String -> Metadata -> Maybe String
lookupString key meta = KeyMap.lookup (keyFromString key) meta >>= Yaml.toString
--------------------------------------------------------------------------------
lookupStringList :: String -> Metadata -> Maybe [String]
lookupStringList key meta =
KeyMap.lookup (keyFromString key) meta >>= Yaml.toList >>= mapM Yaml.toString
--------------------------------------------------------------------------------
class Monad m => MonadMetadata m where
getMetadata :: Identifier -> m Metadata
getMatches :: Pattern -> m [Identifier]
getAllMetadata :: Pattern -> m [(Identifier, Metadata)]
getAllMetadata pattern = do
matches' <- getMatches pattern
forM matches' $ \id' -> do
metadata <- getMetadata id'
return (id', metadata)
--------------------------------------------------------------------------------
getMetadataField :: MonadMetadata m => Identifier -> String -> m (Maybe String)
getMetadataField identifier key = do
metadata <- getMetadata identifier
return $ lookupString key metadata
--------------------------------------------------------------------------------
-- | Version of 'getMetadataField' which throws an error if the field does not
-- exist.
getMetadataField' :: (MonadFail m, MonadMetadata m) => Identifier -> String -> m String
getMetadataField' identifier key = do
field <- getMetadataField identifier key
case field of
Just v -> return v
Nothing -> fail $ "Hakyll.Core.Metadata.getMetadataField': " ++
"Item " ++ show identifier ++ " has no metadata field " ++ show key
--------------------------------------------------------------------------------
makePatternDependency :: MonadMetadata m => Pattern -> m Dependency
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 (\(k, v) -> (keyToText k, BinaryYaml v)) $ KeyMap.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 $
KeyMap.fromList $ map (\(k, v) -> (keyFromText k, unBinaryYaml v)) 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"
--------------------------------------------------------------------------------
#if MIN_VERSION_aeson(2,0,0)
keyFromString :: String -> AK.Key
keyFromString = AK.fromString
keyToText :: AK.Key -> T.Text
keyToText = AK.toText
keyFromText :: T.Text -> AK.Key
keyFromText = AK.fromText
#else
keyFromString :: String -> T.Text
keyFromString = T.pack
keyToText :: T.Text -> T.Text
keyToText = id
keyFromText :: T.Text -> T.Text
keyFromText = id
#endif
|