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