about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/julia-modules/tests/julia-top-n/app/Main.hs
blob: ed9f8d405b12cee402c643da24795939765f5560 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}

module Main (main) where

import Control.Exception
import Control.Monad
import Data.Aeson as A hiding (Options, defaultOptions)
import qualified Data.Aeson.Key             as A
import qualified Data.Aeson.KeyMap          as HM
import qualified Data.ByteString.Lazy.Char8 as BL8
import qualified Data.List as L
import Data.Text as T
import qualified Data.Vector as V
import qualified Data.Yaml as Yaml
import GHC.Generics
import Options.Applicative
import System.Exit
import System.FilePath
import Test.Sandwich hiding (info)
import UnliftIO.MVar
import UnliftIO.Process


data Args = Args {
  countFilePath :: FilePath
  , topN :: Int
  , parallelism :: Int
  }

argsParser :: Parser Args
argsParser = Args
  <$> strOption (long "count-file" <> short 'c' <> help "YAML file containing package names and counts")
  <*> option auto (long "top-n" <> short 'n' <> help "How many of the top packages to build" <> showDefault <> value 100 <> metavar "INT")
  <*> option auto (long "parallelism" <> short 'p' <> help "How many builds to run at once" <> showDefault <> value 10 <> metavar "INT")

data NameAndCount = NameAndCount {
  name :: Text
  , count :: Int
  , uuid :: Text
  } deriving (Show, Eq, Generic, FromJSON)

newtype JuliaPath = JuliaPath FilePath
  deriving Show

julia :: Label "julia" (MVar (Maybe JuliaPath))
julia = Label

main :: IO ()
main = do
  clo <- parseCommandLineArgs argsParser (return ())
  let Args {..} = optUserOptions clo

  namesAndCounts :: [NameAndCount] <- Yaml.decodeFileEither countFilePath >>= \case
    Left err -> throwIO $ userError ("Couldn't decode names and counts YAML file: " <> show err)
    Right x -> pure x

  runSandwichWithCommandLineArgs' defaultOptions argsParser $
    describe ("Building environments for top " <> show topN <> " Julia packages") $
      parallelN parallelism $
        forM_ (L.take topN namesAndCounts) $ \(NameAndCount {..}) ->
          introduce' (defaultNodeOptions { nodeOptionsVisibilityThreshold = 0 }) (T.unpack name) julia (newMVar Nothing) (const $ return ()) $ do
            it "Builds" $ do
              let cp = proc "nix" ["build", "--impure", "--no-link", "--json", "--expr"
                                  , "with import ../../../../. {}; julia.withPackages [\"" <> T.unpack name <> "\"]"
                                  ]
              output <- readCreateProcessWithLogging cp ""
              juliaPath <- case A.eitherDecode (BL8.pack output) of
                Right (A.Array ((V.!? 0) -> Just (A.Object (aesonLookup "outputs" -> Just (A.Object (aesonLookup "out" -> Just (A.String t))))))) -> pure (JuliaPath ((T.unpack t) </> "bin" </> "julia"))
                x -> expectationFailure ("Couldn't parse output: " <> show x)

              getContext julia >>= flip modifyMVar_ (const $ return (Just juliaPath))

            it "Uses" $ do
              getContext julia >>= readMVar >>= \case
                Nothing -> expectationFailure "Build step failed."
                Just (JuliaPath juliaPath) -> do
                  let cp = proc juliaPath ["-e", "using " <> T.unpack name]
                  createProcessWithLogging cp >>= waitForProcess >>= (`shouldBe` ExitSuccess)

aesonLookup :: Text -> HM.KeyMap v -> Maybe v
aesonLookup = HM.lookup . A.fromText