{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}

module Ormolu.Utils.Cabal
  ( CabalInfo (..),
    defaultCabalInfo,
    PackageName,
    unPackageName,
    Extension (..),
    getCabalInfoForSourceFile,
    findCabalFile,
    parseCabalInfo,
  )
where

import Control.Exception
import Control.Monad.IO.Class
import qualified Data.ByteString as B
import Data.Map.Lazy (Map)
import qualified Data.Map.Lazy as M
import Data.Maybe (maybeToList)
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Distribution.ModuleName as ModuleName
import Distribution.PackageDescription
import Distribution.PackageDescription.Parsec
import qualified Distribution.Types.CondTree as CT
import Distribution.Utils.Path (getSymbolicPath)
import Language.Haskell.Extension
import Ormolu.Config
import Ormolu.Exception
import System.Directory
import System.FilePath
import System.IO (hPutStrLn, stderr)
import System.IO.Error (isDoesNotExistError)

-- | Cabal information of interest to Ormolu.
data CabalInfo = CabalInfo
  { -- | Package name
    CabalInfo -> Maybe String
ciPackageName :: !(Maybe String),
    -- | Extension and language settings in the form of 'DynOption's
    CabalInfo -> [DynOption]
ciDynOpts :: ![DynOption],
    -- | Direct dependencies
    CabalInfo -> Set String
ciDependencies :: !(Set String),
    -- | Absolute path to the cabal file, if it was found
    CabalInfo -> Maybe String
ciCabalFilePath :: !(Maybe FilePath)
  }
  deriving (CabalInfo -> CabalInfo -> Bool
(CabalInfo -> CabalInfo -> Bool)
-> (CabalInfo -> CabalInfo -> Bool) -> Eq CabalInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CabalInfo -> CabalInfo -> Bool
$c/= :: CabalInfo -> CabalInfo -> Bool
== :: CabalInfo -> CabalInfo -> Bool
$c== :: CabalInfo -> CabalInfo -> Bool
Eq, Int -> CabalInfo -> ShowS
[CabalInfo] -> ShowS
CabalInfo -> String
(Int -> CabalInfo -> ShowS)
-> (CabalInfo -> String)
-> ([CabalInfo] -> ShowS)
-> Show CabalInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CabalInfo] -> ShowS
$cshowList :: [CabalInfo] -> ShowS
show :: CabalInfo -> String
$cshow :: CabalInfo -> String
showsPrec :: Int -> CabalInfo -> ShowS
$cshowsPrec :: Int -> CabalInfo -> ShowS
Show)

-- | Cabal info that is used by default when no .cabal file can be found.
defaultCabalInfo :: CabalInfo
defaultCabalInfo :: CabalInfo
defaultCabalInfo =
  CabalInfo :: Maybe String
-> [DynOption] -> Set String -> Maybe String -> CabalInfo
CabalInfo
    { ciPackageName :: Maybe String
ciPackageName = Maybe String
forall a. Maybe a
Nothing,
      ciDynOpts :: [DynOption]
ciDynOpts = [],
      ciDependencies :: Set String
ciDependencies = Set String
forall a. Set a
Set.empty,
      ciCabalFilePath :: Maybe String
ciCabalFilePath = Maybe String
forall a. Maybe a
Nothing
    }

-- | Locate .cabal file corresponding to the given Haskell source file and
-- obtain 'CabalInfo' from it.
getCabalInfoForSourceFile ::
  MonadIO m =>
  -- | Haskell source file
  FilePath ->
  -- | Extracted cabal info
  m CabalInfo
getCabalInfoForSourceFile :: String -> m CabalInfo
getCabalInfoForSourceFile String
sourceFile = IO CabalInfo -> m CabalInfo
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO CabalInfo -> m CabalInfo) -> IO CabalInfo -> m CabalInfo
forall a b. (a -> b) -> a -> b
$ do
  String -> IO (Maybe String)
