@@ -14,8 +14,7 @@ module Obelisk.Command.Run where
14import Control.Arrow ((&&&))
14import Control.Arrow ((&&&))
15import Control.Exception (Exception, bracket)
15import Control.Exception (Exception, bracket)
16import Control.Lens (ifor, (.~), (&))
16import Control.Lens (ifor, (.~), (&))
17−import Control.Concurrent (forkIO)
17+import Control.Monad (filterM)
18−import Control.Monad (filterM, void)
19import Control.Monad.Except (runExceptT, throwError)
18import Control.Monad.Except (runExceptT, throwError)
20import Control.Monad.IO.Class (liftIO)
19import Control.Monad.IO.Class (liftIO)
21import Control.Monad.Reader (MonadIO)
20import Control.Monad.Reader (MonadIO)
@@ -46,23 +45,13 @@ import Debug.Trace (trace)
46import Distribution.Compiler (CompilerFlavor(..))
45import Distribution.Compiler (CompilerFlavor(..))
47import Distribution.PackageDescription.Parsec (parseGenericPackageDescription)
46import Distribution.PackageDescription.Parsec (parseGenericPackageDescription)
48import Distribution.Parsec.ParseResult (runParseResult)
47import Distribution.Parsec.ParseResult (runParseResult)
49−import Distribution.Pretty (prettyShow)
50−import Distribution.Simple.Compiler (PackageDB (GlobalPackageDB))
51−import Distribution.Simple.Configure (configCompilerEx, getInstalledPackages)
52−import Distribution.Simple.PackageIndex (InstalledPackageIndex, lookupDependency)
53−import Distribution.Simple.Program.Db (defaultProgramDb)
54import qualified Distribution.System as Dist
48import qualified Distribution.System as Dist
55−import Distribution.Types.BuildInfo (buildable, cppOptions, defaultExtensions, defaultLanguage, hsSourceDirs, options, targetBuildDepends)
49+import Distribution.Types.BuildInfo (buildable, cppOptions, defaultExtensions, defaultLanguage, hsSourceDirs, options)
56import Distribution.Types.CondTree (simplifyCondTree)
50import Distribution.Types.CondTree (simplifyCondTree)
57−import Distribution.Types.Dependency (Dependency (..), depPkgName)
58import Distribution.Types.GenericPackageDescription (ConfVar (Arch, Impl, OS), condLibrary)
51import Distribution.Types.GenericPackageDescription (ConfVar (Arch, Impl, OS), condLibrary)
59−import Distribution.Types.InstalledPackageInfo (compatPackageKey)
60import Distribution.Types.Library (libBuildInfo)
52import Distribution.Types.Library (libBuildInfo)
61−import Distribution.Types.PackageName (mkPackageName)
62−import Distribution.Types.VersionRange (anyVersion)
63import Distribution.Utils.Generic (toUTF8BS, readUTF8File)
53import Distribution.Utils.Generic (toUTF8BS, readUTF8File)
64import qualified Distribution.Parsec.Common as Dist
54import qualified Distribution.Parsec.Common as Dist
65−import qualified Distribution.Verbosity as Verbosity (silent)
66import qualified Hpack.Config as Hpack
55import qualified Hpack.Config as Hpack
67import qualified Hpack.Render as Hpack
56import qualified Hpack.Render as Hpack
68import qualified Hpack.Yaml as Hpack
57import qualified Hpack.Yaml as Hpack
@@ -74,7 +63,7 @@ import System.FilePath
74import qualified System.Info
63import qualified System.Info
75import System.IO.Temp (withSystemTempDirectory)
64import System.IO.Temp (withSystemTempDirectory)
77−import Obelisk.App (MonadObelisk, getObelisk, runObelisk)
66+import Obelisk.App (MonadObelisk)
78import Obelisk.CliApp (
67import Obelisk.CliApp (
79 Severity (..),
68 Severity (..),
@@ -88,7 +77,7 @@ import Obelisk.CliApp (
88 withSpinner,
77 withSpinner,
90import Obelisk.Command.Nix
79import Obelisk.Command.Nix
91−import Obelisk.Command.Project
80+import Obelisk.Command.Project (nixShellWithoutPkgs, withProjectRoot, findProjectAssets, bashEscape)
92import Obelisk.Command.Thunk (attrCacheFileName)
81import Obelisk.Command.Thunk (attrCacheFileName)
93import Obelisk.Command.Utils (findExePath, ghcidExePath)
82import Obelisk.Command.Utils (findExePath, ghcidExePath)
@@ -107,8 +96,6 @@ data CabalPackageInfo = CabalPackageInfo
107 -- ^ List of compiler-specific options (e.g., the "ghc-options" field of the cabal file)
96 -- ^ List of compiler-specific options (e.g., the "ghc-options" field of the cabal file)
108 , _cabalPackageInfo_cppOptions :: [String]
97 , _cabalPackageInfo_cppOptions :: [String]
109 -- ^ List of CPP (C Preprocessor) options (e.g. the "cpp-options" field of the cabal file)
98 -- ^ List of CPP (C Preprocessor) options (e.g. the "cpp-options" field of the cabal file)
110− , _cabalPackageInfo_buildDepends :: [Dependency]
111− -- ^ List of build dependencies listed in the cabal file
114-- | 'Bool' with a better name for its purpose.
101-- | 'Bool' with a better name for its purpose.
@@ -157,8 +144,8 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
157 , _target_attr = Just "__unstable__.profiledObRun"
144 , _target_attr = Just "__unstable__.profiledObRun"
158 , _target_expr = Nothing
145 , _target_expr = Nothing
160− (assetType, assets) <- findProjectAssets root
147+ assets <- findProjectAssets root
161− putLog Debug $ describeImpureAssetSource assetType assets
148+ putLog Debug $ "Assets impurely loaded from: " <> assets
162 time <- liftIO getCurrentTime
149 time <- liftIO getCurrentTime
163 let profileBaseName = formatTime defaultTimeLocale profileBasePattern time
150 let profileBaseName = formatTime defaultTimeLocale profileBasePattern time
164 liftIO $ createDirectoryIfMissing True $ takeDirectory $ root </> profileBaseName
151 liftIO $ createDirectoryIfMissing True $ takeDirectory $ root </> profileBaseName
@@ -176,16 +163,9 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
176run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
163run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
177run root interpretPaths = do
164run root interpretPaths = do
178 pkgs <- getParsedLocalPkgs root interpretPaths
165 pkgs <- getParsedLocalPkgs root interpretPaths
179− (assetType, assets) <- findProjectAssets root
166+ assets <- findProjectAssets root
180− manifestPkg <- parsePackagesOrFail . (:[]) . T.unpack =<< getHaskellManifestProjectPath root
167+ putLog Debug $ "Assets impurely loaded from: " <> assets
181− putLog Debug $ describeImpureAssetSource assetType assets
183− AssetSource_Derivation -> do
185− putLog Debug "Starting static file derivation watcher..."
186− void $ liftIO $ forkIO $ runObelisk ob $ watchStaticFilesDerivation root
188− ghciArgs <- getGhciSessionSettings (pkgs <> manifestPkg) root True
168+ ghciArgs <- getGhciSessionSettings pkgs root True
189 freePort <- getFreePort
169 freePort <- getFreePort
190 withGhciScriptArgs pkgs $ \dotGhciArgs -> do
170 withGhciScriptArgs pkgs $ \dotGhciArgs -> do
191 runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
171 runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
@@ -242,12 +222,7 @@ getLocalPkgs root interpretPaths = do
242 let rootsAndExclusions = calcIntepretFinds "" interpretPaths
222 let rootsAndExclusions = calcIntepretFinds "" interpretPaths
244 fmap fold $ for (MMap.toAscList rootsAndExclusions) $ \(interpretPathRoot, exclusions) ->
224 fmap fold $ for (MMap.toAscList rootsAndExclusions) $ \(interpretPathRoot, exclusions) ->
245− let allExclusions = obeliskPackageExclusions
225+ let allExclusions = obeliskPackageExclusions <> exclusions <> Set.singleton ("*" </> attrCacheFileName)
247− <> Set.singleton ("*" </> attrCacheFileName)
248− <> Set.singleton ("*" </> "lib/asset/manifest") -- NB: obelisk-asset-manifest is excluded because it generates
249− -- a module that in turn imports it. This will cause ob run to
250− -- fail in its current implementation.
251 in fmap (Set.fromList . map normalise) $ runFind $
226 in fmap (Set.fromList . map normalise) $ runFind $
252 ["-L", interpretPathRoot, "(", "-name", "*.cabal", "-o", "-name", Hpack.packageConfig, ")", "-a", "-type", "f"]
227 ["-L", interpretPathRoot, "(", "-name", "*.cabal", "-o", "-name", Hpack.packageConfig, ")", "-a", "-type", "f"]
253 <> concat [["-not", "-path", p </> "*"] | p <- toList allExclusions]
228 <> concat [["-not", "-path", p </> "*"] | p <- toList allExclusions]
@@ -379,7 +354,6 @@ parseCabalPackage' pkg = runExceptT $ do
379 defaultLanguage $ libBuildInfo lib
354 defaultLanguage $ libBuildInfo lib
380 , _cabalPackageInfo_compilerOptions = options $ libBuildInfo lib
355 , _cabalPackageInfo_compilerOptions = options $ libBuildInfo lib
381 , _cabalPackageInfo_cppOptions = cppOptions $ libBuildInfo lib
356 , _cabalPackageInfo_cppOptions = cppOptions $ libBuildInfo lib
382− , _cabalPackageInfo_buildDepends = targetBuildDepends $ libBuildInfo lib
384 Right Nothing -> pure Nothing
358 Right Nothing -> pure Nothing
385 Left (_, errors) ->
359 Left (_, errors) ->
@@ -426,8 +400,7 @@ withGhciScriptArgs
426 => f CabalPackageInfo -- ^ List of packages to load into ghci
400 => f CabalPackageInfo -- ^ List of packages to load into ghci
427 -> ([String] -> m ()) -- ^ Action to run with the extra ghci arguments
401 -> ([String] -> m ()) -- ^ Action to run with the extra ghci arguments
429−withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp ->
403+withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp -> f ["-XNoImplicitPrelude", "-ghci-script", fp]
430− f ["-XNoImplicitPrelude", "-ghci-script", fp]
432 -- These lines must be first and allow the session to support a custom Prelude when @-XNoImplicitPrelude@
405 -- These lines must be first and allow the session to support a custom Prelude when @-XNoImplicitPrelude@
433 -- is passed to the ghci session.
406 -- is passed to the ghci session.
@@ -477,7 +450,6 @@ getGhciSessionSettings (toList -> packageInfos) pathBase useRelativePaths = do
477 -- all paths to 'pathBase'.
450 -- all paths to 'pathBase'.
478 selfExe <- liftIO $ canonicalizePath =<< getExecutablePath
451 selfExe <- liftIO $ canonicalizePath =<< getExecutablePath
479 canonicalPathBase <- liftIO $ canonicalizePath pathBase
452 canonicalPathBase <- liftIO $ canonicalizePath pathBase
480− installedPackageIndex <- loadPackageIndex packageInfos pathBase
482 (pkgFiles, pkgSrcPaths :: [NonEmpty FilePath]) <- fmap unzip $ liftIO $ for packageInfos $ \pkg -> do
454 (pkgFiles, pkgSrcPaths :: [NonEmpty FilePath]) <- fmap unzip $ liftIO $ for packageInfos $ \pkg -> do
483 canonicalSrcDirs <- traverse canonicalizePath $ (_cabalPackageInfo_packageRoot pkg </>) <$> _cabalPackageInfo_sourceDirs pkg
455 canonicalSrcDirs <- traverse canonicalizePath $ (_cabalPackageInfo_packageRoot pkg </>) <$> _cabalPackageInfo_sourceDirs pkg
@@ -486,47 +458,16 @@ getGhciSessionSettings (toList -> packageInfos) pathBase useRelativePaths = do
488 $ baseGhciOptions
460 $ baseGhciOptions
489− <> ["-DOBELISK_ASSET_PASSTHRU"] -- For passthrough static assets
490 <> ["-F", "-pgmF", selfExe, "-optF", preprocessorIdentifier]
461 <> ["-F", "-pgmF", selfExe, "-optF", preprocessorIdentifier]
491 <> concatMap (\p -> ["-optF", p]) pkgFiles
462 <> concatMap (\p -> ["-optF", p]) pkgFiles
492 <> [ "-i" <> intercalate ":" (concatMap toList pkgSrcPaths) ]
463 <> [ "-i" <> intercalate ":" (concatMap toList pkgSrcPaths) ]
493− <> concatMap (\packageId -> ["-package-id", packageId ])
494− (packageIds installedPackageIndex)
496 relativeTo' = if useRelativePaths then relativeTo else const
465 relativeTo' = if useRelativePaths then relativeTo else const
497− -- Package names we're building and not needed from the package DB
499− map (mkPackageName . T.unpack . _cabalPackageInfo_packageName)
501− packageIds installedPackageIndex =
502− map (dependencyPackageId installedPackageIndex) $
503− filter ((`notElem` packageNames) . depPkgName) $
504− concatMap _cabalPackageInfo_buildDepends packageInfos <>
505− [Dependency (mkPackageName "obelisk-run") anyVersion]
506− dependencyPackageId installedPackageIndex dep =
507− case lookupDependency installedPackageIndex dep of
508− ((_version,installedPackageInfo:_) :_) ->
509− compatPackageKey installedPackageInfo
510− _ -> error $ "Couldn't resolve dependency for " <> prettyShow dep
512−-- Load the package index used by the GHC in this path's nix project
513−loadPackageIndex :: MonadObelisk m => [CabalPackageInfo] -> FilePath -> m InstalledPackageIndex
514−loadPackageIndex packageInfos root = do
515− ghcPath <- getPathInNixEnvironment "bash -c 'type -p ghc'"
516− ghcPkgPath <- getPathInNixEnvironment "bash -c 'type -p ghc-pkg'"
517− (compiler, _platform, programDb) <- liftIO
518− $ configCompilerEx (Just GHC) (Just ghcPath) (Just ghcPkgPath) defaultProgramDb Verbosity.silent
519− liftIO $ getInstalledPackages Verbosity.silent compiler [GlobalPackageDB] programDb
521− getPathInNixEnvironment cmd = do
522− path <- readProcessAndLogStderr Debug =<< mkObNixShellProc root False True (packageInfoToNamePathMap packageInfos) "ghc" (Just cmd)
523− liftIO $ canonicalizePath $ T.unpack $ T.strip path
525baseGhciOptions :: [String]
467baseGhciOptions :: [String]
526baseGhciOptions =
468baseGhciOptions =
527 [ "-ignore-dot-ghci"
469 [ "-ignore-dot-ghci"
528 , "-no-user-package-db"
470 , "-no-user-package-db"
529− , "-hide-all-packages"
530 , "-package-env", "-"
471 , "-package-env", "-"