fix:import: save each file's latest dates, separately (#2125)
This commit is contained in:
parent
d1635a55f8
commit
c6a580ff3b
@ -109,6 +109,7 @@ module Hledger.Read (
|
|||||||
-- * Misc
|
-- * Misc
|
||||||
journalStrictChecks,
|
journalStrictChecks,
|
||||||
saveLatestDates,
|
saveLatestDates,
|
||||||
|
saveLatestDatesForFiles,
|
||||||
|
|
||||||
-- * Re-exported
|
-- * Re-exported
|
||||||
JournalReader.tmpostingrulep,
|
JournalReader.tmpostingrulep,
|
||||||
@ -132,7 +133,7 @@ import Data.Default (def)
|
|||||||
import Data.Foldable (asum)
|
import Data.Foldable (asum)
|
||||||
import Data.List (group, sort, sortBy)
|
import Data.List (group, sort, sortBy)
|
||||||
import Data.List.NonEmpty (nonEmpty)
|
import Data.List.NonEmpty (nonEmpty)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (catMaybes, fromMaybe)
|
||||||
import Data.Ord (comparing)
|
import Data.Ord (comparing)
|
||||||
import Data.Semigroup (sconcat)
|
import Data.Semigroup (sconcat)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@ -243,15 +244,17 @@ readJournal iopts@InputOpts{strict_} mpath txt = do
|
|||||||
--
|
--
|
||||||
readJournalFile :: InputOpts -> PrefixedFilePath -> ExceptT String IO Journal
|
readJournalFile :: InputOpts -> PrefixedFilePath -> ExceptT String IO Journal
|
||||||
readJournalFile iopts@InputOpts{new_, new_save_} prefixedfile = do
|
readJournalFile iopts@InputOpts{new_, new_save_} prefixedfile = do
|
||||||
(j,latestdates) <- readJournalFileAndLatestDates iopts prefixedfile
|
(j, mlatestdates) <- readJournalFileAndLatestDates iopts prefixedfile
|
||||||
when (new_ && new_save_) $ liftIO $
|
when (new_ && new_save_) $ liftIO $
|
||||||
saveLatestDates latestdates (snd $ splitReaderPrefix prefixedfile)
|
case mlatestdates of
|
||||||
|
Nothing -> return ()
|
||||||
|
Just (LatestDatesForFile f ds) -> saveLatestDates ds f
|
||||||
return j
|
return j
|
||||||
|
|
||||||
-- The implementation of readJournalFile, but with --new,
|
-- The implementation of readJournalFile.
|
||||||
-- also returns the latest transaction date(s) read.
|
-- With --new, it also returns the latest transaction date(s) read from each file.
|
||||||
-- Used by readJournalFiles, to save those at the end.
|
-- readJournalFiles uses this to update .latest files only after a successful read of all.
|
||||||
readJournalFileAndLatestDates :: InputOpts -> PrefixedFilePath -> ExceptT String IO (Journal,LatestDates)
|
readJournalFileAndLatestDates :: InputOpts -> PrefixedFilePath -> ExceptT String IO (Journal, Maybe LatestDatesForFile)
|
||||||
readJournalFileAndLatestDates iopts prefixedfile = do
|
readJournalFileAndLatestDates iopts prefixedfile = do
|
||||||
let
|
let
|
||||||
(mfmt, f) = splitReaderPrefix prefixedfile
|
(mfmt, f) = splitReaderPrefix prefixedfile
|
||||||
@ -266,9 +269,9 @@ readJournalFileAndLatestDates iopts prefixedfile = do
|
|||||||
then do
|
then do
|
||||||
ds <- liftIO $ previousLatestDates f
|
ds <- liftIO $ previousLatestDates f
|
||||||
let (newj, newds) = journalFilterSinceLatestDates ds j
|
let (newj, newds) = journalFilterSinceLatestDates ds j
|
||||||
return (newj, newds)
|
return (newj, Just $ LatestDatesForFile f newds)
|
||||||
else
|
else
|
||||||
return (j, [])
|
return (j, Nothing)
|
||||||
|
|
||||||
-- | Read a Journal from each specified file path (using @readJournalFile@)
|
-- | Read a Journal from each specified file path (using @readJournalFile@)
|
||||||
-- and combine them into one; or return the first error message.
|
-- and combine them into one; or return the first error message.
|
||||||
@ -285,20 +288,20 @@ readJournalFileAndLatestDates iopts prefixedfile = do
|
|||||||
readJournalFiles :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO Journal
|
readJournalFiles :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO Journal
|
||||||
readJournalFiles iopts@InputOpts{strict_,new_,new_save_} prefixedfiles = do
|
readJournalFiles iopts@InputOpts{strict_,new_,new_save_} prefixedfiles = do
|
||||||
let iopts' = iopts{strict_=False, new_save_=False}
|
let iopts' = iopts{strict_=False, new_save_=False}
|
||||||
(j,latestdates) <-
|
(j, latestdatesforfiles) <-
|
||||||
traceOrLogAt 6 ("readJournalFiles: "++show prefixedfiles) $
|
traceOrLogAt 6 ("readJournalFiles: "++show prefixedfiles) $
|
||||||
readJournalFilesAndLatestDates iopts' prefixedfiles
|
readJournalFilesAndLatestDates iopts' prefixedfiles
|
||||||
when strict_ $ liftEither $ journalStrictChecks j
|
when strict_ $ liftEither $ journalStrictChecks j
|
||||||
when (new_ && new_save_) $ liftIO $
|
when (new_ && new_save_) $ liftIO $ saveLatestDatesForFiles latestdatesforfiles
|
||||||
mapM_ (saveLatestDates latestdates . snd . splitReaderPrefix) prefixedfiles
|
|
||||||
return j
|
return j
|
||||||
|
|
||||||
-- The implementation of readJournalFiles, but with --new,
|
-- The implementation of readJournalFiles, but with --new,
|
||||||
-- also returns the latest transaction date(s) read in each file.
|
-- also returns the latest transaction date(s) read in each file.
|
||||||
-- Used by the import command, to save those at the end.
|
-- Used by the import command, to save those at the end.
|
||||||
readJournalFilesAndLatestDates :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO (Journal,LatestDates)
|
readJournalFilesAndLatestDates :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO (Journal, [LatestDatesForFile])
|
||||||
readJournalFilesAndLatestDates iopts =
|
readJournalFilesAndLatestDates iopts pfs = do
|
||||||
fmap (maybe def sconcat . nonEmpty) . mapM (readJournalFileAndLatestDates iopts)
|
(js, lastdates) <- unzip <$> mapM (readJournalFileAndLatestDates iopts) pfs
|
||||||
|
return (maybe def sconcat $ nonEmpty js, catMaybes lastdates)
|
||||||
|
|
||||||
-- | Run the extra -s/--strict checks on a journal,
|
-- | Run the extra -s/--strict checks on a journal,
|
||||||
-- returning the first error message if any of them fail.
|
-- returning the first error message if any of them fail.
|
||||||
@ -371,6 +374,9 @@ newJournalContent = do
|
|||||||
-- and how many transactions there were on that date.
|
-- and how many transactions there were on that date.
|
||||||
type LatestDates = [Day]
|
type LatestDates = [Day]
|
||||||
|
|
||||||
|
-- The path of an input file, and its current "LatestDates".
|
||||||
|
data LatestDatesForFile = LatestDatesForFile FilePath LatestDates
|
||||||
|
|
||||||
-- | Get all instances of the latest date in an unsorted list of dates.
|
-- | Get all instances of the latest date in an unsorted list of dates.
|
||||||
-- Ie, if the latest date appears once, return it in a one-element list,
|
-- Ie, if the latest date appears once, return it in a one-element list,
|
||||||
-- if it appears three times (anywhere), return three of it.
|
-- if it appears three times (anywhere), return three of it.
|
||||||
@ -383,6 +389,10 @@ latestDates = {-# HLINT ignore "Avoid reverse" #-}
|
|||||||
saveLatestDates :: LatestDates -> FilePath -> IO ()
|
saveLatestDates :: LatestDates -> FilePath -> IO ()
|
||||||
saveLatestDates dates f = T.writeFile (latestDatesFileFor f) $ T.unlines $ map showDate dates
|
saveLatestDates dates f = T.writeFile (latestDatesFileFor f) $ T.unlines $ map showDate dates
|
||||||
|
|
||||||
|
-- | Save each file's latest dates.
|
||||||
|
saveLatestDatesForFiles :: [LatestDatesForFile] -> IO ()
|
||||||
|
saveLatestDatesForFiles = mapM_ (\(LatestDatesForFile f ds) -> saveLatestDates ds f)
|
||||||
|
|
||||||
-- | What were the latest transaction dates seen the last time this
|
-- | What were the latest transaction dates seen the last time this
|
||||||
-- journal file was read ? If there were multiple transactions on the
|
-- journal file was read ? If there were multiple transactions on the
|
||||||
-- latest date, that number of dates is returned, otherwise just one.
|
-- latest date, that number of dates is returned, otherwise just one.
|
||||||
|
|||||||
@ -54,10 +54,10 @@ importcmd opts@CliOpts{rawopts_=rawopts,inputopts_=iopts} j = do
|
|||||||
case inputfiles of
|
case inputfiles of
|
||||||
[] -> error' "please provide one or more input files as arguments" -- PARTIAL:
|
[] -> error' "please provide one or more input files as arguments" -- PARTIAL:
|
||||||
fs -> do
|
fs -> do
|
||||||
enewjandlatestdates <- runExceptT $ readJournalFilesAndLatestDates iopts' fs
|
enewjandlatestdatesforfiles <- runExceptT $ readJournalFilesAndLatestDates iopts' fs
|
||||||
case enewjandlatestdates of
|
case enewjandlatestdatesforfiles of
|
||||||
Left err -> error' err
|
Left err -> error' err
|
||||||
Right (newj, latestdates) ->
|
Right (newj, latestdatesforfiles) ->
|
||||||
case sortOn tdate $ jtxns newj of
|
case sortOn tdate $ jtxns newj of
|
||||||
-- with --dry-run the output should be valid journal format, so messages have ; prepended
|
-- with --dry-run the output should be valid journal format, so messages have ; prepended
|
||||||
[] -> do
|
[] -> do
|
||||||
@ -71,23 +71,27 @@ importcmd opts@CliOpts{rawopts_=rawopts,inputopts_=iopts} j = do
|
|||||||
newts -> do
|
newts -> do
|
||||||
if dryrun
|
if dryrun
|
||||||
then do
|
then do
|
||||||
-- first show imported txns
|
-- show txns to be imported
|
||||||
printf "; would import %d new transactions from %s:\n\n" (length newts) inputstr
|
printf "; would import %d new transactions from %s:\n\n" (length newts) inputstr
|
||||||
mapM_ (T.putStr . showTransaction) newts
|
mapM_ (T.putStr . showTransaction) newts
|
||||||
|
|
||||||
-- then check the whole journal with them added, if in strict mode
|
-- then check the whole journal with them added, if in strict mode
|
||||||
when (strict_ iopts) $ strictChecks
|
when (strict_ iopts) $ strictChecks
|
||||||
|
|
||||||
else do
|
else do
|
||||||
-- first check the whole journal with them added, if in strict mode
|
-- first check the whole journal with them added, if in strict mode
|
||||||
when (strict_ iopts) $ strictChecks
|
when (strict_ iopts) $ strictChecks
|
||||||
-- then add (append) the transactions to the main journal file
|
|
||||||
|
-- then append the transactions to the main journal file.
|
||||||
-- XXX This writes unix line endings (\n), some at least,
|
-- XXX This writes unix line endings (\n), some at least,
|
||||||
-- even if the file uses dos line endings (\r\n), which could leave
|
-- even if the file uses dos line endings (\r\n), which could leave
|
||||||
-- mixed line endings in the file. See also writeFileWithBackupIfChanged.
|
-- mixed line endings in the file. See also writeFileWithBackupIfChanged.
|
||||||
foldM_ (`journalAddTransaction` opts) j newts -- gets forced somehow.. (how ?)
|
foldM_ (`journalAddTransaction` opts) j newts -- gets forced somehow.. (how ?)
|
||||||
|
|
||||||
printf "imported %d new transactions from %s to %s\n" (length newts) inputstr (journalFilePath j)
|
printf "imported %d new transactions from %s to %s\n" (length newts) inputstr (journalFilePath j)
|
||||||
-- and finally update the .latest files
|
|
||||||
mapM_ (saveLatestDates latestdates . snd . splitReaderPrefix) fs
|
-- and if we got this far, update each file's .latest file
|
||||||
|
saveLatestDatesForFiles latestdatesforfiles
|
||||||
|
|
||||||
where
|
where
|
||||||
-- add the new transactions to the journal in memory and check the whole thing
|
-- add the new transactions to the journal in memory and check the whole thing
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user