{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} module ProbeSolvers where import Control.Exception ( try, SomeException ) import Data.Char ( toLower ) import qualified Data.List as L import Data.Maybe ( catMaybes ) import System.Exit ( ExitCode(..) ) import System.Process ( readProcessWithExitCode ) newtype TestLevel = TestLevel String deriving Eq newtype SolverName = SolverName String deriving (Eq, Show) newtype SolverVersion = SolverVersion String deriving (Eq, Show) getSolverVersion :: SolverName -> IO (Either String SolverVersion) getSolverVersion (SolverName solver) = let args = case toLower <$> solver of -- n.b. abc will return a non-zero exit code if asked -- for command usage. "abc" -> ["s", "-q", "version;quit"] _ -> ["--version"] in try (readProcessWithExitCode (toLower <$> solver) args "") >>= \case Right (r,o,e) -> if r == ExitSuccess then let ol = lines o in return $ Right $ SolverVersion $ if null ol then (solver <> " v??") else head ol else return $ Left $ solver <> " version error: " <> show r <> " /;/ " <> e Left (err :: SomeException) -> return $ Left $ solver <> " invocation error: " <> show err reportSolverVersions :: TestLevel -> (solverinfo -> SolverName) -> [(solverinfo, Either String SolverVersion)] -> IO [(solverinfo, SolverVersion)] reportSolverVersions testLevel getSolverName versionedSolvers = do putStrLn "SOLVER SELF-REPORTED VERSIONS::" catMaybes <$> mapM (rep testLevel) versionedSolvers where rep lvl (testsolver, versionInfo) = let s = getSolverName testsolver in disp lvl testsolver s versionInfo disp lvl solver (SolverName sname) = \case Right v@(SolverVersion ver) -> do putStrLn $ " Solver " <> sname <> " -> " <> ver return $ Just (solver, v) Left e -> if and [ "does not exist" `L.isInfixOf` e , lvl == TestLevel "0" ] then do putStrLn $ " Solver " <> sname <> " not found; skipping (would fail with CI_TEST_LEVEL=1)" return Nothing else do putStrLn $ " Solver " <> sname <> " error: " <> e return $ Just (solver, SolverVersion "v?")