forked from commercialhaskell/stack-templates
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test-templates.hs
executable file
·127 lines (112 loc) · 4.07 KB
/
test-templates.hs
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
#!/usr/bin/env stack
{-
stack runghc
--resolver lts-5.11 --install-ghc
--no-terminal
--package mockery
--package getopt-generics
--package text
--package unordered-containers
--package yaml
--
-Wall -Werror
-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main (main) where
import Control.Arrow ((***))
import Control.Monad (forM_, unless)
import Data.HashMap.Strict (keys)
import Data.List
import Data.Maybe (fromMaybe)
import Data.Monoid
import qualified Data.Text as T
import Data.Yaml (ParseException, Object)
import qualified Data.Yaml as Yaml
import System.Directory
import System.Exit (die)
import System.FilePath ((</>), dropExtension, takeExtension, takeBaseName)
import System.IO
import System.Process
import Test.Mockery.Directory
import WithCli
excluded :: [String]
excluded =
"ghcjs-old-base" : -- ghcjs takes too long to setup
"ghcjs" : -- ghcjs takes too long to setup
"quickcheck-test-framework" : -- test-suite fails (probably intentionally)
"simple-hpack" : -- stack init fails on missing cabal file (fixed in stack on master)
"tasty-discover" : -- contains a stack file, makes `stack new` choke
"yesod-mongo" : -- needs a running db instance
"yesod-mysql" : -- needs a running db instance
"yesod-postgres-fay" : -- needs a running db instance
"yesod-postgres" : -- needs a running db instance
"yesod-sqlite" : -- missing CSFR cookie?
[]
isExcluded :: FilePath -> Bool
isExcluded file = dropExtension file `elem` excluded
main :: IO ()
main = do
logImportant $ "Verifying " <> templateInfoFile
verified <- verifyInfo
case verified of
Left err -> die err
_ -> return ()
withHsfiles $ \ hsfiles ->
forM_ hsfiles $ \ hsfile -> do
logImportant ("testing " ++ takeBaseName hsfile)
inTempDirectory $ do
callCommand ("stack new test-project " ++ hsfile ++ " --no-terminal")
setCurrentDirectory "test-project"
callCommand "stack test --fast --no-terminal --install-ghc"
withHsfiles :: ([FilePath] -> IO ()) -> IO ()
withHsfiles action = withCli $ \ (args :: [FilePath]) -> do
hsfiles <- case args of
[] -> fmap (filter $ not . isExcluded) getHsfiles
_ -> do
mapM_ checkExists args
return args
currentDirectory <- canonicalizePath =<< getCurrentDirectory
action $ map (currentDirectory </>) hsfiles
verifyInfo :: IO (Either String ())
verifyInfo = do
checkExists templateInfoFile
decoded <- Yaml.decodeFileEither templateInfoFile :: IO (Either ParseException Object)
case decoded of
Left ex -> return . Left $ "Invalid " <> templateInfoFile <> " file. " <> show ex
Right o -> do
templates <- getHsfiles
let info = map T.unpack (keys o)
check = uniqueElems (map takeBaseName templates) info
output = notEnough *** tooMuch $ check
case check of
(Nothing, Nothing) -> return $ Right ()
_ -> return $ Left $ uncurry (<>) output
where
formatOutput header items =
fromMaybe "" $ unlines . (header :) . map (" - " <>) <$> items
notEnough = formatOutput $ "Add the following templates to " <> templateInfoFile <> ":"
tooMuch = formatOutput $ "Remove the following templates from " <> templateInfoFile <> ":"
uniqueElems :: Eq a => [a] -> [a] -> (Maybe [a], Maybe [a])
uniqueElems = bothWays unique
where
bothWays f xs ys = (f xs ys, f ys xs)
unique xs ys =
case xs \\ ys of
[] -> Nothing
diff -> Just diff
templateInfoFile :: String
templateInfoFile = "template-info.yaml"
getHsfiles :: IO [FilePath]
getHsfiles =
sort . filter ((== ".hsfiles") . takeExtension) <$>
getDirectoryContents "."
checkExists :: FilePath -> IO ()
checkExists file = do
exists <- doesFileExist file
unless exists $
die ("file not found: " ++ file)
logImportant :: String -> IO ()
logImportant message =
hPutStrLn stderr $ unlines [line, message, line]
where
line = replicate (length message) '='