on master help sign in
Merged with 'develop' branch
commitbc8e60fcde1f141539e87240f742c33ac7151a42 authorhsloan <ishaqsloan@gmail.com> dateMon 4 Dec 2017, 21:08 (9 years ago) parent627a7b0
11 files changed+251
.gitmodules+3 README.md+32 build-frontend+19 default.nix+7 ghci-backend+7 ghcid-backend+7 ghcid-frontend+7 ob-init.hs+146 script-env/default.nix+5 script-env/ob-init.nix+9 script-env/parse-backend-listen.nix+9
.gitmodules+3
@@ -13,3 +13,6 @@
1313[submodule "obelisk-https"]
1414 path = obelisk-https
1515 url = git@github.com:obsidiansystems/obelisk-https
16+[submodule "reflex-platform"]
17+ path = reflex-platform
18+ url = git@github.com:reflex-frp/reflex-platform.git
README.mdnew file+32
@@ -0,0 +1,32 @@
1+Assuming you've already added SSH keys to both your github and gitlab
2+accounts, please proceed with the instructions that follow.
3+
4+In your new project's git repository:
5+
6+```bash
7+git init
8+```
9+The ob-init.hs script will add and update the focus submodule as well as
10+generate the necessary boilerplate files and folders. Enter the following in
11+your console, followed by your project's name when prompted.
12+
13+```bash
14+./ob-init.hs
15+```
16+Build the frontend by running ./focus/build-frontend
17+
18+Now you can try running the backend in GHCi by running
19+
20+./focus/ghci-backend
21+
22+and then typing
23+
24+main
25+
26+at the GHCi prompt.
27+
28+Point your web browser at [localhost:8000](localhost:8000) and everything should work.
29+
30+Feel free to edit the frontend and backend directories as you see fit.
31+
32+Thank you for using Obelisk.
build-frontendnew file+19
@@ -0,0 +1,19 @@
1+#!/usr/bin/env bash
2+set -eu -o pipefail
3+
4+echo -ne '\033]0;'$0'\007'
5+nix-shell -A shells.ghcjs --run '
6+ cabal --project-file=cabal-ghcjs.project --builddir=dist-ghcjs new-build exe:frontend
7+ mkdir -p frontendJs
8+ (cd frontendJs; ln -sfT ../dist-ghcjs/build/*/ghcjs-*/frontend-*/c/frontend/build/frontend/frontend.jsexe frontend.jsexe)
9+ '
10+
11+# GC flags
12+# If BUSY_YIELD < SCHED_QUANTUM, only one thread ever seems to get to run.
13+# -DGHCJS_GC_INTERVAL=60000 -DGHCJS_BUSY_YIELD=5 -DGHCJS_SCHED_QUANTUM=5
14+
15+# Xtreme optimization
16+# -O2 -fplugin=Reflex.Optimizer -fexpose-all-unfoldings -fspecialise-aggressively
17+
18+# dump ghc intermediate outputs for analysis
19+# -dumpdir=dump-js -ddump-to-file -ddump-simpl -ddump-hi -dppr-cols=200 -ddump-rule-firings -dsuppress-all
default.nixnew file+7
@@ -0,0 +1,7 @@
1+{}:
2+let
3+ reflex-platform = import ./reflex-platform {};
4+in
5+{
6+ inherit (reflex-platform) project;
7+}
ghci-backendnew file+7
@@ -0,0 +1,7 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+
4+echo -ne '\033]0;'$0'\007'
5+nix-shell -A shells.ghc --run '
6+ cabal new-repl exe:backend
7+ '
ghcid-backendnew file+7
@@ -0,0 +1,7 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+
4+nix-shell -A shells.ghc --run '
5+ cd backend
6+ ghcid -W -c"date >> asdf; cabal new-repl exe:backend" --restart=../common/src
7+'
ghcid-frontendnew file+7
@@ -0,0 +1,7 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+
4+nix-shell -A shells.ghc --run '
5+ cd frontend
6+ ghcid -W -c"cabal new-repl exe:frontend"
7+'
ob-init.hsnew file+146
@@ -0,0 +1,146 @@
1+#! /usr/bin/env nix-shell
2+#! nix-shell "./script-env/ob-init.nix" -i "runghc"
3+--TODO: Don't depend on the user's environment - everything should be based on nixpkgs via reflex-platform
4+{-|
5+ Description: This script prompts user for the project name, and
6+ initializes the Obelisk submodules along with appropriate
7+ directory layout fit for best developer environment results.
8+ This script is to be used within an existing
9+ github repository and assumes that you have already
10+ configured/added your SSH key with both github and gitlab.
11+-}
12+
13+
14+{-# LANGUAGE OverloadedStrings #-}
15+{-# LANGUAGE LambdaCase #-}
16+{-# LANGUAGE TemplateHaskell #-}
17+
18+import System.Process (callProcess)
19+import System.Directory ( doesDirectoryExist
20+ , createDirectoryIfMissing
21+ , doesFileExist)
22+import Data.Text (Text)
23+import qualified Data.Text as Text
24+import qualified Data.Text.IO as Text
25+import Data.Monoid ((<>))
26+
27+main :: IO ()
28+main = do
29+ --TODO consider passing an arg instead of using a prompt
30+ putStr "Project name: "
31+ projectName <- Text.getLine
32+ doesDirectoryExist "obelisk" >>= \case
33+ True -> putStrLn "Skipping obelisk (already exists)"
34+ False -> do
35+ callProcess "git"
36+ [ "submodule"
37+ , "add"
38+ , "-b"
39+ , "develop"
40+ , "git@github.com:obsidiansystems/obelisk.git"
41+ ]
42+ callProcess "git"
43+ [ "submodule"
44+ , "update"
45+ , "--init"
46+ , "--recursive"
47+ ]
48+ mkdirs ["common/src", "frontend/src", "backend/src", "static", "config"]
49+ let defNix = "default.nix" :: FilePath
50+ let frontend = "frontend/src/Main.hs" :: FilePath
51+ let backend = "backend/src/Main.hs" :: FilePath
52+ createFileIfMissing defNix $ nixExpr projectName
53+ createFileIfMissing frontend frontSrc
54+ createFileIfMissing backend backSrc
55+
56+
57+--TODO: Consider using fileEmbed to generate default.nix in initializing folder
58+nixExpr :: Text -- ^ The name of the project; this must be a valid Cabal package name
59+ -> Text
60+nixExpr projectName = Text.unlines
61+ [ "{}: (import ./obelisk {}).mkDerivation {"
62+ , " name = \"" <> projectName <> "\";"
63+ , " version = \"0.1\";"
64+ , " commonDepends = p: with p; ["
65+ , " data-default"
66+ , " file-embed"
67+ , " ];"
68+ , " frontendDepends = p: with p; ["
69+ , " data-default"
70+ , " file-embed"
71+ , " obelisk-asset-th"
72+ , " ghcjs-dom"
73+ , " reflex"
74+ , " reflex-dom"
75+ , " these"
76+ , " ];"
77+ , " backendDepends = p: with p; ["
78+ , " data-default"
79+ , " resource-pool"
80+ , " snap"
81+ , " snap-core"
82+ , " snap-loader-static"
83+ , " snap-server"
84+ , " ];"
85+ , "}"
86+ ]
87+
88+
89+frontSrc :: Text
90+frontSrc = Text.unlines
91+ [ "{-# LANGUAGE OverloadedStrings #-}"
92+ , ""
93+ , "import Reflex.Dom"
94+ , "import GHCJS.DOM.Types (JSM, MonadJSM)"
95+ , ""
96+ , "#ifdef MIN_VERSION_jsaddle_warp"
97+ , "import Language.Javascript.JSaddle.Warp (run)"
98+ , "#endif"
99+ , ""
100+ , "#ifdef MIN_VERSION_jsaddle_wkwebview"
101+ , "import Language.Javascript.JSaddle.WKWebView (runFile)"
102+ , "#endif"
103+ , ""
104+ , "#if defined(__GHCJS__) && !defined(MIN_VERSION_jsaddle_warp) && !defined(MIN_VERSION_jsaddle_wkwebview)"
105+ , "runApp :: JSM () -> IO ()"
106+ , "runApp = id"
107+ , "#endif"
108+ , ""
109+ , "#ifdef MIN_VERSION_jsaddle_warp"
110+ , "runApp :: JSM () -> IO ()"
111+ , "runApp = run 3913"
112+ , "#endif"
113+ , ""
114+ , "#ifdef MIN_VERSION_jsaddle_wkwebview"
115+ , "runApp :: JSM () -> IO ()"
116+ , "runApp = runFile \"index.html\" \"\""
117+ , "#endif"
118+ , ""
119+ , "main = mainWidget $ text \"Hello new project\""
120+ ]
121+
122+backSrc :: Text
123+backSrc = Text.unlines
124+ [ "{-# LANGUAGE OverloadedStrings #-}"
125+ , ""
126+ , "import Data.Default"
127+ , "import Obelisk.Backend"
128+ , "import Obelisk.Backend.Snap"
129+ , "import Snap"
130+ , ""
131+ , "main :: IO ()"
132+ , "main = quickHttpServe $ rootHandler"
133+ , ""
134+ , "rootHandler :: Snap ()"
135+ , "rootHandler = route [(\"\", serveApp \"\" $ def)]"
136+ ]
137+
138+
139+mkdirs :: [FilePath] -> IO ()
140+mkdirs = mapM_ $ createDirectoryIfMissing True
141+
142+createFileIfMissing :: FilePath -> Text -> IO ()
143+createFileIfMissing aFile content =
144+ doesFileExist aFile >>= \case
145+ True -> putStrLn ("Skipping " ++ show aFile ++ "(already exist)")
146+ False -> Text.writeFile aFile content
script-env/default.nixnew file+5
@@ -0,0 +1,5 @@
1+{ compiler ? "ghc802" }:
2+let tryReflex = import ../reflex-platform {};
3+in { pkgs = tryReflex.nixpkgs.pkgs;
4+ ghcWithPackages = f: tryReflex.nixpkgs.pkgs.haskell.packages.${compiler}.ghcWithPackages (hkgs: with hkgs; [ ghcid ] ++ f hkgs);
5+}
script-env/ob-init.nixnew file+9
@@ -0,0 +1,9 @@
1+with import ./. {};
2+
3+let ghc = ghcWithPackages
4+ (hkgs: with hkgs; [ text ]);
5+in pkgs.stdenv.mkDerivation {
6+ name = "generate-env";
7+ buildInputs = [ ghc pkgs.cabal2nix ];
8+ shellHook = "eval $(egrep ^export ${ghc}/bin/ghc)";
9+}
script-env/parse-backend-listen.nixnew file+9
@@ -0,0 +1,9 @@
1+with import ./. {};
2+
3+let ghc = ghcWithPackages
4+ (hkgs: with hkgs; [ text time ]);
5+in pkgs.stdenv.mkDerivation {
6+ name = "generate-env";
7+ buildInputs = [ ghc pkgs.cabal2nix ];
8+ shellHook = "eval $(egrep ^export ${ghc}/bin/ghc)";
9+}