on master help sign in
13 files changed+72−279
since splitsnapshots
unifiedsplit
ChangeLog.md−9 default.nix+4−10 lib/asset/README.md+2−2 lib/asset/manifest/obelisk-asset-manifest.cabal+1−11 lib/asset/manifest/src-bin/static-th.hs−41 lib/asset/manifest/src/Obelisk/Asset/Cabal.hs−42 lib/asset/manifest/src/Obelisk/Asset/Gather.hs+13−13 lib/asset/manifest/src/Obelisk/Asset/Promoted.hs+27−8 lib/asset/manifest/src/Obelisk/Asset/TH.hs+3−25 lib/command/obelisk-command.cabal−3 lib/command/src/Obelisk/Command/Project.hs+8−84 lib/command/src/Obelisk/Command/Run.hs+10−28 skeleton/frontend/src/Frontend.hs+4−3
ChangeLog.md−9
@@ -2,15 +2,6 @@
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−## Unreleased
6−
7−* Use TemplateHaskell to determine asset file paths
8− * Migration: All uses of `static @"some/path"` become `$(static "some/path")`. Instead of requiring `TypeApplications` and `DataKinds`, modules calling `static` must now enable `TemplateHaskell`.
9− * Deprecation: Deprecate static asset modules generated via 'obelisk-asset-manifest-generate' in favor of modules generated via 'obelisk-asset-th-generate'. The new executable takes the same arguments as the old and should be a drop-in replacement. To preserve the old behavior, set `__deprecated.useObeliskAssetManifestGenerate = true;` in your obelisk project configuration.
10− * Feature: Files added to the static directory while `ob run` is active no longer require `ob run` to be restarted
11−* Feature: When `staticFiles` is a derivation, as opposed to a regular directory, produce a symlink to the result of that derivation at `static.out` and have `ob run` serve static assets from that symlink. This makes is possible for the static asset derivation to be rebuilt and the new results served without restarting `ob run`.
12−* Feature: Rebuild static asset derivations while `ob run` is active as long as the change to the derivation is within the project folder. `ob run` now displays a message ("Static assets rebuilt and symlinked to static.out") whenever static assets have been rebuilt and the new static assets are being served.
13−
145## v0.9.1.0
156
167* [#801](https://github.com/obsidiansystems/obelisk/pull/801): Remove errors and warning for local packages without a library component
default.nix+4−10
@@ -65,7 +65,7 @@ in rec {
6565 '';
6666 nullIfAbsent = p: if lib.pathExists p then p else null;
6767 #TODO: Avoid copying files within the nix store. Right now, obelisk-asset-manifest-generate copies files into a big blob so that the android/ios static assets can be imported from there; instead, we should get everything lined up right before turning it into an APK, so that copies, if necessary, only exist temporarily.
68− processAssets = { src, packageName ? "obelisk-generated-static", moduleName ? "Obelisk.Generated.Static", exe ? "obelisk-asset-th-generate" }: pkgs.runCommand "asset-manifest" {
68+ processAssets = { src, packageName ? "obelisk-generated-static", moduleName ? "Obelisk.Generated.Static" }: pkgs.runCommand "asset-manifest" {
6969 inherit src;
7070 outputs = [ "out" "haskellManifest" "symlinked" ];
7171 nativeBuildInputs = [ ghcObelisk.obelisk-asset-manifest ];
@@ -73,7 +73,7 @@ in rec {
7373 set -euo pipefail
7474 touch "$out"
7575 mkdir -p "$symlinked"
76− ${exe} "$src" "$haskellManifest" ${packageName} ${moduleName} "$symlinked"
76+ obelisk-asset-manifest-generate "$src" "$haskellManifest" ${packageName} ${moduleName} "$symlinked"
7777 '';
7878
7979 compressedJs = frontend: optimizationLevel: pkgs.runCommand "compressedJs" {} ''
@@ -237,14 +237,13 @@ in rec {
237237 , withHoogle ? false # Setting this to `true` makes shell reloading far slower
238238 , __closureCompilerOptimizationLevel ? "ADVANCED" # Set this to `null` to skip the closure-compiler step
239239 , __withGhcide ? false
240− , __deprecated ? {}
241240 }:
242241 let
243242 allConfig = nixpkgs.lib.makeExtensible (self: {
244243 base = base';
245244 inherit args;
246245 userSettings = {
247− inherit android ios packages overrides tools shellToolOverrides withHoogle __closureCompilerOptimizationLevel __withGhcide __deprecated;
246+ inherit android ios packages overrides tools shellToolOverrides withHoogle __closureCompilerOptimizationLevel __withGhcide;
248247 staticFiles = if staticFiles == null then self.base + /static else staticFiles;
249248 };
250249 frontendName = "frontend";
@@ -252,12 +251,7 @@ in rec {
252251 commonName = "common";
253252 staticName = "obelisk-generated-static";
254253 staticFilesImpure = let fs = self.userSettings.staticFiles; in if lib.isDerivation fs then fs else toString fs;
255− processedStatic = processAssets {
256− src = self.userSettings.staticFiles;
257− exe = if lib.attrByPath ["userSettings" "__deprecated" "useObeliskAssetManifestGenerate"] false self
258− then builtins.trace "obelisk-asset-manifest-generate is deprecated. Use obelisk-asset-th-generate instead." "obelisk-asset-manifest-generate"
259− else "obelisk-asset-th-generate";
260− };
254+ processedStatic = processAssets { src = self.userSettings.staticFiles; };
261255 # The packages whose names and roles are defined by this package
262256 predefinedPackages = lib.filterAttrs (_: x: x != null) {
263257 ${self.frontendName} = nullIfAbsent (self.base + "/frontend");
lib/asset/README.md+2−2
@@ -5,7 +5,7 @@
55
66**Efficiently served, aggressively cached static web resources.**
77
8−The `assets.nix` file contains nix expressions that are a mutually recursive set of attributes used to create static asset directories with hashable file encodings. This file should be incorporated within your project's `default.nix` file.
8+The `assets.nix` file contains nix expressions that are a mutually recursive set of attributes used to create static asset directories with hashable file encodings. This file should be incorporated within your project's `default.nix` file. (See `example/default.nix`, line 2)
99
1010```nix
1111{ assets ? import ./../assets.nix { inherit nixpkgs; } }:
@@ -19,7 +19,7 @@ In this example, `mkAssets` is used on a directory that has a `.png` file inside
1919myAssets = assets.mkAssets ./static;
2020```
2121
22−Once you have successfully incorporated `assets.nix` into your project's nix file(s), use `nix-build` to generate a symlink of your `mkAssets` expression. The following command will generate an immutable symlink that holds hashed static assets.
22+Once you have successfully incorporated `assets.nix` into your project's nix file(s), use `nix-build` to generate a symlink of your `mkAssets` expression. The following command from `example/run-example` (line 3) will generate an immutable symlink that holds hashed static assets.
2323
2424```bash
2525nix-build -o static.assets -A myAssets
lib/asset/manifest/obelisk-asset-manifest.cabal+1−11
@@ -27,7 +27,6 @@ library
2727 , unix-compat
2828 , vector
2929 exposed-modules:
30− Obelisk.Asset.Cabal
3130 Obelisk.Asset.Gather
3231 Obelisk.Asset.Promoted
3332 Obelisk.Asset.Symlink
@@ -36,7 +35,7 @@ library
3635 other-extensions: TemplateHaskell
3736 ghc-options:
3837 -Wall -Werror -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O2
39− -fno-warn-unused-do-bind -funbox-strict-fields -fprof-auto-calls
38+ -fno-warn-unused-do-bind -funbox-strict-fields -fprof-auto-calls
4039
4140executable obelisk-asset-manifest-generate
4241 hs-source-dirs: src-bin
@@ -45,12 +44,3 @@ executable obelisk-asset-manifest-generate
4544 base
4645 , obelisk-asset-manifest
4746 , text
48−
49−executable obelisk-asset-th-generate
50− hs-source-dirs: src-bin
51− main-is: static-th.hs
52− build-depends:
53− base
54− , obelisk-asset-manifest
55− , filepath
56− , text
lib/asset/manifest/src-bin/static-th.hsdeleted−41
@@ -1,41 +0,0 @@
1−import qualified Data.Text as T
2−import Obelisk.Asset.Cabal
3−import Obelisk.Asset.Gather
4−import Obelisk.Asset.Symlink
5−import System.Environment
6−import System.FilePath
7−
8−main :: IO ()
9−main = do
10− --TODO: Usage
11− [root, haskellTarget, packageName, moduleName, fileTarget] <- getArgs
12− paths <- gatherHashedPaths root
13− writeCabalProject haskellTarget $ SimplePkg
14− { _simplePkg_name = T.pack packageName
15− , _simplePkg_moduleName = T.pack moduleName
16− , _simplePkg_dependencies = map T.pack
17− [ "base"
18− , "obelisk-asset-manifest"
19− , "template-haskell"
20− ]
21− , _simplePkg_moduleContents = T.pack $ unlines
22− [ "{-# Language CPP #-}"
23− , "{-|"
24− , " Description:"
25− , " Automatically generated module that provides the 'static' TH function"
26− , " to generate paths to static assets."
27− , "-}"
28− , "module " <> moduleName <> " ( static ) where"
29− , ""
30− , "import Obelisk.Asset.TH"
31− , "import Language.Haskell.TH"
32− , ""
33− , "static :: FilePath -> Q Exp"
34− , "#ifdef OBELISK_ASSET_PASSTHRU"
35− , "static = staticAssetRaw"
36− , "#else"
37− , "static = staticAssetHashed " <> show root
38− , "#endif"
39− ]
40− }
41− copyAndSymlink paths root fileTarget
lib/asset/manifest/src/Obelisk/Asset/Cabal.hsdeleted−42
@@ -1,42 +0,0 @@
1−{-# Language OverloadedStrings #-}
2−module Obelisk.Asset.Cabal where
3−
4−import qualified Data.List as L
5−import Data.Text (Text)
6−import qualified Data.Text as T
7−import qualified Data.Text.IO as T
8−import System.Directory
9−import System.FilePath
10−
11−-- | A generated single-module package
12−data SimplePkg = SimplePkg
13− { _simplePkg_name :: Text
14− , _simplePkg_moduleName :: Text
15− , _simplePkg_moduleContents :: Text
16− , _simplePkg_dependencies :: [Text]
17− }
18−
19−cabalFile :: SimplePkg -> Text
20−cabalFile (SimplePkg packageName moduleName _ deps) = T.unlines
21− [ "name: " <> packageName
22− , "version: 0"
23− , "cabal-version: >= 1.2"
24− , "build-type: Simple"
25− , ""
26− , "library"
27− , " hs-source-dirs: src"
28− , " build-depends:"
29− , " " <> T.intercalate ", " deps
30− , " exposed-modules: " <> moduleName
31− ]
32−
33−writeCabalProject :: FilePath -> SimplePkg -> IO ()
34−writeCabalProject target pkg = do
35− createDirectoryIfMissing True target
36− T.writeFile (target </> T.unpack (_simplePkg_name pkg) <.> "cabal") $ cabalFile pkg
37− let moduleName = _simplePkg_moduleName pkg
38− (modName', moduleDirPath) = case L.uncons (reverse $ T.splitOn "." moduleName) of
39− Nothing -> error $ "writeStaticProject: invalid module name " <> T.unpack moduleName
40− Just (name, parents) -> (name, target </> "src" </> T.unpack (T.intercalate "/" $ reverse parents))
41− createDirectoryIfMissing True moduleDirPath
42− T.writeFile (moduleDirPath </> T.unpack modName' <.> "hs") $ _simplePkg_moduleContents pkg
lib/asset/manifest/src/Obelisk/Asset/Gather.hs+13−13
@@ -6,21 +6,21 @@ module Obelisk.Asset.Gather
66 , toHashedPath
77 ) where
88
9−import Control.DeepSeq (force)
9+import Control.DeepSeq
1010import Control.Monad (forM)
11−import Data.Bits (shift, (.|.), (.&.))
12−import qualified Data.ByteString.Lazy as LBS (readFile, toStrict, ByteString, length, index)
13−import qualified Data.ByteString.Lazy.Builder as LBS (toLazyByteString, word8)
14−import Data.Char (ord)
15−import Data.Digest.Pure.SHA (bytestringDigest, sha256)
11+import Data.Bits
12+import qualified Data.ByteString.Lazy as LBS
13+import qualified Data.ByteString.Lazy.Builder as LBS
14+import Data.Char
15+import Data.Digest.Pure.SHA
1616import Data.Map (Map)
17−import qualified Data.Map as Map (singleton)
18−import qualified Data.Text as T (unpack)
19−import Data.Text.Encoding (decodeUtf8)
20−import qualified Data.Vector.Unboxed as UV ((!), fromList)
21−import Data.Word (Word8)
22−import System.FilePath.Posix ((</>), splitFileName, normalise)
23−import System.Directory (listDirectory, doesFileExist)
17+import qualified Data.Map as Map
18+import qualified Data.Text as T
19+import Data.Text.Encoding
20+import qualified Data.Vector.Unboxed as UV
21+import Data.Word
22+import System.FilePath.Posix
23+import System.Directory
2424
2525-- | Given a path, recursively explore it, creating hashed paths for all files found
2626gatherHashedPaths
lib/asset/manifest/src/Obelisk/Asset/Promoted.hs+27−8
@@ -10,6 +10,7 @@ module Obelisk.Asset.Promoted
1010import Obelisk.Asset.Gather
1111
1212import Data.Foldable
13+import qualified Data.List as L
1314import Language.Haskell.TH (runQ, pprint)
1415import Language.Haskell.TH.Syntax hiding (lift)
1516import GHC.TypeLits
@@ -17,11 +18,12 @@ import Data.Sequence (Seq)
1718import qualified Data.Sequence as Seq
1819import Control.Monad.Trans.Writer
1920import System.FilePath
21+import System.Directory
2022import Data.Text (Text)
2123import qualified Data.Text as T
24+import qualified Data.Text.IO as T
2225import Data.Map (Map)
2326import qualified Data.Map as Map
24−import Obelisk.Asset.Cabal (writeCabalProject, SimplePkg(..))
2527
2628data StaticConfig = StaticConfig
2729 { _staticConfig_packageName :: Text --TODO: Better type
@@ -30,14 +32,31 @@ data StaticConfig = StaticConfig
3032
3133writeStaticProject :: Map FilePath FilePath -> FilePath -> StaticConfig -> IO ()
3234writeStaticProject paths target cfg = do
35+ createDirectoryIfMissing True target
36+ T.writeFile (target </> T.unpack (_staticConfig_packageName cfg) <.> "cabal") $ staticCabalFile cfg
3337 let modName = _staticConfig_moduleName cfg
38+ (modName', moduleDirPath) = case L.uncons (reverse $ T.splitOn "." modName) of
39+ Nothing -> error $ "writeStaticProject: invalid module name " <> T.unpack modName
40+ Just (name, parents) -> (name, target </> "src" </> T.unpack (T.intercalate "/" $ reverse parents))
41+ createDirectoryIfMissing True moduleDirPath
3442 modContents <- staticModuleFile modName paths
35− writeCabalProject target $ SimplePkg
36− { _simplePkg_name = _staticConfig_packageName cfg
37− , _simplePkg_moduleName = _staticConfig_moduleName cfg
38− , _simplePkg_moduleContents = modContents
39− , _simplePkg_dependencies = ["base", "ghc-prim", "text"]
40− }
43+ T.writeFile (moduleDirPath </> T.unpack modName' <.> "hs") modContents
44+
45+staticCabalFile :: StaticConfig -> Text
46+staticCabalFile cfg = T.unlines
47+ [ "name: " <> _staticConfig_packageName cfg
48+ , "version: 0"
49+ , "cabal-version: >= 1.2"
50+ , "build-type: Simple"
51+ , ""
52+ , "library"
53+ , " hs-source-dirs: src"
54+ , " build-depends:"
55+ , " base,"
56+ , " ghc-prim,"
57+ , " text"
58+ , " exposed-modules: " <> _staticConfig_moduleName cfg
59+ ]
4160
4261staticModuleFile :: Text -> Map FilePath FilePath -> IO Text
4362staticModuleFile moduleName paths = do
@@ -50,7 +69,7 @@ staticModuleFile moduleName paths = do
5069 , "{-# LANGUAGE OverloadedStrings #-}"
5170 , "{-# LANGUAGE ScopedTypeVariables #-}"
5271 , "{-# LANGUAGE TypeApplications #-}"
53− , "module " <> moduleName <> " {-# DEPRECATED \"Generate this module with the 'obelisk-asset-th-generate' executable instead.\" #-} where"
72+ , "module " <> moduleName <> " where"
5473 , ""
5574 , "import qualified GHC.Types"
5675 , "import Data.Text (Text)"
lib/asset/manifest/src/Obelisk/Asset/TH.hs+3−25
@@ -1,36 +1,14 @@
1−{-|
2−Description:
3− Template Haskell for generating asset paths.
4−-}
51module Obelisk.Asset.TH
62 ( assetPath
7− , staticAssetRaw
8− , staticAssetHashed
93 ) where
104
115import Obelisk.Asset.Gather
126
13−import Language.Haskell.TH
147import Language.Haskell.TH.Syntax
158import System.FilePath.Posix
169
17−-- | Produces the hashed path of a file
18−hashedAssetFilePath :: FilePath -> FilePath -> Q FilePath
19−hashedAssetFilePath root relativePath = do
20− qAddDependentFile $ root </> relativePath
21− runIO (toHashedPath root relativePath)
22−
2310-- | Produces a string literal with the hashed path of the file
2411assetPath :: FilePath -> FilePath -> Q Exp
25−assetPath root relativePath =
26− LitE . StringL <$> hashedAssetFilePath root relativePath
27−
28−staticPrefix :: FilePath
29−staticPrefix = "/static"
30−
31−staticAssetRaw :: FilePath -> Q Exp
32−staticAssetRaw fp = returnQ $ LitE $ StringL $ staticPrefix </> fp
33−
34−staticAssetHashed :: FilePath -> FilePath -> Q Exp
35−staticAssetHashed root fp = do
36− LitE . StringL . (staticPrefix </>) <$> hashedAssetFilePath root fp
12+assetPath root relativePath = do
13+ qAddDependentFile $ root </> relativePath
14+ LitE . StringL <$> runIO (toHashedPath root relativePath)
lib/command/obelisk-command.cabal−3
@@ -20,7 +20,6 @@ library
2020 , exceptions
2121 , extra
2222 , filepath
23− , fsnotify
2423 , git
2524 , github
2625 , here
@@ -40,8 +39,6 @@ library
4039 , optparse-applicative
4140 , placeholders
4241 , process
43− , reflex
44− , reflex-fsnotify
4542 , shell-escape
4643 , temporary
4744 , terminal-size
lib/command/src/Obelisk/Command/Project.hs+8−84
@@ -1,9 +1,6 @@
11{-# LANGUAGE FlexibleContexts #-}
22{-# LANGUAGE LambdaCase #-}
33{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE ScopedTypeVariables #-}
5−{-# LANGUAGE TupleSections #-}
6−
74module Obelisk.Command.Project
85 ( InitSource (..)
96 , findProjectObeliskCommand
@@ -19,17 +16,12 @@ module Obelisk.Command.Project
1916 , toObeliskDir
2017 , withProjectRoot
2118 , bashEscape
22− , getHaskellManifestProjectPath
23− , AssetSource(..)
24− , describeImpureAssetSource
25− , watchStaticFilesDerivation
2619 ) where
2720
2821import Control.Concurrent.MVar (MVar, newMVar, withMVarMasked)
29−import Control.Lens ((.~), (?~), (<&>), (^.), _3)
22+import Control.Lens ((.~), (?~), (<&>))
3023import Control.Monad
3124import Control.Monad.IO.Class (liftIO)
32−import Control.Monad.Log
3325import Control.Monad.State
3426import qualified Data.Aeson as Json
3527import qualified Data.ByteString.UTF8 as BSU
@@ -42,19 +34,14 @@ import Data.Text (Text)
4234import qualified Data.Text as T
4335import Data.Text.Encoding (decodeUtf8, encodeUtf8)
4436import Data.Traversable (for)
45−import Reflex
46−import Reflex.FSNotify
47−import Reflex.Host.Headless
4837import System.Directory
4938import System.Environment (lookupEnv)
5039import System.FilePath
51−import System.FSNotify (defaultConfig)
5240import System.IO.Temp
5341import System.IO.Unsafe (unsafePerformIO)
5442import System.PosixCompat.Files
5543import System.PosixCompat.Types
5644import System.PosixCompat.User
57−import qualified System.Process as Proc
5845import Text.ShellEscape (bash, bytes)
5946
6047import GitHub.Data.GitData (Branch)
@@ -347,21 +334,7 @@ nixShellWithHoogle root isPure shell' command = do
347334 \})).project.shells.${shell}"
348335 & nixShellConfig_common . nixCmdConfig_args .~ [ strArg "shell" shell' ]
349336
350−-- | Describes the provenance of static assets (i.e., are they the result of a derivation
351−-- that was built, or just a folder full of files.
352−data AssetSource = AssetSource_Derivation
353− | AssetSource_Files
354− deriving (Eq)
355−
356−-- | Some log messages to make it easier to tell where static files are coming from
357−describeImpureAssetSource :: AssetSource -> Text -> Text
358−describeImpureAssetSource src path = case src of
359− AssetSource_Files -> "Assets impurely loaded from: " <> path
360− AssetSource_Derivation -> "Assets derivation built and impurely loaded from: " <> path
361−
362−-- | Determine where the static files of a project are and whether they're plain files or a derivation.
363−-- If they are a derivation, that derivation will be built.
364−findProjectAssets :: MonadObelisk m => FilePath -> m (AssetSource, Text)
337+findProjectAssets :: MonadObelisk m => FilePath -> m Text
365338findProjectAssets root = do
366339 isDerivation <- readProcessAndLogStderr Debug $ setCwd (Just root) $
367340 proc nixExePath
@@ -373,59 +346,10 @@ findProjectAssets root = do
373346 ]
374347 -- Check whether the impure static files are a derivation (and so must be built)
375348 if isDerivation == "1"
376− then do
377− _ <- readProcessAndLogStderr Debug $ setCwd (Just root) $
378− proc nixBuildExePath staticFilesDrvSymlinkArgs
379−
380− pure (AssetSource_Derivation, T.pack $ root </> "static.out")
381− else fmap (AssetSource_Files,) $ readProcessAndLogStderr Debug $ setCwd (Just root) $
349+ then fmap T.strip $ readProcessAndLogStderr Debug $ setCwd (Just root) $ -- Strip whitespace here because nix-build has no --raw option
350+ proc nixBuildExePath
351+ [ "--no-out-link"
352+ , "-E", "(import ./. {}).passthru.staticFilesImpure"
353+ ]
354+ else readProcessAndLogStderr Debug $ setCwd (Just root) $
382355 proc nixExePath ["eval", "-f", ".", "passthru.staticFilesImpure", "--raw"]
383−
384−-- | Get the nix store path to the generated static asset manifest module (e.g., "obelisk-generated-static")
385−getHaskellManifestProjectPath :: MonadObelisk m => FilePath -> m Text
386−getHaskellManifestProjectPath root = fmap T.strip $ readProcessAndLogStderr Debug $ setCwd (Just root) $
387− proc nixBuildExePath
388− [ "--no-out-link"
389− , "-E"
390− , "(let a = import ./. {}; in a.passthru.processedStatic.haskellManifest)"
391− ]
392−
393−staticFilesDrvSymlinkArgs :: [String]
394−staticFilesDrvSymlinkArgs =
395− [ "-o", "static.out"
396− , "-E", "(import ./. {}).passthru.staticFilesImpure"
397− ]
398−
399−-- | Watch the project directory for file changes and check whether those file changes
400−-- cause changes in the static files nix derivation. If so, rebuild it.
401−watchStaticFilesDerivation
402− :: MonadObelisk m
403− => FilePath
404− -> m ()
405−watchStaticFilesDerivation root = do
406− cfg <- getCliConfig
407− drv0 <- liftIO runShowDrv
408− liftIO $ runHeadlessApp $ do
409− pb <- getPostBuild
410− checkForChanges <- watchDirectoryTree defaultConfig (root <$ pb) (const True)
411− drv <- performEvent $ liftIO runShowDrv <$ checkForChanges
412− drvs <- foldDyn (\new (_, old, _) -> (old, new, old /= new)) (drv0, drv0, False) drv
413− out <- throttleBatchWithLag
414− (\e -> performEvent $ ffor e $ \_ -> liftIO $ void runDrvBuild)
415− (void $ ffilter (^._3) $ updated drvs)
416− performEvent_ $ ffor out $ \_ ->
417− runCli cfg $
418− putLog Informational "Static assets rebuilt and symlinked to static.out"
419− pure never
420− where
421− showDrv :: Proc.CreateProcess
422− showDrv = (Proc.proc nixExePath
423− [ "show-derivation"
424− , "-f", "."
425− , "passthru.staticFilesImpure"
426− ]) { Proc.cwd = Just root }
427− runShowDrv :: IO String
428− runShowDrv = Proc.readCreateProcess showDrv ""
429− runDrvBuild :: IO String
430− runDrvBuild = Proc.readCreateProcess
431− ((Proc.proc nixBuildExePath staticFilesDrvSymlinkArgs) { Proc.cwd = Just root }) ""
lib/command/src/Obelisk/Command/Run.hs+10−28
@@ -14,8 +14,7 @@ module Obelisk.Command.Run where
1414import Control.Arrow ((&&&))
1515import Control.Exception (Exception, bracket)
1616import Control.Lens (ifor, (.~), (&))
17−import Control.Concurrent (forkIO)
18−import Control.Monad (filterM, void)
17+import Control.Monad (filterM)
1918import Control.Monad.Except (runExceptT, throwError)
2019import Control.Monad.IO.Class (liftIO)
2120import Control.Monad.Reader (MonadIO)
@@ -64,23 +63,21 @@ import System.FilePath
6463import qualified System.Info
6564import System.IO.Temp (withSystemTempDirectory)
6665
67−import Obelisk.App (MonadObelisk, getObelisk, runObelisk)
66+import Obelisk.App (MonadObelisk)
6867import Obelisk.CliApp (
6968 Severity (..),
7069 failWith,
71− getCliConfig,
7270 proc,
7371 putLog,
7472 readCreateProcessWithExitCode,
7573 readProcessAndLogStderr,
76− runCli,
7774 runProcess_,
7875 setCwd,
7976 setDelegateCtlc,
8077 withSpinner,
8178 )
8279import Obelisk.Command.Nix
83−import Obelisk.Command.Project
80+import Obelisk.Command.Project (nixShellWithoutPkgs, withProjectRoot, findProjectAssets, bashEscape)
8481import Obelisk.Command.Thunk (attrCacheFileName)
8582import Obelisk.Command.Utils (findExePath, ghcidExePath)
8683
@@ -147,8 +144,8 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
147144 , _target_attr = Just "__unstable__.profiledObRun"
148145 , _target_expr = Nothing
149146 }
150− (assetType, assets) <- findProjectAssets root
151− putLog Debug $ describeImpureAssetSource assetType assets
147+ assets <- findProjectAssets root
148+ putLog Debug $ "Assets impurely loaded from: " <> assets
152149 time <- liftIO getCurrentTime
153150 let profileBaseName = formatTime defaultTimeLocale profileBasePattern time
154151 liftIO $ createDirectoryIfMissing True $ takeDirectory $ root </> profileBaseName
@@ -166,17 +163,9 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
166163run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
167164run root interpretPaths = do
168165 pkgs <- getParsedLocalPkgs root interpretPaths
169− (assetType, assets) <- findProjectAssets root
170− manifestPkg <- parsePackagesOrFail . (:[]) . T.unpack =<< getHaskellManifestProjectPath root
171− putLog Debug $ describeImpureAssetSource assetType assets
172− case assetType of
173− AssetSource_Derivation -> do
174− cliConfig <- getCliConfig
175− ob <- getObelisk
176− putLog Debug "Starting static file derivation watcher..."
177− void $ liftIO $ forkIO $ runCli cliConfig $ runObelisk ob $ watchStaticFilesDerivation root
178− _ -> pure ()
179− ghciArgs <- getGhciSessionSettings (pkgs <> manifestPkg) root True
166+ assets <- findProjectAssets root
167+ putLog Debug $ "Assets impurely loaded from: " <> assets
168+ ghciArgs <- getGhciSessionSettings pkgs root True
180169 freePort <- getFreePort
181170 withGhciScriptArgs pkgs $ \dotGhciArgs -> do
182171 runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
@@ -233,12 +222,7 @@ getLocalPkgs root interpretPaths = do
233222 let rootsAndExclusions = calcIntepretFinds "" interpretPaths
234223
235224 fmap fold $ for (MMap.toAscList rootsAndExclusions) $ \(interpretPathRoot, exclusions) ->
236− let allExclusions = obeliskPackageExclusions
237− <> exclusions
238− <> Set.singleton ("*" </> attrCacheFileName)
239− <> Set.singleton ("*" </> "lib/asset/manifest") -- NB: obelisk-asset-manifest is excluded because it generates
240− -- a module that in turn imports it. This will cause ob run to
241− -- fail in its current implementation.
225+ let allExclusions = obeliskPackageExclusions <> exclusions <> Set.singleton ("*" </> attrCacheFileName)
242226 in fmap (Set.fromList . map normalise) $ runFind $
243227 ["-L", interpretPathRoot, "(", "-name", "*.cabal", "-o", "-name", Hpack.packageConfig, ")", "-a", "-type", "f"]
244228 <> concat [["-not", "-path", p </> "*"] | p <- toList allExclusions]
@@ -416,8 +400,7 @@ withGhciScriptArgs
416400 => f CabalPackageInfo -- ^ List of packages to load into ghci
417401 -> ([String] -> m ()) -- ^ Action to run with the extra ghci arguments
418402 -> m ()
419−withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp ->
420− f ["-XNoImplicitPrelude", "-ghci-script", fp]
403+withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp -> f ["-XNoImplicitPrelude", "-ghci-script", fp]
421404 where
422405 -- These lines must be first and allow the session to support a custom Prelude when @-XNoImplicitPrelude@
423406 -- is passed to the ghci session.
@@ -475,7 +458,6 @@ getGhciSessionSettings (toList -> packageInfos) pathBase useRelativePaths = do
475458
476459 pure
477460 $ baseGhciOptions
478− <> ["-DOBELISK_ASSET_PASSTHRU"] -- For passthrough static assets
479461 <> ["-F", "-pgmF", selfExe, "-optF", preprocessorIdentifier]
480462 <> concatMap (\p -> ["-optF", p]) pkgFiles
481463 <> [ "-i" <> intercalate ":" (concatMap toList pkgSrcPaths) ]
skeleton/frontend/src/Frontend.hs+4−3
@@ -1,5 +1,6 @@
1+{-# LANGUAGE DataKinds #-}
12{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE TypeApplications #-}
34
45module Frontend where
56
@@ -26,7 +27,7 @@ frontend :: Frontend (R FrontendRoute)
2627frontend = Frontend
2728 { _frontend_head = do
2829 el "title" $ text "Obelisk Minimal Example"
29− elAttr "link" ("href" =: $(static "main.css") <> "type" =: "text/css" <> "rel" =: "stylesheet") blank
30+ elAttr "link" ("href" =: static @"main.css" <> "type" =: "text/css" <> "rel" =: "stylesheet") blank
3031 , _frontend_body = do
3132 el "h1" $ text "Welcome to Obelisk!"
3233 el "p" $ text $ T.pack commonStuff
@@ -37,7 +38,7 @@ frontend = Frontend
3738 -- print "Hello, World!" on the client.
3839 prerender_ blank $ liftJSM $ void $ eval ("console.log('Hello, World!')" :: T.Text)
3940
40− elAttr "img" ("src" =: $(static "obelisk.jpg")) blank
41+ elAttr "img" ("src" =: static @"obelisk.jpg") blank
4142 el "div" $ do
4243 exampleConfig <- getConfig "common/example"
4344 case exampleConfig of