hakyll-convert-0.2.0.0: Hakyll/Convert/OutputFormat.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
module Hakyll.Convert.OutputFormat
(validOutputFormat, formatPath)
where
import Data.Default
import Data.Time.Format (formatTime, defaultTimeLocale)
import System.FilePath
import Hakyll.Convert.Common
import qualified Data.Text as T
import qualified Data.Map.Strict as M
validOutputFormat :: T.Text -> Bool
validOutputFormat format
| T.null format = False
| otherwise =
case formatPath format def of
Just _ -> True
Nothing -> False
formatPath :: T.Text -> DistilledPost -> Maybe T.Text
formatPath format post = helper [] format >>= return.T.concat
where
helper acc input =
case T.uncons input of
Just ('%', rest) ->
case T.uncons rest of
Just (ch, rest2) ->
if ch `M.member` acceptableFormats
then let formatter = acceptableFormats M.! ch
in helper ((formatter post):acc) rest2
else Nothing
Just (ch, rest) -> helper ((T.singleton ch):acc) rest
Nothing -> Just $ reverse acc
-- When adding a new format, don't forget to update the help message in
-- tools/hakyll-convert.hs
acceptableFormats :: M.Map Char (DistilledPost -> T.Text)
acceptableFormats = M.fromList [
-- this lets users put literal percent sign in the format)
('%', const $ T.singleton '%')
, ('o', fmtOriginalPath) -- original filepath, like 2016/01/02/blog-post.html
, ('s', fmtSlug) -- original slug, i.e. "blog-post" from the example above
, ('y', fmtYear2) -- publication year, 2 digits
, ('Y', fmtYear4) -- publication year, 4 digits
, ('m', fmtMonth) -- publication month
, ('d', fmtDay) -- publication day
, ('H', fmtHour) -- publication hour
, ('M', fmtMinute) -- publication minute
, ('S', fmtSecond) -- publication second
]
fmtOriginalPath post =
T.pack
. dropTrailingSlash
. dropExtensions
$ chopUri (dpUri post)
where
dropTrailingSlash = reverse . dropWhile (== '/') . reverse
chopUri (dropPrefix "http://" -> ("",rest)) =
-- carelessly assumes we can treat URIs like filepaths
joinPath $ drop 1 -- drop the domain
$ splitPath rest
chopUri u = error $
"We've wrongly assumed that blog post URIs start with http://, but we got: " ++ u
dropPrefix :: Eq a => [a] -> [a] -> ([a],[a])
dropPrefix (x:xs) (y:ys) | x == y = dropPrefix xs ys
dropPrefix left right = (left,right)
fmtSlug post =
T.reverse
. (T.takeWhile (/= '/'))
. T.reverse
$ fmtOriginalPath post
fmtDate format = T.pack . (formatTime defaultTimeLocale format) . dpDate
fmtYear2 = fmtDate "%y"
fmtYear4 = fmtDate "%Y"
fmtMonth = fmtDate "%m"
fmtDay = fmtDate "%d"
fmtHour = fmtDate "%H"
fmtMinute = fmtDate "%M"
fmtSecond = fmtDate "%S"