cabal icon indicating copy to clipboard operation
cabal copied to clipboard

REPL command in project requires a target

Open philderbeast opened this issue 11 months ago • 3 comments

Fixes #10527 and #9983. Depend-on: #10688.

Doesn't allow an empty list of targets with a project context.

With a project, the REPL command requires a target. If one is not given then a message is shown explaining this and naming the project if the --project-file option was given (but not when the default 'cabal.project' project name is used implicitly). We're not yet able to list project targets so in the meantime, the messages lists the packages of the project.

  • When the implicit default cabal.project is used:
$ cat cabal.project
packages: pkg-one pkg-two

$ cabal repl
Error: [Cabal-7076]
With a project, the REPL command requires a single target. The packages in this
project are:
 - pkg-one
 - pkg-two
  • When the --project-file option is used, the file name is included:
$ cat some.project 
packages: pkg-one pkg-two

$ cabal repl --project-file=some.project
...
Error: [Cabal-7076]
With a project, the REPL command requires a single target. The packages in this
project, 'some.project', are:
 - pkg-one
 - pkg-two
  • When the project has no packages, this is mentioned in the message:
$ cat empty.project

$ cabal repl --project-file=empty.project
...
Error: [Cabal-7076]
With a project, the REPL command requires a single target but there are no
packages in this project, 'empty.project', to choose a package (library) or
other component from as the target for this command.
  • Before the fix the message mentioned a fake-package-0. This was confusing:
$ ~/.ghcup/bin/cabal-3.12.1.0 repl --project-file=some.project
...
Error: [Cabal-7076]
Internal error when trying to open a repl for the package fake-package-0. The
package is not in the set of available targets for the project plan, which would
suggest an inconsistency between readTargetSelectors and resolveTargets.
  • Earlier cabal-install:exe:cabal versions mentioned using all as the target but this won't work for the REPL command:
$ ~/.ghcup/bin/cabal-3.10.3.0 repl --project-file=some.project
Error: cabal-3.10.3.0: No targets given and there is no package in the current
directory. Use the target 'all' for all packages in the project or specify
packages or components by name or location. See 'cabal build --help' for more
details on target options.

philderbeast avatar Dec 28 '24 13:12 philderbeast

This pull request will be easier to review once the cfgVerbosity changes are merged.

philderbeast avatar Jun 16 '25 20:06 philderbeast

Did you consider modifying validatedTargets, in particular the selectPackageTargets function? That seems likely to be more correct to me than this ad-hoc manipulation of target strings.

mpickering avatar Jun 19 '25 11:06 mpickering

@philderbeast could you post a little summary on the state of this patch? Do you believe you addressed all Matt's concerns? If you're done, please ping Matt for re-reviewing.

Rebasing on master is also advisable.

There's still a chance we could get this into 3.16 but it's getting tight...

ulysses4ever avatar Jun 26 '25 13:06 ulysses4ever

could you post a little summary on the state of this patch?

I'm currently stumbling over assertions.

philderbeast avatar Jul 03 '25 11:07 philderbeast

Let me know if you need some help with this @philderbeast

mpickering avatar Jul 03 '25 11:07 mpickering

Thanks @mpickering. I'd like to be able to get a line number for the assertion I'm triggering here on this branch. Is that possible?

Assertion failed with backtrace for cabal init generated package

I'm able to run cabal init for a new package, alter the generated main as follows, add -fno-ignore-asserts to the executable in the .cabal file and then trigger the assertion and get a line number with the stack backtrace.

main :: IO ()
main = do
+   assert False (pure ())
    putStrLn "Hello, Haskell!"
$ cabal run assert
Resolving dependencies...
Build profile: -w ghc-9.12.2 -O1
In order, the following will be built (use -v for more details):
 - assert-0.1.0.0 (exe:assert) (configuration changed)
Configuring executable 'assert' for assert-0.1.0.0...
Preprocessing executable 'assert' for assert-0.1.0.0...
Building executable 'assert' for assert-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, dist-newstyle/build/x86_64-linux/ghc-9.12.2/assert-0.1.0.0/x/assert/build/assert/assert-tmp/Main.o ) [Optimisation flags changed]
[2 of 2] Linking dist-newstyle/build/x86_64-linux/ghc-9.12.2/assert-0.1.0.0/x/assert/build/assert/assert [Objects changed]
assert: Uncaught exception ghc-internal:GHC.Internal.IO.Exception.AssertionFailed:

