From eefb04abfec96b8b964f5fd36c0f7a8e702bb4dc Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Tue, 13 Jul 2010 19:36:43 +0000 Subject: [PATCH] auto-create missing journal files rather than giving an error --- Hledger/Cli/Commands/Add.hs | 3 ++- Hledger/Cli/Utils.hs | 18 +++++++----------- hledger-lib/Hledger/Read.hs | 26 +++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Hledger/Cli/Commands/Add.hs b/Hledger/Cli/Commands/Add.hs index c4b9a3788..9cab2cded 100644 --- a/Hledger/Cli/Commands/Add.hs +++ b/Hledger/Cli/Commands/Add.hs @@ -28,13 +28,14 @@ import qualified Data.Foldable as Foldable (find) -- command has no effect. add :: [Opt] -> [String] -> Journal -> IO () add opts args j - | filepath j == "-" = return () + | f == "-" = return () | otherwise = do hPutStrLn stderr $ "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." today <- getCurrentDay 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, -- validating, displaying and appending them to the journal file, until diff --git a/Hledger/Cli/Utils.hs b/Hledger/Cli/Utils.hs index 84b60ba82..486b5dc7a 100644 --- a/Hledger/Cli/Utils.hs +++ b/Hledger/Cli/Utils.hs @@ -23,7 +23,7 @@ import Hledger.Data import Hledger.Read import Hledger.Cli.Options (Opt(..),journalFilePathFromOpts) -- ,optsToFilterSpec) import Safe (readMay) -import System.Directory (doesFileExist, getModificationTime, getDirectoryContents, copyFile) +import System.Directory (getModificationTime, getDirectoryContents, copyFile) import System.Exit import System.FilePath ((), splitFileName, takeDirectory) 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 -- it, or throw an error. 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 -- it's stdin, or it doesn't exist and we are adding. We read it strictly -- to let the add command work. - f <- journalFilePathFromOpts opts - fileexists <- doesFileExist f - let creating = not fileexists && cmdname == "add" + journalFilePathFromOpts opts >>= readJournalFile Nothing >>= either error runcmd + where costify = (if CostBasis `elem` opts then journalConvertAmountsToCost else id) 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. readJournalWithOpts :: [Opt] -> String -> IO Journal readJournalWithOpts opts s = do - j <- readJournal Nothing s >>= either error return - let cost = CostBasis `elem` opts - return $ (if cost then journalConvertAmountsToCost else id) j + j <- readJournal Nothing s >>= either error return + 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. journalReload :: Journal -> IO (Either String Journal) diff --git a/hledger-lib/Hledger/Read.hs b/hledger-lib/Hledger/Read.hs index a68fc0c77..cfbfc2a00 100644 --- a/hledger-lib/Hledger/Read.hs +++ b/hledger-lib/Hledger/Read.hs @@ -16,16 +16,18 @@ module Hledger.Read ( myTimelog, ) where +import Hledger.Data.Dates (getCurrentDay) import Hledger.Data.Types (Journal(..)) import Hledger.Data.Utils import Hledger.Read.Common import Hledger.Read.Journal as Journal import Hledger.Read.Timelog as Timelog +import Hledger.Cli.Version (version) import Control.Monad.Error import Data.Either (partitionEithers) import Safe (headDef) -import System.Directory (getHomeDirectory) +import System.Directory (doesFileExist, getHomeDirectory) import System.Environment (getEnv) import System.FilePath (()) import System.IO (IOMode(..), withFile, hGetContents, stderr) @@ -82,10 +84,28 @@ journalFromPathAndString format fp s = do fmt fs = intercalate ", " (init fs) ++ " or " ++ last fs ++ " " -- | 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 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 -- trying all known formats, or give an error string.