on fb71a21 help sign in
82 lines 3.0 kB history raw
1-- | A module containing various function for manipulating and examinating
2-- files and directories.
3module Text.Hakyll.File
4 ( toDestination
5 , toCache
6 , toURL
7 , removeSpaces
8 , makeDirectories
9 , getRecursiveContents
10 , havingExtension
11 , isCacheValid
12 , directory
13 ) where
15import System.Directory
16import System.FilePath
17import Control.Monad
19-- | Auxiliary function to remove pathSeparators form the start. We don't deal
20-- with absolute paths here.
21removeLeadingSeparator :: FilePath -> FilePath
22removeLeadingSeparator [] = []
23removeLeadingSeparator p@(x:xs) | x `elem` pathSeparators = xs
24 | otherwise = p
26-- | Convert a relative filepath to a filepath in the destination (_site).
27toDestination :: FilePath -> FilePath
28toDestination path = "_site" </> (removeLeadingSeparator path)
30-- | Convert a relative filepath to a filepath in the cache (_cache).
31toCache :: FilePath -> FilePath
32toCache path = "_cache" </> (removeLeadingSeparator path)
34-- | Get the url for a given page.
35toURL :: FilePath -> FilePath
36toURL = flip addExtension ".html" . dropExtension
38-- | Swaps spaces for '-'.
39removeSpaces :: FilePath -> FilePath
40removeSpaces = map swap
41 where swap ' ' = '-'
42 swap x = x
44-- | Given a path to a file, try to make the path writable by making
45-- all directories on the path.
46makeDirectories :: FilePath -> IO ()
47makeDirectories path = createDirectoryIfMissing True dir
48 where dir = takeDirectory path
50-- | Get all contents of a directory. Note that files starting with a dot (.)
51-- will be ignored.
52getRecursiveContents :: FilePath -> IO [FilePath]
53getRecursiveContents topdir = do
54 names <- getDirectoryContents topdir
55 let properNames = filter isProper names
56 paths <- forM properNames $ \name -> do
57 let path = topdir </> name
58 isDirectory <- doesDirectoryExist path
59 if isDirectory
60 then getRecursiveContents path
61 else return [path]
62 return (concat paths)
63 where isProper = not . (== '.') . head
65-- | A filter that takes all file names with a given extension. Prefix the
66-- extension with a dot:
67--
68-- > havingExtension ".markdown" ["index.markdown", "style.css"] == ["index.markdown"]
69havingExtension :: String -> [FilePath] -> [FilePath]
70havingExtension extension = filter ((==) extension . takeExtension)
72-- | Perform an IO action on every file in a given directory.
73directory :: (FilePath -> IO ()) -> FilePath -> IO ()
74directory action dir = getRecursiveContents dir >>= mapM_ action
76-- | Check if a cache file is still valid.
77isCacheValid :: FilePath -> [FilePath] -> IO Bool
78isCacheValid cache depends = doesFileExist cache >>= \exists ->
79 if not exists then return False
80 else do dependsModified <- (mapM getModificationTime depends) >>= return . maximum
81 cacheModified <- getModificationTime cache
82 return (cacheModified >= dependsModified)