aboutsummaryrefslogtreecommitdiff
path: root/tests/CompileTest.hs
blob: 88ba44e299b19504490a5d2554545facf8db3920 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
{-# LANGUAGE ScopedTypeVariables, GADTs, ImplicitParams, OverloadedStrings #-}

{-| This test tries to compile the Helper against every supported version of the
  Cabal library. Since we compile the Helper at runtime, on the user's machine,
  it is very important to make sure this will not fail to compile.

  This test only covers using v2-build to install the requested Cabal library
  version because it has the best build product caching (keeps CI times
  down). We could also use stack since it has a global package cache but we
  don't support that because stack always comes with the right Cabal library
  version available for a given resolver anyways.
-}

import System.Environment (getArgs)
import System.Directory
import System.FilePath
import System.Process
import System.Exit
import System.IO
import System.IO.Temp
import Data.List
import Data.Maybe
import Data.Version
import Data.Functor
import Data.Function
import Distribution.Version (VersionRange, withinRange)
import Control.Arrow
import Control.Monad
import Control.Monad.Trans.Maybe
import Prelude

import CabalHelper.Compiletime.Compat.Environment
import CabalHelper.Compiletime.Compat.Version
import CabalHelper.Compiletime.Compat.Parsec
import CabalHelper.Compiletime.Cabal
import CabalHelper.Compiletime.Compile
import CabalHelper.Compiletime.Program.GHC
import CabalHelper.Compiletime.Types
import CabalHelper.Shared.Common

import TestOptions

withinRange'CH :: Version -> VersionRange -> Bool
withinRange'CH v r =
    withinRange (fromDataVersion v) r

setupHOME :: IO ()
setupHOME = do
  mhome <- lookupEnv "HOME"
  case mhome of
    Just home -> do
      exists <- doesDirectoryExist home
      when (not exists) createHOME
    Nothing -> createHOME

createHOME :: IO ()
createHOME = do
  tmp <- fromMaybe "/tmp" <$> lookupEnv "TMPDIR"
  let home = tmp </> "compile-test-home"
  _ <- rawSystem "rm" ["-r", home]
  createDirectory home
  setEnv "HOME" home

main :: IO ()
main = do
  (modProgs, args) <- testOpts =<< getArgs

  let ?progs = modProgs defaultPrograms
  let ?opts = defaultCompileOptions { oVerbose = True }
  let ?verbose = \level -> case level of 1 -> True; _ -> False

  case args of
    "list-versions":[] -> do
        mapM_ print =<< relevantCabalVersions =<< ghcVersion
    "list-versions":ghc_ver_str:[] ->
        mapM_ print =<< relevantCabalVersions (GhcVersion (parseVer ghc_ver_str))
    _ ->
        test args

test :: Env => [String] -> IO ()
test args = do
  let action
       | null args = testRelevantCabalVersions
       | otherwise = testCabalVersions $ map parseVer' args

  setupHOME

  action

parseVer' :: String -> CabalVersion
parseVer' "HEAD" = CabalHEAD ()
parseVer' v      = CabalVersion $ parseVer v

relevantCabalVersions :: GhcVersion -> IO [Version]
relevantCabalVersions g = map snd . filter fst <$> allCabalVersions g

allCabalVersions :: GhcVersion -> IO [(Bool,Version)]
allCabalVersions (GhcVersion ghc_ver) = do
  cabal_versions
      <- map parseVer . lines <$> readFile "tests/cabal-versions"
  let
    constraint :: VersionRange
    Just constraint =
        fmap snd $
        find (and . (zipWith (==) `on` versionBranch) ghc_ver . fst) $
        constraint_table

    constraint_table :: [(Version, VersionRange)]
    constraint_table =
        map (parseVer *** (absorbParsecFailure "constraint_table" . eitherParsec)) $
            -- , ("7.8"  , ">= 1.18    && < 2")
            [ ("7.10" , ">= 1.22.2  && < 2")
            , ("8.0.1", ">= 1.24          ")
            , ("8.0.2", ">= 1.24.2        ")
            , ("8.2",   ">= 1.24.2.0      ")
            , ("8.4",   ">= 2.0.0.2       ")
            , ("8.6",   ">= 2.0.0.2       ")
            , ("8.8",   ">= 3.0.0.0       ")
            ]
  return $ reverse $ map (flip withinRange'CH constraint &&& id) cabal_versions


testRelevantCabalVersions :: Env => IO ()
testRelevantCabalVersions = do
  ghc_ver <- ghcVersion
  relevant_cabal_versions <- relevantCabalVersions ghc_ver
  testCabalVersions $ map CabalVersion relevant_cabal_versions ++ [CabalHEAD ()]

testCabalVersions :: Env => [CabalVersion] -> IO ()
testCabalVersions versions = do
--  ghcVer <- ghcVersion
  rvs <- forM versions $ \cv -> do
    withSystemTempDirectory "cabal-helper.proj-local-tmp" $ \tmpdir -> do

    let sver = showCabalVersion cv
    hPutStrLn stderr $ "\n\n\n\n\n\n====== Compiling with Cabal-" ++ sver

    let che0 = \icv db -> CompHelperEnv
          { cheCabalVer = icv
          , chePkgDb = db
          , cheProjDir = tmpdir
          , chePlanJson = Nothing
          , cheDistV2 = Just $ tmpdir </> "dist-newstyle"
          , cheProjLocalCacheDir =
              tmpdir </> "dist-newstyle" </> "cache"
          }

    che <- case cv of
      CabalHEAD () -> do
        rcv <- resolveCabalVersion cv
        db <- getPrivateCabalPkgDb rcv
        mcabalVersions <- runMaybeT $ listCabalVersions (Just db)
        case mcabalVersions of
          Just [hdver] ->
            return $ che0 (CabalVersion hdver) [db]
          _ ->
            return $ che0 (CabalHEAD ()) []
      (CabalVersion ver) ->
        return $ che0 (CabalVersion ver) []

    compileHelper che

  let printStatus (cv, rv) = putStrLn $ "- Cabal "++ver++" "++status
        where  ver = showCabalVersion cv
               status = case rv of
                         Right _ ->
                             "succeeded"
                         Left rvc ->
                             "failed (exit code "++show rvc++")"

  let drvs = versions `zip` rvs

  mapM_ printStatus drvs
  if any isLeft' $ map snd $ filter ((/=(CabalHEAD ())) . fst) drvs
     then exitFailure
     else exitSuccess

 where
   isLeft' (Left _) = True
   isLeft' (Right _) = False