2010-02-13 23:00:34 +03:00
|
|
|
{-# LANGUAGE CPP #-}
|
2010-05-30 23:11:58 +04:00
|
|
|
{-|
|
|
|
|
|
|
|
|
Read hledger data from various data formats, and related utilities.
|
|
|
|
|
2009-04-04 12:50:36 +04:00
|
|
|
-}
|
|
|
|
|
2010-05-30 23:11:58 +04:00
|
|
|
module Hledger.Read (
|
|
|
|
tests_Hledger_Read,
|
|
|
|
myLedgerPath,
|
|
|
|
myTimelogPath,
|
|
|
|
myJournal,
|
|
|
|
myTimelog,
|
2010-05-31 05:15:18 +04:00
|
|
|
readJournalFile,
|
|
|
|
readJournal,
|
2010-05-30 23:11:58 +04:00
|
|
|
)
|
2009-04-04 12:50:36 +04:00
|
|
|
where
|
2010-05-30 23:11:58 +04:00
|
|
|
import Hledger.Data.Types (Journal(..))
|
|
|
|
import Hledger.Data.Utils
|
|
|
|
import Hledger.Read.Common
|
2010-05-31 05:15:18 +04:00
|
|
|
import qualified Hledger.Read.Journal (parseJournal,ledgerFile,tests_Journal)
|
|
|
|
import qualified Hledger.Read.Timelog (parseJournal,tests_Timelog)
|
2010-05-30 23:11:58 +04:00
|
|
|
|
2009-04-04 12:50:36 +04:00
|
|
|
import Control.Monad.Error
|
2010-05-31 05:15:18 +04:00
|
|
|
import Data.Either (partitionEithers)
|
2009-04-04 12:50:36 +04:00
|
|
|
import System.Directory (getHomeDirectory)
|
|
|
|
import System.Environment (getEnv)
|
2010-05-30 23:11:58 +04:00
|
|
|
import System.FilePath ((</>))
|
|
|
|
import System.Exit
|
|
|
|
import System.IO (stderr)
|
2010-02-13 23:00:34 +03:00
|
|
|
#if __GLASGOW_HASKELL__ <= 610
|
2010-05-31 05:15:18 +04:00
|
|
|
import Prelude hiding (readFile, putStr, putStrLn, print, getContents)
|
|
|
|
import System.IO.UTF8
|
2010-05-30 23:11:58 +04:00
|
|
|
#else
|
|
|
|
import System.IO (hPutStrLn)
|
2010-02-13 23:00:34 +03:00
|
|
|
#endif
|
2009-04-04 12:50:36 +04:00
|
|
|
|
|
|
|
|
2010-05-31 05:15:18 +04:00
|
|
|
formats = [
|
|
|
|
"journal"
|
|
|
|
,"timelog"
|
|
|
|
-- ,"csv"
|
|
|
|
]
|
|
|
|
|
|
|
|
unknownformatmsg fp = printf "could not recognise %sdata in %s" (fmt formats) fp
|
|
|
|
where fmt [] = ""
|
|
|
|
fmt [f] = f ++ " "
|
|
|
|
fmt fs = intercalate ", " (init fs) ++ " or " ++ last fs ++ " "
|
|
|
|
|
|
|
|
parsers = [Hledger.Read.Journal.parseJournal
|
|
|
|
,Hledger.Read.Timelog.parseJournal
|
|
|
|
]
|
|
|
|
|
2009-06-05 09:03:10 +04:00
|
|
|
ledgerenvvar = "LEDGER"
|
|
|
|
timelogenvvar = "TIMELOG"
|
|
|
|
ledgerdefaultfilename = ".ledger"
|
|
|
|
timelogdefaultfilename = ".timelog"
|
2009-04-04 12:50:36 +04:00
|
|
|
|
|
|
|
-- | Get the user's default ledger file path.
|
|
|
|
myLedgerPath :: IO String
|
|
|
|
myLedgerPath =
|
2009-06-05 09:03:10 +04:00
|
|
|
getEnv ledgerenvvar `catch`
|
|
|
|
(\_ -> do
|
2009-11-19 04:48:37 +03:00
|
|
|
home <- getHomeDirectory `catch` (\_ -> return "")
|
2009-06-05 09:03:10 +04:00
|
|
|
return $ home </> ledgerdefaultfilename)
|
2009-04-04 12:50:36 +04:00
|
|
|
|
|
|
|
-- | Get the user's default timelog file path.
|
|
|
|
myTimelogPath :: IO String
|
|
|
|
myTimelogPath =
|
2009-06-05 09:03:10 +04:00
|
|
|
getEnv timelogenvvar `catch`
|
|
|
|
(\_ -> do
|
|
|
|
home <- getHomeDirectory
|
|
|
|
return $ home </> timelogdefaultfilename)
|
2009-04-04 12:50:36 +04:00
|
|
|
|
2010-05-23 21:41:25 +04:00
|
|
|
-- | Read the user's default journal file, or give an error.
|
|
|
|
myJournal :: IO Journal
|
2010-05-30 23:11:58 +04:00
|
|
|
myJournal = myLedgerPath >>= readJournalFile
|
2009-04-04 12:50:36 +04:00
|
|
|
|
|
|
|
-- | Read the user's default timelog file, or give an error.
|
2010-05-23 21:41:25 +04:00
|
|
|
myTimelog :: IO Journal
|
2010-05-30 23:11:58 +04:00
|
|
|
myTimelog = myTimelogPath >>= readJournalFile
|
2009-04-04 12:50:36 +04:00
|
|
|
|
2010-05-31 05:15:18 +04:00
|
|
|
-- | Read a journal from this file, trying all known data formats,
|
|
|
|
-- or give an error.
|
2010-05-30 23:11:58 +04:00
|
|
|
readJournalFile :: FilePath -> IO Journal
|
2010-05-31 05:15:18 +04:00
|
|
|
readJournalFile "-" = getContents >>= journalFromPathAndString "(stdin)"
|
|
|
|
readJournalFile f = readFile f >>= journalFromPathAndString f
|
2009-04-04 12:50:36 +04:00
|
|
|
|
2010-05-31 05:15:18 +04:00
|
|
|
-- | Read a Journal from this string, trying all known data formats, or
|
|
|
|
-- give an error.
|
2010-05-30 23:11:58 +04:00
|
|
|
readJournal :: String -> IO Journal
|
2010-05-31 05:15:18 +04:00
|
|
|
readJournal = journalFromPathAndString "(string)"
|
|
|
|
|
|
|
|
-- | Read a Journal from this string, trying each known data format in
|
|
|
|
-- turn, or give an error. The file path is also required.
|
|
|
|
journalFromPathAndString :: FilePath -> String -> IO Journal
|
|
|
|
journalFromPathAndString f s = do
|
|
|
|
(errors, journals) <- partitionEithers `fmap` mapM try parsers
|
|
|
|
case journals of j:_ -> return j
|
|
|
|
_ -> hPutStrLn stderr (errmsg errors) >> exitWith (ExitFailure 1)
|
|
|
|
where
|
|
|
|
try p = (runErrorT . p f) s
|
|
|
|
errmsg [] = unknownformatmsg f
|
|
|
|
errmsg (e:_) = unlines [unknownformatmsg f, e]
|
2009-04-04 12:50:36 +04:00
|
|
|
|
2010-05-30 23:11:58 +04:00
|
|
|
tests_Hledger_Read = TestList
|
|
|
|
[
|
|
|
|
|
|
|
|
"ledgerFile" ~: do
|
|
|
|
assertBool "ledgerFile should parse an empty file" (isRight $ parseWithCtx emptyCtx Hledger.Read.Journal.ledgerFile "")
|
|
|
|
r <- readJournal "" -- don't know how to get it from ledgerFile
|
|
|
|
assertBool "ledgerFile parsing an empty file should give an empty ledger" $ null $ jtxns r
|
|
|
|
|
|
|
|
,Hledger.Read.Journal.tests_Journal
|
|
|
|
,Hledger.Read.Timelog.tests_Timelog
|
|
|
|
]
|