1
1
{-# LANGUAGE BangPatterns #-}
2
+ {-# LANGUAGE InstanceSigs #-}
2
3
3
4
module Distribution.Solver.Modular.Message (
4
5
Message(..),
5
- showMessages
6
+ SolverTrace(..),
7
+ groupMessages,
6
8
) where
7
9
8
10
import qualified Data.List as L
@@ -41,51 +43,130 @@ data Message =
41
43
| Success
42
44
| Failure ConflictSet FailReason
43
45
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
+
44
122
-- | Transforms the structured message type to actual messages (strings).
45
123
--
46
124
-- The log contains level numbers, which are useful for any trace that involves
47
125
-- backtracking, because only the level numbers will allow to keep track of
48
126
-- 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
51
129
where
52
130
-- 'go' increments the level for a recursive call when it encounters
53
131
-- '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
55
133
go !_ (Done x) = Done x
56
134
go !_ (Fail x) = Fail x
135
+
57
136
-- complex patterns
58
137
go !l (Step (TryP qpn i) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =
59
138
goPReject l qpn [i] c fr ms
139
+
60
140
go !l (Step (TryP qpn i) (Step Enter (Step (Skip conflicts) (Step Leave ms)))) =
61
141
goPSkip l qpn [i] conflicts ms
142
+
62
143
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
+
64
146
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
66
150
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
+
68
153
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
+
70
156
-- standard display
71
157
go !l (Step Enter ms) = go (l+1) ms
72
158
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)
89
170
90
171
-- special handler for many subsequent package rejections
91
172
goPReject :: Int
@@ -94,32 +175,24 @@ showMessages = go 0
94
175
-> ConflictSet
95
176
-> FailReason
96
177
-> Progress Message a b
97
- -> Progress String a b
178
+ -> Progress SolverTrace a b
98
179
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
100
182
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)
102
184
103
185
-- Handle many subsequent skipped package instances.
104
186
goPSkip :: Int
105
187
-> QPN
106
188
-> [POption]
107
189
-> Set CS.Conflict
108
190
-> Progress Message a b
109
- -> Progress String a b
191
+ -> Progress SolverTrace a b
110
192
goPSkip l qpn is conflicts (Step (TryP qpn' i) (Step Enter (Step (Skip conflicts') (Step Leave ms))))
111
193
| qpn == qpn' && conflicts == conflicts' = goPSkip l qpn (i : is) conflicts ms
112
194
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)
123
196
124
197
-- | Display the set of 'Conflicts' for a skipped package version.
125
198
showConflicts :: Set CS.Conflict -> String
0 commit comments