-
Notifications
You must be signed in to change notification settings - Fork 697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor cabal-install
solver config log output
#9159
base: master
Are you sure you want to change the base?
Conversation
Can you show us some examples? |
I've reworked the commit message a bit:
Before the changes …
… and after the changes:
There are many open questions left as code comments. I would greatly appreciate any feedback on them :) |
Could this perhaps say "all other available versions of package "? We're not rejecting other packages and now the message doesn't tell us which package it is talking about, so when it later references a constraint it is unclear what it refers to. |
Also, if we run with higher verbosity we should perhaps go back to listing all the package versions that get rejected. Alternatively, I wonder if we could do something more like footnotes, e.g. with verbose output produce
Or maybe we even print this on normal verbosity (i.e. max of two additional package versions, then an ellipsis) and then print the full list only with higher verbosity. |
Thanks for working on the solver error messages. I haven't had time to read the code carefully yet, but I have a few comments.
|
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
6c95e3b
to
52f087e
Compare
cabal-install
solver config log output (and add a --json
machine-readable option)
I've reworked this PR a bit: It now aims to add a It would be greatly appreciated if this PR could receive another round of reviews, as it significantly refactors the solver logging logic: Instead of relying on strings, it introduces a new data structure representation of logs that's utilized in several places in the code before being serialized with I'm seeking advice on:
|
There are TODOs and clean ups left to do, but I think this is looking great. The solver is now giving structured information (
for serialising JSON we already have
Right, this hits the legacy parsing path for ProjectConfig but we can hope be able to avoid the worst of it. I'd start by following another solver flag like I hope this helps 🤞 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read the updated diff, and I'm not sure I completely understand the PR. It looks like it currently has two main parts, the refactoring to add an intermediate representation of the solver log and a --json flag.
--json flag
What is the reason for formatting the log as JSON? Is it related to making the log collapsible as in #9199? I'm still not sure I understand the use case for collapsing it. Do you want to collapse the error message that is shown by default when the solver fails to find a solution, or the full verbose (-v3) log? Do you have an example of a build where it would have helped? I'm also curious to see an example because if a subtree seems irrelevant, it's possible that the solver didn't need to explore it, and it could be optimized away.
Refactoring
I can see how the SolverTrace
data structure is useful for implementing different types of formatting, such as JSON or bolded output, but I was wondering if you were also planning to use it for other parts of #8939. If so, how would SolverTrace
be used to change the contents of error messages?
This is the way that I understand the current code for creating the solver log:
The solver traverses the search tree and converts it to a list of Message
in the backjumpAndExplore
function. The list of Message
aims to preserve as much of the tree structure as possible, without using a large amount of memory, by describing going up and down the branches of the tree. Then the solver uses the remaining tree structure to convert the Message
s into strings that are more helpful for the user in showMessages
, for example, by combining similar rejected versions into a single line.
I would expect that it would be better to apply most processing of the contents of the log to the list of Message
s, where more of the tree structure is available.
cabal-install
solver config log output (and add a --json
machine-readable option)cabal-install
solver config log output
To answer @grayjay's concerns, I have decided to split this PR into two parts. This PR will now focus solely on the refactoring and is no longer in draft status (I have also updated the PR description accordingly). The other PR, which is still a draft #9465, will introduce the Since I feel that part of the answers to your questions was in my comments: #9159 (comment) and #9199 (comment). I wrote up in the original RFC #8939 (comment) an up-to-date plan of action of what I’m trying to achieve. Hope the whole thing makes more sense :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yvan-sraka Thanks for splitting the PR. I did a full review after our discussion in the meeting.
@@ -41,51 +42,130 @@ data Message = | |||
| Success | |||
| Failure ConflictSet FailReason | |||
|
|||
data Log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could Log
, SolverTrace
, and related types go in cabal-install-solver/src/Distribution/Solver/Types/ with the other types that are part of the solver API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant that the types related to SolverTrace/SummarizedMessage should go in the Types directory, because they are now part of the solver's API. Message
should stay in Message.hs, in the Modular directory, because it is still only used internally.
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
createErrorMsg failure@(ExhaustiveSearch cs cm) = | ||
handleFailure :: SolverFailure | ||
-> RetryLog SolverTrace String (Assignment, RevDepMap) | ||
handleFailure failure@(ExhaustiveSearch cs _cm) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was cm
renamed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
| RejectS QSN Bool ConflictSet FailReason | ||
| Skipping' (Set CS.Conflict) | ||
| TryingF QFN Bool | ||
| TryingP QPN POption (Maybe (GoalReason QPN)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to split the TryingP
constructor into two, one for a new goal, and one for an existing goal? Then the Maybe
could be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
cabal-install-solver/src/Distribution/Solver/Modular/Message.hs
Outdated
Show resolved
Hide resolved
@@ -41,51 +42,130 @@ data Message = | |||
| Success | |||
| Failure ConflictSet FailReason | |||
|
|||
data Log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would help to have some comments describing how the new types and Message
relate to each other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yvan-sraka Thanks! I still had some questions and comments from my last review, but they were collapsed due to the renaming changes, so I marked them with new comments to make them visible again. I also added a few comments on the new changes.
( maximumBy | ||
) | ||
import qualified Data.Map as Map | ||
import qualified Data.Set as Set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please undo the formatting of the imports or move it to a separate PR? It is difficult to see what has changed with the reordering.
createErrorMsg failure@(ExhaustiveSearch cs cm) = | ||
handleFailure :: SolverFailure | ||
-> RetryLog SolverTrace String (Assignment, RevDepMap) | ||
handleFailure failure@(ExhaustiveSearch cs _cm) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
tryToMinimizeConflictSet runSolver sc cs cm = | ||
foldl (\r v -> retryNoSolution r $ tryToRemoveOneVar v) | ||
foldl (\r v -> retryMap mkErrorMsg $ retryNoSolution (retryMap show r) $ tryToRemoveOneVar v) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
retryMap :: (t -> step) -> RetryLog t fail done -> RetryLog step fail done | ||
retryMap f l = fromProgress $ (\p -> foldProgress (\x xs -> Step (f x) xs) Fail Done p) $ toProgress l |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
-- 'Skip' should always be handled by 'goPSkip' in the case above. | ||
go !l (Step (Skip conflicts) ms) = Step (SolverTrace $ AtLevel l $ (Skipping' conflicts)) (go l ms) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here
data Entry | ||
= LogPackageGoal QPN QGoalReason | ||
| LogRejectF QFN Bool ConflictSet FailReason | ||
| LogRejectS QSN Bool ConflictSet FailReason | ||
| LogSkipping (Set CS.Conflict) | ||
| LogTryingF QFN Bool | ||
| LogTryingP QPN POption (Maybe (GoalReason QPN)) | ||
| LogTryingS QSN Bool | ||
| LogRejectMany QPN [POption] ConflictSet FailReason | ||
| LogSkipMany QPN [POption] (Set CS.Conflict) | ||
| LogUnknownPackage QPN (GoalReason QPN) | ||
| LogSuccessMsg | ||
| LogFailureMsg ConflictSet FailReason |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the constructor names start with "Entry" now?
| LogSuccessMsg | ||
| LogFailureMsg ConflictSet FailReason |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that LogSuccessMsg
and LogFailureMsg
could be shortened to LogSuccess
and LogFailure
now.
| LogSuccessMsg | ||
| LogFailureMsg ConflictSet FailReason | ||
|
||
data EntryMsg = AtLevel Int Entry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would probably be clearer to use the same name for the type and the constructor, such as EntryAtLevel
.
displayMessage (LogSkipMany _ _ cs) = "skipping: " ++ showConflicts cs | ||
displayMessage (LogRejectMany qpn is c fr) = "rejecting: " ++ L.intercalate ", " (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr | ||
|
||
-- | Transforms the structured message type to actual messages (SummarizedMsg s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type name should be SummarizedMessage
.
|
||
module Distribution.Solver.Modular.Message ( | ||
Message(..), | ||
showMessages | ||
SummarizedMessage(..), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that SummarizedMessage
needs to be re-exported from this module.
This PR does not modify
cabal
behaviour and is about code refactoring. It's part of the initiative described in this RFC #8939.Special thanks to @andreabedini for refactoring and authoring the
displayMessage'
function. This significantly enhanced the readability ofDistribution.Solver.Modular.Message
. Moreover, the pair-programming sessions were invaluable in helping me kick off the implementation of a PATCH to address this issue :)Checklist: