auto-create missing journal files rather than giving an error

This commit is contained in:
Simon Michael 2010-07-13 19:36:43 +00:00
parent 50aeb272b0
commit eefb04abfe
3 changed files with 32 additions and 15 deletions

View File

@ -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

View File

@ -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)

View File

@ -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.