Remove race conditions checking file existence before reading

This commit is contained in:
Joshua Clayton 2016-07-02 07:46:01 -04:00
parent d9efa11777
commit 752a3b23b9
No known key found for this signature in database
GPG Key ID: 5B6558F77E9A8118
2 changed files with 12 additions and 11 deletions

View File

@ -5,11 +5,13 @@ module Unused.Cache
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Reader import Control.Monad.Trans.Reader
import System.Directory
import Data.Csv (FromRecord, ToRecord, HasHeader(..), encode, decode) import Data.Csv (FromRecord, ToRecord, HasHeader(..), encode, decode)
import Data.Vector (toList) import Data.Vector (toList)
import System.Directory (createDirectoryIfMissing)
import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Lazy as BS
import qualified Data.ByteString.Lazy.Char8 as C
import Unused.Cache.DirectoryFingerprint import Unused.Cache.DirectoryFingerprint
import Unused.Util (safeReadFile)
newtype CacheFileName = CacheFileName String newtype CacheFileName = CacheFileName String
type Cache = ReaderT CacheFileName IO type Cache = ReaderT CacheFileName IO
@ -31,11 +33,11 @@ writeCache contents = do
readCache :: FromRecord a => Cache (Maybe [a]) readCache :: FromRecord a => Cache (Maybe [a])
readCache = do readCache = do
(CacheFileName fileName) <- ask (CacheFileName fileName) <- ask
exists <- liftIO $ doesFileExist fileName
if exists either
then fmap processCsv (decode NoHeader <$> liftIO (BS.readFile fileName)) (const Nothing)
else return Nothing (processCsv . decode NoHeader . C.pack)
<$> (liftIO $ safeReadFile fileName)
where where
processCsv = either (const Nothing) (Just . toList) processCsv = either (const Nothing) (Just . toList)

View File

@ -4,12 +4,11 @@ module Unused.ResultsClassifier.Config
) where ) where
import qualified Data.Yaml as Y import qualified Data.Yaml as Y
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Char8 as C
import qualified Data.Either as E import qualified Data.Either as E
import qualified Data.Bifunctor as B import qualified Data.Bifunctor as B
import System.FilePath ((</>)) import System.FilePath ((</>))
import System.Directory (getHomeDirectory, doesFileExist) import System.Directory (getHomeDirectory)
import Paths_unused (getDataFileName) import Paths_unused (getDataFileName)
import Unused.ResultsClassifier.Types (LanguageConfiguration, ParseConfigError(..)) import Unused.ResultsClassifier.Types (LanguageConfiguration, ParseConfigError(..))
import Unused.Util (safeReadFile) import Unused.Util (safeReadFile)
@ -17,11 +16,11 @@ import Unused.Util (safeReadFile)
loadConfig :: IO (Either String [LanguageConfiguration]) loadConfig :: IO (Either String [LanguageConfiguration])
loadConfig = do loadConfig = do
configFileName <- getDataFileName ("data" </> "config.yml") configFileName <- getDataFileName ("data" </> "config.yml")
exists <- doesFileExist configFileName
if exists either
then Y.decodeEither <$> BS.readFile configFileName (const $ Left "default config not found")
else return $ Left "default config not found" (Y.decodeEither . C.pack)
<$> safeReadFile configFileName
loadAllConfigurations :: IO (Either [ParseConfigError] [LanguageConfiguration]) loadAllConfigurations :: IO (Either [ParseConfigError] [LanguageConfiguration])
loadAllConfigurations = do loadAllConfigurations = do