module CabalAnalyzer (analyzeCabalFileAllTargets, checkIfGivenVersionWorksForAllTargets) where
import Distribution.Types.GenericPackageDescription
import Distribution.PackageDescription.Parsec
import Distribution.PackageDescription.Configuration
import Distribution.Types.PackageDescription
import Distribution.Types.ComponentRequestedSpec
import Distribution.Types.Library
import Distribution.Types.Executable
import Distribution.Types.ForeignLib
import Distribution.Types.BuildInfo
import Distribution.Types.SetupBuildInfo
import Distribution.Types.TestSuite
import Distribution.Types.Benchmark
import Distribution.Version
import Distribution.Types.Dependency
import Distribution.Types.PackageName
import Distribution.System
import Distribution.Compiler
import Data.Maybe (fromMaybe, maybeToList)
import qualified Data.ByteString as B
import Control.Monad (mplus, msum)
import VabalError
import GhcVersionChaser
import GhcDatabase
import VabalContext
unableToSatisfyConstraintsError :: a
unableToSatisfyConstraintsError = throwVabalError "Error, could not satisfy constraints."
cannotParseCabalFileError :: a
cannotParseCabalFileError = throwVabalError "Error while parsing cabal file."
makeCompilerInfo :: Version -> CompilerInfo
makeCompilerInfo v = unknownCompilerInfo (CompilerId GHC v) NoAbiTag
isBase :: Dependency -> Bool
isBase (Dependency packageName _) = unPackageName packageName == "base"
extractBaseConstraints :: [Dependency] -> VersionRange
extractBaseConstraints deps =
let constraints = depVerRange <$> filter isBase deps
in foldr intersectVersionRanges anyVersion constraints
queryDependency :: VersionRange -> Dependency -> Bool
queryDependency allowedBaseRange dep@(Dependency _ range)
| isBase dep = not . isNoVersion $ intersectVersionRanges range allowedBaseRange
| otherwise = True
constraintsForBase :: FlagAssignment
-> GenericPackageDescription
-> VersionRange
-> CompilerInfo
-> Maybe VersionRange
constraintsForBase flags pkgDescr otherBaseConstraints compiler =
let finalizedPkgDescr = finalizePD flags
(ComponentRequestedSpec True True)
(queryDependency otherBaseConstraints)
buildPlatform
compiler
[]
pkgDescr
in case finalizedPkgDescr of
Left _ -> Nothing
Right (pd, _) ->
let setupDependencies = setupDepends <$> maybeToList (setupBuildInfo pd)
projectDependencies = map targetBuildDepends $ concat
[ libBuildInfo <$> maybeToList (library pd)
, libBuildInfo <$> subLibraries pd
, buildInfo <$> executables pd
, foreignLibBuildInfo <$> foreignLibs pd
, testBuildInfo <$> testSuites pd
, benchmarkBuildInfo <$> benchmarks pd
]
dependencies = setupDependencies ++ projectDependencies
baseConstraints = map extractBaseConstraints dependencies
in Just $ foldr intersectVersionRanges anyVersion baseConstraints
analyzeCabalFileAllTargets :: FlagAssignment
-> VabalContext
-> Maybe Version
-> B.ByteString
-> Version
analyzeCabalFileAllTargets flags ctx baseVersionConstraint cabalFile =
case parseGenericPackageDescriptionMaybe cabalFile of
Nothing -> cannotParseCabalFileError
Just pkgDescr -> {-# SCC "vabal-core" #-}
let otherBaseConstraints = maybe anyVersion thisVersion baseVersionConstraint
candidates = map (fmap makeCompilerInfo)
$ findGhcVersions (allGhcInfo ctx) otherBaseConstraints pkgDescr
allBaseConstraints = map (uncurry $ constraintsForBase flags pkgDescr) candidates
newestGhcCandidate =
msum $ map (>>= newestGhcVersionIn (allGhcInfo ctx)) allBaseConstraints
availableGhcCandidate =
msum $ map (>>= newestGhcVersionIn (availableGhcs ctx)) allBaseConstraints
ghcCandidate =
if alwaysNewestGhc ctx then
newestGhcCandidate
else
availableGhcCandidate `mplus` newestGhcCandidate
in fromMaybe unableToSatisfyConstraintsError ghcCandidate
checkIfGivenVersionWorksForAllTargets :: FlagAssignment
-> VabalContext
-> B.ByteString
-> Version
-> Bool
checkIfGivenVersionWorksForAllTargets flags ctx cabalFile selectedGhcVersion =
case parseGenericPackageDescriptionMaybe cabalFile of
Nothing -> cannotParseCabalFileError
Just pkgDescr ->
let ghc = makeCompilerInfo selectedGhcVersion
in case constraintsForBase flags pkgDescr anyVersion ghc of
Nothing -> unableToSatisfyConstraintsError
Just suggestedBaseVersionRange ->
maybe False (`withinRange` suggestedBaseVersionRange) $
baseVersionForGhc (allGhcInfo ctx) selectedGhcVersion