From bd77081fdfa37f3f88ad2bf8efc57f9517c3db0c Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 13:14:31 +0200 Subject: [PATCH 01/14] Write reports per owner --- src/Hledger/Flow/Common.hs | 3 +++ src/Hledger/Flow/Reports.hs | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Hledger/Flow/Common.hs b/src/Hledger/Flow/Common.hs index e3f34b5..5bbd4a2 100644 --- a/src/Hledger/Flow/Common.hs +++ b/src/Hledger/Flow/Common.hs @@ -446,3 +446,6 @@ extractImportDirs inputFile = do %"\n\nhledger-flow expects to find input files in this structure:\n"% "import/owner/bank/account/filestate/year/trxfile\n\n"% "Have a look at the documentation for a detailed explanation:\n"%s) inputFile (docURL "input-files") + +listOwners :: HasBaseDir o => o -> Shell FilePath +listOwners opts = fmap basename $ lsDirs $ (baseDir opts) "import" diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index 085e7c8..f7957a3 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -6,12 +6,14 @@ module Hledger.Flow.Reports import Turtle hiding (stdout, stderr, proc) import Prelude hiding (FilePath, putStrLn, writeFile) -import qualified Data.Text as T -import qualified Hledger.Flow.Types as FlowTypes import Hledger.Flow.Report.Types import Hledger.Flow.Common import Control.Concurrent.STM +import qualified Data.Text as T +import qualified Hledger.Flow.Types as FlowTypes +import qualified Data.List as List + generateReports :: ReportOptions -> IO () generateReports opts = sh ( do @@ -27,15 +29,16 @@ generateReports opts = sh ( generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [FilePath] generateReports' opts ch = do 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" - ownerReports opts ch "everyone" + owners <- single $ shellToList $ listOwners opts + let actions = List.concat $ fmap (\owner -> ownerReports opts ch owner) owners + if (sequential opts) then sequence actions else single $ shellToList $ parallel actions -ownerReports :: ReportOptions -> TChan FlowTypes.LogMessage -> Text -> IO [FilePath] +ownerReports :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> [IO FilePath] ownerReports opts ch owner = do - let journal = (baseDir opts) "all-years" <.> "journal" - let reportsDir = (baseDir opts) "reports" fromText owner + let journal = (baseDir opts) "import" owner "all-years" <.> "journal" + let reportsDir = (baseDir opts) "reports" owner let actions = map (\r -> r opts ch journal reportsDir) [accountList, incomeStatement] - results <- if (sequential opts) then sequence actions else single $ shellToList $ parallel actions - return $ map fst results + map (fmap fst) actions incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> IO (FilePath, FlowTypes.FullTimedOutput) incomeStatement opts ch journal reportsDir = do From fcf1e52fc99921baea012f54c525996ddd590e1b Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 14:47:22 +0200 Subject: [PATCH 02/14] Extract journal and report dir --- src/Hledger/Flow/Reports.hs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index f7957a3..2486c68 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -30,13 +30,21 @@ generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [FilePath] generateReports' opts ch = do 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" owners <- single $ shellToList $ listOwners opts - let actions = List.concat $ fmap (\owner -> ownerReports opts ch owner) owners + let ppp = map (ownerParams opts) owners :: [(FilePath, FilePath)] + let actions = List.concat $ fmap (\params -> generateReports'' opts ch params) ppp if (sequential opts) then sequence actions else single $ shellToList $ parallel actions -ownerReports :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> [IO FilePath] -ownerReports opts ch owner = do - let journal = (baseDir opts) "import" owner "all-years" <.> "journal" - let reportsDir = (baseDir opts) "reports" owner +ownerParams :: ReportOptions -> FilePath -> (FilePath, FilePath) +ownerParams opts owner = (ownerJournal opts owner, ownerReportDir opts owner) + +ownerJournal :: ReportOptions -> FilePath -> FilePath +ownerJournal opts owner = (baseDir opts) "import" owner "all-years" <.> "journal" + +ownerReportDir :: ReportOptions -> FilePath -> FilePath +ownerReportDir opts owner = (baseDir opts) "reports" owner + +generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO FilePath] +generateReports'' opts ch (journal, reportsDir) = do let actions = map (\r -> r opts ch journal reportsDir) [accountList, incomeStatement] map (fmap fst) actions From c9b817c43a66d728bb880db4bbb53d95ca22949d Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 14:51:51 +0200 Subject: [PATCH 03/14] Generate top-level reports in addition to owner reports --- src/Hledger/Flow/Reports.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index 2486c68..43ea0a9 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -30,8 +30,10 @@ generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [FilePath] generateReports' opts ch = do 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" owners <- single $ shellToList $ listOwners opts - let ppp = map (ownerParams opts) owners :: [(FilePath, FilePath)] - let actions = List.concat $ fmap (\params -> generateReports'' opts ch params) ppp + let reportParams = [((baseDir opts) "all-years" <.> "journal", + (baseDir opts) "reports")] + ++ map (ownerParams opts) owners :: [(FilePath, FilePath)] + let actions = List.concat $ fmap (\params -> generateReports'' opts ch params) reportParams if (sequential opts) then sequence actions else single $ shellToList $ parallel actions ownerParams :: ReportOptions -> FilePath -> (FilePath, FilePath) From 8946b9fe1e6558b6adf86edc330d30e4d30dc7d9 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 15:34:11 +0200 Subject: [PATCH 04/14] Refactor --- src/Hledger/Flow/Reports.hs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index 43ea0a9..254210b 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -30,20 +30,19 @@ generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [FilePath] generateReports' opts ch = do 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" owners <- single $ shellToList $ listOwners opts - let reportParams = [((baseDir opts) "all-years" <.> "journal", - (baseDir opts) "reports")] - ++ map (ownerParams opts) owners :: [(FilePath, FilePath)] + + let reportParams = [(journalFile opts [], outputDir opts [])] ++ map (ownerParams opts) owners let actions = List.concat $ fmap (\params -> generateReports'' opts ch params) reportParams if (sequential opts) then sequence actions else single $ shellToList $ parallel actions -ownerParams :: ReportOptions -> FilePath -> (FilePath, FilePath) -ownerParams opts owner = (ownerJournal opts owner, ownerReportDir opts owner) +journalFile :: ReportOptions -> [FilePath] -> FilePath +journalFile opts dirs = (foldl () (baseDir opts) dirs) "all-years" <.> "journal" -ownerJournal :: ReportOptions -> FilePath -> FilePath -ownerJournal opts owner = (baseDir opts) "import" owner "all-years" <.> "journal" +outputDir :: ReportOptions -> [FilePath] -> FilePath +outputDir opts dirs = foldl () (baseDir opts) ("reports":dirs) -ownerReportDir :: ReportOptions -> FilePath -> FilePath -ownerReportDir opts owner = (baseDir opts) "reports" owner +ownerParams :: ReportOptions -> FilePath -> (FilePath, FilePath) +ownerParams opts owner = (journalFile opts ["import", owner], outputDir opts [owner]) generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO FilePath] generateReports'' opts ch (journal, reportsDir) = do From 1f9229421d01f1ffb28397edf113005017776bec Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 15:37:02 +0200 Subject: [PATCH 05/14] Renaming --- src/Hledger/Flow/Reports.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index 254210b..d88cc7e 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -55,16 +55,16 @@ incomeStatement opts ch journal reportsDir = do let outputFile = reportsDir "income-expenses" <.> "txt" let sharedOptions = ["--depth", "2", "--pretty-tables", "not:equity"] let reportArgs = ["incomestatement"] ++ sharedOptions ++ ["--average", "--yearly"] - generateReport' opts ch journal outputFile reportArgs + generateReport opts ch journal outputFile reportArgs accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> IO (FilePath, FlowTypes.FullTimedOutput) accountList opts ch journal reportsDir = do let outputFile = reportsDir "accounts" <.> "txt" let reportArgs = ["accounts"] - generateReport' opts ch journal outputFile reportArgs + generateReport opts ch journal outputFile reportArgs -generateReport' :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> [Text] -> IO (FilePath, FlowTypes.FullTimedOutput) -generateReport' opts ch journal outputFile args = do +generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> [Text] -> IO (FilePath, FlowTypes.FullTimedOutput) +generateReport opts ch journal outputFile args = do let reportsDir = directory outputFile mktree reportsDir let relativeJournal = relativeToBase opts journal From 62a5772aeebbbe48cf29eb9cb9e1487eaaa74606 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 16:07:23 +0200 Subject: [PATCH 06/14] Generate reports per year - single hardcoded year for now --- src/Hledger/Flow/Common.hs | 3 +++ src/Hledger/Flow/Reports.hs | 30 ++++++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Hledger/Flow/Common.hs b/src/Hledger/Flow/Common.hs index 5bbd4a2..a65bb3b 100644 --- a/src/Hledger/Flow/Common.hs +++ b/src/Hledger/Flow/Common.hs @@ -449,3 +449,6 @@ extractImportDirs inputFile = do listOwners :: HasBaseDir o => o -> Shell FilePath listOwners opts = fmap basename $ lsDirs $ (baseDir opts) "import" + +intPath :: Int -> FilePath +intPath = fromText . (format d) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index d88cc7e..ab2e568 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -46,30 +46,28 @@ ownerParams opts owner = (journalFile opts ["import", owner], outputDir opts [ow generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO FilePath] generateReports'' opts ch (journal, reportsDir) = do - let actions = map (\r -> r opts ch journal reportsDir) [accountList, incomeStatement] + let actions = map (\r -> r opts ch journal reportsDir 2018) [accountList, incomeStatement] map (fmap fst) actions -incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> IO (FilePath, FlowTypes.FullTimedOutput) -incomeStatement opts ch journal reportsDir = do - mktree reportsDir - let outputFile = reportsDir "income-expenses" <.> "txt" +incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (FilePath, FlowTypes.FullTimedOutput) +incomeStatement opts ch journal reportsDir year = do let sharedOptions = ["--depth", "2", "--pretty-tables", "not:equity"] - let reportArgs = ["incomestatement"] ++ sharedOptions ++ ["--average", "--yearly"] - generateReport opts ch journal outputFile reportArgs + let reportArgs = ["incomestatement"] ++ sharedOptions + generateReport opts ch journal reportsDir year ("income-expenses" <.> "txt") reportArgs -accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> IO (FilePath, FlowTypes.FullTimedOutput) -accountList opts ch journal reportsDir = do - let outputFile = reportsDir "accounts" <.> "txt" +accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (FilePath, FlowTypes.FullTimedOutput) +accountList opts ch journal reportsDir year = do let reportArgs = ["accounts"] - generateReport opts ch journal outputFile reportArgs + generateReport opts ch journal reportsDir year ("accounts" <.> "txt") reportArgs -generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> [Text] -> IO (FilePath, FlowTypes.FullTimedOutput) -generateReport opts ch journal outputFile args = do - let reportsDir = directory outputFile +generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> FilePath -> [Text] -> IO (FilePath, FlowTypes.FullTimedOutput) +generateReport opts ch journal baseOutDir year fileName args = do + let reportsDir = baseOutDir intPath year mktree reportsDir + let outputFile = reportsDir fileName let relativeJournal = relativeToBase opts journal - let reportArgs = ["--file", format fp journal] ++ args - let reportDisplayArgs = ["--file", format fp relativeJournal] ++ args + let reportArgs = ["--file", format fp journal, "--period", repr year] ++ args + let reportDisplayArgs = ["--file", format fp relativeJournal, "--period", repr year] ++ args let hledger = format fp $ FlowTypes.hlPath . hledgerInfo $ opts :: Text let cmdLabel = format ("hledger "%s) $ showCmdArgs reportDisplayArgs result@((exitCode, stdOut, _), _) <- timeAndExitOnErr opts ch cmdLabel dummyLogger channelErr procStrictWithErr (hledger, reportArgs, empty) From 5a3b3813ebbdfde5a2496b7de368d684704bcc8b Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 16:15:00 +0200 Subject: [PATCH 07/14] Make it a list of hardcoded years --- src/Hledger/Flow/Reports.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index ab2e568..b9bda03 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -46,7 +46,9 @@ ownerParams opts owner = (journalFile opts ["import", owner], outputDir opts [ow generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO FilePath] generateReports'' opts ch (journal, reportsDir) = do - let actions = map (\r -> r opts ch journal reportsDir 2018) [accountList, incomeStatement] + let years = [2016, 2017] + y <- years + let actions = map (\r -> r opts ch journal reportsDir y) [accountList, incomeStatement] map (fmap fst) actions incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (FilePath, FlowTypes.FullTimedOutput) From 8d94568b6d72bb2092bbe5ad98dc5f219a7393c4 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 16:39:29 +0200 Subject: [PATCH 08/14] Fix report count - report successes and failures --- src/Hledger/Flow/Reports.hs | 51 +++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index b9bda03..32877d6 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -9,6 +9,7 @@ import Prelude hiding (FilePath, putStrLn, writeFile) import Hledger.Flow.Report.Types import Hledger.Flow.Common import Control.Concurrent.STM +import Data.Either import qualified Data.Text as T import qualified Hledger.Flow.Types as FlowTypes @@ -21,48 +22,40 @@ generateReports opts = sh ( logHandle <- fork $ consoleChannelLoop ch liftIO $ if (showOptions opts) then channelOutLn ch (repr opts) else return () (reports, diff) <- time $ liftIO $ generateReports' opts ch - liftIO $ channelOutLn ch $ format ("Generated "%d%" reports in "%s) (length reports) $ repr diff + let failedAttempts = lefts reports + let failedText = if List.null failedAttempts then "" else format ("(and attempted to write "%d%" more) ") $ length failedAttempts + liftIO $ channelOutLn ch $ format ("Generated "%d%" reports "%s%"in "%s) (length (rights reports)) failedText $ repr diff liftIO $ terminateChannelLoop ch wait logHandle ) -generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [FilePath] +generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [Either FilePath FilePath] generateReports' opts ch = do 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" owners <- single $ shellToList $ listOwners opts - let reportParams = [(journalFile opts [], outputDir opts [])] ++ map (ownerParams opts) owners let actions = List.concat $ fmap (\params -> generateReports'' opts ch params) reportParams if (sequential opts) then sequence actions else single $ shellToList $ parallel actions -journalFile :: ReportOptions -> [FilePath] -> FilePath -journalFile opts dirs = (foldl () (baseDir opts) dirs) "all-years" <.> "journal" - -outputDir :: ReportOptions -> [FilePath] -> FilePath -outputDir opts dirs = foldl () (baseDir opts) ("reports":dirs) - -ownerParams :: ReportOptions -> FilePath -> (FilePath, FilePath) -ownerParams opts owner = (journalFile opts ["import", owner], outputDir opts [owner]) - -generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO FilePath] +generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO (Either FilePath FilePath)] generateReports'' opts ch (journal, reportsDir) = do - let years = [2016, 2017] + let years = [2018] y <- years let actions = map (\r -> r opts ch journal reportsDir y) [accountList, incomeStatement] map (fmap fst) actions -incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (FilePath, FlowTypes.FullTimedOutput) +incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) incomeStatement opts ch journal reportsDir year = do let sharedOptions = ["--depth", "2", "--pretty-tables", "not:equity"] let reportArgs = ["incomestatement"] ++ sharedOptions generateReport opts ch journal reportsDir year ("income-expenses" <.> "txt") reportArgs -accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (FilePath, FlowTypes.FullTimedOutput) +accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) accountList opts ch journal reportsDir year = do let reportArgs = ["accounts"] generateReport opts ch journal reportsDir year ("accounts" <.> "txt") reportArgs -generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> FilePath -> [Text] -> IO (FilePath, FlowTypes.FullTimedOutput) +generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> FilePath -> [Text] -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) generateReport opts ch journal baseOutDir year fileName args = do let reportsDir = baseOutDir intPath year mktree reportsDir @@ -73,8 +66,22 @@ generateReport opts ch journal baseOutDir year fileName args = do let hledger = format fp $ FlowTypes.hlPath . hledgerInfo $ opts :: Text let cmdLabel = format ("hledger "%s) $ showCmdArgs reportDisplayArgs result@((exitCode, stdOut, _), _) <- timeAndExitOnErr opts ch cmdLabel dummyLogger channelErr procStrictWithErr (hledger, reportArgs, empty) - if not (T.null stdOut) then do - writeTextFile outputFile (cmdLabel <> "\n\n"<> stdOut) - channelOutLn ch $ format ("Wrote "%fp) $ relativeToBase opts outputFile - else channelErrLn ch $ format ("No report output for '"%s%"' "%s) cmdLabel (repr exitCode) - return (outputFile, result) + if not (T.null stdOut) + then + do + writeTextFile outputFile (cmdLabel <> "\n\n"<> stdOut) + channelOutLn ch $ format ("Wrote "%fp) $ relativeToBase opts outputFile + return (Right outputFile, result) + else + do + channelErrLn ch $ format ("No report output for '"%s%"' "%s) cmdLabel (repr exitCode) + return (Left outputFile, result) + +journalFile :: ReportOptions -> [FilePath] -> FilePath +journalFile opts dirs = (foldl () (baseDir opts) dirs) "all-years" <.> "journal" + +outputDir :: ReportOptions -> [FilePath] -> FilePath +outputDir opts dirs = foldl () (baseDir opts) ("reports":dirs) + +ownerParams :: ReportOptions -> FilePath -> (FilePath, FilePath) +ownerParams opts owner = (journalFile opts ["import", owner], outputDir opts [owner]) From 94ae11dd6f2cea326e152097a878e8360aa8f018 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sat, 11 May 2019 20:31:08 +0200 Subject: [PATCH 09/14] Extract includeYears - dummy version --- src/Hledger/Flow/Common.hs | 3 +++ src/Hledger/Flow/Reports.hs | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Hledger/Flow/Common.hs b/src/Hledger/Flow/Common.hs index a65bb3b..78dfcc0 100644 --- a/src/Hledger/Flow/Common.hs +++ b/src/Hledger/Flow/Common.hs @@ -452,3 +452,6 @@ listOwners opts = fmap basename $ lsDirs $ (baseDir opts) "import" intPath :: Int -> FilePath intPath = fromText . (format d) + +includeYears :: FilePath -> IO [Int] +includeYears _ = return [2016, 2017] diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index 32877d6..db77f6a 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -33,13 +33,15 @@ generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [Either Fi generateReports' opts ch = do 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" owners <- single $ shellToList $ listOwners opts - let reportParams = [(journalFile opts [], outputDir opts [])] ++ map (ownerParams opts) owners - let actions = List.concat $ fmap (\params -> generateReports'' opts ch params) reportParams + let baseJournal = journalFile opts [] + let baseReportDir = outputDir opts [] + years <- includeYears baseJournal + let reportParams = [(baseJournal, baseReportDir)] ++ map (ownerParams opts) owners + let actions = List.concat $ fmap (generateReports'' opts ch years) reportParams if (sequential opts) then sequence actions else single $ shellToList $ parallel actions -generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> (FilePath, FilePath) -> [IO (Either FilePath FilePath)] -generateReports'' opts ch (journal, reportsDir) = do - let years = [2018] +generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> [Int] -> (FilePath, FilePath) -> [IO (Either FilePath FilePath)] +generateReports'' opts ch years (journal, reportsDir) = do y <- years let actions = map (\r -> r opts ch journal reportsDir y) [accountList, incomeStatement] map (fmap fst) actions From 503ee36fa8105ce7060cc732cab6db618e1484f4 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sun, 12 May 2019 10:57:28 +0200 Subject: [PATCH 10/14] Read years from include file --- src/Hledger/Flow/Common.hs | 29 ++++++++++++++++++++--- src/Hledger/Flow/Reports.hs | 10 ++++---- test/Common/Unit.hs | 47 ++++++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/Hledger/Flow/Common.hs b/src/Hledger/Flow/Common.hs index 78dfcc0..b9f4a79 100644 --- a/src/Hledger/Flow/Common.hs +++ b/src/Hledger/Flow/Common.hs @@ -6,9 +6,13 @@ import Turtle import Prelude hiding (FilePath, putStrLn) import qualified Data.Text as T import qualified Data.Text.IO as T +import qualified Data.Text.Read as T import qualified GHC.IO.Handle.FD as H +import Data.Char (isDigit) import Data.Maybe +import Data.Either + import qualified Control.Foldl as Fold import qualified Data.Map.Strict as Map import Data.Time.LocalTime @@ -450,8 +454,27 @@ extractImportDirs inputFile = do listOwners :: HasBaseDir o => o -> Shell FilePath listOwners opts = fmap basename $ lsDirs $ (baseDir opts) "import" -intPath :: Int -> FilePath +intPath :: Integer -> FilePath intPath = fromText . (format d) -includeYears :: FilePath -> IO [Int] -includeYears _ = return [2016, 2017] +includeYears :: TChan LogMessage -> FilePath -> IO [Integer] +includeYears ch includeFile = do + txt <- readTextFile includeFile + case includeYears' txt of + Left msg -> do + channelErrLn ch msg + return [] + Right years -> return years + +includeYears' :: Text -> Either Text [Integer] +includeYears' txt = case partitionEithers (includeYears'' txt) of + (errors, []) -> do + let msg = format ("Unable to extract years from the following text:\n"%s%"\nErrors:\n"%s) txt (T.intercalate "\n" $ map T.pack errors) + Left msg + (_, years) -> Right years + +includeYears'' :: Text -> [Either String Integer] +includeYears'' txt = map extractDigits (T.lines txt) + +extractDigits :: Text -> Either String Integer +extractDigits txt = fmap fst $ (T.decimal . (T.filter isDigit)) txt diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index db77f6a..d079ff8 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -35,29 +35,29 @@ generateReports' opts ch = do owners <- single $ shellToList $ listOwners opts let baseJournal = journalFile opts [] let baseReportDir = outputDir opts [] - years <- includeYears baseJournal + years <- includeYears ch baseJournal let reportParams = [(baseJournal, baseReportDir)] ++ map (ownerParams opts) owners let actions = List.concat $ fmap (generateReports'' opts ch years) reportParams if (sequential opts) then sequence actions else single $ shellToList $ parallel actions -generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> [Int] -> (FilePath, FilePath) -> [IO (Either FilePath FilePath)] +generateReports'' :: ReportOptions -> TChan FlowTypes.LogMessage -> [Integer] -> (FilePath, FilePath) -> [IO (Either FilePath FilePath)] generateReports'' opts ch years (journal, reportsDir) = do y <- years let actions = map (\r -> r opts ch journal reportsDir y) [accountList, incomeStatement] map (fmap fst) actions -incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) +incomeStatement :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Integer -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) incomeStatement opts ch journal reportsDir year = do let sharedOptions = ["--depth", "2", "--pretty-tables", "not:equity"] let reportArgs = ["incomestatement"] ++ sharedOptions generateReport opts ch journal reportsDir year ("income-expenses" <.> "txt") reportArgs -accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) +accountList :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Integer -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) accountList opts ch journal reportsDir year = do let reportArgs = ["accounts"] generateReport opts ch journal reportsDir year ("accounts" <.> "txt") reportArgs -generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Int -> FilePath -> [Text] -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) +generateReport :: ReportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> Integer -> FilePath -> [Text] -> IO (Either FilePath FilePath, FlowTypes.FullTimedOutput) generateReport opts ch journal baseOutDir year fileName args = do let reportsDir = baseOutDir intPath year mktree reportsDir diff --git a/test/Common/Unit.hs b/test/Common/Unit.hs index c928b91..408498b 100644 --- a/test/Common/Unit.hs +++ b/test/Common/Unit.hs @@ -10,6 +10,10 @@ import Prelude hiding (FilePath) import TestHelpers import Hledger.Flow.Common +import Data.Either +import qualified Data.Text as T +import qualified Data.List as List + testShowCmdArgs = TestCase ( do let options = ["--number", "/tmp/file with spaces"] @@ -17,4 +21,45 @@ testShowCmdArgs = TestCase ( let actual = showCmdArgs options assertEqual "Convert command-line arguments to text" expected actual) -tests = TestList [testShowCmdArgs] +testIncludeYears = TestCase ( + do + let txterr = "Some text without years" + let expectederr = ["Unable to extract years from the following text:", txterr, "Errors:"] + let actualerr = (init . head) $ map (T.lines) $ lefts [includeYears' txterr] :: [Text] + assertEqual "Get a list of years from an include file - error case" expectederr actualerr + + let txt1 = "### Generated by hledger-flow - DO NOT EDIT ###\n\n" <> + "!include import/2014-include.journal\n" <> + "!include import/2015-include.journal\n" <> + "!include import/2016-include.journal\n" <> + "!include import/2017-include.journal\n" <> + "!include import/2018-include.journal\n" <> + "!include import/2019-include.journal" + + let expected1 = Right [2014..2019] + let actual1 = includeYears' txt1 + assertEqual "Get a list of years from an include file - success case 1" expected1 actual1 + + let txt2 = "!include 2019-include.journal" + + let expected2 = Right [2019] + let actual2 = includeYears' txt2 + assertEqual "Get a list of years from an include file - success case 2" expected2 actual2 + ) + +testExtractDigits = TestCase ( + do + let txt1 = "A number: 321\nAnother number is 42, so is 0" + + let expected1 = Right 321420 + let actual1 = extractDigits txt1 + assertEqual "Extract digits from text 1" expected1 actual1 + + let txt2 = "No numbers in this line" + + let expected2 = Left "input does not start with a digit" + let actual2 = extractDigits txt2 + assertEqual "Extract digits from text 2" expected2 actual2 + ) + +tests = TestList [testShowCmdArgs, testIncludeYears, testExtractDigits] From 81d533ee1dcf13ad61ff682ee2610c504ee6b4d8 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sun, 12 May 2019 11:05:08 +0200 Subject: [PATCH 11/14] Update work-in-progress message --- src/Hledger/Flow/Reports.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Hledger/Flow/Reports.hs b/src/Hledger/Flow/Reports.hs index d079ff8..da69a8f 100644 --- a/src/Hledger/Flow/Reports.hs +++ b/src/Hledger/Flow/Reports.hs @@ -31,7 +31,11 @@ generateReports opts = sh ( generateReports' :: ReportOptions -> TChan FlowTypes.LogMessage -> IO [Either FilePath FilePath] generateReports' opts ch = do - 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" + let wipMsg = "Report generation is still a work-in-progress - please let me know how this can be more useful.\n\n" + <> "Keep an eye out for report-related pull requests and issues, and feel free to submit some of your own:\n" + <> "https://github.com/apauley/hledger-flow/pulls\n" + <> "https://github.com/apauley/hledger-flow/issues\n" + channelOutLn ch wipMsg owners <- single $ shellToList $ listOwners opts let baseJournal = journalFile opts [] let baseReportDir = outputDir opts [] From c1ef7a156ced519bead61d398a0a9caaad8bdc51 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sun, 12 May 2019 11:05:38 +0200 Subject: [PATCH 12/14] Bump version to 0.12.1 --- package.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.yaml b/package.yaml index 980abce..63a3b1f 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: hledger-flow -version: 0.12.0.99 +version: 0.12.1.0 synopsis: An hledger workflow focusing on automated statement import and classification. category: Finance, Console license: GPL-3 From f0b7a247289c1da0af5fcefdf52d43a93e9bfc68 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sun, 12 May 2019 11:12:12 +0200 Subject: [PATCH 13/14] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ++++++ .github/ISSUE_TEMPLATE/feature_request.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f0152c8..34f7c04 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -26,6 +26,12 @@ $ hledger-flow --show-options import ``` **To Reproduce** + +FYI, we have a repo with some example transactions which you can use to run `hledger-flow` on: +https://github.com/apauley/hledger-flow-example + +Can you reproduce your issue on these example files? + Steps to reproduce the behavior: 1. Given this input (files or other input) 2. And when running this exact command (with `--show-options`) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 4fbd603..61bf893 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -26,6 +26,12 @@ the runtime options with `--show-options` e.g: $ hledger-flow --show-options import ``` +**Our Example Statements Repository** + +FYI, we have a repo with some example transactions which you can use to run `hledger-flow` on: +https://github.com/apauley/hledger-flow-example + +Can you give examples of what you would like by running `hledger-flow` on these files? **Describe the solution you'd like** A clear and concise description of what you want to happen. From 69141b338ff4d9687a96b5b3407cca26e67faea6 Mon Sep 17 00:00:00 2001 From: Andreas Pauley Date: Sun, 12 May 2019 11:26:09 +0200 Subject: [PATCH 14/14] Update ChangeLog --- ChangeLog.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index aa8a020..c6f770b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,13 @@ # Changelog for [hledger-flow](https://github.com/apauley/hledger-flow) +## 0.12.1 + +Generate some reports per owner. + +Report generation is still a work-in-progress. + +https://github.com/apauley/hledger-flow/pull/57 + ## 0.12.0 - Re-organised the command-line interface: