on master help sign in
Merge branch 'develop' into rk-no-redirect
35c719fAli Abrar
CONTRIBUTING.md+5
@@ -5,6 +5,7 @@ Contributions and issue reports are encouraged and appreciated!
5- [Opening Issues](#opening-issues)
5- [Opening Issues](#opening-issues)
6- [Submitting Changes](#submitting-changes)
6- [Submitting Changes](#submitting-changes)
7 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
7 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
8+ - [Guidelines for Pull Requests](#guidelines-for-pull-requests)
8 - [Code Quality](#code-quality)
9 - [Code Quality](#code-quality)
9 - [Documentation](#documentation)
10 - [Documentation](#documentation)
10
11
@@ -34,6 +35,10 @@ Commits that update a dependency should include some information about why the d
34#### Body
35#### Body
35For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
36For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
36
37
38+### Guidelines for Pull Requests
39+
40+Wherever possible, pull requests should add a single feature or fix a single bug. Pull requests should not bundle several unrelated changes.
41+
37### Code Quality
42### Code Quality
38
43
39#### Warnings
44#### Warnings
ChangeLog.md+1
@@ -9,6 +9,7 @@ This project's release branch is `master`. This log is written from the perspect
9* The backend no longer runs in BackendConfigsT.
9* The backend no longer runs in BackendConfigsT.
10* Add tabulation package. See Data.Tabulation for details.
10* Add tabulation package. See Data.Tabulation for details.
11* Add encoders for `DMap`, `HasFields` (cf. Data.Tabulation), and JSON.
11* Add encoders for `DMap`, `HasFields` (cf. Data.Tabulation), and JSON.
12+* Use IP address for nginx proxy pass instead of localhost
12
13
13## v0.1.1.0 - 2019-05-17
14## v0.1.1.0 - 2019-05-17
14
15
README.md+5
@@ -5,6 +5,7 @@ Obelisk provides an easy way to develop and deploy your [Reflex](https://github.
5- [Installing Obelisk](#installing-obelisk)
5- [Installing Obelisk](#installing-obelisk)
6- [Developing an Obelisk project](#developing-an-obelisk-project)
6- [Developing an Obelisk project](#developing-an-obelisk-project)
7 - [Hoogle](#hoogle)
7 - [Hoogle](#hoogle)
8+ - [Adding Packages](#adding-packages)
8 - [Adding Package Overrides](#adding-package-overrides)
9 - [Adding Package Overrides](#adding-package-overrides)
9- [Deploying](#deploying)
10- [Deploying](#deploying)
10 - [Locally](#locally)
11 - [Locally](#locally)
@@ -92,6 +93,10 @@ To enter a nix-shell from which you can run the hoogle command-line client or a
92
93
93`nix-shell -A shells.ghc --arg withHoogle true`
94`nix-shell -A shells.ghc --arg withHoogle true`
94
95
96+### Adding packages
97+
98+In order to add package dependencies, declare them under the build-depends field in the appropriate cabal files (backend, common, and frontend each have their own). The corresponding Nix packages will automatically be selected when building.
99+
95### Adding package overrides
100### Adding package overrides
96
101
97To add a version override to any Haskell package, or to add a Haskell package that doesn't exist in the nixpkgs used by Obelisk, use the `overrides` attribute in your project's `default.nix`. For example, to use a specific version of the `aeson` package, your `default.nix` will look like:
102To add a version override to any Haskell package, or to add a Haskell package that doesn't exist in the nixpkgs used by Obelisk, use the `overrides` attribute in your project's `default.nix`. For example, to use a specific version of the `aeson` package, your `default.nix` will look like:
default.nix+1−1
@@ -198,7 +198,7 @@ in rec {
198 enableACME = enableHttps;
198 enableACME = enableHttps;
199 forceSSL = enableHttps;
199 forceSSL = enableHttps;
200 locations.${baseUrl} = {
200 locations.${baseUrl} = {
201− proxyPass = "http://localhost:" + toString internalPort;
201+ proxyPass = "http://127.0.0.1:" + toString internalPort;
202 proxyWebsockets = true;
202 proxyWebsockets = true;
203 };
203 };
204 };
204 };
lib/command/src/Obelisk/Command/Run.hs+4−1
@@ -73,7 +73,10 @@ run = do
73 -- Check whether the impure static files are a derivation (and so must be built)
73 -- Check whether the impure static files are a derivation (and so must be built)
74 if isDerivation == "1"
74 if isDerivation == "1"
75 then fmap T.strip $ readProcessAndLogStderr Debug $ -- Strip whitespace here because nix-build has no --raw option
75 then fmap T.strip $ readProcessAndLogStderr Debug $ -- Strip whitespace here because nix-build has no --raw option
76+ proc "nix-build"
77+ [ "--no-out-link"
76− proc "nix-build" ["-E", "(import " <> importableRoot <> "{}).passthru.staticFilesImpure"]
78+ , "-E", "(import " <> importableRoot <> "{}).passthru.staticFilesImpure"
79+ ]
77 else readProcessAndLogStderr Debug $
80 else readProcessAndLogStderr Debug $
78 proc "nix" ["eval", "-f", root, "passthru.staticFilesImpure", "--raw"]
81 proc "nix" ["eval", "-f", root, "passthru.staticFilesImpure", "--raw"]
79 putLog Debug $ "Assets impurely loaded from: " <> assets
82 putLog Debug $ "Assets impurely loaded from: " <> assets
lib/command/src/Obelisk/Command/VmBuilder.hs+2−1
@@ -156,7 +156,8 @@ testLinuxBuild stateDir
156 | System.Info.os == "linux" = failWith "Using the docker builder is not necessary on linux."
156 | System.Info.os == "linux" = failWith "Using the docker builder is not necessary on linux."
157 | otherwise = do
157 | otherwise = do
158 (exitCode, _stdout, stderr) <- readCreateProcessWithExitCode $ proc "nix-build"
158 (exitCode, _stdout, stderr) <- readCreateProcessWithExitCode $ proc "nix-build"
159+ [ "--no-out-link"
159− [ "-E", "(import <nixpkgs> { system = \"x86_64-linux\"; }).writeText \"test\" builtins.currentTime"
160+ , "-E", "(import <nixpkgs> { system = \"x86_64-linux\"; }).writeText \"test\" builtins.currentTime"
160 , "--builders", nixBuildersArgString stateDir
161 , "--builders", nixBuildersArgString stateDir
161 ]
162 ]
162 unless (exitCode == ExitSuccess) $ do
163 unless (exitCode == ExitSuccess) $ do
lib/executable-config/lookup/src-ghcjs/Obelisk/ExecutableConfig/Lookup.hs+17−8
@@ -15,28 +15,37 @@ import GHCJS.DOM.Document (getHead)
15import GHCJS.DOM.DOMStringMap (get)
15import GHCJS.DOM.DOMStringMap (get)
16import GHCJS.DOM.Element (getInnerHTML)
16import GHCJS.DOM.Element (getInnerHTML)
17import GHCJS.DOM.HTMLElement (HTMLElement(HTMLElement), getDataset)
17import GHCJS.DOM.HTMLElement (HTMLElement(HTMLElement), getDataset)
18−import GHCJS.DOM.NodeList (item, getLength)
18+import GHCJS.DOM.NodeList (IsNodeList, item, getLength)
19import GHCJS.DOM.ParentNode (querySelectorAll)
19import GHCJS.DOM.ParentNode (querySelectorAll)
20−import GHCJS.DOM.Types (Node(Node), castTo)
20+import GHCJS.DOM.Types (MonadJSM, Node(Node), castTo)
21
21
22getConfigs :: IO (Map Text ByteString)
22getConfigs :: IO (Map Text ByteString)
23getConfigs = do
23getConfigs = do
24 Just doc <- currentDocument
24 Just doc <- currentDocument
25 Just hd <- getHead doc
25 Just hd <- getHead doc
26− nodes <- collToList =<< querySelectorAll hd ("[data-obelisk-executable-config-inject-key]" :: Text)
26+ nodes <- nodeListNodes =<< querySelectorAll hd ("[data-obelisk-executable-config-inject-key]" :: Text)
27 fmap Map.fromList $ for nodes $ \node -> do
27 fmap Map.fromList $ for nodes $ \node -> do
28 e <- castTo HTMLElement node >>= \case
28 e <- castTo HTMLElement node >>= \case
29 Nothing -> error "Found node with data attribute obelisk-executable-config-inject-key that is not an HTMLElement."
29 Nothing -> error "Found node with data attribute obelisk-executable-config-inject-key that is not an HTMLElement."
30 Just htmlE -> return htmlE
30 Just htmlE -> return htmlE
31 dataset <- getDataset e
31 dataset <- getDataset e
32 (,)
32 (,)
33− <$> get dataset ("obelisk-executable-config-inject-key" :: Text)
33+ -- the key is camelCased: https://html.spec.whatwg.org/multipage/dom.html#dom-dataset
34+ <$> get dataset ("obeliskExecutableConfigInjectKey" :: Text)
34 <*> (fmap decodeOrFail (getInnerHTML e))
35 <*> (fmap decodeOrFail (getInnerHTML e))
35 where
36 where
36− collToList es = do
37− len <- getLength es
38− list <- traverse (item es) [0..len-1]
39− pure $ catMaybes list
40 decodeOrFail x = case B64.decode (T.encodeUtf8 x) of
37 decodeOrFail x = case B64.decode (T.encodeUtf8 x) of
41 Left e -> error ("Obelisk.ExecutableConfig.Lookup.getConfigs: error when decoding base64: " ++ e)
38 Left e -> error ("Obelisk.ExecutableConfig.Lookup.getConfigs: error when decoding base64: " ++ e)
42 Right x' -> x'
39 Right x' -> x'
40+
41+-- | Collect all nodes in the node list.
42+--
43+-- TODO: this and the version in obelisk-frontend should be
44+-- upstreamed to jsaddle.
45+nodeListNodes :: (IsNodeList l, MonadJSM m) => l -> m [Node]
46+nodeListNodes es = do
47+ len <- getLength es
48+ -- Warning! len is unsigned. If the NodeList is empty, we must avoid
49+ -- accidentally traversing over [0..maxBound::Word]
50+ nodes <- traverse (item es) $ if len == 0 then [] else [0..len-1]
51+ pure $ catMaybes nodes
lib/frontend/src/Obelisk/Frontend.hs+16−9
@@ -43,11 +43,11 @@ import qualified GHCJS.DOM as DOM
43import qualified GHCJS.DOM.Types as DOM
43import qualified GHCJS.DOM.Types as DOM
44import qualified GHCJS.DOM.History as DOM
44import qualified GHCJS.DOM.History as DOM
45import qualified GHCJS.DOM.Window as DOM
45import qualified GHCJS.DOM.Window as DOM
46−import Language.Javascript.JSaddle (JSM, jsNull)
46+import Language.Javascript.JSaddle (MonadJSM, JSM, jsNull)
47import GHCJS.DOM (currentDocument)
47import GHCJS.DOM (currentDocument)
48import GHCJS.DOM.Document (getHead)
48import GHCJS.DOM.Document (getHead)
49−import GHCJS.DOM.Node (removeChild_)
49+import GHCJS.DOM.Node (Node, removeChild_)
50−import GHCJS.DOM.NodeList (item, getLength)
50+import GHCJS.DOM.NodeList (IsNodeList, item, getLength)
51import GHCJS.DOM.ParentNode (querySelectorAll)
51import GHCJS.DOM.ParentNode (querySelectorAll)
52import Obelisk.Frontend.Cookie
52import Obelisk.Frontend.Cookie
53import Obelisk.Route.Frontend
53import Obelisk.Route.Frontend
@@ -105,13 +105,20 @@ removeHTMLConfigs :: JSM ()
105removeHTMLConfigs = void $ runMaybeT $ do
105removeHTMLConfigs = void $ runMaybeT $ do
106 doc <- MaybeT currentDocument
106 doc <- MaybeT currentDocument
107 hd <- MaybeT $ getHead doc
107 hd <- MaybeT $ getHead doc
108− es <- collToList =<< querySelectorAll hd ("[data-obelisk-executable-config-inject-key]" :: Text)
108+ es <- nodeListNodes =<< querySelectorAll hd ("[data-obelisk-executable-config-inject-key]" :: Text)
109 for_ es $ removeChild_ hd
109 for_ es $ removeChild_ hd
110− where
110+
111− collToList es = do
111+-- | Collect all nodes in the node list.
112+--
113+-- TODO: this and the version in exe-config/ghcjs/lookup should be
114+-- upstreamed to jsaddle.
115+nodeListNodes :: (IsNodeList l, MonadJSM m) => l -> m [Node]
116+nodeListNodes es = do
112− len <- getLength es
117+ len <- getLength es
113− lst <- traverse (item es) $ take (fromIntegral len) $ [0..] -- fun with unsigned types ...
118+ -- Warning! len is unsigned. If the NodeList is empty, we must avoid
119+ -- accidentally traversing over [0..maxBound::Word]
120+ nodes <- traverse (item es) $ if len == 0 then [] else [0..len-1]
114− pure $ catMaybes lst
121+ pure $ catMaybes nodes
115
122
116setInitialRoute :: Bool -> JSM ()
123setInitialRoute :: Bool -> JSM ()
117setInitialRoute useHash = do
124setInitialRoute useHash = do
lib/route/src/Obelisk/Route.hs+1−1
@@ -202,7 +202,7 @@ decode e x = runIdentity (tryDecode e x)
202tryDecode :: Encoder Identity parse decoded encoded -> encoded -> parse decoded
202tryDecode :: Encoder Identity parse decoded encoded -> encoded -> parse decoded
203tryDecode (Encoder (Identity impl)) x = _encoderImpl_decode impl x
203tryDecode (Encoder (Identity impl)) x = _encoderImpl_decode impl x
204
204
205−-- | Similar to 'decode' above, once an encoder has been checked so that its check monad is Identity, it
205+-- | Similar to 'decode', once an encoder has been checked so that its check monad is Identity, it
206-- can be used to actually encode by using this. Note that while there's no constraint on the parse monad here,
206-- can be used to actually encode by using this. Note that while there's no constraint on the parse monad here,
207-- one should usually be applying decode and encode to the same 'Encoder'
207-- one should usually be applying decode and encode to the same 'Encoder'
208encode :: Encoder Identity parse decoded encoded -> decoded -> encoded
208encode :: Encoder Identity parse decoded encoded -> decoded -> encoded
lib/selftest/src/Obelisk/SelfTest.hs+10−9
@@ -75,6 +75,7 @@ main = do
75 unless isVerbose $
75 unless isVerbose $
76 putStrLn "Tests may take longer to run if there are unbuilt derivations: use -v for verbose output"
76 putStrLn "Tests may take longer to run if there are unbuilt derivations: use -v for verbose output"
77 let verbosity = bool silently verbosely isVerbose
77 let verbosity = bool silently verbosely isVerbose
78+ nixBuild args = run "nix-build" ("--no-out-link" : args)
78 obeliskImpl <- fromString <$> getEnv "OBELISK_IMPL"
79 obeliskImpl <- fromString <$> getEnv "OBELISK_IMPL"
79 httpManager <- HTTP.newManager HTTP.defaultManagerSettings
80 httpManager <- HTTP.newManager HTTP.defaultManagerSettings
80 [p0, p1, p2, p3] <- liftIO $ getFreePorts 4
81 [p0, p1, p2, p3] <- liftIO $ getFreePorts 4
@@ -141,22 +142,22 @@ main = do
141 testObRunInDir p2 p3 (Just "frontend") httpManager
142 testObRunInDir p2 p3 (Just "frontend") httpManager
142
143
143 describe "obelisk project" $ parallel $ do
144 describe "obelisk project" $ parallel $ do
144− it "can build obelisk command" $ inTmpObInit $ \_ -> run "nix-build" ["-A", "command" , obeliskImpl]
145+ it "can build obelisk command" $ inTmpObInit $ \_ -> nixBuild ["-A", "command" , obeliskImpl]
145− it "can build obelisk skeleton" $ inTmpObInit $ \_ -> run "nix-build" ["-A", "skeleton", obeliskImpl]
146+ it "can build obelisk skeleton" $ inTmpObInit $ \_ -> nixBuild ["-A", "skeleton", obeliskImpl]
146− it "can build obelisk shell" $ inTmpObInit $ \_ -> run "nix-build" ["-A", "shell", obeliskImpl]
147+ it "can build obelisk shell" $ inTmpObInit $ \_ -> nixBuild ["-A", "shell", obeliskImpl]
147 -- See https://github.com/obsidiansystems/obelisk/issues/101
148 -- See https://github.com/obsidiansystems/obelisk/issues/101
148− -- it "can build everything" $ shelly_ $ run "nix-build" [obeliskImpl]
149+ -- it "can build everything" $ shelly_ $ nixBuild [obeliskImpl]
149
150
150 describe "blank initialized project" $ parallel $ do
151 describe "blank initialized project" $ parallel $ do
151
152
152 it "can build ghc.backend" $ inTmpObInit $ \_ -> do
153 it "can build ghc.backend" $ inTmpObInit $ \_ -> do
153− run "nix-build" ["--no-out-link", "-A", "ghc.backend"]
154+ nixBuild ["-A", "ghc.backend"]
154 it "can build ghcjs.frontend" $ inTmpObInit $ \_ -> do
155 it "can build ghcjs.frontend" $ inTmpObInit $ \_ -> do
155− run "nix-build" ["--no-out-link", "-A", "ghcjs.frontend"]
156+ nixBuild ["-A", "ghcjs.frontend"]
156
157
157 if os == "darwin"
158 if os == "darwin"
158− then it "can build ios" $ inTmpObInit $ \_ -> run "nix-build" ["--no-out-link", "-A", "ios.frontend" ]
159+ then it "can build ios" $ inTmpObInit $ \_ -> nixBuild ["-A", "ios.frontend"]
159− else it "can build android" $ inTmpObInit $ \_ -> run "nix-build" ["--no-out-link", "-A", "android.frontend"]
160+ else it "can build android" $ inTmpObInit $ \_ -> nixBuild ["-A", "android.frontend"]
160
161
161 forM_ ["ghc", "ghcjs"] $ \compiler -> do
162 forM_ ["ghc", "ghcjs"] $ \compiler -> do
162 let
163 let
@@ -166,7 +167,7 @@ main = do
166 it ("can build in " <> shell) $ inTmpObInit $ \_ -> inShell $ "cabal new-build --" <> fromString compiler <> " all"
167 it ("can build in " <> shell) $ inTmpObInit $ \_ -> inShell $ "cabal new-build --" <> fromString compiler <> " all"
167
168
168 it "can build reflex project" $ inTmpObInit $ \_ -> do
169 it "can build reflex project" $ inTmpObInit $ \_ -> do
169− run "nix-build" []
170+ nixBuild []
170
171
171 it "has idempotent thunk update" $ inTmpObInit $ \_ -> do
172 it "has idempotent thunk update" $ inTmpObInit $ \_ -> do
172 u <- update
173 u <- update