;run: comments
This commit is contained in:
parent
8431cbe95b
commit
cf05ccb8e4
@ -46,16 +46,22 @@ runmode = hledgerCommandMode
|
|||||||
)
|
)
|
||||||
cligeneralflagsgroups1
|
cligeneralflagsgroups1
|
||||||
hiddenflags
|
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' :: CliOpts -> Journal -> IO ()
|
||||||
run' _opts _j = return ()
|
run' _opts _j = return ()
|
||||||
|
|
||||||
-- | The actual run command.
|
-- | The actual run command.
|
||||||
run :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> CliOpts -> Journal -> IO ()
|
run :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> CliOpts -> Journal -> IO ()
|
||||||
run findBuiltinCommand CliOpts{rawopts_=rawopts} j = do
|
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
|
addJournalToCache j defaultJournalKey
|
||||||
let args = dbg1 "args" $ listofstringopt "args" rawopts
|
let args = dbg1 "args" $ listofstringopt "args" rawopts
|
||||||
case args of
|
case args of
|
||||||
@ -68,6 +74,7 @@ run findBuiltinCommand CliOpts{rawopts_=rawopts} j = do
|
|||||||
True -> runFromFiles findBuiltinCommand args
|
True -> runFromFiles findBuiltinCommand args
|
||||||
False -> runFromArgs findBuiltinCommand args
|
False -> runFromArgs findBuiltinCommand args
|
||||||
|
|
||||||
|
-- | Run commands from files given to "run".
|
||||||
runFromFiles :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
|
runFromFiles :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
|
||||||
runFromFiles findBuiltinCommand inputfiles = do
|
runFromFiles findBuiltinCommand inputfiles = do
|
||||||
dbg1IO "inputfiles" inputfiles
|
dbg1IO "inputfiles" inputfiles
|
||||||
@ -78,6 +85,7 @@ runFromFiles findBuiltinCommand inputfiles = do
|
|||||||
|
|
||||||
forM_ commands (runCommand findBuiltinCommand . parseCommand)
|
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 :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
|
||||||
runFromArgs findBuiltinCommand args = do
|
runFromArgs findBuiltinCommand args = do
|
||||||
-- read commands from all the inputfiles
|
-- read commands from all the inputfiles
|
||||||
@ -91,26 +99,27 @@ parseCommand line =
|
|||||||
-- # begins a comment, ignore everything after #
|
-- # begins a comment, ignore everything after #
|
||||||
takeWhile (not. ((Just '#')==) . headMay) $ words' (strip line)
|
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 :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> [String] -> IO ()
|
||||||
runCommand findBuiltinCommand cmdline = do
|
runCommand findBuiltinCommand cmdline = do
|
||||||
dbg1IO "runCommand for" cmdline
|
dbg1IO "runCommand for" cmdline
|
||||||
-- # begins a comment, ignore everything after #
|
|
||||||
case cmdline of
|
case cmdline of
|
||||||
"echo":args -> putStrLn $ unwords $ args
|
"echo":args -> putStrLn $ unwords $ args
|
||||||
cmdname:args ->
|
cmdname:args ->
|
||||||
case findBuiltinCommand cmdname of
|
case findBuiltinCommand cmdname of
|
||||||
Nothing -> putStrLn $ unwords (cmdname:args)
|
Nothing -> putStrLn $ unwords (cmdname:args)
|
||||||
Just (cmdmode,cmdaction) -> do
|
Just (cmdmode,cmdaction) -> do
|
||||||
-- Allow "run" to call "run"
|
-- Allow "run" to call "run"
|
||||||
let cmdaction' = if cmdname == "run" then run findBuiltinCommand else cmdaction
|
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
|
-- 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
|
-- to do it here as well to make sure that each command can use @ARGFILEs
|
||||||
args' <- expandArgsAt args
|
args' <- expandArgsAt args
|
||||||
dbg1IO "runCommand final args" (cmdname,args')
|
dbg1IO "runCommand final args" (cmdname,args')
|
||||||
opts <- getHledgerCliOpts' cmdmode args'
|
opts <- getHledgerCliOpts' cmdmode args'
|
||||||
withJournalCached opts (cmdaction' opts)
|
withJournalCached opts (cmdaction' opts)
|
||||||
[] -> return ()
|
[] -> return ()
|
||||||
|
|
||||||
|
-- | Run an interactive REPL.
|
||||||
runREPL :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> IO ()
|
runREPL :: (String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())) -> IO ()
|
||||||
runREPL findBuiltinCommand = do
|
runREPL findBuiltinCommand = do
|
||||||
putStrLn "Enter hledger commands, or 'quit' for help."
|
putStrLn "Enter hledger commands, or 'quit' for help."
|
||||||
@ -127,13 +136,15 @@ runREPL findBuiltinCommand = do
|
|||||||
liftIO $ runCommand findBuiltinCommand $ parseCommand input
|
liftIO $ runCommand findBuiltinCommand $ parseCommand input
|
||||||
loop
|
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 :: MVar (Map.Map String Journal)
|
||||||
journalCache = unsafePerformIO $ newMVar Map.empty
|
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 :: String
|
||||||
defaultJournalKey = "journal specified in args of run"
|
defaultJournalKey = "journal specified in the args of run"
|
||||||
|
|
||||||
addJournalToCache :: Journal -> String -> IO ()
|
addJournalToCache :: Journal -> String -> IO ()
|
||||||
addJournalToCache j key = modifyMVar_ journalCache $ \cache ->
|
addJournalToCache j key = modifyMVar_ journalCache $ \cache ->
|
||||||
@ -141,15 +152,20 @@ addJournalToCache j key = modifyMVar_ journalCache $ \cache ->
|
|||||||
Just _ -> return cache
|
Just _ -> return cache
|
||||||
Nothing -> return $ Map.insert key j 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 -> (Journal -> IO ()) -> IO ()
|
||||||
withJournalCached cliopts cmd = do
|
withJournalCached cliopts cmd = do
|
||||||
mbjournalpaths <- journalFilePathFromOptsNoDefault cliopts
|
mbjournalpaths <- journalFilePathFromOptsNoDefault cliopts
|
||||||
let journalpaths = case mbjournalpaths of
|
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
|
Just paths -> paths
|
||||||
j <- journalTransform cliopts . sconcat <$> mapM (readAndCacheJournalFile (inputopts_ cliopts)) journalpaths
|
j <- journalTransform cliopts . sconcat <$> mapM (readAndCacheJournalFile (inputopts_ cliopts)) journalpaths
|
||||||
cmd j
|
cmd j
|
||||||
where
|
where
|
||||||
|
-- | Read a journal file, caching it if it has not been read before.
|
||||||
readAndCacheJournalFile :: InputOpts -> PrefixedFilePath -> IO Journal
|
readAndCacheJournalFile :: InputOpts -> PrefixedFilePath -> IO Journal
|
||||||
readAndCacheJournalFile iopts "-" = do
|
readAndCacheJournalFile iopts "-" = do
|
||||||
dbg1IO "readAndCacheJournalFile using stdin, not cached" "-"
|
dbg1IO "readAndCacheJournalFile using stdin, not cached" "-"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user