forall (m :: * -> *). MonadIO m => String -> m (Maybe String)
findCabalFile String
sourceFile IO (Maybe String) -> (Maybe String -> IO CabalInfo) -> IO CabalInfo
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Just String
cabalFile -> String -> String -> IO CabalInfo
forall (m :: * -> *). MonadIO m => String -> String -> m CabalInfo
parseCabalInfo String
cabalFile String
sourceFile
    Maybe String
Nothing -> do
      Handle -> String -> IO ()
hPutStrLn Handle
stderr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Could not find a .cabal file for " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
sourceFile
      CabalInfo -> IO CabalInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CabalInfo
defaultCabalInfo

-- | Find the path to an appropriate .cabal file for a Haskell source file,
-- if available.
findCabalFile ::
  MonadIO m =>
  -- | Path to a Haskell source file in a project with a .cabal file
  FilePath ->
  -- | Absolute path to the .cabal file if available
  m (Maybe FilePath)
findCabalFile :: String -> m (Maybe String)
findCabalFile String
sourceFile = IO (Maybe String) -> m (Maybe String)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe String) -> m (Maybe String))
-> IO (Maybe String) -> m (Maybe String)
forall a b. (a -> b) -> a -> b
$ do
  String
parentDir <- ShowS
takeDirectory ShowS -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO String
makeAbsolute String
sourceFile
  [String]
dirEntries <-
    String -> IO [String]
