run: do not pre-load journal(s) at the start of "run" [#2345]

wait for the first command to do this. Same for "repl"
This commit is contained in:
Dmitry Astapov 2025-03-08 16:46:04 +00:00 committed by Simon Michael
parent c0b3c932ea
commit 9963a01a15
2 changed files with 37 additions and 33 deletions

View File

@ -81,28 +81,28 @@ newtype DefaultRunJournal = DefaultRunJournal (NE.NonEmpty String) deriving (Sho
-- | The actual run command.
run :: Maybe DefaultRunJournal -> (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> CliOpts -> IO ()
run defaultJournalOverride findBuiltinCommand addons cliopts@CliOpts{rawopts_=rawopts} = do
withJournalCached defaultJournalOverride cliopts $ \(_,key) -> do
let args = dbg1 "args" $ listofstringopt "args" rawopts
isTerminal <- isStdinTerminal
if args == [] && not isTerminal
then do
inputFiles <- journalFilePathFromOpts cliopts
let journalFromStdin = any (== "-") $ map (snd . splitReaderPrefix) $ NE.toList inputFiles
if journalFromStdin
then error' "'run' can't read commands from stdin, as one of the input files was stdin as well"
else runREPL key findBuiltinCommand addons
else do
-- Check if arguments start with "--".
-- If not, assume that they are files with commands
case args of
"--":_ -> runFromArgs key findBuiltinCommand addons args
_ -> runFromFiles key findBuiltinCommand addons args
jpaths <- DefaultRunJournal <$> journalFilePathFromOptsOrDefault defaultJournalOverride cliopts
let args = dbg1 "args" $ listofstringopt "args" rawopts
isTerminal <- isStdinTerminal
if args == [] && not isTerminal
then do
inputFiles <- journalFilePathFromOpts cliopts
let journalFromStdin = any (== "-") $ map (snd . splitReaderPrefix) $ NE.toList inputFiles
if journalFromStdin
then error' "'run' can't read commands from stdin, as one of the input files was stdin as well"
else runREPL jpaths findBuiltinCommand addons
else do
-- Check if arguments start with "--".
-- If not, assume that they are files with commands
case args of
"--":_ -> runFromArgs jpaths findBuiltinCommand addons args
_ -> runFromFiles jpaths findBuiltinCommand addons args
-- | The actual repl command.
repl :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> CliOpts -> IO ()
repl findBuiltinCommand addons cliopts = do
withJournalCached Nothing cliopts $ \(_,key) -> do
runREPL key findBuiltinCommand addons
jpaths <- DefaultRunJournal <$> journalFilePathFromOptsOrDefault Nothing cliopts
runREPL jpaths findBuiltinCommand addons
-- | Run commands from files given to "run".
runFromFiles :: DefaultRunJournal -> (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> [String] -> IO ()
@ -156,9 +156,9 @@ runCommand defaultJournalOverride findBuiltinCommand addons cmdline = do
| infoFlag -> runInfoForTopic "hledger" mmodecmdname
| manFlag -> runManForTopic "hledger" mmodecmdname
| otherwise -> do
withJournalCached (Just defaultJournalOverride) opts $ \(j,key) -> do
withJournalCached (Just defaultJournalOverride) opts $ \(j,jpaths) -> do
if cmdname == "run" -- allow "run" to call "run"
then run (Just key) findBuiltinCommand addons opts
then run (Just jpaths) findBuiltinCommand addons opts
else cmdaction opts j
Nothing | cmdname `elem` addons ->
system (printf "%s-%s %s" progname cmdname (unwords' args)) >>= exitWith
@ -208,23 +208,28 @@ stdinCache :: MVar (Maybe T.Text)
stdinCache = unsafePerformIO $ newMVar Nothing
{-# NOINLINE stdinCache #-}
-- | Get the journal(s) to read, either from the defaultJournalOverride or from the cliopts
journalFilePathFromOptsOrDefault :: Maybe DefaultRunJournal -> CliOpts -> IO (NE.NonEmpty PrefixedFilePath)
journalFilePathFromOptsOrDefault defaultJournalOverride cliopts = do
case defaultJournalOverride of
Nothing -> journalFilePathFromOpts cliopts
Just (DefaultRunJournal defaultFiles) -> do
mbjournalpaths <- journalFilePathFromOptsNoDefault cliopts
case mbjournalpaths of
Nothing -> return defaultFiles -- use the journal(s) given to the "run" itself
Just journalpaths -> return journalpaths
-- | Similar to `withJournal`, but uses caches all the journals it reads.
-- When reading from stdin, caches the stdin contents so that we could reprocess
-- it if a read with different InputOptions is requested.
withJournalCached :: Maybe DefaultRunJournal -> CliOpts -> ((Journal, DefaultRunJournal) -> IO ()) -> IO ()
withJournalCached defaultJournalOverride cliopts cmd = do
(j,key) <- case defaultJournalOverride of
Nothing -> journalFilePathFromOpts cliopts >>= readFiles
Just (DefaultRunJournal defaultFiles) -> do
mbjournalpaths <- journalFilePathFromOptsNoDefault cliopts
case mbjournalpaths of
Nothing -> readFiles defaultFiles -- use the journal(s) given to the "run" itself
Just journalpaths -> readFiles journalpaths
cmd (j,key)
journalpaths <- journalFilePathFromOptsOrDefault defaultJournalOverride cliopts
j <- readFiles journalpaths
cmd (j,DefaultRunJournal journalpaths)
where
readFiles journalpaths = do
j <- journalTransform cliopts . sconcat <$> mapM (readAndCacheJournalFile (inputopts_ cliopts)) journalpaths
return (j, DefaultRunJournal journalpaths)
readFiles journalpaths =
journalTransform cliopts . sconcat <$> mapM (readAndCacheJournalFile (inputopts_ cliopts)) journalpaths
-- | Read a journal file, caching it (and InputOptions used to read it) if it has not been seen before.
-- If the same file is requested with different InputOptions, we read it anew and cache
-- it separately.

View File

@ -150,7 +150,7 @@ Assets, depth 2:
--------------------
$-1
# ** 0. Run caches input files, and re-parses files when InputOptions change
# ** 11. Run caches input files, and re-parses files when InputOptions change
<
2017-01-01 groceries
assets:cash -$100
@ -158,7 +158,6 @@ Assets, depth 2:
$ hledger run --debug 1 -f- -- accounts -- balance -f sample.journal -- balance cash --forecast -- balance cash -f sample.journal --forecast -- register -- register -f sample.journal 2>&1 | grep readAndCacheJournalFile | sed -e "s#$(pwd)/##"
>
readAndCacheJournalFile reading and caching -:
readAndCacheJournalFile using cache for -:
readAndCacheJournalFile reading and caching sample.journal:
readAndCacheJournalFile reading and caching -:
readAndCacheJournalFile reading and caching sample.journal: