@@ -4,7 +4,8 @@ module Hledger.Flow.CSVImport
4
4
( importCSVs
5
5
) where
6
6
7
- import Turtle hiding (stdout , stderr , proc , procStrictWithErr )
7
+ import qualified Turtle as Turtle hiding (stdout , stderr , proc , procStrictWithErr )
8
+ import Turtle ((%) , (</>) , (<.>) )
8
9
import Prelude hiding (putStrLn , take )
9
10
import qualified Data.Text as T
10
11
import qualified Data.List.NonEmpty as NonEmpty
@@ -18,43 +19,43 @@ import Hledger.Flow.RuntimeOptions
18
19
import Control.Concurrent.STM
19
20
20
21
importCSVs :: RuntimeOptions -> IO ()
21
- importCSVs opts = sh (
22
+ importCSVs opts = Turtle. sh (
22
23
do
23
- ch <- liftIO newTChanIO
24
- logHandle <- fork $ consoleChannelLoop ch
25
- liftIO $ if (showOptions opts) then channelOutLn ch (repr opts) else return ()
26
- liftIO $ logVerbose opts ch " Starting import"
27
- (journals, diff) <- time $ liftIO $ importCSVs' opts ch
28
- liftIO $ channelOutLn ch $ format (" Imported " % d% " journals in " % s) (length journals) $ repr diff
29
- liftIO $ terminateChannelLoop ch
30
- wait logHandle
24
+ ch <- Turtle. liftIO newTChanIO
25
+ logHandle <- Turtle. fork $ consoleChannelLoop ch
26
+ Turtle. liftIO $ if (showOptions opts) then channelOutLn ch (Turtle. repr opts) else return ()
27
+ Turtle. liftIO $ logVerbose opts ch " Starting import"
28
+ (journals, diff) <- Turtle. time $ Turtle. liftIO $ importCSVs' opts ch
29
+ Turtle. liftIO $ channelOutLn ch $ Turtle. format (" Imported " % Turtle. d% " journals in " % Turtle. s) (length journals) $ Turtle. repr diff
30
+ Turtle. liftIO $ terminateChannelLoop ch
31
+ Turtle. wait logHandle
31
32
)
32
33
33
34
pathSeparators :: [Char ]
34
35
pathSeparators = [' /' , ' \\ ' , ' :' ]
35
36
36
- inputFilePattern :: Pattern Text
37
- inputFilePattern = contains (once (oneOf pathSeparators) <> asciiCI " 1-in" <> once (oneOf pathSeparators) <> plus digit <> once (oneOf pathSeparators))
37
+ inputFilePattern :: Turtle. Pattern T. Text
38
+ inputFilePattern = Turtle. contains (Turtle. once (Turtle. oneOf pathSeparators) <> Turtle. asciiCI " 1-in" <> Turtle. once (Turtle. oneOf pathSeparators) <> Turtle. plus Turtle. digit <> Turtle. once (Turtle. oneOf pathSeparators))
38
39
39
40
importCSVs' :: RuntimeOptions -> TChan FlowTypes. LogMessage -> IO [TurtlePath ]
40
41
importCSVs' opts ch = do
41
42
let baseImportDir = forceTrailingSlash $ (turtleBaseDir opts) </> " import"
42
- let runDir = forceTrailingSlash $ collapse $ (turtleBaseDir opts) </> (turtleRunDir opts)
43
+ let runDir = forceTrailingSlash $ Turtle. collapse $ (turtleBaseDir opts) </> (turtleRunDir opts)
43
44
let effectiveDir = if useRunDir opts
44
45
then if (forceTrailingSlash $ runDir </> " import" ) == baseImportDir then baseImportDir else runDir
45
46
else baseImportDir
46
- channelOutLn ch $ format (" Collecting input files from " % fp) effectiveDir
47
- (inputFiles, diff) <- time $ single . shellToList . onlyFiles $ find inputFilePattern effectiveDir
47
+ channelOutLn ch $ Turtle. format (" Collecting input files from " % Turtle. fp) effectiveDir
48
+ (inputFiles, diff) <- Turtle. time $ Turtle. single . shellToList . onlyFiles $ Turtle. find inputFilePattern effectiveDir
48
49
let fileCount = length inputFiles
49
50
if (fileCount == 0 ) then
50
51
do
51
- let msg = format (" I couldn't find any input files underneath " % fp
52
+ let msg = Turtle. format (" I couldn't find any input files underneath " % Turtle. fp
52
53
% " \n\n hledger-flow expects to find its input files in specifically\n named directories.\n\n " %
53
- " Have a look at the documentation for a detailed explanation:\n " % s) effectiveDir (docURL " input-files" )
54
+ " Have a look at the documentation for a detailed explanation:\n " % Turtle. s) effectiveDir (docURL " input-files" )
54
55
errExit 1 ch msg []
55
56
else
56
57
do
57
- channelOutLn ch $ format (" Found " % d% " input files in " % s% " . Proceeding with import..." ) fileCount (repr diff)
58
+ channelOutLn ch $ Turtle. format (" Found " % Turtle. d% " input files in " % Turtle. s% " . Proceeding with import..." ) fileCount (Turtle. repr diff)
58
59
let actions = map (extractAndImport opts ch) inputFiles :: [IO TurtlePath ]
59
60
importedJournals <- parAwareActions opts actions
60
61
_ <- writeIncludesUpTo opts ch effectiveDir importedJournals
@@ -81,25 +82,25 @@ importCSV opts ch importDirs srcFile = do
81
82
then customConstruct opts ch constructScript bankName accountName ownerName
82
83
else hledgerImport opts ch
83
84
let journalOut = changePathAndExtension " 3-journal" " journal" csvFile
84
- mktree $ directory journalOut
85
+ Turtle. mktree $ Turtle. directory journalOut
85
86
importFun csvFile journalOut
86
87
87
- preprocessIfNeeded :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> Line -> Line -> Line -> TurtlePath -> IO TurtlePath
88
+ preprocessIfNeeded :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> Turtle. Line -> Turtle. Line -> Turtle. Line -> TurtlePath -> IO TurtlePath
88
89
preprocessIfNeeded opts ch script bank account owner src = do
89
90
shouldPreprocess <- verboseTestFile opts ch script
90
91
if shouldPreprocess
91
92
then preprocess opts ch script bank account owner src
92
93
else return src
93
94
94
- preprocess :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> Line -> Line -> Line -> TurtlePath -> IO TurtlePath
95
+ preprocess :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> Turtle. Line -> Turtle. Line -> Turtle. Line -> TurtlePath -> IO TurtlePath
95
96
preprocess opts ch script bank account owner src = do
96
97
let csvOut = changePathAndExtension " 2-preprocessed" " csv" src
97
- mktree $ directory csvOut
98
- let args = [format fp src, format fp csvOut, lineToText bank, lineToText account, lineToText owner]
98
+ Turtle. mktree $ Turtle. directory csvOut
99
+ let args = [Turtle. format Turtle. fp src, Turtle. format Turtle. fp csvOut, Turtle. lineToText bank, Turtle. lineToText account, Turtle. lineToText owner]
99
100
let relScript = relativeToBase opts script
100
101
let relSrc = relativeToBase opts src
101
- let cmdLabel = format (" executing '" % fp% " ' on '" % fp% " '" ) relScript relSrc
102
- _ <- timeAndExitOnErr opts ch cmdLabel channelOut channelErr (parAwareProc opts) (format fp script, args, empty)
102
+ let cmdLabel = Turtle. format (" executing '" % Turtle. fp% " ' on '" % Turtle. fp% " '" ) relScript relSrc
103
+ _ <- timeAndExitOnErr opts ch cmdLabel channelOut channelErr (parAwareProc opts) (Turtle. format Turtle. fp script, args, Turtle. empty)
103
104
return csvOut
104
105
105
106
hledgerImport :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> TurtlePath -> IO TurtlePath
@@ -117,28 +118,28 @@ hledgerImport' opts ch importDirs csvSrc journalOut = do
117
118
case maybeRulesFile of
118
119
Just rf -> do
119
120
let relRules = relativeToBase opts rf
120
- let hledger = format fp $ FlowTypes. hlPath . hledgerInfo $ opts :: Text
121
- let args = [" print" , " --rules-file" , format fp rf, " --file" , format fp csvSrc, " --output-file" , format fp journalOut]
122
- let cmdLabel = format (" importing '" % fp% " ' using rules file '" % fp% " '" ) relCSV relRules
123
- _ <- timeAndExitOnErr opts ch cmdLabel channelOut channelErr (parAwareProc opts) (hledger, args, empty)
121
+ let hledger = Turtle. format Turtle. fp $ FlowTypes. hlPath . hledgerInfo $ opts :: T. Text
122
+ let args = [" print" , " --rules-file" , Turtle. format Turtle. fp rf, " --file" , Turtle. format Turtle. fp csvSrc, " --output-file" , Turtle. format Turtle. fp journalOut]
123
+ let cmdLabel = Turtle. format (" importing '" % Turtle. fp% " ' using rules file '" % Turtle. fp% " '" ) relCSV relRules
124
+ _ <- timeAndExitOnErr opts ch cmdLabel channelOut channelErr (parAwareProc opts) (hledger, args, Turtle. empty)
124
125
return journalOut
125
126
Nothing ->
126
127
do
127
128
let relativeCandidates = map (relativeToBase opts) candidates
128
- let candidatesTxt = T. intercalate " \n " $ map (format fp) relativeCandidates
129
- let msg = format (" I couldn't find an hledger rules file while trying to import\n " % fp
130
- % " \n\n I will happily use the first rules file I can find from any one of these " % d% " files:\n " % s
131
- % " \n\n Here is a bit of documentation about rules files that you may find helpful:\n " % s)
129
+ let candidatesTxt = T. intercalate " \n " $ map (Turtle. format Turtle. fp) relativeCandidates
130
+ let msg = Turtle. format (" I couldn't find an hledger rules file while trying to import\n " % Turtle. fp
131
+ % " \n\n I will happily use the first rules file I can find from any one of these " % Turtle. d% " files:\n " % Turtle. s
132
+ % " \n\n Here is a bit of documentation about rules files that you may find helpful:\n " % Turtle. s)
132
133
relCSV (length candidates) candidatesTxt (docURL " rules-files" )
133
134
errExit 1 ch msg csvSrc
134
135
135
136
rulesFileCandidates :: TurtlePath -> ImportDirs -> [TurtlePath ]
136
137
rulesFileCandidates csvSrc importDirs = statementSpecificRulesFiles csvSrc importDirs ++ generalRulesFiles importDirs
137
138
138
- importDirLines :: (ImportDirs -> TurtlePath ) -> ImportDirs -> [Line ]
139
- importDirLines dirFun importDirs = NonEmpty. toList $ textToLines $ format fp $ dirname $ dirFun importDirs
139
+ importDirLines :: (ImportDirs -> TurtlePath ) -> ImportDirs -> [Turtle. Line ]
140
+ importDirLines dirFun importDirs = NonEmpty. toList $ Turtle. textToLines $ Turtle. format Turtle. fp $ Turtle. dirname $ dirFun importDirs
140
141
141
- importDirLine :: (ImportDirs -> TurtlePath ) -> ImportDirs -> Line
142
+ importDirLine :: (ImportDirs -> TurtlePath ) -> ImportDirs -> Turtle. Line
142
143
importDirLine dirFun importDirs = foldl (<>) " " $ importDirLines dirFun importDirs
143
144
144
145
generalRulesFiles :: ImportDirs -> [TurtlePath ]
@@ -152,25 +153,25 @@ generalRulesFiles importDirs = do
152
153
153
154
statementSpecificRulesFiles :: TurtlePath -> ImportDirs -> [TurtlePath ]
154
155
statementSpecificRulesFiles csvSrc importDirs = do
155
- let srcSuffix = snd $ T. breakOnEnd " _" (format fp (basename csvSrc))
156
+ let srcSuffix = snd $ T. breakOnEnd " _" (Turtle. format Turtle. fp (Turtle. basename csvSrc))
156
157
157
158
if ((T. take 3 srcSuffix) == " rfo" )
158
159
then
159
160
do
160
- let srcSpecificFilename = fromText srcSuffix <.> " rules"
161
+ let srcSpecificFilename = Turtle. fromText srcSuffix <.> " rules"
161
162
map (</> srcSpecificFilename) [accountDir importDirs, bankDir importDirs, importDir importDirs]
162
163
else []
163
164
164
- customConstruct :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> Line -> Line -> Line -> TurtlePath -> TurtlePath -> IO TurtlePath
165
+ customConstruct :: RuntimeOptions -> TChan FlowTypes. LogMessage -> TurtlePath -> Turtle. Line -> Turtle. Line -> Turtle. Line -> TurtlePath -> TurtlePath -> IO TurtlePath
165
166
customConstruct opts ch constructScript bank account owner csvSrc journalOut = do
166
- let script = format fp constructScript :: Text
167
+ let script = Turtle. format Turtle. fp constructScript :: T. Text
167
168
let relScript = relativeToBase opts constructScript
168
- let constructArgs = [format fp csvSrc, " -" , lineToText bank, lineToText account, lineToText owner]
169
- let constructCmdText = format (" Running: " % fp% " " % s) relScript (showCmdArgs constructArgs)
170
- let stdLines = inprocWithErrFun (channelErrLn ch) (script, constructArgs, empty)
171
- let hledger = format fp $ FlowTypes. hlPath . hledgerInfo $ opts :: Text
172
- let args = [" print" , " --ignore-assertions" , " --file" , " -" , " --output-file" , format fp journalOut]
169
+ let constructArgs = [Turtle. format Turtle. fp csvSrc, " -" , Turtle. lineToText bank, Turtle. lineToText account, Turtle. lineToText owner]
170
+ let constructCmdText = Turtle. format (" Running: " % Turtle. fp% " " % Turtle. s) relScript (showCmdArgs constructArgs)
171
+ let stdLines = inprocWithErrFun (channelErrLn ch) (script, constructArgs, Turtle. empty)
172
+ let hledger = Turtle. format Turtle. fp $ FlowTypes. hlPath . hledgerInfo $ opts :: T. Text
173
+ let args = [" print" , " --ignore-assertions" , " --file" , " -" , " --output-file" , Turtle. format Turtle. fp journalOut]
173
174
let relSrc = relativeToBase opts csvSrc
174
- let cmdLabel = format (" executing '" % fp% " ' on '" % fp% " '" ) relScript relSrc
175
+ let cmdLabel = Turtle. format (" executing '" % Turtle. fp% " ' on '" % Turtle. fp% " '" ) relScript relSrc
175
176
_ <- timeAndExitOnErr' opts ch cmdLabel [constructCmdText] channelOut channelErr (parAwareProc opts) (hledger, args, stdLines)
176
177
return journalOut
0 commit comments