Assertion failed

HasCallStack backtrace:
  throwIO, called at libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs:444:5 in ghc-internal:GHC.Internal.IO.Exception
  assert, called at app/Main.hs:7:5 in assert-0.1.0.0-inplace-assert:Main

Assertion failed (without backtrace so far :cry:) for cabal-install

On wip/assertion-failed, I've added an assertion to warnIfAssertionsAreEnabled to see if I can trigger an assertion and get back a line number for cabal-install but no luck so far.

$ cabal run cabal-install:exe:cabal -- build all --dry-run
Configuration is affected by the following files:
- cabal.project
Build profile: -w ghc-9.12.2 -O1
In order, the following will be built (use -v for more details):
 - cabal-install-3.17.0.0 (exe:cabal) (configuration changed)
Configuring executable 'cabal' for cabal-install-3.17.0.0...
Preprocessing executable 'cabal' for cabal-install-3.17.0.0...
Building executable 'cabal' for cabal-install-3.17.0.0...
Warning: this is a debug build of cabal-install with assertions enabled.
Assertion failed
Assertion failed

philderbeast avatar Jul 07 '25 20:07 philderbeast

@philderbeast I run the test which is failing

-----BEGIN CABAL OUTPUT-----
Resolving dependencies...
-----END CABAL OUTPUT-----
Assertion failed
CallStack (from HasCallStack):
  assert, called at src/Distribution/Client/ProjectOrchestration.hs:1061:3 in cabal-install-3.17.0.0-inplace:Distribution.Client.ProjectOrchestration

which points to this code:

1053 -- | Wrapper around 'ProjectPlanning.pruneInstallPlanToTargets' that adjusts    
1054 -- for the extra unneeded info in the 'TargetsMap'.                             
1055 pruneInstallPlanToTargets                                                       
1056   :: TargetAction                                                               
1057   -> TargetsMap                                                                 
1058   -> ElaboratedInstallPlan                                                      
1059   -> ElaboratedInstallPlan                                                      
1060 pruneInstallPlanToTargets targetActionType targetsMap elaboratedPlan =          
1061   assert (Map.size targetsMap > 0) $                                            
1062     ProjectPlanning.pruneInstallPlanToTargets                                   
1063       targetActionType                                                          
1064       (Map.map (map fst) targetsMap)                                            
1065       elaboratedPlan 

Is that what you are looking for?

mpickering avatar Jul 08 '25 13:07 mpickering

I run the test which is failing

Interesting. Shouldn't all CI runs have a backtrace that points to the same location for the failing assertion?

Validate ubuntu-22.04 ghc-9.8.4 has the backtrace location you shared @mpickering but Validate ubuntu-22.04 ghc-9.12.2 doesn't.

Here's a quick diff of a snippet of the output from those above CI runs (ghc-9.8.4 first in red).

- Assertion failed
- CallStack (from HasCallStack):
-   assert, called at src/Distribution/Client/ProjectOrchestration.hs:1061:3 in cabal-install-3.17.0.0-inplace:Distribution.Client.ProjectOrchestration
+   | Assertion failed
+   |
+ 
+ HasCallStack backtrace:
+   throwIO, called at src/Test/Cabal/Server.hs:213:21 in cabal-testsuite-3-inplace:Test.Cabal.Server

philderbeast avatar Jul 10 '25 12:07 philderbeast

I run the test which is failing

Interesting. Shouldn't all CI runs have a backtrace that points to the same location for the failing assertion?

Validate ubuntu-22.04 ghc-9.8.4 has the backtrace location you shared @mpickering but Validate ubuntu-22.04 ghc-9.12.2 doesn't.

Here's a quick diff of a snippet of the output from those above CI runs (ghc-9.8.4 first in red).

- Assertion failed
- CallStack (from HasCallStack):
-   assert, called at src/Distribution/Client/ProjectOrchestration.hs:1061:3 in cabal-install-3.17.0.0-inplace:Distribution.Client.ProjectOrchestration
+   | Assertion failed
+   |
+ 
+ HasCallStack backtrace:
+   throwIO, called at src/Test/Cabal/Server.hs:213:21 in cabal-testsuite-3-inplace:Test.Cabal.Server