listDirectory String
parentDir IO [String] -> (IOError -> IO [String]) -> IO [String]
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \case
      (IOError -> Bool
isDoesNotExistError -> Bool
True) -> [String] -> IO [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
      IOError
e -> IOError -> IO [String]
forall e a. Exception e => e -> IO a
throwIO IOError
e
  let findDotCabal :: [String] -> IO (Maybe String)
findDotCabal = \case
        [] -> Maybe String -> IO (Maybe String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing
        String
e : [String]
es
          | ShowS
takeExtension String
e String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
".cabal" ->
              String -> IO Bool
doesFileExist (String
parentDir String -> ShowS
</> String
e) IO Bool -> (Bool -> IO (Maybe String)) -> IO (Maybe String)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                Bool
True -> Maybe String -> IO (Maybe String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> IO (Maybe String))
-> Maybe String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall a. a -> Maybe a
Just String
e
                Bool
False -> [String] -> IO (Maybe String)
findDotCabal [String]
es
        String
_ : [String]
es -> [String] -> IO (Maybe String)
findDotCabal [String]
es
  [String] -> IO (Maybe String)
findDotCabal [String]
dirEntries IO (Maybe String)
-> (Maybe String -> IO (Maybe String)) -> IO (Maybe String)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Just String
cabalFile -> Maybe String -> IO (Maybe String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> IO (Maybe String))
-> (String -> Maybe String) -> String -> IO (Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String
forall a. a -> Maybe a
Just (String -> IO (Maybe String)) -> String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ String
parentDir String -> ShowS
</> String
cabalFile
    Maybe String
Nothing ->
      if String -> Bool
isDrive String
parentDir
        then Maybe String -> IO (Maybe String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing
        else String -> IO (Maybe String)
forall (m :: * -> *). MonadIO m => String -> m (Maybe String)
findCabalFile String
parentDir

-- | Parse 'CabalInfo' from a .cabal file at the given 'FilePath'.
parseCabalInfo ::
  MonadIO m =>
  -- | Location of the .cabal file
  FilePath ->
  -- | Location of the source file we are formatting
  FilePath ->
  -- | Extracted cabal info
  m CabalInfo
parseCabalInfo :: String -> String -> m CabalInfo
parseCabalInfo String
cabalFileAsGiven String
sourceFileAsGiven = IO CabalInfo -> m CabalInfo
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO CabalInfo -> m CabalInfo) -> IO CabalInfo -> m CabalInfo
forall a b. (a -> b) -> a -> b
$ do
  String
cabalFile <- String -> IO String
makeAbsolute String
cabalFileAsGiven
  String
sourceFileAbs <- String -> IO String
makeAbsolute String
sourceFileAsGiven
  ByteString
cabalFileBs <- String -> IO ByteString
B.readFile String
cabalFile
  GenericPackageDescription
genericPackageDescription <-
    case ByteString -> Maybe GenericPackageDescription
parseGenericPackageDescriptionMaybe ByteString
cabalFileBs of
      Just GenericPackageDescription
gpd -> GenericPackageDescription -> IO GenericPackageDescription
forall (f :: * -> *) a. Applicative f => a -> f a
pure GenericPackageDescription
gpd
      Maybe GenericPackageDescription
Nothing -> OrmoluException -> IO GenericPackageDescription
forall e a. Exception e => e -> IO a
throwIO (String -> OrmoluException
OrmoluCabalFileParsingFailed String
cabalFile)
  ([DynOption]
dynOpts, [String]
dependencies) <- do
    let extMap :: Map String ([DynOption], [String])
extMap = String
-> GenericPackageDescription -> Map String ([DynOption], [String])
getExtensionAndDepsMap String
cabalFile GenericPackageDescription
genericPackageDescription
    case String
-> Map String ([DynOption], [String])
-> Maybe ([DynOption], [String])
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (ShowS
dropExtensions String
sourceFileAbs) Map String ([DynOption], [String])
extMap of
      Just ([DynOption], [String])
exts -> ([DynOption], [String]) -> IO ([DynOption], [String])
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([DynOption], [String])
exts
      Maybe ([DynOption], [String])
Nothing -> do
        String
relativeCabalFile <- String -> IO String
makeRelativeToCurrentDirectory String
cabalFile
        Handle -> String -> IO ()
hPutStrLn Handle
stderr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
          String
"Found .cabal file "
            String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
relativeCabalFile
            String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", but it did not mention "
            String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
sourceFileAsGiven
        ([DynOption], [String]) -> IO ([DynOption], [String])
forall (m :: * -> *) a. Monad m => a -> m a
return ([], [])
  let pdesc :: PackageDescription
pdesc = GenericPackageDescription -> PackageDescription
packageDescription GenericPackageDescription
genericPackageDescription
      packageName :: String
packageName = (PackageName -> String
unPackageName (PackageName -> String)
-> (PackageDescription -> PackageName)
-> PackageDescription
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageIdentifier -> PackageName
pkgName (PackageIdentifier -> PackageName)
-> (PackageDescription -> PackageIdentifier)
-> PackageDescription
-> PackageName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageDescription -> PackageIdentifier
package) PackageDescription
pdesc
  CabalInfo -> IO CabalInfo
forall (m :: * -> *) a. Monad m => a -> m a
return
    CabalInfo :: Maybe String
-> [DynOption] -> Set String -> Maybe String -> CabalInfo
CabalInfo
      { ciPackageName :: Maybe String
ciPackageName = String -> Maybe String
forall a. a -> Maybe a
Just String
packageName,
        ciDynOpts :: [DynOption]
ciDynOpts = [DynOption]
dynOpts,
        ciDependencies :: Set String
ciDependencies = [String] -> Set String
forall a. Ord a => [a] -> Set a
Set.fromList [String]
dependencies,
        ciCabalFilePath :: Maybe String
ciCabalFilePath = String -> Maybe String
forall a. a -> Maybe a
Just String
cabalFile
      }

-- | Get a map from Haskell source file paths (without any extensions) to
-- the corresponding 'DynOption's and dependencies.
getExtensionAndDepsMap ::
  -- | Path to the cabal file
  FilePath ->
  -- | Parsed generic package description
  GenericPackageDescription ->
  Map FilePath ([DynOption], [String])
getExtensionAndDepsMap :: String
-> GenericPackageDescription -> Map String ([DynOption], [String])
getExtensionAndDepsMap String
cabalFile GenericPackageDescription {[(UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)]
[(UnqualComponentName, CondTree ConfVar [Dependency] Executable)]
[(UnqualComponentName, CondTree ConfVar [Dependency] ForeignLib)]
[(UnqualComponentName, CondTree ConfVar [Dependency] Library)]
[(UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)]
[PackageFlag]
Maybe Version
Maybe (CondTree ConfVar [Dependency] Library)
PackageDescription
gpdScannedVersion :: GenericPackageDescription -> Maybe Version
genPackageFlags :: GenericPackageDescription -> [PackageFlag]
condLibrary :: GenericPackageDescription
-> Maybe (CondTree ConfVar [Dependency] Library)
condSubLibraries :: GenericPackageDescription
-> [(UnqualComponentName, CondTree ConfVar [Dependency] Library)]
condForeignLibs :: GenericPackageDescription
-> [(UnqualComponentName,
     CondTree ConfVar [Dependency] ForeignLib)]
condExecutables :: GenericPackageDescription
-> [(UnqualComponentName,
     CondTree ConfVar [Dependency] Executable)]
condTestSuites :: GenericPackageDescription
-> [(UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)]
condBenchmarks :: GenericPackageDescription
-> [(UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)]
condBenchmarks :: [(UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)]
condTestSuites :: [(UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)]
condExecutables :: [(UnqualComponentName, CondTree ConfVar [Dependency] Executable)]
condForeignLibs :: [(UnqualComponentName, CondTree ConfVar [Dependency] ForeignLib)]
condSubLibraries :: [(UnqualComponentName, CondTree ConfVar [Dependency] Library)]
condLibrary :: Maybe (CondTree ConfVar [Dependency] Library)
genPackageFlags :: [PackageFlag]
gpdScannedVersion :: Maybe Version
packageDescription :: PackageDescription
packageDescription :: GenericPackageDescription -> PackageDescription
..} =
  [Map String ([DynOption], [String])]
-> Map String ([DynOption], [String])
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([Map String ([DynOption], [String])]
 -> Map String ([DynOption], [String]))
-> ([[Map String ([DynOption], [String])]]
    -> [Map String ([DynOption], [String])])
-> [[Map String ([DynOption], [String])]]
-> Map String ([DynOption], [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Map String ([DynOption], [String])]]
-> [Map String ([DynOption], [String])]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Map String ([DynOption], [String])]]
 -> Map String ([DynOption], [String]))
