hackport-0.5.5: cabal/cabal-install/Distribution/Solver/Modular/Log.hs
module Distribution.Solver.Modular.Log
( Log
, logToProgress
) where
import Prelude ()
import Distribution.Solver.Compat.Prelude
import Data.List as L
import Distribution.Solver.Types.Progress
import Distribution.Solver.Modular.Dependency
import Distribution.Solver.Modular.Message
import Distribution.Solver.Modular.Tree (FailReason(..))
import qualified Distribution.Solver.Modular.ConflictSet as CS
import Distribution.Verbosity
-- | The 'Log' datatype.
--
-- Represents the progress of a computation lazily.
--
-- Parameterized over the type of actual messages and the final result.
type Log m a = Progress m (ConflictSet, ConflictMap) a
messages :: Progress step fail done -> [step]
messages = foldProgress (:) (const []) (const [])
data Exhaustiveness = Exhaustive | BackjumpLimitReached
-- | Postprocesses a log file. Takes as an argument a limit on allowed backjumps.
-- If the limit is 'Nothing', then infinitely many backjumps are allowed. If the
-- limit is 'Just 0', backtracking is completely disabled.
logToProgress :: Verbosity -> Maybe Int -> Log Message a -> Progress String String a
logToProgress verbosity mbj l =
let es = proc (Just 0) l -- catch first error (always)
ms = proc mbj l
in go es es -- trace for first error
(showMessages (const True) True ms) -- run with backjump limit applied
where
-- Proc takes the allowed number of backjumps and a 'Progress' and explores the
-- messages until the maximum number of backjumps has been reached. It filters out
-- and ignores repeated backjumps. If proc reaches the backjump limit, it truncates
-- the 'Progress' and ends it with the last conflict set. Otherwise, it leaves the
-- original result.
proc :: Maybe Int -> Log Message b -> Progress Message (Exhaustiveness, ConflictSet, ConflictMap) b
proc _ (Done x) = Done x
proc _ (Fail (cs, cm)) = Fail (Exhaustive, cs, cm)
proc mbj' (Step x@(Failure cs Backjump) xs@(Step Leave (Step (Failure cs' Backjump) _)))
| cs == cs' = Step x (proc mbj' xs) -- repeated backjumps count as one
proc (Just 0) (Step (Failure cs Backjump) _) = Fail (BackjumpLimitReached, cs, mempty) -- No final conflict map available
proc (Just n) (Step x@(Failure _ Backjump) xs) = Step x (proc (Just (n - 1)) xs)
proc mbj' (Step x xs) = Step x (proc mbj' xs)
-- The first two arguments are both supposed to be the log up to the first error.
-- That's the error that will always be printed in case we do not find a solution.
-- We pass this log twice, because we evaluate it in parallel with the full log,
-- but we also want to retain the reference to its beginning for when we print it.
-- This trick prevents a space leak!
--
-- The third argument is the full log, ending with either the solution or the
-- exhaustiveness and final conflict set.
go :: Progress Message (Exhaustiveness, ConflictSet, ConflictMap) b
-> Progress Message (Exhaustiveness, ConflictSet, ConflictMap) b
-> Progress String (Exhaustiveness, ConflictSet, ConflictMap) b
-> Progress String String b
go ms (Step _ ns) (Step x xs) = Step x (go ms ns xs)
go ms r (Step x xs) = Step x (go ms r xs)
go ms (Step _ ns) r = go ms ns r
go ms (Fail (_, cs', _)) (Fail (exh, cs, cm)) = Fail $
"Could not resolve dependencies:\n" ++
unlines (messages $ showMessages (L.foldr (\ v _ -> v `CS.member` cs') True) False ms) ++
case exh of
Exhaustive ->
"After searching the rest of the dependency tree exhaustively, "
++ "these were the goals I've had most trouble fulfilling: "
++ showCS cm cs
where
showCS = if verbosity > normal
then CS.showCSWithFrequency
else CS.showCSSortedByFrequency
BackjumpLimitReached ->
"Backjump limit reached (" ++ currlimit mbj ++
"change with --max-backjumps or try to run with --reorder-goals).\n"
where currlimit (Just n) = "currently " ++ show n ++ ", "
currlimit Nothing = ""
go _ _ (Done s) = Done s
go _ (Done _) (Fail _) = Fail $
-- Should not happen: Second argument is the log up to first error,
-- third one is the entire log. Therefore it should never happen that
-- the second log finishes with 'Done' and the third log with 'Fail'.
"Could not resolve dependencies; something strange happened."