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:
		
							parent
							
								
									c510f11424
								
							
						
					
					
						commit
						0df4a235af
					
				| @ -5,6 +5,7 @@ module Application | |||||||
|     , makeFoundation |     , makeFoundation | ||||||
|     ) where |     ) where | ||||||
| 
 | 
 | ||||||
|  | import Data.IORef | ||||||
| import Import | import Import | ||||||
| import Yesod.Default.Config | import Yesod.Default.Config | ||||||
| import Yesod.Default.Main | import Yesod.Default.Main | ||||||
| @ -21,6 +22,10 @@ import Handler.JournalEntriesR | |||||||
| import Handler.RegisterR | import Handler.RegisterR | ||||||
| 
 | 
 | ||||||
| import Hledger.Web.Options (defwebopts) | 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 | -- 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 | -- 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 | -- performs initialization and creates a WAI application. This is also the | ||||||
| -- place to put your migrate statements to have automatic database | -- place to put your migrate statements to have automatic database | ||||||
| -- migrations handled by Yesod. | -- migrations handled by Yesod. | ||||||
| makeApplication :: AppConfig DefaultEnv Extra -> IO Application | makeApplication :: Journal -> AppConfig DefaultEnv Extra -> IO Application | ||||||
| makeApplication conf = do | makeApplication j conf = do | ||||||
|     foundation <- makeFoundation conf |     foundation <- makeFoundation conf | ||||||
|  |     writeIORef (appJournal foundation) j | ||||||
|     app <- toWaiAppPlain foundation |     app <- toWaiAppPlain foundation | ||||||
|     return $ logWare app |     return $ logWare app | ||||||
|   where |   where | ||||||
| @ -44,13 +50,16 @@ makeFoundation :: AppConfig DefaultEnv Extra -> IO App | |||||||
| makeFoundation conf = do | makeFoundation conf = do | ||||||
|     manager <- newManager def |     manager <- newManager def | ||||||
|     s <- staticSite |     s <- staticSite | ||||||
|     return $ App conf s manager |     jref <- newIORef nulljournal | ||||||
|       defwebopts |     return $ App conf s manager defwebopts jref | ||||||
| 
 | 
 | ||||||
