Skip to content

Commit 5a36362

Browse files
committed
imp:journal: use a symlink's target's directory for relative include paths
When reading a symbolically-linked journal file, relative paths in include directives are now evaluated relative to the directory of the real linked file, not the directory of the symlink. This also seems to fix an obscure case where stats did not report absolute included file paths in certain circumstances (stdin, maybe no terminal..)
1 parent f6a5092 commit 5a36362

File tree

2 files changed

+16
-12
lines changed

2 files changed

+16
-12
lines changed

hledger-lib/Hledger/Read/JournalReader.hs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ import qualified Hledger.Read.CsvReader as CsvReader (reader)
104104
import qualified Hledger.Read.RulesReader as RulesReader (reader)
105105
import qualified Hledger.Read.TimeclockReader as TimeclockReader (reader)
106106
import qualified Hledger.Read.TimedotReader as TimedotReader (reader)
107+
import System.Directory (canonicalizePath)
107108

108109
--- ** doctest setup
109110
-- $setup
@@ -304,22 +305,24 @@ includedirectivep = do
304305
where
305306
getFilePaths
306307
:: MonadIO m => Int -> SourcePos -> FilePath -> JournalParser m [FilePath]
307-
getFilePaths parseroff parserpos filename = do
308-
let curdir = takeDirectory (sourceName parserpos)
309-
filename' <- lift $ expandHomePath filename
310-
`orRethrowIOError` (show parserpos ++ " locating " ++ filename)
311-
-- Compiling filename as a glob pattern works even if it is a literal
312-
fileglob <- case tryCompileWith compDefault{errorRecovery=False} filename' of
308+
getFilePaths parseroff parserpos fileglobpattern = do
309+
-- Expand a ~ at the start of the glob pattern, if any.
310+
fileglobpattern' <- lift $ expandHomePath fileglobpattern
311+
`orRethrowIOError` (show parserpos ++ " locating " ++ fileglobpattern)
312+
-- Compile the glob pattern.
313+
fileglob <- case tryCompileWith compDefault{errorRecovery=False} fileglobpattern' of
313314
Right x -> pure x
314-
Left e -> customFailure $
315-
parseErrorAt parseroff $ "Invalid glob pattern: " ++ e
316-
-- Get all matching files in the current working directory, sorting in
317-
-- lexicographic order to simulate the output of 'ls'.
315+
Left e -> customFailure $ parseErrorAt parseroff $ "Invalid glob pattern: " ++ e
316+
-- Get the directory of the including file. This will be used to resolve relative paths.
317+
let parentfilepath = sourceName parserpos
318+
realparentfilepath <- liftIO $ canonicalizePath parentfilepath -- Follow a symlink. If the path is already absolute, the operation never fails.
319+
let curdir = takeDirectory realparentfilepath
320+
-- Find all matched files, in lexicographic order mimicking the output of 'ls'.
318321
filepaths <- liftIO $ sort <$> globDir1 fileglob curdir
319322
if (not . null) filepaths
320323
then pure filepaths
321324
else customFailure $ parseErrorAt parseroff $
322-
"No existing files match pattern: " ++ filename
325+
"No existing files match pattern: " ++ fileglobpattern
323326

324327
parseChild :: MonadIO m => SourcePos -> PrefixedFilePath -> ErroringJournalParser m ()
325328
parseChild parentpos prefixedpath = do

hledger/test/stats.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ $ hledger -f- stats
88
include a.j
99
include b.j
1010
$ touch a.j b.j; hledger -f- stats; rm -f a.j b.j
11-
> /Included files *: *\.\/a\.j/
11+
> /Included files.*\/a\.j
12+
.*\/b\.j/

0 commit comments

Comments
 (0)