Skip to content

Commit 8913d56

Browse files
authored
Merge pull request #30 from apauley/exit-on-err
Exit on err
2 parents f2b9af4 + 59e2806 commit 8913d56

15 files changed

+189
-93
lines changed

.circleci/config.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ jobs:
4545
command: git clone --recurse-submodules https://github.com/apauley/hledger-flow-example.git $HOME/hledger-flow-example
4646
- run:
4747
name: hledger-flow import
48-
command: ~/.local/bin/hledger-flow import --verbose $HOME/hledger-flow-example
48+
command: ~/.local/bin/hledger-flow import --show-options --verbose $HOME/hledger-flow-example
4949
- run:
5050
name: hledger-flow report
51-
command: ~/.local/bin/hledger-flow report --verbose $HOME/hledger-flow-example
51+
command: ~/.local/bin/hledger-flow report --show-options --verbose $HOME/hledger-flow-example
5252
- run:
5353
name: Undo package.yaml change before cache_save
5454
command: git checkout HEAD package.yaml

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
.stack-work/
2+
dist/
3+
dist-newstyle/
24
hledger-flow.cabal
35
*~
46
scratch
57
docs/my-finances
68
releases/
7-
*.c.*
9+
*.c.*

.travis.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ before_install:
3030
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sed -i 's/- -dynamic /- -static /g' $TRAVIS_BUILD_DIR/package.yaml; fi
3131
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cat /proc/cpuinfo; fi
3232
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cat /proc/meminfo; fi
33-
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update && sudo apt install hledger; fi
3433
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sysctl -n machdep.cpu.brand_string; fi
3534
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update --verbose; fi
3635
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install --verbose haskell-stack hledger; fi
@@ -54,15 +53,16 @@ install:
5453
- hledger-flow version
5554
- ldd $(which hledger-flow) || true
5655
- ./bin/release-tarball ~/.local/bin/hledger-flow
56+
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then stack install hledger; fi
5757
- which hledger
5858
- hledger --version
5959
- git clone --recurse-submodules https://github.com/apauley/hledger-flow-example.git $HOME/hledger-flow-example
6060

6161
script:
6262
- stack test --interleaved-output --ghc-options=-Werror
6363
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git checkout HEAD package.yaml; fi
64-
- hledger-flow import --verbose $HOME/hledger-flow-example
65-
- hledger-flow report --verbose $HOME/hledger-flow-example
64+
- hledger-flow import --show-options --verbose $HOME/hledger-flow-example
65+
- hledger-flow report --show-options --verbose $HOME/hledger-flow-example
6666

6767
deploy:
6868
provider: releases

ChangeLog.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog for [hledger-flow](https://github.com/apauley/hledger-flow)
22

3+
## 0.11.1.2
4+
5+
- Exit with an error code when any external script fails - https://github.com/apauley/hledger-flow/issues/28
6+
- Capture external process output when doing parallel processing, in order to better prevent mangled concurrent output.
7+
- Allow users to specify a path to an hledger executable
8+
- Display a user-friendly error message if hledger cannot be found - https://github.com/apauley/hledger-flow/issues/22
9+
310
## 0.11.1.1
411

512
- Support input files from the year 2011 - https://github.com/apauley/hledger-flow/issues/27

TODO.org

-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
- Overall reports, and reports per owner
1111
- More useful reports?
1212
** Performance
13-
- Generate reports in parallel
1413
- Don't re-process statements that have already been processed
1514
** Documentation
1615
- Expand the step-by-step instructions with more scenarios
17-
** Random Thoughts
18-
- First build a list of actions, then perform the actions

app/Main.hs

+23-12
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ import Hledger.Flow.Common
1414
import Hledger.Flow.Reports
1515
import Hledger.Flow.CSVImport
1616

17-
type SubcommandParams = (Maybe FilePath, Bool, Bool, Bool)
17+
data SubcommandParams = SubcommandParams { maybeBaseDir :: Maybe FilePath
18+
, hledgerPathOpt :: Maybe FilePath
19+
, verbose :: Bool
20+
, showOpts :: Bool
21+
, sequential :: Bool
22+
}
23+
deriving (Show)
1824
data Command = Version (Maybe Text) | Import SubcommandParams | Report SubcommandParams deriving (Show)
1925

2026
main :: IO ()
@@ -26,29 +32,34 @@ main = do
2632
Report subParams -> toReportOptions subParams >>= generateReports
2733

2834
toImportOptions :: SubcommandParams -> IO IT.ImportOptions
29-
toImportOptions (maybeBaseDir, verbose, showOpts, sequential) = do
30-
bd <- dirOrPwd maybeBaseDir
35+
toImportOptions params = do
36+
bd <- dirOrPwd $ maybeBaseDir params
37+
hli <- hledgerInfoFromPath $ hledgerPathOpt params
3138
return IT.ImportOptions { IT.baseDir = bd
32-
, IT.verbose = verbose
33-
, IT.showOptions = showOpts
34-
, IT.sequential = sequential }
39+
, IT.hledgerInfo = hli
40+
, IT.verbose = verbose params
41+
, IT.showOptions = showOpts params
42+
, IT.sequential = sequential params }
3543

