on master help sign in
Run command first pass

Loads backend, common and frontend through a single ghci using ghcid for autoreloading on change

commit383c2a814a3ea4a267114d52408117517c665a52 authorLuigy Leon <luigy@outlook.com> dateSun 22 Apr 2018, 23:58 (8 years ago) parent57b4e41
6 files changed+69−16
default.nix+1−1 lib/command/obelisk-command.cabal+1 lib/command/src/Obelisk/Command.hs+22−3 lib/command/src/Obelisk/Command/Repl.hs+27 lib/run-frontend/src/Obelisk/Widget/Run.hs+17−12 skeleton/frontend/frontend.cabal+1
default.nix+1−1
@@ -134,7 +134,7 @@ rec {
134134 backendName
135135 commonName
136136 frontendName
137− ]) ++ ghcDevPackages;
137+ ]);
138138 ghcjs = filter (x: hasAttr x combinedPackages) [
139139 frontendName
140140 commonName
lib/command/obelisk-command.cabal+1
@@ -17,6 +17,7 @@ library
1717 , github
1818 , hit
1919 , mtl
20+ , network
2021 , network-uri
2122 , optparse-applicative
2223 , process
lib/command/src/Obelisk/Command.hs+22−3
@@ -5,10 +5,12 @@ module Obelisk.Command where
55import Control.Monad
66import Data.List
77import Data.Monoid
8+import qualified Data.Text as T
89import Options.Applicative
910import System.Environment
1011import System.FilePath
1112import System.IO
13+import System.IO.Temp (withSystemTempDirectory)
1214import System.Posix.Process
1315
1416import Obelisk.Command.Project
@@ -48,7 +50,7 @@ initSource = foldl1 (<|>)
4850
4951data ObCommand
5052 = ObCommand_Init InitSource
51− | ObCommand_Dev
53+ | ObCommand_Dev FilePath
5254 | ObCommand_Thunk ThunkCommand
5355 | ObCommand_Repl FilePath
5456 | ObCommand_Watch FilePath
@@ -56,7 +58,7 @@ data ObCommand
5658obCommand :: Parser ObCommand
5759obCommand = hsubparser $ mconcat
5860 [ command "init" $ info (ObCommand_Init <$> initSource) $ progDesc "Initialize an Obelisk project"
59− , command "dev" $ info (pure ObCommand_Dev) $ progDesc "Run current project in development mode"
61+ , command "dev" $ info (ObCommand_Dev <$> (strArgument (action "directory"))) $ progDesc "Run current project in development mode"
6062 , command "thunk" $ info (ObCommand_Thunk <$> thunkCommand) $ progDesc "Manipulate thunk directories"
6163 , command "repl" $ info (ObCommand_Repl <$> (strArgument (action "directory"))) $ progDesc "Open an interactive interpreter"
6264 , command "watch" $ info (ObCommand_Watch <$> (strArgument (action "directory")))$ progDesc "Watch directory for changes and update interactive interpreter"
@@ -131,7 +133,24 @@ main = do
131133ob :: ObCommand -> IO ()
132134ob = \case
133135 ObCommand_Init source -> initProject source
134− ObCommand_Dev -> putStrLn "Dev!"
136+ ObCommand_Dev _ -> do
137+ freePort <- getFreePort
138+ let dotGhci = unlines
139+ [ ":set args --port " <> show freePort
140+ , ":set -ibackend/src:common/src:frontend/src"
141+ , ":add Common.Api Backend.App Frontend.App"
142+ , ":module + Control.Concurrent Obelisk.Widget.Run Common.Api Frontend.App Backend.App"
143+ ]
144+ testCmd = unlines
145+ [ "backendId <- forkIO backend"
146+ , "let conf = defRunConfig { _runConfig_redirectPort = " <> show freePort <> "}"
147+ , "runWidget conf frontend"
148+ , "killThread backendId"
149+ ]
150+ withSystemTempDirectory "ob-ghci" $ \fp -> do
151+ let dotGhciPath = fp </> ".ghci"
152+ writeFile dotGhciPath dotGhci
153+ runDev dotGhciPath $ Just testCmd
135154 ObCommand_Thunk tc -> case tc of
136155 ThunkCommand_Update thunks -> mapM_ updateThunkToLatest thunks
137156 ThunkCommand_Unpack thunks -> mapM_ unpackThunk thunks
lib/command/src/Obelisk/Command/Repl.hs+27
@@ -1,10 +1,17 @@
11{-# LANGUAGE OverloadedStrings #-}
22module Obelisk.Command.Repl
33 ( runRepl
4+ , runDev
45 , watch
6+ , getFreePort
57 ) where
68
9+import qualified Control.Exception as E
10+import Data.Maybe
711import Data.Monoid ((<>))
12+import Data.Text (Text)
13+import qualified Data.Text as T
14+import Network.Socket
815
916import Obelisk.Command.Project
1017
@@ -16,3 +23,23 @@ runRepl dir = inProjectShell "ghc" $ "cd " <> dir <> "; cabal new-repl"
1623watch :: FilePath -> IO ()
1724watch dir = inProjectShell "ghc" $ "cd " <> dir <> "; ghcid -W --command='cabal new-repl'"
1825
26+-- | Dev
27+runDev :: FilePath -> Maybe String -> IO ()
28+runDev dotGhci mcmd = inProjectShell "ghc" ghcidOpts
29+ where
30+ ghcidOpts = unwords $
31+ [ "ghcid"
32+ , "-W"
33+ , "--command='ghci -ghci-script " <> dotGhci <> "' "
34+ ] <> maybeToList (flip fmap mcmd $ \cmd -> " --test=$'" <> cmd <> "'")
35+
36+getFreePort :: IO PortNumber
37+getFreePort = withSocketsDo $ do
38+ addr:_ <- getAddrInfo (Just defaultHints) (Just "127.0.0.1") (Just "0")
39+ E.bracket (open addr) close socketPort
40+ where
41+ open addr = do
42+ sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
43+ bind sock (addrAddress addr)
44+ return sock
45+
lib/run-frontend/src/Obelisk/Widget/Run.hs+17−12
@@ -11,22 +11,27 @@ import Network.Wai.Handler.Warp (defaultSettings, setTimeout, setPort, runSettin
1111import Network.WebSockets.Connection (defaultConnectionOptions)
1212import Reflex.Dom.Core
1313
14−test :: IO ()
15−test = do
16− runWidget $ do
17− text "hello world"
18− elAttr "img" ("src" =: "/obelisk.jpg") $ return ()
19−
20−runWidget :: Widget () () -> IO ()
21−runWidget w = do
14+runWidget :: RunConfig -> Widget () () -> IO ()
15+runWidget conf w = do
2216 man <- newManager defaultManagerSettings
23− let port = 3003 -- TODO
24− redirectHost = "0.0.0.0"
25− redirectPort = 38383
26− runSettings (setPort port (setTimeout 3600 defaultSettings)) =<<
17+ let redirectHost = _runConfig_redirectHost conf
18+ redirectPort = _runConfig_redirectPort conf
19+ runSettings (setPort (_runConfig_port conf) (setTimeout 3600 defaultSettings)) =<<
2720 jsaddleWithAppOr defaultConnectionOptions (mainWidget' w >> syncPoint) (fallbackProxy redirectHost redirectPort man)
2821
2922fallbackProxy :: ByteString -> Int -> Manager -> Application
3023fallbackProxy host port = RP.waiProxyTo handleRequest RP.defaultOnExc
3124 where handleRequest _req = return $ RP.WPRProxyDest $ RP.ProxyDest host port
3225
26+data RunConfig = RunConfig
27+ { _runConfig_port :: Int
28+ , _runConfig_redirectHost :: ByteString
29+ , _runConfig_redirectPort :: Int
30+ }
31+
32+defRunConfig :: RunConfig
33+defRunConfig = RunConfig
34+ { _runConfig_port = 3000
35+ , _runConfig_redirectHost = "0.0.0.0"
36+ , _runConfig_redirectPort = 3001
37+ }
skeleton/frontend/frontend.cabal+1
@@ -8,6 +8,7 @@ library
88 build-depends: base
99 , reflex-dom
1010 , static
11+ , obelisk-run-frontend
1112 , text
1213 exposed-modules:
1314 Frontend.App