aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xinstall.hs162
1 files changed, 162 insertions, 0 deletions
diff --git a/install.hs b/install.hs
new file mode 100755
index 0000000..d8c36c1
--- /dev/null
+++ b/install.hs
@@ -0,0 +1,162 @@
+#!/usr/bin/env stack
+{- stack script
+ --resolver lts-13.12
+ --ghc-options -Wall
+-}
+
+-- = About
+--
+-- Install multiple versions of haskell-code-indexer, each with the version of
+-- GHC it was built with appended to the executable name.
+--
+-- = Original
+--
+-- Modified from the BSD3 licensed script at:
+-- https://github.com/haskell/haskell-ide-engine/blob/ec5e34ca52d389b713df918f02ff63920aede4be/install.hs
+--
+-- Thanks haskell-ide-engine folks!
+--
+-- = Changes from the original
+--
+-- + Switched from Shake to IO script
+-- + Added optparse-applicative
+-- + Switched to Stack only (PRs welcome to support other tools)
+module Main (main) where
+
+import Control.Monad
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as LBS
+import Data.Char (isSpace)
+import Data.Foldable
+import Data.List (dropWhileEnd)
+import qualified Data.Text as T
+import Data.Text.Encoding
+import Development.Shake.FilePath
+import Options.Applicative
+import System.Directory (copyFile, removeFile)
+import System.Process.Typed
+
+-- | Keep this in sync with the stack.yamls at the top level of the project.
+supportedGhcVersions :: [Version]
+supportedGhcVersions =
+ map Version ["8.0.2", "8.2.2", "8.4.3", "8.4.4", "8.6.3"]
+
+newtype Version = Version { unVersion :: String } deriving Eq
+
+-- * CLI args
+
+data Args = Args
+ { argBuildVersions :: [Version]
+ , argBuildServer :: Bool
+ }
+
+cliArgs :: IO Args
+cliArgs =
+ customExecParser (prefs showHelpOnError) argsParser
+
+argsParser :: ParserInfo Args
+argsParser =
+ fmap defaultToAll $
+ info (helper <*> parser) (fullDesc <> progDesc desc)
+ where
+ parser :: Parser Args
+ parser =
+ Args
+ <$> (some indexVersion <|> pure mempty)
+ <*> switch
+ ( long "server"
+ <> help "Build haskell-code-server"
+ )
+
+ indexVersion :: Parser Version
+ indexVersion =
+ argument (eitherReader checkVersion)
+ ( metavar "INDEX_VERSION"
+ <> help "haskell-code-indexer-X-Y-Z version to build"
+ )
+
+ checkVersion :: String -> Either String Version
+ checkVersion s =
+ case find ((==) (Version s)) supportedGhcVersions of
+ Nothing ->
+ Left . unwords $
+ "Not a supported GHC version. Currently supported versions are:"
+ : map unVersion supportedGhcVersions
+
+ Just v ->
+ Right v
+
+ defaultToAll :: Args -> Args
+ defaultToAll args =
+ if argBuildVersions args == mempty && argBuildServer args == False
+ then Args (reverse supportedGhcVersions) True -- reverse to build latest first
+ else args
+
+ desc :: String
+ desc =
+ "Install haskell-code-indexer executables with the GHC version they were"
+ <> " compiled with appended to their name. Builds everything if you don't"
+ <> " specify options. Not that if you already have an indexer executable"
+ <> " without the GHC version appended in your Stack's local bin"
+ <> " it will be deleted."
+
+-- * Build
+
+main :: IO ()
+main =
+ run =<< cliArgs
+
+run :: Args -> IO ()
+run args = do
+ putStrLn (startupNotice args)
+ when (argBuildServer args) buildServer
+ for_ (argBuildVersions args) buildVersion
+
+startupNotice :: Args -> String
+startupNotice args =
+ unlines
+ $ "Building:"
+ : (if argBuildServer args
+ then [" + haskell-code-explorer"]
+ else mempty)
+ <> map versionEntry (argBuildVersions args)
+ where
+ versionEntry :: Version -> String
+ versionEntry v =
+ " + haskell-code-indexer-" <> unVersion v
+
+buildServer :: IO ()
+buildServer =
+ void $ execStack ["build", "--copy-bins", "haskell-code-explorer:haskell-code-server"]
+
+buildVersion :: Version -> IO ()
+buildVersion v = do
+ execStackWithVersion_ v ["build", "--copy-bins", "haskell-code-explorer:haskell-code-indexer"]
+ localBinDir <- getLocalBin
+
+ let
+ -- exe is "exe" on Windows and "" otherwise
+ fromFile = localBinDir </> "haskell-code-indexer" <.> exe
+ toFile = localBinDir </> "haskell-code-indexer-" ++ unVersion v <.> exe
+
+ copyFile fromFile toFile
+ removeFile fromFile
+
+-- | E.g. @"/home/user/bin"@.
+getLocalBin :: IO FilePath
+getLocalBin = do
+ stackLocalDir' <- decodeUtf8 <$> execStack ["path", "--stack-yaml=stack.yaml", "--local-bin"]
+ pure $ trimEnd (T.unpack stackLocalDir')
+
+-- | Uses the stack.yaml for the given @Version@.
+execStackWithVersion_ :: Version -> [String] -> IO ()
+execStackWithVersion_ v args = do
+ let stackFile = "stack-" ++ unVersion v ++ ".yaml"
+ void $ execStack (("--stack-yaml=" ++ stackFile) : args)
+
+execStack :: [String] -> IO ByteString
+execStack =
+ fmap LBS.toStrict . readProcessStdout_ . proc "stack"
+
+trimEnd :: String -> String
+trimEnd = dropWhileEnd isSpace