11{-# LANGUAGE BangPatterns #-}
2+ {-# LANGUAGE InstanceSigs #-}
23
34module Distribution.Solver.Modular.Message (
45 Message (.. ),
5- showMessages
6+ SolverTrace (.. ),
7+ groupMessages ,
68 ) where
79
810import qualified Data.List as L
@@ -41,51 +43,130 @@ data Message =
4143 | Success
4244 | Failure ConflictSet FailReason
4345
46+ data Log
47+ = PackageGoal QPN QGoalReason
48+ | RejectF QFN Bool ConflictSet FailReason
49+ | RejectS QSN Bool ConflictSet FailReason
50+ | Skipping' (Set CS. Conflict )
51+ | TryingF QFN Bool
52+ | TryingP QPN POption (Maybe (GoalReason QPN ))
53+ | TryingS QSN Bool
54+ | RejectMany QPN [POption ] ConflictSet FailReason
55+ | SkipMany QPN [POption ] (Set CS. Conflict )
56+ | UnknownPackage' QPN (GoalReason QPN )
57+ | SuccessMsg
58+ | FailureMsg ConflictSet FailReason
59+
60+ data AtLevel a = AtLevel Int a
61+
62+ type Trace = AtLevel Log
63+
64+ data SolverTrace = SolverTrace Trace | ErrorMsg String
65+
66+ instance Show SolverTrace where
67+ show (SolverTrace i) = displayMessageAtLevel i
68+ show (ErrorMsg s) = show s
69+
70+ instance Show Log where
71+ show = displayMessage
72+
73+ displayMessageAtLevel :: Trace -> String
74+ displayMessageAtLevel (AtLevel l msg) =
75+ let s = show l
76+ in " [" ++ replicate (3 - length s) ' _' ++ s ++ " ] " ++ displayMessage msg
77+
78+ displayMessage :: Log -> String
79+ displayMessage (PackageGoal qpn gr) = " next goal: " ++ showQPN qpn ++ showGR gr
80+ displayMessage (RejectF qfn b c fr) = " rejecting: " ++ showQFNBool qfn b ++ showFR c fr
81+ displayMessage (RejectS qsn b c fr) = " rejecting: " ++ showQSNBool qsn b ++ showFR c fr
82+ displayMessage (Skipping' cs) = showConflicts cs
83+ displayMessage (TryingF qfn b) = " trying: " ++ showQFNBool qfn b
84+ displayMessage (TryingP qpn i mgr) = " trying: " ++ showQPNPOpt qpn i ++ maybe " " showGR mgr
85+ displayMessage (TryingS qsn b) = " trying: " ++ showQSNBool qsn b
86+ displayMessage (UnknownPackage' qpn gr) = " unknown package" ++ showQPN qpn ++ showGR gr
87+ displayMessage SuccessMsg = " done"
88+ displayMessage (FailureMsg c fr) = " fail: " ++ showFR c fr
89+ displayMessage (SkipMany _ _ cs) = " skipping: " ++ showConflicts cs
90+ -- TODO: Instead of displaying `aeson-1.0.2.1, aeson-1.0.2.0, aeson-1.0.1.0, ...`,
91+ -- the following line aim to display `aeson: 1.0.2.1, 1.0.2.0, 1.0.1.0, ...`.
92+ --
93+ -- displayMessage (RejectMany qpn is c fr) = "rejecting: " ++ fmtPkgsGroupedByName (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr
94+ displayMessage (RejectMany qpn is c fr) = " rejecting: " ++ L. intercalate " , " (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr
95+
96+ -- TODO: This function should take as input the Index? So even without calling the solver, We can say things as
97+ -- "There is no version in the Hackage index that match the given constraints".
98+ --
99+ -- Alternatively, by passing this to the solver, we could get a more semantic output like:
100+ -- `all versions of aeson available are in conflict with ...`. Isn't already what `tryToMinimizeConflictSet` is doing?
101+ -- fmtPkgsGroupedByName :: [String] -> String
102+ -- fmtPkgsGroupedByName pkgs = L.intercalate " " $ fmtPkgGroup (groupByName pkgs)
103+ -- where
104+ -- groupByName :: [String] -> Map.Map String [String]
105+ -- groupByName = foldr f Map.empty
106+ -- where
107+ -- f versionString m = let (pkg, ver) = splitOnLastHyphen versionString
108+ -- in Map.insertWith (++) pkg [ver] m
109+ -- -- FIXME: This is not a very robust way to split the package name and version.
110+ -- -- I should rather retrieve the package name and version from the QPN ...
111+ -- splitOnLastHyphen :: String -> (String, String)
112+ -- splitOnLastHyphen s =
113+ -- case reverse (L.elemIndices '-' s) of
114+ -- (x:_) -> (take x s, drop (x + 1) s)
115+ -- _ -> error "splitOnLastHyphen: no hyphen found"
116+
117+ -- fmtPkgGroup :: Map.Map String [String] -> [String]
118+ -- fmtPkgGroup = map formatEntry . Map.toList
119+ -- where
120+ -- formatEntry (pkg, versions) = pkg ++ ": " ++ L.intercalate ", " versions
121+
44122-- | Transforms the structured message type to actual messages (strings).
45123--
46124-- The log contains level numbers, which are useful for any trace that involves
47125-- backtracking, because only the level numbers will allow to keep track of
48126-- backjumps.
49- showMessages :: Progress Message a b -> Progress String a b
50- showMessages = go 0
127+ groupMessages :: Progress Message a b -> Progress SolverTrace a b
128+ groupMessages = go 0
51129 where
52130 -- 'go' increments the level for a recursive call when it encounters
53131 -- 'TryP', 'TryF', or 'TryS' and decrements the level when it encounters 'Leave'.
54- go :: Int -> Progress Message a b -> Progress String a b
132+ go :: Int -> Progress Message a b -> Progress SolverTrace a b
55133 go ! _ (Done x) = Done x
56134 go ! _ (Fail x) = Fail x
135+
57136 -- complex patterns
58137 go ! l (Step (TryP qpn i) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =
59138 goPReject l qpn [i] c fr ms
139+
60140 go ! l (Step (TryP qpn i) (Step Enter (Step (Skip conflicts) (Step Leave ms)))) =
61141 goPSkip l qpn [i] conflicts ms
142+
62143 go ! l (Step (TryF qfn b) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =
63- (atLevel l $ " rejecting: " ++ showQFNBool qfn b ++ showFR c fr) (go l ms)
144+ Step (SolverTrace $ AtLevel l $ (RejectF qfn b c fr)) (go l ms)
145+
64146 go ! l (Step (TryS qsn b) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =
65- (atLevel l $ " rejecting: " ++ showQSNBool qsn b ++ showFR c fr) (go l ms)
147+ Step (SolverTrace $ AtLevel l $ (RejectS qsn b c fr)) (go l ms)
148+
149+ -- "Trying ..." message when a new goal is started
66150 go ! l (Step (Next (Goal (P _ ) gr)) (Step (TryP qpn' i) ms@ (Step Enter (Step (Next _) _)))) =
67- (atLevel l $ " trying: " ++ showQPNPOpt qpn' i ++ showGR gr) (go l ms)
151+ Step (SolverTrace $ AtLevel l $ (TryingP qpn' i (Just gr))) (go l ms)
152+
68153 go ! l (Step (Next (Goal (P qpn) gr)) (Step (Failure _c UnknownPackage ) ms)) =
69- atLevel l (" unknown package: " ++ showQPN qpn ++ showGR gr) $ go l ms
154+ Step (SolverTrace $ AtLevel l $ (UnknownPackage' qpn gr)) (go l ms)
155+
70156 -- standard display
71157 go ! l (Step Enter ms) = go (l+ 1 ) ms
72158 go ! l (Step Leave ms) = go (l- 1 ) ms
73- go ! l (Step (TryP qpn i) ms) = (atLevel l $ " trying: " ++ showQPNPOpt qpn i) (go l ms)
74- go ! l (Step (TryF qfn b) ms) = (atLevel l $ " trying: " ++ showQFNBool qfn b) (go l ms)
75- go ! l (Step (TryS qsn b) ms) = (atLevel l $ " trying: " ++ showQSNBool qsn b) (go l ms)
76- go ! l (Step (Next (Goal (P qpn) gr)) ms) = (atLevel l $ showPackageGoal qpn gr) (go l ms)
77- go ! l (Step (Next _) ms) = go l ms -- ignore flag goals in the log
78- go ! l (Step (Skip conflicts) ms) =
79- -- 'Skip' should always be handled by 'goPSkip' in the case above.
80- (atLevel l $ " skipping: " ++ showConflicts conflicts) (go l ms)
81- go ! l (Step (Success ) ms) = (atLevel l $ " done" ) (go l ms)
82- go ! l (Step (Failure c fr) ms) = (atLevel l $ showFailure c fr) (go l ms)
83-
84- showPackageGoal :: QPN -> QGoalReason -> String
85- showPackageGoal qpn gr = " next goal: " ++ showQPN qpn ++ showGR gr
86-
87- showFailure :: ConflictSet -> FailReason -> String
88- showFailure c fr = " fail" ++ showFR c fr
159+
160+ go ! l (Step (TryP qpn i) ms) = Step (SolverTrace $ AtLevel l $ (TryingP qpn i Nothing )) (go l ms)
161+ go ! l (Step (TryF qfn b) ms) = Step (SolverTrace $ AtLevel l $ (TryingF qfn b)) (go l ms)
162+ go ! l (Step (TryS qsn b) ms) = Step (SolverTrace $ AtLevel l $ (TryingS qsn b)) (go l ms)
163+ go ! l (Step (Next (Goal (P qpn) gr)) ms) = Step (SolverTrace $ AtLevel l $ (PackageGoal qpn gr)) (go l ms)
164+ go ! l (Step (Next _) ms) = go l ms -- ignore flag goals in the log
165+
166+ -- 'Skip' should always be handled by 'goPSkip' in the case above.
167+ go ! l (Step (Skip conflicts) ms) = Step (SolverTrace $ AtLevel l $ (Skipping' conflicts)) (go l ms)
168+ go ! l (Step (Success ) ms) = Step (SolverTrace $ AtLevel l $ SuccessMsg ) (go l ms)
169+ go ! l (Step (Failure c fr) ms) = Step (SolverTrace $ AtLevel l $ (FailureMsg c fr)) (go l ms)
89170
90171 -- special handler for many subsequent package rejections
91172 goPReject :: Int
@@ -94,32 +175,24 @@ showMessages = go 0
94175 -> ConflictSet
95176 -> FailReason
96177 -> Progress Message a b
97- -> Progress String a b
178+ -> Progress SolverTrace a b
98179 goPReject l qpn is c fr (Step (TryP qpn' i) (Step Enter (Step (Failure _ fr') (Step Leave ms))))
99- | qpn == qpn' && fr == fr' = goPReject l qpn (i : is) c fr ms
180+ | qpn == qpn' && fr == fr' =
181+ goPReject l qpn (i : is) c fr ms
100182 goPReject l qpn is c fr ms =
101- (atLevel l $ " rejecting: " ++ L. intercalate " , " ( map (showQPNPOpt qpn) ( reverse is)) ++ showFR c fr) (go l ms)
183+ Step ( SolverTrace $ AtLevel l $ ( RejectMany qpn is c fr) ) (go l ms)
102184
103185 -- Handle many subsequent skipped package instances.
104186 goPSkip :: Int
105187 -> QPN
106188 -> [POption ]
107189 -> Set CS. Conflict
108190 -> Progress Message a b
109- -> Progress String a b
191+ -> Progress SolverTrace a b
110192 goPSkip l qpn is conflicts (Step (TryP qpn' i) (Step Enter (Step (Skip conflicts') (Step Leave ms))))
111193 | qpn == qpn' && conflicts == conflicts' = goPSkip l qpn (i : is) conflicts ms
112194 goPSkip l qpn is conflicts ms =
113- let msg = " skipping: "
114- ++ L. intercalate " , " (map (showQPNPOpt qpn) (reverse is))
115- ++ showConflicts conflicts
116- in atLevel l msg (go l ms)
117-
118- -- write a message with the current level number
119- atLevel :: Int -> String -> Progress String a b -> Progress String a b
120- atLevel l x xs =
121- let s = show l
122- in Step (" [" ++ replicate (3 - length s) ' _' ++ s ++ " ] " ++ x) xs
195+ Step (SolverTrace $ AtLevel l $ (SkipMany qpn is conflicts)) (go l ms)
123196
124197-- | Display the set of 'Conflicts' for a skipped package version.
125198showConflicts :: Set CS. Conflict -> String
0 commit comments