imp: -f now errors if given a glob matching no files, like LEDGER_FILE
Previously LEDGER_FILE=foo hledger add did, but hledger -f foo add didn't.
Now they both consistently will error if given a glob
(a path contining [, {, *, or ?) that matches nothing,
rather than auto-creating a file with a glob-like name.
Hledger.Utils.IO:
expandPathOrGlob
This commit is contained in:
parent
88f6c16dd5
commit
e7d7c49562
@ -150,7 +150,7 @@ import Data.Text (Text)
|
|||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Data.Text.IO qualified as T
|
import Data.Text.IO qualified as T
|
||||||
import Data.Time (Day)
|
import Data.Time (Day)
|
||||||
import Safe (headDef, headMay)
|
import Safe (headDef)
|
||||||
import System.Directory (doesFileExist)
|
import System.Directory (doesFileExist)
|
||||||
import System.Environment (getEnv)
|
import System.Environment (getEnv)
|
||||||
import System.FilePath ((<.>), (</>), splitDirectories, splitFileName, takeFileName)
|
import System.FilePath ((<.>), (</>), splitDirectories, splitFileName, takeFileName)
|
||||||
@ -223,18 +223,8 @@ defaultJournalPath = do
|
|||||||
homedir <- fromMaybe "" <$> getHomeSafe
|
homedir <- fromMaybe "" <$> getHomeSafe
|
||||||
let defaultfile = homedir </> journalDefaultFilename
|
let defaultfile = homedir </> journalDefaultFilename
|
||||||
return defaultfile
|
return defaultfile
|
||||||
else do
|
else
|
||||||
-- If it contains glob metacharacters, expand the pattern and error if no matches.
|
expandPathOrGlob "." p
|
||||||
-- Otherwise just expand ~ and return the path, even if the file doesn't exist yet.
|
|
||||||
let hasGlobChars = any (`elem` p) ("*?[{" :: [Char])
|
|
||||||
if hasGlobChars
|
|
||||||
then do
|
|
||||||
mf <- headMay <$> expandGlob "." p `C.catch` (\(_::C.IOException) -> return [])
|
|
||||||
case mf of
|
|
||||||
Just f -> return f
|
|
||||||
Nothing -> error' $ "LEDGER_FILE glob pattern \"" <> p <> "\" matched no files"
|
|
||||||
else
|
|
||||||
expandPath "." p
|
|
||||||
|
|
||||||
-- | Like defaultJournalPath, but return an error message instead of raising an error.
|
-- | Like defaultJournalPath, but return an error message instead of raising an error.
|
||||||
defaultJournalPathSafely :: IO (Either String String)
|
defaultJournalPathSafely :: IO (Either String String)
|
||||||
|
|||||||
@ -40,6 +40,7 @@ module Hledger.Utils.IO (
|
|||||||
expandHomePath,
|
expandHomePath,
|
||||||
expandPath,
|
expandPath,
|
||||||
expandGlob,
|
expandGlob,
|
||||||
|
expandPathOrGlob,
|
||||||
sortByModTime,
|
sortByModTime,
|
||||||
openFileOrStdin,
|
openFileOrStdin,
|
||||||
readFileOrStdinPortably,
|
readFileOrStdinPortably,
|
||||||
@ -423,6 +424,26 @@ expandPath curdir p = (if isRelative p then (curdir </>) else id) <$> expandHome
|
|||||||
expandGlob :: FilePath -> FilePath -> IO [FilePath]
|
expandGlob :: FilePath -> FilePath -> IO [FilePath]
|
||||||
expandGlob curdir p = expandPath curdir p >>= glob <&> sort -- PARTIAL:
|
expandGlob curdir p = expandPath curdir p >>= glob <&> sort -- PARTIAL:
|
||||||
|
|
||||||
|
-- | Like expandPath, but if the path contains glob metacharacters (* ? [ {),
|
||||||
|
-- treats it as a glob pattern and expands it, returning the first match.
|
||||||
|
-- Raises an error if the glob pattern matches no files.
|
||||||
|
-- If the path contains no glob metacharacters, just expands ~ and returns the path,
|
||||||
|
-- even if the file doesn't exist yet.
|
||||||
|
-- This is useful for options like -f and LEDGER_FILE that should:
|
||||||
|
-- - accept non-existent files (for commands like add/import that create them)
|
||||||
|
-- - expand glob patterns and error if they don't match anything
|
||||||
|
expandPathOrGlob :: FilePath -> FilePath -> IO FilePath
|
||||||
|
expandPathOrGlob curdir p = do
|
||||||
|
let hasGlobChars = any (`elem` p) ("*?[{" :: [Char])
|
||||||
|
if hasGlobChars
|
||||||
|
then do
|
||||||
|
matches <- expandGlob curdir p `catch` (\(_::IOException) -> return [])
|
||||||
|
case headMay matches of
|
||||||
|
Just f -> return f
|
||||||
|
Nothing -> error' $ "glob pattern \"" <> p <> "\" matched no files"
|
||||||
|
else
|
||||||
|
expandPath curdir p
|
||||||
|
|
||||||
-- | Given a list of existing file paths, sort them by modification time (from oldest to newest).
|
-- | Given a list of existing file paths, sort them by modification time (from oldest to newest).
|
||||||
sortByModTime :: [FilePath] -> IO [FilePath]
|
sortByModTime :: [FilePath] -> IO [FilePath]
|
||||||
sortByModTime fs = do
|
sortByModTime fs = do
|
||||||
|
|||||||
@ -755,7 +755,7 @@ journalFilePathFromOptsNoDefault opts = do
|
|||||||
expandPathPreservingPrefix :: FilePath -> PrefixedFilePath -> IO PrefixedFilePath
|
expandPathPreservingPrefix :: FilePath -> PrefixedFilePath -> IO PrefixedFilePath
|
||||||
expandPathPreservingPrefix d prefixedf = do
|
expandPathPreservingPrefix d prefixedf = do
|
||||||
let (p,f) = splitReaderPrefix prefixedf
|
let (p,f) = splitReaderPrefix prefixedf
|
||||||
f' <- expandPath d f
|
f' <- expandPathOrGlob d f
|
||||||
return $ case p of
|
return $ case p of
|
||||||
Just p' -> (show p') ++ ":" ++ f'
|
Just p' -> (show p') ++ ":" ++ f'
|
||||||
Nothing -> f'
|
Nothing -> f'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user