nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 129 lines 5.3 kB view raw
1{-# LANGUAGE DataKinds #-} 2{-# LANGUAGE DeriveAnyClass #-} 3{-# LANGUAGE DeriveGeneric #-} 4{-# LANGUAGE FlexibleContexts #-} 5{-# LANGUAGE LambdaCase #-} 6{-# LANGUAGE OverloadedStrings #-} 7{-# LANGUAGE QuasiQuotes #-} 8{-# LANGUAGE RankNTypes #-} 9{-# LANGUAGE RecordWildCards #-} 10{-# LANGUAGE ScopedTypeVariables #-} 11{-# LANGUAGE ViewPatterns #-} 12 13module Main (main) where 14 15import Control.Monad 16import Control.Monad.IO.Class 17import Data.Aeson as A hiding (Options, defaultOptions) 18import qualified Data.Aeson.Key as A 19import qualified Data.Aeson.KeyMap as HM 20import qualified Data.ByteString.Lazy.Char8 as BL8 21import qualified Data.List as L 22import Data.String.Interpolate 23import Data.Text as T hiding (count) 24import qualified Data.Vector as V 25import qualified Data.Yaml as Yaml 26import GHC.Generics 27import Options.Applicative hiding (info) 28import System.Exit 29import System.FilePath 30import Test.Sandwich 31import UnliftIO.Exception 32import UnliftIO.MVar 33import UnliftIO.Process 34import UnliftIO.QSem 35 36 37data Args = Args { 38 countFilePath :: FilePath 39 , topN :: Int 40 , parallelism :: Int 41 , juliaAttr :: Text 42 } 43 44argsParser :: Parser Args 45argsParser = Args 46 <$> strOption (long "count-file" <> short 'c' <> help "YAML file containing package names and counts") 47 <*> option auto (long "top-n" <> short 'n' <> help "How many of the top packages to build" <> showDefault <> value 100 <> metavar "INT") 48 <*> option auto (long "parallelism" <> short 'p' <> help "How many builds to run at once" <> showDefault <> value 10 <> metavar "INT") 49 <*> strOption (long "julia-attr" <> short 'a' <> help "Which Julia attr to build with" <> showDefault <> value "julia" <> metavar "STRING") 50 51data NameAndCount = NameAndCount { 52 name :: Text 53 , count :: Int 54 , uuid :: Text 55 } deriving (Show, Eq, Generic, FromJSON) 56 57newtype JuliaPath = JuliaPath FilePath 58 deriving Show 59 60julia :: Label "julia" (MVar (Maybe JuliaPath)) 61julia = Label 62 63main :: IO () 64main = do 65 clo <- parseCommandLineArgs argsParser (return ()) 66 let args@(Args {..}) = optUserOptions clo 67 68 namesAndCounts :: [NameAndCount] <- Yaml.decodeFileEither countFilePath >>= \case 69 Left err -> throwIO $ userError ("Couldn't decode names and counts YAML file: " <> show err) 70 Right x -> pure x 71 72 runSandwichWithCommandLineArgs' defaultOptions argsParser $ parallel $ do 73 miscTests args 74 75 describe ("Building environments for top " <> show topN <> " Julia packages") $ 76 introduce "Introduce parallel semaphore" parallelSemaphore (liftIO $ newQSem parallelism) (const $ return ()) $ 77 parallel $ 78 forM_ (L.take topN namesAndCounts) $ \(NameAndCount {..}) -> 79 around "Claim semaphore" claimRunSlot $ 80 testExpr args name [i|#{juliaAttr}.withPackages ["#{name}"]|] 81 82miscTests :: Args -> SpecFree ctx IO () 83miscTests args@(Args {..}) = describe "Misc tests" $ do 84 describe "works for a package outside the General registry" $ do 85 testExpr args "HelloWorld" [iii|(#{juliaAttr}.withPackages.override { 86 packageOverrides = { 87 "HelloWorld" = pkgs.fetchFromGitHub { 88 owner = "codedownio"; 89 repo = "HelloWorld.jl"; 90 rev = "9b41c55df76eb87830dd3bd0b5601ee2582a37c6"; 91 sha256 = "sha256-G+xpMRb0RopW/xWA8KCFF/S8wuHTQbpj0qwm9CihfSc="; 92 }; 93 }; 94 }) [ "HelloWorld" ]|] 95 96 describe "misc cases" $ do 97 testExpr args "Optimization" [iii|(#{juliaAttr}.withPackages) [ "Optimization" "OptimizationOptimJL" ]|] 98 99-- * Low-level 100 101testExpr :: Args -> Text -> String -> SpecFree ctx IO () 102testExpr _args name expr = do 103 introduce' (defaultNodeOptions { nodeOptionsVisibilityThreshold = 0 }) (T.unpack name) julia (newMVar Nothing) (const $ return ()) $ do 104 it "Builds" $ do 105 let cp = proc "nix" ["build", "--impure", "--no-link", "--json", "--expr", [i|with import ../../../../. {}; #{expr}|]] 106 output <- readCreateProcessWithLogging cp "" 107 juliaPath <- case A.eitherDecode (BL8.pack output) of 108 Right (A.Array ((V.!? 0) -> Just (A.Object (aesonLookup "outputs" -> Just (A.Object (aesonLookup "out" -> Just (A.String t))))))) -> do 109 info [i|built: #{t}|] 110 pure (JuliaPath ((T.unpack t) </> "bin" </> "julia")) 111 x -> expectationFailure ("Couldn't parse output: " <> show x) 112 113 getContext julia >>= flip modifyMVar_ (const $ return (Just juliaPath)) 114 115 it "Uses" $ do 116 getContext julia >>= readMVar >>= \case 117 Nothing -> expectationFailure "Build step failed." 118 Just (JuliaPath juliaPath) -> do 119 let cp = proc juliaPath ["-e", "using " <> T.unpack name] 120 createProcessWithLogging cp >>= waitForProcess >>= (`shouldBe` ExitSuccess) 121 122 where 123 aesonLookup :: Text -> HM.KeyMap v -> Maybe v 124 aesonLookup = HM.lookup . A.fromText 125 126claimRunSlot :: (HasParallelSemaphore ctx) => ExampleT ctx IO a -> ExampleT ctx IO () 127claimRunSlot f = do 128 s <- getContext parallelSemaphore 129 bracket_ (liftIO $ waitQSem s) (liftIO $ signalQSem s) (void f)