{-# LANGUAGE LambdaCase #-}
module Cabal (externalCommand) where

import           Imports

import           Data.List
import           Data.Version (makeVersion)
import           System.IO
import           System.IO.Temp
import           System.Environment
import           System.Directory
import           System.FilePath
import           System.Process

import qualified Info
import           Cabal.Paths
import           Cabal.Options

externalCommand :: [String] -> IO ()
externalCommand args = do
  lookupEnv "CABAL" >>= \ case
    Nothing -> run "cabal" args
    Just cabal -> run cabal (drop 1 args)

run :: String -> [String] -> IO ()
run cabal args = do
  rejectUnsupportedOptions args

  Paths{..} <- paths cabal (discardReplOptions args)

  let
    doctest = cache </> "doctest" <> "-" <> Info.version
    script = cache </> "init-ghci-" <> Info.version

  doesFileExist doctest >>= \ case
    True -> pass
    False -> callProcess cabal [
        "install" , "doctest-" <> Info.version
      , "--flag", "-cabal-doctest"
      , "--ignore-project"
      , "--installdir", cache
      , "--program-suffix", "-" <> Info.version
      , "--install-method=copy"
      , "--with-compiler", ghc
      ]

  doesFileExist script >>= \ case
    True -> pass
    False -> writeFileAtomically script ":seti -w -Wdefault"

  callProcess doctest ["--version"]

  let
    repl extraArgs = call cabal ("repl"
      : "--build-depends=QuickCheck"
      : "--build-depends=template-haskell"
      : ("--repl-options=-ghci-script=" <> script)
      : args ++ extraArgs)

  case ghcVersion < makeVersion [9,4] of
    True -> do
      callProcess cabal ("build" : "--only-dependencies" : discardReplOptions args)
      repl ["--with-compiler", doctest, "--with-hc-pkg", ghcPkg]

    False -> do
      withSystemTempDirectory "cabal-doctest" $ \ dir -> do
        repl ["--keep-temp-files", "--repl-multi-file", dir]
        files <- filter (isSuffixOf "-inplace") <$> listDirectory dir
        options <- concat <$> mapM (fmap lines . readFile . combine dir) files
        call doctest ("--no-magic" : options)

writeFileAtomically :: FilePath -> String -> IO ()
writeFileAtomically name contents = do
  (tmp, h) <- openTempFile (takeDirectory name) (takeFileName name)
  hPutStr h contents
  hClose h
  renameFile tmp name
