on master help sign in
Merge branch 'develop' into ae@static-which-prefetch
666a73bAlexandre Esteves
ChangeLog.md+7−1
@@ -5,10 +5,16 @@ This project's release branch is `master`. This log is written from the perspect
5## Unreleased
5## Unreleased
6
6
7* ([#715](https://github.com/obsidiansystems/obelisk/pull/715)) In `Obelisk.Route` deprecate `isoEncoder` and `prismEncoder` in favor of more precisely named `viewEncoder` and `reviewEncoder` (respectively) and improve documentation regarding contravariance of `reviewEncoder`.
7* ([#715](https://github.com/obsidiansystems/obelisk/pull/715)) In `Obelisk.Route` deprecate `isoEncoder` and `prismEncoder` in favor of more precisely named `viewEncoder` and `reviewEncoder` (respectively) and improve documentation regarding contravariance of `reviewEncoder`.
8+* ([#739](https://github.com/obsidiansystems/obelisk/pull/739)) Improve `ob shell` by allowing commands to be passed verbatim after a `--` argument. For example, `ob shell 'run command'` can now be written `ob shell -- run command`.
9+* ([#735](https://github.com/obsidiansystems/obelisk/pull/735)) Fix regression causing custom `Prelude`s to break `ob run`/`ob watch`/`ob repl`.
10+* ([#737](https://github.com/obsidiansystems/obelisk/pull/737)) Fix bug causing custom `Prelude`s to break `ob profile`.
11+* ([#742](https://github.com/obsidiansystems/obelisk/pull/742), [#57](https://github.com/obsidiansystems/obelisk/pull/57), [#406](https://github.com/obsidiansystems/obelisk/pull/406)) Enable `-dedupe` and `-DGHCJS_BROWSER` in GHCJS builds to make JavaScript output considerably smaller leading to faster load/parse times and faster build times.
12+* ([#742](https://github.com/obsidiansystems/obelisk/pull/742)) Update `reflex-platform` which includes:
13+ * A new version of GHCJS where `-dedupe` is fixed.
8
14
9## v0.8.0.0
15## v0.8.0.0
10
16
11−* ([#674](https://github.com/obsidiansystems/obelisk/pull/674), [#711](https://github.com/obsidiansystems/obelisk/pull/711)) Introduce a new thunk format to support accessing the thunk's source directly when packed. When packed, thunks have an additional file called `thunk.nix` and `default.nix` is now a think wrapper around that.
17+* ([#674](https://github.com/obsidiansystems/obelisk/pull/674), [#711](https://github.com/obsidiansystems/obelisk/pull/711)) Introduce a new thunk format to support accessing the thunk's source directly when packed. When packed, thunks have an additional file called `thunk.nix` and `default.nix` is now a thin wrapper around that.
12* ([#665](https://github.com/obsidiansystems/obelisk/pull/665)) Add `--interpret` and `--no-interpret` options to `ob run`/`ob watch`/`ob repl`/`ob shell`. These options allow you to pick which paths will be pre-compiled by `nix` when entering the shell/session and which won't. For example `ob run --no-interpret dep` will ensure that any dependencies found in `./dep` will be built by `nix` before loading the rest of the project into the `ghci` session. The same configuration for `ob shell` will ensure that those packages are built and available in the `ghc` package database inside the shell.
18* ([#665](https://github.com/obsidiansystems/obelisk/pull/665)) Add `--interpret` and `--no-interpret` options to `ob run`/`ob watch`/`ob repl`/`ob shell`. These options allow you to pick which paths will be pre-compiled by `nix` when entering the shell/session and which won't. For example `ob run --no-interpret dep` will ensure that any dependencies found in `./dep` will be built by `nix` before loading the rest of the project into the `ghci` session. The same configuration for `ob shell` will ensure that those packages are built and available in the `ghc` package database inside the shell.
13
19
14 **NOTE:** `ob shell`'s default behavior is now different. By default it now behaves like `ob run`/`ob watch`/`ob repl` in that it does *not* pre-build any packages whose `.cabal` or `package.yaml` files are found in the project. To regain the previous behavior, use `ob shell --no-interpret . --interpret backend --interpret common --interpret frontend` from the project root.
20 **NOTE:** `ob shell`'s default behavior is now different. By default it now behaves like `ob run`/`ob watch`/`ob repl` in that it does *not* pre-build any packages whose `.cabal` or `package.yaml` files are found in the project. To regain the previous behavior, use `ob shell --no-interpret . --interpret backend --interpret common --interpret frontend` from the project root.
default.nix+15−12
@@ -321,29 +321,32 @@ in rec {
321 __unstable__.profiledObRun = let
321 __unstable__.profiledObRun = let
322 profiled = projectOut { inherit system; enableLibraryProfiling = true; };
322 profiled = projectOut { inherit system; enableLibraryProfiling = true; };
323 exeSource = builtins.toFile "ob-run.hs" ''
323 exeSource = builtins.toFile "ob-run.hs" ''
324+ {-# LANGUAGE NoImplicitPrelude #-}
325+ {-# LANGUAGE PackageImports #-}
324 module Main where
326 module Main where
325
327
326− import Control.Exception
328+ -- Explicitly import Prelude from base lest there be multiple modules called Prelude
327− import Reflex.Profiled
329+ import "base" Prelude (IO, (++), read)
328− import System.Environment
329
330
331+ import "base" Control.Exception (finally)
332+ import "reflex" Reflex.Profiled (writeProfilingData)
333+ import "base" System.Environment (getArgs)
334+
330− import qualified Obelisk.Run
335+ import qualified "obelisk-run" Obelisk.Run
331 import qualified Frontend
336 import qualified Frontend
332 import qualified Backend
337 import qualified Backend
333
338
334 main :: IO ()
339 main :: IO ()
335 main = do
340 main = do
336− args <- getArgs
341+ [portStr, assets, profFileName] <- getArgs
337− let port = read $ args !! 0
338− assets = args !! 1
339− profileFile = (args !! 2) <> ".rprof"
340− Obelisk.Run.run port (Obelisk.Run.runServeAsset assets) Backend.backend Frontend.frontend `finally` writeProfilingData profileFile
342+ Obelisk.Run.run (read portStr) (Obelisk.Run.runServeAsset assets) Backend.backend Frontend.frontend
343+ `finally` writeProfilingData (profFileName ++ ".rprof")
341 '';
344 '';
342 in nixpkgs.runCommand "ob-run" {
345 in nixpkgs.runCommand "ob-run" {
343− buildInputs = [ (profiled.ghc.ghcWithPackages (p: [ p.backend p.frontend])) ];
346+ buildInputs = [ (profiled.ghc.ghcWithPackages (p: [p.backend p.frontend])) ];
344 } ''
347 } ''
345− cp ${exeSource} $PWD/ob-run.hs
348+ cp ${exeSource} ob-run.hs
346− mkdir -p $out/bin/
349+ mkdir -p $out/bin
347 ghc -x hs -prof -fno-prof-auto -threaded ob-run.hs -o $out/bin/ob-run
350 ghc -x hs -prof -fno-prof-auto -threaded ob-run.hs -o $out/bin/ob-run
348 '';
351 '';
349
352
dep/reflex-platform/default.nix+1−7
@@ -1,8 +1,2 @@
1# DO NOT HAND-EDIT THIS FILE
1# DO NOT HAND-EDIT THIS FILE
2−let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }:
2+import (import ./thunk.nix)
3− if !fetchSubmodules && !private then builtins.fetchTarball {
4− url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256;
5− } else (import <nixpkgs> {}).fetchFromGitHub {
6− inherit owner repo rev sha256 fetchSubmodules private;
7− };
8−in import (fetch (builtins.fromJSON (builtins.readFile ./github.json)))
dep/reflex-platform/github.json+3−3
@@ -1,8 +1,8 @@
1{
1{
2 "owner": "reflex-frp",
2 "owner": "reflex-frp",
3 "repo": "reflex-platform",
3 "repo": "reflex-platform",
4− "branch": "release/0.5.3.0",
4+ "branch": "develop",
5 "private": false,
5 "private": false,
6− "rev": "9779ea3b4c87fdc971057c561262696d5e9b1847",
6+ "rev": "c21ec7036c8351185cd2feef9ce577b6a61c4f22",
7− "sha256": "0v87ilal9355xwz8y9m0zh14pm9c0f7pqch0854kkj92ybc5l62q"
7+ "sha256": "0m4sdpz6qvngralpyprrbvsyi2zmfh2l3q5vhihwfp3842blvbfg"
8}
8}
dep/reflex-platform/thunk.nixnew file+9
@@ -0,0 +1,9 @@
1+# DO NOT HAND-EDIT THIS FILE
2+let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }:
3+ if !fetchSubmodules && !private then builtins.fetchTarball {
4+ url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256;
5+ } else (import <nixpkgs> {}).fetchFromGitHub {
6+ inherit owner repo rev sha256 fetchSubmodules private;
7+ };
8+ json = builtins.fromJSON (builtins.readFile ./github.json);
9+in fetch json
guides/app-deploy/README.md+14−8
@@ -1,11 +1,12 @@
1# Obelisk Application Deployment Guide
1# Obelisk Application Deployment Guide
2+
2This document serves two purposes, the first one is to guide new users that want to deploy Obelisk/Reflex apps and the second one to provide a walk-through for test driving Obelisk releases.
3This document serves two purposes, the first one is to guide new users that want to deploy Obelisk/Reflex apps and the second one to provide a walk-through for test driving Obelisk releases.
3
4
4−> **Note:** To complete this *entire* guide you need access to a macOS machine running the latest OSX release, a Linux machine (can be a VM on that mac) with Nix installed, an iPhone or iPad, and a recent Android device. It also assumes that you have Nix correctly set up and that your system is set up to fetch from binary caches instead of building everything on your machine. If you notice any of the commands below takes more than 5 minutes, then caches are not likely enabled.
5+> **Note:** This guide can be completed on a Linux host with Nix installed or a macOS host with Nix installed. Each section is labeled regarding which operating system hosts it supports. When going through the guide, start at the beginning and go through all sections that are supported on your host and merely skip sections that are not supported. The sections for iOS deployments require an iPhone or iPad device and the sections for Android deployments require an Android device. This guide assumes that you have Nix correctly set up and that your system is configured to fetch from binary caches instead of building everything on your machine. If you notice any of the commands below takes more than 5 minutes, then caches are not likely enabled.
5>
6>
6> Refer to the [Obelisk Installation Documentation](https://github.com/obsidiansystems/obelisk#installing-obelisk) for instructions on configuring the binary caches for any Nix-compatible setup.
7> Refer to the [Obelisk Installation Documentation](https://github.com/obsidiansystems/obelisk#installing-obelisk) for instructions on configuring the binary caches for any Nix-compatible setup.
7
8
8−## a) Get Obelisk
9+## a) Get Obelisk (Linux, Mac)
9
10
10There are several ways to install Obelisk, but the one we are going to use here allows us to test a single version of Obelisk in different ways. The approach is to clone Obelisk from it's GitHub repository and start a project that uses that local check out.
11There are several ways to install Obelisk, but the one we are going to use here allows us to test a single version of Obelisk in different ways. The approach is to clone Obelisk from it's GitHub repository and start a project that uses that local check out.
11
12
@@ -39,7 +40,7 @@ ob init --branch "$OBELISK_BRANCH"
39
40
40> **Note:** If the `--branch` parameter is not used, then Obelisk sets your project up to look at the `master` branch from GitHub. This is quite handy for real life projects but distracting for our test drive since we want to make sure any changes we do to the Obelisk codebase (like testing a pull request) are immediately picked up.
41> **Note:** If the `--branch` parameter is not used, then Obelisk sets your project up to look at the `master` branch from GitHub. This is quite handy for real life projects but distracting for our test drive since we want to make sure any changes we do to the Obelisk codebase (like testing a pull request) are immediately picked up.
41
42
42−## b) Run the Obelisk app on localhost
43+## b) Run the Obelisk app on localhost (Linux, Mac)
43
44
44Let's test that we can run a server on localhost. This is quite easy:
45Let's test that we can run a server on localhost. This is quite easy:
45
46
@@ -52,9 +53,10 @@ Now open a browser and point it to http://localhost:8000 (or just click on this
52
53
53![](assets/app-deploy.png)
54![](assets/app-deploy.png)
54
55
55−## c) Deploy the web app on a remote machine
56+## c) Prepare a VirtualBox deploy target (Linux, Mac)
56
57
57### Import the NixOS VirtualBox appliance
58### Import the NixOS VirtualBox appliance
59+
58Install [VirtualBox](https://www.virtualbox.org/) on your machine.
60Install [VirtualBox](https://www.virtualbox.org/) on your machine.
59
61
60On NixOS, do this by adding the following line to your `/etc/nixos/configuration.nix` before the last line containing `}`:
62On NixOS, do this by adding the following line to your `/etc/nixos/configuration.nix` before the last line containing `}`:
@@ -201,7 +203,7 @@ git remote add origin "$WORKDIR/myapp-git-remote"
201git push -u origin master
203git push -u origin master
202```
204```
203
205
204−### Deploy
206+### Initialize deployment directory
205
207
206With that, we can come back to the Obelisk app and initialize the deployment:
208With that, we can come back to the Obelisk app and initialize the deployment:
207
209
@@ -216,7 +218,11 @@ Then configure the deployment for VirtualBox:
216echo '{nixosPkgs, ...}: {...}: { imports = [ (nixosPkgs.path + /nixos/modules/virtualisation/virtualbox-image.nix) ]; }' > "$WORKDIR/myappdeploy/module.nix"
218echo '{nixosPkgs, ...}: {...}: { imports = [ (nixosPkgs.path + /nixos/modules/virtualisation/virtualbox-image.nix) ]; }' > "$WORKDIR/myappdeploy/module.nix"
217```
219```
218
220
219−And deploy:
221+## d) Deploy to VirtualBox target (Linux only)
222+
223+> Deploying requires a Linux host in order to build the Linux binaries.
224+
225+Now we can deploy to the VirtualBox VM.
220
226
221```bash
227```bash
222cd "$WORKDIR/myappdeploy"
228cd "$WORKDIR/myappdeploy"
@@ -243,7 +249,7 @@ It should look like this:
243
249
244Congratulations! You have deployed an Obelisk application to a remote server via SSH.
250Congratulations! You have deployed an Obelisk application to a remote server via SSH.
245
251
246−## d) Deploy an Android app (Linux host only)
252+## e) Deploy an Android app (Linux only)
247
253
248> **Note:** This section requires that you be running a Linux *host*.
254> **Note:** This section requires that you be running a Linux *host*.
249
255
@@ -286,7 +292,7 @@ When the deployment is complete opening the app should look something like
286
292
287Congratulations! You have deployed an Obelisk Android app via USB.
293Congratulations! You have deployed an Obelisk Android app via USB.
288
294
289−## e) Deploy an iOS app (macOS host only)
295+## f) Deploy an iOS app (Mac only)
290
296
291> **Note:** This section requires that you be running a macOS *host*.
297> **Note:** This section requires that you be running a macOS *host*.
292
298
lib/asset/manifest/obelisk-asset-manifest.cabal+1−1
@@ -24,7 +24,7 @@ library
24 , template-haskell
24 , template-haskell
25 , text
25 , text
26 , transformers
26 , transformers
27− , unix
27+ , unix-compat
28 , vector
28 , vector
29 exposed-modules:
29 exposed-modules:
30 Obelisk.Asset.Gather
30 Obelisk.Asset.Gather
lib/asset/manifest/src/Obelisk/Asset/Symlink.hs+1−1
@@ -7,7 +7,7 @@ import Data.Map (Map)
7import qualified Data.Map as Map
7import qualified Data.Map as Map
8import System.Directory
8import System.Directory
9import System.FilePath.Posix
9import System.FilePath.Posix
10−import System.Posix.Files
10+import System.PosixCompat.Files
11
11
12-- | Copy the given hashed files from one location to hashed paths in another
12-- | Copy the given hashed files from one location to hashed paths in another
13-- location, and symlink the unhashed paths to the hashed ones
13-- location, and symlink the unhashed paths to the hashed ones
lib/asset/serve-snap/obelisk-asset-serve-snap.cabal+1−1
@@ -23,7 +23,7 @@ library
23 , obelisk-snap-extras
23 , obelisk-snap-extras
24 , text
24 , text
25 , transformers
25 , transformers
26− , unix
26+ , unix-compat
27 exposed-modules:
27 exposed-modules:
28 Obelisk.Asset.Accept
28 Obelisk.Asset.Accept
29 Obelisk.Asset.Serve.Snap
29 Obelisk.Asset.Serve.Snap
lib/asset/serve-snap/src/Obelisk/Asset/Serve/Snap.hs+1−1
@@ -31,7 +31,7 @@ import Data.Text.Encoding (decodeUtf8, encodeUtf8)
31import System.Directory (getDirectoryContents)
31import System.Directory (getDirectoryContents)
32import System.FilePath ((</>), splitFileName, takeDirectory)
32import System.FilePath ((</>), splitFileName, takeDirectory)
33import System.IO.Error (isDoesNotExistError)
33import System.IO.Error (isDoesNotExistError)
34−import System.Posix (getFileStatus, fileSize)
34+import System.PosixCompat.Files (getFileStatus, fileSize)
35
35
36-- | Serve static assets from an asset directory generated via @assets.nix@ or, failing that, from a regular directory.
36-- | Serve static assets from an asset directory generated via @assets.nix@ or, failing that, from a regular directory.
37--
37--
lib/cliapp/obelisk-cliapp.cabal+2
@@ -19,10 +19,12 @@ library
19 , monad-loops
19 , monad-loops
20 , mtl
20 , mtl
21 , process
21 , process
22+ , shell-escape
22 , terminal-size
23 , terminal-size
23 , text
24 , text
24 , time
25 , time
25 , transformers
26 , transformers
27+ , utf8-string
26 exposed-modules:
28 exposed-modules:
27 Obelisk.CliApp
29 Obelisk.CliApp
28 other-modules:
30 other-modules:
lib/cliapp/src/Obelisk/CliApp/Process.hs+4−2
@@ -38,6 +38,7 @@ import Control.Monad.IO.Class (MonadIO, liftIO)
38import Control.Lens (Prism', review)
38import Control.Lens (Prism', review)
39import qualified Data.ByteString as BS
39import qualified Data.ByteString as BS
40import qualified Data.ByteString.Char8 as BSC
40import qualified Data.ByteString.Char8 as BSC
41+import qualified Data.ByteString.UTF8 as BSU
41import Data.Function (fix)
42import Data.Function (fix)
42import Data.Map (Map)
43import Data.Map (Map)
43import qualified Data.Map as Map
44import qualified Data.Map as Map
@@ -54,6 +55,7 @@ import qualified System.IO.Streams as Streams
54import System.IO.Streams.Concurrent (concurrentMerge)
55import System.IO.Streams.Concurrent (concurrentMerge)
55import System.Process (CreateProcess, ProcessHandle, StdStream (CreatePipe), std_err, std_out)
56import System.Process (CreateProcess, ProcessHandle, StdStream (CreatePipe), std_err, std_out)
56import qualified System.Process as Process
57import qualified System.Process as Process
58+import Text.ShellEscape (bash, bytes)
57import qualified Data.Aeson as Aeson
59import qualified Data.Aeson as Aeson
58
60
59import Control.Monad.Log (Severity (..))
61import Control.Monad.Log (Severity (..))
@@ -246,8 +248,8 @@ reconstructCommand p = case p of
246 Process.ShellCommand str -> T.pack str
248 Process.ShellCommand str -> T.pack str
247 Process.RawCommand c as -> processToShellString c as
249 Process.RawCommand c as -> processToShellString c as
248 where
250 where
249− processToShellString cmd args = T.unwords $ map quoteAndEscape (cmd : args)
251+ processToShellString cmd args = T.pack $ unwords $
250− quoteAndEscape x = "'" <> T.replace "'" "'\''" (T.pack x) <> "'"
252+ map (BSU.toString . bytes . bash . BSU.fromString) (cmd : args)
251
253
252reconstructProcSpec :: ProcessSpec -> Text
254reconstructProcSpec :: ProcessSpec -> Text
253reconstructProcSpec = reconstructCommand . Process.cmdspec . _processSpec_createProcess
255reconstructProcSpec = reconstructCommand . Process.cmdspec . _processSpec_createProcess
lib/command/obelisk-command.cabal+3−1
@@ -39,13 +39,15 @@ library
39 , optparse-applicative
39 , optparse-applicative
40 , placeholders
40 , placeholders
41 , process
41 , process
42+ , shell-escape
42 , temporary
43 , temporary
43 , terminal-size
44 , terminal-size
44 , text
45 , text
45 , time
46 , time
46 , transformers
47 , transformers
47− , unix
48+ , unix-compat
48 , unordered-containers
49 , unordered-containers
50+ , utf8-string
49 , which
51 , which
50 , yaml
52 , yaml
51 exposed-modules:
53 exposed-modules:
lib/command/src/Obelisk/Command.hs+10−6
@@ -22,7 +22,7 @@ import System.Environment
22import System.FilePath
22import System.FilePath
23import qualified System.Info
23import qualified System.Info
24import System.IO (hIsTerminalDevice, stdout)
24import System.IO (hIsTerminalDevice, stdout)
25−import System.Posix.Process (executeFile)
25+import System.Process (rawSystem)
26
26
27import Obelisk.App
27import Obelisk.App
28import Obelisk.CliApp
28import Obelisk.CliApp
@@ -114,7 +114,7 @@ obCommand cfg = hsubparser
114 , command "thunk" $ info (ObCommand_Thunk <$> thunkOption) $ progDesc "Manipulate thunk directories"
114 , command "thunk" $ info (ObCommand_Thunk <$> thunkOption) $ progDesc "Manipulate thunk directories"
115 , command "repl" $ info (ObCommand_Repl <$> interpretOpts) $ progDesc "Open an interactive interpreter"
115 , command "repl" $ info (ObCommand_Repl <$> interpretOpts) $ progDesc "Open an interactive interpreter"
116 , command "watch" $ info (ObCommand_Watch <$> interpretOpts) $ progDesc "Watch current project for errors and warnings"
116 , command "watch" $ info (ObCommand_Watch <$> interpretOpts) $ progDesc "Watch current project for errors and warnings"
117− , command "shell" $ info (ObCommand_Shell <$> shellOpts) $ progDesc "Enter a shell with project dependencies"
117+ , command "shell" $ info (ObCommand_Shell <$> shellOpts) $ progDesc "Enter a shell with project dependencies or run a command in such a shell. E.g. ob shell -- ghc-pkg list"
118 , command "doc" $ info (ObCommand_Doc <$> shellFlags <*> packageNames) $
118 , command "doc" $ info (ObCommand_Doc <$> shellFlags <*> packageNames) $
119 progDesc "List paths to haddock documentation for specified packages"
119 progDesc "List paths to haddock documentation for specified packages"
120 <> footerDoc (Just $
120 <> footerDoc (Just $
@@ -285,7 +285,10 @@ shellOpts :: Parser ShellOpts
285shellOpts = ShellOpts
285shellOpts = ShellOpts
286 <$> shellFlags
286 <$> shellFlags
287 <*> interpretOpts
287 <*> interpretOpts
288+ -- This funny construction is used to support optparse-applicative's @--@ parsing.
289+ -- All arguments after @--@ are left unparsed and instead provided to the last positional parser
290+ -- which must therefore be 'many' in order to consume the rest of the input.
288− <*> optional (strArgument (metavar "COMMAND"))
291+ <*> ((\xs -> if null xs then Nothing else Just $ unwords xs) <$> many (strArgument (metavar "COMMAND")))
289
292
290portOpt :: Int -> Parser Int
293portOpt :: Int -> Parser Int
291portOpt dfault = option auto (long "port" <> short 'p' <> help "Port number for server" <> showDefault <> value dfault <> metavar "INT")
294portOpt dfault = option auto (long "port" <> short 'p' <> help "Port number for server" <> showDefault <> value dfault <> metavar "INT")
@@ -363,7 +366,8 @@ main' argsCfg = do
363 Just impl -> do
366 Just impl -> do
364 -- Invoke the real implementation, using --no-handoff to prevent infinite recursion
367 -- Invoke the real implementation, using --no-handoff to prevent infinite recursion
365 putLog Debug $ "Handing off to " <> T.pack impl
368 putLog Debug $ "Handing off to " <> T.pack impl
366− liftIO $ executeFile impl False ("--no-handoff" : myArgs) Nothing
369+ _ <- liftIO $ rawSystem impl ("--no-handoff" : myArgs)
370+ return ()
367 case myArgs of
371 case myArgs of
368 "--no-handoff" : as -> go as -- If we've been told not to hand off, don't hand off
372 "--no-handoff" : as -> go as -- If we've been told not to hand off, don't hand off
369 origPath:inPath:outPath:preprocessorName:packagePaths
373 origPath:inPath:outPath:preprocessorName:packagePaths
@@ -398,11 +402,11 @@ ob = \case
398 ObCommand_Repl interpretPathsList -> withInterpretPaths interpretPathsList runRepl
402 ObCommand_Repl interpretPathsList -> withInterpretPaths interpretPathsList runRepl
399 ObCommand_Watch interpretPathsList -> withInterpretPaths interpretPathsList runWatch
403 ObCommand_Watch interpretPathsList -> withInterpretPaths interpretPathsList runWatch
400 ObCommand_Shell (ShellOpts shellAttr interpretPathsList cmd) -> withInterpretPaths interpretPathsList $ \root interpretPaths ->
404 ObCommand_Shell (ShellOpts shellAttr interpretPathsList cmd) -> withInterpretPaths interpretPathsList $ \root interpretPaths ->
401− nixShellForInterpretPaths False shellAttr root interpretPaths cmd
405+ nixShellForInterpretPaths False shellAttr root interpretPaths cmd -- N.B. We do NOT bash escape here; we want to run the command as-is
402 ObCommand_Doc shellAttr pkgs -> withInterpretPaths [] $ \root interpretPaths ->
406 ObCommand_Doc shellAttr pkgs -> withInterpretPaths [] $ \root interpretPaths ->
403 nixShellForInterpretPaths True shellAttr root interpretPaths $ Just $ haddockCommand pkgs
407 nixShellForInterpretPaths True shellAttr root interpretPaths $ Just $ haddockCommand pkgs
404 ObCommand_Hoogle shell' port -> withProjectRoot "." $ \root -> do
408 ObCommand_Hoogle shell' port -> withProjectRoot "." $ \root -> do
405− nixShellWithHoogle root True shell' $ Just $ "hoogle server -p " <> show port <> " --local"
409+ nixShellWithHoogle root True shell' $ Just $ "hoogle server -p" <> show port <> " --local"
406 ObCommand_Internal icmd -> case icmd of
410 ObCommand_Internal icmd -> case icmd of
407 ObInternal_ApplyPackages origPath inPath outPath packagePaths -> do
411 ObInternal_ApplyPackages origPath inPath outPath packagePaths -> do
408 liftIO $ Preprocessor.applyPackages origPath inPath outPath packagePaths
412 liftIO $ Preprocessor.applyPackages origPath inPath outPath packagePaths
lib/command/src/Obelisk/Command/Deploy.hs+1−1
@@ -25,7 +25,7 @@ import GHC.Generics
25import System.Directory
25import System.Directory
26import System.FilePath
26import System.FilePath
27import System.IO
27import System.IO
28−import System.Posix.Files
28+import System.PosixCompat.Files
29import Text.URI (URI)
29import Text.URI (URI)
30import qualified Text.URI as URI
30import qualified Text.URI as URI
31import Text.URI.Lens
31import Text.URI.Lens
lib/command/src/Obelisk/Command/Project.hs+14−7
@@ -15,6 +15,7 @@ module Obelisk.Command.Project
15 , toImplDir
15 , toImplDir
16 , toObeliskDir
16 , toObeliskDir
17 , withProjectRoot
17 , withProjectRoot
18+ , bashEscape
18 ) where
19 ) where
19
20
20import Control.Concurrent.MVar (MVar, newMVar, withMVarMasked)
21import Control.Concurrent.MVar (MVar, newMVar, withMVarMasked)
@@ -23,6 +24,7 @@ import Control.Monad
23import Control.Monad.IO.Class (liftIO)
24import Control.Monad.IO.Class (liftIO)
24import Control.Monad.State
25import Control.Monad.State
25import qualified Data.Aeson as Json
26import qualified Data.Aeson as Json
27+import qualified Data.ByteString.UTF8 as BSU
26import Data.Bits
28import Data.Bits
27import qualified Data.ByteString.Lazy as BSL
29import qualified Data.ByteString.Lazy as BSL
28import Data.Default (def)
30import Data.Default (def)
@@ -30,15 +32,17 @@ import Data.Function ((&), on)
30import Data.Map (Map)
32import Data.Map (Map)
31import Data.Text (Text)
33import Data.Text (Text)
32import qualified Data.Text as T
34import qualified Data.Text as T
33−import Data.Text.Encoding (decodeUtf8)
35+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
34import Data.Traversable (for)
36import Data.Traversable (for)
35import System.Directory
37import System.Directory
36import System.Environment (lookupEnv)
38import System.Environment (lookupEnv)
37import System.FilePath
39import System.FilePath
38import System.IO.Temp
40import System.IO.Temp
39import System.IO.Unsafe (unsafePerformIO)
41import System.IO.Unsafe (unsafePerformIO)
40−import System.Posix (FileStatus, FileMode, CMode (..), UserID, deviceID, fileID, fileMode, fileOwner, getFileStatus, getRealUserID)
42+import System.PosixCompat.Files
41−import System.Posix.Files
43+import System.PosixCompat.Types
44+import System.PosixCompat.User
45+import Text.ShellEscape (bash, bytes)
42
46
43import GitHub.Data.GitData (Branch)
47import GitHub.Data.GitData (Branch)
44import GitHub.Data.Name (Name)
48import GitHub.Data.Name (Name)
@@ -278,12 +282,15 @@ nixShellRunConfig root isPure command = do
278 pure $ def
282 pure $ def
279 & nixShellConfig_pure .~ isPure
283 & nixShellConfig_pure .~ isPure
280 & nixShellConfig_common . nixCmdConfig_target .~ (def & target_path .~ Nothing)
284 & nixShellConfig_common . nixCmdConfig_target .~ (def & target_path .~ Nothing)
281− & nixShellConfig_run .~ (command <&> \c -> mconcat
285+ & nixShellConfig_run .~ (command <&> \cs -> unwords $ concat
282− [ "export NIX_PATH=nixpkgs=", T.unpack nixpkgsPath, "; "
286+ [ ["export", BSU.toString . bytes . bash $ "NIX_PATH=nixpkgs=" <> encodeUtf8 nixpkgsPath, ";"]
283− , maybe "" (\v -> "export NIX_REMOTE=" <> v <> "; ") nixRemote
287+ , maybe [] (\v -> ["export", BSU.toString . bytes . bash $ "NIX_REMOTE=" <> encodeUtf8 (T.pack v), ";"]) nixRemote
284− , c
288+ , [cs]
285 ])
289 ])
286
290
291+bashEscape :: String -> String
292+bashEscape = BSU.toString . bytes . bash . BSU.fromString
293+
287nixShellRunProc :: NixShellConfig -> ProcessSpec
294nixShellRunProc :: NixShellConfig -> ProcessSpec
288nixShellRunProc cfg = setDelegateCtlc True $ proc "nix-shell" $ runNixShellConfig cfg
295nixShellRunProc cfg = setDelegateCtlc True $ proc "nix-shell" $ runNixShellConfig cfg
289
296
lib/command/src/Obelisk/Command/Run.hs+57−42
@@ -25,12 +25,14 @@ import Data.Default (def)
25import Data.Either (partitionEithers)
25import Data.Either (partitionEithers)
26import Data.Foldable (fold, for_, toList)
26import Data.Foldable (fold, for_, toList)
27import Data.Functor.Identity (runIdentity)
27import Data.Functor.Identity (runIdentity)
28+import Data.List (intercalate)
28import Data.List.NonEmpty (NonEmpty)
29import Data.List.NonEmpty (NonEmpty)
29import qualified Data.List.NonEmpty as NE
30import qualified Data.List.NonEmpty as NE
30import Data.Map (Map)
31import Data.Map (Map)
31import qualified Data.Map as Map
32import qualified Data.Map as Map
32import qualified Data.Map.Monoidal as MMap
33import qualified Data.Map.Monoidal as MMap
33−import Data.Maybe
34+import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
35+import Data.Ord (comparing)
34import Data.Set (Set)
36import Data.Set (Set)
35import qualified Data.Set as Set
37import qualified Data.Set as Set
36import Data.String.Here.Interpolated (i)
38import Data.String.Here.Interpolated (i)
@@ -44,17 +46,17 @@ import Distribution.Compiler (CompilerFlavor(..))
44import Distribution.PackageDescription.Parsec (parseGenericPackageDescription)
46import Distribution.PackageDescription.Parsec (parseGenericPackageDescription)
45import Distribution.Parsec.ParseResult (runParseResult)
47import Distribution.Parsec.ParseResult (runParseResult)
46import qualified Distribution.System as Dist
48import qualified Distribution.System as Dist
47−import Distribution.Types.BuildInfo
49+import Distribution.Types.BuildInfo (buildable, defaultExtensions, defaultLanguage, hsSourceDirs, options)
48−import Distribution.Types.CondTree
50+import Distribution.Types.CondTree (simplifyCondTree)
49−import Distribution.Types.GenericPackageDescription
51+import Distribution.Types.GenericPackageDescription (ConfVar (Arch, Impl, OS), condLibrary)
50−import Distribution.Types.Library
52+import Distribution.Types.Library (libBuildInfo)
51−import Distribution.Utils.Generic
53+import Distribution.Utils.Generic (toUTF8BS, readUTF8File)
52import qualified Distribution.Parsec.Common as Dist
54import qualified Distribution.Parsec.Common as Dist
53import qualified Hpack.Config as Hpack
55import qualified Hpack.Config as Hpack
54import qualified Hpack.Render as Hpack
56import qualified Hpack.Render as Hpack
55import qualified Hpack.Yaml as Hpack
57import qualified Hpack.Yaml as Hpack
56−import Language.Haskell.Extension
58+import Language.Haskell.Extension (Extension, Language)
57−import Network.Socket hiding (Debug)
59+import qualified Network.Socket as Socket
58import System.Directory
60import System.Directory
59import System.Environment (getExecutablePath)
61import System.Environment (getExecutablePath)
60import System.FilePath
62import System.FilePath
@@ -76,7 +78,7 @@ import Obelisk.CliApp (
76 withSpinner,
78 withSpinner,
77 )
79 )
78import Obelisk.Command.Nix
80import Obelisk.Command.Nix
79−import Obelisk.Command.Project (nixShellWithoutPkgs, withProjectRoot, findProjectAssets)
81+import Obelisk.Command.Project (nixShellWithoutPkgs, withProjectRoot, findProjectAssets, bashEscape)
80import Obelisk.Command.Thunk (attrCacheFileName)
82import Obelisk.Command.Thunk (attrCacheFileName)
81import Obelisk.Command.Utils (findExePath, ghcidExePath)
83import Obelisk.Command.Utils (findExePath, ghcidExePath)
82
84
@@ -161,12 +163,12 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
161run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
163run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
162run root interpretPaths = do
164run root interpretPaths = do
163 pkgs <- getParsedLocalPkgs root interpretPaths
165 pkgs <- getParsedLocalPkgs root interpretPaths
164− withGhciScript pkgs $ \dotGhciPath -> do
165− assets <- findProjectAssets root
166+ assets <- findProjectAssets root
166− putLog Debug $ "Assets impurely loaded from: " <> assets
167+ putLog Debug $ "Assets impurely loaded from: " <> assets
167− ghciArgs <- getGhciSessionSettings pkgs root True
168+ ghciArgs <- getGhciSessionSettings pkgs root True
168− freePort <- getFreePort
169+ freePort <- getFreePort
170+ withGhciScriptArgs pkgs $ \dotGhciArgs -> do
169− runGhcid root True (ghciArgs <> mkGhciScriptArg dotGhciPath) pkgs $ Just $ unwords
171+ runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
170 [ "Obelisk.Run.run"
172 [ "Obelisk.Run.run"
171 , show freePort
173 , show freePort
172 , "(Obelisk.Run.runServeAsset " ++ show assets ++ ")"
174 , "(Obelisk.Run.runServeAsset " ++ show assets ++ ")"
@@ -178,15 +180,15 @@ runRepl :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
178runRepl root interpretPaths = do
180runRepl root interpretPaths = do
179 pkgs <- getParsedLocalPkgs root interpretPaths
181 pkgs <- getParsedLocalPkgs root interpretPaths
180 ghciArgs <- getGhciSessionSettings pkgs "." True
182 ghciArgs <- getGhciSessionSettings pkgs "." True
181− withGhciScript pkgs $ \dotGhciPath ->
183+ withGhciScriptArgs pkgs $ \dotGhciArgs ->
182− runGhciRepl root pkgs (ghciArgs <> mkGhciScriptArg dotGhciPath)
184+ runGhciRepl root pkgs (ghciArgs <> dotGhciArgs)
183
185
184runWatch :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
186runWatch :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
185runWatch root interpretPaths = do
187runWatch root interpretPaths = do
186 pkgs <- getParsedLocalPkgs root interpretPaths
188 pkgs <- getParsedLocalPkgs root interpretPaths
187 ghciArgs <- getGhciSessionSettings pkgs root True
189 ghciArgs <- getGhciSessionSettings pkgs root True
188− withGhciScript pkgs $ \dotGhciPath ->
190+ withGhciScriptArgs pkgs $ \dotGhciArgs ->
189− runGhcid root True (ghciArgs <> mkGhciScriptArg dotGhciPath) pkgs Nothing
191+ runGhcid root True (ghciArgs <> dotGhciArgs) pkgs Nothing
190
192
191exportGhciConfig :: MonadObelisk m => Bool -> FilePath -> PathTree Interpret -> m [String]
193exportGhciConfig :: MonadObelisk m => Bool -> FilePath -> PathTree Interpret -> m [String]
192exportGhciConfig useRelativePaths root interpretPaths = do
194exportGhciConfig useRelativePaths root interpretPaths = do
@@ -393,13 +395,29 @@ parsePackagesOrFail dirs' = do
393packageInfoToNamePathMap :: Foldable f => f CabalPackageInfo -> Map Text FilePath
395packageInfoToNamePathMap :: Foldable f => f CabalPackageInfo -> Map Text FilePath
394packageInfoToNamePathMap = Map.fromList . map (_cabalPackageInfo_packageName &&& _cabalPackageInfo_packageRoot) . toList
396packageInfoToNamePathMap = Map.fromList . map (_cabalPackageInfo_packageName &&& _cabalPackageInfo_packageRoot) . toList
395
397
398+-- Like 'withGhciScript' but provides the precise ghci arguments to add to a ghci session
399+withGhciScriptArgs
400+ :: (MonadObelisk m, Foldable f)
401+ => f CabalPackageInfo -- ^ List of packages to load into ghci
402+ -> ([String] -> m ()) -- ^ Action to run with the extra ghci arguments
403+ -> m ()
404+withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp -> f ["-XNoImplicitPrelude", "-ghci-script", fp]
405+ where
406+ -- These lines must be first and allow the session to support a custom Prelude when @-XNoImplicitPrelude@
407+ -- is passed to the ghci session.
408+ loadPreludeManually =
409+ [ ":add Prelude" -- @:add@ is used because it's less noisy when there is no custom Prelude
410+ , ":set -XImplicitPrelude" -- Turn the default setting on
411+ ]
412+
396-- | Create ghci configuration to load the given packages
413-- | Create ghci configuration to load the given packages
397withGhciScript
414withGhciScript
398 :: (MonadObelisk m, Foldable f)
415 :: (MonadObelisk m, Foldable f)
416+ => [String] -- ^ Commands to prefix to file
399− => f CabalPackageInfo -- ^ List of packages to load into ghci
417+ -> f CabalPackageInfo -- ^ List of packages to load into ghci
400 -> (FilePath -> m ()) -- ^ Action to run with the path to generated temporary .ghci
418 -> (FilePath -> m ()) -- ^ Action to run with the path to generated temporary .ghci
401 -> m ()
419 -> m ()
402−withGhciScript (toList -> packageInfos) f =
420+withGhciScript preCommands (toList -> packageInfos) f =
403 withSystemTempDirectory "ob-ghci" $ \fp -> do
421 withSystemTempDirectory "ob-ghci" $ \fp -> do
404 let dotGhciPath = fp </> ".ghci"
422 let dotGhciPath = fp </> ".ghci"
405 liftIO $ writeFile dotGhciPath dotGhci
423 liftIO $ writeFile dotGhciPath dotGhci
@@ -411,7 +429,8 @@ withGhciScript (toList -> packageInfos) f =
411 , [ "Backend" | "backend" `Set.member` packageNames ]
429 , [ "Backend" | "backend" `Set.member` packageNames ]
412 , [ "Frontend" | "frontend" `Set.member` packageNames ]
430 , [ "Frontend" | "frontend" `Set.member` packageNames ]
413 ]
431 ]
414− dotGhci = unlines
432+ dotGhci = unlines $
433+ preCommands <>
415 [ if null modulesToLoad then "" else ":load " <> unwords modulesToLoad
434 [ if null modulesToLoad then "" else ":load " <> unwords modulesToLoad
416 , "import qualified Obelisk.Run"
435 , "import qualified Obelisk.Run"
417 , "import qualified Frontend"
436 , "import qualified Frontend"
@@ -464,7 +483,7 @@ runGhciRepl root (toList -> packages) ghciArgs =
464 -- NOTE: We do *not* want to use $(staticWhich "ghci") here because we need the
483 -- NOTE: We do *not* want to use $(staticWhich "ghci") here because we need the
465 -- ghc that is provided by the shell in the user's project.
484 -- ghc that is provided by the shell in the user's project.
466 nixShellWithoutPkgs root True False (packageInfoToNamePathMap packages) "ghc" $
485 nixShellWithoutPkgs root True False (packageInfoToNamePathMap packages) "ghc" $
467− Just $ unwords $ "ghci" : ghciArgs -- TODO: Shell escape
486+ Just $ unwords $ fmap bashEscape $ "ghci" : ghciArgs
468
487
469-- | Run ghcid
488-- | Run ghcid
470runGhcid
489runGhcid
@@ -477,32 +496,28 @@ runGhcid
477 -> m ()
496 -> m ()
478runGhcid root chdirToRoot ghciArgs (toList -> packages) mcmd =
497runGhcid root chdirToRoot ghciArgs (toList -> packages) mcmd =
479 nixShellWithoutPkgs root True chdirToRoot (packageInfoToNamePathMap packages) "ghc" $
498 nixShellWithoutPkgs root True chdirToRoot (packageInfoToNamePathMap packages) "ghc" $
480− Just $ unwords $ ghcidExePath : opts -- TODO: Shell escape
499+ Just $ unwords $ fmap bashEscape $ ghcidExePath : opts
481 where
500 where
482− opts =
501+ opts = concat
483− [ "-W"
502+ [ ["-W"]
484− , "--outputfile=ghcid-output.txt"
503+ , ["--outputfile=ghcid-output.txt"]
485− ] <> map (\x -> "--reload='" <> x <> "'") reloadFiles
504+ , map (\x -> "--reload=" <> x) reloadFiles
486− <> map (\x -> "--restart='" <> x <> "'") restartFiles
505+ , map (\x -> "--restart=" <> x) restartFiles
487− <> testCmd
506+ , maybe [] (\cmd -> ["--test=" <> cmd]) mcmd
488− <> ["--command='" <> unwords ("ghci" : ghciArgs) <> "'"] -- TODO: Shell escape
507+ , ["--command=" <> unwords ("ghci" : ghciArgs)]
489− testCmd = maybeToList (flip fmap mcmd $ \cmd -> "--test='" <> cmd <> "'") -- TODO: Shell escape
508+ ]
490−
491 adjustRoot x = if chdirToRoot then makeRelative root x else x
509 adjustRoot x = if chdirToRoot then makeRelative root x else x
492 reloadFiles = map adjustRoot [root </> "config"]
510 reloadFiles = map adjustRoot [root </> "config"]
493 restartFiles = map (adjustRoot . _cabalPackageInfo_packageFile) packages
511 restartFiles = map (adjustRoot . _cabalPackageInfo_packageFile) packages
494
512
495−mkGhciScriptArg :: FilePath -> [String]
496−mkGhciScriptArg dotGhci = ["-ghci-script", dotGhci]
497−
498−getFreePort :: MonadIO m => m PortNumber
513+getFreePort :: MonadIO m => m Socket.PortNumber
499−getFreePort = liftIO $ withSocketsDo $ do
514+getFreePort = liftIO $ Socket.withSocketsDo $ do
500− addr:_ <- getAddrInfo (Just defaultHints) (Just "127.0.0.1") (Just "0")
515+ addr:_ <- Socket.getAddrInfo (Just Socket.defaultHints) (Just "127.0.0.1") (Just "0")
501− bracket (open addr) close socketPort
516+ bracket (open addr) Socket.close Socket.socketPort
502 where
517 where
503 open addr = do
518 open addr = do
504− sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
519+ sock <- Socket.socket (Socket.addrFamily addr) (Socket.addrSocketType addr) (Socket.addrProtocol addr)
505− bind sock (addrAddress addr)
520+ Socket.bind sock (Socket.addrAddress addr)
506 return sock
521 return sock
507
522
508
523
lib/command/src/Obelisk/Command/Thunk.hs+1−1
@@ -57,7 +57,7 @@ import System.Exit
57import System.FilePath
57import System.FilePath
58import System.IO.Error
58import System.IO.Error
59import System.IO.Temp
59import System.IO.Temp
60−import System.Posix (getSymbolicLinkStatus, modificationTime)
60+import System.PosixCompat.Files (getSymbolicLinkStatus, modificationTime)
61import System.Which (staticWhich)
61import System.Which (staticWhich)
62import qualified Text.URI as URI
62import qualified Text.URI as URI
63
63
lib/selftest/src/Obelisk/SelfTest.hs+6−1
@@ -243,7 +243,7 @@ main' isVerbose httpManager obeliskRepoReadOnly = withInitCache $ \initCache ->
243 uu <- update
243 uu <- update
244 assertRevEQ u uu
244 assertRevEQ u uu
245
245
246− it "can run 'ob doc'" $ inTmpObInit $ \_ -> runOb ["doc", "reflex"]
246+ it "can run 'ob doc'" $ inTmpObInit $ \_ -> runOb_ ["doc", "reflex"]
247
247
248 describe "ob thunk pack/unpack" $ parallel $ do
248 describe "ob thunk pack/unpack" $ parallel $ do
249 it "has thunk pack and unpack inverses" $ inTmpObInitWithImplCopy $ \_ -> do
249 it "has thunk pack and unpack inverses" $ inTmpObInitWithImplCopy $ \_ -> do
@@ -306,6 +306,11 @@ main' isVerbose httpManager obeliskRepoReadOnly = withInitCache $ \initCache ->
306 void $ errExit False $ runOb ["thunk", "update", toTextIgnore dir, "--branch", "dumble-palooza"]
306 void $ errExit False $ runOb ["thunk", "update", toTextIgnore dir, "--branch", "dumble-palooza"]
307 checkDir dir >>= liftIO . assertEqual "" startingContents
307 checkDir dir >>= liftIO . assertEqual "" startingContents
308
308
309+ describe "ob shell" $ parallel $ do
310+ it "works with --" $ inTmpObInit $ \_ -> do
311+ output <- runOb ["shell", "--", "ghc-pkg", "list"]
312+ liftIO $ assertBool "Unexpected output from ob shell" $ ("Cabal-" `T.isInfixOf` output) && ("ghc-" `T.isInfixOf` output)
313+
309 describe "ob hoogle" $ {- NOT parallel -} do
314 describe "ob hoogle" $ {- NOT parallel -} do
310 it "starts a hoogle server on the given port" $ inTmpObInit $ \_ -> do
315 it "starts a hoogle server on the given port" $ inTmpObInit $ \_ -> do
311 [p0] <- liftIO $ getFreePorts 1
316 [p0] <- liftIO $ getFreePorts 1
lib/snap-extras/obelisk-snap-extras.cabal−1
@@ -12,7 +12,6 @@ library
12 , base
12 , base
13 , bytestring
13 , bytestring
14 , snap-core
14 , snap-core
15− , unix
16 , directory
15 , directory
17 , filepath
16 , filepath
18 , text
17 , text
skeleton/common/common.cabal+1
@@ -12,3 +12,4 @@ library
12 exposed-modules:
12 exposed-modules:
13 Common.Api
13 Common.Api
14 Common.Route
14 Common.Route
15+ ghc-options: -Wall
skeleton/frontend/frontend.cabal+4−2
@@ -28,7 +28,9 @@ executable frontend
28 , reflex-dom
28 , reflex-dom
29 , obelisk-generated-static
29 , obelisk-generated-static
30 , frontend
30 , frontend
31− --TODO: Make these ghc-options optional
32 ghc-options: -threaded
31 ghc-options: -threaded
32+ if impl(ghcjs)
33+ ghc-options: -dedupe
34+ cpp-options: -DGHCJS_BROWSER
33 if os(darwin)
35 if os(darwin)
34− ghc-options: -dynamic
36+ ghc-options: -dynamic