-> [[Map String ([DynOption], [String])]]
-> Map String ([DynOption], [String])
forall a b. (a -> b) -> a -> b
$
    [ (Library -> ([String], ([DynOption], [String])))
-> CondTree ConfVar [Dependency] Library
-> Map String ([DynOption], [String])
forall k a b a v.
(Ord k, Semigroup a, Semigroup b) =>
(a -> ([k], a)) -> CondTree v b a -> Map k a
buildMap Library -> ([String], ([DynOption], [String]))
extractFromLibrary (CondTree ConfVar [Dependency] Library
 -> Map String ([DynOption], [String]))
-> [CondTree ConfVar [Dependency] Library]
-> [Map String ([DynOption], [String])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [CondTree ConfVar [Dependency] Library]
lib [CondTree ConfVar [Dependency] Library]
-> [CondTree ConfVar [Dependency] Library]
-> [CondTree ConfVar [Dependency] Library]
forall a. [a] -> [a] -> [a]
++ [CondTree ConfVar [Dependency] Library]
sublibs,
      (Executable -> ([String], ([DynOption], [String])))
-> CondTree ConfVar [Dependency] Executable
-> Map String ([DynOption], [String])
forall k a b a v.
(Ord k, Semigroup a, Semigroup b) =>
(a -> ([k], a)) -> CondTree v b a -> Map k a
buildMap Executable -> ([String], ([DynOption], [String]))
extractFromExecutable (CondTree ConfVar [Dependency] Executable
 -> Map String ([DynOption], [String]))
-> ((UnqualComponentName, CondTree ConfVar [Dependency] Executable)
    -> CondTree ConfVar [Dependency] Executable)
-> (UnqualComponentName, CondTree ConfVar [Dependency] Executable)
-> Map String ([DynOption], [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UnqualComponentName, CondTree ConfVar [Dependency] Executable)
-> CondTree ConfVar [Dependency] Executable
forall a b. (a, b) -> b
snd ((UnqualComponentName, CondTree ConfVar [Dependency] Executable)
 -> Map String ([DynOption], [String]))
-> [(UnqualComponentName,
     CondTree ConfVar [Dependency] Executable)]
-> [Map String ([DynOption], [String])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(UnqualComponentName, CondTree ConfVar [Dependency] Executable)]
condExecutables,
      (TestSuite -> ([String], ([DynOption], [String])))
-> CondTree ConfVar [Dependency] TestSuite
-> Map String ([DynOption], [String])
forall k a b a v.
(Ord k, Semigroup a, Semigroup b) =>
(a -> ([k], a)) -> CondTree v b a -> Map k a
buildMap TestSuite -> ([String], ([DynOption], [String]))
extractFromTestSuite (CondTree ConfVar [Dependency] TestSuite
 -> Map String ([DynOption], [String]))
-> ((UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)
    -> CondTree ConfVar [Dependency] TestSuite)
-> (UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)
-> Map String ([DynOption], [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)
-> CondTree ConfVar [Dependency] TestSuite
forall a b. (a, b) -> b
snd ((UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)
 -> Map String ([DynOption], [String]))
-> [(UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)]
-> [Map String ([DynOption], [String])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(UnqualComponentName, CondTree ConfVar [Dependency] TestSuite)]
condTestSuites,
      (Benchmark -> ([String], ([DynOption], [String])))
-> CondTree ConfVar [Dependency] Benchmark
-> Map String ([DynOption], [String])
forall k a b a v.
(Ord k, Semigroup a, Semigroup b) =>
(a -> ([k], a)) -> CondTree v b a -> Map k a
buildMap Benchmark -> ([String], ([DynOption], [String]))
extractFromBenchmark (CondTree ConfVar [Dependency] Benchmark
 -> Map String ([DynOption], [String]))
-> ((UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)
    -> CondTree ConfVar [Dependency] Benchmark)
-> (UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)
-> Map String ([DynOption], [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)
-> CondTree ConfVar [Dependency] Benchmark
forall a b. (a, b) -> b
snd ((UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)
 -> Map String ([DynOption], [String]))
-> [(UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)]
-> [Map String ([DynOption], [String])]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(UnqualComponentName, CondTree ConfVar [Dependency] Benchmark)]
condBenchmarks
    ]
  where
    lib :: [CondTree ConfVar [Dependency] Library]
lib = Maybe (CondTree ConfVar [Dependency] Library)
-> [CondTree ConfVar [Dependency] Library]
forall a. Maybe a -> [a]
maybeToList Maybe (CondTree ConfVar [Dependency] Library)
condLibrary
    sublibs :: [CondTree ConfVar [Dependency] Library]
sublibs = (UnqualComponentName, CondTree ConfVar [Dependency] Library)
-> CondTree ConfVar [Dependency] Library
forall a b. (a, b) -> b
snd ((UnqualComponentName, CondTree ConfVar [Dependency] Library)
 -> CondTree ConfVar [Dependency] Library)
-> [(UnqualComponentName, CondTree ConfVar [Dependency] Library)]
-> [CondTree ConfVar [Dependency] Library]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(UnqualComponentName, CondTree ConfVar [Dependency] Library)]
condSubLibraries

    buildMap :: (a -> ([k], a)) -> CondTree v b a -> Map k a
buildMap a -> ([k], a)
f CondTree v b a
a = [(k, a)] -> Map k a
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ((,a
extsAndDeps) (k -> (k, a)) -> [k] -> [(k, a)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [k]
files)
      where
        (a
mergedA, b
_) = CondTree v b a -> (a, b)
forall a c v.
(Semigroup a, Semigroup c) =>
CondTree v c a -> (a, c)
CT.ignoreConditions CondTree v b a
a
        ([k]
files, a
extsAndDeps) = a -> ([k], a)
f a
mergedA

    extractFromBuildInfo :: [String] -> BuildInfo -> ([String], ([DynOption], [String]))
extractFromBuildInfo [String]
extraModules BuildInfo {Bool
[String]
[(String, String)]
[Language]
[Extension]
[Dependency]
[ExeDependency]
[LegacyExeDependency]
[Mixin]
[ModuleName]
[PkgconfigDependency]
[SymbolicPath PackageDir SourceDir]
Maybe Language
PerCompilerFlavor [String]
buildable :: BuildInfo -> Bool
buildTools :: BuildInfo -> [LegacyExeDependency]
buildToolDepends :: BuildInfo -> [ExeDependency]
cppOptions :: BuildInfo -> [String]
asmOptions :: BuildInfo -> [String]
cmmOptions :: BuildInfo -> [String]
ccOptions :: BuildInfo -> [String]
cxxOptions :: BuildInfo -> [String]
ldOptions :: BuildInfo -> [String]
hsc2hsOptions :: BuildInfo -> [String]
pkgconfigDepends :: BuildInfo -> [PkgconfigDependency]
frameworks :: BuildInfo -> [String]
extraFrameworkDirs :: BuildInfo -> [String]
asmSources :: BuildInfo -> [String]
cmmSources :: BuildInfo -> [String]
cSources :: BuildInfo -> [String]
cxxSources :: BuildInfo -> [String]
jsSources :: BuildInfo -> [String]
hsSourceDirs :: BuildInfo -> [SymbolicPath PackageDir SourceDir]
otherModules :: BuildInfo -> [ModuleName]
virtualModules :: BuildInfo -> [ModuleName]
autogenModules :: BuildInfo -> [ModuleName]
defaultLanguage :: BuildInfo -> Maybe Language
otherLanguages :: BuildInfo -> [Language]
defaultExtensions :: BuildInfo -> [Extension]
otherExtensions :: BuildInfo -> [Extension]
oldExtensions :: BuildInfo -> [Extension]
extraLibs :: BuildInfo -> [String]
extraGHCiLibs :: BuildInfo -> [String]
extraBundledLibs :: BuildInfo -> [String]
extraLibFlavours :: BuildInfo -> [String]
extraDynLibFlavours :: BuildInfo -> [String]
extraLibDirs :: BuildInfo -> [String]
includeDirs :: BuildInfo -> [String]
includes :: BuildInfo -> [String]
autogenIncludes :: BuildInfo -> [String]
installIncludes :: BuildInfo -> [String]
options :: BuildInfo -> PerCompilerFlavor [String]
profOptions :: BuildInfo -> PerCompilerFlavor [String]
sharedOptions :: BuildInfo -> PerCompilerFlavor [String]
staticOptions :: BuildInfo -> PerCompilerFlavor [String]
customFieldsBI :: BuildInfo -> [(String, String)]
targetBuildDepends :: BuildInfo -> [Dependency]
mixins :: BuildInfo -> [Mixin]
mixins :: [Mixin]
targetBuildDepends :: [Dependency]
customFieldsBI :: [(String, String)]
staticOptions :: PerCompilerFlavor [String]
sharedOptions :: PerCompilerFlavor [String]
profOptions :: PerCompilerFlavor [String]
options :: PerCompilerFlavor [String]
installIncludes :: [String]
autogenIncludes :: [String]
includes :: [String]
includeDirs :: [String]
extraLibDirs :: [String]
extraDynLibFlavours :: [String]
extraLibFlavours :: [String]
extraBundledLibs :: [String]
extraGHCiLibs :: [String]
extraLibs :: [String]
oldExtensions :: [Extension]
otherExtensions :: [Extension]
defaultExtensions :: [Extension]
otherLanguages :: [Language]
defaultLanguage :: Maybe Language
autogenModules :: [ModuleName]
virtualModules :: [ModuleName]
otherModules :: [ModuleName]
hsSourceDirs :: [SymbolicPath PackageDir SourceDir]
jsSources :: [String]
cxxSources :: [String]
cSources :: [String]
cmmSources :: [String]
asmSources :: [String]
extraFrameworkDirs :: [String]
frameworks :: [String]
pkgconfigDepends :: [PkgconfigDependency]
hsc2hsOptions :: [String]
ldOptions :: [String]
cxxOptions :: [String]
ccOptions :: [String]
cmmOptions :: [String]
asmOptions :: [String]
cppOptions :: [String]
buildToolDepends :: [ExeDependency]
buildTools :: [LegacyExeDependency]
buildable :: Bool
..} = (,([DynOption]
exts, [String]
deps)) ([String] -> ([String], ([DynOption], [String])))
-> [String] -> ([String], ([DynOption], [String]))
forall a b. (a -> b) -> a -> b
$ do
      String
m <- [String]
extraModules [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (ModuleName -> String
ModuleName.toFilePath (ModuleName -> String) -> [ModuleName] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ModuleName]
otherModules)
      (ShowS
takeDirectory String
cabalFile String -> ShowS
</>) ShowS -> [String] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> [String]
prependSrcDirs (ShowS
dropExtensions String
m)
      where
        prependSrcDirs :: String -> [String]
prependSrcDirs String
f
          | [SymbolicPath PackageDir SourceDir] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [SymbolicPath PackageDir SourceDir]
hsSourceDirs = [String
f]
          | Bool
otherwise = (String -> ShowS
</> String
f) ShowS
-> (SymbolicPath PackageDir SourceDir -> String)
-> SymbolicPath PackageDir SourceDir
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SymbolicPath PackageDir SourceDir -> String
forall from to. SymbolicPath from to -> String
getSymbolicPath (SymbolicPath PackageDir SourceDir -> String)
-> [SymbolicPath PackageDir SourceDir] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [SymbolicPath PackageDir SourceDir]
hsSourceDirs
        deps :: [String]
deps = PackageName -> String
unPackageName (PackageName -> String)
-> (Dependency -> PackageName) -> Dependency -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dependency -> PackageName
depPkgName (Dependency -> String) -> [Dependency] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Dependency]
targetBuildDepends
        exts :: [DynOption]
exts = [DynOption]
-> (Language -> [DynOption]) -> Maybe Language -> [DynOption]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] Language -> [DynOption]
langExt Maybe Language
defaultLanguage [DynOption] -> [DynOption] -> [DynOption]
forall a. [a] -> [a] -> [a]
++ (Extension -> DynOption) -> [Extension] -> [DynOption]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Extension -> DynOption
extToDynOption [Extension]
defaultExtensions
        langExt :: Language -> [DynOption]
langExt =
          DynOption -> [DynOption]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (DynOption -> [DynOption])
-> (Language -> DynOption) -> Language -> [DynOption]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> DynOption
DynOption (String -> DynOption)
-> (Language -> String) -> Language -> DynOption
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String
"-X" String -> ShowS
forall a. Semigroup a => a -> a -> a
<>) ShowS -> (Language -> String) -> Language -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
            UnknownLanguage String
