packages feed

keel-linalg-0.1.0.0: test/TestBackend.hs

-- | Shared test harness: find a standard-symbol OpenBLAS and pin it.
--
-- Discovery order: 'openBackend' (env \/ data dir \/ system search); if
-- that misses, a python site-packages sweep for a wheel-bundled stock
-- OpenBLAS (faiss ships one on Windows; numpy\/scipy wheels are
-- symbol-renamed and useless here) is tried through the @KEEL_OPENBLAS@
-- override. No backend found => SKIP (exit 0) with the original
-- failure printed, unless the given require-env-var is set —
-- publish-stage CI sets it with a stock OpenBLAS installed.
module TestBackend (withTestBackend) where

import Control.Exception (IOException, finally, try)
import System.Environment (lookupEnv, setEnv)
import System.Exit (ExitCode (..))
import System.Process (readProcessWithExitCode)

import Keel.Linalg

findWheelOpenblas :: IO (Maybe FilePath)
findWheelOpenblas = do
  r <- try (readProcessWithExitCode "python" ["-c", script] "")
        :: IO (Either IOException (ExitCode, String, String))
  pure $ case r of
    Right (ExitSuccess, out, _) | not (null cleaned) -> Just cleaned
      where cleaned = filter (`notElem` "\r\n") out
    _ -> Nothing
  where
    script =
      "import glob, os, sysconfig\n\
      \sp = sysconfig.get_paths()['purelib']\n\
      \g = glob.glob(os.path.join(sp, 'faiss_cpu.libs', 'libopenblas*.dll'))\n\
      \print(g[0] if g else '')\n"

withTestBackend :: String -> (Backend -> IO ()) -> IO ()
withTestBackend requireVar action = do
  first <- openBackend
  case first of
    Right be -> action be `finally` closeBackend be
    Left firstErr -> do
      wheel <- findWheelOpenblas
      second <- case wheel of
        Nothing -> pure Nothing
        Just dll -> do
          setEnv "KEEL_OPENBLAS" dll
          either (const Nothing) Just <$> openBackend
      required <- lookupEnv requireVar
      case second of
        Just be -> action be `finally` closeBackend be
        Nothing -> case required of
          Just v | v /= "" && v /= "0" ->
            fail (requireVar <> " set but no usable OpenBLAS found: " <> show firstErr)
          _ ->
            putStrLn ("SKIP - no standard-symbol OpenBLAS on this machine ("
              <> show firstErr <> ")")