try only as many data readers as needed for a successful read
This commit is contained in:
parent
6eb7ad28e1
commit
fdb3677129
@ -23,10 +23,8 @@ module Hledger.Read (
|
||||
)
|
||||
where
|
||||
import Control.Monad.Error
|
||||
import Data.Either (partitionEithers)
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import Safe (headDef)
|
||||
import System.Directory (doesFileExist, getHomeDirectory)
|
||||
import System.Environment (getEnv)
|
||||
import System.Exit (exitFailure)
|
||||
@ -60,7 +58,7 @@ readers = [
|
||||
]
|
||||
|
||||
-- | All the data formats we can read.
|
||||
formats = map rFormat readers
|
||||
-- formats = map rFormat readers
|
||||
|
||||
-- | Get the default journal file path specified by the environment.
|
||||
-- Like ledger, we look first for the LEDGER_FILE environment
|
||||
@ -96,36 +94,47 @@ readerForFormat s | null rs = Nothing
|
||||
-- conversion rules may be provided for better conversion of that
|
||||
-- format, and/or a file path for better error messages.
|
||||
readJournal :: Maybe Format -> Maybe CsvReader.CsvRules -> Maybe FilePath -> String -> IO (Either String Journal)
|
||||
readJournal format rules path s = do
|
||||
readJournal format _ path s =
|
||||
let readerstotry = case format of Nothing -> readers
|
||||
Just f -> case readerForFormat f of Just r -> [r]
|
||||
Nothing -> []
|
||||
(errors, journals) <- partitionEithers `fmap` mapM (tryReader s path) readerstotry -- XXX lazify
|
||||
case journals of j:_ -> return $ Right j
|
||||
_ -> return $ Left $ bestErrorMsg errors s path
|
||||
where
|
||||
path' = fromMaybe "(string)" path
|
||||
tryReader :: String -> Maybe FilePath -> Reader -> IO (Either String Journal)
|
||||
tryReader s path r = do -- printf "trying to read %s format\n" (rFormat r)
|
||||
(runErrorT . (rParser r) path') s
|
||||
in firstSuccessOrBestError $ map tryReader readerstotry
|
||||
where
|
||||
path' = fromMaybe "(string)" path
|
||||
tryReader :: Reader -> IO (Either String Journal)
|
||||
tryReader r = do -- printf "trying %s reader\n" (rFormat r)
|
||||
(runErrorT . (rParser r) path') s
|
||||
|
||||
-- unknown format
|
||||
bestErrorMsg :: [String] -> String -> Maybe FilePath -> String
|
||||
bestErrorMsg [] _ path = printf "could not parse %sdata%s" fmts pathmsg
|
||||
where fmts = case formats of
|
||||
[] -> ""
|
||||
[f] -> f ++ " "
|
||||
fs -> intercalate ", " (init fs) ++ " or " ++ last fs ++ " "
|
||||
pathmsg = case path of
|
||||
Nothing -> ""
|
||||
Just p -> " in "++p
|
||||
-- one or more errors - report (the most appropriate ?) one
|
||||
bestErrorMsg es s path = printf "could not parse %s data%s\n%s" (rFormat r) pathmsg e
|
||||
where (r,e) = headDef (head readers, head es) $ filter detects $ zip readers es
|
||||
detects (r,_) = (rDetector r) path' s
|
||||
pathmsg = case path of
|
||||
Nothing -> ""
|
||||
Just p -> " in "++p
|
||||
-- if no reader succeeds, we return the error of the first;
|
||||
-- ideally it would be the error of the most likely intended
|
||||
-- reader, based on file suffix and/or data sniffing.
|
||||
firstSuccessOrBestError :: [IO (Either String Journal)] -> IO (Either String Journal)
|
||||
firstSuccessOrBestError [] = return $ Left "no readers found"
|
||||
firstSuccessOrBestError attempts = firstSuccessOrBestError' attempts
|
||||
where
|
||||
firstSuccessOrBestError' [] = head attempts
|
||||
firstSuccessOrBestError' (a:as) = do
|
||||
r <- a
|
||||
case r of Right j -> return $ Right j
|
||||
Left _ -> firstSuccessOrBestError' as
|
||||
|
||||
-- -- unknown format
|
||||
-- bestErrorMsg :: [String] -> String -> Maybe FilePath -> String
|
||||
-- bestErrorMsg [] _ path = printf "could not parse %sdata%s" fmts pathmsg
|
||||
-- where fmts = case formats of
|
||||
-- [] -> ""
|
||||
-- [f] -> f ++ " "
|
||||
-- fs -> intercalate ", " (init fs) ++ " or " ++ last fs ++ " "
|
||||
-- pathmsg = case path of
|
||||
-- Nothing -> ""
|
||||
-- Just p -> " in "++p
|
||||
-- -- one or more errors - report (the most appropriate ?) one
|
||||
-- bestErrorMsg es s path = printf "could not parse %s data%s\n%s" (rFormat r) pathmsg e
|
||||
-- where (r,e) = headDef (head readers, head es) $ filter detects $ zip readers es
|
||||
-- detects (r,_) = (rDetector r) path' s
|
||||
-- pathmsg = case path of
|
||||
-- Nothing -> ""
|
||||
-- Just p -> " in "++p
|
||||
|
||||
-- | Read a Journal from this file (or stdin if the filename is -) or
|
||||
-- give an error message, using the specified data format or trying
|
||||
|
||||
Loading…
Reference in New Issue
Block a user