web: set up journal for yesod devel, store it in App (fixes #101)

The web app's journal state is now kept in the yesod App as an IORef,
instead of using io-storage.
yesod devel now works; it uses the journal file specified by
$LEDGER_FILE, or ~/.hledger.journal.

web: update journal state handling, fix yesod devel - WIP
This commit is contained in:
Simon Michael 2013-04-09 09:33:19 -07:00
parent c510f11424
commit 0df4a235af
6 changed files with 31 additions and 34 deletions

View File

@ -5,6 +5,7 @@ module Application
, makeFoundation
) where
import Data.IORef
import Import
import Yesod.Default.Config
import Yesod.Default.Main
@ -21,6 +22,10 @@ import Handler.JournalEntriesR
import Handler.RegisterR
import Hledger.Web.Options (defwebopts)
import Hledger.Data (Journal, nulljournal)
import Hledger.Read (readJournalFile)
import Hledger.Utils (error')
import Hledger.Cli.Options (defcliopts, journalFilePathFromOpts)
-- This line actually creates our YesodDispatch instance. It is the second half
-- of the call to mkYesodData which occurs in Foundation.hs. Please see the
@ -31,9 +36,10 @@ mkYesodDispatch "App" resourcesApp
-- performs initialization and creates a WAI application. This is also the
-- place to put your migrate statements to have automatic database
-- migrations handled by Yesod.
makeApplication :: AppConfig DefaultEnv Extra -> IO Application
makeApplication conf = do
makeApplication :: Journal -> AppConfig DefaultEnv Extra -> IO Application
makeApplication j conf = do
foundation <- makeFoundation conf
writeIORef (appJournal foundation) j
app <- toWaiAppPlain foundation
return $ logWare app
where
@ -44,13 +50,16 @@ makeFoundation :: AppConfig DefaultEnv Extra -> IO App
makeFoundation conf = do
manager <- newManager def
s <- staticSite
return $ App conf s manager
defwebopts
jref <- newIORef nulljournal
return $ App conf s manager defwebopts jref
-- for yesod devel
-- uses the journal specified by the LEDGER_FILE env var, or ~/.hledger.journal
getApplicationDev :: IO (Int, Application)
getApplicationDev =
defaultDevelApp loader makeApplication
getApplicationDev = do
f <- journalFilePathFromOpts defcliopts
j <- either error' id `fmap` readJournalFile Nothing Nothing f
defaultDevelApp loader (makeApplication j)
where
loader = loadConfig (configSettings Development)
{ csParseExtra = parseExtra

View File

@ -7,6 +7,7 @@ See a default Yesod app's comments for more details of each part.
module Foundation where
import Prelude
import Data.IORef
import Yesod
import Yesod.Static
import Yesod.Default.Config
@ -26,6 +27,7 @@ import Web.ClientSession (getKey)
import Text.Hamlet (hamletFile)
import Hledger.Web.Options
import Hledger.Data.Types
-- import Hledger.Web.Settings
-- import Hledger.Web.Settings.StaticFiles
@ -40,6 +42,7 @@ data App = App
, httpManager :: Manager
--
, appOpts :: WebOpts
, appJournal :: IORef Journal
}
-- Set up i18n messages. See the message folder.

View File

@ -5,12 +5,13 @@ module Handler.Utils where
import Prelude
import Control.Applicative ((<$>))
import Control.Monad.IO.Class (liftIO)
import Data.IORef
import Data.Maybe
import Data.Text(pack,unpack)
import Data.Time.Calendar
import Data.Time.Clock
import Data.Time.Format
import System.IO.Storage (putValue, getValue)
-- import System.IO.Storage (putValue, getValue)
import System.Locale (defaultTimeLocale)
#if BLAZE_HTML_0_5
import Text.Blaze.Html (toHtml)
@ -70,7 +71,7 @@ getViewData :: Handler ViewData
getViewData = do
app <- getYesod
let opts@WebOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} = appOpts app
(j, err) <- getCurrentJournal $ copts{reportopts_=ropts{no_elide_=True}}
(j, err) <- getCurrentJournal app copts{reportopts_=ropts{no_elide_=True}}
msg <- getMessageOr err
Just here <- getCurrentRoute
today <- liftIO getCurrentDay
@ -88,14 +89,15 @@ getViewData = do
-- | Update our copy of the journal if the file changed. If there is an
-- error while reloading, keep the old one and return the error, and set a
-- ui message.
getCurrentJournal :: CliOpts -> Handler (Journal, Maybe String)
getCurrentJournal opts = do
j <- liftIO $ fromJust `fmap` getValue "hledger" "journal"
getCurrentJournal :: App -> CliOpts -> Handler (Journal, Maybe String)
getCurrentJournal app opts = do
-- XXX put this inside atomicModifyIORef' for thread safety
j <- liftIO $ readIORef $ appJournal app
(jE, changed) <- liftIO $ journalReloadIfChanged opts j
if not changed
then return (j,Nothing)
else case jE of
Right j' -> do liftIO $ putValue "hledger" "journal" j'
Right j' -> do liftIO $ writeIORef (appJournal app) j'
return (j',Nothing)
Left e -> do setMessage $ "error while reading" {- ++ ": " ++ e-}
return (j, Just e)

View File

@ -22,7 +22,7 @@ import Prelude hiding (putStrLn)
import Control.Monad (when)
import Data.Text (pack)
import System.Exit (exitSuccess)
import System.IO.Storage (withStore, putValue)
-- import System.IO.Storage (withStore, putValue)
import Text.Printf
import Hledger
@ -68,17 +68,7 @@ web opts j = do
server :: String -> Int -> WebOpts -> Journal -> IO ()
server baseurl port opts j = do
_ <- printf "Starting http server on port %d with base url %s\n" port baseurl
-- let a = App{getStatic=static staticdir
-- ,appRoot=pack baseurl
-- ,appOpts=opts
-- ,appArgs=patterns_ $ reportopts_ $ cliopts_ opts
-- ,appJournal=j
-- }
withStore "hledger" $ do
putValue "hledger" "journal" j
-- defaultMain (fromArgs parseExtra) makeApplication
app <- makeApplication (AppConfig {
app <- makeApplication j (AppConfig {
appEnv = Development
, appPort = port_ opts
, appRoot = pack baseurl

View File

@ -1,2 +0,0 @@
import Distribution.Simple
main = defaultMain

View File

@ -6,17 +6,12 @@ import Control.Concurrent (forkIO)
import System.Directory (doesFileExist, removeFile)
import System.Exit (exitSuccess)
import Control.Concurrent (threadDelay)
import System.IO.Storage (withStore, putValue)
import Hledger (readJournalFile)
main :: IO ()
main = do
putStrLn "Starting devel application"
(port, app) <- getApplicationDev
forkIO $
withStore "hledger" $ do
readJournalFile Nothing Nothing "dev.journal" >>= putValue "hledger" "journal"
runSettings defaultSettings
{ settingsPort = port
} app