-- cabal-helper: Simple interface to Cabal's configuration state
-- Copyright (C) 2015-2018  Daniel Gröber <cabal-helper@dxld.at>
--
-- SPDX-License-Identifier: Apache-2.0
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0

{-# LANGUAGE CPP, BangPatterns, RecordWildCards, RankNTypes, ViewPatterns,
  TupleSections #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}

#ifdef MIN_VERSION_Cabal
#undef CH_MIN_VERSION_Cabal
#define CH_MIN_VERSION_Cabal MIN_VERSION_Cabal
#endif

module CabalHelper.Runtime.Compat
    ( UnitId
    , componentNameToCh
    , unUnqualComponentName'
    , componentNameFromComponent
    , componentOutDir
    , internalPackageDBPath
    , unFlagAssignment
    ) where

import System.FilePath

import Distribution.PackageDescription
  ( PackageDescription
  , GenericPackageDescription(..)
  , Flag(..)
  , FlagName
  , FlagAssignment
  , Executable(..)
  , Library(..)
  , TestSuite(..)
  , Benchmark(..)
  , BuildInfo(..)
  , TestSuiteInterface(..)
  , BenchmarkInterface(..)
  , withLib
  )
import Distribution.Simple.LocalBuildInfo
  ( ComponentName(..)
  , Component(..)
  , LocalBuildInfo(..)
  )


#if CH_MIN_VERSION_Cabal(1,24,0)
import Distribution.Package (UnitId)
#else
import Distribution.Package (InstalledPackageId)
#endif

#if CH_MIN_VERSION_Cabal(1,25,0)
-- >=1.25
import Distribution.PackageDescription
  ( unFlagName
  -- , mkFlagName
  )
import Distribution.Types.ForeignLib
  ( ForeignLib(..)
  )
import Distribution.Types.UnqualComponentName
  ( UnqualComponentName
  , unUnqualComponentName
  )
#else
-- <1.25
import Distribution.PackageDescription
  ( FlagName(FlagName)
  )
#endif

#if CH_MIN_VERSION_Cabal(2,0,0)
-- CPP >= 2.0
import Distribution.Simple.LocalBuildInfo
  ( allLibModules
  , componentBuildDir
  )
import Distribution.Simple.Register
  ( internalPackageDBPath
  )
import Distribution.Backpack
  ( OpenUnitId(..),
    OpenModule(..)
  )
import Distribution.ModuleName
  ( ModuleName
  )
import Distribution.Types.ComponentId
  ( unComponentId
  )
import Distribution.Types.ComponentLocalBuildInfo
  ( maybeComponentInstantiatedWith
  )
import Distribution.Types.ModuleRenaming
  ( ModuleRenaming(..),
    isDefaultRenaming
  )
import Distribution.Types.MungedPackageId
  ( MungedPackageId
  )
import Distribution.Types.UnitId
  ( UnitId
  , unDefUnitId
  , unUnitId
  )
import Distribution.Types.UnitId
  ( DefUnitId
  )
import Distribution.Utils.NubList
  ( toNubListR
  )
import Distribution.Version
  ( versionNumbers
  , mkVersion
  )
import qualified Distribution.InstalledPackageInfo as Installed
#endif

#if CH_MIN_VERSION_Cabal(3,2,0)
import Distribution.Types.Flag
  ( unFlagAssignment
  )
#elif CH_MIN_VERSION_Cabal(2,2,0)
import Distribution.Types.GenericPackageDescription
  ( unFlagAssignment
  )
#else
#define NOP_UN_FLAG_ASSIGNMENT 1
#endif

#if CH_MIN_VERSION_Cabal(2,5,0)
import Distribution.Types.LibraryName
  ( LibraryName (..)
  )
#endif


import CabalHelper.Shared.Common
import CabalHelper.Shared.InterfaceTypes







#if !CH_MIN_VERSION_Cabal(1,24,0)
type UnitId = InstalledPackageId
#endif



componentNameToCh :: ComponentName -> ChComponentName
#if CH_MIN_VERSION_Cabal(2,5,0)
componentNameToCh :: ComponentName -> ChComponentName
componentNameToCh (CLibName LibraryName
LMainLibName) = ChLibraryName -> ChComponentName
ChLibName ChLibraryName
ChMainLibName
componentNameToCh (CLibName (LSubLibName UnqualComponentName
n)) = ChLibraryName -> ChComponentName
ChLibName (ChLibraryName -> ChComponentName)
-> ChLibraryName -> ChComponentName
forall a b. (a -> b) -> a -> b
$ String -> ChLibraryName
ChSubLibName (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
n)
#elif CH_MIN_VERSION_Cabal(2,0,0)
componentNameToCh CLibName = ChLibName ChMainLibName
componentNameToCh (CSubLibName n) = ChLibName $ ChSubLibName (unUnqualComponentName' n)
#else
componentNameToCh CLibName = ChLibName ChMainLibName
#endif
#if CH_MIN_VERSION_Cabal(2,0,0)
componentNameToCh (CFLibName UnqualComponentName
n) = String -> ChComponentName
ChFLibName (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
n)
#endif
componentNameToCh (CExeName UnqualComponentName
n) = String -> ChComponentName
ChExeName (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
n)
componentNameToCh (CTestName UnqualComponentName
n) = String -> ChComponentName
ChTestName (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
n)
componentNameToCh (CBenchName UnqualComponentName
n) = String -> ChComponentName
ChBenchName (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
n)


#if CH_MIN_VERSION_Cabal(1,25,0)
-- CPP >= 1.25
unUnqualComponentName' :: UnqualComponentName -> String
unUnqualComponentName' :: UnqualComponentName -> String
unUnqualComponentName' = UnqualComponentName -> String
unUnqualComponentName
#else
unUnqualComponentName' :: a -> a
unUnqualComponentName' = id
#endif


componentNameFromComponent :: Component -> ComponentName
#if CH_MIN_VERSION_Cabal(2,5,0)
componentNameFromComponent :: Component -> ComponentName
componentNameFromComponent (CLib Library { libName :: Library -> LibraryName
libName = LibraryName
n }) = LibraryName -> ComponentName
CLibName LibraryName
n
componentNameFromComponent (CFLib ForeignLib {[String]
[ForeignLibOption]
Maybe Version
Maybe LibVersionInfo
BuildInfo
UnqualComponentName
ForeignLibType
foreignLibVersionLinux :: ForeignLib -> Maybe Version
foreignLibVersionInfo :: ForeignLib -> Maybe LibVersionInfo
foreignLibType :: ForeignLib -> ForeignLibType
foreignLibOptions :: ForeignLib -> [ForeignLibOption]
foreignLibName :: ForeignLib -> UnqualComponentName
foreignLibModDefFile :: ForeignLib -> [String]
foreignLibBuildInfo :: ForeignLib -> BuildInfo
foreignLibModDefFile :: [String]
foreignLibVersionLinux :: Maybe Version
foreignLibVersionInfo :: Maybe LibVersionInfo
foreignLibBuildInfo :: BuildInfo
foreignLibOptions :: [ForeignLibOption]
foreignLibType :: ForeignLibType
foreignLibName :: UnqualComponentName
..}) = UnqualComponentName -> ComponentName
CFLibName UnqualComponentName
foreignLibName
#elif CH_MIN_VERSION_Cabal(1,25,0)
-- CPP >= 1.25 (redundant)
componentNameFromComponent (CLib Library { libName = Nothing }) = CLibName
componentNameFromComponent (CLib Library { libName = Just n })  = CSubLibName n
componentNameFromComponent (CFLib ForeignLib {..}) = CFLibName foreignLibName
#else
-- CPP < 1.25
componentNameFromComponent (CLib Library {}) = CLibName
#endif
componentNameFromComponent (CExe Executable {String
BuildInfo
UnqualComponentName
ExecutableScope
modulePath :: Executable -> String
exeScope :: Executable -> ExecutableScope
exeName :: Executable -> UnqualComponentName
buildInfo :: Executable -> BuildInfo
buildInfo :: BuildInfo
exeScope :: ExecutableScope
modulePath :: String
exeName :: UnqualComponentName
..}) = UnqualComponentName -> ComponentName
CExeName UnqualComponentName
exeName
componentNameFromComponent (CTest TestSuite {BuildInfo
TestSuiteInterface
UnqualComponentName
testName :: TestSuite -> UnqualComponentName
testInterface :: TestSuite -> TestSuiteInterface
testBuildInfo :: TestSuite -> BuildInfo
testBuildInfo :: BuildInfo
testInterface :: TestSuiteInterface
testName :: UnqualComponentName
..}) = UnqualComponentName -> ComponentName
CTestName UnqualComponentName
testName
componentNameFromComponent (CBench Benchmark {BenchmarkInterface
BuildInfo
UnqualComponentName
benchmarkName :: Benchmark -> UnqualComponentName
benchmarkInterface :: Benchmark -> BenchmarkInterface
benchmarkBuildInfo :: Benchmark -> BuildInfo
benchmarkBuildInfo :: BuildInfo
benchmarkInterface :: BenchmarkInterface
benchmarkName :: UnqualComponentName
..}) = UnqualComponentName -> ComponentName
CBenchName UnqualComponentName
benchmarkName


componentOutDir :: LocalBuildInfo -> Component -> FilePath
componentOutDir :: LocalBuildInfo -> Component -> String
componentOutDir LocalBuildInfo
lbi (CLib Library {Bool
[ModuleReexport]
[ModuleName]
BuildInfo
LibraryName
LibraryVisibility
signatures :: Library -> [ModuleName]
reexportedModules :: Library -> [ModuleReexport]
libVisibility :: Library -> LibraryVisibility
libExposed :: Library -> Bool
libBuildInfo :: Library -> BuildInfo
exposedModules :: Library -> [ModuleName]
libBuildInfo :: BuildInfo
libVisibility :: LibraryVisibility
libExposed :: Bool
signatures :: [ModuleName]
reexportedModules :: [ModuleReexport]
exposedModules :: [ModuleName]
libName :: LibraryName
libName :: Library -> LibraryName
..})=
    LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi
#if CH_MIN_VERSION_Cabal(2,0,0)
componentOutDir LocalBuildInfo
lbi (CFLib ForeignLib {[String]
[ForeignLibOption]
Maybe Version
Maybe LibVersionInfo
BuildInfo
UnqualComponentName
ForeignLibType
foreignLibModDefFile :: [String]
foreignLibVersionLinux :: Maybe Version
foreignLibVersionInfo :: Maybe LibVersionInfo
foreignLibBuildInfo :: BuildInfo
foreignLibOptions :: [ForeignLibOption]
foreignLibType :: ForeignLibType
foreignLibName :: UnqualComponentName
foreignLibVersionLinux :: ForeignLib -> Maybe Version
foreignLibVersionInfo :: ForeignLib -> Maybe LibVersionInfo
foreignLibType :: ForeignLib -> ForeignLibType
foreignLibOptions :: ForeignLib -> [ForeignLibOption]
foreignLibName :: ForeignLib -> UnqualComponentName
foreignLibModDefFile :: ForeignLib -> [String]
foreignLibBuildInfo :: ForeignLib -> BuildInfo
..}) =
    LocalBuildInfo -> String -> String
componentOutDir' LocalBuildInfo
lbi (UnqualComponentName -> String
unUnqualComponentName UnqualComponentName
foreignLibName)
#endif
componentOutDir LocalBuildInfo
lbi (CExe Executable {String
BuildInfo
UnqualComponentName
ExecutableScope
buildInfo :: BuildInfo
exeScope :: ExecutableScope
modulePath :: String
exeName :: UnqualComponentName
modulePath :: Executable -> String
exeScope :: Executable -> ExecutableScope
exeName :: Executable -> UnqualComponentName
buildInfo :: Executable -> BuildInfo
..}) =
    LocalBuildInfo -> String -> String
componentOutDir' LocalBuildInfo
lbi (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
exeName)
componentOutDir LocalBuildInfo
lbi (CTest TestSuite { testInterface :: TestSuite -> TestSuiteInterface
testInterface = TestSuiteLibV09 Version
_ ModuleName
_, BuildInfo
UnqualComponentName
testBuildInfo :: BuildInfo
testName :: UnqualComponentName
testName :: TestSuite -> UnqualComponentName
testBuildInfo :: TestSuite -> BuildInfo
..}) =
    LocalBuildInfo -> String -> String
componentOutDir' LocalBuildInfo
lbi (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
testName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"Stub")
componentOutDir LocalBuildInfo
lbi (CTest TestSuite { testInterface :: TestSuite -> TestSuiteInterface
testInterface = TestSuiteInterface
_, BuildInfo
UnqualComponentName
testBuildInfo :: BuildInfo
testName :: UnqualComponentName
testName :: TestSuite -> UnqualComponentName
testBuildInfo :: TestSuite -> BuildInfo
..}) =
    LocalBuildInfo -> String -> String
componentOutDir' LocalBuildInfo
lbi (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
testName)
componentOutDir LocalBuildInfo
lbi (CBench Benchmark { benchmarkInterface :: Benchmark -> BenchmarkInterface
benchmarkInterface = BenchmarkInterface
_, BuildInfo
UnqualComponentName
benchmarkBuildInfo :: BuildInfo
benchmarkName :: UnqualComponentName
benchmarkName :: Benchmark -> UnqualComponentName
benchmarkBuildInfo :: Benchmark -> BuildInfo
..})=
    LocalBuildInfo -> String -> String
componentOutDir' LocalBuildInfo
lbi (UnqualComponentName -> String
unUnqualComponentName' UnqualComponentName
benchmarkName)

componentOutDir' :: LocalBuildInfo -> String -> FilePath
componentOutDir' :: LocalBuildInfo -> String -> String
componentOutDir' LocalBuildInfo
lbi String
compName' =
  ----- Copied from Distribution/Simple/GHC.hs:buildOrReplExe
  let targetDir :: String
targetDir = (LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi) String -> String -> String
</> String
compName'
      compDir :: String
compDir    = String
targetDir String -> String -> String
</> (String
compName' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-tmp")
  in String
compDir

#if !CH_MIN_VERSION_Cabal(2,0,0)
internalPackageDBPath :: LocalBuildInfo -> FilePath -> FilePath
internalPackageDBPath lbi distPref =
  distPref </> "package.conf.inplace"
#endif

#ifdef NOP_UN_FLAG_ASSIGNMENT
unFlagAssignment = id
#endif