lan -> String
lan
            Language
lan -> Language -> String
forall a. Show a => a -> String
show Language
lan
        extToDynOption :: Extension -> DynOption
extToDynOption =
          String -> DynOption
DynOption (String -> DynOption)
-> (Extension -> String) -> Extension -> DynOption
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
            EnableExtension KnownExtension
e -> String
"-X" String -> ShowS
forall a. [a] -> [a] -> [a]
++ KnownExtension -> String
forall a. Show a => a -> String
show KnownExtension
e
            DisableExtension KnownExtension
e -> String
"-XNo" String -> ShowS
forall a. [a] -> [a] -> [a]
++ KnownExtension -> String
forall a. Show a => a -> String
show KnownExtension
e
            UnknownExtension String
e -> String
"-X" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
e

    extractFromLibrary :: Library -> ([String], ([DynOption], [String]))
extractFromLibrary Library {Bool
[ModuleReexport]
[ModuleName]
BuildInfo
LibraryName
LibraryVisibility
libName :: Library -> LibraryName
exposedModules :: Library -> [ModuleName]
reexportedModules :: Library -> [ModuleReexport]
signatures :: Library -> [ModuleName]
libExposed :: Library -> Bool
libVisibility :: Library -> LibraryVisibility
libBuildInfo :: Library -> BuildInfo
libBuildInfo :: BuildInfo
libVisibility :: LibraryVisibility
libExposed :: Bool
signatures :: [ModuleName]
reexportedModules :: [ModuleReexport]
exposedModules :: [ModuleName]
libName :: LibraryName
..} =
      [String] -> BuildInfo -> ([String], ([DynOption], [String]))
