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