pkg!: cli: Add --today option to explicitly set the current date. (#1674)
rawOptsTo* in hledger-lib now takes a day as an argument, and does not live in the IO monad, since it's now pure. This is so that we can run tests containing future transactions that won't fail as soon as ‘the future’ actually arrives.
This commit is contained in:
		
							parent
							
								
									765466c392
								
							
						
					
					
						commit
						6905e40c4d
					
				| @ -228,21 +228,20 @@ parseCommodity optStr = | |||||||
|       Left _ -> Left optStr  |       Left _ -> Left optStr  | ||||||
|       Right (Amount acommodity _ astyle _) -> Right (acommodity, astyle) |       Right (Amount acommodity _ astyle _) -> Right (acommodity, astyle) | ||||||
| 
 | 
 | ||||||
| -- | Parse an InputOpts from a RawOpts and the current date. | -- | Parse an InputOpts from a RawOpts and a provided date. | ||||||
| -- This will fail with a usage error if the forecast period expression cannot be parsed. | -- This will fail with a usage error if the forecast period expression cannot be parsed. | ||||||
| rawOptsToInputOpts :: RawOpts -> IO InputOpts | rawOptsToInputOpts :: Day -> RawOpts -> InputOpts | ||||||
| rawOptsToInputOpts rawopts = do | rawOptsToInputOpts day rawopts = | ||||||
|     d <- getCurrentDay |  | ||||||
| 
 | 
 | ||||||
|     let noinferprice = boolopt "strict" rawopts || stringopt "args" rawopts == "balancednoautoconversion" |     let noinferprice = boolopt "strict" rawopts || stringopt "args" rawopts == "balancednoautoconversion" | ||||||
| 
 | 
 | ||||||
|         -- Do we really need to do all this work just to get the requested end date? This is duplicating |         -- Do we really need to do all this work just to get the requested end date? This is duplicating | ||||||
|         -- much of reportOptsToSpec. |         -- much of reportOptsToSpec. | ||||||
|         ropts = rawOptsToReportOpts d rawopts |         ropts = rawOptsToReportOpts day rawopts | ||||||
|         argsquery = lefts . rights . map (parseQueryTerm d) $ querystring_ ropts |         argsquery = lefts . rights . map (parseQueryTerm day) $ querystring_ ropts | ||||||
|         datequery = simplifyQuery . filterQuery queryIsDate . And $ queryFromFlags ropts : argsquery |         datequery = simplifyQuery . filterQuery queryIsDate . And $ queryFromFlags ropts : argsquery | ||||||
| 
 | 
 | ||||||
|     return InputOpts{ |     in InputOpts{ | ||||||
|        -- files_             = listofstringopt "file" rawopts |        -- files_             = listofstringopt "file" rawopts | ||||||
|        mformat_           = Nothing |        mformat_           = Nothing | ||||||
|       ,mrules_file_       = maybestringopt "rules-file" rawopts |       ,mrules_file_       = maybestringopt "rules-file" rawopts | ||||||
| @ -251,7 +250,7 @@ rawOptsToInputOpts rawopts = do | |||||||
|       ,new_               = boolopt "new" rawopts |       ,new_               = boolopt "new" rawopts | ||||||
|       ,new_save_          = True |       ,new_save_          = True | ||||||
|       ,pivot_             = stringopt "pivot" rawopts |       ,pivot_             = stringopt "pivot" rawopts | ||||||
|       ,forecast_          = forecastPeriodFromRawOpts d rawopts |       ,forecast_          = forecastPeriodFromRawOpts day rawopts | ||||||
|       ,reportspan_        = DateSpan (queryStartDate False datequery) (queryEndDate False datequery) |       ,reportspan_        = DateSpan (queryStartDate False datequery) (queryEndDate False datequery) | ||||||
|       ,auto_              = boolopt "auto" rawopts |       ,auto_              = boolopt "auto" rawopts | ||||||
|       ,balancingopts_     = defbalancingopts{ |       ,balancingopts_     = defbalancingopts{ | ||||||
|  | |||||||
| @ -777,9 +777,7 @@ updateReportSpec = setEither reportOpts | |||||||
| updateReportSpecWith :: (ReportOpts -> ReportOpts) -> ReportSpec -> Either String ReportSpec | updateReportSpecWith :: (ReportOpts -> ReportOpts) -> ReportSpec -> Either String ReportSpec | ||||||
| updateReportSpecWith = overEither reportOpts | updateReportSpecWith = overEither reportOpts | ||||||
| 
 | 
 | ||||||
| -- | Generate a ReportSpec from RawOpts and the current date. | -- | Generate a ReportSpec from RawOpts and a provided day, or return an error | ||||||
| rawOptsToReportSpec :: RawOpts -> IO ReportSpec | -- string if there are regular expression errors. | ||||||
| rawOptsToReportSpec rawopts = do | rawOptsToReportSpec :: Day -> RawOpts -> Either String ReportSpec | ||||||
|     d <- getCurrentDay | rawOptsToReportSpec day = reportOptsToSpec day . rawOptsToReportOpts day | ||||||
|     let ropts = rawOptsToReportOpts d rawopts |  | ||||||
|     either fail return $ reportOptsToSpec d ropts |  | ||||||
|  | |||||||
| @ -119,6 +119,7 @@ helpflags = [ | |||||||
|  ,flagNone ["info"] (setboolopt "info") "Show info manual with info" |  ,flagNone ["info"] (setboolopt "info") "Show info manual with info" | ||||||
|  -- ,flagNone ["browse-args"] (setboolopt "browse-args") "use a web UI to select options and build up a command line" |  -- ,flagNone ["browse-args"] (setboolopt "browse-args") "use a web UI to select options and build up a command line" | ||||||
|  ,flagReq  ["debug"] (\s opts -> Right $ setopt "debug" s opts) "[N]" "show debug output (levels 1-9, default: 1)" |  ,flagReq  ["debug"] (\s opts -> Right $ setopt "debug" s opts) "[N]" "show debug output (levels 1-9, default: 1)" | ||||||
|  |  ,flagReq  ["today"] (\s opts -> Right $ setopt "today" s opts) "DATE" "generate reports treating DATE as the current day (for testing purposes)" | ||||||
|  ,flagNone ["version"] (setboolopt "version") "show version information" |  ,flagNone ["version"] (setboolopt "version") "show version information" | ||||||
|  ] |  ] | ||||||
| 
 | 
 | ||||||
| @ -466,8 +467,11 @@ replaceNumericFlags = map replace | |||||||
| -- Also records the terminal width, if supported. | -- Also records the terminal width, if supported. | ||||||
| rawOptsToCliOpts :: RawOpts -> IO CliOpts | rawOptsToCliOpts :: RawOpts -> IO CliOpts | ||||||
| rawOptsToCliOpts rawopts = do | rawOptsToCliOpts rawopts = do | ||||||
|   iopts <- rawOptsToInputOpts rawopts |   day <- case maybestringopt "today" rawopts of | ||||||
|   rspec <- rawOptsToReportSpec rawopts |               Nothing -> getCurrentDay | ||||||
|  |               Just d  -> maybe (fail $ "Unable to parse date \"" ++ d ++ "\"") pure $ parsedateM d  -- PARTIAL: | ||||||
|  |   let iopts = rawOptsToInputOpts day rawopts | ||||||
|  |   rspec <- either fail pure $ rawOptsToReportSpec day rawopts  -- PARTIAL: | ||||||
|   mcolumns <- readMay <$> getEnvSafe "COLUMNS" |   mcolumns <- readMay <$> getEnvSafe "COLUMNS" | ||||||
|   mtermwidth <- |   mtermwidth <- | ||||||
| #ifdef mingw32_HOST_OS | #ifdef mingw32_HOST_OS | ||||||
|  | |||||||
| @ -33,6 +33,7 @@ import qualified Data.Text.Lazy as TL | |||||||
| import qualified Data.Text.Lazy.IO as TL | import qualified Data.Text.Lazy.IO as TL | ||||||
| import Data.Time.Calendar (Day) | import Data.Time.Calendar (Day) | ||||||
| import Data.Time.Format (formatTime, defaultTimeLocale, iso8601DateFormat) | import Data.Time.Format (formatTime, defaultTimeLocale, iso8601DateFormat) | ||||||
|  | import Lens.Micro ((^.)) | ||||||
| import Safe (headDef, headMay, atMay) | import Safe (headDef, headMay, atMay) | ||||||
| import System.Console.CmdArgs.Explicit (flagNone) | import System.Console.CmdArgs.Explicit (flagNone) | ||||||
| import System.Console.Haskeline (runInputT, defaultSettings, setComplete) | import System.Console.Haskeline (runInputT, defaultSettings, setComplete) | ||||||
| @ -93,8 +94,8 @@ add opts j | |||||||
|     | otherwise = do |     | otherwise = do | ||||||
|         hPutStrLn stderr $ "Adding transactions to journal file " <> journalFilePath j |         hPutStrLn stderr $ "Adding transactions to journal file " <> journalFilePath j | ||||||
|         showHelp |         showHelp | ||||||
|         today <- getCurrentDay |         let today = opts^.rsDay | ||||||
|         let es = defEntryState{esOpts=opts |             es = defEntryState{esOpts=opts | ||||||
|                               ,esArgs=listofstringopt "args" $ rawopts_ opts |                               ,esArgs=listofstringopt "args" $ rawopts_ opts | ||||||
|                               ,esToday=today |                               ,esToday=today | ||||||
|                               ,esDefDate=today |                               ,esDefDate=today | ||||||
|  | |||||||
| @ -49,8 +49,8 @@ closemode = hledgerCommandMode | |||||||
| -- debugger, beware: close is incredibly devious. simple rules combine to make a horrid maze. | -- debugger, beware: close is incredibly devious. simple rules combine to make a horrid maze. | ||||||
| -- tests are in hledger/test/close.test. | -- tests are in hledger/test/close.test. | ||||||
| close CliOpts{rawopts_=rawopts, reportspec_=rspec} j = do | close CliOpts{rawopts_=rawopts, reportspec_=rspec} j = do | ||||||
|   today <- getCurrentDay |  | ||||||
|   let |   let | ||||||
|  |     today = _rsDay rspec | ||||||
|     -- show opening entry, closing entry, or (default) both ? |     -- show opening entry, closing entry, or (default) both ? | ||||||
|     (opening, closing) = |     (opening, closing) = | ||||||
|       case (boolopt "open" rawopts, boolopt "close" rawopts) of |       case (boolopt "open" rawopts, boolopt "close" rawopts) of | ||||||
|  | |||||||
| @ -39,9 +39,9 @@ rewritemode = hledgerCommandMode | |||||||
| 
 | 
 | ||||||
| rewrite opts@CliOpts{rawopts_=rawopts,reportspec_=rspec} j@Journal{jtxns=ts} = do | rewrite opts@CliOpts{rawopts_=rawopts,reportspec_=rspec} j@Journal{jtxns=ts} = do | ||||||
|   -- rewrite matched transactions |   -- rewrite matched transactions | ||||||
|   d <- getCurrentDay |   let today = _rsDay rspec | ||||||
|   let modifiers = transactionModifierFromOpts opts : jtxnmodifiers j |   let modifiers = transactionModifierFromOpts opts : jtxnmodifiers j | ||||||
|   let j' = j{jtxns=either error' id $ modifyTransactions mempty d modifiers ts}  -- PARTIAL: |   let j' = j{jtxns=either error' id $ modifyTransactions mempty today modifiers ts}  -- PARTIAL: | ||||||
|   -- run the print command, showing all transactions, or show diffs |   -- run the print command, showing all transactions, or show diffs | ||||||
|   printOrDiff rawopts opts{reportspec_=rspec{_rsQuery=Any}} j j' |   printOrDiff rawopts opts{reportspec_=rspec{_rsQuery=Any}} j j' | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -59,12 +59,11 @@ data OneSpan = OneSpan | |||||||
| 
 | 
 | ||||||
| roi ::  CliOpts -> Journal -> IO () | roi ::  CliOpts -> Journal -> IO () | ||||||
| roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportOpts{..}}} j = do | roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportOpts{..}}} j = do | ||||||
|   d <- getCurrentDay |  | ||||||
|   -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". |   -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". | ||||||
|   let |   let | ||||||
|  |     today = _rsDay rspec | ||||||
|     priceOracle = journalPriceOracle infer_value_ j |     priceOracle = journalPriceOracle infer_value_ j | ||||||
|     styles = journalCommodityStyles j |     styles = journalCommodityStyles j | ||||||
|     today = _rsDay rspec |  | ||||||
|     mixedAmountValue periodlast date = |     mixedAmountValue periodlast date = | ||||||
|         maybe id (mixedAmountApplyValuation priceOracle styles periodlast today date) value_ |         maybe id (mixedAmountApplyValuation priceOracle styles periodlast today date) value_ | ||||||
|         . mixedAmountToCost cost_ styles |         . mixedAmountToCost cost_ styles | ||||||
| @ -74,7 +73,7 @@ roi CliOpts{rawopts_=rawopts, reportspec_=rspec@ReportSpec{_rsReportOpts=ReportO | |||||||
|     showCashFlow = boolopt "cashflow" rawopts |     showCashFlow = boolopt "cashflow" rawopts | ||||||
|     prettyTables = pretty_tables_ |     prettyTables = pretty_tables_ | ||||||
|     makeQuery flag = do |     makeQuery flag = do | ||||||
|         q <- either usageError (return . fst) . parseQuery d . T.pack $ stringopt flag rawopts |         q <- either usageError (return . fst) . parseQuery today . T.pack $ stringopt flag rawopts | ||||||
|         return . simplifyQuery $ And [queryFromFlags ropts{period_=PeriodAll}, q] |         return . simplifyQuery $ And [queryFromFlags ropts{period_=PeriodAll}, q] | ||||||
| 
 | 
 | ||||||
|   investmentsQuery <- makeQuery "investment" |   investmentsQuery <- makeQuery "investment" | ||||||
|  | |||||||
| @ -43,12 +43,12 @@ statsmode = hledgerCommandMode | |||||||
| -- | Print various statistics for the journal. | -- | Print various statistics for the journal. | ||||||
| stats :: CliOpts -> Journal -> IO () | stats :: CliOpts -> Journal -> IO () | ||||||
| stats opts@CliOpts{reportspec_=rspec} j = do | stats opts@CliOpts{reportspec_=rspec} j = do | ||||||
|   d <- getCurrentDay |   let today = _rsDay rspec | ||||||
|   let q = _rsQuery rspec |       q = _rsQuery rspec | ||||||
|       l = ledgerFromJournal q j |       l = ledgerFromJournal q j | ||||||
|       reportspan = ledgerDateSpan l `spanDefaultsFrom` queryDateSpan False q |       reportspan = ledgerDateSpan l `spanDefaultsFrom` queryDateSpan False q | ||||||
|       intervalspans = splitSpan (interval_ $ _rsReportOpts rspec) reportspan |       intervalspans = splitSpan (interval_ $ _rsReportOpts rspec) reportspan | ||||||
|       showstats = showLedgerStats l d |       showstats = showLedgerStats l today | ||||||
|       s = unlinesB $ map showstats intervalspans |       s = unlinesB $ map showstats intervalspans | ||||||
|   writeOutputLazyText opts $ TB.toLazyText s |   writeOutputLazyText opts $ TB.toLazyText s | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -27,8 +27,8 @@ tagsmode = hledgerCommandMode | |||||||
| 
 | 
 | ||||||
| tags :: CliOpts -> Journal -> IO () | tags :: CliOpts -> Journal -> IO () | ||||||
| tags CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do | tags CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do | ||||||
|   d <- getCurrentDay |   let today = _rsDay rspec | ||||||
|   let args = listofstringopt "args" rawopts |       args = listofstringopt "args" rawopts | ||||||
|   mtagpat <- mapM (either Fail.fail pure . toRegexCI . T.pack) $ headMay args |   mtagpat <- mapM (either Fail.fail pure . toRegexCI . T.pack) $ headMay args | ||||||
|   let |   let | ||||||
|     querystring = map T.pack $ drop 1 args |     querystring = map T.pack $ drop 1 args | ||||||
| @ -36,7 +36,7 @@ tags CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do | |||||||
|     parsed      = boolopt "parsed" rawopts |     parsed      = boolopt "parsed" rawopts | ||||||
|     empty       = empty_ $ _rsReportOpts rspec |     empty       = empty_ $ _rsReportOpts rspec | ||||||
| 
 | 
 | ||||||
|   argsquery <- either usageError (return . fst) $ parseQueryList d querystring |   argsquery <- either usageError (return . fst) $ parseQueryList today querystring | ||||||
|   let |   let | ||||||
|     q = simplifyQuery $ And [queryFromFlags $ _rsReportOpts rspec, argsquery] |     q = simplifyQuery $ And [queryFromFlags $ _rsReportOpts rspec, argsquery] | ||||||
|     txns = filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j |     txns = filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user