4
4
--resolver nightly-2018-12-15
5
5
--package shake
6
6
--package directory
7
+ --package extra
7
8
-}
9
+ {-# LANGUAGE LambdaCase #-}
10
+ {-# LANGUAGE TupleSections #-}
8
11
import Development.Shake
9
12
import Development.Shake.Command
10
13
import Development.Shake.FilePath
11
14
import Control.Monad
15
+ import Control.Monad.IO.Class
16
+ import Control.Monad.Extra (unlessM , mapMaybeM )
17
+ import Data.Maybe (isJust )
12
18
import System.Directory ( findExecutable )
13
19
import System.Environment ( getProgName
14
20
, unsetEnv
@@ -19,6 +25,7 @@ import System.Info ( os
19
25
20
26
import Data.List ( dropWhileEnd
21
27
, intersperse
28
+ , intercalate
22
29
)
23
30
import Data.Char ( isSpace )
24
31
@@ -57,7 +64,7 @@ main = do
57
64
want [" short-help" ]
58
65
-- general purpose targets
59
66
phony " submodules" updateSubmodules
60
- phony " cabal" (getStackGhcPath mostRecentHieVersion >>= installCabal)
67
+ phony " cabal" installCabal
61
68
phony " short-help" shortHelpMessage
62
69
phony " all" shortHelpMessage
63
70
phony " help" helpMessage
@@ -72,26 +79,21 @@ main = do
72
79
)
73
80
liftIO $ putStrLn $ embedInStars msg
74
81
75
-
76
82
-- stack specific targets
77
83
phony " build" (need (reverse $ map (" hie-" ++ ) hieVersions))
78
- phony " build-all" (need [" build-docs" , " build" ])
79
- phony " build-docs" (need (reverse $ map (" build-doc-" ++ ) hieVersions))
84
+ phony " build-all" (need [" build-doc" , " build" ])
80
85
phony " test" $ do
81
86
need [" submodules" ]
82
87
need [" cabal" ]
83
88
forM_ hieVersions stackTest
84
89
85
90
phony " build-copy-compiler-tool" $ forM_ hieVersions buildCopyCompilerTool
86
91
87
- phony " stack-build-doc" stackBuildDoc
88
- forM_
89
- hieVersions
90
- (\ version -> phony (" build-doc-" ++ version) $ do
92
+ phony " build-doc" $ do
91
93
need [" submodules" ]
92
- need [ " cabal " ]
93
- need [ " stack-build-doc " ]
94
- )
94
+ stackBuildDoc
95
+
96
+ -- main targets for building hie with `stack`
95
97
forM_
96
98
hieVersions
97
99
(\ version -> phony (" hie-" ++ version) $ do
@@ -103,22 +105,17 @@ main = do
103
105
104
106
-- cabal specific targets
105
107
phony " cabal-build" (need (map (" cabal-hie-" ++ ) ghcVersions))
106
- phony " cabal-build-all" (need [" cabal-build-docs" , " cabal-build" ])
107
- phony " cabal-build-docs" (need (map (" cabal-build-doc-" ++ ) ghcVersions))
108
+ phony " cabal-build-all" (need [" cabal-build-doc" , " cabal-build" ])
109
+ phony " cabal-build-doc" $ do
110
+ need [" submodules" ]
111
+ need [" cabal" ]
112
+ cabalBuildDoc
108
113
109
114
phony " cabal-test" $ do
110
115
need [" submodules" ]
111
116
need [" cabal" ]
112
117
forM_ ghcVersions cabalTest
113
118
114
- phony " cabal-doc" cabalBuildDoc
115
- forM_
116
- hieVersions
117
- (\ version -> phony (" cabal-build-doc-" ++ version) $ do
118
- need [" submodules" ]
119
- need [" cabal" ]
120
- need [" cabal-doc" ]
121
- )
122
119
forM_
123
120
hieVersions
124
121
(\ version -> phony (" cabal-hie-" ++ version) $ do
@@ -145,6 +142,7 @@ buildIcuMacosFix version = execStackWithYaml_
145
142
, " --extra-include-dirs=/usr/local/opt/icu4c/include"
146
143
]
147
144
145
+ -- | update the submodules that the project is in the state as required by the `stack.yaml` files
148
146
updateSubmodules :: Action ()
149
147
updateSubmodules = do
150
148
command_ [] " git" [" submodule" , " sync" , " --recursive" ]
@@ -157,24 +155,21 @@ validateCabalNewInstallIsSupported = when (os `elem` ["mingw32", "win32"]) $ do
157
155
158
156
configureCabal :: VersionNumber -> Action ()
159
157
configureCabal versionNumber = do
160
- ghcPath' <- liftIO $ getGhcPath versionNumber
161
- ghcPath <- case ghcPath' of
162
- Nothing -> do
158
+ ghcPath <- getGhcPath versionNumber >>= \ case
159
+ Nothing -> do -- TODO: this is better written using a monad-transformer
163
160
liftIO $ putStrLn $ embedInStars (ghcVersionNotFound versionNumber)
164
161
error (ghcVersionNotFound versionNumber)
165
162
Just p -> return p
166
163
execCabal_
167
164
[" new-configure" , " -w" , ghcPath, " --write-ghc-environment-files=never" ]
168
165
169
166
findInstalledGhcs :: IO [(VersionNumber , GhcPath )]
170
- findInstalledGhcs = foldM
171
- (\ found version -> do
172
- path <- getGhcPath version
173
- case path of
174
- Nothing -> return found
175
- Just p -> return $ (version, p) : found
167
+ findInstalledGhcs = mapMaybeM
168
+ (\ version -> do
169
+ getGhcPath version >>= \ case
170
+ Nothing -> return Nothing
171
+ Just p -> return $ Just (version, p)
176
172
)
177
- []
178
173
hieVersions
179
174
180
175
cabalBuildHie :: VersionNumber -> Action ()
@@ -198,36 +193,30 @@ cabalInstallHie versionNumber = do
198
193
(localBin </> " hie-" ++ dropExtension versionNumber <.> exe)
199
194
200
195
cabalBuildDoc :: Action ()
201
- cabalBuildDoc = generateHoogleDatabase $ do
202
- localBin <- getLocalBin
203
- execCabal_ [" new-install" , " --symlink-bindir=" ++ localBin, " hoogle" ]
196
+ cabalBuildDoc = do
197
+ execCabal_ [" new-build" , " hoogle" , " generate" ]
204
198
execCabal_ [" new-exec" , " hoogle" , " generate" ]
205
199
206
- generateHoogleDatabase :: Action () -> Action ()
207
- generateHoogleDatabase installIfNecessary = do
208
- mayHoogle <- liftIO $ findExecutable " hoogle"
209
- case mayHoogle of
210
- Nothing -> installIfNecessary
211
- Just hoogle -> command_ [] " hoogle" [" generate" ]
212
-
213
-
214
200
cabalTest :: VersionNumber -> Action ()
215
201
cabalTest versionNumber = do
216
202
configureCabal versionNumber
217
203
execCabal_ [" new-test" ]
218
204
219
- installCabal :: GhcPath -> Action ()
220
- installCabal ghc = do
221
- execStack_ [" install" , " --stack-yaml=shake.yaml" , " cabal-install" ]
205
+ installCabal :: Action ()
206
+ installCabal = do
207
+ -- install `cabal-install` if not already installed
208
+ unlessM (existsExecutable " cabal" ) $ do
209
+ execStack_ [" install" , " --stack-yaml=shake.yaml" , " cabal-install" ]
222
210
execCabal_ [" update" ]
211
+ ghc <- getStackGhcPath mostRecentHieVersion
223
212
execCabal_ [" install" , " Cabal-2.4.1.0" , " --with-compiler=" ++ ghc]
224
213
225
214
stackBuildHie :: VersionNumber -> Action ()
226
215
stackBuildHie versionNumber = do
227
- execStackWithYaml_ versionNumber [" install" , " happy" ]
228
216
execStackWithYaml_ versionNumber [" build" ]
229
217
`actionOnException` liftIO (putStrLn stackBuildFailMsg)
230
218
219
+ -- | copy the built binaries into the localBinDir
231
220
stackInstallHie :: VersionNumber -> Action ()
232
221
stackInstallHie versionNumber = do
233
222
execStackWithYaml_ versionNumber [" install" ]
@@ -247,10 +236,11 @@ stackTest :: VersionNumber -> Action ()
247
236
stackTest versionNumber = execStackWithYaml_ versionNumber [" test" ]
248
237
249
238
stackBuildDoc :: Action ()
250
- stackBuildDoc = generateHoogleDatabase $ do
251
- execStack_ [" --stack-yaml=shake.yaml" , " install " , " hoogle" ]
239
+ stackBuildDoc = do
240
+ execStack_ [" --stack-yaml=shake.yaml" , " build " , " hoogle" ]
252
241
execStack_ [" --stack-yaml=shake.yaml" , " exec" , " hoogle" , " generate" ]
253
242
243
+ -- | short help message is printed by default
254
244
shortHelpMessage :: Action ()
255
245
shortHelpMessage = do
256
246
let out = liftIO . putStrLn
@@ -275,25 +265,19 @@ shortHelpMessage = do
275
265
++ allVersionMessage hieVersions
276
266
++ " )"
277
267
)
278
- , ( " build-all"
279
- , " Builds hie and hoogle databases for all supported GHC versions"
280
- )
268
+ , stackBuildAllTarget
281
269
, stackHieTarget mostRecentHieVersion
282
- , stackBuildDocTarget mostRecentHieVersion
270
+ , stackBuildDocTarget
283
271
, stackHieTarget " 8.4.4"
284
- , stackBuildDocTarget " 8.4.4"
285
272
, emptyTarget
286
273
, ( " cabal-ghcs"
287
274
, " Show all GHC versions that can be installed via `cabal-build` and `cabal-build-all`."
288
275
)
289
- , (" cabal-build" , " Builds hie with cabal with all installed GHCs." )
290
- , ( " cabal-build-all"
291
- , " Builds hie and hoogle databases for all installed GHC versions with cabal"
292
- )
276
+ , cabalBuildTarget
277
+ , cabalBuildAllTarget
293
278
, cabalHieTarget mostRecentHieVersion
294
- , cabalBuildDocTarget mostRecentHieVersion
279
+ , cabalBuildDocTarget
295
280
, cabalHieTarget " 8.4.4"
296
- , cabalBuildDocTarget " 8.4.4"
297
281
]
298
282
299
283
@@ -315,13 +299,13 @@ helpMessage = do
315
299
-- All targets the shake file supports
316
300
targets :: [(String , String )]
317
301
targets =
318
- generalTargets
319
- ++ [emptyTarget]
320
- ++ stackTargets
321
- ++ [emptyTarget]
322
- ++ cabalTargets
323
- ++ [emptyTarget]
324
- ++ macosTargets
302
+ intercalate
303
+ [emptyTarget]
304
+ [ generalTargets
305
+ , stackTargets
306
+ , cabalTargets
307
+ , macosTargets
308
+ ]
325
309
326
310
-- All targets with their respective help message.
327
311
generalTargets =
@@ -339,39 +323,29 @@ helpMessage = do
339
323
++ allVersionMessage hieVersions
340
324
++ " )"
341
325
)
342
- , ( " build-all"
343
- , " Builds hie and hoogle databases for all supported GHC versions"
344
- )
345
- , ( " build-docs"
346
- , " Builds the Hoogle database for all supported GHC versions"
347
- )
326
+ , stackBuildAllTarget
327
+ , stackBuildDocTarget
348
328
, (" test" , " Runs hie tests with stack" )
349
329
]
350
330
++ map stackHieTarget hieVersions
351
- ++ map stackBuildDocTarget hieVersions
352
331
353
332
cabalTargets =
354
333
[ ( " cabal-ghcs"
355
334
, " Show all GHC versions that can be installed via `cabal-build` and `cabal-build-all`."
356
335
)
357
- , (" cabal-build" , " Builds hie with cabal with all installed GHCs." )
358
- , ( " cabal-build-all"
359
- , " Builds hie and hoogle databases for all installed GHC versions with cabal"
360
- )
361
- , ( " cabal-build-docs"
362
- , " Builds the Hoogle database for all installed GHC versions with cabal"
363
- )
336
+ , cabalBuildTarget
337
+ , cabalBuildAllTarget
338
+ , cabalBuildDocTarget
364
339
, (" cabal-test" , " Runs hie tests with cabal" )
365
340
]
366
341
++ map cabalHieTarget hieVersions
367
- ++ map cabalBuildDocTarget hieVersions
368
342
369
343
-- | Empty target. Purpose is to introduce a newline between the targets
370
344
emptyTarget :: (String , String )
371
345
emptyTarget = (" " , " " )
372
346
373
347
-- | Number of spaces the target name including whitespace should have.
374
- -- At least twenty, maybe more if target names are long. At most length of the longest target plus five.
348
+ -- At least twenty, maybe more if target names are long and at least the length of the longest target plus five.
375
349
space :: [(String , String )] -> Int
376
350
space phonyTargets = maximum (20 : map ((+ 5 ) . length . fst ) phonyTargets)
377
351
@@ -395,20 +369,32 @@ cabalHieTarget version =
395
369
, " Builds hie for GHC version " ++ version ++ " only with cabal new-build"
396
370
)
397
371
398
- stackBuildDocTarget :: VersionNumber -> (String , String )
399
- stackBuildDocTarget version =
400
- ( " build-doc-" ++ version
401
- , " Builds the Hoogle database for GHC version "
402
- ++ version
403
- ++ " only with stack"
372
+ stackBuildDocTarget :: (String , String )
373
+ stackBuildDocTarget =
374
+ ( " build-doc"
375
+ , " Builds the Hoogle database"
376
+ )
377
+
378
+ stackBuildAllTarget :: (String , String )
379
+ stackBuildAllTarget =
380
+ ( " build-all"
381
+ , " Builds hie for all supported GHC versions and the hoogle database"
382
+ )
383
+
384
+ cabalBuildTarget :: (String , String )
385
+ cabalBuildTarget =
386
+ (" cabal-build" , " Builds hie with cabal with all installed GHCs." )
387
+
388
+ cabalBuildDocTarget :: (String , String )
389
+ cabalBuildDocTarget =
390
+ ( " cabal-build-doc"
391
+ , " Builds the Hoogle database with cabal"
404
392
)
405
393
406
- cabalBuildDocTarget :: VersionNumber -> (String , String )
407
- cabalBuildDocTarget version =
408
- ( " cabal-build-doc-" ++ version
409
- , " Builds the Hoogle database for GHC version "
410
- ++ version
411
- ++ " only with cabal"
394
+ cabalBuildAllTarget :: (String , String )
395
+ cabalBuildAllTarget =
396
+ ( " cabal-build-all"
397
+ , " Builds hie for all installed GHC versions and the hoogle database with cabal"
412
398
)
413
399
414
400
-- | Creates a message of the form "a, b, c and d", where a,b,c,d are GHC versions.
@@ -422,6 +408,9 @@ allVersionMessage wordList = case wordList of
422
408
lastVersion = last msg
423
409
in concat $ (init $ init msg) ++ [" and " , lastVersion]
424
410
411
+
412
+ -- TODO: more sophisticated interface to stack and cabal
413
+
425
414
execStackWithYaml_ :: VersionNumber -> [String ] -> Action ()
426
415
execStackWithYaml_ versionNumber args = do
427
416
let stackFile = " stack-" ++ versionNumber ++ " .yaml"
@@ -441,6 +430,9 @@ execStack_ = command_ [] "stack"
441
430
execCabal_ :: [String ] -> Action ()
442
431
execCabal_ = command_ [] " cabal"
443
432
433
+ existsExecutable :: MonadIO m => String -> m Bool
434
+ existsExecutable executable = liftIO $ isJust <$> findExecutable executable
435
+
444
436
-- | Get the path to the GHC compiler executable linked to the local `stack-$GHCVER.yaml`.
445
437
-- Equal to the command `stack path --stack-yaml $stack-yaml --compiler-exe`.
446
438
-- This might install a GHC if it is not already installed, thus, might fail if stack fails to install the GHC.
@@ -453,14 +445,12 @@ getStackGhcPath ghcVersion = do
453
445
-- If no such GHC can be found, Nothing is returned.
454
446
-- First, it is checked whether there is a GHC with the name `ghc-$VersionNumber`.
455
447
-- If this yields no result, it is checked, whether the numeric-version of the `ghc`
456
- -- command fits to the desired version.
457
- getGhcPath :: VersionNumber -> IO (Maybe GhcPath )
458
- getGhcPath ghcVersion = do
459
- pathMay <- findExecutable (" ghc-" ++ ghcVersion)
460
- case pathMay of
448
+ -- command fits to the desired version.
449
+ getGhcPath :: MonadIO m => VersionNumber -> m (Maybe GhcPath )
450
+ getGhcPath ghcVersion = liftIO $ do
451
+ findExecutable (" ghc-" ++ ghcVersion) >>= \ case
461
452
Nothing -> do
462
- noPrefixPathMay <- findExecutable " ghc"
463
- case noPrefixPathMay of
453
+ findExecutable " ghc" >>= \ case
464
454
Nothing -> return Nothing
465
455
Just p -> do
466
456
Stdout version <- cmd p [" --numeric-version" ] :: IO (Stdout String )
0 commit comments