module Text.Hakyll.File
( toDestination
, toCache
, toUrl
, toRoot
, removeSpaces
, makeDirectories
, getRecursiveContents
, sortByBaseName
, havingExtension
, directory
, isMoreRecent
, isFileMoreRecent
) where
import System.Directory
import System.FilePath
import System.Time (ClockTime)
import Control.Monad
import Data.List (isPrefixOf, sortBy)
import Data.Ord (comparing)
import Control.Monad.Reader (liftIO)
import Text.Hakyll.HakyllMonad
import Text.Hakyll.Internal.FileType (isRenderableFile)
removeLeadingSeparator :: FilePath -> FilePath
removeLeadingSeparator [] = []
removeLeadingSeparator path
| head path' `elem` pathSeparators = tail path'
| otherwise = path'
where
path' = if "$root" `isPrefixOf` path then drop 5 path
else path
toDestination :: FilePath -> Hakyll FilePath
toDestination url = do dir <- askHakyll siteDirectory
enableIndexUrl' <- askHakyll enableIndexUrl
let destination = if enableIndexUrl' && separatorEnd
then dir </> noSeparator </> "index.html"
else dir </> noSeparator
return destination
where
noSeparator = removeLeadingSeparator url
separatorEnd = not (null url) && last url == '/'
toCache :: FilePath -> Hakyll FilePath
toCache path = do dir <- askHakyll cacheDirectory
return $ dir </> removeLeadingSeparator path
toUrl :: FilePath -> Hakyll FilePath
toUrl path = do enableIndexUrl' <- askHakyll enableIndexUrl
return $ if not (isRenderableFile path)
then path
else if enableIndexUrl' && not isIndex
then indexUrl
else withSimpleHtmlExtension
where
isIndex = dropExtension (takeFileName path) == "index"
withSimpleHtmlExtension = flip addExtension ".html" $ dropExtension path
indexUrl = dropExtension path ++ "/"
toRoot :: FilePath -> FilePath
toRoot = emptyException . joinPath . map parent . splitPath
. takeDirectory . removeLeadingSeparator
where
parent = const ".."
emptyException [] = "."
emptyException x = x
removeSpaces :: FilePath -> FilePath
removeSpaces = map swap
where
swap ' ' = '-'
swap x = x
makeDirectories :: FilePath -> Hakyll ()
makeDirectories path = liftIO $ createDirectoryIfMissing True dir
where
dir = takeDirectory path
getRecursiveContents :: FilePath -> Hakyll [FilePath]
getRecursiveContents topdir = do
names <- liftIO $ getDirectoryContents topdir
let properNames = filter isProper names
paths <- forM properNames $ \name -> do
let path = topdir </> name
isDirectory <- liftIO $ doesDirectoryExist path
if isDirectory
then getRecursiveContents path
else return [path]
return (concat paths)
where
isProper = not . (== '.') . head
sortByBaseName :: [FilePath] -> [FilePath]
sortByBaseName = sortBy compareBaseName
where
compareBaseName = comparing takeFileName
havingExtension :: String -> [FilePath] -> [FilePath]
havingExtension extension = filter ((==) extension . takeExtension)
directory :: (FilePath -> Hakyll ()) -> FilePath -> Hakyll ()
directory action dir = getRecursiveContents dir >>= mapM_ action
isMoreRecent :: ClockTime
-> [FilePath]
-> Hakyll Bool
isMoreRecent _ [] = return True
isMoreRecent timeStamp depends = do
dependsModified <- liftIO $ mapM getModificationTime depends
return (timeStamp >= maximum dependsModified)
isFileMoreRecent :: FilePath
-> [FilePath]
-> Hakyll Bool
isFileMoreRecent file depends = do
exists <- liftIO $ doesFileExist file
if not exists
then return False
else do timeStamp <- liftIO $ getModificationTime file
isMoreRecent timeStamp depends