-- | Input the Cabal package description.
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Debian.Debianize.InputCabal
    ( inputCabalization
    ) where

import Control.Exception (bracket)
import Control.Lens (view)
import Control.Monad (when)
import Control.Monad.Trans (MonadIO, liftIO)
import Data.Set as Set (toList)
import Debian.Debianize.BasicInfo (Flags, verbosity, compilerFlavor, cabalFlagAssignments)
import Debian.Debianize.Prelude (intToVerbosity')
import Debian.GHC (getCompilerInfo)
import Debian.Orphans ()
import Distribution.Compiler (CompilerInfo)
import Distribution.Package (Package(packageId))
import Distribution.PackageDescription as Cabal (PackageDescription)
import Distribution.PackageDescription.Configuration (finalizePD)
import Distribution.PackageDescription.Parsec (readGenericPackageDescription)
import Distribution.Types.ComponentRequestedSpec (ComponentRequestedSpec(ComponentRequestedSpec))
import Distribution.Simple.Utils (defaultPackageDesc, die', setupMessage)
import Distribution.System as Cabal (buildArch, Platform(..))
import qualified Distribution.System as Cabal (buildOS)
#if MIN_VERSION_Cabal(3,2,0)
import Distribution.Types.Flag (mkFlagAssignment)
#else
import Distribution.Types.GenericPackageDescription (mkFlagAssignment)
#endif
import Distribution.Verbosity (Verbosity)
import Prelude hiding (break, lines, log, null, readFile, sum)
import System.Directory (doesFileExist, getCurrentDirectory)
import System.Exit (ExitCode(..))
import System.Posix.Files (setFileCreationMask)
import System.Process (system)

-- | Load a PackageDescription using the information in the Flags record -
-- in particular, using the dependency environment in the EnvSet, find
-- the newest available compiler of the requested compiler flavor and
-- use that information load the configured PackageDescription.
inputCabalization :: forall m. (MonadIO m) => Flags -> m (Either String PackageDescription)
inputCabalization :: forall (m :: * -> *).
MonadIO m =>
Flags -> m (Either String PackageDescription)
inputCabalization Flags
flags =
    forall (m :: * -> *).
MonadIO m =>
Flags -> m (Either String CompilerInfo)
getCompInfo Flags
flags forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left) (\CompilerInfo
cinfo -> forall a b. b -> Either a b
Right forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CompilerInfo -> m PackageDescription
doCompInfo CompilerInfo
cinfo)
    where
      doCompInfo :: CompilerInfo -> m PackageDescription
      doCompInfo :: CompilerInfo -> m PackageDescription
doCompInfo CompilerInfo
cinfo = do
        -- Load a GenericPackageDescription from the current directory
        -- and from that create a finalized PackageDescription for the
        -- given CompilerId.
        GenericPackageDescription
genPkgDesc <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Verbosity -> IO String
defaultPackageDesc Verbosity
vb forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Verbosity -> String -> IO GenericPackageDescription
readGenericPackageDescription Verbosity
vb
        let finalized :: Either [Dependency] (PackageDescription, FlagAssignment)
finalized = FlagAssignment
-> ComponentRequestedSpec
-> (Dependency -> Bool)
-> Platform
-> CompilerInfo
-> [PackageVersionConstraint]
-> GenericPackageDescription
-> Either [Dependency] (PackageDescription, FlagAssignment)
finalizePD ([(FlagName, Bool)] -> FlagAssignment
mkFlagAssignment (forall a. Set a -> [a]
toList Set (FlagName, Bool)
fs)) (Bool -> Bool -> ComponentRequestedSpec
ComponentRequestedSpec Bool
True Bool
False) (forall a b. a -> b -> a
const Bool
True) (Arch -> OS -> Platform
Platform Arch
buildArch OS
Cabal.buildOS) CompilerInfo
cinfo [] GenericPackageDescription
genPkgDesc
        Either [Dependency] PackageDescription
ePkgDesc <- forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left)
                           (\ (PackageDescription
pkgDesc, FlagAssignment
_) -> do forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (FileMode -> IO FileMode
setFileCreationMask FileMode
0o022) FileMode -> IO FileMode
setFileCreationMask forall a b. (a -> b) -> a -> b
$ \ FileMode
_ -> Verbosity -> PackageDescription -> IO ()
autoreconf Verbosity
vb PackageDescription
pkgDesc
                                                 forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. b -> Either a b
Right PackageDescription
pkgDesc))
                           Either [Dependency] (PackageDescription, FlagAssignment)
finalized
        forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\ [Dependency]
deps -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO String
getCurrentDirectory forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ String
here ->
                          forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"Missing dependencies in cabal package at " forall a. [a] -> [a] -> [a]
++ String
here forall a. [a] -> [a] -> [a]
++ String
": " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show [Dependency]
deps)
               forall (m :: * -> *) a. Monad m => a -> m a
return
               Either [Dependency] PackageDescription
ePkgDesc
      vb :: Verbosity
vb = Int -> Verbosity
intToVerbosity' forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' Flags Int
verbosity Flags
flags
      fs :: Set (FlagName, Bool)
fs = forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' Flags (Set (FlagName, Bool))
cabalFlagAssignments Flags
flags

getCompInfo :: MonadIO m => Flags -> m (Either String CompilerInfo)
getCompInfo :: forall (m :: * -> *).
MonadIO m =>
Flags -> m (Either String CompilerInfo)
getCompInfo Flags
flags =
              forall (m :: * -> *).
MonadIO m =>
CompilerFlavor -> m (Either String CompilerInfo)
getCompilerInfo (forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' Flags CompilerFlavor
compilerFlavor Flags
flags)

-- | Run the package's configuration script.
autoreconf :: Verbosity -> Cabal.PackageDescription -> IO ()
autoreconf :: Verbosity -> PackageDescription -> IO ()
autoreconf Verbosity
verbose PackageDescription
pkgDesc = do
    Bool
ac <- String -> IO Bool
doesFileExist String
"configure.ac"
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
ac forall a b. (a -> b) -> a -> b
$ do
        Bool
c <- String -> IO Bool
doesFileExist String
"configure"
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
c) forall a b. (a -> b) -> a -> b
$ do
            Verbosity -> String -> PackageIdentifier -> IO ()
setupMessage Verbosity
verbose String
"Running autoreconf" (forall pkg. Package pkg => pkg -> PackageIdentifier
packageId PackageDescription
pkgDesc)
            ExitCode
ret <- String -> IO ExitCode
system String
"autoreconf"
            case ExitCode
ret of
              ExitCode
ExitSuccess -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
              ExitFailure Int
n -> forall a. Verbosity -> String -> IO a
die' Verbosity
verbose (String
"autoreconf failed with status " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
n)