;run: comments

This commit is contained in:
Dmitry Astapov 2025-02-23 13:12:14 +00:00 committed by Simon Michael
parent 8431cbe95b
commit cf05ccb8e4

View File

@ -46,16 +46,22 @@ runmode = hledgerCommandMode
)
cligeneralflagsgroups1
hiddenflags
([], Just $ argsFlag "[COMMANDS_FILE1 COMMANDS_FILE2 ...]")
([], Just $ argsFlag "[COMMANDS_FILE1 COMMANDS_FILE2 ...] OR [command1 args... -- command2 args... -- command3 args...]")
-- | The fake run command introduced to break circular dependency
-- | The fake run command introduced to break circular dependency.
-- This module needs access to `findBuiltinCommand`, which is defined in Hledger.Cli.Commands
-- However, Hledger.Cli.Commands imports this module, which creates circular dependency.
-- We expose this do-nothing function so that it could be included in the list of all commands inside
-- Hledger.Cli.Commands and ensure that "run" is recognized as a valid command by the Hledger.Cli top-level
-- command line parser. That parser, however, would not call run'. It has a special case for "run", and
-- will call "run" (see below), passing it `findBuiltinCommand`, thus breaking circular dependency.
run' :: CliOpts -> Journal -> IO ()
run' _opts _j = return ()
-- | The actual run command.
run :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> CliOpts -> Journal -> IO ()
run findBuiltinCommand CliOpts{rawopts_=rawopts} j = do
-- Add current journal to cache
-- Add current journal to cache, so that any commands that dont specify `-f` could fetch it from there
addJournalToCache j defaultJournalKey
let args = dbg1 "args" $ listofstringopt "args" rawopts
case args of
@ -68,6 +74,7 @@ run findBuiltinCommand CliOpts{rawopts_=rawopts} j = do
True -> runFromFiles findBuiltinCommand args
False -> runFromArgs findBuiltinCommand args
-- | Run commands from files given to "run".
runFromFiles :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
runFromFiles findBuiltinCommand inputfiles = do
dbg1IO "inputfiles" inputfiles
@ -78,6 +85,7 @@ runFromFiles findBuiltinCommand inputfiles = do
forM_ commands (runCommand findBuiltinCommand . parseCommand)
-- | Run commands from command line arguments given to "run".
runFromArgs :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
runFromArgs findBuiltinCommand args = do
-- read commands from all the inputfiles
@ -91,26 +99,27 @@ parseCommand line =
-- # begins a comment, ignore everything after #
takeWhile (not. ((Just '#')==) . headMay) $ words' (strip line)
-- | Take a single command line (from file, or REPL, or "--"-surrounded block of the args), and run it.
runCommand :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
runCommand findBuiltinCommand cmdline = do
dbg1IO "runCommand for" cmdline
-- # begins a comment, ignore everything after #
case cmdline of
"echo":args -> putStrLn $ unwords $ args
cmdname:args ->
case findBuiltinCommand cmdname of
Nothing -> putStrLn $ unwords (cmdname:args)
Just (cmdmode,cmdaction) -> do
-- Allow "run" to call "run"
let cmdaction' = if cmdname == "run" then run findBuiltinCommand else cmdaction
-- Normally expandArgsAt is done by the Cli.hs, but it stops at the first '--', so we need
-- to do it here as well to make sure that each command can use @ARGFILEs
args' <- expandArgsAt args
dbg1IO "runCommand final args" (cmdname,args')
opts <- getHledgerCliOpts' cmdmode args'
withJournalCached opts (cmdaction' opts)
Nothing -> putStrLn $ unwords (cmdname:args)
Just (cmdmode,cmdaction) -> do
-- Allow "run" to call "run"
let cmdaction' = if cmdname == "run" then run findBuiltinCommand else cmdaction
-- Even though expandArgsAt is done by the Cli.hs, it stops at the first '--', so we need
-- to do it here as well to make sure that each command can use @ARGFILEs
args' <- expandArgsAt args
dbg1IO "runCommand final args" (cmdname,args')
opts <- getHledgerCliOpts' cmdmode args'
withJournalCached opts (cmdaction' opts)
[] -> return ()
-- | Run an interactive REPL.
runREPL :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> IO ()
runREPL findBuiltinCommand = do
putStrLn "Enter hledger commands, or 'quit' for help."
@ -127,13 +136,15 @@ runREPL findBuiltinCommand = do
liftIO $ runCommand findBuiltinCommand $ parseCommand input
loop
{-# NOINLINE journalCache #-}
-- | Cache of all journals that have been read by commands given to "run",
-- keyed by the fully-expanded filename.
journalCache :: MVar (Map.Map String Journal)
journalCache = unsafePerformIO $ newMVar Map.empty
{-# NOINLINE journalCache #-}
-- | Key used to cache the journal given in the arguments to 'run'.
-- | Key used to cache the journal given in the arguments to 'run' itself.
defaultJournalKey :: String
defaultJournalKey = "journal specified in args of run"
defaultJournalKey = "journal specified in the args of run"
addJournalToCache :: Journal -> String -> IO ()
addJournalToCache j key = modifyMVar_ journalCache $ \cache ->
@ -141,15 +152,20 @@ addJournalToCache j key = modifyMVar_ journalCache $ \cache ->
Just _ -> return cache
Nothing -> return $ Map.insert key j cache
-- | Similar to `withJournal`, but uses caches all the journals it reads.
withJournalCached :: CliOpts -> (Journal -> IO ()) -> IO ()
withJournalCached cliopts cmd = do
mbjournalpaths <- journalFilePathFromOptsNoDefault cliopts
let journalpaths = case mbjournalpaths of
Nothing -> NE.fromList [defaultJournalKey]
Nothing ->
-- If the command does not have -f args, it will use the default journal
-- that was supplied to the "run" itself
NE.fromList [defaultJournalKey]
Just paths -> paths
j <- journalTransform cliopts . sconcat <$> mapM (readAndCacheJournalFile (inputopts_ cliopts)) journalpaths
cmd j
where
-- | Read a journal file, caching it if it has not been read before.
readAndCacheJournalFile :: InputOpts -> PrefixedFilePath -> IO Journal
readAndCacheJournalFile iopts "-" = do
dbg1IO "readAndCacheJournalFile using stdin, not cached" "-"