packages feed

emgm-0.3: Setup.lhs

#! /usr/bin/env runhaskell

\begin{code}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS -Wall #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Setup
-- Copyright   :  (c) 2008, 2009 Universiteit Utrecht
-- License     :  BSD3
--
-- Maintainer  :  generics@haskell.org
-----------------------------------------------------------------------------

module Main (main) where

import System.Cmd
  ( system
  )

import System.FilePath
  ( (</>)
  )

import Data.Version
  ( Version(..)
  )

import Distribution.Simple
  ( defaultMainWithHooks
  , simpleUserHooks
  , UserHooks(runTests, haddockHook, buildHook)
  , Args
  )

import Distribution.Simple.LocalBuildInfo
  ( LocalBuildInfo(..)
  )

import Distribution.Simple.Program
  ( userSpecifyArgs
  )

import Distribution.Simple.Setup
  ( HaddockFlags
  , BuildFlags
  )

import Distribution.Package

import Distribution.PackageDescription
  ( PackageDescription(..)
  , BuildInfo(..)
  , Library(..)
  , Executable(..)
  )

main :: IO ()
main = defaultMainWithHooks hooks
  where
    hooks = simpleUserHooks
            { runTests    = runTests'
            , haddockHook = haddockHook'
            , buildHook   = buildHook'
            }

-- Run a 'test' binary that gets built when configured with '-ftest'.
runTests' :: Args -> Bool -> PackageDescription -> LocalBuildInfo -> IO ()
runTests' _ _ _ _ = system cmd >> return ()
  where testdir = "dist" </> "build" </> "test"
        testcmd = "." </> "test"
        cmd = "cd " ++ testdir ++ " && " ++ testcmd

-- Define __HADDOCK__ for CPP when running haddock. This is a workaround for
-- Haddock not building the documentation due to some issue with Template
-- Haskell.
haddockHook' :: PackageDescription -> LocalBuildInfo -> UserHooks -> HaddockFlags -> IO ()
haddockHook' pkg lbi =
  haddockHook simpleUserHooks pkg (lbi { withPrograms = p })
  where
    p = userSpecifyArgs "haddock" ["--optghc=-D__HADDOCK__"] (withPrograms lbi)

-- Insert CPP flag for building with template-haskell versions >= 2.3. This was
-- previously done in the .cabal file, but it was not backwards compatible with
-- Cabal 1.2. This should work with Cabal from 1.2 to 1.6 at least.
buildHook' :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
buildHook' pkg lbi hooks flags = do
  buildHook simpleUserHooks pkg (lbi { localPkgDescr = newPkgDescr }) hooks flags
  where

    -- Old local package description
    oldPkgDescr = localPkgDescr lbi

    -- New local package description
    newPkgDescr =
      case thVersion of
        Nothing      ->
          oldPkgDescr
        Just version ->
          if version >= Version [2,3] []
          then
            oldPkgDescr
              { library = addThCppToLibrary (library oldPkgDescr)
              , executables = map addThCppToExec (executables oldPkgDescr)
              }
          else
            oldPkgDescr

    -- Template Haskell package name
    thPackageName = mkPackageName "template-haskell"

    mkPackageName :: (Read a) => String -> a
    mkPackageName nm =
      fst $ head $ reads shownNm ++ reads ("PackageName " ++ shownNm)
      where
        shownNm = show nm

    -- template-haskell version
    thVersion = findThVersion (packageDeps lbi)

    -- CPP options for template-haskell >= 2.3
    thCppOpt = "-DTH_LOC_DERIVEREP"

    -- Find the version of the template-haskell package
    findThVersion []          = Nothing
    findThVersion (PackageIdentifier name version:ps)
      | name == thPackageName = Just version
      | otherwise             = findThVersion ps

    -- Add the template-haskell CPP flag to a BuildInfo
    addThCppToBuildInfo :: BuildInfo -> BuildInfo
    addThCppToBuildInfo bi =
      bi { cppOptions = thCppOpt : cppOptions bi }

    -- Add the template-haskell CPP flag to a library package description
    addThCppToLibrary :: Maybe Library -> Maybe Library
    addThCppToLibrary ml = do
      lib <- ml
      return (lib { libBuildInfo = addThCppToBuildInfo (libBuildInfo lib) })

    -- Add the template-haskell CPP flag to an executable package description
    addThCppToExec :: Executable -> Executable
    addThCppToExec exec =
      exec { buildInfo = addThCppToBuildInfo (buildInfo exec) }

\end{code}