{-# LANGUAGE OverloadedStrings #-}
module Hledger.Flow.Import.ImportHelpersTurtle
( allYearIncludeFiles,
extractImportDirs,
extraIncludesForFile,
groupIncludeFiles,
groupAndWriteIncludeFiles,
includePreamble,
toIncludeFiles,
toIncludeLine,
writeIncludesUpTo,
writeToplevelAllYearsInclude,
yearsIncludeMap,
)
where
import Control.Concurrent.STM (TChan)
import qualified Data.List as List (nub, sort)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import Hledger.Flow.BaseDir (relativeToBase, relativeToBase', turtleBaseDir)
import Hledger.Flow.Common (allYearsFileName, directivesFile, filterPaths, groupValuesBy, writeFiles, writeFiles')
import Hledger.Flow.DocHelpers (docURL)
import Hledger.Flow.Import.Types
import Hledger.Flow.Logging (logVerbose)
import Hledger.Flow.PathHelpers (TurtlePath)
import Hledger.Flow.Types
import Turtle ((%), (<.>), (</>))
import qualified Turtle
extractImportDirs :: TurtlePath -> Either T.Text ImportDirs
FilePath
inputFile = do
case FilePath -> [FilePath]
importDirBreakdown FilePath
inputFile of
[FilePath
bd, FilePath
owner, FilePath
bank, FilePath
account, FilePath
filestate, FilePath
year] -> ImportDirs -> Either Text ImportDirs
forall a b. b -> Either a b
Right (ImportDirs -> Either Text ImportDirs)
-> ImportDirs -> Either Text ImportDirs
forall a b. (a -> b) -> a -> b
$ FilePath
-> FilePath
-> FilePath
-> FilePath
-> FilePath
-> FilePath
-> ImportDirs
ImportDirs FilePath
bd FilePath
owner FilePath
bank FilePath
account FilePath
filestate FilePath
year
[FilePath]
_ -> do
Text -> Either Text ImportDirs
forall a b. a -> Either a b
Left (Text -> Either Text ImportDirs) -> Text -> Either Text ImportDirs
forall a b. (a -> b) -> a -> b
$
Format Text (FilePath -> Text -> Text) -> FilePath -> Text -> Text
forall r. Format Text r -> r
Turtle.format
( Format (FilePath -> Text -> Text) (FilePath -> Text -> Text)
"I couldn't find the right number of directories between \"import\" and the input file:\n"
Format (FilePath -> Text -> Text) (FilePath -> Text -> Text)
-> Format (Text -> Text) (FilePath -> Text -> Text)
-> Format (Text -> Text) (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (FilePath -> Text -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp
Format (Text -> Text) (FilePath -> Text -> Text)
-> Format (Text -> Text) (Text -> Text)
-> Format (Text -> Text) (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (Text -> Text)
"\n\nhledger-flow expects to find input files in this structure:\n"
Format (Text -> Text) (FilePath -> Text -> Text)
-> Format (Text -> Text) (Text -> Text)
-> Format (Text -> Text) (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (Text -> Text)
"import/owner/bank/account/filestate/year/trxfile\n\n"
Format (Text -> Text) (FilePath -> Text -> Text)
-> Format (Text -> Text) (Text -> Text)
-> Format (Text -> Text) (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (Text -> Text)
"Have a look at the documentation for a detailed explanation:\n"
Format (Text -> Text) (FilePath -> Text -> Text)
-> Format Text (Text -> Text)
-> Format Text (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format Text (Text -> Text)
forall r. Format r (Text -> r)
Turtle.s
)
FilePath
inputFile
(Line -> Text
docURL Line
"input-files")
importDirBreakdown :: TurtlePath -> [TurtlePath]
importDirBreakdown :: FilePath -> [FilePath]
importDirBreakdown = [FilePath] -> FilePath -> [FilePath]
importDirBreakdown' []
importDirBreakdown' :: [TurtlePath] -> TurtlePath -> [TurtlePath]
importDirBreakdown' :: [FilePath] -> FilePath -> [FilePath]
importDirBreakdown' [FilePath]
acc FilePath
path = do
let dir :: FilePath
dir = FilePath -> FilePath
Turtle.directory FilePath
path
if FilePath -> FilePath
Turtle.dirname FilePath
dir FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
"import" Bool -> Bool -> Bool
|| (FilePath -> FilePath
Turtle.dirname FilePath
dir FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
"")
then FilePath
dir FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
acc
else [FilePath] -> FilePath -> [FilePath]
importDirBreakdown' (FilePath
dir FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
acc) (FilePath -> [FilePath]) -> FilePath -> [FilePath]
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
Turtle.parent FilePath
dir
groupIncludeFiles :: [TurtlePath] -> (TurtleFileBundle, TurtleFileBundle)
groupIncludeFiles :: [FilePath] -> (TurtleFileBundle, TurtleFileBundle)
groupIncludeFiles = TurtleFileBundle -> (TurtleFileBundle, TurtleFileBundle)
allYearIncludeFiles (TurtleFileBundle -> (TurtleFileBundle, TurtleFileBundle))
-> ([FilePath] -> TurtleFileBundle)
-> [FilePath]
-> (TurtleFileBundle, TurtleFileBundle)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [FilePath] -> TurtleFileBundle
groupIncludeFilesPerYear ([FilePath] -> TurtleFileBundle)
-> ([FilePath] -> [FilePath]) -> [FilePath] -> TurtleFileBundle
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
filter FilePath -> Bool
isJournalFile
isJournalFile :: TurtlePath -> Bool
isJournalFile :: FilePath -> Bool
isJournalFile FilePath
f = FilePath -> Maybe FilePath
Turtle.extension FilePath
f Maybe FilePath -> Maybe FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
"journal"
allYearIncludeFiles :: TurtleFileBundle -> (TurtleFileBundle, TurtleFileBundle)
allYearIncludeFiles :: TurtleFileBundle -> (TurtleFileBundle, TurtleFileBundle)
allYearIncludeFiles TurtleFileBundle
m = (TurtleFileBundle
m, [FilePath] -> TurtleFileBundle
yearsIncludeMap ([FilePath] -> TurtleFileBundle) -> [FilePath] -> TurtleFileBundle
forall a b. (a -> b) -> a -> b
$ TurtleFileBundle -> [FilePath]
forall k a. Map k a -> [k]
Map.keys TurtleFileBundle
m)
yearsIncludeMap :: [TurtlePath] -> TurtleFileBundle
yearsIncludeMap :: [FilePath] -> TurtleFileBundle
yearsIncludeMap = (FilePath -> FilePath) -> [FilePath] -> TurtleFileBundle
forall k v. (Ord k, Ord v) => (v -> k) -> [v] -> Map k [v]
groupValuesBy FilePath -> FilePath
allYearsPath
allYearsPath :: TurtlePath -> TurtlePath
allYearsPath :: FilePath -> FilePath
allYearsPath = (FilePath -> FilePath) -> FilePath -> FilePath
allYearsPath' FilePath -> FilePath
Turtle.directory
allYearsPath' :: (TurtlePath -> TurtlePath) -> TurtlePath -> TurtlePath
allYearsPath' :: (FilePath -> FilePath) -> FilePath -> FilePath
allYearsPath' FilePath -> FilePath
dir FilePath
p = FilePath -> FilePath
dir FilePath
p FilePath -> FilePath -> FilePath
</> FilePath
allYearsFileName
includeFileName :: TurtlePath -> TurtlePath
includeFileName :: FilePath -> FilePath
includeFileName = (FilePath -> FilePath -> FilePath
<.> FilePath
"journal") (FilePath -> FilePath)
-> (FilePath -> FilePath) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack (Text -> FilePath) -> (FilePath -> Text) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Format Text (FilePath -> Text) -> FilePath -> Text
forall r. Format Text r -> r
Turtle.format (Format Text (FilePath -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp Format Text (FilePath -> Text)
-> Format Text Text -> Format Text (FilePath -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format Text Text
"-include")) (FilePath -> Text) -> (FilePath -> FilePath) -> FilePath -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
Turtle.dirname
groupIncludeFilesPerYear :: [TurtlePath] -> TurtleFileBundle
groupIncludeFilesPerYear :: [FilePath] -> TurtleFileBundle
groupIncludeFilesPerYear [] = TurtleFileBundle
forall k a. Map k a
Map.empty
groupIncludeFilesPerYear ps :: [FilePath]
ps@(FilePath
p : [FilePath]
_) = case FilePath -> Either Text ImportDirs
extractImportDirs FilePath
p of
Right ImportDirs
_ -> (FilePath -> FilePath) -> [FilePath] -> TurtleFileBundle
forall k v. (Ord k, Ord v) => (v -> k) -> [v] -> Map k [v]
groupValuesBy FilePath -> FilePath
initialIncludeFilePath [FilePath]
ps
Left Text
_ -> (FilePath -> FilePath) -> [FilePath] -> TurtleFileBundle
forall k v. (Ord k, Ord v) => (v -> k) -> [v] -> Map k [v]
groupValuesBy FilePath -> FilePath
parentIncludeFilePath [FilePath]
ps
initialIncludeFilePath :: TurtlePath -> TurtlePath
initialIncludeFilePath :: FilePath -> FilePath
initialIncludeFilePath FilePath
p = (FilePath -> FilePath
Turtle.parent (FilePath -> FilePath)
-> (FilePath -> FilePath) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
Turtle.parent (FilePath -> FilePath)
-> (FilePath -> FilePath) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
Turtle.parent) FilePath
p FilePath -> FilePath -> FilePath
</> FilePath -> FilePath
includeFileName FilePath
p
parentIncludeFilePath :: TurtlePath -> TurtlePath
parentIncludeFilePath :: FilePath -> FilePath
parentIncludeFilePath FilePath
p = (FilePath -> FilePath
Turtle.parent (FilePath -> FilePath)
-> (FilePath -> FilePath) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
Turtle.parent) FilePath
p FilePath -> FilePath -> FilePath
</> FilePath -> FilePath
Turtle.filename FilePath
p
toIncludeFiles :: (HasBaseDir o, HasVerbosity o) => o -> TChan LogMessage -> TurtleFileBundle -> IO (Map.Map TurtlePath T.Text)
toIncludeFiles :: forall o.
(HasBaseDir o, HasVerbosity o) =>
o -> TChan LogMessage -> TurtleFileBundle -> IO (Map FilePath Text)
toIncludeFiles o
opts TChan LogMessage
ch TurtleFileBundle
m = do
TurtleFileBundle
preMap <- o
-> TChan LogMessage
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
forall o.
(HasBaseDir o, HasVerbosity o) =>
o
-> TChan LogMessage
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
extraIncludes o
opts TChan LogMessage
ch (TurtleFileBundle -> [FilePath]
forall k a. Map k a -> [k]
Map.keys TurtleFileBundle
m) [Text
"opening.journal"] [FilePath
"pre-import.journal"] []
TurtleFileBundle
postMap <- o
-> TChan LogMessage
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
forall o.
(HasBaseDir o, HasVerbosity o) =>
o
-> TChan LogMessage
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
extraIncludes o
opts TChan LogMessage
ch (TurtleFileBundle -> [FilePath]
forall k a. Map k a -> [k]
Map.keys TurtleFileBundle
m) [Text
"closing.journal"] [FilePath
"post-import.journal"] [FilePath
"prices.journal"]
Map FilePath Text -> IO (Map FilePath Text)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Map FilePath Text -> IO (Map FilePath Text))
-> Map FilePath Text -> IO (Map FilePath Text)
forall a b. (a -> b) -> a -> b
$ (Map FilePath Text -> Map FilePath Text
addPreamble (Map FilePath Text -> Map FilePath Text)
-> (TurtleFileBundle -> Map FilePath Text)
-> TurtleFileBundle
-> Map FilePath Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TurtleFileBundle
-> TurtleFileBundle -> TurtleFileBundle -> Map FilePath Text
toIncludeFiles' TurtleFileBundle
preMap TurtleFileBundle
postMap) TurtleFileBundle
m
toIncludeFiles' :: TurtleFileBundle -> TurtleFileBundle -> TurtleFileBundle -> Map.Map TurtlePath T.Text
toIncludeFiles' :: TurtleFileBundle
-> TurtleFileBundle -> TurtleFileBundle -> Map FilePath Text
toIncludeFiles' TurtleFileBundle
preMap TurtleFileBundle
postMap = (FilePath -> [FilePath] -> Text)
-> TurtleFileBundle -> Map FilePath Text
forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey ((FilePath -> [FilePath] -> Text)
-> TurtleFileBundle -> Map FilePath Text)
-> (FilePath -> [FilePath] -> Text)
-> TurtleFileBundle
-> Map FilePath Text
forall a b. (a -> b) -> a -> b
$ TurtleFileBundle
-> TurtleFileBundle -> FilePath -> [FilePath] -> Text
generatedIncludeText TurtleFileBundle
preMap TurtleFileBundle
postMap
addPreamble :: Map.Map TurtlePath T.Text -> Map.Map TurtlePath T.Text
addPreamble :: Map FilePath Text -> Map FilePath Text
addPreamble = (Text -> Text) -> Map FilePath Text -> Map FilePath Text
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map (\Text
txt -> Text
includePreamble Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
txt)
toIncludeLine :: TurtlePath -> TurtlePath -> T.Text
toIncludeLine :: FilePath -> FilePath -> Text
toIncludeLine FilePath
base FilePath
file = Format Text (FilePath -> Text) -> FilePath -> Text
forall r. Format Text r -> r
Turtle.format (Format (FilePath -> Text) (FilePath -> Text)
"include " Format (FilePath -> Text) (FilePath -> Text)
-> Format Text (FilePath -> Text) -> Format Text (FilePath -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format Text (FilePath -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp) (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath -> FilePath
relativeToBase' FilePath
base FilePath
file
generatedIncludeText :: TurtleFileBundle -> TurtleFileBundle -> TurtlePath -> [TurtlePath] -> T.Text
generatedIncludeText :: TurtleFileBundle
-> TurtleFileBundle -> FilePath -> [FilePath] -> Text
generatedIncludeText TurtleFileBundle
preMap TurtleFileBundle
postMap FilePath
outputFile [FilePath]
fs = do
let preFiles :: [FilePath]
preFiles = [FilePath] -> Maybe [FilePath] -> [FilePath]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [FilePath] -> [FilePath]) -> Maybe [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ FilePath -> TurtleFileBundle -> Maybe [FilePath]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
outputFile TurtleFileBundle
preMap
let files :: [FilePath]
files = [FilePath] -> [FilePath]
forall a. Eq a => [a] -> [a]
List.nub ([FilePath] -> [FilePath])
-> ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [FilePath] -> [FilePath]
forall a. Ord a => [a] -> [a]
List.sort ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ [FilePath]
fs
let postFiles :: [FilePath]
postFiles = [FilePath] -> Maybe [FilePath] -> [FilePath]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [FilePath] -> [FilePath]) -> Maybe [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ FilePath -> TurtleFileBundle -> Maybe [FilePath]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
outputFile TurtleFileBundle
postMap
let lns :: [Text]
lns = (FilePath -> Text) -> [FilePath] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> Text
toIncludeLine (FilePath -> FilePath -> Text) -> FilePath -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
Turtle.directory FilePath
outputFile) ([FilePath] -> [Text]) -> [FilePath] -> [Text]
forall a b. (a -> b) -> a -> b
$ [FilePath]
preFiles [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
files [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
postFiles
Text -> [Text] -> Text
T.intercalate Text
"\n" ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ [Text]
lns [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [Text
""]
includePreamble :: T.Text
includePreamble :: Text
includePreamble = Text
"### Generated by hledger-flow - DO NOT EDIT ###\n"
groupAndWriteIncludeFiles :: (HasBaseDir o, HasVerbosity o) => o -> TChan LogMessage -> [TurtlePath] -> IO [TurtlePath]
groupAndWriteIncludeFiles :: forall o.
(HasBaseDir o, HasVerbosity o) =>
o -> TChan LogMessage -> [FilePath] -> IO [FilePath]
groupAndWriteIncludeFiles o
opts TChan LogMessage
ch = o
-> TChan LogMessage
-> (TurtleFileBundle, TurtleFileBundle)
-> IO [FilePath]
forall o.
(HasBaseDir o, HasVerbosity o) =>
o
-> TChan LogMessage
-> (TurtleFileBundle, TurtleFileBundle)
-> IO [FilePath]
writeFileMap o
opts TChan LogMessage
ch ((TurtleFileBundle, TurtleFileBundle) -> IO [FilePath])
-> ([FilePath] -> (TurtleFileBundle, TurtleFileBundle))
-> [FilePath]
-> IO [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [FilePath] -> (TurtleFileBundle, TurtleFileBundle)
groupIncludeFiles
writeFileMap :: (HasBaseDir o, HasVerbosity o) => o -> TChan LogMessage -> (TurtleFileBundle, TurtleFileBundle) -> IO [TurtlePath]
writeFileMap :: forall o.
(HasBaseDir o, HasVerbosity o) =>
o
-> TChan LogMessage
-> (TurtleFileBundle, TurtleFileBundle)
-> IO [FilePath]
writeFileMap o
opts TChan LogMessage
ch (TurtleFileBundle
m, TurtleFileBundle
allYears) = do
[FilePath]
_ <- Map FilePath Text -> IO [FilePath]
writeFiles' (Map FilePath Text -> IO [FilePath])
-> Map FilePath Text -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ (Map FilePath Text -> Map FilePath Text
addPreamble (Map FilePath Text -> Map FilePath Text)
-> (TurtleFileBundle -> Map FilePath Text)
-> TurtleFileBundle
-> Map FilePath Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TurtleFileBundle
-> TurtleFileBundle -> TurtleFileBundle -> Map FilePath Text
toIncludeFiles' TurtleFileBundle
forall k a. Map k a
Map.empty TurtleFileBundle
forall k a. Map k a
Map.empty) TurtleFileBundle
allYears
IO (Map FilePath Text) -> IO [FilePath]
writeFiles (IO (Map FilePath Text) -> IO [FilePath])
-> (TurtleFileBundle -> IO (Map FilePath Text))
-> TurtleFileBundle
-> IO [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (o -> TChan LogMessage -> TurtleFileBundle -> IO (Map FilePath Text)
forall o.
(HasBaseDir o, HasVerbosity o) =>
o -> TChan LogMessage -> TurtleFileBundle -> IO (Map FilePath Text)
toIncludeFiles o
opts TChan LogMessage
ch) (TurtleFileBundle -> IO [FilePath])
-> TurtleFileBundle -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ TurtleFileBundle
m
writeIncludesUpTo :: (HasBaseDir o, HasVerbosity o) => o -> TChan LogMessage -> TurtlePath -> [TurtlePath] -> IO [TurtlePath]
writeIncludesUpTo :: forall o.
(HasBaseDir o, HasVerbosity o) =>
o -> TChan LogMessage -> FilePath -> [FilePath] -> IO [FilePath]
writeIncludesUpTo o
_ TChan LogMessage
_ FilePath
_ [] = [FilePath] -> IO [FilePath]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
writeIncludesUpTo o
opts TChan LogMessage
ch FilePath
stopAt [FilePath]
journalFiles = do
let shouldStop :: Bool
shouldStop = (FilePath -> Bool) -> [FilePath] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\FilePath
dir -> FilePath
dir FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
stopAt) ([FilePath] -> Bool) -> [FilePath] -> Bool
forall a b. (a -> b) -> a -> b
$ (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> FilePath
Turtle.parent [FilePath]
journalFiles
if Bool
shouldStop
then [FilePath] -> IO [FilePath]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [FilePath]
journalFiles
else do
[FilePath]
newJournalFiles <- o -> TChan LogMessage -> [FilePath] -> IO [FilePath]
forall o.
(HasBaseDir o, HasVerbosity o) =>
o -> TChan LogMessage -> [FilePath] -> IO [FilePath]
groupAndWriteIncludeFiles o
opts TChan LogMessage
ch [FilePath]
journalFiles
o -> TChan LogMessage -> FilePath -> [FilePath] -> IO [FilePath]
forall o.
(HasBaseDir o, HasVerbosity o) =>
o -> TChan LogMessage -> FilePath -> [FilePath] -> IO [FilePath]
writeIncludesUpTo o
opts TChan LogMessage
ch FilePath
stopAt [FilePath]
newJournalFiles
writeToplevelAllYearsInclude :: (HasBaseDir o, HasVerbosity o) => o -> IO [TurtlePath]
writeToplevelAllYearsInclude :: forall o. (HasBaseDir o, HasVerbosity o) => o -> IO [FilePath]
writeToplevelAllYearsInclude o
opts = do
Bool
directivesExists <- FilePath -> IO Bool
forall (io :: * -> *). MonadIO io => FilePath -> io Bool
Turtle.testfile (o -> FilePath
forall o. HasBaseDir o => o -> FilePath
directivesFile o
opts)
let preMap :: TurtleFileBundle
preMap = if Bool
directivesExists then FilePath -> [FilePath] -> TurtleFileBundle
forall k a. k -> a -> Map k a
Map.singleton (o -> FilePath
forall o. HasBaseDir o => o -> FilePath
turtleBaseDir o
opts FilePath -> FilePath -> FilePath
</> FilePath
allYearsFileName) [o -> FilePath
forall o. HasBaseDir o => o -> FilePath
directivesFile o
opts] else TurtleFileBundle
forall k a. Map k a
Map.empty
let allTop :: TurtleFileBundle
allTop = FilePath -> [FilePath] -> TurtleFileBundle
forall k a. k -> a -> Map k a
Map.singleton (o -> FilePath
forall o. HasBaseDir o => o -> FilePath
turtleBaseDir o
opts FilePath -> FilePath -> FilePath
</> FilePath
allYearsFileName) [FilePath
"import" FilePath -> FilePath -> FilePath
</> FilePath
allYearsFileName]
Map FilePath Text -> IO [FilePath]
writeFiles' (Map FilePath Text -> IO [FilePath])
-> Map FilePath Text -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ (Map FilePath Text -> Map FilePath Text
addPreamble (Map FilePath Text -> Map FilePath Text)
-> (TurtleFileBundle -> Map FilePath Text)
-> TurtleFileBundle
-> Map FilePath Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TurtleFileBundle
-> TurtleFileBundle -> TurtleFileBundle -> Map FilePath Text
toIncludeFiles' TurtleFileBundle
preMap TurtleFileBundle
forall k a. Map k a
Map.empty) TurtleFileBundle
allTop
extraIncludes :: (HasBaseDir o, HasVerbosity o) => o -> TChan LogMessage -> [TurtlePath] -> [T.Text] -> [TurtlePath] -> [TurtlePath] -> IO TurtleFileBundle
o
opts TChan LogMessage
ch = o
-> TChan LogMessage
-> TurtleFileBundle
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
forall o.
(HasBaseDir o, HasVerbosity o) =>
o
-> TChan LogMessage
-> TurtleFileBundle
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
extraIncludes' o
opts TChan LogMessage
ch TurtleFileBundle
forall k a. Map k a
Map.empty
extraIncludes' :: (HasBaseDir o, HasVerbosity o) => o -> TChan LogMessage -> TurtleFileBundle -> [TurtlePath] -> [T.Text] -> [TurtlePath] -> [TurtlePath] -> IO TurtleFileBundle
o
_ TChan LogMessage
_ TurtleFileBundle
acc [] [Text]
_ [FilePath]
_ [FilePath]
_ = TurtleFileBundle -> IO TurtleFileBundle
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return TurtleFileBundle
acc
extraIncludes' o
opts TChan LogMessage
ch TurtleFileBundle
acc (FilePath
file : [FilePath]
files) [Text]
extraSuffixes [FilePath]
manualFiles [FilePath]
prices = do
TurtleFileBundle
extra <- o
-> TChan LogMessage
-> FilePath
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
forall o.
(HasVerbosity o, HasBaseDir o) =>
o
-> TChan LogMessage
-> FilePath
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
extraIncludesForFile o
opts TChan LogMessage
ch FilePath
file [Text]
extraSuffixes [FilePath]
manualFiles [FilePath]
prices
o
-> TChan LogMessage
-> TurtleFileBundle
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
forall o.
(HasBaseDir o, HasVerbosity o) =>
o
-> TChan LogMessage
-> TurtleFileBundle
-> [FilePath]
-> [Text]
-> [FilePath]
-> [FilePath]
-> IO TurtleFileBundle
extraIncludes' o
opts TChan LogMessage
ch (([FilePath] -> [FilePath] -> [FilePath])
-> TurtleFileBundle -> TurtleFileBundle -> TurtleFileBundle
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
(++) TurtleFileBundle
acc TurtleFileBundle
extra) [FilePath]
files [Text]
extraSuffixes [FilePath]
manualFiles [FilePath]
prices
extraIncludesForFile :: (HasVerbosity o, HasBaseDir o) => o -> TChan LogMessage -> TurtlePath -> [T.Text] -> [TurtlePath] -> [TurtlePath] -> IO TurtleFileBundle
o
opts TChan LogMessage
ch FilePath
file [Text]
extraSuffixes [FilePath]
manualFiles [FilePath]
prices = do
let dirprefix :: FilePath
dirprefix = Text -> FilePath
T.unpack (Text -> FilePath) -> Text -> FilePath
forall a b. (a -> b) -> a -> b
$ (Text, Text) -> Text
forall a b. (a, b) -> a
fst ((Text, Text) -> Text) -> (Text, Text) -> Text
forall a b. (a -> b) -> a -> b
$ HasCallStack => Text -> Text -> (Text, Text)
Text -> Text -> (Text, Text)
T.breakOn Text
"-" (Text -> (Text, Text)) -> Text -> (Text, Text)
forall a b. (a -> b) -> a -> b
$ Format Text (FilePath -> Text) -> FilePath -> Text
forall r. Format Text r -> r
Turtle.format Format Text (FilePath -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
Turtle.basename FilePath
file
let fileNames :: [FilePath]
fileNames = (Text -> FilePath) -> [Text] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> FilePath
T.unpack (Text -> FilePath) -> (Text -> Text) -> Text -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Format Text (FilePath -> Text -> Text) -> FilePath -> Text -> Text
forall r. Format Text r -> r
Turtle.format (Format (Text -> Text) (FilePath -> Text -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp Format (Text -> Text) (FilePath -> Text -> Text)
-> Format (Text -> Text) (Text -> Text)
-> Format (Text -> Text) (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (Text -> Text)
"-" Format (Text -> Text) (FilePath -> Text -> Text)
-> Format Text (Text -> Text)
-> Format Text (FilePath -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format Text (Text -> Text)
forall r. Format r (Text -> r)
Turtle.s) FilePath
dirprefix) [Text]
extraSuffixes
let suffixFiles :: [FilePath]
suffixFiles = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath
Turtle.directory FilePath
file FilePath -> FilePath -> FilePath
</>) [FilePath]
fileNames
let suffixDirFiles :: [FilePath]
suffixDirFiles = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (((FilePath -> FilePath
Turtle.directory FilePath
file FilePath -> FilePath -> FilePath
</> FilePath
"_manual_") FilePath -> FilePath -> FilePath
</> FilePath
dirprefix) FilePath -> FilePath -> FilePath
</>) [FilePath]
manualFiles
let priceFiles :: [FilePath]
priceFiles = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ((((FilePath -> FilePath
Turtle.directory FilePath
file FilePath -> FilePath -> FilePath
</> FilePath
"..") FilePath -> FilePath -> FilePath
</> FilePath
"prices") FilePath -> FilePath -> FilePath
</> FilePath
dirprefix) FilePath -> FilePath -> FilePath
</>) [FilePath]
prices
let extraFiles :: [FilePath]
extraFiles = [FilePath]
suffixFiles [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
suffixDirFiles [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
priceFiles
[FilePath]
filtered <- Shell [FilePath] -> IO [FilePath]
forall (io :: * -> *) a. MonadIO io => Shell a -> io a
Turtle.single (Shell [FilePath] -> IO [FilePath])
-> Shell [FilePath] -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ (FilePath -> IO Bool) -> [FilePath] -> Shell [FilePath]
filterPaths FilePath -> IO Bool
forall (io :: * -> *). MonadIO io => FilePath -> io Bool
Turtle.testfile [FilePath]
extraFiles
let logMsg :: Text
logMsg =
Format Text (FilePath -> Int -> Text -> Int -> Text -> Text)
-> FilePath -> Int -> Text -> Int -> Text -> Text
forall r. Format Text r -> r
Turtle.format
(Format
(FilePath -> Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
"Looking for possible extra include files for '" Format
(FilePath -> Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format
(Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format
(Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format
(Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp Format
(Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format
(Int -> Text -> Int -> Text -> Text)
(Int -> Text -> Int -> Text -> Text)
-> Format
(Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format
(Int -> Text -> Int -> Text -> Text)
(Int -> Text -> Int -> Text -> Text)
"' among these " Format
(Int -> Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format
(Text -> Int -> Text -> Text) (Int -> Text -> Int -> Text -> Text)
-> Format
(Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format
(Text -> Int -> Text -> Text) (Int -> Text -> Int -> Text -> Text)
forall n r. Integral n => Format r (n -> r)
Turtle.d Format
(Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format
(Text -> Int -> Text -> Text) (Text -> Int -> Text -> Text)
-> Format
(Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Int -> Text -> Text) (Text -> Int -> Text -> Text)
" options: " Format
(Text -> Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format (Int -> Text -> Text) (Text -> Int -> Text -> Text)
-> Format
(Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Int -> Text -> Text) (Text -> Int -> Text -> Text)
forall r. Format r (Text -> r)
Turtle.s Format
(Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format (Int -> Text -> Text) (Int -> Text -> Text)
-> Format
(Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Int -> Text -> Text) (Int -> Text -> Text)
". Found " Format
(Int -> Text -> Text)
(FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format (Text -> Text) (Int -> Text -> Text)
-> Format
(Text -> Text) (FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (Int -> Text -> Text)
forall n r. Integral n => Format r (n -> r)
Turtle.d Format
(Text -> Text) (FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format (Text -> Text) (Text -> Text)
-> Format
(Text -> Text) (FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format (Text -> Text) (Text -> Text)
": " Format
(Text -> Text) (FilePath -> Int -> Text -> Int -> Text -> Text)
-> Format Text (Text -> Text)
-> Format Text (FilePath -> Int -> Text -> Int -> Text -> Text)
forall b c a. Format b c -> Format a b -> Format a c
% Format Text (Text -> Text)
forall r. Format r (Text -> r)
Turtle.s)
(o -> FilePath -> FilePath
forall o. HasBaseDir o => o -> FilePath -> FilePath
relativeToBase o
opts FilePath
file)
([FilePath] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
extraFiles)
([Text] -> Text
forall a text. (Show a, IsString text) => a -> text
Turtle.repr ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ o -> [FilePath] -> [Text]
forall o. HasBaseDir o => o -> [FilePath] -> [Text]
relativeFilesAsText o
opts [FilePath]
extraFiles)
([FilePath] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilePath]
filtered)
([Text] -> Text
forall a text. (Show a, IsString text) => a -> text
Turtle.repr ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ o -> [FilePath] -> [Text]
forall o. HasBaseDir o => o -> [FilePath] -> [Text]
relativeFilesAsText o
opts [FilePath]
filtered)
o -> TChan LogMessage -> Text -> IO ()
forall o. HasVerbosity o => o -> TChan LogMessage -> Text -> IO ()
logVerbose o
opts TChan LogMessage
ch Text
logMsg
TurtleFileBundle -> IO TurtleFileBundle
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (TurtleFileBundle -> IO TurtleFileBundle)
-> TurtleFileBundle -> IO TurtleFileBundle
forall a b. (a -> b) -> a -> b
$ [(FilePath, [FilePath])] -> TurtleFileBundle
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(FilePath
file, [FilePath]
filtered)]
relativeFilesAsText :: (HasBaseDir o) => o -> [TurtlePath] -> [T.Text]
relativeFilesAsText :: forall o. HasBaseDir o => o -> [FilePath] -> [Text]
relativeFilesAsText o
opts = (FilePath -> Text) -> [FilePath] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Format Text (FilePath -> Text) -> FilePath -> Text
forall r. Format Text r -> r
Turtle.format Format Text (FilePath -> Text)
forall r. Format r (FilePath -> r)
Turtle.fp (FilePath -> Text) -> (FilePath -> FilePath) -> FilePath -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. o -> FilePath -> FilePath
forall o. HasBaseDir o => o -> FilePath -> FilePath
relativeToBase o
opts)