Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package ghc-hledger-lib for openSUSE:Factory
checked in at 2025-12-19 16:45:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-hledger-lib (Old)
and /work/SRC/openSUSE:Factory/.ghc-hledger-lib.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-hledger-lib"
Fri Dec 19 16:45:38 2025 rev:44 rq:1323028 version:1.51.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-hledger-lib/ghc-hledger-lib.changes
2025-11-27 15:20:01.701101551 +0100
+++
/work/SRC/openSUSE:Factory/.ghc-hledger-lib.new.1928/ghc-hledger-lib.changes
2025-12-19 16:49:02.081872879 +0100
@@ -1,0 +2,18 @@
+Mon Dec 8 21:11:05 UTC 2025 - Peter Simons <[email protected]>
+
+- Update hledger-lib to version 1.51.1.
+ Upstream's change log file format is strange (too much unmodified
+ text at at the top). The automatic updater cannot extract the
+ relevant additions. You can find the file at:
+ http://hackage.haskell.org/package/hledger-lib-1.51.1/src/CHANGES.md
+
+-------------------------------------------------------------------
+Fri Dec 5 10:48:22 UTC 2025 - Peter Simons <[email protected]>
+
+- Update hledger-lib to version 1.51.
+ Upstream's change log file format is strange (too much unmodified
+ text at at the top). The automatic updater cannot extract the
+ relevant additions. You can find the file at:
+ http://hackage.haskell.org/package/hledger-lib-1.51/src/CHANGES.md
+
+-------------------------------------------------------------------
Old:
----
hledger-lib-1.50.3.tar.gz
New:
----
hledger-lib-1.51.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-hledger-lib.spec ++++++
--- /var/tmp/diff_new_pack.TsrEaD/_old 2025-12-19 16:49:05.274006369 +0100
+++ /var/tmp/diff_new_pack.TsrEaD/_new 2025-12-19 16:49:05.274006369 +0100
@@ -20,7 +20,7 @@
%global pkgver %{pkg_name}-%{version}
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 1.50.3
+Version: 1.51.1
Release: 0
Summary: A library providing the core functionality of hledger
License: GPL-3.0-or-later
++++++ hledger-lib-1.50.3.tar.gz -> hledger-lib-1.51.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/CHANGES.md
new/hledger-lib-1.51.1/CHANGES.md
--- old/hledger-lib-1.50.3/CHANGES.md 2025-11-18 23:54:26.000000000 +0100
+++ new/hledger-lib-1.51.1/CHANGES.md 2025-12-08 22:04:20.000000000 +0100
@@ -13,10 +13,31 @@
-->
-Internal/api/developer-ish changes in the hledger-lib (and hledger) packages.
+API/developer-ish changes in hledger-lib.
For user-visible changes, see the hledger package changelog.
+# 1.51.1 2025-12-08
+
+
+# 1.51 2025-12-05
+
+Breaking changes
+
+- Hledger.Data.Balancing: balanceTransaction -> balanceSingleTransaction
+- Hledger.Utils.IO:
+ - inputToHandle -> textToHandle; set utf8 not utf8_bom
+ - readHandlePortably, readHandlePortably' -> hGetContentsPortably
+
+Improvements
+
+- Hledger.Utils.String:
+ quoteForCommandLine now quotes some additional problem characters, and no
longer quotes "7".
+ [#2468]
+
+
+# 1.50.4 2025-12-04
+
# 1.50.3 2025-11-18
# 1.50.2 2025-09-26
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Data/Balancing.hs
new/hledger-lib-1.51.1/Hledger/Data/Balancing.hs
--- old/hledger-lib-1.50.3/Hledger/Data/Balancing.hs 2025-11-18
23:54:26.000000000 +0100
+++ new/hledger-lib-1.51.1/Hledger/Data/Balancing.hs 2025-12-08
22:03:33.000000000 +0100
@@ -16,7 +16,7 @@
, defbalancingopts
-- * transaction balancing
, isTransactionBalanced
-, balanceTransaction
+, balanceSingleTransaction
, balanceTransactionHelper
-- * assertion validation
, transactionCheckAssertions
@@ -173,32 +173,21 @@
Right _ -> Right t
Left e -> Left e
--- | Balance this transaction, ensuring that its postings
+-- | Balance this isolated transaction, ensuring that its postings
-- (and its balanced virtual postings) sum to 0,
-- by inferring a missing amount or conversion price(s) if needed.
-- Or if balancing is not possible, because the amounts don't sum to 0 or
-- because there's more than one missing amount, return an error message.
--
--- Transactions with balance assignments can have more than one
--- missing amount; to balance those you should use the more powerful
--- journalBalanceTransactions.
---
--- The "sum to 0" test is done using commodity display precisions,
--- if provided, so that the result agrees with the numbers users can see.
---
-balanceTransaction ::
- BalancingOpts
- -> Transaction
- -> Either String Transaction
-balanceTransaction bopts = fmap fst . balanceTransactionHelper bopts
+-- Note this is not as accurate as @balanceTransactionInJournal@,
+-- which considers the whole journal when calculating balance assignments and
balance assertions.
+balanceSingleTransaction :: BalancingOpts -> Transaction -> Either String
Transaction
+balanceSingleTransaction bopts = fmap fst . balanceTransactionHelper bopts
--- | Helper used by balanceTransaction and
balanceTransactionWithBalanceAssignmentAndCheckAssertionsB;
+-- | Helper used by balanceSingleTransaction and
balanceTransactionWithBalanceAssignmentAndCheckAssertionsB;
-- use one of those instead.
-- It also returns a list of accounts and amounts that were inferred.
-balanceTransactionHelper ::
- BalancingOpts
- -> Transaction
- -> Either String (Transaction, [(AccountName, MixedAmount)])
+balanceTransactionHelper :: BalancingOpts -> Transaction -> Either String
(Transaction, [(AccountName, MixedAmount)])
balanceTransactionHelper bopts t = do
let lbl = lbl_ "balanceTransactionHelper"
(t', inferredamtsandaccts) <- t
@@ -411,7 +400,7 @@
-- journalBalanceTransactions
-- runST
-- runExceptT
--- balanceTransaction (Transaction.hs)
+-- balanceSingleTransaction (Transaction.hs)
-- balanceTransactionHelper
-- runReaderT
-- balanceTransactionAndCheckAssertionsB
@@ -422,7 +411,7 @@
-- journalCheckBalanceAssertions
-- journalBalanceTransactions
-- transactionWizard, postingsBalanced (Add.hs), tests (Transaction.hs)
--- balanceTransaction (Transaction.hs) XXX hledger add won't allow balance
assignments + missing amount ?
+-- balanceSingleTransaction (Transaction.hs) XXX hledger add won't allow
balance assignments + missing amount ?
-- | Monad used for statefully balancing/amount-inferring/assertion-checking
-- a sequence of transactions.
@@ -532,7 +521,7 @@
-- postponing those which do until later. The balanced ones are split
into their postings,
-- keeping these and the not-yet-balanced transactions in the same
relative order.
psandts :: [Either Posting Transaction] <- fmap concat $ forM ts $
\case
- t | null $ assignmentPostings t -> case balanceTransaction bopts t of
+ t | null $ assignmentPostings t -> case balanceSingleTransaction
bopts t of
Left e -> throwError e
Right t' -> do
lift $ writeArray balancedtxns (tindex t') t'
@@ -810,10 +799,10 @@
(fst <$> transactionInferBalancingAmount M.empty
nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` (eur 3 @@ usd 4),
"c" `post` missingamt]}) @?=
Right nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post`
(eur 3 @@ usd 4), "c" `post` usd 1]}
- , testGroup "balanceTransaction" [
+ , testGroup "balanceSingleTransaction" [
testCase "detect unbalanced entry, sign error" $
assertLeft
- (balanceTransaction defbalancingopts
+ (balanceSingleTransaction defbalancingopts
(Transaction
0
""
@@ -828,7 +817,7 @@
[posting {paccount = "a", pamount = mixedAmount (usd 1)},
posting {paccount = "b", pamount = mixedAmount (usd 1)}]))
,testCase "detect unbalanced entry, multiple missing amounts" $
assertLeft $
- balanceTransaction defbalancingopts
+ balanceSingleTransaction defbalancingopts
(Transaction
0
""
@@ -845,7 +834,7 @@
])
,testCase "one missing amount is inferred" $
(pamount . last . tpostings <$>
- balanceTransaction defbalancingopts
+ balanceSingleTransaction defbalancingopts
(Transaction
0
""
@@ -861,7 +850,7 @@
Right (mixedAmount $ usd (-1))
,testCase "conversion price is inferred" $
(pamount . headErr . tpostings <$> -- PARTIAL headErr succeeds
because non-null postings list
- balanceTransaction defbalancingopts
+ balanceSingleTransaction defbalancingopts
(Transaction
0
""
@@ -877,9 +866,9 @@
, posting {paccount = "b", pamount = mixedAmount (eur (-1))}
])) @?=
Right (mixedAmount $ usd 1.35 @@ eur 1)
- ,testCase "balanceTransaction balances based on cost if there are unit
prices" $
+ ,testCase "balanceSingleTransaction balances based on cost if there
are unit prices" $
assertRight $
- balanceTransaction defbalancingopts
+ balanceSingleTransaction defbalancingopts
(Transaction
0
""
@@ -894,9 +883,9 @@
[ posting {paccount = "a", pamount = mixedAmount $ usd 1 `at`
eur 2}
, posting {paccount = "a", pamount = mixedAmount $ usd (-2)
`at` eur 1}
])
- ,testCase "balanceTransaction balances based on cost if there are
total prices" $
+ ,testCase "balanceSingleTransaction balances based on cost if there
are total prices" $
assertRight $
- balanceTransaction defbalancingopts
+ balanceSingleTransaction defbalancingopts
(Transaction
0
""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Data/Journal.hs
new/hledger-lib-1.51.1/Hledger/Data/Journal.hs
--- old/hledger-lib-1.50.3/Hledger/Data/Journal.hs 2025-11-18
23:54:26.000000000 +0100
+++ new/hledger-lib-1.51.1/Hledger/Data/Journal.hs 2025-12-08
22:03:33.000000000 +0100
@@ -1153,6 +1153,7 @@
-- "comm" and "cur" are accepted as synonyms meaning the commodity symbol.
-- Pivoting on an unknown field or tag, or on commodity when there are
multiple commodities, returns "".
-- Pivoting on a tag when there are multiple values for that tag, returns the
first value.
+-- Pivoting on the "type" tag normalises type values to their short spelling.
pivotComponent :: Text -> Posting -> Text
pivotComponent fieldortagname p
| fieldortagname == "code", Just t <- ptransaction p = tcode t
@@ -1164,7 +1165,10 @@
| fieldortagname `elem` commnames = case map acommodity $ amounts $ pamount
p of [s] -> s; _ -> unknown
| fieldortagname == "amt" = case amounts $ pamount p of [a] ->
T.pack $ show $ aquantity a; _ -> unknown
| fieldortagname == "cost" = case amounts $ pamount p of
[a@Amount{acost=Just _}] -> T.pack $ lstrip $ showAmountCost a; _ -> unknown
- | Just (_, tagvalue) <- postingFindTag fieldortagname p = tagvalue
+ | Just (_, tagvalue) <- postingFindTag fieldortagname p =
+ if fieldortagname == "type"
+ then either (const tagvalue) (T.pack . show) $ parseAccountType True
tagvalue
+ else tagvalue
| otherwise = unknown
where
descnames = ["desc", "description"] -- allow "description" for hledger
<=1.30 compat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Read/Common.hs
new/hledger-lib-1.51.1/Hledger/Read/Common.hs
--- old/hledger-lib-1.50.3/Hledger/Read/Common.hs 2025-11-18
23:54:26.000000000 +0100
+++ new/hledger-lib-1.51.1/Hledger/Read/Common.hs 2025-12-08
22:03:33.000000000 +0100
@@ -262,7 +262,7 @@
handleReadFnToTextReadFn :: (InputOpts -> FilePath -> Text -> ExceptT String
IO Journal) -> InputOpts -> FilePath -> Handle -> ExceptT String IO Journal
handleReadFnToTextReadFn p iopts fp =
- p iopts fp <=< lift . readHandlePortably
+ p iopts fp <=< lift . hGetContentsPortably Nothing
-- | Get the date span from --forecast's PERIODEXPR argument, if any.
-- This will fail with a usage error if the period expression cannot be parsed,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Read/CsvReader.hs
new/hledger-lib-1.51.1/Hledger/Read/CsvReader.hs
--- old/hledger-lib-1.50.3/Hledger/Read/CsvReader.hs 2025-11-18
23:54:26.000000000 +0100
+++ new/hledger-lib-1.51.1/Hledger/Read/CsvReader.hs 2025-12-08
22:03:33.000000000 +0100
@@ -63,7 +63,7 @@
parse sep iopts f h = do
rules <- readRules $ getRulesFile f (mrules_file_ iopts)
mencoding <- rulesEncoding rules
- csvtext <- lift $ readHandlePortably' mencoding h
+ csvtext <- lift $ hGetContentsPortably mencoding h
readJournalFromCsv rules f csvtext (Just sep)
-- apply any command line account aliases. Can fail with a bad replacement
pattern.
>>= liftEither . journalApplyAliases (aliasesFromOpts iopts)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Read/JournalReader.hs
new/hledger-lib-1.51.1/Hledger/Read/JournalReader.hs
--- old/hledger-lib-1.50.3/Hledger/Read/JournalReader.hs 2025-11-18
20:00:30.000000000 +0100
+++ new/hledger-lib-1.51.1/Hledger/Read/JournalReader.hs 2025-12-08
22:03:33.000000000 +0100
@@ -32,6 +32,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE MultiWayIf #-}
--- ** exports
module Hledger.Read.JournalReader (
@@ -72,13 +73,14 @@
--- ** imports
import Control.Exception qualified as C
-import Control.Monad (forM_, when, void, unless, filterM)
+import Control.Monad (forM_, when, void, unless, filterM, forM)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Except (ExceptT(..), runExceptT)
import Control.Monad.State.Strict (evalStateT,get,modify',put)
import Control.Monad.Trans.Class (lift)
import Data.Char (toLower)
import Data.Either (isRight, lefts)
+import Data.Functor ((<&>))
import Data.Map.Strict qualified as M
import Data.Text (Text)
import Data.String
@@ -91,6 +93,7 @@
import Text.Megaparsec hiding (parse)
import Text.Megaparsec.Char
import Text.Printf
+import System.Directory (canonicalizePath, doesFileExist, makeAbsolute)
import System.FilePath
import "Glob" System.FilePath.Glob hiding (match)
-- import "filepattern" System.FilePattern.Directory
@@ -103,8 +106,7 @@
import Hledger.Read.RulesReader qualified as RulesReader (reader)
import Hledger.Read.TimeclockReader qualified as TimeclockReader (reader)
import Hledger.Read.TimedotReader qualified as TimedotReader (reader)
-import System.Directory (canonicalizePath, doesFileExist)
-import Data.Functor ((<&>))
+import Data.Function ((&))
--- ** doctest setup
-- $setup
@@ -304,21 +306,26 @@
-- save the position at start of include directive, for error messages
eoff <- getOffset
pos <- getSourcePos
+ let errorNoArg = customFailure $ parseErrorAt eoff "include needs a file
path or glob pattern argument"
-- parse the directive
string "include"
- lift skipNonNewlineSpaces1
- prefixedglob <- rstrip . T.unpack <$> takeWhileP Nothing (`notElem`
[';','\n'])
- lift followingcommentp
+ -- notFollowedBy newline <?> "a file path or glob pattern argument"
+ prefixedglob <- (do
+ lift skipNonNewlineSpaces1
+ prefixedglob <- rstrip . T.unpack <$> takeWhileP Nothing (`notElem`
[';','\n'])
+ lift followingcommentp
+ return prefixedglob
+ ) <|> errorNoArg
+
let (mprefix,glb) = splitReaderPrefix prefixedglob
- parentf <- sourcePosFilePath pos -- a little slow, don't do too often
- when (null $ dbg6 (parentf <> " include: glob pattern") glb) $
- customFailure $ parseErrorAt eoff $ "include needs a file path or glob
pattern argument"
+ parentf <- sourcePosFilePath pos
+ when (null $ dbg6 (parentf <> " include: glob pattern") glb) errorNoArg
-- Find the file or glob-matched files (just the ones from this include
directive), with some IO error checking.
+ paths <- findMatchedFiles eoff parentf glb
-- Also report whether a glob pattern was used, and not just a literal file
path.
-- (paths, isglob) <- findMatchedFiles off pos glb
- paths <- findMatchedFiles eoff parentf glb
-- XXX worth the trouble ? no
-- Comprehensively exclude files already processed. Some complexities here:
@@ -348,12 +355,8 @@
-- Converts ** without a slash to **/*, like zsh's GLOB_STAR_SHORT, so **
also matches file name parts.
-- Checks if any matched paths are directories and excludes those.
-- Converts all matched paths to their canonical form.
- --
- -- Glob patterns never match dot files or files under dot directories,
- -- even if it seems like they should; this is a workaround for Glob bug
#49.
- -- This workaround is disabled if the --old-glob flag is present in the
command line
- -- (detected with unsafePerformIO; it's not worth a ton of boilerplate).
- -- In that case, be aware ** recursive globs will search intermediate dot
directories.
+ -- Note * and ** mostly won't implicitly match dot files or dot
directories,
+ -- but ** will implicitly search non-top-level dot directories (see #2498,
Glob#49).
findMatchedFiles :: (MonadIO m) => Int -> FilePath -> FilePath ->
JournalParser m [FilePath]
findMatchedFiles off parentf globpattern = do
@@ -369,14 +372,15 @@
-- * at the start of a file name ignores dot-named files and
directories, by default.
-- ** (or zero or more consecutive *'s) not followed by slash is
equivalent to *.
-- A **/ component matches any number of directory parts.
- -- A **/ ignores dot-named directories in its starting and ending
directories, by default.
- -- But **/ does search intermediate dot-named directories. Eg it can
find a/.b/c.
+ -- A **/ does not implicitly search top-level dot directories or
implicitly match do files,
+ -- but it does search non-top-level dot directories. Eg ** will find the
c file in a/.b/c.
-- expand a tilde at the start of the glob pattern, or throw an error
- expandedglob <- lift $ expandHomePath globpattern `orRethrowIOError`
"failed to expand ~"
+ expandedglob <- lift $ expandHomePath globpattern & handleIOError off
"failed to expand ~"
-- get the directory of the including file
- let cwd = takeDirectory parentf
+ -- need to canonicalise a symlink parentf so takeDirectory works
correctly [#2503]
+ cwd <- fmap takeDirectory <$> liftIO $ canonicalizePath parentf
-- Don't allow 3 or more stars.
when ("***" `isInfixOf` expandedglob) $
@@ -394,7 +398,6 @@
g <- case tryCompileWith compDefault{errorRecovery=False} expandedglob'
of
Left e -> customFailure $ parseErrorAt off $ "Invalid glob pattern: "
++ e
Right x -> pure x
- let isglob = not $ isLiteral g
-- Find all matched paths. These might include directories or the
current file.
paths <- liftIO $ globDir1 g cwd
@@ -402,49 +405,44 @@
-- Exclude any directories or symlinks to directories, and canonicalise,
and sort.
files <- liftIO $
filterM doesFileExist paths
- >>= mapM canonicalizePath
+ >>= mapM makeAbsolute
<&> sort
- -- Work around a Glob bug with dot dirs: while **/ ignores dot dirs in
the starting and ending dirs,
- -- it does search dot dirs in between those two (Glob #49).
- -- This could be inconvenient, eg making it hard to avoid VCS
directories in a source tree.
- -- We work around as follows: when any glob was used, paths involving
dot dirs are excluded in post processing.
- -- Unfortunately this means valid globs like .dotdir/* can't be used;
only literal paths can match
- -- things in dot dirs. An --old-glob command line flag disables this
workaround, for backward compatibility.
- oldglobflag <- liftIO $ getFlag ["old-glob"]
- let
- files2 = (if isglob && not oldglobflag then filter (not.hasdotdir)
else id) files
- where
- hasdotdir p = any isdotdir $ splitPath p
- where
- isdotdir c = "." `isPrefixOf` c && "/" `isSuffixOf` c
+ -- Throw an error if one of these files is among the grandparent files,
forming a cycle.
+ -- Though, ignore the immediate parent file for convenience. XXX
inconsistent - should it ignore all cyclic includes ?
+ -- We used to store the canonical paths, then switched to non-canonical
paths for more useful output,
+ -- which means for each include directive we must re-canonicalise
everything here; noticeable ? XXX
+ parentj <- get
+ let parentfiles = jincludefilestack parentj
+ cparentfiles <- liftIO $ mapM canonicalizePath parentfiles
+ let cparentf = take 1 parentfiles
+ files2 <- forM files $ \f -> do
+ cf <- liftIO $ canonicalizePath f
+ if
+ | [cf] == cparentf -> return cf -- current file - return
canonicalised, will be excluded later
+ | cf `elem` drop 1 cparentfiles -> customFailure $ parseErrorAt off
$ "This included file forms a cycle: " ++ f
+ | otherwise -> return f
-- Throw an error if no files were matched.
- when (null files2) $
- customFailure $ parseErrorAt off $ "No files were matched by glob
pattern: " ++ globpattern
+ when (null files2) $ customFailure $ parseErrorAt off $ "No files were
matched by: " ++ globpattern
- -- If a glob was used, exclude the current file, for convenience.
+ -- If the current file got included, ignore it (last, to avoid
triggering the error above).
let
files3 =
- dbg6 (parentf <> " include: matched files" <> if isglob then "
(excluding current file)" else "") $
- (if isglob then filter (/= parentf) else id) files2
+ dbg6 (parentf <> " include: matched files (excluding current file)")
$
+ filter (not.(`elem` cparentf)) files2
return files3
-- Parse the given included file (and any deeper includes, recursively) as
if it was inlined in the current (parent) file.
-- The offset of the start of the include directive in the parent file is
provided for error messages.
parseIncludedFile :: MonadIO m => InputOpts -> Int -> PrefixedFilePath ->
ErroringJournalParser m ()
- parseIncludedFile iopts1 eoff prefixedpath = do
+ parseIncludedFile iopts1 off prefixedpath = do
let (_mprefix,filepath) = splitReaderPrefix prefixedpath
- -- Throw an error if a cycle is detected
- parentj <- get
- let parentfilestack = jincludefilestack parentj
- when (dbg7 "parseIncludedFile: reading" filepath `elem` parentfilestack)
$
- customFailure $ parseErrorAt eoff $ "This included file forms a cycle:
" ++ filepath
-
-- Read the file's content, or throw an error
- childInput <- lift $ readFilePortably filepath `orRethrowIOError`
"failed to read a file"
+ childInput <- lift $ readFilePortably filepath & handleIOError off
"failed to read a file"
+ parentj <- get
let initChildj = newJournalWithParseStateFrom filepath parentj
-- Choose a reader based on the file path prefix or file extension,
@@ -491,22 +489,20 @@
,jincludefilestack = filepath : jincludefilestack j
}
--- Get the canonical path of the file referenced by this parse position.
--- Symbolic links will be dereferenced. This probably will always succeed
--- (since the parse file's path is probably always absolute).
+-- Get the absolute path of the file referenced by this parse position.
+-- (Symbolic links will not be dereferenced.)
+-- This probably will always succeed, since the parse file's path is probably
always absolute.
sourcePosFilePath :: (MonadIO m) => SourcePos -> m FilePath
-sourcePosFilePath = liftIO . canonicalizePath . sourceName
--- "canonicalizePath is a very big hammer. If you only need an absolute path,
makeAbsolute is sufficient"
--- but we only do this once per include directive, seems ok to leave it as is.
-
--- | Lift an IO action into the exception monad, rethrowing any IO
--- error with the given message prepended.
-orRethrowIOError :: MonadIO m => IO a -> String -> TextParser m a
-orRethrowIOError io msg = do
+sourcePosFilePath = liftIO . makeAbsolute . sourceName
+
+-- | Lift an IO action into the exception monad, converting any IO error
+-- to a parse error message at the given offset.
+handleIOError :: MonadIO m => Int -> String -> IO a -> TextParser m a
+handleIOError off msg io = do
eResult <- liftIO $ (Right <$> io) `C.catch` \(e::C.IOException) -> pure $
Left $ printf "%s:\n%s" msg (show e)
case eResult of
Right res -> pure res
- Left errMsg -> fail errMsg
+ Left errMsg -> setOffset off >> fail errMsg
-- Parse an account directive, adding its info to the journal's
-- list of account declarations.
@@ -1258,8 +1254,8 @@
assertParse ignoredpricecommoditydirectivep "N $\n"
,testGroup "includedirectivep" [
- testCase "include" $ assertParseErrorE (includedirectivep definputopts)
"include nosuchfile\n" "No files were matched by glob pattern: nosuchfile"
- ,testCase "glob" $ assertParseErrorE (includedirectivep definputopts)
"include nosuchfile*\n" "No files were matched by glob pattern: nosuchfile*"
+ testCase "include" $ assertParseErrorE (includedirectivep definputopts)
"include nosuchfile\n" "No files were matched by: nosuchfile"
+ ,testCase "glob" $ assertParseErrorE (includedirectivep definputopts)
"include nosuchfile*\n" "No files were matched by: nosuchfile*"
]
,testCase "marketpricedirectivep" $ assertParseEq marketpricedirectivep
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Read/RulesReader.hs
new/hledger-lib-1.51.1/Hledger/Read/RulesReader.hs
--- old/hledger-lib-1.50.3/Hledger/Read/RulesReader.hs 2025-11-18
23:54:26.000000000 +0100
+++ new/hledger-lib-1.51.1/Hledger/Read/RulesReader.hs 2025-12-08
22:03:33.000000000 +0100
@@ -235,7 +235,7 @@
(_, Just f, mc) -> do -- trace "file found" $
mencoding <- rulesEncoding rules
liftIO $ do
- raw <- openFileOrStdin f >>= readHandlePortably' mencoding
+ raw <- openFileOrStdin f >>= hGetContentsPortably mencoding
maybe (return raw) (\c -> runCommandAsFilter rulesfile (dbg0Msg
("running: "++c) c) raw) mc
-- no file pattern, but a data generating command
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Read.hs
new/hledger-lib-1.51.1/Hledger/Read.hs
--- old/hledger-lib-1.50.3/Hledger/Read.hs 2025-11-18 23:54:26.000000000
+0100
+++ new/hledger-lib-1.51.1/Hledger/Read.hs 2025-12-08 22:03:33.000000000
+0100
@@ -133,7 +133,7 @@
--- ** imports
import Control.Exception qualified as C
-import Control.Monad (unless, when, forM, (<=<))
+import Control.Monad (unless, when, forM, (>=>))
import "mtl" Control.Monad.Except (ExceptT(..), runExceptT, liftEither)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Default (def)
@@ -167,6 +167,7 @@
import Prelude hiding (getContents, writeFile)
import Hledger.Data.JournalChecks (journalStrictChecks)
import Text.Printf (printf)
+import Hledger.Data.Journal (journalNumberTransactions)
--- ** doctest setup
-- $setup
@@ -223,7 +224,7 @@
exists <- doesFileExist defaultfile
if exists then return defaultfile
-- else error' $ "LEDGER_FILE is unset and \"" <> defaultfile <> "\" was
not found"
- else error' $ "neither LEDGER_FILE nor \"" <> defaultfile <> "\" were
found"
+ else error' $ "neither LEDGER_FILE nor \"" <> defaultfile <> "\" was found"
else do
mf <- headMay <$> expandGlob "." ledgerfile `C.catch` (\(_::C.IOException)
-> return [])
case mf of
@@ -350,10 +351,12 @@
-- The implementation of readJournalFiles.
-- With --new, it also returns the latest transaction date(s) read in each file
-- (used by the import command).
+-- This also renumbers the transactions, ensuring their tindex values are
unique;
+-- that's also done elsewhere, but some code (accountTransactionsReport) needs
it done sooner.
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)
+ return (journalNumberTransactions $ maybe def sconcat $ nonEmpty js,
catMaybes lastdates)
-- | An easy version of 'readJournal' which assumes default options, and fails
in the IO monad.
readJournal' :: Handle -> IO Journal
@@ -361,7 +364,7 @@
-- | An even easier version of readJournal' which takes a 'Text' instead of a
'Handle'.
readJournal'' :: Text -> IO Journal
-readJournal'' = readJournal' <=< inputToHandle
+readJournal'' = textToHandle >=> readJournal'
-- | An easy version of 'readJournalFile' which assumes default options, and
fails
-- in the IO monad.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/Hledger/Utils/IO.hs
new/hledger-lib-1.51.1/Hledger/Utils/IO.hs
--- old/hledger-lib-1.50.3/Hledger/Utils/IO.hs 2025-11-18 23:54:26.000000000
+0100
+++ new/hledger-lib-1.51.1/Hledger/Utils/IO.hs 2025-12-08 22:03:33.000000000
+0100
@@ -46,10 +46,9 @@
readFileOrStdinPortably',
readFileStrictly,
readFilePortably,
- readHandlePortably,
- readHandlePortably',
+ hGetContentsPortably,
-- hereFileRelative,
- inputToHandle,
+ textToHandle,
-- * Command line parsing
progArgs,
@@ -154,7 +153,7 @@
import System.FilePath (isRelative, (</>))
import "Glob" System.FilePath.Glob (glob)
import System.Info (os)
-import System.IO (Handle, IOMode (..), hClose, hGetEncoding,
hIsTerminalDevice, hPutStr, hPutStrLn, hSetNewlineMode, hSetEncoding, openFile,
stderr, stdin, stdout, universalNewlineMode, utf8_bom)
+import System.IO (Handle, IOMode (..), hClose, hGetEncoding,
hIsTerminalDevice, hPutStr, hPutStrLn, hSetNewlineMode, hSetEncoding, openFile,
stderr, stdin, stdout, universalNewlineMode, utf8_bom, utf8)
import System.IO.Encoding qualified as Enc
import System.IO.Unsafe (unsafePerformIO)
import System.Process (CreateProcess(..), StdStream(CreatePipe),
createPipe, shell, waitForProcess, withCreateProcess)
@@ -417,6 +416,7 @@
-- | Like expandPath, but treats the expanded path as a glob, and returns
-- zero or more matched absolute file paths, alphabetically sorted.
-- Can raise an error.
+-- For a more elaborate glob expander, see 'findMatchedFiles' (used by the
include directive).
expandGlob :: FilePath -> FilePath -> IO [FilePath]
expandGlob curdir p = expandPath curdir p >>= glob <&> sort -- PARTIAL:
@@ -435,7 +435,7 @@
-- using the system locale's text encoding,
-- ignoring any utf8 BOM prefix (as seen in paypal's 2018 CSV, eg) if that
encoding is utf8.
readFilePortably :: FilePath -> IO T.Text
-readFilePortably f = openFile f ReadMode >>= readHandlePortably
+readFilePortably f = openFile f ReadMode >>= hGetContentsPortably Nothing
-- | Like readFilePortably, but read from standard input if the path is "-".
readFileOrStdinPortably :: String -> IO T.Text
@@ -443,7 +443,7 @@
-- | Like readFileOrStdinPortably, but take an optional converter.
readFileOrStdinPortably' :: Maybe DynEncoding -> String -> IO T.Text
-readFileOrStdinPortably' c f = openFileOrStdin f >>= readHandlePortably' c
+readFileOrStdinPortably' c f = openFileOrStdin f >>= hGetContentsPortably c
-- | Open a file for reading, using the standard System.IO.openFile.
-- This opens the handle in text mode, using the initial system locale's text
encoding.
@@ -451,32 +451,27 @@
openFileOrStdin "-" = return stdin
openFileOrStdin f' = openFile f' ReadMode
--- readHandlePortably' with no text encoding specified.
-readHandlePortably :: Handle -> IO T.Text
-readHandlePortably = readHandlePortably' Nothing
-
--- | Read text from a handle with a specified encoding, using the encoding
package.
--- Or if no encoding is specified, it uses the handle's current encoding,
--- after first changing it to UTF-8BOM if it was UTF-8, to allow a Byte Order
Mark at the start.
+-- | Read text from a handle, perhaps using a specified encoding from the
encoding package.
+-- Or if no encoding is specified, using the handle's current encoding,
+-- changing it to UTF-8BOM if it was UTF-8, to ignore any Byte Order Mark at
the start.
-- Also it converts Windows line endings to newlines.
-- If decoding fails, this throws an IOException (or possibly a
UnicodeException or something else from the encoding package).
-readHandlePortably' :: Maybe DynEncoding -> Handle -> IO T.Text
-readHandlePortably' Nothing h = do
+hGetContentsPortably :: Maybe DynEncoding -> Handle -> IO T.Text
+hGetContentsPortably Nothing h = do
hSetNewlineMode h universalNewlineMode
menc <- hGetEncoding h
when (fmap show menc == Just "UTF-8") $ hSetEncoding h utf8_bom
T.hGetContents h
-readHandlePortably' (Just e) h =
+hGetContentsPortably (Just e) h =
-- convert newlines manually, because Enc.hGetContents uses bytestring's
hGetContents
T.replace "\r\n" "\n" . T.pack <$> let ?enc = e in Enc.hGetContents h
--- | Create a handle from which the given text can be read.
--- Its encoding will be UTF-8BOM.
-inputToHandle :: T.Text -> IO Handle
-inputToHandle t = do
+-- | Create a handle from which the given text can be read. Its encoding will
be UTF-8.
+textToHandle :: T.Text -> IO Handle
+textToHandle t = do
(r, w) <- createPipe
- hSetEncoding r utf8_bom
- hSetEncoding w utf8_bom
+ hSetEncoding r utf8
+ hSetEncoding w utf8
-- use a separate thread so that we don't deadlock if we can't write all of
the text at once
forkIO $ T.hPutStr w t >> hClose w
return r
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hledger-lib-1.50.3/hledger-lib.cabal
new/hledger-lib-1.51.1/hledger-lib.cabal
--- old/hledger-lib-1.50.3/hledger-lib.cabal 2025-11-18 23:54:26.000000000
+0100
+++ new/hledger-lib-1.51.1/hledger-lib.cabal 2025-12-08 22:04:20.000000000
+0100
@@ -5,7 +5,7 @@
-- see: https://github.com/sol/hpack
name: hledger-lib
-version: 1.50.3
+version: 1.51.1
synopsis: A library providing the core functionality of hledger
description: This library contains hledger's core functionality.
It is used by most hledger* packages so that they support the
same
@@ -46,7 +46,7 @@
location: https://github.com/simonmichael/hledger
flag debug
- description: Build with GHC 9.10+'s stack traces enabled
+ description: Build with GHC 9.10+ stack traces enabled
manual: True
default: False
@@ -57,9 +57,11 @@
Hledger.Data.Account
Hledger.Data.AccountName
Hledger.Data.Amount
+ Hledger.Data.BalanceData
Hledger.Data.Balancing
Hledger.Data.Currency
Hledger.Data.Dates
+ Hledger.Data.DayPartition
Hledger.Data.Errors
Hledger.Data.Journal
Hledger.Data.JournalChecks
@@ -68,10 +70,11 @@
Hledger.Data.Json
Hledger.Data.Ledger
Hledger.Data.Period
+ Hledger.Data.PeriodData
Hledger.Data.PeriodicTransaction
- Hledger.Data.StringFormat
Hledger.Data.Posting
Hledger.Data.RawOptions
+ Hledger.Data.StringFormat
Hledger.Data.Timeclock
Hledger.Data.Transaction
Hledger.Data.TransactionModifier
@@ -84,26 +87,17 @@
Hledger.Read.InputOptions
Hledger.Read.JournalReader
Hledger.Read.RulesReader
- Hledger.Read.TimedotReader
Hledger.Read.TimeclockReader
- Hledger.Write.Beancount
- Hledger.Write.Csv
- Hledger.Write.Ods
- Hledger.Write.Html
- Hledger.Write.Html.Attribute
- Hledger.Write.Html.Blaze
- Hledger.Write.Html.Lucid
- Hledger.Write.Html.HtmlCommon
- Hledger.Write.Spreadsheet
+ Hledger.Read.TimedotReader
Hledger.Reports
- Hledger.Reports.ReportOptions
- Hledger.Reports.ReportTypes
Hledger.Reports.AccountTransactionsReport
Hledger.Reports.BalanceReport
Hledger.Reports.BudgetReport
Hledger.Reports.EntriesReport
Hledger.Reports.MultiBalanceReport
Hledger.Reports.PostingsReport
+ Hledger.Reports.ReportOptions
+ Hledger.Reports.ReportTypes
Hledger.Utils
Hledger.Utils.Debug
Hledger.Utils.IO
@@ -112,18 +106,25 @@
Hledger.Utils.String
Hledger.Utils.Test
Hledger.Utils.Text
+ Hledger.Write.Beancount
+ Hledger.Write.Csv
+ Hledger.Write.Html
+ Hledger.Write.Html.Attribute
+ Hledger.Write.Html.Blaze
+ Hledger.Write.Html.HtmlCommon
+ Hledger.Write.Html.Lucid
+ Hledger.Write.Ods
+ Hledger.Write.Spreadsheet
Text.Tabular.AsciiWide
Text.WideString
other-modules:
- Hledger.Data.BalanceData
- Hledger.Data.DayPartition
- Hledger.Data.PeriodData
Paths_hledger_lib
autogen-modules:
Paths_hledger_lib
hs-source-dirs:
./
ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures
-Wno-orphans -Wno-type-defaults -Wno-unused-do-bind
+ cpp-options: -DVERSION="1.51.1"
build-depends:
Decimal >=0.5.1
, Glob >=0.9
@@ -183,6 +184,7 @@
hs-source-dirs:
test
ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures
-Wno-orphans -Wno-type-defaults -Wno-unused-do-bind
+ cpp-options: -DVERSION="1.51.1"
build-depends:
Decimal >=0.5.1
, Glob >=0.7
@@ -236,8 +238,6 @@
default-language: GHC2021
if (flag(debug))
cpp-options: -DDEBUG
- if impl(ghc >= 9.0) && impl(ghc < 9.2)
- buildable: False
test-suite unittest
type: exitcode-stdio-1.0
@@ -245,6 +245,7 @@
hs-source-dirs:
test
ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures
-Wno-orphans -Wno-type-defaults -Wno-unused-do-bind
+ cpp-options: -DVERSION="1.51.1"
build-depends:
Decimal >=0.5.1
, Glob >=0.9