#!/usr/bin/runghc

\begin{code}
import Data.Maybe(fromMaybe)
import Distribution.PackageDescription(HookedBuildInfo,emptyHookedBuildInfo
                                      ,PackageDescription,emptyBuildInfo
                                      ,BuildInfo(extraLibDirs,includeDirs))
import Distribution.PackageDescription.Parse(writeHookedBuildInfo)
import Distribution.Simple(defaultMainWithHooks,autoconfUserHooks
                          ,preConf,postConf)
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup(ConfigFlags(configVerbosity),Flag(Flag))
import Distribution.Verbosity(Verbosity,silent)
import System.Exit(ExitCode(ExitSuccess),exitWith)
import System.Directory(removeFile,findExecutable,doesDirectoryExist)
import System.Process(runInteractiveProcess, waitForProcess)
import System.IO(hClose, hGetContents, hPutStr, stderr)
import Control.Monad(when)
import Control.Exception(SomeException,try)

main = defaultMainWithHooks autoconfUserHooks{preConf= preConf
                                             ,postConf= postConf}
  where
    preConf ::  [String] -> ConfigFlags -> IO HookedBuildInfo
    preConf args flags = do
      try (removeFile "PostgreSQL.buildinfo")::IO (Either SomeException ())
      return emptyHookedBuildInfo
    postConf :: [String] -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
    postConf args flags _ localbuildinfo = do
      mb_bi <- pqConfigBuildInfo (configVerbosity flags)
      writeHookedBuildInfo "PostgreSQL.buildinfo" (Just (fromMaybe emptyBuildInfo mb_bi),[])

\end{code}

The following code is derived from Distribution.Simple.Configure
\begin{code}
findProgram
    :: String              -- ^ program name
    -> Maybe FilePath      -- ^ optional explicit path
    -> IO (Maybe FilePath)
findProgram name Nothing = do
  mb_path <- findExecutable name
  case mb_path of
    Nothing   -> message ("No " ++ name ++ " found")
    Just path -> message ("Using " ++ name ++ ": " ++ path)
  return mb_path
findProgram name (Just path) = do
  message ("Using " ++ name ++ ": " ++ path)
  return (Just path)

rawSystemGrabOutput :: (Flag Verbosity) -> FilePath -> [String] -> IO String
rawSystemGrabOutput verbosity path args = do
  when (verbosity /= Flag silent) $
        putStrLn (path ++ concatMap (' ':) args)
  (inp,out,err,pid) <- runInteractiveProcess path args Nothing Nothing
  exitCode <- waitForProcess pid
  if exitCode /= ExitSuccess
    then do errMsg <- hGetContents err
            hPutStr stderr errMsg
            exitWith exitCode
    else return ()
  hClose inp
  hClose err
  hGetContents out

message :: String -> IO ()
message s = putStrLn $ "configure: " ++ s
\end{code}

Populate BuildInfo using pkg-config tool.
\begin{code}
pqConfigBuildInfo:: (Flag Verbosity)-> IO (Maybe BuildInfo)
pqConfigBuildInfo verbosity = do
  mb_pq_config_path <- findProgram "pg_config" Nothing
  case mb_pq_config_path of
    Just pq_config_path -> do
       message ("configuring pq library") 
       res <- rawSystemGrabOutput verbosity pq_config_path ["--libdir"]
       let lib_dirs= words res
       res <- rawSystemGrabOutput verbosity pq_config_path ["--includedir"]
       let inc_dirs= words res
       res <- rawSystemGrabOutput verbosity pq_config_path ["--includedir-server"]
       let inc_dirs_server'= words res
       inc_dirs_server <-onlyExistingDirsOf inc_dirs_server'
       let bi= emptyBuildInfo{extraLibDirs= lib_dirs
                             ,includeDirs= inc_dirs++inc_dirs_server}
       return (Just bi)
    Nothing -> do
       message ("The package will be built using default settings for pq library")
       return Nothing

onlyExistingDirsOf:: [FilePath]-> IO [FilePath]
onlyExistingDirsOf [] = return []
onlyExistingDirsOf (dirPath:restPaths') = do
  restPaths <-onlyExistingDirsOf restPaths'
  exists <-doesDirectoryExist dirPath
  if exists then return (dirPath:restPaths) 
            else do message ("missing directory: "++dirPath)
                    return restPaths

\end{code}
