Copyright © 2008 Dave Bayer. Subject to a BSD-style license.
This module is part of the Annote project.
module Files
(createDirectory,doesFileExist,doesDirectoryExist,
reportError,baseName,newSuffix,isNewer)
where
Files provides miscellaneous file utilities.
Directory
provides an interface for directory manipulation.
We import the following functions:
createDirectory :: FilePath -> IO ()
getModificationTime :: FilePath -> IO ClockTime
doesFileExist :: FilePath -> IO Bool
doesDirectoryExist :: FilePath -> IO Bool
import Directory
(createDirectory,getModificationTime,doesFileExist,doesDirectoryExist)
Control.Exception provides support for raising and catching
exceptions.
We import the following functions:
tryJust :: (Exception -> Maybe b) -> IO a -> IO (Either b a)
ioErrors :: Exception -> Maybe IOError
import Control.Exception (tryJust,ioErrors)
System.IO is the standard IO library.
We import the following function:
hPutStrLn :: Handle -> String -> IO ()
import System.IO (stderr,hPutStrLn)
Regex provides regular expression matching.
It is a wrapper around Text.Regex.
import Regex (mkRegex,mkSub,doSub,isMatch)
reportErrorreportError writes an error message to stderr.
The reversed argument order is chosen to allow calls of the form
reportError msg $ who
where msg is a simple string, but who needs to be constructed.
reportError :: String → String → IO () reportError msg who = hPutStrLn stderr $ "annote: " ++ who ++ ": " ++ msg
baseNamebaseName returns the base filename of name.
baseName :: FilePath → FilePath
baseName name =
doSub name $ mkSub ("^.*/", "")
newSuffixnewSuffix replaces the filename extension of name with ext.
If name does not have an extension, then ext is added.
newSuffix :: FilePath → String → FilePath
newSuffix name ext =
if isMatch name $ mkRegex "[.]"
then doSub name $ mkSub ("[.][^.]*$", suffix)
else name ++ suffix
where suffix = '.' : ext
isNewerisNewer is a predicate, reporting whether or not name1 has a more
recent modification date than name2.
It returns False if name1 does not exist, and True if name2
does not exist.
isNewer can be used to decide whether or not name2 should be updated
from name1.
getModificationTime may fail with isPermissionError even though we have
already checked existence; we catch and report this error.
isNewer :: FilePath → FilePath → IO Bool
isNewer name1 name2 =
do exists1 ← doesFileExist name1
if exists1
then do
exists2 ← doesFileExist name2
if exists2
then do
try ← tryJust ioErrors newer
case try of
Right t → return t
Left _ → do
reportError perr $ name1 ++ " or " ++ name2
return False
else do
return True
else do
reportError derr name1
return False
where newer = do
t1 ← getModificationTime name1
t2 ← getModificationTime name2
return $ t1 > t2
derr = "file does not exist"
perr = "file permission error"