lib: refactor low-level text file reading

This commit is contained in:
Simon Michael 2018-01-04 16:17:25 -08:00
parent 631f0fc1e2
commit 81e964502b
5 changed files with 23 additions and 30 deletions

View File

@ -156,7 +156,7 @@ readJournalFile mformat mrulesfile assrt prefixedfile = do
(mprefixformat, f) = splitReaderPrefix prefixedfile (mprefixformat, f) = splitReaderPrefix prefixedfile
mfmt = mformat <|> mprefixformat mfmt = mformat <|> mprefixformat
requireJournalFileExists f requireJournalFileExists f
readFileOrStdinAnyLineEnding f >>= readJournal mfmt mrulesfile assrt (Just f) readFileOrStdinPortably f >>= readJournal mfmt mrulesfile assrt (Just f)
-- | If a filepath is prefixed by one of the reader names and a colon, -- | If a filepath is prefixed by one of the reader names and a colon,
-- split that off. Eg "csv:-" -> (Just "csv", "-"). -- split that off. Eg "csv:-" -> (Just "csv", "-").
@ -276,7 +276,7 @@ readJournalFileWithOpts iopts prefixedfile = do
(mfmt, f) = splitReaderPrefix prefixedfile (mfmt, f) = splitReaderPrefix prefixedfile
iopts' = iopts{mformat_=firstJust [mfmt, mformat_ iopts]} iopts' = iopts{mformat_=firstJust [mfmt, mformat_ iopts]}
requireJournalFileExists f requireJournalFileExists f
t <- readFileOrStdinAnyLineEnding f t <- readFileOrStdinPortably f
ej <- readJournalWithOpts iopts' (Just f) t ej <- readJournalWithOpts iopts' (Just f) t
case ej of case ej of
Left e -> return $ Left e Left e -> return $ Left e
@ -324,7 +324,7 @@ latestDatesFileFor f = dir </> ".latest" <.> fname
(dir, fname) = splitFileName f (dir, fname) = splitFileName f
readFileStrictly :: FilePath -> IO Text readFileStrictly :: FilePath -> IO Text
readFileStrictly f = readFile' f >>= \t -> C.evaluate (T.length t) >> return t readFileStrictly f = readFilePortably f >>= \t -> C.evaluate (T.length t) >> return t
-- | Given zero or more latest dates (all the same, representing the -- | Given zero or more latest dates (all the same, representing the
-- latest previously seen transaction date, and how many transactions -- latest previously seen transaction date, and how many transactions

View File

@ -104,7 +104,7 @@ readJournalFromCsv mrulesfile csvfile csvdata =
if rulesfileexists if rulesfileexists
then do then do
dbg1IO "using conversion rules file" rulesfile dbg1IO "using conversion rules file" rulesfile
liftIO $ (readFile' rulesfile >>= expandIncludes (takeDirectory rulesfile)) liftIO $ (readFilePortably rulesfile >>= expandIncludes (takeDirectory rulesfile))
else return $ defaultRulesText rulesfile else return $ defaultRulesText rulesfile
rules <- liftIO (runExceptT $ parseAndValidateCsvRules rulesfile rulestext) >>= either throwerr return rules <- liftIO (runExceptT $ parseAndValidateCsvRules rulesfile rulestext) >>= either throwerr return
dbg2IO "rules" rules dbg2IO "rules" rules
@ -365,7 +365,7 @@ instance ShowErrorComponent String where
-- and runs some extra validation checks. -- and runs some extra validation checks.
parseRulesFile :: FilePath -> ExceptT String IO CsvRules parseRulesFile :: FilePath -> ExceptT String IO CsvRules
parseRulesFile f = parseRulesFile f =
liftIO (readFile' f >>= expandIncludes (takeDirectory f)) >>= parseAndValidateCsvRules f liftIO (readFilePortably f >>= expandIncludes (takeDirectory f)) >>= parseAndValidateCsvRules f
-- | Inline all files referenced by include directives in this hledger CSV rules text, recursively. -- | Inline all files referenced by include directives in this hledger CSV rules text, recursively.
-- Included file paths may be relative to the directory of the provided file path. -- Included file paths may be relative to the directory of the provided file path.

View File

@ -188,7 +188,7 @@ includedirectivep = do
liftIO $ runExceptT $ do liftIO $ runExceptT $ do
let curdir = takeDirectory (sourceName parentpos) let curdir = takeDirectory (sourceName parentpos)
filepath <- expandPath curdir filename `orRethrowIOError` (show parentpos ++ " locating " ++ filename) filepath <- expandPath curdir filename `orRethrowIOError` (show parentpos ++ " locating " ++ filename)
txt <- readFileAnyLineEnding filepath `orRethrowIOError` (show parentpos ++ " reading " ++ filepath) txt <- readFilePortably filepath `orRethrowIOError` (show parentpos ++ " reading " ++ filepath)
(ej1::Either (ParseError Char MPErr) ParsedJournal) <- (ej1::Either (ParseError Char MPErr) ParsedJournal) <-
runParserT runParserT
(evalStateT (evalStateT

View File

@ -150,30 +150,23 @@ firstJust ms = case dropWhile (==Nothing) ms of
[] -> Nothing [] -> Nothing
(md:_) -> md (md:_) -> md
-- | Read a file in universal newline mode, handling any of the usual line ending conventions. -- | Read text from a file, handling any of the usual line ending conventions.
readFile' :: FilePath -> IO Text readFilePortably :: FilePath -> IO Text
readFile' name = do readFilePortably f = openFile f ReadMode >>= readHandlePortably
h <- openFile name ReadMode
hSetNewlineMode h universalNewlineMode
T.hGetContents h
-- | Read a file in universal newline mode, handling any of the usual line ending conventions. -- | Read text from a file, or from standard input if the path is "-",
readFileAnyLineEnding :: FilePath -> IO Text -- handling any of the usual line ending conventions.
readFileAnyLineEnding path = do readFileOrStdinPortably :: String -> IO Text
h <- openFile path ReadMode readFileOrStdinPortably f = openFileOrStdin f ReadMode >>= readHandlePortably
hSetNewlineMode h universalNewlineMode
T.hGetContents h
-- | Read the given file, or standard input if the path is "-", using
-- universal newline mode.
readFileOrStdinAnyLineEnding :: String -> IO Text
readFileOrStdinAnyLineEnding f = do
h <- fileHandle f
hSetNewlineMode h universalNewlineMode
T.hGetContents h
where where
fileHandle "-" = return stdin openFileOrStdin :: String -> IOMode -> IO Handle
fileHandle f = openFile f ReadMode openFileOrStdin "-" _ = return stdin
openFileOrStdin f m = openFile f m
readHandlePortably :: Handle -> IO Text
readHandlePortably h = do
hSetNewlineMode h universalNewlineMode
T.hGetContents h
-- | Total version of maximum, for integral types, giving 0 for an empty list. -- | Total version of maximum, for integral types, giving 0 for an empty list.
maximum' :: Integral a => [a] -> a maximum' :: Integral a => [a] -> a

View File

@ -249,7 +249,7 @@ openBrowserOn u = trybrowsers browsers u
-- indicating whether we did anything. -- indicating whether we did anything.
writeFileWithBackupIfChanged :: FilePath -> T.Text -> IO Bool writeFileWithBackupIfChanged :: FilePath -> T.Text -> IO Bool
writeFileWithBackupIfChanged f t = do writeFileWithBackupIfChanged f t = do
s <- readFile' f s <- readFilePortably f
if t == s then return False if t == s then return False
else backUpFile f >> T.writeFile f t >> return True else backUpFile f >> T.writeFile f t >> return True
@ -259,7 +259,7 @@ writeFileWithBackup :: FilePath -> String -> IO ()
writeFileWithBackup f t = backUpFile f >> writeFile f t writeFileWithBackup f t = backUpFile f >> writeFile f t
readFileStrictly :: FilePath -> IO T.Text readFileStrictly :: FilePath -> IO T.Text
readFileStrictly f = readFile' f >>= \s -> C.evaluate (T.length s) >> return s readFileStrictly f = readFilePortably f >>= \s -> C.evaluate (T.length s) >> return s
-- | Back up this file with a (incrementing) numbered suffix, or give an error. -- | Back up this file with a (incrementing) numbered suffix, or give an error.
backUpFile :: FilePath -> IO () backUpFile :: FilePath -> IO ()