on c8ebdad help sign in
26 files changed+153−239
since splitsnapshots
unifiedsplit
.github/pull_request_template.md−2 ChangeLog.md+1−19 README.md+3−6 all-builds.nix+1−1 default.nix+38−45 dep/reflex-platform/github.json+3−3 haskell-overlays/misc-deps.nix+2−8 haskell-overlays/obelisk.nix−4 lib/command/obelisk-command.cabal+1−1 lib/command/src/Obelisk/Command/Deploy.hs+27−24 lib/command/src/Obelisk/Command/Preprocessor.hs+2−3 lib/command/src/Obelisk/Command/Project.hs+4−10 lib/command/src/Obelisk/Command/Run.hs+11−9 lib/command/src/Obelisk/Command/Thunk.hs+34−42 lib/command/src/Obelisk/Command/Utils.hs+1−27 lib/command/src/Obelisk/Command/VmBuilder.hs+8−8 lib/executable-config/default.nix+3−2 lib/executable-config/lookup/src/Obelisk/Configs.hs−2 lib/route/src/Obelisk/Route.hs+2−3 lib/run/src/Obelisk/Run.hs+3−3 lib/snap-extras/src/Obelisk/Snap/Extras.hs+1−1 skeleton/backend/backend.cabal+2−2 skeleton/cabal.project−1 skeleton/common/common.cabal+1−1 skeleton/default.nix+3−10 skeleton/frontend/frontend.cabal+2−2
.github/pull_request_template.md−2
@@ -3,8 +3,6 @@
33I have:
44
55 - [ ] Based work on latest `develop` branch
6− - [ ] Followed the [contribution guide](https://github.com/obsidiansystems/obelisk/blob/develop/CONTRIBUTING.md#submitting-changes)
76 - [ ] Looked for lint in my changes with `hlint .` (lint found code you did not write can be left alone)
87 - [ ] Run the test suite: `$(nix-build -A selftest --no-out-link)`
9− - [ ] [Updated the changelog](https://github.com/obsidiansystems/obelisk/blob/develop/CONTRIBUTING.md#in-the-changelog)
108 - [ ] (Optional) Run CI tests locally: `nix-build release.nix -A build.x86_64-linux --no-out-link` (or `x86_64-darwin` on macOS)
ChangeLog.md+1−19
@@ -2,26 +2,8 @@
22
33This project's release branch is `master`. This log is written from the perspective of the release branch: when changes hit `master`, they are considered released.
44
5−## v0.9.1.0
5+## Unreleased
66
7−* [#801](https://github.com/obsidiansystems/obelisk/pull/801): Remove errors and warning for local packages without a library component
8−* [#812](https://github.com/obsidiansystems/obelisk/pull/812): Add support for `NoImplicitPrelude` and other extensions disabled via `No`
9−* Pinned version bumps:
10− * reflex-platform [0.7.0.0](https://github.com/reflex-frp/reflex-platform/releases/tag/v0.7.0.0)
11− * hnix 0.8.0
12−* [#787](https://github.com/obsidiansystems/obelisk/pull/787): Set `immutable` cache control directive when serving content-addressed static assets
13−* Use iOS SDK 13.2
14−
15−
16−## v0.9.0.1
17−
18−* ([#810](https://github.com/obsidiansystems/obelisk/pull/810)) Fix loading of `all.js` in fully compiled web apps.
19−
20−## v0.9.0.0
21−
22−* **(Breaking change)** Backport nixpkgs upgrades to ACME/Let's Encrypt handling so that HTTPS deployments continue to work flawlessly. If your deployment is having trouble renewing [Let's Encrypt](https://letsencrypt.org/) certificates, upgrade to this version.
23− * **IMPORTANT:** In order to use [Let's Encrypt](https://letsencrypt.org/) you must now accept their [terms of service](https://letsencrypt.org/repository/). To do that, add `terms.security.acme.acceptTerms = true;` to the `import ./.obelisk/impl {` section in your `default.nix`. The new skeleton application may serve as an [example](https://github.com/obsidiansystems/obelisk/blob/4759342ab3570888c027d4c58cb5694cb832d624/skeleton/default.nix#L13).
24−* Update reflex-platform dependency to v0.6.0.0
257* ([#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`.
268* ([#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`.
279* ([#735](https://github.com/obsidiansystems/obelisk/pull/735)) Fix regression causing custom `Prelude`s to break `ob run`/`ob watch`/`ob repl`.
README.md+3−6
@@ -66,10 +66,7 @@ Obelisk assumes basic knowledge of [Haskell](https://www.haskell.org/) and [Refl
6666 sudo launchctl stop org.nixos.nix-daemon
6767 sudo launchctl start org.nixos.nix-daemon
6868 ```
69−1. Install obelisk:
70− ```bash
71− nix-env -f https://github.com/obsidiansystems/obelisk/archive/master.tar.gz -iA command
72− ```
69+1. Install obelisk: `nix-env -f https://github.com/obsidiansystems/obelisk/archive/master.tar.gz -iA command`
7370
7471### Accessing private repositories
7572
@@ -114,7 +111,7 @@ First create a new EC2 instance:
1141111. Launch a NixOS 19.09 EC2 instance (we recommend [this AMI](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#LaunchInstanceWizard:ami=ami-00a8eeaf232a74f84))
1151121. In the instance configuration wizard ensure that your instance has at least 1GB RAM and 10GB disk space.
1161131. When prompted save your AWS private key (`~/myaws.pem`) somewhere safe. We'll need it later during deployment.
117−1. Go to "Security Groups", select your instance's security group and under "Inbound" tab add a new rule for HTTP port 80 and HTTPS port 443.
114+1. Go to "Security Groups", select your instance's security group and under "Inbound" tab add a new rule for HTTP port 80 and 443.
118115
119116At this stage your instance should be booting and become accessible shortly. Note down the hostname of your EC2 instance.
120117
@@ -221,7 +218,7 @@ Your account must also belong to an Apple Developer Team, if you want to access
2212181. Click accept to authorize on both the computer and the iPhone.
222219
223220##### Xcode
224−Install Xcode 11.2 (contains iOS SDK 13.2) and open it so that it runs its post install tool setup.
221+Install Xcode 8.2 (contains iOS SDK 10.2) and open it so that it runs its post install tool setup.
225222
226223These versions will work out of the box but iOS SDKs prior to 11.3 should also work. You can choose another installed version in `default.nix`
227224
all-builds.nix+1−1
@@ -1,6 +1,6 @@
11{ self-args ? {
22 config.android_sdk.accept_license = true;
3− iosSdkVersion = "13.2";
3+ iosSdkVersion = "10.2";
44 }
55, local-self ? import ./. self-args
66, supportedSystems ? [ builtins.currentSystem ]
default.nix+38−45
@@ -1,10 +1,7 @@
11{ system ? builtins.currentSystem
22, profiling ? false
3−, iosSdkVersion ? "13.2"
3+, iosSdkVersion ? "10.2"
44, config ? {}
5−, terms ? { # Accepted terms, conditions, and licenses
6− security.acme.acceptTerms = false;
7− }
85, reflex-platform-func ? import ./dep/reflex-platform
96}:
107let
@@ -117,7 +114,7 @@ in rec {
117114 "${routeHost}".email = adminEmail;
118115 } else {};
119116
120− security.acme.${if enableHttps && (terms.security.acme.acceptTerms or false) then "acceptTerms" else null} = true;
117+ security.acme.${if enableHttps then "acceptTerms" else null} = true;
121118 };
122119
123120 mkObeliskApp =
@@ -141,9 +138,6 @@ in rec {
141138 locations.${baseUrl} = {
142139 proxyPass = "http://127.0.0.1:" + toString internalPort;
143140 proxyWebsockets = true;
144− extraConfig = ''
145− access_log off;
146− '';
147141 };
148142 };
149143 };
@@ -186,9 +180,7 @@ in rec {
186180 set -eux
187181 ln -s '${if profiling then backend else haskellLib.justStaticExecutables backend}'/bin/* $out/
188182 ln -s '${mkAssets assets}' $out/static.assets
189− for d in '${mkAssets (compressedJs frontend optimizationLevel)}'/*/; do
190− ln -s "$d" "$out"/"$(basename "$d").assets"
191− done
183+ ln -s '${mkAssets (compressedJs frontend optimizationLevel)}'/* $out
192184 echo ${version} > $out/version
193185 '';
194186
@@ -337,40 +329,39 @@ in rec {
337329 });
338330 in allConfig;
339331 in (mkProject (projectDefinition args)).projectConfig);
340− mainProjectOut = projectOut { inherit system; };
332+ projectOutHost = projectOut { inherit system; };
341333 serverOn = projectInst: version: serverExe
342334 projectInst.ghc.backend
343− mainProjectOut.ghcjs.frontend
335+ projectOutHost.ghcjs.frontend
344336 projectInst.passthru.staticFiles
345337 projectInst.passthru.__closureCompilerOptimizationLevel
346338 version;
347− linuxExe = serverOn (projectOut { system = "x86_64-linux"; });
348339 dummyVersion = "Version number is only available for deployments";
349− in mainProjectOut // {
350− __unstable__.profiledObRun = let
351− profiled = projectOut { inherit system; enableLibraryProfiling = true; };
352− exeSource = builtins.toFile "ob-run.hs" ''
353− {-# LANGUAGE NoImplicitPrelude #-}
354− {-# LANGUAGE PackageImports #-}
355− module Main where
356−
357− -- Explicitly import Prelude from base lest there be multiple modules called Prelude
358− import "base" Prelude (IO, (++), read)
359−
360− import "base" Control.Exception (finally)
361− import "reflex" Reflex.Profiled (writeProfilingData)
362− import "base" System.Environment (getArgs)
363−
364− import qualified "obelisk-run" Obelisk.Run
365− import qualified Frontend
366− import qualified Backend
367−
368− main :: IO ()
369− main = do
370− [portStr, assets, profFileName] <- getArgs
371− Obelisk.Run.run (read portStr) (Obelisk.Run.runServeAsset assets) Backend.backend Frontend.frontend
372− `finally` writeProfilingData (profFileName ++ ".rprof")
373− '';
340+ profiledObRun =
341+ let
342+ profiled = projectOut { inherit system; enableLibraryProfiling = true; };
343+ exeSource = builtins.toFile "ob-run-profiled.hs" ''
344+ {-# LANGUAGE NoImplicitPrelude #-}
345+ {-# LANGUAGE PackageImports #-}
346+ module Main where
347+
348+ -- Explicitly import Prelude from base lest there be multiple modules called Prelude
349+ import "base" Prelude (IO, (++), read)
350+
351+ import "base" Control.Exception (finally)
352+ import "reflex" Reflex.Profiled (writeProfilingData)
353+ import "base" System.Environment (getArgs)
354+
355+ import qualified "obelisk-run" Obelisk.Run
356+ import qualified Frontend
357+ import qualified Backend
358+
359+ main :: IO ()
360+ main = do
361+ [portStr, assets, profFileName] <- getArgs
362+ Obelisk.Run.run (read portStr) (Obelisk.Run.runServeAsset assets) Backend.backend Frontend.frontend
363+ `finally` writeProfilingData (profFileName ++ ".rprof")
364+ '';
374365 in nixpkgs.runCommand "ob-run" {
375366 buildInputs = [ (profiled.ghc.ghcWithPackages (p: [p.backend p.frontend])) ];
376367 } ''
@@ -378,14 +369,16 @@ in rec {
378369 mkdir -p $out/bin
379370 ghc -x hs -prof -fno-prof-auto -threaded ob-run.hs -o $out/bin/ob-run
380371 '';
381−
382− linuxExeConfigurable = linuxExe;
383− linuxExe = linuxExe dummyVersion;
384− exe = serverOn mainProjectOut dummyVersion;
372+ in projectOutHost // lib.makeExtensible (self: {
373+ __unstable__.profiledObRun = profiledObRun;
374+ exeConfigurable = { system, version }: serverOn (projectOut { inherit system; }) version;
375+ exe = self.exeConfigurable { inherit system; version = dummyVersion; };
376+ linuxExeConfigurable = version: self.exeConfigurable { system = "x86_64-linux"; inherit version; };
377+ linuxExe = self.linuxExeConfigurable dummyVersion;
385378 server = args@{ hostName, adminEmail, routeHost, enableHttps, version, module ? serverModules.mkBaseEc2 }:
386− server (args // { exe = linuxExe version; });
379+ server (args // { exe = self.linuxExeConfigurable version; });
387380 obelisk = import (base' + "/.obelisk/impl") {};
388− };
381+ });
389382 haskellPackageSets = {
390383 inherit (reflex-platform) ghc ghcjs;
391384 };
dep/reflex-platform/github.json+3−3
@@ -1,8 +1,8 @@
11{
22 "owner": "reflex-frp",
33 "repo": "reflex-platform",
4− "branch": "release/0.7.0.0",
4+ "branch": "eac@tweaks-from-wrinkl",
55 "private": false,
6− "rev": "27a7851a780ff21472d85f9a02fb84635ef9027a",
7− "sha256": "1m4zlw91dpjlbdchjyxhvhv3k7lilm0qa17dhhww868xxc27sann"
6+ "rev": "1cca141c7a87e98e8e36860c326408942851bf61",
7+ "sha256": "0mlxn6zy4983rr3ahslm5yvyz6gkqs9m6by9xl9vm0dhm2cb36gj"
88}
haskell-overlays/misc-deps.nix+2−8
@@ -9,14 +9,8 @@ let
99in
1010
1111{
12− regex-base = self.callHackage "regex-base" "0.94.0.0" {};
13− regex-posix = self.callHackage "regex-posix" "0.96.0.0" {};
14− regex-tdfa = self.callHackage "regex-tdfa" "1.3.1.0" {};
15− test-framework = haskellLib.dontCheck (self.callHackage "test-framework" "0.8.2.0" {});
16− hnix = haskellLib.dontCheck (self.callHackage "hnix" "0.8.0" {});
17− hnix-store-core = self.callHackage "hnix-store-core" "0.2.0.0" {};
18−
19− aeson-gadt-th = self.callHackage "aeson-gadt-th" "0.2.4" {};
12+ hnix = haskellLib.dontCheck (haskellLib.doJailbreak (self.callCabal2nix "hnix" (hackGet ../dep/hnix) {}));
13+ hnix-store-core = self.callHackage "hnix-store-core" "0.1.0.0" {};
2014
2115 ghcid = self.callCabal2nix "ghcid" (hackGet ../dep/ghcid) {};
2216 # Exports more internals
haskell-overlays/obelisk.nix−4
@@ -19,12 +19,8 @@ in
1919 obelisk-command = haskellLib.overrideCabal (self.callCabal2nix "obelisk-command" (obeliskCleanSource ../lib/command) {}) {
2020 librarySystemDepends = [
2121 pkgs.jre
22− pkgs.git
2322 pkgs.nix
2423 pkgs.nix-prefetch-git
25− pkgs.openssh
26− pkgs.rsync
27− pkgs.which
2824 (haskellLib.justStaticExecutables self.ghcid)
2925 ];
3026 };
lib/command/obelisk-command.cabal+1−1
@@ -1,5 +1,5 @@
11name: obelisk-command
2−version: 0.9.0.1
2+version: 0.8.0.0
33cabal-version: >= 1.8
44build-type: Simple
55
lib/command/src/Obelisk/Command/Deploy.hs+27−24
@@ -17,6 +17,7 @@ import Data.Bits
1717import qualified Data.ByteString.Lazy as BSL
1818import Data.Default
1919import qualified Data.Map as Map
20+import Data.Maybe (isJust)
2021import qualified Data.Set as Set
2122import Data.String.Here.Interpolated (i)
2223import qualified Data.Text as T
@@ -85,12 +86,13 @@ deployInit' thunkPtr (DeployInitOpts deployDir sshKeyPath hostnames route adminE
8586 --accidentally create a production deployment that uses development
8687 --credentials to connect to some resources. This could result in, e.g.,
8788 --production data backed up to a dev environment.
88− withSpinner "Creating project configuration directories" $ liftIO $ do
89− mapM_ (createDirectoryIfMissing True)
90− [ deployDir </> "config" </> "backend"
91− , deployDir </> "config" </> "common"
92− , deployDir </> "config" </> "frontend"
93− ]
89+ withSpinner "Creating project configuration directories" $ do
90+ callProcessAndLogOutput (Notice, Error) $
91+ proc "mkdir" [ "-p"
92+ , deployDir </> "config" </> "backend"
93+ , deployDir </> "config" </> "common"
94+ , deployDir </> "config" </> "frontend"
95+ ]
9496
9597 let srcDir = deployDir </> "src"
9698 withSpinner ("Creating source thunk (" <> T.pack (makeRelative deployDir srcDir) <> ")") $ do
@@ -124,14 +126,15 @@ deployPush deployPath getNixBuilders = do
124126 route <- readDeployConfig deployPath $ "config" </> "common" </> "route"
125127 routeHost <- getHostFromRoute enableHttps route
126128 let srcPath = deployPath </> "src"
127− thunkPtr <- readThunk srcPath >>= \case
128− Right (ThunkData_Packed _ ptr) -> return ptr
129+ thunkPtr' <- readThunk srcPath >>= \case
130+ Right (ThunkData_Packed _ ptr) -> return $ Just ptr
129131 Right ThunkData_Checkout -> do
130132 checkGitCleanStatus srcPath True >>= \case
131− True -> packThunk (ThunkPackConfig False (ThunkConfig Nothing)) srcPath
132− False -> failWith $ T.pack $ "ob deploy push: ensure " <> srcPath <> " has no pending changes and latest is pushed upstream."
133+ True -> Just <$> packThunk (ThunkPackConfig False (ThunkConfig Nothing)) srcPath
134+ False -> Nothing <$ putLog Warning "Skipping packing of src thunk; won't be able to automatically commit this deployment"
135+ -- failWith $ T.pack $ "ob deploy push: ensure " <> srcPath <> " has no pending changes and latest is pushed upstream."
133136 Left err -> failWith $ "ob deploy push: couldn't read src thunk: " <> T.pack (show err)
134− let version = show . _thunkRev_commit $ _thunkPtr_rev thunkPtr
137+ let version' = show . _thunkRev_commit . _thunkPtr_rev <$> thunkPtr'
135138 builders <- getNixBuilders
136139 let moduleFile = deployPath </> "module.nix"
137140 moduleFileExists <- liftIO $ doesFileExist moduleFile
@@ -148,7 +151,7 @@ deployPush deployPath getNixBuilders = do
148151 [ strArg "hostName" host
149152 , strArg "adminEmail" adminEmail
150153 , strArg "routeHost" routeHost
151− , strArg "version" version
154+ , strArg "version" $ maybe "Deployment was done with a dirty source tree" id version'
152155 , boolArg "enableHttps" enableHttps
153156 ] <> [rawArg "module" ("import " <> toNixPath moduleFile) | moduleFileExists ])
154157 & nixCmdConfig_builders .~ builders
@@ -161,8 +164,8 @@ deployPush deployPath getNixBuilders = do
161164 "nix-copy-closure" ["-v", "--to", "--use-substitutes", "root@" <> host, "--gzip", outputPath]
162165 withSpinner "Uploading config" $ ifor_ buildOutputByHost $ \host _ -> do
163166 callProcessAndLogOutput (Notice, Warning) $
164− proc rsyncPath
165− [ "-e " <> sshPath <> " " <> unwords sshOpts
167+ proc "rsync"
168+ [ "-e ssh " <> unwords sshOpts
166169 , "-qarvz"
167170 , deployPath </> "config"
168171 , "root@" <> host <> ":/var/lib/backend"
@@ -170,22 +173,22 @@ deployPush deployPath getNixBuilders = do
170173 --TODO: Create GC root so we're sure our closure won't go away during this time period
171174 withSpinner "Switching to new configuration" $ ifor_ buildOutputByHost $ \host outputPath -> do
172175 callProcessAndLogOutput (Notice, Warning) $
173− proc sshPath $ sshOpts <>
176+ proc "ssh" $ sshOpts <>
174177 [ "root@" <> host
175178 , unwords
176− -- Note that we don't want to $(staticWhich "nix-env") here, because this is executing on a remote machine
177179 [ "nix-env -p /nix/var/nix/profiles/system --set " <> outputPath
178180 , "&&"
179181 , "/nix/var/nix/profiles/system/bin/switch-to-configuration switch"
180182 ]
181183 ]
182− isClean <- checkGitCleanStatus deployPath True
183− when (not isClean) $ do
184− withSpinner "Committing changes to Git" $ do
185− callProcessAndLogOutput (Debug, Error) $
186− gitProc deployPath ["add", "."]
187− callProcessAndLogOutput (Debug, Error) $
188− gitProc deployPath ["commit", "-m", "New deployment"]
184+ when (isJust version') $ do
185+ isClean <- checkGitCleanStatus deployPath True
186+ when (not isClean) $ do
187+ withSpinner "Committing changes to Git" $ do
188+ callProcessAndLogOutput (Debug, Error) $ proc "git"
189+ ["-C", deployPath, "add", "."]
190+ callProcessAndLogOutput (Debug, Error) $ proc "git"
191+ ["-C", deployPath, "commit", "-m", "New deployment"]
189192 putLog Notice $ "Deployed => " <> T.pack route
190193 where
191194 callProcess' envMap cmd args = do
@@ -315,7 +318,7 @@ readDeployConfig deployDir fname = liftIO $ do
315318
316319verifyHostKey :: MonadObelisk m => FilePath -> FilePath -> String -> m ()
317320verifyHostKey knownHostsPath keyPath hostName =
318− callProcessAndLogOutput (Notice, Warning) $ proc sshPath $
321+ callProcessAndLogOutput (Notice, Warning) $ proc "ssh" $
319322 sshArgs knownHostsPath keyPath True <>
320323 [ "root@" <> hostName
321324 , "-o", "NumberOfPasswordPrompts=0"
lib/command/src/Obelisk/Command/Preprocessor.hs+2−3
@@ -47,8 +47,7 @@ applyPackages origPath inPath outPath packagePaths' = do
4747 Left err -> do
4848 hPutStrLn stderr $ "Error: Unable to parse cabal package " <> packagePath <> "; Skipping preprocessor on " <> origPath <> ". Error: " <> show err
4949 pure Nothing
50− Right (Just (_, packageInfo)) -> pure $ Just packageInfo
51− Right Nothing -> pure Nothing
50+ Right (_, packageInfo) -> pure $ Just packageInfo
5251
5352 writeOutput packageInfo' inPath outPath
5453
@@ -76,7 +75,7 @@ generateHeader origPath packageInfo =
7675 ext -> (TL.fromString (show ext) :)
7776 showExt = \case
7877 EnableExtension ext -> [TL.fromString (show ext)]
79− DisableExtension ext -> ["No" <> TL.fromString (show ext)]
78+ DisableExtension _ -> []
8079 UnknownExtension ext -> [TL.fromString ext]
8180
8281 ghcOptions =
lib/command/src/Obelisk/Command/Project.hs+4−10
@@ -51,7 +51,7 @@ import Obelisk.App (MonadObelisk)
5151import Obelisk.CliApp
5252import Obelisk.Command.Nix
5353import Obelisk.Command.Thunk
54−import Obelisk.Command.Utils (nixBuildExePath, nixExePath, toNixPath, cp, nixShellPath)
54+import Obelisk.Command.Utils (nixBuildExePath, nixExePath, toNixPath)
5555
5656--TODO: Make this module resilient to random exceptions
5757
@@ -116,7 +116,7 @@ initProject source force = withSystemTempDirectory "ob-init" $ \tmpDir -> do
116116 skel <- nixBuildAttrWithCache implDir "skeleton" --TODO: I don't think there's actually any reason to cache this
117117
118118 callProcessAndLogOutput (Notice, Error) $
119− proc cp
119+ proc "cp"
120120 [ "-r"
121121 , "--preserve=links"
122122 , obDir
@@ -126,7 +126,7 @@ initProject source force = withSystemTempDirectory "ob-init" $ \tmpDir -> do
126126
127127 withSpinner "Copying project skeleton" $ do
128128 callProcessAndLogOutput (Notice, Error) $
129− proc cp
129+ proc "cp"
130130 [ "-r"
131131 , "--no-preserve=mode"
132132 , "-T"
@@ -137,12 +137,6 @@ initProject source force = withSystemTempDirectory "ob-init" $ \tmpDir -> do
137137 let configDir = "config"
138138 createDirectoryIfMissing False configDir
139139 mapM_ (createDirectoryIfMissing False . (configDir </>)) ["backend", "common", "frontend"]
140− putLog Notice $ T.intercalate "\n"
141− [ "An obelisk project has been successfully initialized. Next steps:"
142− , " 'ob run': Start a development server"
143− , " 'ob watch': Watch for changes without starting a server"
144− , " 'ob repl': Load your project into GHCi"
145− ]
146140
147141callHandoffOb
148142 :: MonadObelisk m
@@ -298,7 +292,7 @@ bashEscape :: String -> String
298292bashEscape = BSU.toString . bytes . bash . BSU.fromString
299293
300294nixShellRunProc :: NixShellConfig -> ProcessSpec
301−nixShellRunProc cfg = setDelegateCtlc True $ proc nixShellPath $ runNixShellConfig cfg
295+nixShellRunProc cfg = setDelegateCtlc True $ proc "nix-shell" $ runNixShellConfig cfg
302296
303297nixShellWithoutPkgs
304298 :: MonadObelisk m
lib/command/src/Obelisk/Command/Run.hs+11−9
@@ -14,7 +14,7 @@ module Obelisk.Command.Run where
1414import Control.Arrow ((&&&))
1515import Control.Exception (Exception, bracket)
1616import Control.Lens (ifor, (.~), (&))
17−import Control.Monad (filterM)
17+import Control.Monad (filterM, unless)
1818import Control.Monad.Except (runExceptT, throwError)
1919import Control.Monad.IO.Class (liftIO)
2020import Control.Monad.Reader (MonadIO)
@@ -304,16 +304,15 @@ parseCabalPackage
304304 -> m (Maybe CabalPackageInfo)
305305parseCabalPackage dir = parseCabalPackage' dir >>= \case
306306 Left err -> Nothing <$ putLog Error err
307− Right (Just (warnings, pkgInfo)) -> do
307+ Right (warnings, pkgInfo) -> do
308308 for_ warnings $ putLog Warning . T.pack . show
309309 pure $ Just pkgInfo
310− Right Nothing -> pure Nothing
311310
312311-- | Like 'parseCabalPackage' but returns errors and warnings directly so as to avoid 'MonadObelisk'.
313312parseCabalPackage'
314313 :: (MonadIO m)
315314 => FilePath -- ^ Package directory
316− -> m (Either T.Text (Maybe ([Dist.PWarning], CabalPackageInfo)))
315+ -> m (Either T.Text ([Dist.PWarning], CabalPackageInfo))
317316parseCabalPackage' pkg = runExceptT $ do
318317 (cabalContents, packageFile, packageName) <- guessCabalPackageFile pkg >>= \case
319318 Left GuessPackageFileError_NotFound -> throwError $ "No .cabal or package.yaml file found in " <> T.pack pkg
@@ -341,7 +340,7 @@ parseCabalPackage' pkg = runExceptT $ do
341340 case condLibrary <$> result of
342341 Right (Just condLib) -> do
343342 let (_, lib) = simplifyCondTree evalConfVar condLib
344− pure $ Just $ (warnings,) $ CabalPackageInfo
343+ pure $ (warnings,) $ CabalPackageInfo
345344 { _cabalPackageInfo_packageName = T.pack packageName
346345 , _cabalPackageInfo_packageFile = packageFile
347346 , _cabalPackageInfo_packageRoot = takeDirectory packageFile
@@ -355,17 +354,17 @@ parseCabalPackage' pkg = runExceptT $ do
355354 , _cabalPackageInfo_compilerOptions = options $ libBuildInfo lib
356355 , _cabalPackageInfo_cppOptions = cppOptions $ libBuildInfo lib
357356 }
358− Right Nothing -> pure Nothing
357+ Right Nothing -> throwError "Haskell package has no library component"
359358 Left (_, errors) ->
360359 throwError $ T.pack $ "Failed to parse " <> packageFile <> ":\n" <> unlines (map show errors)
361360
362361parsePackagesOrFail :: (MonadObelisk m, Foldable f) => f FilePath -> m (NE.NonEmpty CabalPackageInfo)
363362parsePackagesOrFail dirs' = do
364− packageInfos' <- fmap catMaybes $ for dirs $ \dir -> do
363+ (pkgDirErrs, packageInfos') <- fmap partitionEithers $ for dirs $ \dir -> do
365364 flip fmap (parseCabalPackage dir) $ \case
366365 Just packageInfo
367− | _cabalPackageInfo_buildable packageInfo -> Just packageInfo
368− _ -> Nothing
366+ | _cabalPackageInfo_buildable packageInfo -> Right packageInfo
367+ _ -> Left dir
369368
370369 -- Sort duplicate packages such that we prefer shorter paths, but fall back to alphabetical ordering.
371370 let packagesByName = Map.map (NE.sortBy $ comparing $ \p -> let n = _cabalPackageInfo_packageFile p in (length n, n))
@@ -387,6 +386,9 @@ parsePackagesOrFail dirs' = do
387386 "No valid, buildable packages found" <> (if null dirs then "" else " in " <> intercalate ", " dirs)
388387 Just xs -> pure xs
389388
389+ unless (null pkgDirErrs) $
390+ putLog Warning $ T.pack $ "Failed to find buildable packages in " <> intercalate ", " pkgDirErrs
391+
390392 pure packageInfos
391393 where
392394 dirs = toList dirs'
lib/command/src/Obelisk/Command/Thunk.hs+34−42
@@ -26,9 +26,8 @@ import qualified Data.ByteString.Lazy as LBS
2626import Data.Containers.ListUtils (nubOrd)
2727import Data.Default
2828import Data.Either.Combinators (fromRight', rightToMaybe)
29−import Data.Foldable (toList)
29+import Data.Foldable (for_, toList)
3030import Data.Function ((&))
31−import Data.Functor ((<&>))
3231import Data.Git.Ref (Ref)
3332import qualified Data.Git.Ref as Ref
3433import qualified Data.List as L
@@ -238,35 +237,38 @@ matchThunkSpecToDir
238237 -> Set FilePath -- ^ Set of file paths relative to the given directory
239238 -> m ThunkData
240239matchThunkSpecToDir thunkSpec dir dirFiles = do
241− case nonEmpty (toList $ dirFiles `Set.difference` expectedPaths) of
242− Just fs -> throwError $ ReadThunkError_UnrecognizedPaths $ (dir </>) <$> fs
243− Nothing -> pure ()
244− case nonEmpty (toList $ requiredPaths `Set.difference` dirFiles) of
245− Just fs -> throwError $ ReadThunkError_MissingPaths $ (dir </>) <$> fs
246− Nothing -> pure ()
247− datas <- fmap toList $ flip Map.traverseMaybeWithKey (_thunkSpec_files thunkSpec) $ \expectedPath -> \case
248− ThunkFileSpec_AttrCache -> Nothing <$ dirMayExist expectedPath
249− ThunkFileSpec_CheckoutIndicator -> liftIO (doesDirectoryExist (dir </> expectedPath)) <&> \case
250− False -> Nothing
251− True -> Just ThunkData_Checkout
252− ThunkFileSpec_FileMatches expectedContents -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do
253− actualContents <- liftIO (T.readFile $ dir </> expectedPath)
254− case T.strip expectedContents == T.strip actualContents of
255− True -> pure Nothing
256− False -> throwError $ ReadThunkError_FileDoesNotMatch (dir </> expectedPath) expectedContents
257− ThunkFileSpec_Ptr parser -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do
258− let path = dir </> expectedPath
259− liftIO (doesFileExist path) >>= \case
260− False -> pure Nothing
261− True -> do
262− actualContents <- liftIO $ LBS.readFile path
263− case parser actualContents of
264− Right v -> pure $ Just (ThunkData_Packed thunkSpec v)
265− Left e -> throwError $ ReadThunkError_UnparseablePtr (dir </> expectedPath) e
266−
267− case nonEmpty datas of
268− Nothing -> throwError ReadThunkError_UnrecognizedThunk
269− Just xs -> fold1WithM xs $ \a b -> either throwError pure (mergeThunkData a b)
240+ isCheckout <- fmap or $ flip Map.traverseWithKey (_thunkSpec_files thunkSpec) $ \expectedPath -> \case
241+ ThunkFileSpec_CheckoutIndicator -> liftIO (doesDirectoryExist (dir </> expectedPath))
242+ _ -> pure False
243+ case isCheckout of
244+ True -> pure ThunkData_Checkout
245+ False -> do
246+ for_ (nonEmpty (toList $ dirFiles `Set.difference` expectedPaths)) $ \fs ->
247+ throwError $ ReadThunkError_UnrecognizedPaths $ (dir </>) <$> fs
248+ for_ (nonEmpty (toList $ requiredPaths `Set.difference` dirFiles)) $ \fs ->
249+ throwError $ ReadThunkError_MissingPaths $ (dir </>) <$> fs
250+ datas <- fmap toList $ flip Map.traverseMaybeWithKey (_thunkSpec_files thunkSpec) $ \expectedPath -> \case
251+ ThunkFileSpec_AttrCache -> Nothing <$ dirMayExist expectedPath
252+ ThunkFileSpec_CheckoutIndicator -> pure Nothing -- Handled above
253+ ThunkFileSpec_FileMatches expectedContents -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do
254+ actualContents <- liftIO (T.readFile $ dir </> expectedPath)
255+ case T.strip expectedContents == T.strip actualContents of
256+ True -> pure Nothing
257+ False -> throwError $ ReadThunkError_FileDoesNotMatch (dir </> expectedPath) expectedContents
258+ ThunkFileSpec_Ptr parser -> handle (\(e :: IOError) -> throwError $ ReadThunkError_FileError e) $ do
259+ let path = dir </> expectedPath
260+ liftIO (doesFileExist path) >>= \case
261+ False -> pure Nothing
262+ True -> do
263+ actualContents <- liftIO $ LBS.readFile path
264+ case parser actualContents of
265+ Right v -> pure $ Just (thunkSpec, v)
266+ Left e -> throwError $ ReadThunkError_UnparseablePtr (dir </> expectedPath) e
267+
268+ uncurry ThunkData_Packed <$> case nonEmpty datas of
269+ Nothing -> throwError ReadThunkError_UnrecognizedThunk
270+ Just xs -> fold1WithM xs $ \a@(_, ptrA) (_, ptrB) ->
271+ if ptrA == ptrB then pure a else throwError $ ReadThunkError_AmbiguousPackedState ptrA ptrB
270272 where
271273 rootPathsOnly = Set.fromList . mapMaybe takeRootDir . Map.keys
272274 takeRootDir = fmap NonEmpty.head . nonEmpty . splitPath
@@ -282,15 +284,6 @@ matchThunkSpecToDir thunkSpec dir dirFiles = do
282284 True -> throwError $ ReadThunkError_UnrecognizedPaths $ expectedPath :| []
283285 False -> pure ()
284286
285− -- Combine 'ThunkData' from different files, preferring "Checkout" over "Packed"
286− mergeThunkData ThunkData_Checkout ThunkData_Checkout = Right ThunkData_Checkout
287− mergeThunkData ThunkData_Checkout ThunkData_Packed{} = Left bothPackedAndUnpacked
288− mergeThunkData ThunkData_Packed{} ThunkData_Checkout = Left bothPackedAndUnpacked
289− mergeThunkData a@(ThunkData_Packed _ ptrA) (ThunkData_Packed _ ptrB) =
290− if ptrA == ptrB then Right a else Left $ ReadThunkError_AmbiguousPackedState ptrA ptrB
291−
292− bothPackedAndUnpacked = ReadThunkError_UnrecognizedState "Both packed data and checkout present"
293−
294287 fold1WithM (x :| xs) f = foldM f x xs
295288
296289readThunkWith
@@ -305,8 +298,7 @@ readThunkWith specTypes dir = do
305298 Left e -> putLog Debug [i|Thunk specification ${_thunkSpec_name spec} did not match ${dir}: ${e}|] *> loop rest
306299 x@(Right _) -> x <$ putLog Debug [i|Thunk specification ${_thunkSpec_name spec} matched ${dir}|]
307300
308−-- | Read a thunk and validate that it is exactly a packed thunk.
309−-- If additional data is present, fail.
301+-- | Read a packed or unpacked thunk based on predefined thunk specifications.
310302readThunk :: (MonadObelisk m) => FilePath -> m (Either ReadThunkError ThunkData)
311303readThunk = readThunkWith thunkSpecTypes
312304
lib/command/src/Obelisk/Command/Utils.hs+1−27
@@ -60,32 +60,6 @@ nixPrefetchGitPath = $(staticWhich "nix-prefetch-git")
6060nixPrefetchUrlPath :: FilePath
6161nixPrefetchUrlPath = $(staticWhich "nix-prefetch-url")
6262
63−nixShellPath :: FilePath
64−nixShellPath = $(staticWhich "nix-shell")
65−
66−rsyncPath :: FilePath
67−rsyncPath = $(staticWhich "rsync")
68−
69−sshPath :: FilePath
70−sshPath = $(staticWhich "ssh")
71−
72−gitPath :: FilePath
73−gitPath = $(staticWhich "git")
74−
75−whichPath :: FilePath
76−whichPath = $(staticWhich "which")
77−
78−sshKeygenPath :: FilePath
79−sshKeygenPath = $(staticWhich "ssh-keygen")
80−
81−-- $(staticWhich "docker") was intentionally omitted, at least for now
82−-- One concern is that I don't know how particular docker is about having the
83−-- CLI exe match the version of the docker daemon, which is largely outside of
84−-- the control of obelisk-command.
85−-- TODO: Investigate the tradeoffs associated with this choice
86−dockerPath :: FilePath
87−dockerPath = "docker"
88−
8963-- | Nix syntax requires relative paths to be prefixed by @./@ or
9064-- @../@. This will make a 'FilePath' that can be embedded in a Nix
9165-- expression.
@@ -123,7 +97,7 @@ initGit repo = do
12397 git ["commit", "-m", "Initial commit."]
12498
12599gitProcNoRepo :: [String] -> ProcessSpec
126−gitProcNoRepo args = setEnvOverride (M.singleton "GIT_TERMINAL_PROMPT" "0" <>) $ proc gitPath args
100+gitProcNoRepo args = setEnvOverride (M.singleton "GIT_TERMINAL_PROMPT" "0" <>) $ proc "git" args
127101
128102gitProc :: FilePath -> [String] -> ProcessSpec
129103gitProc repo = gitProcNoRepo . runGitInDir
lib/command/src/Obelisk/Command/VmBuilder.hs+8−8
@@ -21,7 +21,7 @@ import qualified System.Info
2121
2222import Obelisk.App (MonadObelisk, getObeliskUserStateDir)
2323import Obelisk.CliApp
24−import Obelisk.Command.Utils (rmPath, whichPath, sshKeygenPath, nixBuildExePath, dockerPath)
24+import Obelisk.Command.Utils (rmPath)
2525
2626-- | Generate the `--builders` argument string to enable the VM builder after ensuring it is available.
2727getNixBuildersArg :: MonadObelisk m => m String
@@ -35,7 +35,7 @@ getNixBuildersArg = do
3535
3636checkForNixDarwin :: MonadObelisk m => String -> m ()
3737checkForNixDarwin sshIdFile = do
38− (exitCode, _, _) <- readCreateProcessWithExitCode $ proc whichPath ["darwin-rebuild"]
38+ (exitCode, _, _) <- readCreateProcessWithExitCode $ proc "which" ["darwin-rebuild"]
3939 unless (exitCode == ExitSuccess) $ failWith $ T.intercalate "\n"
4040 [ "Deployments from macOS require nix-darwin to be installed."
4141 , "Follow the installation instructions here: https://github.com/LnL7/nix-darwin"
@@ -67,7 +67,7 @@ containerExists :: MonadObelisk m => FilePath -> m Bool
6767containerExists stateDir = handle (\(_ :: IOError) -> failWith needDockerMsg) $ do
6868 containerNames <- fmap (map T.strip . T.lines) $
6969 readProcessAndLogStderr Error $
70− proc dockerPath ["container", "list", "--all", "--format", "{{.Names}}"]
70+ proc "docker" ["container", "list", "--all", "--format", "{{.Names}}"]
7171 let exists = containerName `elem` containerNames
7272 when exists $ testLinuxBuild stateDir
7373 pure exists
@@ -85,7 +85,7 @@ containerSshPort = 2222
8585startContainer :: MonadObelisk m => m ()
8686startContainer = withSpinner "Starting VM builder" $
8787 callProcessAndLogOutput (Debug, Debug) $
88− proc dockerPath ["start", containerName]
88+ proc "docker" ["start", containerName]
8989
9090-- | Creates the Docker container; assumes it does not exist.
9191setupNixDocker :: MonadObelisk m => FilePath -> m ()
@@ -98,12 +98,12 @@ setupNixDocker stateDir = withSpinner ("Creating Docker container named " <> con
9898 callProcessAndLogOutput (Debug, Error) $
9999 proc rmPath ["-f", stateDir </> sshKeyFileName, stateDir </> sshKeyFileName <.> "pub"]
100100 callProcessAndLogOutput (Debug, Error) $
101− proc sshKeygenPath ["-t", "ed25519", "-f", stateDir </> sshKeyFileName, "-P", ""]
101+ proc "ssh-keygen" ["-t", "ed25519", "-f", stateDir </> sshKeyFileName, "-P", ""]
102102
103103 -- Build the docker container (which uses the SSH keys in the 'ssh' folder)
104104 containerId <- fmap T.strip $ readProcessAndLogStderr Error $
105− proc dockerPath ["build", stateDir, "--quiet"]
106− callProcessAndLogOutput (Debug, Error) $ proc dockerPath
105+ proc "docker" ["build", stateDir, "--quiet"]
106+ callProcessAndLogOutput (Debug, Error) $ proc "docker"
107107 [ "run"
108108 , "--restart", "always"
109109 , "--detach"
@@ -155,7 +155,7 @@ testLinuxBuild :: MonadObelisk m => FilePath -> m ()
155155testLinuxBuild stateDir
156156 | System.Info.os == "linux" = failWith "Using the docker builder is not necessary on linux."
157157 | otherwise = do
158− (exitCode, _stdout, stderr) <- readCreateProcessWithExitCode $ proc nixBuildExePath
158+ (exitCode, _stdout, stderr) <- readCreateProcessWithExitCode $ proc "nix-build"
159159 [ "--no-out-link"
160160 , "-E", "(import <nixpkgs> { system = \"x86_64-linux\"; }).writeText \"test\" builtins.currentTime"
161161 , "--builders", nixBuildersArgString stateDir
lib/executable-config/default.nix+3−2
@@ -5,13 +5,14 @@
55{ lib
66, runCommand
77, obeliskCleanSource
8+, staticDirName ? ""
89}:
910
1011let
1112 injectConfig = config: assets: runCommand "inject-config" {} (''
1213 set -x
13− mkdir -p $out
14− cp --no-preserve=mode -Lr "${assets}" $out/static
14+ mkdir -p "$out"/'${staticDirName}'
15+ cp --no-preserve=mode -Lr "${assets}"/. "$out"/'${staticDirName}'/
1516 chmod +w "$out"
1617 '' + lib.optionalString (!(builtins.isNull config)) ''
1718 if ! mkdir $out/config; then
lib/executable-config/lookup/src/Obelisk/Configs.hs−2
@@ -22,7 +22,6 @@ import Control.Applicative (Alternative)
2222import Control.Monad (MonadPlus)
2323import Control.Monad.Base (MonadBase)
2424import Control.Monad.Catch (MonadThrow)
25−import Control.Monad.Fail (MonadFail)
2625import Control.Monad.Fix (MonadFix)
2726import Control.Monad.IO.Class (MonadIO)
2827import Control.Monad.Morph (MFunctor)
@@ -88,7 +87,6 @@ newtype ConfigsT m a = ConfigsT { unConfigsT :: ReaderT (Map Text ByteString) m
8887 , Monad
8988 , MonadPlus
9089 , Alternative
91− , MonadFail
9290 , MonadFix
9391 , MonadThrow
9492 , MonadIO
lib/route/src/Obelisk/Route.hs+2−3
@@ -170,7 +170,6 @@ import Data.Text (Text)
170170import qualified Data.Text as T
171171import qualified Data.Text.Encoding as T
172172import Data.Text.Lens (IsText, packed, unpacked)
173−import Data.Type.Equality
174173import Data.Universe
175174import Data.Universe.Some
176175import Network.HTTP.Types.URI
@@ -1039,8 +1038,8 @@ someSumEncoder = Encoder $ pure $ EncoderImpl
10391038
10401039data Void1 :: * -> * where {}
10411040
1042−instance UniverseSome Void1 where
1043− universeSome = []
1041+instance Universe (Some Void1) where
1042+ universe = []
10441043
10451044void1Encoder :: (Applicative check, MonadError Text parse) => Encoder check parse (Some Void1) a
10461045void1Encoder = Encoder $ pure $ EncoderImpl
lib/run/src/Obelisk/Run.hs+3−3
@@ -144,9 +144,9 @@ runWidget conf configs frontend validFullEncoder = do
144144
145145 cert <- X509.newX509 >>= X509Request.makeX509FromReq certRequest
146146 _ <- X509.setPublicKey cert privateKey
147− timenow <- getCurrentTime
148− _ <- X509.setNotBefore cert $ addUTCTime (-1) timenow
149− _ <- X509.setNotAfter cert $ addUTCTime (365 * 24 * 60 * 60) timenow
147+ now <- getCurrentTime
148+ _ <- X509.setNotBefore cert $ addUTCTime (-1) now
149+ _ <- X509.setNotAfter cert $ addUTCTime (365 * 24 * 60 * 60) now
150150 _ <- X509.signX509 cert privateKey Nothing
151151
152152 certByteString <- BSUTF8.fromString <$> PEM.writeX509 cert
lib/snap-extras/src/Obelisk/Snap/Extras.hs+1−1
@@ -17,7 +17,7 @@ import System.Directory
1717-- | Set response header for "permanent" caching
1818cachePermanently :: MonadSnap m => m ()
1919cachePermanently = do
20− modifyResponse $ setHeader "Cache-Control" "public, max-age=315360000, immutable"
20+ modifyResponse $ setHeader "Cache-Control" "public, max-age=315360000"
2121 modifyResponse $ setHeader "Expires" "Tue, 01 Feb 2050 00:00:00 GMT" --TODO: This should be set to "approximately one year from the time the response is sent"
2222
2323-- | Set response header to not cache
skeleton/backend/backend.cabal+2−2
@@ -14,12 +14,12 @@ library
1414 , obelisk-route
1515 exposed-modules:
1616 Backend
17− ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -fno-show-valid-hole-fits
17+ ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O
1818
1919executable backend
2020 main-is: main.hs
2121 hs-source-dirs: src-bin
22− ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -threaded -fno-show-valid-hole-fits
22+ ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -threaded
2323 if impl(ghcjs)
2424 buildable: False
2525 build-depends: base
skeleton/cabal.project−1
@@ -1,3 +1,2 @@
11optional-packages:
22 *
3−write-ghc-environment-files: never
skeleton/common/common.cabal+1−1
@@ -12,4 +12,4 @@ library
1212 exposed-modules:
1313 Common.Api
1414 Common.Route
15− ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -fno-show-valid-hole-fits
15+ ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O
skeleton/default.nix+3−10
@@ -1,17 +1,10 @@
1−{ system ? builtins.currentSystem
2−, obelisk ? import ./.obelisk/impl {
3− inherit system;
4− iosSdkVersion = "13.2";
5−
1+{ obelisk ? import ./.obelisk/impl {
2+ system = builtins.currentSystem;
3+ iosSdkVersion = "10.2";
64 # You must accept the Android Software Development Kit License Agreement at
75 # https://developer.android.com/studio/terms in order to build Android apps.
86 # Uncomment and set this to `true` to indicate your acceptance:
97 # config.android_sdk.accept_license = false;
10−
11− # In order to use Let's Encrypt for HTTPS deployments you must accept
12− # their terms of service at https://letsencrypt.org/repository/.
13− # Uncomment and set this to `true` to indicate your acceptance:
14− # terms.security.acme.acceptTerms = false;
158 }
169}:
1710with obelisk;
skeleton/frontend/frontend.cabal+2−2
@@ -16,7 +16,7 @@ library
1616 , text
1717 exposed-modules:
1818 Frontend
19− ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -fno-show-valid-hole-fits
19+ ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O
2020
2121executable frontend
2222 main-is: main.hs
@@ -28,7 +28,7 @@ executable frontend
2828 , reflex-dom
2929 , obelisk-generated-static
3030 , frontend
31− ghc-options: -threaded -O -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -fno-show-valid-hole-fits
31+ ghc-options: -threaded -O -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates
3232 if impl(ghcjs)
3333 ghc-options: -dedupe
3434 cpp-options: -DGHCJS_BROWSER