{-|
Utilities for doing I/O with ledger files.
-}moduleLedger.IOwhereimportControl.Monad.ErrorimportData.Time.ClockimportData.Time.LocalTime(LocalTime)importLedger.Ledger(cacheLedger)importLedger.Parse(parseLedger)importLedger.RawLedger(canonicaliseAmounts,filterRawLedger)importLedger.Types(DateSpan(..),RawLedger,Ledger(..))importLedger.Utils(getCurrentLocalTime)importSystem.Directory(getHomeDirectory)importSystem.Environment(getEnv)importSystem.IOimportText.ParserCombinators.ParsecimportqualifiedData.MapasMap(lookup)ledgerdefaultpath="~/.ledger"timelogdefaultpath="~/.timelog"ledgerenvvar="LEDGER"timelogenvvar="TIMELOG"-- | A tuple of arguments specifying how to filter a raw ledger file:-- -- - only include transactions in this date span-- -- - only include if cleared\/uncleared\/don't care-- -- - only include if real\/don't care-- -- - convert all amounts to cost basis-- -- - only include if matching these account patterns-- -- - only include if matching these description patternstypeIOArgs=(DateSpan,MaybeBool,Bool,Bool,[String],[String])noioargs=(DateSpanNothingNothing,Nothing,False,False,[],[])-- | Get the user's default ledger file path.myLedgerPath::IOStringmyLedgerPath=getEnvledgerenvvar`catch`\_->returnledgerdefaultpath-- | Get the user's default timelog file path.myTimelogPath::IOStringmyTimelogPath=getEnvtimelogenvvar`catch`\_->returntimelogdefaultpath-- | Read the user's default ledger file, or give an error.myLedger::IOLedgermyLedger=myLedgerPath>>=readLedger-- | Read the user's default timelog file, or give an error.myTimelog::IOLedgermyTimelog=myTimelogPath>>=readLedger-- | Read a ledger from this file, with no filtering, or give an error.readLedger::FilePath->IOLedgerreadLedgerf=tildeExpandf>>=readLedgerWithIOArgsnoioargs-- | Read a ledger from this file, filtering according to the io args,-- | or give an error.readLedgerWithIOArgs::IOArgs->FilePath->IOLedgerreadLedgerWithIOArgsioargsf=dot<-getCurrentLocalTimes<-readFilefrl<-rawLedgerFromStringsreturn$filterAndCacheLedgerioargssrl-- | Read a RawLedger from the given string, using the current time as-- reference time, or give a parse error.rawLedgerFromString::String->IORawLedgerrawLedgerFromStrings=dot<-getCurrentLocalTimeliftM(eithererrorid)$runErrorT$parseLedgert"(string)"s-- | Convert a RawLedger to a canonicalised, cached and filtered Ledger.filterAndCacheLedger::IOArgs->String->RawLedger->LedgerfilterAndCacheLedger(span,cleared,real,costbasis,apats,dpats)rawtextrl=(cacheLedgerapats$filterRawLedgerspandpatsclearedreal$canonicaliseAmountscostbasisrl){rawledgertext=rawtext}-- | Expand ~ in a file path (does not handle ~name).tildeExpand::FilePath->IOFilePathtildeExpand('~':[])=getHomeDirectorytildeExpand('~':'/':xs)=getHomeDirectory>>=return.(++('/':xs))--handle ~name, requires -fvia-C or ghc 6.8:--import System.Posix.User-- tildeExpand ('~':xs) = do let (user, path) = span (/= '/') xs-- pw <- getUserEntryForName user-- return (homeDirectory pw ++ path)tildeExpandxs=returnxs