module ToolShed.System.File(
SearchPath,
LocatedData,
locate,
getFile,
fromFile,
getFilePath,
getData
) where
import qualified Control.Exception
import qualified Control.Monad
import qualified Data.List
import qualified System.Directory
import qualified System.FilePath
import System.FilePath((</>))
import qualified System.IO.Error
type SearchPath = [System.FilePath.FilePath]
locate :: System.FilePath.FilePath -> SearchPath -> IO [System.FilePath.FilePath]
locate fileName searchPath
| System.FilePath.isRelative fileName' = Control.Monad.filterM System.Directory.doesFileExist . filter System.FilePath.isValid . Data.List.nubBy System.FilePath.equalFilePath $ map (System.FilePath.normalise . (</> fileName')) searchPath
| not $ System.FilePath.isValid fileName' = Control.Exception.throwIO . System.IO.Error.userError $ "Invalid filename; " ++ fileName'
| otherwise = do
fileExists <- System.Directory.doesFileExist fileName'
if not fileExists
then Control.Exception.throwIO . System.IO.Error.mkIOError System.IO.Error.doesNotExistErrorType "No such file" Nothing $ Just fileName'
else return [fileName']
where
fileName' = System.FilePath.normalise fileName
type LocatedData a = (System.FilePath.FilePath, a)
getFilePath :: LocatedData a -> System.FilePath.FilePath
getFilePath = fst
getData :: LocatedData a -> a
getData = snd
getFile :: System.FilePath.FilePath -> SearchPath -> IO (LocatedData String)
getFile fileName directories = do
filePaths <- locate fileName directories
if null filePaths
then Control.Exception.throwIO . System.IO.Error.mkIOError System.IO.Error.doesNotExistErrorType ("Can't find in " ++ show directories) Nothing $ Just fileName
else let
filePath = head filePaths
in (,) filePath `fmap` readFile filePath
fromFile :: Read a => System.FilePath.FilePath -> SearchPath -> IO (LocatedData a)
fromFile fileName directories = do
(filePath, fileContents) <- getFile fileName directories
case reads fileContents of
[(x, _)] -> return (filePath, x)
_ -> error . showString "ToolShed.System.File.fromFile:\tfailed to parse file=" $ shows filePath "."