@@ -6,11 +6,14 @@ module Hledger.Flow.Reports
6
6
7
7
import Turtle hiding (stdout , stderr , proc )
8
8
import Prelude hiding (FilePath , putStrLn , writeFile )
9
- import qualified Data.Text as T
10
- import qualified Hledger.Flow.Types as FlowTypes
11
9
import Hledger.Flow.Report.Types
12
10
import Hledger.Flow.Common
13
11
import Control.Concurrent.STM
12
+ import Data.Either
13
+
14
+ import qualified Data.Text as T
15
+ import qualified Hledger.Flow.Types as FlowTypes
16
+ import qualified Data.List as List
14
17
15
18
generateReports :: ReportOptions -> IO ()
16
19
generateReports opts = sh (
@@ -19,50 +22,72 @@ generateReports opts = sh (
19
22
logHandle <- fork $ consoleChannelLoop ch
20
23
liftIO $ if (showOptions opts) then channelOutLn ch (repr opts) else return ()
21
24
(reports, diff) <- time $ liftIO $ generateReports' opts ch
22
- liftIO $ channelOutLn ch $ format (" Generated " % d% " reports in " % s) (length reports) $ repr diff
25
+ let failedAttempts = lefts reports
26
+ let failedText = if List. null failedAttempts then " " else format (" (and attempted to write " % d% " more) " ) $ length failedAttempts
27
+ liftIO $ channelOutLn ch $ format (" Generated " % d% " reports " % s% " in " % s) (length (rights reports)) failedText $ repr diff
23
28
liftIO $ terminateChannelLoop ch
24
29
wait logHandle
25
30
)
26
31
27
- generateReports' :: ReportOptions -> TChan FlowTypes. LogMessage -> IO [FilePath ]
32
+ generateReports' :: ReportOptions -> TChan FlowTypes. LogMessage -> IO [Either FilePath FilePath ]
28
33
generateReports' opts ch = do
29
- channelOutLn ch " Report generation has not been fully implemented yet. Keep an eye out for report pull requests: https://github.com/apauley/hledger-flow/pulls"
30
- ownerReports opts ch " everyone"
34
+ let wipMsg = " Report generation is still a work-in-progress - please let me know how this can be more useful.\n\n "
35
+ <> " Keep an eye out for report-related pull requests and issues, and feel free to submit some of your own:\n "
36
+ <> " https://github.com/apauley/hledger-flow/pulls\n "
37
+ <> " https://github.com/apauley/hledger-flow/issues\n "
38
+ channelOutLn ch wipMsg
39
+ owners <- single $ shellToList $ listOwners opts
40
+ let baseJournal = journalFile opts []
41
+ let baseReportDir = outputDir opts []
42
+ years <- includeYears ch baseJournal
43
+ let reportParams = [(baseJournal, baseReportDir)] ++ map (ownerParams opts) owners
44
+ let actions = List. concat $ fmap (generateReports'' opts ch years) reportParams
45
+ if (sequential opts) then sequence actions else single $ shellToList $ parallel actions
31
46
32
- ownerReports :: ReportOptions -> TChan FlowTypes. LogMessage -> Text -> IO [FilePath ]
33
- ownerReports opts ch owner = do
34
- let journal = (baseDir opts) </> " all-years" <.> " journal"
35
- let reportsDir = (baseDir opts) </> " reports" </> fromText owner
36
- let actions = map (\ r -> r opts ch journal reportsDir) [accountList, incomeStatement]
37
- results <- if (sequential opts) then sequence actions else single $ shellToList $ parallel actions
38
- return $ map fst results
47
+ generateReports'' :: ReportOptions -> TChan FlowTypes. LogMessage -> [Integer ] -> (FilePath , FilePath ) -> [IO (Either FilePath FilePath )]
48
+ generateReports'' opts ch years (journal, reportsDir) = do
49
+ y <- years
50
+ let actions = map (\ r -> r opts ch journal reportsDir y) [accountList, incomeStatement]
51
+ map (fmap fst ) actions
39
52
40
- incomeStatement :: ReportOptions -> TChan FlowTypes. LogMessage -> FilePath -> FilePath -> IO (FilePath , FlowTypes. FullTimedOutput )
41
- incomeStatement opts ch journal reportsDir = do
42
- mktree reportsDir
43
- let outputFile = reportsDir </> " income-expenses" <.> " txt"
53
+ incomeStatement :: ReportOptions -> TChan FlowTypes. LogMessage -> FilePath -> FilePath -> Integer -> IO (Either FilePath FilePath , FlowTypes. FullTimedOutput )
54
+ incomeStatement opts ch journal reportsDir year = do
44
55
let sharedOptions = [" --depth" , " 2" , " --pretty-tables" , " not:equity" ]
45
- let reportArgs = [" incomestatement" ] ++ sharedOptions ++ [ " --average " , " --yearly " ]
46
- generateReport' opts ch journal outputFile reportArgs
56
+ let reportArgs = [" incomestatement" ] ++ sharedOptions
57
+ generateReport opts ch journal reportsDir year ( " income-expenses " <.> " txt " ) reportArgs
47
58
48
- accountList :: ReportOptions -> TChan FlowTypes. LogMessage -> FilePath -> FilePath -> IO (FilePath , FlowTypes. FullTimedOutput )
49
- accountList opts ch journal reportsDir = do
50
- let outputFile = reportsDir </> " accounts" <.> " txt"
59
+ accountList :: ReportOptions -> TChan FlowTypes. LogMessage -> FilePath -> FilePath -> Integer -> IO (Either FilePath FilePath , FlowTypes. FullTimedOutput )
60
+ accountList opts ch journal reportsDir year = do
51
61
let reportArgs = [" accounts" ]
52
- generateReport' opts ch journal outputFile reportArgs
62
+ generateReport opts ch journal reportsDir year ( " accounts " <.> " txt " ) reportArgs
53
63
54
- generateReport' :: ReportOptions -> TChan FlowTypes. LogMessage -> FilePath -> FilePath -> [Text ] -> IO (FilePath , FlowTypes. FullTimedOutput )
55
- generateReport' opts ch journal outputFile args = do
56
- let reportsDir = directory outputFile
64
+ generateReport :: ReportOptions -> TChan FlowTypes. LogMessage -> FilePath -> FilePath -> Integer -> FilePath -> [Text ] -> IO (Either FilePath FilePath , FlowTypes. FullTimedOutput )
65
+ generateReport opts ch journal baseOutDir year fileName args = do
66
+ let reportsDir = baseOutDir </> intPath year
57
67
mktree reportsDir
68
+ let outputFile = reportsDir </> fileName
58
69
let relativeJournal = relativeToBase opts journal
59
- let reportArgs = [" --file" , format fp journal] ++ args
60
- let reportDisplayArgs = [" --file" , format fp relativeJournal] ++ args
70
+ let reportArgs = [" --file" , format fp journal, " --period " , repr year ] ++ args
71
+ let reportDisplayArgs = [" --file" , format fp relativeJournal, " --period " , repr year ] ++ args
61
72
let hledger = format fp $ FlowTypes. hlPath . hledgerInfo $ opts :: Text
62
73
let cmdLabel = format (" hledger " % s) $ showCmdArgs reportDisplayArgs
63
74
result@ ((exitCode, stdOut, _), _) <- timeAndExitOnErr opts ch cmdLabel dummyLogger channelErr procStrictWithErr (hledger, reportArgs, empty)
64
- if not (T. null stdOut) then do
65
- writeTextFile outputFile (cmdLabel <> " \n\n " <> stdOut)
66
- channelOutLn ch $ format (" Wrote " % fp) $ relativeToBase opts outputFile
67
- else channelErrLn ch $ format (" No report output for '" % s% " ' " % s) cmdLabel (repr exitCode)
68
- return (outputFile, result)
75
+ if not (T. null stdOut)
76
+ then
77
+ do
78
+ writeTextFile outputFile (cmdLabel <> " \n\n " <> stdOut)
79
+ channelOutLn ch $ format (" Wrote " % fp) $ relativeToBase opts outputFile
80
+ return (Right outputFile, result)
81
+ else
82
+ do
83
+ channelErrLn ch $ format (" No report output for '" % s% " ' " % s) cmdLabel (repr exitCode)
84
+ return (Left outputFile, result)
85
+
86
+ journalFile :: ReportOptions -> [FilePath ] -> FilePath
87
+ journalFile opts dirs = (foldl (</>) (baseDir opts) dirs) </> " all-years" <.> " journal"
88
+
89
+ outputDir :: ReportOptions -> [FilePath ] -> FilePath
90
+ outputDir opts dirs = foldl (</>) (baseDir opts) (" reports" : dirs)
91
+
92
+ ownerParams :: ReportOptions -> FilePath -> (FilePath , FilePath )
93
+ ownerParams opts owner = (journalFile opts [" import" , owner], outputDir opts [owner])
0 commit comments