3644
toReportOptions :: SubcommandParams -> IO RT.ReportOptions
37-
toReportOptions (maybeBaseDir, verbose, showOpts, sequential) = do
38-
bd <- dirOrPwd maybeBaseDir
45+
toReportOptions params = do
46+
bd <- dirOrPwd $ maybeBaseDir params
47+
hli <- hledgerInfoFromPath $ hledgerPathOpt params
3948
return RT.ReportOptions { RT.baseDir = bd
40-
, RT.verbose = verbose
41-
, RT.showOptions = showOpts
42-
, RT.sequential = sequential }
49+
, RT.hledgerInfo = hli
50+
, RT.verbose = verbose params
51+
, RT.showOptions = showOpts params
52+
, RT.sequential = sequential params }
4353

4454
parser :: Parser Command
4555
parser = fmap Import (subcommand "import" "Converts CSV transactions into categorised journal files" subcommandParser)
4656
<|> fmap Report (subcommand "report" "Generate Reports" subcommandParser)
4757
<|> fmap Version (subcommand "version" "Display version information" noArgs)
4858

4959
subcommandParser :: Parser SubcommandParams
50-
subcommandParser = (,,,)
60+
subcommandParser = SubcommandParams
5161
<$> optional (argPath "basedir" "The hledger-flow base directory")
62+
<*> optional (optPath "hledger-path" 'H' "The full path to an hledger executable")
5263
<*> switch (long "verbose" <> short 'v' <> help "Print more verbose output")
5364
<*> switch (long "show-options" <> help "Print the options this program will run with")
5465
<*> switch (long "sequential" <> help "Disable parallel processing")

bin/tag-release

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ BASEDIR="$(pwd)"
77
GITHASH="$(git log -1 --format=tformat:%H)"
88
PACKAGE_VERSION="$(grep '^version:' ${BASEDIR}/package.yaml|awk '{print $2}')"
99
VERSION="v${PACKAGE_VERSION}-beta"
10+
MSG=$(echo -e "Release version ${PACKAGE_VERSION}\n\nSee ChangeLog for details - https://github.com/apauley/hledger-flow/blob/master/ChangeLog.md")
1011

11-
git tag --sign --message="Release version ${PACKAGE_VERSION}" ${VERSION} ${GITHASH}
12+
git tag --sign --message="${MSG}" ${VERSION} ${GITHASH}

package.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: hledger-flow
2-
version: 0.11.1.1
2+
version: 0.11.1.2
33
synopsis: An hledger workflow focusing on automated statement import and classification.
44
category: Finance, Console
55
license: GPL-3

src/Hledger/Flow/CSVImport.hs

+25-21
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ module Hledger.Flow.CSVImport
44
( importCSVs
55
) where
66

