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