auto-create missing journal files rather than giving an error
This commit is contained in:
parent
50aeb272b0
commit
eefb04abfe
@ -28,13 +28,14 @@ import qualified Data.Foldable as Foldable (find)
|
|||||||
-- command has no effect.
|
-- command has no effect.
|
||||||
add :: [Opt] -> [String] -> Journal -> IO ()
|
add :: [Opt] -> [String] -> Journal -> IO ()
|
||||||
add opts args j
|
add opts args j
|
||||||
| filepath j == "-" = return ()
|
| f == "-" = return ()
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
hPutStrLn stderr $
|
hPutStrLn stderr $
|
||||||
"Enter one or more transactions, which will be added to your journal file.\n"
|
"Enter one or more transactions, which will be added to your journal file.\n"
|
||||||
++"To complete a transaction, enter . as account name. To quit, press control-c."
|
++"To complete a transaction, enter . as account name. To quit, press control-c."
|
||||||
today <- getCurrentDay
|
today <- getCurrentDay
|
||||||
getAndAddTransactions j opts args today `catch` (\e -> unless (isEOFError e) $ ioError e)
|
getAndAddTransactions j opts args today `catch` (\e -> unless (isEOFError e) $ ioError e)
|
||||||
|
where f = filepath j
|
||||||
|
|
||||||
-- | Read a number of transactions from the command line, prompting,
|
-- | Read a number of transactions from the command line, prompting,
|
||||||
-- validating, displaying and appending them to the journal file, until
|
-- validating, displaying and appending them to the journal file, until
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import Hledger.Data
|
|||||||
import Hledger.Read
|
import Hledger.Read
|
||||||
import Hledger.Cli.Options (Opt(..),journalFilePathFromOpts) -- ,optsToFilterSpec)
|
import Hledger.Cli.Options (Opt(..),journalFilePathFromOpts) -- ,optsToFilterSpec)
|
||||||
import Safe (readMay)
|
import Safe (readMay)
|
||||||
import System.Directory (doesFileExist, getModificationTime, getDirectoryContents, copyFile)
|
import System.Directory (getModificationTime, getDirectoryContents, copyFile)
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.FilePath ((</>), splitFileName, takeDirectory)
|
import System.FilePath ((</>), splitFileName, takeDirectory)
|
||||||
import System.Info (os)
|
import System.Info (os)
|
||||||
@ -34,25 +34,21 @@ import System.Time (ClockTime, getClockTime, diffClockTimes, TimeDiff(TimeDiff))
|
|||||||
-- | Parse the user's specified journal file and run a hledger command on
|
-- | Parse the user's specified journal file and run a hledger command on
|
||||||
-- it, or throw an error.
|
-- it, or throw an error.
|
||||||
withJournalDo :: [Opt] -> [String] -> String -> ([Opt] -> [String] -> Journal -> IO ()) -> IO ()
|
withJournalDo :: [Opt] -> [String] -> String -> ([Opt] -> [String] -> Journal -> IO ()) -> IO ()
|
||||||
withJournalDo opts args cmdname cmd = do
|
withJournalDo opts args _ cmd = do
|
||||||
-- We kludgily read the file before parsing to grab the full text, unless
|
-- We kludgily read the file before parsing to grab the full text, unless
|
||||||
-- it's stdin, or it doesn't exist and we are adding. We read it strictly
|
-- it's stdin, or it doesn't exist and we are adding. We read it strictly
|
||||||
-- to let the add command work.
|
-- to let the add command work.
|
||||||
f <- journalFilePathFromOpts opts
|
journalFilePathFromOpts opts >>= readJournalFile Nothing >>= either error runcmd
|
||||||
fileexists <- doesFileExist f
|
where
|
||||||
let creating = not fileexists && cmdname == "add"
|
|
||||||
costify = (if CostBasis `elem` opts then journalConvertAmountsToCost else id)
|
costify = (if CostBasis `elem` opts then journalConvertAmountsToCost else id)
|
||||||
runcmd = cmd opts args . costify
|
runcmd = cmd opts args . costify
|
||||||
if creating
|
|
||||||
then runcmd nulljournal
|
|
||||||
else readJournalFile Nothing f >>= either error runcmd
|
|
||||||
|
|
||||||
-- | Get a journal from the given string and options, or throw an error.
|
-- | Get a journal from the given string and options, or throw an error.
|
||||||
readJournalWithOpts :: [Opt] -> String -> IO Journal
|
readJournalWithOpts :: [Opt] -> String -> IO Journal
|
||||||
readJournalWithOpts opts s = do
|
readJournalWithOpts opts s = do
|
||||||
j <- readJournal Nothing s >>= either error return
|
j <- readJournal Nothing s >>= either error return
|
||||||
let cost = CostBasis `elem` opts
|
|
||||||
return $ (if cost then journalConvertAmountsToCost else id) j
|
return $ (if cost then journalConvertAmountsToCost else id) j
|
||||||
|
where cost = CostBasis `elem` opts
|
||||||
|
|
||||||
-- | Re-read a journal from its data file, or return an error string.
|
-- | Re-read a journal from its data file, or return an error string.
|
||||||
journalReload :: Journal -> IO (Either String Journal)
|
journalReload :: Journal -> IO (Either String Journal)
|
||||||
|
|||||||
@ -16,16 +16,18 @@ module Hledger.Read (
|
|||||||
myTimelog,
|
myTimelog,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
import Hledger.Data.Dates (getCurrentDay)
|
||||||
import Hledger.Data.Types (Journal(..))
|
import Hledger.Data.Types (Journal(..))
|
||||||
import Hledger.Data.Utils
|
import Hledger.Data.Utils
|
||||||
import Hledger.Read.Common
|
import Hledger.Read.Common
|
||||||
import Hledger.Read.Journal as Journal
|
import Hledger.Read.Journal as Journal
|
||||||
import Hledger.Read.Timelog as Timelog
|
import Hledger.Read.Timelog as Timelog
|
||||||
|
import Hledger.Cli.Version (version)
|
||||||
|
|
||||||
import Control.Monad.Error
|
import Control.Monad.Error
|
||||||
import Data.Either (partitionEithers)
|
import Data.Either (partitionEithers)
|
||||||
import Safe (headDef)
|
import Safe (headDef)
|
||||||
import System.Directory (getHomeDirectory)
|
import System.Directory (doesFileExist, getHomeDirectory)
|
||||||
import System.Environment (getEnv)
|
import System.Environment (getEnv)
|
||||||
import System.FilePath ((</>))
|
import System.FilePath ((</>))
|
||||||
import System.IO (IOMode(..), withFile, hGetContents, stderr)
|
import System.IO (IOMode(..), withFile, hGetContents, stderr)
|
||||||
@ -82,10 +84,28 @@ journalFromPathAndString format fp s = do
|
|||||||
fmt fs = intercalate ", " (init fs) ++ " or " ++ last fs ++ " "
|
fmt fs = intercalate ", " (init fs) ++ " or " ++ last fs ++ " "
|
||||||
|
|
||||||
-- | Read a journal from this file, using the specified data format or
|
-- | Read a journal from this file, using the specified data format or
|
||||||
-- trying all known formats, or give an error string.
|
-- trying all known formats, or give an error string; also create the file
|
||||||
|
-- if it doesn't exist.
|
||||||
readJournalFile :: Maybe String -> FilePath -> IO (Either String Journal)
|
readJournalFile :: Maybe String -> FilePath -> IO (Either String Journal)
|
||||||
readJournalFile format "-" = getContents >>= journalFromPathAndString format "(stdin)"
|
readJournalFile format "-" = getContents >>= journalFromPathAndString format "(stdin)"
|
||||||
readJournalFile format f = withFile f ReadMode $ \h -> hGetContents h >>= journalFromPathAndString format f
|
readJournalFile format f = do
|
||||||
|
ensureJournalFile f
|
||||||
|
withFile f ReadMode $ \h -> hGetContents h >>= journalFromPathAndString format f
|
||||||
|
|
||||||
|
-- | Ensure there is a journal at the given file path, creating an empty one if needed.
|
||||||
|
ensureJournalFile :: FilePath -> IO ()
|
||||||
|
ensureJournalFile f = do
|
||||||
|
exists <- doesFileExist f
|
||||||
|
when (not exists) $ do
|
||||||
|
printf "No journal file at %s, creating...\n" f
|
||||||
|
printf "Edit this file or use hledger add or hledger web to add transactions.\n"
|
||||||
|
emptyJournal >>= writeFile f
|
||||||
|
|
||||||
|
-- | Give the content for a new auto-created journal file.
|
||||||
|
emptyJournal :: IO String
|
||||||
|
emptyJournal = do
|
||||||
|
d <- getCurrentDay
|
||||||
|
return $ printf "; journal created by hledger %s on %s\n; see http://hledger.org/MANUAL.html#file-format\n\n" version (show d)
|
||||||
|
|
||||||
-- | Read a Journal from this string, using the specified data format or
|
-- | Read a Journal from this string, using the specified data format or
|
||||||
-- trying all known formats, or give an error string.
|
-- trying all known formats, or give an error string.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user