@@ -106,7 +106,8 @@ import Distribution.Simple.Compiler
106106 )
107107import Distribution.Simple.Program.GHC
108108import Distribution.Simple.Setup
109- ( ReplOptions (.. )
109+ ( Flag
110+ , ReplOptions (.. )
110111 , commonSetupTempFileOptions
111112 )
112113import Distribution.Simple.Utils
@@ -170,8 +171,8 @@ import Data.List
170171import qualified Data.Map as Map
171172import qualified Data.Set as Set
172173import Distribution.Client.ProjectConfig
173- ( ProjectConfig (projectConfigShared )
174- , ProjectConfigShared (projectConfigConstraints , projectConfigMultiRepl )
174+ ( ProjectConfig (.. )
175+ , ProjectConfigShared (.. )
175176 )
176177import Distribution.Client.ReplFlags
177178 ( EnvFlags (envIncludeTransitive , envPackages )
@@ -195,6 +196,8 @@ import System.FilePath
195196 , splitSearchPath
196197 , (</>)
197198 )
199+ import Text.PrettyPrint hiding ((<>) )
200+ import Distribution.Types.PackageName.Magic ( fakePackageId )
198201
199202replCommand :: CommandUI (NixStyleFlags ReplFlags )
200203replCommand =
@@ -281,17 +284,29 @@ multiReplDecision ctx compiler flags =
281284-- For more details on how this works, see the module
282285-- "Distribution.Client.ProjectOrchestration"
283286replAction :: NixStyleFlags ReplFlags -> [String ] -> GlobalFlags -> IO ()
284- replAction flags@ NixStyleFlags {extraFlags = r @ ReplFlags {.. }, .. } targetStrings globalFlags =
285- withContextAndSelectors verbosity AcceptNoTargets ( Just LibKind ) flags targetStrings globalFlags ReplCommand $ \ targetCtx ctx targetSelectors -> do
287+ replAction flags@ NixStyleFlags {extraFlags = replFlags @ ReplFlags {.. }, configFlags } targetStrings globalFlags = do
288+ withCtx verbosity targetStrings $ \ targetCtx ctx userTargetSelectors -> do
286289 when (buildSettingOnlyDeps (buildSettings ctx)) $
287290 dieWithException verbosity ReplCommandDoesn'tSupport
288291 let projectRoot = distProjectRootDirectory $ distDirLayout ctx
289292 distDir = distDirectory $ distDirLayout ctx
290293
291- baseCtx <- case targetCtx of
292- ProjectContext -> return ctx
294+ -- After ther user selectors have been resolved, and it's decided what context
295+ -- we're in, implement repl-specific behaviour.
296+ (baseCtx, targetSelectors) <- case targetCtx of
297+ -- If in the project context, and no selectors are provided
298+ -- then produce an error.
299+ ProjectContext -> do
300+ let projectFile = projectConfigProjectFile . projectConfigShared $ projectConfig ctx
301+ let pkgs = projectPackages $ projectConfig ctx
302+ case userTargetSelectors of
303+ [] -> dieWithException verbosity $
304+ RenderReplTargetProblem [render (reportProjectNoTarget projectFile pkgs)]
305+ _ -> return (ctx, userTargetSelectors)
306+ -- In the global context, construct a fake package which can be used to start
307+ -- a repl with extra arguments if `-b` is given.
293308 GlobalContext -> do
294- unless (null targetStrings ) $
309+ unless (null userTargetSelectors ) $
295310 dieWithException verbosity $
296311 ReplTakesNoArguments targetStrings
297312 let
@@ -303,12 +318,18 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g
303318 library = emptyLibrary{libBuildInfo = lBuildInfo}
304319 lBuildInfo =
305320 emptyBuildInfo
306- { targetBuildDepends = [baseDep]
321+ { targetBuildDepends = [baseDep] ++ envPackages replEnvFlags
307322 , defaultLanguage = Just Haskell2010
308323 }
309324 baseDep = Dependency " base" anyVersion mainLibSet
310325
311- updateContextAndWriteProjectFile' ctx sourcePackage
326+ -- Write the fake package
327+ updatedCtx <- updateContextAndWriteProjectFile' ctx sourcePackage
328+ -- Specify the selector for this package
329+ let fakeSelector = TargetPackage TargetExplicitNamed [fakePackageId] Nothing
330+ return (updatedCtx, [fakeSelector])
331+
332+ -- For the script context, no special behaviour.
312333 ScriptContext scriptPath scriptExecutable -> do
313334 unless (length targetStrings == 1 ) $
314335 dieWithException verbosity $
@@ -318,7 +339,8 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g
318339 dieWithException verbosity $
319340 ReplTakesSingleArgument targetStrings
320341
321- updateContextAndWriteProjectFile ctx scriptPath scriptExecutable
342+ updatedCtx <- updateContextAndWriteProjectFile ctx scriptPath scriptExecutable
343+ return (updatedCtx, userTargetSelectors)
322344
323345 -- If multi-repl is used, we need a Cabal recent enough to handle it.
324346 -- We need to do this before solving, but the compiler version is only known
@@ -361,7 +383,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g
361383 -- especially in the no-project case.
362384 withInstallPlan (lessVerbose verbosity) baseCtx' $ \ elaboratedPlan sharedConfig -> do
363385 -- targets should be non-empty map, but there's no NonEmptyMap yet.
364- targets <- validatedTargets (projectConfigShared (projectConfig ctx)) (pkgConfigCompiler sharedConfig) elaboratedPlan targetSelectors
386+ targets <- validatedTargets' (projectConfigShared (projectConfig ctx)) (pkgConfigCompiler sharedConfig) elaboratedPlan targetSelectors
365387
366388 let
367389 (unitId, _) = fromMaybe (error " panic: targets should be non-empty" ) $ safeHead $ Map. toList targets
@@ -385,7 +407,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g
385407 let ProjectBaseContext {.. } = baseCtx''
386408
387409 -- Recalculate with updated project.
388- targets <- validatedTargets (projectConfigShared projectConfig) (pkgConfigCompiler elaboratedShared') elaboratedPlan targetSelectors
410+ targets <- validatedTargets' (projectConfigShared projectConfig) (pkgConfigCompiler elaboratedShared') elaboratedPlan targetSelectors
389411
390412 let
391413 elaboratedPlan' =
@@ -518,31 +540,13 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g
518540 go m (" PATH" , Just s) = foldl' (\ m' f -> Map. insertWith (+) f 1 m') m (splitSearchPath s)
519541 go m _ = m
520542
543+ withCtx ctxVerbosity strings =
544+ withContextAndSelectors ctxVerbosity AcceptNoTargets (Just LibKind ) flags strings globalFlags ReplCommand
545+
521546 verbosity = cfgVerbosity normal flags
522547 tempFileOptions = commonSetupTempFileOptions $ configCommonFlags configFlags
523548
524- validatedTargets ctx compiler elaboratedPlan targetSelectors = do
525- let multi_repl_enabled = multiReplDecision ctx compiler r
526- -- Interpret the targets on the command line as repl targets
527- -- (as opposed to say build or haddock targets).
528- targets <-
529- either (reportTargetProblems verbosity) return $
530- resolveTargetsFromSolver
531- (selectPackageTargets multi_repl_enabled)
532- selectComponentTarget
533- elaboratedPlan
534- Nothing
535- targetSelectors
536-
537- -- Reject multiple targets, or at least targets in different
538- -- components. It is ok to have two module/file targets in the
539- -- same component, but not two that live in different components.
540- when (Set. size (distinctTargetComponents targets) > 1 && not (useMultiRepl multi_repl_enabled)) $
541- reportTargetProblems
542- verbosity
543- [multipleTargetsProblem multi_repl_enabled targets]
544-
545- return targets
549+ validatedTargets' = validatedTargets verbosity replFlags
546550
547551-- | Create a constraint which requires a later version of Cabal.
548552-- This is used for commands which require a specific feature from the Cabal library
@@ -555,6 +559,69 @@ requireCabal version source =
555559 , source
556560 )
557561
562+ reportProjectNoTarget :: Flag FilePath -> [String ] -> Doc
563+ reportProjectNoTarget projectFile pkgs =
564+ case (null pkgs, projectName) of
565+ (True , Just project) ->
566+ text " There are no packages in"
567+ <+> (project <> char ' .' )
568+ <+> text " Please add a package to the project and"
569+ <+> pickComponent
570+ (True , Nothing ) ->
571+ text " Please add a package to the project and" <+> pickComponent
572+ (False , Just project) ->
573+ text " Please"
574+ <+> pickComponent
575+ <+> text " The packages in"
576+ <+> project
577+ <+> (text " from which to select a component target are" <> colon)
578+ $+$ nest 1 (vcat [text " -" <+> text pkg | pkg <- sort pkgs])
579+ (False , Nothing ) ->
580+ text " Please"
581+ <+> pickComponent
582+ <+> (text " The packages from which to select a component in 'cabal.project'" <> comma)
583+ <+> (text " the implicit default as if `--project-file=cabal.project` was added as a command option" <> comma)
584+ <+> (text " are" <> colon)
585+ $+$ nest 1 (vcat [text " -" <+> text pkg | pkg <- sort pkgs])
586+ where
587+ projectName = case projectFile of
588+ Flag " " -> Nothing
589+ Flag n -> Just $ quotes (text n)
590+ _ -> Nothing
591+ pickComponent = text " pick a single [package:][ctype:]component (or all) as target for the REPL command."
592+
593+ -- | Invariant: validatedTargets returns at least one target for the REPL.
594+ validatedTargets
595+ :: Verbosity
596+ -> ReplFlags
597+ -> ProjectConfigShared
598+ -> Compiler
599+ -> ElaboratedInstallPlan
600+ -> [TargetSelector ]
601+ -> IO TargetsMap
602+ validatedTargets verbosity replFlags ctx compiler elaboratedPlan targetSelectors = do
603+ let multi_repl_enabled = multiReplDecision ctx compiler replFlags
604+ -- Interpret the targets on the command line as repl targets (as opposed to
605+ -- say build or haddock targets).
606+ targets <-
607+ either (reportTargetProblems verbosity) return $
608+ resolveTargetsFromSolver
609+ (selectPackageTargets multi_repl_enabled)
610+ selectComponentTarget
611+ elaboratedPlan
612+ Nothing
613+ targetSelectors
614+
615+ -- Reject multiple targets, or at least targets in different components. It is
616+ -- ok to have two module/file targets in the same component, but not two that
617+ -- live in different components.
618+ when (Set. size (distinctTargetComponents targets) > 1 && not (useMultiRepl multi_repl_enabled)) $
619+ reportTargetProblems
620+ verbosity
621+ [multipleTargetsProblem multi_repl_enabled targets]
622+
623+ return targets
624+
558625-- | First version of GHC which supports multiple home packages
559626minMultipleHomeUnitsVersion :: Version
560627minMultipleHomeUnitsVersion = mkVersion [9 , 4 ]
0 commit comments