| -- for yesod devel | -- for yesod devel | ||||||
|  | -- uses the journal specified by the LEDGER_FILE env var, or ~/.hledger.journal | ||||||
| getApplicationDev :: IO (Int, Application) | getApplicationDev :: IO (Int, Application) | ||||||
| getApplicationDev = | getApplicationDev = do | ||||||
|     defaultDevelApp loader makeApplication |   f <- journalFilePathFromOpts defcliopts | ||||||
|  |   j <- either error' id `fmap` readJournalFile Nothing Nothing f | ||||||
|  |   defaultDevelApp loader (makeApplication j) | ||||||
|   where |   where | ||||||
|     loader = loadConfig (configSettings Development) |     loader = loadConfig (configSettings Development) | ||||||
|         { csParseExtra = parseExtra |         { csParseExtra = parseExtra | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ See a default Yesod app's comments for more details of each part. | |||||||
| module Foundation where | module Foundation where | ||||||
| 
 | 
 | ||||||
| import Prelude | import Prelude | ||||||
|  | import Data.IORef | ||||||
| import Yesod | import Yesod | ||||||
| import Yesod.Static | import Yesod.Static | ||||||
| import Yesod.Default.Config | import Yesod.Default.Config | ||||||
| @ -26,6 +27,7 @@ import Web.ClientSession (getKey) | |||||||
| import Text.Hamlet (hamletFile) | import Text.Hamlet (hamletFile) | ||||||
| 
 | 
 | ||||||
| import Hledger.Web.Options | import Hledger.Web.Options | ||||||
|  | import Hledger.Data.Types | ||||||
| -- import Hledger.Web.Settings | -- import Hledger.Web.Settings | ||||||
| -- import Hledger.Web.Settings.StaticFiles | -- import Hledger.Web.Settings.StaticFiles | ||||||
| 
 | 
 | ||||||
| @ -40,6 +42,7 @@ data App = App | |||||||
|     , httpManager :: Manager |     , httpManager :: Manager | ||||||
|       -- |       -- | ||||||
|     , appOpts    :: WebOpts |     , appOpts    :: WebOpts | ||||||
|  |     , appJournal :: IORef Journal | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| -- Set up i18n messages. See the message folder. | -- Set up i18n messages. See the message folder. | ||||||
|  | |||||||
| @ -5,12 +5,13 @@ module Handler.Utils where | |||||||
| import Prelude | import Prelude | ||||||
| import Control.Applicative ((<$>)) | import Control.Applicative ((<$>)) | ||||||
| import Control.Monad.IO.Class (liftIO) | import Control.Monad.IO.Class (liftIO) | ||||||
|  | import Data.IORef | ||||||
| import Data.Maybe | import Data.Maybe | ||||||
| import Data.Text(pack,unpack) | import Data.Text(pack,unpack) | ||||||
| import Data.Time.Calendar | import Data.Time.Calendar | ||||||
| import Data.Time.Clock | import Data.Time.Clock | ||||||
| import Data.Time.Format | import Data.Time.Format | ||||||
| import System.IO.Storage (putValue, getValue) | -- import System.IO.Storage (putValue, getValue) | ||||||
| import System.Locale (defaultTimeLocale) | import System.Locale (defaultTimeLocale) | ||||||
| #if BLAZE_HTML_0_5 | #if BLAZE_HTML_0_5 | ||||||
| import Text.Blaze.Html (toHtml) | import Text.Blaze.Html (toHtml) | ||||||
| @ -70,7 +71,7 @@ getViewData :: Handler ViewData | |||||||
| getViewData = do | getViewData = do | ||||||
|   app        <- getYesod |   app        <- getYesod | ||||||
|   let opts@WebOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} = appOpts app |   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 |   msg        <- getMessageOr err | ||||||
|   Just here  <- getCurrentRoute |   Just here  <- getCurrentRoute | ||||||
|   today      <- liftIO getCurrentDay |   today      <- liftIO getCurrentDay | ||||||
| @ -88,17 +89,18 @@ getViewData = do | |||||||
|       -- | Update our copy of the journal if the file changed. If there is an |       -- | 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 |       -- error while reloading, keep the old one and return the error, and set a | ||||||
|       -- ui message. |       -- ui message. | ||||||
|       getCurrentJournal :: CliOpts -> Handler (Journal, Maybe String) |       getCurrentJournal :: App -> CliOpts -> Handler (Journal, Maybe String) | ||||||
|       getCurrentJournal opts = do |       getCurrentJournal app opts = do | ||||||
|         j <- liftIO $ fromJust `fmap` getValue "hledger" "journal" |         -- XXX put this inside atomicModifyIORef' for thread safety | ||||||
|  |         j <- liftIO $ readIORef $ appJournal app | ||||||
|         (jE, changed) <- liftIO $ journalReloadIfChanged opts j |         (jE, changed) <- liftIO $ journalReloadIfChanged opts j | ||||||
|         if not changed |         if not changed | ||||||
|          then return (j,Nothing) |          then return (j,Nothing) | ||||||
|          else case jE of |          else case jE of | ||||||
|                 Right j' -> do liftIO $ putValue "hledger" "journal" j' |                 Right j' -> do liftIO $ writeIORef (appJournal app) j' | ||||||
|                                return (j',Nothing) |                                return (j',Nothing) | ||||||
|                 Left e  -> do setMessage $ "error while reading" {- ++ ": " ++ e-} |                 Left e   -> do setMessage $ "error while reading" {- ++ ": " ++ e-} | ||||||
|                               return (j, Just e) |                                return (j, Just e) | ||||||
| 
 | 
 | ||||||
|       -- | Get the named request parameter, or the empty string if not present. |       -- | Get the named request parameter, or the empty string if not present. | ||||||
|       getParameterOrNull :: String -> Handler String |       getParameterOrNull :: String -> Handler String | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ import Prelude hiding (putStrLn) | |||||||
| import Control.Monad (when) | import Control.Monad (when) | ||||||
| import Data.Text (pack) | import Data.Text (pack) | ||||||
| import System.Exit (exitSuccess) | import System.Exit (exitSuccess) | ||||||
| import System.IO.Storage (withStore, putValue) | -- import System.IO.Storage (withStore, putValue) | ||||||
| import Text.Printf | import Text.Printf | ||||||
| 
 | 
 | ||||||
| import Hledger | import Hledger | ||||||
| @ -67,18 +67,8 @@ web opts j = do | |||||||
| 
 | 
 | ||||||
| server :: String -> Int -> WebOpts -> Journal -> IO () | server :: String -> Int -> WebOpts -> Journal -> IO () | ||||||
| server baseurl port opts j = do | server baseurl port opts j = do | ||||||
|   _ <- printf "Starting http server on port %d with base url %s\n" port baseurl |     _ <- printf "Starting http server on port %d with base url %s\n" port baseurl | ||||||
|   -- let a = App{getStatic=static staticdir |     app <- makeApplication j (AppConfig { | ||||||
|   --            ,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 { |  | ||||||
|               appEnv = Development |               appEnv = Development | ||||||
|             , appPort = port_ opts |             , appPort = port_ opts | ||||||
|             , appRoot = pack baseurl |             , appRoot = pack baseurl | ||||||
|  | |||||||
| @ -1,2 +0,0 @@ | |||||||
| import Distribution.Simple |  | ||||||
| main = defaultMain |  | ||||||
| @ -6,17 +6,12 @@ import Control.Concurrent (forkIO) | |||||||
| import System.Directory (doesFileExist, removeFile) | import System.Directory (doesFileExist, removeFile) | ||||||
| import System.Exit (exitSuccess) | import System.Exit (exitSuccess) | ||||||
| import Control.Concurrent (threadDelay) | import Control.Concurrent (threadDelay) | ||||||
| import System.IO.Storage (withStore, putValue) |  | ||||||
| 
 |  | ||||||
| import Hledger (readJournalFile) |  | ||||||
| 
 | 
 | ||||||
| main :: IO () | main :: IO () | ||||||
| main = do | main = do | ||||||
|     putStrLn "Starting devel application" |     putStrLn "Starting devel application" | ||||||
|     (port, app) <- getApplicationDev |     (port, app) <- getApplicationDev | ||||||
|     forkIO $ |     forkIO $ | ||||||
|       withStore "hledger" $ do |  | ||||||
|         readJournalFile Nothing Nothing "dev.journal" >>= putValue "hledger" "journal" |  | ||||||
|         runSettings defaultSettings |         runSettings defaultSettings | ||||||
|           { settingsPort = port |           { settingsPort = port | ||||||
|           } app |           } app | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user