7-
import Turtle
7+
import Turtle hiding (stdout, stderr, proc, procStrictWithErr)
88
import Prelude hiding (FilePath, putStrLn, take)
99
import qualified Data.Text as T
1010
import qualified Data.List.NonEmpty as NonEmpty
11-
import Hledger.Flow.Types (LogMessage)
11+
import qualified Hledger.Flow.Types as FlowTypes
1212
import Hledger.Flow.Import.Types
1313
import Hledger.Flow.Common
1414
import Control.Concurrent.STM
@@ -18,10 +18,10 @@ importCSVs opts = sh (
1818
do
1919
ch <- liftIO newTChanIO
2020
logHandle <- fork $ consoleChannelLoop ch
21-
liftIO $ if (showOptions opts) then channelOut ch (repr opts) else return ()
21+
liftIO $ if (showOptions opts) then channelOutLn ch (repr opts) else return ()
2222
liftIO $ logVerbose opts ch "Starting import"
2323
(journals, diff) <- time $ liftIO $ importCSVs' opts ch
24-
liftIO $ channelOut ch $ format ("Imported "%d%" journals in "%s) (length journals) $ repr diff
24+
liftIO $ channelOutLn ch $ format ("Imported "%d%" journals in "%s) (length journals) $ repr diff
2525
liftIO $ terminateChannelLoop ch
2626
wait logHandle
2727
)
@@ -32,9 +32,9 @@ pathSeparators = ['/', '\\', ':']
3232
inputFilePattern :: Pattern Text
3333
inputFilePattern = contains (once (oneOf pathSeparators) <> asciiCI "1-in" <> once (oneOf pathSeparators) <> plus digit <> once (oneOf pathSeparators))
3434

35-
importCSVs' :: ImportOptions -> TChan LogMessage -> IO [FilePath]
35+
importCSVs' :: ImportOptions -> TChan FlowTypes.LogMessage -> IO [FilePath]
3636
importCSVs' opts ch = do
37-
channelOut ch "Collecting input files..."
37+
channelOutLn ch "Collecting input files..."
3838
(inputFiles, diff) <- time $ single . shellToList . onlyFiles $ find inputFilePattern $ baseDir opts
3939
let fileCount = length inputFiles
4040
if (fileCount == 0) then
@@ -45,20 +45,20 @@ importCSVs' opts ch = do
4545
errExit 1 ch msg []
4646
else
4747
do
48-
channelOut ch $ format ("Found "%d%" input files in "%s%". Proceeding with import...") fileCount (repr diff)
48+
channelOutLn ch $ format ("Found "%d%" input files in "%s%". Proceeding with import...") fileCount (repr diff)
4949
let actions = map (extractAndImport opts ch) inputFiles :: [IO FilePath]
5050
importedJournals <- if (sequential opts) then sequence actions else single . shellToList $ parallel actions
5151
sh $ writeIncludesUpTo opts ch "import" importedJournals
5252
return importedJournals
5353

54-
extractAndImport :: ImportOptions -> TChan LogMessage -> FilePath -> IO FilePath
54+
extractAndImport :: ImportOptions -> TChan FlowTypes.LogMessage -> FilePath -> IO FilePath
5555
extractAndImport opts ch inputFile = do
5656
case extractImportDirs inputFile of
5757
Right importDirs -> importCSV opts ch importDirs inputFile
5858
Left errorMessage -> do
5959
errExit 1 ch errorMessage inputFile
6060

61-
importCSV :: ImportOptions -> TChan LogMessage -> ImportDirs -> FilePath -> IO FilePath
61+
importCSV :: ImportOptions -> TChan FlowTypes.LogMessage -> ImportDirs -> FilePath -> IO FilePath
6262
importCSV opts ch importDirs srcFile = do
6363
let preprocessScript = accountDir importDirs </> "preprocess"
6464
let constructScript = accountDir importDirs </> "construct"
@@ -74,43 +74,46 @@ importCSV opts ch importDirs srcFile = do
7474
mktree $ directory journalOut
7575
importFun csvFile journalOut
7676

77-
preprocessIfNeeded :: ImportOptions -> TChan LogMessage -> FilePath -> Line -> Line -> Line -> FilePath -> IO FilePath
77+
preprocessIfNeeded :: ImportOptions -> TChan FlowTypes.LogMessage -> FilePath -> Line -> Line -> Line -> FilePath -> IO FilePath
7878
preprocessIfNeeded opts ch script bank account owner src = do
7979
shouldPreprocess <- verboseTestFile opts ch script
8080
if shouldPreprocess
8181
then preprocess opts ch script bank account owner src
8282
else return src
8383

