{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}

-----------------------------------------------------------------------------

--                      copy :
--                              $(MAKE) install prefix=$(destdir)/$(prefix) \
--                                              bindir=$(destdir)/$(bindir) \

-- |
-- Module      :  Distribution.Make
-- Copyright   :  Martin Sj&#xF6;gren 2004
-- License     :  BSD3
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- This is an alternative build system that delegates everything to the @make@
-- program. All the commands just end up calling @make@ with appropriate
-- arguments. The intention was to allow preexisting packages that used
-- makefiles to be wrapped into Cabal packages. In practice essentially all
-- such packages were converted over to the \"Simple\" build system instead.
-- Consequently this module is not used much and it certainly only sees cursory
-- maintenance and no testing. Perhaps at some point we should stop pretending
-- that it works.
--
-- Uses the parsed command-line from "Distribution.Simple.Setup" in order to build
-- Haskell tools using a back-end build system based on make. Obviously we
-- assume that there is a configure script, and that after the ConfigCmd has
-- been run, there is a Makefile. Further assumptions:
--
-- [ConfigCmd] We assume the configure script accepts
--              @--with-hc@,
--              @--with-hc-pkg@,
--              @--prefix@,
--              @--bindir@,
--              @--libdir@,
--              @--libexecdir@,
--              @--datadir@.
--
-- [BuildCmd] We assume that the default Makefile target will build everything.
--
-- [InstallCmd] We assume there is an @install@ target. Note that we assume that
-- this does *not* register the package!
--
-- [CopyCmd]    We assume there is a @copy@ target, and a variable @$(destdir)@.
--              The @copy@ target should probably just invoke @make install@
--              recursively (e.g. @$(MAKE) install prefix=$(destdir)\/$(prefix)
--              bindir=$(destdir)\/$(bindir)@. The reason we can\'t invoke @make
--              install@ directly here is that we don\'t know the value of @$(prefix)@.
--
-- [SDistCmd] We assume there is a @dist@ target.
--
-- [RegisterCmd] We assume there is a @register@ target and a variable @$(user)@.
--
-- [UnregisterCmd] We assume there is an @unregister@ target.
--
-- [HaddockCmd] We assume there is a @docs@ or @doc@ target.
module Distribution.Make
  ( module Distribution.Package
  , License (..)
  , Version
  , defaultMain
  , defaultMainArgs
  ) where

import Distribution.Compat.Prelude
import Prelude ()

-- local
import Distribution.License
import Distribution.Package
import Distribution.Pretty
import Distribution.Simple.Command
import Distribution.Simple.Program
import Distribution.Simple.Setup
import Distribution.Simple.Utils
import Distribution.Version

import System.Environment (getArgs, getProgName)

defaultMain :: IO ()
defaultMain = getArgs >>= defaultMainArgs

defaultMainArgs :: [String] -> IO ()
defaultMainArgs = defaultMainHelper

defaultMainHelper :: [String] -> IO ()
defaultMainHelper args = do
  command <- commandsRun (globalCommand commands) commands args
  case command of
    CommandHelp help -> printHelp help
    CommandList opts -> printOptionsList opts
    CommandErrors errs -> printErrors errs
    CommandReadyToGo (flags, commandParse) ->
      case commandParse of
        _
          | fromFlag (globalVersion flags) -> printVersion
          | fromFlag (globalNumericVersion flags) -> printNumericVersion
        CommandHelp help -> printHelp help
        CommandList opts -> printOptionsList opts
        CommandErrors errs -> printErrors errs
        CommandReadyToGo action -> action
  where
    printHelp help = getProgName >>= putStr . help
    printOptionsList = putStr . unlines
    printErrors errs = do
      putStr (intercalate "\n" errs)
      exitWith (ExitFailure 1)
    printNumericVersion = putStrLn $ prettyShow cabalVersion
    printVersion =
      putStrLn $
        "Cabal library version "
          ++ prettyShow cabalVersion
    progs = defaultProgramDb
    commands =
      [ configureCommand progs `commandAddAction` configureAction
      , buildCommand progs `commandAddAction` buildAction
      , installCommand `commandAddAction` installAction
      , copyCommand `commandAddAction` copyAction
      , haddockCommand `commandAddAction` haddockAction
      , cleanCommand `commandAddAction` cleanAction
      , sdistCommand `commandAddAction` sdistAction
      , registerCommand `commandAddAction` registerAction
      , unregisterCommand `commandAddAction` unregisterAction
      ]

configureAction :: ConfigFlags -> [String] -> IO ()
configureAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ configVerbosity flags
      mbWorkDir = flagToMaybe $ configWorkingDir flags
  rawSystemExit verbosity mbWorkDir "sh" $
    "configure"
      : configureArgs backwardsCompatHack flags
  where
    backwardsCompatHack = True

copyAction :: CopyFlags -> [String] -> IO ()
copyAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ copyVerbosity flags
      mbWorkDir = flagToMaybe $ copyWorkingDir flags
      destArgs = case fromFlag $ copyDest flags of
        NoCopyDest -> ["install"]
        CopyTo path -> ["copy", "destdir=" ++ path]
        CopyToDb _ -> error "CopyToDb not supported via Make"

  rawSystemExit verbosity mbWorkDir "make" destArgs

installAction :: InstallFlags -> [String] -> IO ()
installAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ installVerbosity flags
      mbWorkDir = flagToMaybe $ installWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" ["install"]
  rawSystemExit verbosity mbWorkDir "make" ["register"]

haddockAction :: HaddockFlags -> [String] -> IO ()
haddockAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ haddockVerbosity flags
      mbWorkDir = flagToMaybe $ haddockWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" ["docs"]
    `catchIO` \_ ->
      rawSystemExit verbosity mbWorkDir "make" ["doc"]

buildAction :: BuildFlags -> [String] -> IO ()
buildAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ buildVerbosity flags
      mbWorkDir = flagToMaybe $ buildWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" []

cleanAction :: CleanFlags -> [String] -> IO ()
cleanAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ cleanVerbosity flags
      mbWorkDir = flagToMaybe $ cleanWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" ["clean"]

sdistAction :: SDistFlags -> [String] -> IO ()
sdistAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ sDistVerbosity flags
      mbWorkDir = flagToMaybe $ sDistWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" ["dist"]

registerAction :: RegisterFlags -> [String] -> IO ()
registerAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ registerVerbosity flags
      mbWorkDir = flagToMaybe $ registerWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" ["register"]

unregisterAction :: RegisterFlags -> [String] -> IO ()
unregisterAction flags args = do
  noExtraFlags args
  let verbosity = fromFlag $ registerVerbosity flags
      mbWorkDir = flagToMaybe $ registerWorkingDir flags
  rawSystemExit verbosity mbWorkDir "make" ["unregister"]
