More safely handle reading files

This replaces readIfFileExists, which has a race-condition and may raise
an exception, with safeReadFile, which safely reads a file and includes
the IOException if something goes wrong.
This commit is contained in:
Joshua Clayton 2016-07-02 07:08:09 -04:00
parent e1d6143161
commit d9efa11777
No known key found for this signature in database
GPG Key ID: 5B6558F77E9A8118
3 changed files with 10 additions and 15 deletions

View File

@ -10,7 +10,7 @@ import qualified System.Directory as D
import qualified Data.Char as C import qualified Data.Char as C
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Unused.Cache.FindArgsFromIgnoredPaths import Unused.Cache.FindArgsFromIgnoredPaths
import Unused.Util (safeHead, readIfFileExists) import Unused.Util (safeHead, safeReadFile)
type MD5Config = ReaderT String IO type MD5Config = ReaderT String IO
@ -43,7 +43,7 @@ md5Result r = do
liftIO $ readProcess md5exec [] r liftIO $ readProcess md5exec [] r
ignoredPaths :: IO [String] ignoredPaths :: IO [String]
ignoredPaths = fromMaybe [] <$> (fmap lines <$> readIfFileExists ".gitignore") ignoredPaths = either (const []) id <$> (fmap lines <$> safeReadFile ".gitignore")
md5Executable :: IO (Maybe String) md5Executable :: IO (Maybe String)
md5Executable = md5Executable =

View File

@ -12,7 +12,7 @@ import System.FilePath ((</>))
import System.Directory (getHomeDirectory, doesFileExist) import System.Directory (getHomeDirectory, doesFileExist)
import Paths_unused (getDataFileName) import Paths_unused (getDataFileName)
import Unused.ResultsClassifier.Types (LanguageConfiguration, ParseConfigError(..)) import Unused.ResultsClassifier.Types (LanguageConfiguration, ParseConfigError(..))
import Unused.Util (readIfFileExists) import Unused.Util (safeReadFile)
loadConfig :: IO (Either String [LanguageConfiguration]) loadConfig :: IO (Either String [LanguageConfiguration])
loadConfig = do loadConfig = do
@ -39,10 +39,10 @@ loadAllConfigurations = do
loadConfigFromFile :: String -> IO (Either ParseConfigError [LanguageConfiguration]) loadConfigFromFile :: String -> IO (Either ParseConfigError [LanguageConfiguration])
loadConfigFromFile path = do loadConfigFromFile path = do
file <- fmap C.pack <$> readIfFileExists path file <- fmap C.pack <$> safeReadFile path
return $ case file of return $ case file of
Nothing -> Right [] Left _ -> Right []
Just body -> addSourceToLeft path $ Y.decodeEither body Right body -> addSourceToLeft path $ Y.decodeEither body
addSourceToLeft :: String -> Either String c -> Either ParseConfigError c addSourceToLeft :: String -> Either String c -> Either ParseConfigError c
addSourceToLeft source = B.first (ParseConfigError source) addSourceToLeft source = B.first (ParseConfigError source)

View File

@ -2,11 +2,11 @@ module Unused.Util
( groupBy ( groupBy
, stringToInt , stringToInt
, safeHead , safeHead
, readIfFileExists , safeReadFile
) where ) where
import System.Directory (doesFileExist)
import Control.Arrow ((&&&)) import Control.Arrow ((&&&))
import qualified Control.Exception as E
import qualified Data.List as L import qualified Data.List as L
import Data.Function import Data.Function
import Data.Char (digitToInt, isDigit) import Data.Char (digitToInt, isDigit)
@ -27,10 +27,5 @@ stringToInt xs
where where
loop = foldl (\acc x -> acc * 10 + digitToInt x) loop = foldl (\acc x -> acc * 10 + digitToInt x)
readIfFileExists :: String -> IO (Maybe String) safeReadFile :: FilePath -> IO (Either E.IOException String)
readIfFileExists path = do safeReadFile = E.try . readFile
exists <- doesFileExist path
if exists
then Just <$> readFile path
else return Nothing