Interesting.. I will try when I have a moment to see why this is. I wonder if it's to do with the callstack propagation changes in 9.12.2.

mpickering avatar Jul 16 '25 15:07 mpickering

@philderbeast I reproduced and fixed the issue with assertions not showing a source location

 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ImplicitParams #-}
 #ifdef GIT_REV
 {-# LANGUAGE TemplateHaskell #-}
 #endif
@@ -301,6 +302,8 @@ import GitHash
   )
 #endif
 
+import Control.Exception.Context
+
 -- We only get our own version number when we're building with ourselves
 cabalVersion :: Version
 #if defined(BOOTSTRAPPED_CABAL)
@@ -535,7 +538,7 @@ topHandlerWith cont prog = do
       cont se
 
     message :: String -> Exception.SomeException -> String
-    message pname (Exception.SomeException se) =
+    message pname e@(Exception.SomeException se) =
       case cast se :: Maybe Exception.IOException of
         Just ioe
           | ioeGetVerbatim ioe ->
@@ -551,11 +554,16 @@ topHandlerWith cont prog = do
                   detail = ioeGetErrorString ioe
                in wrapText $ addErrorPrefix $ pname ++ ": " ++ file ++ detail
         _ ->
-          displaySomeException se ++ "\n"
+          displaySomeException e ++ "\n"
 
 -- | BC wrapper around 'Exception.displayException'.
-displaySomeException :: Exception.Exception e => e -> String
-displaySomeException se = Exception.displayException se
+displaySomeException :: SomeException -> String
+displaySomeException (SomeException e) =
+  case displayExceptionContext ?exceptionContext of
+    "" -> msg
+    dc -> msg ++ "\n\n" ++ dc
+  where
+    msg = displayException e

I can make a ticket and PR next week.

mpickering avatar Jul 18 '25 08:07 mpickering

I can make a ticket and PR next week.

Awesome thanks @mpickering.

philderbeast avatar Jul 21 '25 11:07 philderbeast

@mpickering @philderbeast this patch may fix a regression that people are actively noticing in 3.16.0.0. What's needed to make progress on it, do you have an idea?

ulysses4ever avatar Jul 29 '25 13:07 ulysses4ever

What's needed to make progress on it, do you have an idea?

@ulysses4ever I've pushed an update where I guard against triggering the assertion.

philderbeast avatar Jul 29 '25 19:07 philderbeast

Cool, thanks! Let's see what CI says.

Any chance you could squash some of those commits?

ulysses4ever avatar Jul 29 '25 20:07 ulysses4ever

I missed updating a test. The update in the test output is:

$ git diff
...
 # checking repl command with an 'empty.project' with no packages
 # cabal repl
 Warning: There are no packages or optional-packages in the project
-Resolving dependencies...
+Error: [Cabal-7076]
+There are no packages in 'empty.project'. Please add a package to the project and pick a
+ single [package:][ctype:]component as target for the REPL command.

philderbeast avatar Jul 30 '25 11:07 philderbeast

I'm struggling a bit to do a proper review without diving in and understanding all the details myself. So I am also happy to merge what you have done already (with the error message comment modified) and we can improve it later if necessary.


It seems that there is some awkwardness around the fact that

  • In a project context you have to specify a target
  • In other contexts you don't have to specify a target

This leads to passing AcceptNoTargets to withContextAndSelectors, and then having to check whether there are no targets in the ProjectContext case.

Perhaps another design would be to make withContextAndSelectors take a function TargetContext -> AcceptNoTargets? Did you consider doing that?

I suppose resolveTargets is not suitable here since that is dealing with resolving what a target string is referring to (in this case there isn't a target string).

mpickering avatar Aug 05 '25 09:08 mpickering

Sorry @mpickering for roping you in for an premature review. I couldn't see how to cancel a "re-request review". Thanks for the feedback. I sought early feedback given the urgency of #11107.

philderbeast avatar Aug 07 '25 20:08 philderbeast

It seems that there is some awkwardness around the fact that

  • In a project context you have to specify a target
  • In other contexts you don't have to specify a target

I'm making one exception here, picking the package as the target when a project has but one package and no targets are given.

philderbeast avatar Aug 08 '25 01:08 philderbeast

@mpickering could you take another look at this? it'd be great to have it in for 3.16.1.0...

ulysses4ever avatar Sep 29 '25 18:09 ulysses4ever