|
| 1 | +#!/usr/bin/env stack |
| 2 | +{- stack |
| 3 | + --stack-yaml=shake.yaml |
| 4 | + --install-ghc runghc |
| 5 | + --package shake |
| 6 | + --package tar |
| 7 | + --package zlib |
| 8 | +-} |
| 9 | + |
| 10 | +import qualified Data.ByteString.Lazy as BS |
| 11 | +import qualified Codec.Archive.Tar as Tar |
| 12 | +import qualified Codec.Compression.GZip as GZip |
| 13 | + |
| 14 | +import Development.Shake |
| 15 | +import Development.Shake.Command |
| 16 | +import Development.Shake.FilePath |
| 17 | +import Control.Monad |
| 18 | +import System.Environment ( unsetEnv ) |
| 19 | +import System.Info ( os |
| 20 | + , arch |
| 21 | + ) |
| 22 | + |
| 23 | +import Data.List ( dropWhileEnd ) |
| 24 | +import Data.Char ( isSpace ) |
| 25 | + |
| 26 | +type VersionNumber = String |
| 27 | +type GhcPath = String |
| 28 | + |
| 29 | +-- |Defines all different hie versions that are buildable. |
| 30 | +-- If they are edited, |
| 31 | +hieVersions :: [VersionNumber] |
| 32 | +hieVersions = ["8.2.2", "8.4.3", "8.4.4", "8.6.1", "8.6.2", "8.6.3"] |
| 33 | + |
| 34 | +-- |Most recent version of hie. |
| 35 | +-- Important for `dist`, the `hie-wrapper` of the most recent hie |
| 36 | +-- will be copied to the tar-archive. |
| 37 | +mostRecentHieVersion :: VersionNumber |
| 38 | +mostRecentHieVersion = last hieVersions |
| 39 | + |
| 40 | +main :: IO () |
| 41 | +main = do |
| 42 | + -- unset GHC_PACKAGE_PATH for cabal |
| 43 | + unsetEnv "GHC_PACKAGE_PATH" |
| 44 | + shakeArgs shakeOptions { shakeFiles = "_build" } $ do |
| 45 | + want ["help"] |
| 46 | + phony "ghc" $ do |
| 47 | + ghc <- getGhcPath |
| 48 | + command_ [] ghc ["--version"] |
| 49 | + liftIO $ putStrLn "GHC" |
| 50 | + phony "submodules" updateSubmodules |
| 51 | + phony "cabal" (getGhcPath >>= installCabal) |
| 52 | + phony "all" helpMessage |
| 53 | + phony "help" helpMessage |
| 54 | + phony "build" (need (reverse $ map ("hie-" ++) hieVersions)) |
| 55 | + phony "build-all" (need ["build"] >> need ["build-docs"]) |
| 56 | + phony "dist" buildDist |
| 57 | + phony "build-docs" (need (reverse $ map ("build-doc-hie-" ++) hieVersions)) |
| 58 | + phony "test" (forM_ hieVersions test) |
| 59 | + phony "build-copy-compiler-tool" $ forM_ hieVersions buildCopyCompilerTool |
| 60 | + |
| 61 | + forM_ |
| 62 | + hieVersions |
| 63 | + (\version -> phony ("build-doc-hie-" ++ version) $ do |
| 64 | + buildDoc version |
| 65 | + ) |
| 66 | + |
| 67 | + forM_ |
| 68 | + hieVersions |
| 69 | + (\version -> phony ("hie-" ++ version) $ do |
| 70 | + need ["submodules"] |
| 71 | + need ["cabal"] |
| 72 | + buildHie version |
| 73 | + installHie version |
| 74 | + ) |
| 75 | + |
| 76 | + phony "icu-macos-fix" |
| 77 | + (need ["icu-macos-fix-install"] >> need ["icu-macos-fix-build"]) |
| 78 | + phony "icu-macos-fix-install" (command_ [] "brew" ["install", "icu4c"]) |
| 79 | + phony "icu-macos-fix-build" $ mapM_ buildIcuMacosFix hieVersions |
| 80 | + |
| 81 | +-- |Creates a compressed tar-archive consisting of all hie versions and `hie-wrapper`. |
| 82 | +-- Creates a temporary folder, copies all hie versions to it and compresses it in the end. |
| 83 | +buildDist :: Action () |
| 84 | +buildDist = do |
| 85 | + -- Create the name of the resulting tar file. |
| 86 | + Stdout gitRef' <- command [] "git" ["describe", "--tags"] |
| 87 | + let gitRef = trim gitRef' |
| 88 | + let hieDistName = concat ["hie-", gitRef, "-", arch, "-", os] |
| 89 | + -- define name constants for later use |
| 90 | + let hieWrapper = "hie-wrapper" <.> exe |
| 91 | + let hie = "hie" <.> exe |
| 92 | + let mkHie version = "hie-" ++ version <.> exe |
| 93 | + |
| 94 | + withTempDir |
| 95 | + (\temporaryDir -> do |
| 96 | + forM_ hieVersions $ \hieVersion -> do |
| 97 | + buildHie hieVersion |
| 98 | + -- after building `hie` copy it to the temporary folder |
| 99 | + localInstallRoot <- getLocalInstallRoot hieVersion |
| 100 | + copyFile' (localInstallRoot </> "bin" </> hie) |
| 101 | + (temporaryDir </> mkHie hieVersion) |
| 102 | + |
| 103 | + -- if the most recent hie-* version is copied, |
| 104 | + -- copy it again as the default hie version |
| 105 | + -- Also, add its hie-wrapper to the tar archive |
| 106 | + when (hieVersion == mostRecentHieVersion) $ do |
| 107 | + copyFile' (localInstallRoot </> "bin" </> hieWrapper) |
| 108 | + (temporaryDir </> hieWrapper) |
| 109 | + copyFile' (localInstallRoot </> "bin" </> hie) (temporaryDir </> hie) |
| 110 | + |
| 111 | + -- After every hie has been built, pack them into a tar. |
| 112 | + -- Encrypt the resulting tar file with gzip |
| 113 | + liftIO |
| 114 | + $ BS.writeFile (hieDistName ++ ".tar.gz") |
| 115 | + . GZip.compress |
| 116 | + . Tar.write |
| 117 | + =<< Tar.pack temporaryDir (hieWrapper : hie : map mkHie hieVersions) |
| 118 | + ) |
| 119 | + return () |
| 120 | + |
| 121 | +buildIcuMacosFix :: VersionNumber -> Action () |
| 122 | +buildIcuMacosFix version = execStackWithYaml_ |
| 123 | + version |
| 124 | + [ "build" |
| 125 | + , "text-icu" |
| 126 | + , "--extra-lib-dirs=/usr/local/opt/icu4c/lib" |
| 127 | + , "--extra-include-dirs=/usr/local/opt/icu4c/include" |
| 128 | + ] |
| 129 | + |
| 130 | +updateSubmodules :: Action () |
| 131 | +updateSubmodules = do |
| 132 | + command_ [] "git" ["submodule", "sync"] |
| 133 | + command_ [] "git" ["submodule", "update", "--init"] |
| 134 | + |
| 135 | +installCabal :: GhcPath -> Action () |
| 136 | +installCabal ghc = do |
| 137 | + execStack_ ["install", "cabal-install"] |
| 138 | + execCabal_ ["v1-update"] |
| 139 | + execCabal_ ["v1-install", "Cabal-2.4.1.0", "--with-compiler=" ++ ghc] |
| 140 | + |
| 141 | +buildHie :: VersionNumber -> Action () |
| 142 | +buildHie versionNumber = do |
| 143 | + when (versionNumber `elem` ["hie-8.2.2", "hie-8.2.1"]) |
| 144 | + $ execStackWithYaml_ versionNumber ["install", "happy"] |
| 145 | + execStackWithYaml_ versionNumber ["build"] |
| 146 | + |
| 147 | +installHie :: VersionNumber -> Action () |
| 148 | +installHie versionNumber = do |
| 149 | + execStackWithYaml_ versionNumber ["install"] |
| 150 | + localBinDir <- getLocalBin |
| 151 | + localInstallRoot <- getLocalInstallRoot versionNumber |
| 152 | + let hie = "hie" <.> exe |
| 153 | + copyFile' (localInstallRoot </> "bin" </> hie) |
| 154 | + (localBinDir </> "hie-" ++ versionNumber <.> exe) |
| 155 | + copyFile' (localInstallRoot </> "bin" </> hie) |
| 156 | + (localBinDir </> "hie-" ++ dropExtension versionNumber <.> exe) |
| 157 | + |
| 158 | +buildCopyCompilerTool :: VersionNumber -> Action () |
| 159 | +buildCopyCompilerTool versionNumber = |
| 160 | + execStackWithYaml_ versionNumber ["build", "--copy-compiler-tool"] |
| 161 | + |
| 162 | +test :: VersionNumber -> Action () |
| 163 | +test versionNumber = execStackWithYaml_ versionNumber ["test"] |
| 164 | + |
| 165 | +buildDoc :: VersionNumber -> Action () |
| 166 | +buildDoc versionNumber = do |
| 167 | + execStackWithYaml_ versionNumber ["install", "hoogle"] |
| 168 | + execStackWithYaml_ versionNumber ["exec", "hoogle", "generate"] |
| 169 | + |
| 170 | +helpMessage :: Action () |
| 171 | +helpMessage = do |
| 172 | + let out = liftIO . putStrLn |
| 173 | + out "" |
| 174 | + out "Usage:" |
| 175 | + out " stack Shakefile.hs <target>" |
| 176 | + out "" |
| 177 | + out "Targets:" |
| 178 | + out |
| 179 | + " 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)" |
| 180 | + out |
| 181 | + " build-all Builds hie and hoogle databases for all supported GHC versions" |
| 182 | + out " hie-8.2.1 Builds hie for GHC version 8.2.1 only" |
| 183 | + out " hie-8.2.2 Builds hie for GHC version 8.2.2 only" |
| 184 | + out " hie-8.4.2 Builds hie for GHC version 8.4.2 only" |
| 185 | + out " hie-8.4.3 Builds hie for GHC version 8.4.3 only" |
| 186 | + out " hie-8.4.4 Builds hie for GHC version 8.4.4 only" |
| 187 | + out " hie-8.6.1 Builds hie for GHC version 8.6.1 only" |
| 188 | + out " hie-8.6.2 Builds hie for GHC version 8.6.2 only" |
| 189 | + out " hie-8.6.3 Builds hie for GHC version 8.6.3 only" |
| 190 | + out " submodules Updates local git submodules" |
| 191 | + out |
| 192 | + " cabal NOTE 3: This is needed for stack only projects too" |
| 193 | + out |
| 194 | + " build-docs Builds the Hoogle database for all supported GHC versions" |
| 195 | + out " test Runs hie tests" |
| 196 | + out " icu-macos-fix Fixes icu related problems in MacOS" |
| 197 | + out |
| 198 | + " dist Creates a tarball containing all the hie binaries" |
| 199 | + out " help Show help" |
| 200 | + out "" |
| 201 | + |
| 202 | +execStackWithYaml_ :: VersionNumber -> [String] -> Action () |
| 203 | +execStackWithYaml_ versionNumber args = do |
| 204 | + let stackFile = "stack-" ++ versionNumber ++ ".yaml" |
| 205 | + command_ [] "stack" (("--stack-yaml=" ++ stackFile) : args) |
| 206 | + |
| 207 | +execStackWithYaml :: CmdResult r => VersionNumber -> [String] -> Action r |
| 208 | +execStackWithYaml versionNumber args = do |
| 209 | + let stackFile = "stack-" ++ versionNumber ++ ".yaml" |
| 210 | + command [] "stack" (("--stack-yaml=" ++ stackFile) : args) |
| 211 | + |
| 212 | +execStack :: CmdResult r => [String] -> Action r |
| 213 | +execStack = command [] "stack" |
| 214 | + |
| 215 | +execStack_ :: [String] -> Action () |
| 216 | +execStack_ = command_ [] "stack" |
| 217 | + |
| 218 | +execCabal_ :: [String] -> Action () |
| 219 | +execCabal_ = command_ [] "cabal" |
| 220 | + |
| 221 | +-- |Get the path to the GHC compiler executable linked to the local `stack.yaml` |
| 222 | +-- Equal to the command `stack path --compiler-exe` |
| 223 | +getGhcPath :: Action GhcPath |
| 224 | +getGhcPath = do |
| 225 | + Stdout ghc' <- execStack ["path", "--compiler-exe"] |
| 226 | + return $ trim ghc' |
| 227 | + |
| 228 | +-- |Read the local install root of the stack project specified by the VersionNumber |
| 229 | +-- Returns the filepath of the local install root. |
| 230 | +-- Equal to the command `stack path --local-install-root` |
| 231 | +getLocalInstallRoot :: VersionNumber -> Action FilePath |
| 232 | +getLocalInstallRoot hieVersion = do |
| 233 | + Stdout localInstallRoot' <- execStackWithYaml |
| 234 | + hieVersion |
| 235 | + ["path", "--local-install-root"] |
| 236 | + return $ trim localInstallRoot' |
| 237 | + |
| 238 | +-- |Get the local binary path of stack. |
| 239 | +-- Equal to the command `stack path --local-bin` |
| 240 | +getLocalBin :: Action FilePath |
| 241 | +getLocalBin = do |
| 242 | + Stdout stackLocalDir' <- execStack ["path", "--local-bin"] |
| 243 | + return $ trim stackLocalDir' |
| 244 | + |
| 245 | +-- |Trim the end of a string |
| 246 | +trim :: String -> String |
| 247 | +trim = dropWhileEnd isSpace |
0 commit comments