{-# LANGUAGE CPP #-}
module Curry.Files.PathUtils
(
lookupCurryFile
, lookupCurryModule
, lookupCurryInterface
, lookupFile
, getModuleModTime
, writeModule
, readModule
, addVersion
, checkVersion
) where
import qualified Control.Exception as C (IOException, handle)
import Control.Monad (liftM)
import Data.List (isPrefixOf, isSuffixOf)
import System.FilePath
import System.Directory
import System.IO
#if MIN_VERSION_directory(1,2,0)
import Data.Time (UTCTime)
#else
import System.Time (ClockTime)
#endif
import Curry.Base.Ident
import Curry.Files.Filenames
lookupCurryFile :: [FilePath] -> FilePath -> IO (Maybe FilePath)
lookupCurryFile paths fn = lookupFile paths exts fn
where
exts | null fnExt = sourceExts
| otherwise = [fnExt]
fnExt = takeExtension fn
lookupCurryModule :: [FilePath]
-> [FilePath]
-> ModuleIdent
-> IO (Maybe FilePath)
lookupCurryModule paths libPaths m =
lookupFile (paths ++ libPaths) moduleExts (moduleNameToFile m)
lookupCurryInterface :: [FilePath]
-> ModuleIdent
-> IO (Maybe FilePath)
lookupCurryInterface paths m = lookupFile paths [icurryExt] (moduleNameToFile m)
lookupFile :: [FilePath]
-> [String]
-> FilePath
-> IO (Maybe FilePath)
lookupFile paths exts file = lookup' files
where
files = [ normalise (p </> f) | p <- paths, f <- baseNames ]
baseNames = map (replaceExtension file) exts
lookup' [] = return Nothing
lookup' (f : fs) = do
exists <- doesFileExist f
if exists then return (Just f) else lookup' fs
writeModule :: FilePath
-> String
-> IO ()
writeModule fn contents = do
createDirectoryIfMissing True $ takeDirectory fn
tryWriteFile fn contents
readModule :: FilePath -> IO (Maybe String)
readModule = tryOnExistingFile readFileUTF8
where
readFileUTF8 :: FilePath -> IO String
readFileUTF8 fn = do
hdl <- openFile fn ReadMode
hSetEncoding hdl utf8
hGetContents hdl
#if MIN_VERSION_directory(1,2,0)
getModuleModTime :: FilePath -> IO (Maybe UTCTime)
#else
getModuleModTime :: FilePath -> IO (Maybe ClockTime)
#endif
getModuleModTime = tryOnExistingFile getModificationTime
addVersion :: String -> String -> String
addVersion v content = "{- " ++ v ++ " -}\n" ++ content
checkVersion :: String -> String -> Either String String
checkVersion expected src = case lines src of
[] -> Left "empty file"
(l:ls) -> case getVersion l of
Just v | v == expected -> Right (unlines ls)
| otherwise -> Left $ "Expected version `" ++ expected
++ "', but found version `" ++ v ++ "'"
_ -> Left $ "No version found"
where
getVersion s | "{- " `isPrefixOf` s && " -}" `isSuffixOf` s
= Just (reverse $ drop 3 $ reverse $ drop 3 s)
| otherwise
= Nothing
tryOnExistingFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)
tryOnExistingFile action fn = C.handle ignoreIOException $ do
exists <- doesFileExist fn
if exists then Just `liftM` action fn
else return Nothing
ignoreIOException :: C.IOException -> IO (Maybe a)
ignoreIOException _ = return Nothing
tryWriteFile :: FilePath
-> String
-> IO ()
tryWriteFile fn contents = do
exists <- doesFileExist fn
if exists then C.handle issueWarning (writeFileUTF8 fn contents)
else writeFileUTF8 fn contents
where
issueWarning :: C.IOException -> IO ()
issueWarning _ = do
putStrLn $ "*** Warning: cannot update file `" ++ fn ++ "' (update ignored)"
return ()
writeFileUTF8 :: FilePath -> String -> IO ()
writeFileUTF8 fn' str =
withFile fn' WriteMode (\hdl -> hSetEncoding hdl utf8 >> hPutStr hdl str)