extractFromBuildInfo (ModuleName -> String
ModuleName.toFilePath (ModuleName -> String) -> [ModuleName] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [ModuleName]
exposedModules) BuildInfo
libBuildInfo
    extractFromExecutable :: Executable -> ([String], ([DynOption], [String]))
extractFromExecutable Executable {String
BuildInfo
ExecutableScope
UnqualComponentName
exeName :: Executable -> UnqualComponentName
modulePath :: Executable -> String
exeScope :: Executable -> ExecutableScope
buildInfo :: Executable -> BuildInfo
buildInfo :: BuildInfo
exeScope :: ExecutableScope
modulePath :: String
exeName :: UnqualComponentName
..} =
      [String] -> BuildInfo -> ([String], ([DynOption], [String]))
extractFromBuildInfo [String
modulePath] BuildInfo
buildInfo
    extractFromTestSuite :: TestSuite -> ([String], ([DynOption], [String]))
extractFromTestSuite TestSuite {BuildInfo
TestSuiteInterface
UnqualComponentName
testName :: TestSuite -> UnqualComponentName
testInterface :: TestSuite -> TestSuiteInterface
testBuildInfo :: TestSuite -> BuildInfo
testBuildInfo :: BuildInfo
testInterface :: TestSuiteInterface
testName :: UnqualComponentName
..} =
      [String] -> BuildInfo -> ([String], ([DynOption], [String]))
