@@ -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
@@ -72,16 +61,12 @@ import System.Directory
72import System.Environment (getExecutablePath)
61import System.Environment (getExecutablePath)
73import System.FilePath
62import System.FilePath
74import qualified System.Info
63import qualified System.Info
75−import System.IO (hClose, hGetLine)
76import System.IO.Temp (withSystemTempDirectory)
64import System.IO.Temp (withSystemTempDirectory)
77−import System.Process (CreateProcess (..), StdStream (..))
79−import Obelisk.App (MonadObelisk, getObelisk, runObelisk)
66+import Obelisk.App (MonadObelisk)
80import Obelisk.CliApp (
67import Obelisk.CliApp (
81 Severity (..),
68 Severity (..),
87 readCreateProcessWithExitCode,
72 readCreateProcessWithExitCode,
@@ -92,7 +77,7 @@ import Obelisk.CliApp (
92 withSpinner,
77 withSpinner,
94import Obelisk.Command.Nix
79import Obelisk.Command.Nix
95−import Obelisk.Command.Project
80+import Obelisk.Command.Project (nixShellWithoutPkgs, withProjectRoot, findProjectAssets, bashEscape)
96import Obelisk.Command.Thunk (attrCacheFileName)
81import Obelisk.Command.Thunk (attrCacheFileName)
97import Obelisk.Command.Utils (findExePath, ghcidExePath)
82import Obelisk.Command.Utils (findExePath, ghcidExePath)
@@ -111,8 +96,6 @@ data CabalPackageInfo = CabalPackageInfo
111 -- ^ 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)
112 , _cabalPackageInfo_cppOptions :: [String]
97 , _cabalPackageInfo_cppOptions :: [String]
113 -- ^ 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)
114− , _cabalPackageInfo_buildDepends :: [Dependency]
115− -- ^ List of build dependencies listed in the cabal file
118-- | 'Bool' with a better name for its purpose.
101-- | 'Bool' with a better name for its purpose.
@@ -161,8 +144,8 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
161 , _target_attr = Just "__unstable__.profiledObRun"
144 , _target_attr = Just "__unstable__.profiledObRun"
162 , _target_expr = Nothing
145 , _target_expr = Nothing
164− (assetType, assets) <- findProjectAssets root
147+ assets <- findProjectAssets root
165− putLog Debug $ describeImpureAssetSource assetType assets
148+ putLog Debug $ "Assets impurely loaded from: " <> assets
166 time <- liftIO getCurrentTime
149 time <- liftIO getCurrentTime
167 let profileBaseName = formatTime defaultTimeLocale profileBasePattern time
150 let profileBaseName = formatTime defaultTimeLocale profileBasePattern time
168 liftIO $ createDirectoryIfMissing True $ takeDirectory $ root </> profileBaseName
151 liftIO $ createDirectoryIfMissing True $ takeDirectory $ root </> profileBaseName
@@ -180,16 +163,9 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
180run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
163run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
181run root interpretPaths = do
164run root interpretPaths = do
182 pkgs <- getParsedLocalPkgs root interpretPaths
165 pkgs <- getParsedLocalPkgs root interpretPaths
183− (assetType, assets) <- findProjectAssets root
166+ assets <- findProjectAssets root
184− manifestPkg <- parsePackagesOrFail . (:[]) . T.unpack =<< getHaskellManifestProjectPath root
167+ putLog Debug $ "Assets impurely loaded from: " <> assets
185− putLog Debug $ describeImpureAssetSource assetType assets
187− AssetSource_Derivation -> do
189− putLog Debug "Starting static file derivation watcher..."
190− void $ liftIO $ forkIO $ runObelisk ob $ watchStaticFilesDerivation root
192− ghciArgs <- getGhciSessionSettings (pkgs <> manifestPkg) root True
168+ ghciArgs <- getGhciSessionSettings pkgs root True
193 freePort <- getFreePort
169 freePort <- getFreePort
194 withGhciScriptArgs pkgs $ \dotGhciArgs -> do
170 withGhciScriptArgs pkgs $ \dotGhciArgs -> do
195 runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
171 runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
@@ -246,12 +222,7 @@ getLocalPkgs root interpretPaths = do
246 let rootsAndExclusions = calcIntepretFinds "" interpretPaths
222 let rootsAndExclusions = calcIntepretFinds "" interpretPaths
248 fmap fold $ for (MMap.toAscList rootsAndExclusions) $ \(interpretPathRoot, exclusions) ->
224 fmap fold $ for (MMap.toAscList rootsAndExclusions) $ \(interpretPathRoot, exclusions) ->
249− let allExclusions = obeliskPackageExclusions
225+ let allExclusions = obeliskPackageExclusions <> exclusions <> Set.singleton ("*" </> attrCacheFileName)
251− <> Set.singleton ("*" </> attrCacheFileName)
252− <> Set.singleton ("*" </> "lib/asset/manifest") -- NB: obelisk-asset-manifest is excluded because it generates
253− -- a module that in turn imports it. This will cause ob run to
254− -- fail in its current implementation.
255 in fmap (Set.fromList . map normalise) $ runFind $
226 in fmap (Set.fromList . map normalise) $ runFind $
256 ["-L", interpretPathRoot, "(", "-name", "*.cabal", "-o", "-name", Hpack.packageConfig, ")", "-a", "-type", "f"]
227 ["-L", interpretPathRoot, "(", "-name", "*.cabal", "-o", "-name", Hpack.packageConfig, ")", "-a", "-type", "f"]
257 <> concat [["-not", "-path", p </> "*"] | p <- toList allExclusions]
228 <> concat [["-not", "-path", p </> "*"] | p <- toList allExclusions]
@@ -383,7 +354,6 @@ parseCabalPackage' pkg = runExceptT $ do
383 defaultLanguage $ libBuildInfo lib
354 defaultLanguage $ libBuildInfo lib
384 , _cabalPackageInfo_compilerOptions = options $ libBuildInfo lib
355 , _cabalPackageInfo_compilerOptions = options $ libBuildInfo lib
385 , _cabalPackageInfo_cppOptions = cppOptions $ libBuildInfo lib
356 , _cabalPackageInfo_cppOptions = cppOptions $ libBuildInfo lib
386− , _cabalPackageInfo_buildDepends = targetBuildDepends $ libBuildInfo lib
388 Right Nothing -> pure Nothing
358 Right Nothing -> pure Nothing
389 Left (_, errors) ->
359 Left (_, errors) ->
@@ -430,8 +400,7 @@ withGhciScriptArgs
430 => f CabalPackageInfo -- ^ List of packages to load into ghci
400 => f CabalPackageInfo -- ^ List of packages to load into ghci
431 -> ([String] -> m ()) -- ^ Action to run with the extra ghci arguments
401 -> ([String] -> m ()) -- ^ Action to run with the extra ghci arguments
433−withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp ->
403+withGhciScriptArgs packageInfos f = withGhciScript loadPreludeManually packageInfos $ \fp -> f ["-XNoImplicitPrelude", "-ghci-script", fp]
434− f ["-XNoImplicitPrelude", "-ghci-script", fp]
436 -- 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@
437 -- is passed to the ghci session.
406 -- is passed to the ghci session.
@@ -481,7 +450,6 @@ getGhciSessionSettings (toList -> packageInfos) pathBase useRelativePaths = do
481 -- all paths to 'pathBase'.
450 -- all paths to 'pathBase'.
482 selfExe <- liftIO $ canonicalizePath =<< getExecutablePath
451 selfExe <- liftIO $ canonicalizePath =<< getExecutablePath
483 canonicalPathBase <- liftIO $ canonicalizePath pathBase
452 canonicalPathBase <- liftIO $ canonicalizePath pathBase
484− installedPackageIndex <- loadPackageIndex pathBase
486 (pkgFiles, pkgSrcPaths :: [NonEmpty FilePath]) <- fmap unzip $ liftIO $ for packageInfos $ \pkg -> do
454 (pkgFiles, pkgSrcPaths :: [NonEmpty FilePath]) <- fmap unzip $ liftIO $ for packageInfos $ \pkg -> do
487 canonicalSrcDirs <- traverse canonicalizePath $ (_cabalPackageInfo_packageRoot pkg </>) <$> _cabalPackageInfo_sourceDirs pkg
455 canonicalSrcDirs <- traverse canonicalizePath $ (_cabalPackageInfo_packageRoot pkg </>) <$> _cabalPackageInfo_sourceDirs pkg
@@ -490,51 +458,16 @@ getGhciSessionSettings (toList -> packageInfos) pathBase useRelativePaths = do
492 $ baseGhciOptions
460 $ baseGhciOptions
493− <> ["-DOBELISK_ASSET_PASSTHRU"] -- For passthrough static assets
494 <> ["-F", "-pgmF", selfExe, "-optF", preprocessorIdentifier]
461 <> ["-F", "-pgmF", selfExe, "-optF", preprocessorIdentifier]
495 <> concatMap (\p -> ["-optF", p]) pkgFiles
462 <> concatMap (\p -> ["-optF", p]) pkgFiles
496 <> [ "-i" <> intercalate ":" (concatMap toList pkgSrcPaths) ]
463 <> [ "-i" <> intercalate ":" (concatMap toList pkgSrcPaths) ]
497− <> concatMap (\packageId -> ["-package-id", packageId ])
498− (packageIds installedPackageIndex)
500 relativeTo' = if useRelativePaths then relativeTo else const
465 relativeTo' = if useRelativePaths then relativeTo else const
501− -- Package names we're building and not needed from the package DB
503− map (mkPackageName . T.unpack . _cabalPackageInfo_packageName)
505− packageIds installedPackageIndex =
506− map (dependencyPackageId installedPackageIndex) $
507− filter ((`notElem` packageNames) . depPkgName) $
508− concatMap _cabalPackageInfo_buildDepends packageInfos <>
509− [Dependency (mkPackageName "obelisk-run") anyVersion]
510− dependencyPackageId installedPackageIndex dep =
511− case lookupDependency installedPackageIndex dep of
512− ((_version,installedPackageInfo:_) :_) ->
513− compatPackageKey installedPackageInfo
514− _ -> error $ "Couldn't resolve dependency for " <> prettyShow dep
516−-- Load the package index used by the GHC in this path's nix project
517−loadPackageIndex :: (MonadObelisk m) => FilePath -> m InstalledPackageIndex
518−loadPackageIndex root = do
519− ghcPath <- getPathInNixEnvironment "bash -c 'type -p ghc'"
520− ghcPkgPath <- getPathInNixEnvironment "bash -c 'type -p ghc-pkg'"
521− (compiler, _platform, programDb) <- liftIO
522− $ configCompilerEx (Just GHC) (Just ghcPath) (Just ghcPkgPath) defaultProgramDb Verbosity.silent
523− liftIO $ getInstalledPackages Verbosity.silent compiler [GlobalPackageDB] programDb
525− getPathInNixEnvironment cmd = do
526− (_,Just h,_,_) <- createProcess_ "loadPackageIndex" $ procSpec cmd
527− path <- liftIO $ hGetLine h >>= canonicalizePath
531− overCreateProcess (\cs -> cs { std_out = CreatePipe }) . obShellRunProc root
533baseGhciOptions :: [String]
467baseGhciOptions :: [String]
534baseGhciOptions =
468baseGhciOptions =
535 [ "-ignore-dot-ghci"
469 [ "-ignore-dot-ghci"
536 , "-no-user-package-db"
470 , "-no-user-package-db"
537− , "-hide-all-packages"
538 , "-package-env", "-"
471 , "-package-env", "-"