84-
preprocess :: ImportOptions -> TChan LogMessage -> FilePath -> Line -> Line -> Line -> FilePath -> IO FilePath
84+
preprocess :: ImportOptions -> TChan FlowTypes.LogMessage -> FilePath -> Line -> Line -> Line -> FilePath -> IO FilePath
8585
preprocess opts ch script bank account owner src = do
8686
let csvOut = changePathAndExtension "2-preprocessed" "csv" src
8787
mktree $ directory csvOut
8888
let script' = format fp script :: Text
89-
let action = proc script' [format fp src, format fp csvOut, lineToText bank, lineToText account, lineToText owner] empty
89+
let action = (parAwareProc opts) script' [format fp src, format fp csvOut, lineToText bank, lineToText account, lineToText owner] empty
9090
let relScript = relativeToBase opts script
9191
let relSrc = relativeToBase opts src
9292
let msg = format ("executing '"%fp%"' on '"%fp%"'") relScript relSrc
93-
_ <- logVerboseTime opts ch msg action
93+
((_, stdOut, _), _) <- timeAndExitOnErr opts ch msg action
94+
channelOut ch stdOut
9495
return csvOut
9596

96-
hledgerImport :: ImportOptions -> TChan LogMessage -> FilePath -> FilePath -> IO FilePath
97+
hledgerImport :: ImportOptions -> TChan FlowTypes.LogMessage -> FilePath -> FilePath -> IO FilePath
9798
hledgerImport opts ch csvSrc journalOut = do
9899
case extractImportDirs csvSrc of
99100
Right importDirs -> hledgerImport' opts ch importDirs csvSrc journalOut
100101
Left errorMessage -> do
101102
errExit 1 ch errorMessage csvSrc
102103

103-
hledgerImport' :: ImportOptions -> TChan LogMessage -> ImportDirs -> FilePath -> FilePath -> IO FilePath
104+
hledgerImport' :: ImportOptions -> TChan FlowTypes.LogMessage -> ImportDirs -> FilePath -> FilePath -> IO FilePath
104105
hledgerImport' opts ch importDirs csvSrc journalOut = do
105106
let candidates = rulesFileCandidates csvSrc importDirs
106107
maybeRulesFile <- firstExistingFile candidates
107108
let relCSV = relativeToBase opts csvSrc
108109
case maybeRulesFile of
109110
Just rf -> do
110111
let relRules = relativeToBase opts rf
111-
let action = proc "hledger" ["print", "--rules-file", format fp rf, "--file", format fp csvSrc, "--output-file", format fp journalOut] empty
112+
let hledger = format fp $ FlowTypes.hlPath . hledgerInfo $ opts :: Text
113+
let action = (parAwareProc opts) hledger ["print", "--rules-file", format fp rf, "--file", format fp csvSrc, "--output-file", format fp journalOut] empty
112114
let msg = format ("importing '"%fp%"' using rules file '"%fp%"'") relCSV relRules
113-
_ <- logVerboseTime opts ch msg action
115+
((_, stdOut, _), _) <- timeAndExitOnErr opts ch msg action
116+
channelOut ch stdOut
114117
return journalOut
115118
Nothing ->
116119
do
@@ -151,14 +154,15 @@ statementSpecificRulesFiles csvSrc importDirs = do
151154
map (</> srcSpecificFilename) [accountDir importDirs, bankDir importDirs, importDir importDirs]
152155
else []
153156

154-
customConstruct :: ImportOptions -> TChan LogMessage -> FilePath -> Line -> Line -> Line -> FilePath -> FilePath -> IO FilePath
157+
customConstruct :: ImportOptions -> TChan FlowTypes.LogMessage -> FilePath -> Line -> Line -> Line -> FilePath -> FilePath -> IO FilePath
155158
customConstruct opts ch constructScript bank account owner csvSrc journalOut = do
156159
let script = format fp constructScript :: Text
157160
let importOut = inproc script [format fp csvSrc, "-", lineToText bank, lineToText account, lineToText owner] empty
158-
let action = proc "hledger" ["print", "--ignore-assertions", "--file", "-", "--output-file", format fp journalOut] importOut
161+
let hledger = format fp $ FlowTypes.hlPath . hledgerInfo $ opts :: Text
162+
let action = (parAwareProc opts) hledger ["print", "--ignore-assertions", "--file", "-", "--output-file", format fp journalOut] importOut
159163
let relScript = relativeToBase opts constructScript
160164
let relSrc = relativeToBase opts csvSrc
161165
let msg = format ("executing '"%fp%"' on '"%fp%"'") relScript relSrc
162-
_ <- logVerboseTime opts ch msg action
163-
166+
((_, stdOut, _), _) <- timeAndExitOnErr opts ch msg action
167+
channelOut ch stdOut
164168
return journalOut

0 commit comments

Comments
 (0)