extractFromBuildInfo [String]
mainPath BuildInfo
testBuildInfo
      where
        mainPath :: [String]
mainPath = case TestSuiteInterface
testInterface of
          TestSuiteExeV10 Version
_ String
p -> [String
p]
          TestSuiteLibV09 Version
_ ModuleName
p -> [ModuleName -> String
ModuleName.toFilePath ModuleName
p]
          TestSuiteUnsupported {} -> []
    extractFromBenchmark :: Benchmark -> ([String], ([DynOption], [String]))
extractFromBenchmark Benchmark {BuildInfo
BenchmarkInterface
UnqualComponentName
benchmarkName :: Benchmark -> UnqualComponentName
benchmarkInterface :: Benchmark -> BenchmarkInterface
benchmarkBuildInfo :: Benchmark -> BuildInfo
benchmarkBuildInfo :: BuildInfo
benchmarkInterface :: BenchmarkInterface
benchmarkName :: UnqualComponentName
..} =
      [String] -> BuildInfo -> ([String], ([DynOption], [String]))
extractFromBuildInfo [String]
mainPath BuildInfo
benchmarkBuildInfo
      where
        mainPath :: [String]
mainPath = case BenchmarkInterface
benchmarkInterface of
          BenchmarkExeV10 Version
_ String
p -> [String
p]
          BenchmarkUnsupported {} -> []