2
2
3
3
module Distribution.Solver.Modular.Message (
4
4
Message (.. ),
5
- showMessages
5
+ SolverTrace (.. ),
6
+ groupMessages ,
6
7
) where
7
8
8
9
import qualified Data.List as L
@@ -41,51 +42,130 @@ data Message =
41
42
| Success
42
43
| Failure ConflictSet FailReason
43
44
45
+ data Log
46
+ = PackageGoal QPN QGoalReason
47
+ | RejectF QFN Bool ConflictSet FailReason
48
+ | RejectS QSN Bool ConflictSet FailReason
49
+ | Skipping' (Set CS. Conflict )
50
+ | TryingF QFN Bool
51
+ | TryingP QPN POption (Maybe (GoalReason QPN ))
52
+ | TryingS QSN Bool
53
+ | RejectMany QPN [POption ] ConflictSet FailReason
54
+ | SkipMany QPN [POption ] (Set CS. Conflict )
55
+ | UnknownPackage' QPN (GoalReason QPN )
56
+ | SuccessMsg
57
+ | FailureMsg ConflictSet FailReason
58
+
59
+ data AtLevel a = AtLevel Int a
60
+
61
+ type Trace = AtLevel Log
62
+
63
+ data SolverTrace = SolverTrace Trace | ErrorMsg String
64
+
65
+ instance Show SolverTrace where
66
+ show (SolverTrace i) = displayMessageAtLevel i
67
+ show (ErrorMsg s) = show s
68
+
69
+ instance Show Log where
70
+ show = displayMessage
71
+
72
+ displayMessageAtLevel :: Trace -> String
73
+ displayMessageAtLevel (AtLevel l msg) =
74
+ let s = show l
75
+ in " [" ++ replicate (3 - length s) ' _' ++ s ++ " ] " ++ displayMessage msg
76
+
77
+ displayMessage :: Log -> String
78
+ displayMessage (PackageGoal qpn gr) = " next goal: " ++ showQPN qpn ++ showGR gr
79
+ displayMessage (RejectF qfn b c fr) = " rejecting: " ++ showQFNBool qfn b ++ showFR c fr
80
+ displayMessage (RejectS qsn b c fr) = " rejecting: " ++ showQSNBool qsn b ++ showFR c fr
81
+ displayMessage (Skipping' cs) = showConflicts cs
82
+ displayMessage (TryingF qfn b) = " trying: " ++ showQFNBool qfn b
83
+ displayMessage (TryingP qpn i mgr) = " trying: " ++ showQPNPOpt qpn i ++ maybe " " showGR mgr
84
+ displayMessage (TryingS qsn b) = " trying: " ++ showQSNBool qsn b
85
+ displayMessage (UnknownPackage' qpn gr) = " unknown package" ++ showQPN qpn ++ showGR gr
86
+ displayMessage SuccessMsg = " done"
87
+ displayMessage (FailureMsg c fr) = " fail: " ++ showFR c fr
88
+ displayMessage (SkipMany _ _ cs) = " skipping: " ++ showConflicts cs
89
+ -- TODO: Instead of displaying `aeson-1.0.2.1, aeson-1.0.2.0, aeson-1.0.1.0, ...`,
90
+ -- the following line aim to display `aeson: 1.0.2.1, 1.0.2.0, 1.0.1.0, ...`.
91
+ --
92
+ -- displayMessage (RejectMany qpn is c fr) = "rejecting: " ++ fmtPkgsGroupedByName (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr
93
+ displayMessage (RejectMany qpn is c fr) = " rejecting: " ++ L. intercalate " , " (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr
94
+
95
+ -- TODO: This function should take as input the Index? So even without calling the solver, We can say things as
96
+ -- "There is no version in the Hackage index that match the given constraints".
97
+ --
98
+ -- Alternatively, by passing this to the solver, we could get a more semantic output like:
99
+ -- `all versions of aeson available are in conflict with ...`. Isn't already what `tryToMinimizeConflictSet` is doing?
100
+ -- fmtPkgsGroupedByName :: [String] -> String
101
+ -- fmtPkgsGroupedByName pkgs = L.intercalate " " $ fmtPkgGroup (groupByName pkgs)
102
+ -- where
103
+ -- groupByName :: [String] -> Map.Map String [String]
104
+ -- groupByName = foldr f Map.empty
105
+ -- where
106
+ -- f versionString m = let (pkg, ver) = splitOnLastHyphen versionString
107
+ -- in Map.insertWith (++) pkg [ver] m
108
+ -- -- FIXME: This is not a very robust way to split the package name and version.
109
+ -- -- I should rather retrieve the package name and version from the QPN ...
110
+ -- splitOnLastHyphen :: String -> (String, String)
111
+ -- splitOnLastHyphen s =
112
+ -- case reverse (L.elemIndices '-' s) of
113
+ -- (x:_) -> (take x s, drop (x + 1) s)
114
+ -- _ -> error "splitOnLastHyphen: no hyphen found"
115
+
116
+ -- fmtPkgGroup :: Map.Map String [String] -> [String]
117
+ -- fmtPkgGroup = map formatEntry . Map.toList
118
+ -- where
119
+ -- formatEntry (pkg, versions) = pkg ++ ": " ++ L.intercalate ", " versions
120
+
44
121
-- | Transforms the structured message type to actual messages (strings).
45
122
--
46
123
-- The log contains level numbers, which are useful for any trace that involves
47
124
-- backtracking, because only the level numbers will allow to keep track of
48
125
-- backjumps.
49
- showMessages :: Progress Message a b -> Progress String a b
50
- showMessages = go 0
126
+ groupMessages :: Progress Message a b -> Progress SolverTrace a b
127
+ groupMessages = go 0
51
128
where
52
129
-- 'go' increments the level for a recursive call when it encounters
53
130
-- 'TryP', 'TryF', or 'TryS' and decrements the level when it encounters 'Leave'.
54
- go :: Int -> Progress Message a b -> Progress String a b
131
+ go :: Int -> Progress Message a b -> Progress SolverTrace a b
55
132
go ! _ (Done x) = Done x
56
133
go ! _ (Fail x) = Fail x
134
+
57
135
-- complex patterns
58
136
go ! l (Step (TryP qpn i) (Step Enter (Step (Failure c fr) (Step Leave ms)))) =
59
137
goPReject l qpn [i] c fr ms
138
+
60
139
go ! l (Step (TryP qpn i) (Step Enter (Step (Skip conflicts) (Step Leave ms)))) =
61
140
goPSkip l qpn [i] conflicts ms
141
+
62
142
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)
143
+ Step (SolverTrace $ AtLevel l $ (RejectF qfn b c fr)) (go l ms)
144
+
64
145
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)
146
+ Step (SolverTrace $ AtLevel l $ (RejectS qsn b c fr)) (go l ms)
147
+
148
+ -- "Trying ..." message when a new goal is started
66
149
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)
150
+ Step (SolverTrace $ AtLevel l $ (TryingP qpn' i (Just gr))) (go l ms)
151
+
68
152
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
153
+ Step (SolverTrace $ AtLevel l $ (UnknownPackage' qpn gr)) (go l ms)
154
+
70
155
-- standard display
71
156
go ! l (Step Enter ms) = go (l+ 1 ) ms
72
157
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
158
+
159
+ go ! l (Step (TryP qpn i) ms) = Step (SolverTrace $ AtLevel l $ (TryingP qpn i Nothing )) (go l ms)
160
+ go ! l (Step (TryF qfn b) ms) = Step (SolverTrace $ AtLevel l $ (TryingF qfn b)) (go l ms)
161
+ go ! l (Step (TryS qsn b) ms) = Step (SolverTrace $ AtLevel l $ (TryingS qsn b)) (go l ms)
162
+ go ! l (Step (Next (Goal (P qpn) gr)) ms) = Step (SolverTrace $ AtLevel l $ (PackageGoal qpn gr)) (go l ms)
163
+ go ! l (Step (Next _) ms) = go l ms -- ignore flag goals in the log
164
+
165
+ -- 'Skip' should always be handled by 'goPSkip' in the case above.
166
+ go ! l (Step (Skip conflicts) ms) = Step (SolverTrace $ AtLevel l $ (Skipping' conflicts)) (go l ms)
167
+ go ! l (Step (Success ) ms) = Step (SolverTrace $ AtLevel l $ SuccessMsg ) (go l ms)
168
+ go ! l (Step (Failure c fr) ms) = Step (SolverTrace $ AtLevel l $ (FailureMsg c fr)) (go l ms)
89
169
90
170
-- special handler for many subsequent package rejections
91
171
goPReject :: Int
@@ -94,32 +174,24 @@ showMessages = go 0
94
174
-> ConflictSet
95
175
-> FailReason
96
176
-> Progress Message a b
97
- -> Progress String a b
177
+ -> Progress SolverTrace a b
98
178
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
179
+ | qpn == qpn' && fr == fr' =
180
+ goPReject l qpn (i : is) c fr ms
100
181
goPReject l qpn is c fr ms =
101
- (atLevel l $ " rejecting: " ++ L. intercalate " , " ( map (showQPNPOpt qpn) ( reverse is)) ++ showFR c fr) (go l ms)
182
+ Step ( SolverTrace $ AtLevel l $ ( RejectMany qpn is c fr) ) (go l ms)
102
183
103
184
-- Handle many subsequent skipped package instances.
104
185
goPSkip :: Int
105
186
-> QPN
106
187
-> [POption ]
107
188
-> Set CS. Conflict
108
189
-> Progress Message a b
109
- -> Progress String a b
190
+ -> Progress SolverTrace a b
110
191
goPSkip l qpn is conflicts (Step (TryP qpn' i) (Step Enter (Step (Skip conflicts') (Step Leave ms))))
111
192
| qpn == qpn' && conflicts == conflicts' = goPSkip l qpn (i : is) conflicts ms
112
193
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
194
+ Step (SolverTrace $ AtLevel l $ (SkipMany qpn is conflicts)) (go l ms)
123
195
124
196
-- | Display the set of 'Conflicts' for a skipped package version.
125
197
showConflicts :: Set CS. Conflict -> String
0 commit comments