packages feed

hsinstall-3.0: src/app/HSInstall/Build.hs

module HSInstall.Build
  ( BuildTool
  , PackageName (..)
  , clean
  , determineBuildTool
  , installBinaries
  , makeCabal
  , warnAboutCabalMultiExe
  )
  where

import Data.List.NonEmpty qualified as NE
import System.Directory (getDirectoryContents)
import System.Process (callProcess)
import System.Log.Logger

import HSInstall.Except (justDoIt)
import HSInstall.Log (n)
import HSInstall.Opts (BuildMode (AppImage, Dist), ExeFile (..), ExeFiles (..))
import HSInstall.System.Process (CmdArgs, readProcessWithLogging)


newtype PackageName = PackageName String

data BuildTool = Cabal | Stack

instance Show BuildTool where
  show Cabal = "cabal"
  show Stack = "stack"


determineBuildTool :: IO BuildTool
determineBuildTool = do
  dirContents <- getDirectoryContents "."
  pure $ if "stack.yaml" `elem` dirContents
    then Stack
    else Cabal


clean :: BuildTool -> IO ()
clean Cabal = readProcessWithLogging "Clean specified" ("cabal", ["v2-clean"])
clean Stack = readProcessWithLogging "Clean specified" ("stack", ["clean"])


modeToStackArg :: BuildMode -> PackageName -> [String]
modeToStackArg (AppImage _ _ (ExeFile exeFp)) (PackageName pName) =
  [ pName <> ":" <> exeFp ]
modeToStackArg (Dist _ _ AllExes) _ = []
modeToStackArg (Dist _ _ (SpecificExes ne)) (PackageName pName) =
  NE.toList . NE.map (\(ExeFile n') -> pName <> ":" <> n') $ ne


mkInstallArgs :: BuildTool -> BuildMode -> PackageName -> FilePath -> CmdArgs

mkInstallArgs Cabal mode packageName binDir =
  ( "cabal"
  , [ "v2-install"
    , "--install-method=copy"
    , "--overwrite-policy=always"
    , "--installdir=" <> binDir
    ]
    <> modeToStackArg mode packageName
  )

mkInstallArgs Stack mode packageName binDir =
  ( "stack"
  , [ "install"
    , "--local-bin-path=" <> binDir
    ]
    <> modeToStackArg mode packageName
  )


installBinaries :: BuildTool -> BuildMode -> PackageName -> FilePath -> IO ()
installBinaries buildTool mode packageName binDir =
  readProcessWithLogging "Installing binaries"
    $ mkInstallArgs buildTool mode packageName binDir


makeCabal :: BuildTool -> IO ()
makeCabal Cabal = justDoIt $ callProcess "hpack" []
makeCabal Stack = justDoIt $ callProcess "stack" ["query"]


warnAboutCabalMultiExe :: BuildMode -> BuildTool -> IO ()
warnAboutCabalMultiExe (Dist _ _ (SpecificExes _)) Cabal =
  warningM n "cabal will currently only install all binaries, I believe it's a bug"
warnAboutCabalMultiExe _                           _     = pure ()