2018-12-11 17:22:18 +03:00
|
|
|
#!/usr/bin/env stack
|
2019-01-14 22:53:44 +03:00
|
|
|
{- stack
|
|
|
|
--stack-yaml shake.yaml
|
|
|
|
--install-ghc
|
|
|
|
runghc
|
|
|
|
--package shake
|
|
|
|
--package tar
|
|
|
|
--package zlib
|
2018-12-12 21:33:21 +03:00
|
|
|
-}
|
|
|
|
|
|
|
|
import qualified Data.ByteString.Lazy as BS
|
|
|
|
import qualified Codec.Archive.Tar as Tar
|
|
|
|
import qualified Codec.Compression.GZip as GZip
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
import Development.Shake
|
|
|
|
import Development.Shake.Command
|
|
|
|
import Development.Shake.FilePath
|
|
|
|
import Control.Monad
|
2019-01-14 10:35:20 +03:00
|
|
|
import System.Environment ( getProgName
|
|
|
|
, unsetEnv
|
|
|
|
)
|
2018-12-13 19:15:58 +03:00
|
|
|
import System.Info ( os
|
|
|
|
, arch
|
|
|
|
)
|
|
|
|
|
|
|
|
import Data.List ( dropWhileEnd )
|
|
|
|
import Data.Char ( isSpace )
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
type VersionNumber = String
|
|
|
|
type GhcPath = String
|
|
|
|
|
2018-12-13 19:15:58 +03:00
|
|
|
-- |Defines all different hie versions that are buildable.
|
2019-01-30 19:36:01 +03:00
|
|
|
-- If they are edited, make sure to maintain the order of the versions.
|
2018-12-13 19:15:58 +03:00
|
|
|
hieVersions :: [VersionNumber]
|
2019-01-15 23:13:49 +03:00
|
|
|
hieVersions =
|
|
|
|
["8.2.1", "8.2.2", "8.4.2", "8.4.3", "8.4.4", "8.6.1", "8.6.2", "8.6.3"]
|
2018-12-11 17:22:18 +03:00
|
|
|
|
2018-12-13 19:15:58 +03:00
|
|
|
-- |Most recent version of hie.
|
2019-01-26 02:45:09 +03:00
|
|
|
-- Important for `dist`, the `hie-wrapper` of the most recent hie
|
2018-12-13 19:15:58 +03:00
|
|
|
-- will be copied to the tar-archive.
|
|
|
|
mostRecentHieVersion :: VersionNumber
|
|
|
|
mostRecentHieVersion = last hieVersions
|
|
|
|
|
2018-12-11 17:22:18 +03:00
|
|
|
main :: IO ()
|
2018-12-11 18:17:33 +03:00
|
|
|
main = do
|
2018-12-12 21:33:21 +03:00
|
|
|
-- unset GHC_PACKAGE_PATH for cabal
|
2018-12-11 18:29:37 +03:00
|
|
|
unsetEnv "GHC_PACKAGE_PATH"
|
|
|
|
shakeArgs shakeOptions { shakeFiles = "_build" } $ do
|
2018-12-21 16:33:11 +03:00
|
|
|
want ["help"]
|
2018-12-11 18:29:37 +03:00
|
|
|
phony "ghc" $ do
|
2018-12-13 19:15:58 +03:00
|
|
|
ghc <- getGhcPath
|
2018-12-11 18:29:37 +03:00
|
|
|
command_ [] ghc ["--version"]
|
2018-12-12 21:33:21 +03:00
|
|
|
liftIO $ putStrLn "GHC"
|
|
|
|
phony "submodules" updateSubmodules
|
2018-12-13 19:15:58 +03:00
|
|
|
phony "cabal" (getGhcPath >>= installCabal)
|
2018-12-12 21:33:21 +03:00
|
|
|
phony "all" helpMessage
|
|
|
|
phony "help" helpMessage
|
2018-12-21 21:09:30 +03:00
|
|
|
phony "build" (need (reverse $ map ("hie-" ++) hieVersions))
|
2018-12-12 21:33:21 +03:00
|
|
|
phony "build-all" (need ["build"] >> need ["build-docs"])
|
|
|
|
phony "dist" buildDist
|
2018-12-25 18:13:12 +03:00
|
|
|
phony "build-docs" (need (reverse $ map ("build-doc-hie-" ++) hieVersions))
|
2018-12-12 21:33:21 +03:00
|
|
|
phony "test" (forM_ hieVersions test)
|
|
|
|
phony "build-copy-compiler-tool" $ forM_ hieVersions buildCopyCompilerTool
|
2018-12-11 17:22:18 +03:00
|
|
|
|
2019-01-30 19:36:01 +03:00
|
|
|
forM_ hieVersions
|
|
|
|
(\version -> phony ("build-doc-hie-" ++ version) $ buildDoc version)
|
2018-12-25 18:13:12 +03:00
|
|
|
|
2018-12-11 18:29:37 +03:00
|
|
|
forM_
|
|
|
|
hieVersions
|
|
|
|
(\version -> phony ("hie-" ++ version) $ do
|
|
|
|
need ["submodules"]
|
|
|
|
need ["cabal"]
|
2018-12-12 21:33:21 +03:00
|
|
|
buildHie version
|
2018-12-21 20:51:06 +03:00
|
|
|
installHie version
|
2018-12-11 18:29:37 +03:00
|
|
|
)
|
2018-12-11 17:22:18 +03:00
|
|
|
|
2018-12-13 18:48:36 +03:00
|
|
|
phony "icu-macos-fix"
|
|
|
|
(need ["icu-macos-fix-install"] >> need ["icu-macos-fix-build"])
|
|
|
|
phony "icu-macos-fix-install" (command_ [] "brew" ["install", "icu4c"])
|
|
|
|
phony "icu-macos-fix-build" $ mapM_ buildIcuMacosFix hieVersions
|
|
|
|
|
2018-12-13 19:15:58 +03:00
|
|
|
-- |Creates a compressed tar-archive consisting of all hie versions and `hie-wrapper`.
|
|
|
|
-- Creates a temporary folder, copies all hie versions to it and compresses it in the end.
|
2018-12-12 21:33:21 +03:00
|
|
|
buildDist :: Action ()
|
|
|
|
buildDist = do
|
2019-01-15 23:13:49 +03:00
|
|
|
need ["submodules"]
|
|
|
|
need ["cabal"]
|
2018-12-13 19:15:58 +03:00
|
|
|
-- Create the name of the resulting tar file.
|
2018-12-12 21:33:21 +03:00
|
|
|
Stdout gitRef' <- command [] "git" ["describe", "--tags"]
|
2018-12-13 19:15:58 +03:00
|
|
|
let gitRef = trim gitRef'
|
2018-12-12 21:33:21 +03:00
|
|
|
let hieDistName = concat ["hie-", gitRef, "-", arch, "-", os]
|
2018-12-14 12:30:29 +03:00
|
|
|
-- define name constants for later use
|
|
|
|
let hieWrapper = "hie-wrapper" <.> exe
|
|
|
|
let hie = "hie" <.> exe
|
|
|
|
let mkHie version = "hie-" ++ version <.> exe
|
2018-12-13 19:15:58 +03:00
|
|
|
|
2018-12-12 21:33:21 +03:00
|
|
|
withTempDir
|
|
|
|
(\temporaryDir -> do
|
|
|
|
forM_ hieVersions $ \hieVersion -> do
|
|
|
|
buildHie hieVersion
|
2018-12-13 19:15:58 +03:00
|
|
|
-- after building `hie` copy it to the temporary folder
|
|
|
|
localInstallRoot <- getLocalInstallRoot hieVersion
|
2018-12-14 12:30:29 +03:00
|
|
|
copyFile' (localInstallRoot </> "bin" </> hie)
|
|
|
|
(temporaryDir </> mkHie hieVersion)
|
2018-12-12 21:33:21 +03:00
|
|
|
|
|
|
|
-- if the most recent hie-* version is copied,
|
|
|
|
-- copy it again as the default hie version
|
2019-01-26 02:45:09 +03:00
|
|
|
-- Also, add its hie-wrapper to the tar archive
|
2018-12-13 19:15:58 +03:00
|
|
|
when (hieVersion == mostRecentHieVersion) $ do
|
2018-12-14 12:30:29 +03:00
|
|
|
copyFile' (localInstallRoot </> "bin" </> hieWrapper)
|
|
|
|
(temporaryDir </> hieWrapper)
|
|
|
|
copyFile' (localInstallRoot </> "bin" </> hie) (temporaryDir </> hie)
|
2018-12-12 21:33:21 +03:00
|
|
|
|
2018-12-13 19:15:58 +03:00
|
|
|
-- After every hie has been built, pack them into a tar.
|
|
|
|
-- Encrypt the resulting tar file with gzip
|
2018-12-12 21:33:21 +03:00
|
|
|
liftIO
|
2018-12-12 21:58:17 +03:00
|
|
|
$ BS.writeFile (hieDistName ++ ".tar.gz")
|
2018-12-12 21:33:21 +03:00
|
|
|
. GZip.compress
|
|
|
|
. Tar.write
|
2018-12-14 12:30:29 +03:00
|
|
|
=<< Tar.pack temporaryDir (hieWrapper : hie : map mkHie hieVersions)
|
2018-12-12 21:33:21 +03:00
|
|
|
)
|
|
|
|
return ()
|
|
|
|
|
2018-12-13 18:48:36 +03:00
|
|
|
buildIcuMacosFix :: VersionNumber -> Action ()
|
|
|
|
buildIcuMacosFix version = execStackWithYaml_
|
|
|
|
version
|
|
|
|
[ "build"
|
|
|
|
, "text-icu"
|
|
|
|
, "--extra-lib-dirs=/usr/local/opt/icu4c/lib"
|
|
|
|
, "--extra-include-dirs=/usr/local/opt/icu4c/include"
|
|
|
|
]
|
|
|
|
|
2018-12-12 21:33:21 +03:00
|
|
|
updateSubmodules :: Action ()
|
|
|
|
updateSubmodules = do
|
2019-01-08 04:23:16 +03:00
|
|
|
command_ [] "git" ["submodule", "sync", "--recursive"]
|
|
|
|
command_ [] "git" ["submodule", "update", "--init", "--recursive"]
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
installCabal :: GhcPath -> Action ()
|
|
|
|
installCabal ghc = do
|
2018-12-11 18:29:37 +03:00
|
|
|
execStack_ ["install", "cabal-install"]
|
2019-01-11 14:45:59 +03:00
|
|
|
execCabal_ ["update"]
|
|
|
|
execCabal_ ["install", "Cabal-2.4.1.0", "--with-compiler=" ++ ghc]
|
2018-12-11 17:22:18 +03:00
|
|
|
|
2018-12-12 21:33:21 +03:00
|
|
|
buildHie :: VersionNumber -> Action ()
|
|
|
|
buildHie versionNumber = do
|
2018-12-11 18:29:37 +03:00
|
|
|
when (versionNumber `elem` ["hie-8.2.2", "hie-8.2.1"])
|
2018-12-12 21:33:21 +03:00
|
|
|
$ execStackWithYaml_ versionNumber ["install", "happy"]
|
2019-01-30 19:36:01 +03:00
|
|
|
execStackWithYaml_ versionNumber ["build"]
|
|
|
|
`actionOnException` liftIO (putStrLn buildFailMsg)
|
2019-01-26 02:45:09 +03:00
|
|
|
|
|
|
|
buildFailMsg :: String
|
|
|
|
buildFailMsg =
|
2019-01-30 19:36:01 +03:00
|
|
|
let starsLine
|
|
|
|
= "\n******************************************************************\n"
|
|
|
|
in starsLine
|
2019-01-26 02:45:09 +03:00
|
|
|
++ "building failed, "
|
|
|
|
++ "try running `stack clean` and restart the build\n"
|
|
|
|
++ "if this does not work, open an issue at \n"
|
|
|
|
++ "https://github.com/haskell/haskell-ide-engine"
|
|
|
|
++ starsLine
|
2018-12-12 21:33:21 +03:00
|
|
|
|
2018-12-21 20:51:06 +03:00
|
|
|
installHie :: VersionNumber -> Action ()
|
|
|
|
installHie versionNumber = do
|
2018-12-12 21:33:21 +03:00
|
|
|
execStackWithYaml_ versionNumber ["install"]
|
2018-12-21 20:51:06 +03:00
|
|
|
localBinDir <- getLocalBin
|
|
|
|
localInstallRoot <- getLocalInstallRoot versionNumber
|
|
|
|
let hie = "hie" <.> exe
|
|
|
|
copyFile' (localInstallRoot </> "bin" </> hie)
|
2018-12-12 21:33:21 +03:00
|
|
|
(localBinDir </> "hie-" ++ versionNumber <.> exe)
|
2018-12-21 21:09:30 +03:00
|
|
|
copyFile' (localInstallRoot </> "bin" </> hie)
|
2018-12-25 18:07:15 +03:00
|
|
|
(localBinDir </> "hie-" ++ dropExtension versionNumber <.> exe)
|
2018-12-11 18:29:37 +03:00
|
|
|
|
|
|
|
buildCopyCompilerTool :: VersionNumber -> Action ()
|
|
|
|
buildCopyCompilerTool versionNumber =
|
2018-12-12 21:33:21 +03:00
|
|
|
execStackWithYaml_ versionNumber ["build", "--copy-compiler-tool"]
|
2018-12-11 18:29:37 +03:00
|
|
|
|
|
|
|
test :: VersionNumber -> Action ()
|
2018-12-12 21:33:21 +03:00
|
|
|
test versionNumber = execStackWithYaml_ versionNumber ["test"]
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
buildDoc :: VersionNumber -> Action ()
|
|
|
|
buildDoc versionNumber = do
|
2018-12-12 21:33:21 +03:00
|
|
|
execStackWithYaml_ versionNumber ["install", "hoogle"]
|
|
|
|
execStackWithYaml_ versionNumber ["exec", "hoogle", "generate"]
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
helpMessage :: Action ()
|
2018-12-11 18:29:37 +03:00
|
|
|
helpMessage = do
|
2019-01-14 10:35:20 +03:00
|
|
|
scriptName <- liftIO getProgName
|
2018-12-12 21:33:21 +03:00
|
|
|
out ""
|
|
|
|
out "Usage:"
|
2019-01-30 19:36:01 +03:00
|
|
|
out' ("stack " <> scriptName <> " <target>")
|
2018-12-12 21:33:21 +03:00
|
|
|
out ""
|
|
|
|
out "Targets:"
|
2019-01-30 19:36:01 +03:00
|
|
|
mapM_ (out' . showTarget) targets
|
2018-12-12 21:33:21 +03:00
|
|
|
out ""
|
2019-01-30 19:36:01 +03:00
|
|
|
where
|
|
|
|
out = liftIO . putStrLn
|
|
|
|
out' = out . (" " ++)
|
|
|
|
-- |Number of spaces the target name including whitespace should have.
|
|
|
|
-- At least twenty, maybe more if target names are long. At most length of the longest target plus five.
|
|
|
|
space :: Int
|
|
|
|
space = maximum (20 : map ((+ 5) . length . fst) targets)
|
|
|
|
|
|
|
|
-- |Show a target.
|
|
|
|
-- Concatenates the target with its help message and inserts whitespace between them.
|
|
|
|
showTarget :: (String, String) -> String
|
|
|
|
showTarget (target, msg) =
|
|
|
|
target ++ replicate (space - length target) ' ' ++ msg
|
|
|
|
|
|
|
|
-- |Target for a specific ghc version
|
|
|
|
hieTarget :: String -> (String, String)
|
|
|
|
hieTarget version =
|
|
|
|
("hie-" ++ version, "Builds hie for GHC version " ++ version ++ " only")
|
|
|
|
|
|
|
|
-- All targets with their respective help message.
|
|
|
|
targets =
|
|
|
|
[ ( "build"
|
|
|
|
, "Builds hie for all supported GHC versions (8.2.1, 8.2.2, 8.4.2, 8.4.3, 8.4.4, 8.6.1, 8.6.2 and 8.6.3)"
|
|
|
|
)
|
|
|
|
, ( "build-all"
|
|
|
|
, "Builds hie and hoogle databases for all supported GHC versions"
|
|
|
|
)
|
|
|
|
, ("cabal", "NOTE 3: This is needed for stack only projects too")
|
|
|
|
, ( "build-docs"
|
|
|
|
, "Builds the Hoogle database for all supported GHC versions"
|
|
|
|
)
|
|
|
|
, ("test" , "Runs hie tests")
|
|
|
|
, ("icu-macos-fix", "Fixes icu related problems in MacOS")
|
|
|
|
, ("dist", "Creates a tarball containing all the hie binaries")
|
|
|
|
, ("help" , "Show help")
|
|
|
|
]
|
|
|
|
++ map hieTarget hieVersions
|
2018-12-11 17:22:18 +03:00
|
|
|
|
2018-12-12 21:33:21 +03:00
|
|
|
execStackWithYaml_ :: VersionNumber -> [String] -> Action ()
|
|
|
|
execStackWithYaml_ versionNumber args = do
|
2018-12-11 18:29:37 +03:00
|
|
|
let stackFile = "stack-" ++ versionNumber ++ ".yaml"
|
|
|
|
command_ [] "stack" (("--stack-yaml=" ++ stackFile) : args)
|
2018-12-11 17:22:18 +03:00
|
|
|
|
2018-12-12 21:33:21 +03:00
|
|
|
execStackWithYaml :: CmdResult r => VersionNumber -> [String] -> Action r
|
|
|
|
execStackWithYaml versionNumber args = do
|
|
|
|
let stackFile = "stack-" ++ versionNumber ++ ".yaml"
|
|
|
|
command [] "stack" (("--stack-yaml=" ++ stackFile) : args)
|
|
|
|
|
2018-12-11 17:22:18 +03:00
|
|
|
execStack :: CmdResult r => [String] -> Action r
|
2018-12-11 18:29:37 +03:00
|
|
|
execStack = command [] "stack"
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
execStack_ :: [String] -> Action ()
|
2018-12-11 18:29:37 +03:00
|
|
|
execStack_ = command_ [] "stack"
|
2018-12-11 17:22:18 +03:00
|
|
|
|
|
|
|
execCabal_ :: [String] -> Action ()
|
2018-12-11 17:47:21 +03:00
|
|
|
execCabal_ = command_ [] "cabal"
|
2018-12-12 21:33:21 +03:00
|
|
|
|
2018-12-13 19:15:58 +03:00
|
|
|
-- |Get the path to the GHC compiler executable linked to the local `stack.yaml`
|
|
|
|
-- Equal to the command `stack path --compiler-exe`
|
|
|
|
getGhcPath :: Action GhcPath
|
|
|
|
getGhcPath = do
|
2018-12-12 21:33:21 +03:00
|
|
|
Stdout ghc' <- execStack ["path", "--compiler-exe"]
|
2018-12-13 19:15:58 +03:00
|
|
|
return $ trim ghc'
|
|
|
|
|
|
|
|
-- |Read the local install root of the stack project specified by the VersionNumber
|
2019-01-26 02:45:09 +03:00
|
|
|
-- Returns the filepath of the local install root.
|
2018-12-13 19:15:58 +03:00
|
|
|
-- Equal to the command `stack path --local-install-root`
|
|
|
|
getLocalInstallRoot :: VersionNumber -> Action FilePath
|
|
|
|
getLocalInstallRoot hieVersion = do
|
|
|
|
Stdout localInstallRoot' <- execStackWithYaml
|
|
|
|
hieVersion
|
|
|
|
["path", "--local-install-root"]
|
|
|
|
return $ trim localInstallRoot'
|
|
|
|
|
|
|
|
-- |Get the local binary path of stack.
|
|
|
|
-- Equal to the command `stack path --local-bin`
|
2018-12-12 21:33:21 +03:00
|
|
|
getLocalBin :: Action FilePath
|
|
|
|
getLocalBin = do
|
|
|
|
Stdout stackLocalDir' <- execStack ["path", "--local-bin"]
|
2018-12-13 19:15:58 +03:00
|
|
|
return $ trim stackLocalDir'
|
|
|
|
|
|
|
|
-- |Trim the end of a string
|
|
|
|
trim :: String -> String
|
|
|
|
trim = dropWhileEnd isSpace
|