packages feed

HsOpenSSL-0.11.4.6: Setup.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}

import Distribution.Simple
import Distribution.Simple.Setup (ConfigFlags(..), toFlag)
import Distribution.Simple.LocalBuildInfo (localPkgDescr)

#if __GLASGOW_HASKELL__ >= 802
import Distribution.PackageDescription (FlagName(..), mkFlagName)
#else
import Distribution.PackageDescription (FlagName(..))
#endif

import Distribution.Verbosity (silent)
import System.Info (os)
import qualified Control.Exception as E (tryJust, throw)
import System.IO.Error (isUserError)
import Control.Monad (forM)
import Data.List

-- On macOS we're checking whether OpenSSL library is avaiable
-- and if not, we're trying to find Homebrew or MacPorts OpenSSL installations.
--
-- Method is dumb -- set homebrew-openssl or macports-openssl flag and try
-- to configure and check C libs.
--
-- If no or multiple libraries are found we display error message
-- with instructions.

main
    | os == "darwin" =
        defaultMainWithHooks simpleUserHooks { confHook = conf }
    | otherwise =
        defaultMain

flags = ["homebrew-openssl", "macports-openssl"]

conf descr cfg = do
    c <- tryConfig descr cfg
    case c of
        Right lbi -> return lbi -- library was found
        Left e
            | configConfigurationsFlags cfg
              `intersect` [(mkFlagName f, True) | f <- flags] /= [] ->
                E.throw e
                -- flag was set but library still wasn't found
            | otherwise -> do
                r <- forM flags $ \ f ->
                    fmap (f,) $ tryConfig descr $
                    setFlag (mkFlagName f) cfg { configVerbosity = toFlag silent }
                    -- TODO: configure is a long operation
                    -- while checkForeignDeps is fast.
                    -- Perhaps there is a way to configure once
                    -- and only apply flags to result and check.
                    -- However, additional `configure`s happen only on macOS
                    -- and only when library wasn't found.
                case [(f,r) | (f, Right r) <- r] of
                    [(_,lbi)] ->
                        return lbi -- library was found
                    [] ->
                        fail notFound
                    fs ->
                        fail $ multipleFound fs

notFound = unlines
    [ "Can't find OpenSSL library,"
    , "install it via 'brew install openssl' or 'port install openssl'"
    , "or use --extra-include-dirs= and --extra-lib-dirs="
    , "to specify location of installed OpenSSL library."
    ]

multipleFound fs = unlines
    [ "Multiple OpenSSL libraries were found,"
    , "use " ++ intercalate " or " ["'-f " ++ f ++ "'" | (f,_) <- fs]
    , "to specify location of installed OpenSSL library."
    ]

setFlag f c = c { configConfigurationsFlags = go (configConfigurationsFlags c) }
    where go [] = []
          go (x@(n, _):xs)
              | n == f = (f, True) : xs
              | otherwise = x : go xs

tryConfig descr flags = do
    lbi <- confHook simpleUserHooks descr flags
    -- confHook simpleUserHooks == Distribution.Simple.Configure.configure

    -- Testing whether C lib and header dependencies are working.
    -- We check exceptions only here, to check C libs errors but not other
    -- configuration problems like not resolved .cabal dependencies.
    E.tryJust ue $ do
        postConf simpleUserHooks [] flags (localPkgDescr lbi) lbi
        -- postConf simpleUserHooks ~==
        --   Distribution.Simple.Configure.checkForeignDeps

        return lbi

    where ue e | isUserError e = Just e
               | otherwise = Nothing

#if __GLASGOW_HASKELL__ < 802
mkFlagName = FlagName
#endif