Check for version conflicts ourselves.

This was done by cabal-install previously. But doing it ourselves, we gain a
few things:

* Found out about problems faster.
* Get a complete list of problems, including tests.
* Much more user-friendly output.
This commit is contained in:
Michael Snoyman 2012-12-09 18:58:05 +02:00
parent 42621ab17a
commit a609f1fc0c
4 changed files with 63 additions and 13 deletions

View File

@ -3,9 +3,12 @@ module Stackage.InstallInfo
, iiPackageList , iiPackageList
) where ) where
import Control.Arrow ((&&&))
import Control.Monad (forM_)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import Data.Version (showVersion) import Data.Version (showVersion)
import Distribution.Version (withinRange)
import Stackage.Config import Stackage.Config
import Stackage.HaskellPlatform import Stackage.HaskellPlatform
import Stackage.LoadDatabase import Stackage.LoadDatabase
@ -32,17 +35,29 @@ getInstallInfo settings = do
putStrLn "Printing build plan to build-plan.log" putStrLn "Printing build plan to build-plan.log"
writeFile "build-plan.log" $ unlines $ map showDep $ Map.toList final writeFile "build-plan.log" $ unlines $ map showDep $ Map.toList final
case checkBadVersions settings final of
badVersions
| Map.null badVersions -> return ()
| otherwise -> do
forM_ (Map.toList badVersions) $ \(PackageName user, badDeps) -> do
putStrLn $ user ++ " cannot use: "
mapM_ (putStrLn . packageVersionString) $ Map.toList badDeps
putStrLn ""
error "Conflicting build plan, exiting"
return InstallInfo return InstallInfo
{ iiCore = totalCore { iiCore = totalCore
, iiPackages = Map.map (\(v, _, m) -> (v, m)) final , iiPackages = Map.map (biVersion &&& biMaintainer) final
, iiOptionalCore = Map.fromList $ map (\(PackageIdentifier p v) -> (p, v)) $ Set.toList $ hplibs hp , iiOptionalCore = Map.fromList $ map (\(PackageIdentifier p v) -> (p, v)) $ Set.toList $ hplibs hp
, iiPackageDB = pdb , iiPackageDB = pdb
} }
showDep :: (PackageName, (Version, [PackageName], Maintainer)) -> String showDep :: (PackageName, BuildInfo) -> String
showDep (name, (version, deps, Maintainer m)) = showDep (PackageName name, (BuildInfo version deps (Maintainer m) _)) =
concat concat
[ unP name [ name
, "-" , "-"
, showVersion version , showVersion version
, " (" , " ("
@ -56,3 +71,25 @@ showDep (name, (version, deps, Maintainer m)) =
iiPackageList :: InstallInfo -> [String] iiPackageList :: InstallInfo -> [String]
iiPackageList = map packageVersionString . Map.toList . Map.map fst . iiPackages iiPackageList = map packageVersionString . Map.toList . Map.map fst . iiPackages
-- | Check for internal mismatches in required and actual package versions.
checkBadVersions :: BuildSettings
-> Map PackageName BuildInfo
-> Map PackageName (Map PackageName Version)
checkBadVersions settings buildPlan =
Map.filter (not . Map.null) $ Map.map getBadVersions $ Map.filterWithKey unexpectedFailure buildPlan
where
unexpectedFailure name _ = name `Set.notMember` expectedFailures settings
getBadVersions :: BuildInfo -> Map PackageName Version
getBadVersions = Map.unions . map (uncurry checkPackage) . Map.toList . biDeps
checkPackage :: PackageName -> VersionRange -> Map PackageName Version
checkPackage name vr =
case Map.lookup name buildPlan of
-- Can't find the dependency. Could be part of core, so just ignore
-- it.
Nothing -> Map.empty
Just bi
| biVersion bi `withinRange` vr -> Map.empty
| otherwise -> Map.singleton name $ biVersion bi

View File

@ -30,7 +30,7 @@ import Distribution.PackageDescription (Condition (..),
import Distribution.PackageDescription.Parse (ParseResult (ParseOk), import Distribution.PackageDescription.Parse (ParseResult (ParseOk),
parsePackageDescription) parsePackageDescription)
import Distribution.System (buildArch, buildOS) import Distribution.System (buildArch, buildOS)
import Distribution.Version (withinRange) import Distribution.Version (withinRange, unionVersionRanges)
import Stackage.Config import Stackage.Config
import Stackage.Types import Stackage.Types
import Stackage.Util import Stackage.Util
@ -101,8 +101,8 @@ loadPackageDB core deps = do
goBI f x = buildTools $ f $ condTreeData x goBI f x = buildTools $ f $ condTreeData x
depName (Dependency p _) = p depName (Dependency p _) = p
go gpd tree go gpd tree
= Set.unions = Map.unionsWith unionVersionRanges
$ Set.fromList (map (\(Dependency p _) -> p) $ condTreeConstraints tree) $ Map.fromList (map (\(Dependency p vr) -> (p, vr)) $ condTreeConstraints tree)
: map (go gpd) (mapMaybe (checkCond gpd) $ condTreeComponents tree) : map (go gpd) (mapMaybe (checkCond gpd) $ condTreeComponents tree)
checkCond gpd (cond, tree, melse) checkCond gpd (cond, tree, melse)

View File

@ -9,7 +9,7 @@ import Stackage.Types
-- their dependencies. -- their dependencies.
narrowPackageDB :: PackageDB narrowPackageDB :: PackageDB
-> Set (PackageName, Maintainer) -> Set (PackageName, Maintainer)
-> IO (Map PackageName (Version, [PackageName], Maintainer)) -> IO (Map PackageName BuildInfo)
narrowPackageDB (PackageDB pdb) = narrowPackageDB (PackageDB pdb) =
loop Map.empty . Set.map (\(name, maintainer) -> ([], name, maintainer)) loop Map.empty . Set.map (\(name, maintainer) -> ([], name, maintainer))
where where
@ -23,8 +23,13 @@ narrowPackageDB (PackageDB pdb) =
| otherwise -> loop result toProcess' | otherwise -> loop result toProcess'
Just pi -> do Just pi -> do
let users' = p:users let users' = p:users
result' = Map.insert p (piVersion pi, users, maintainer) result result' = Map.insert p BuildInfo
loop result' $ Set.foldl' (addDep users' result' maintainer) toProcess' $ piDeps pi { biVersion = piVersion pi
, biUsers = users
, biMaintainer = maintainer
, biDeps = piDeps pi
} result
loop result' $ Set.foldl' (addDep users' result' maintainer) toProcess' $ Map.keysSet $ piDeps pi
addDep users result maintainer toProcess p = addDep users result maintainer toProcess p =
case Map.lookup p result of case Map.lookup p result of
Nothing -> Set.insert (users, p, maintainer) toProcess Nothing -> Set.insert (users, p, maintainer) toProcess

View File

@ -13,7 +13,7 @@ import Distribution.Package as X (PackageIdentifier (..),
import Distribution.Version as X (VersionRange (..)) import Distribution.Version as X (VersionRange (..))
newtype PackageDB = PackageDB (Map PackageName PackageInfo) newtype PackageDB = PackageDB (Map PackageName PackageInfo)
deriving (Show, Eq, Ord) deriving (Show, Eq)
instance Monoid PackageDB where instance Monoid PackageDB where
mempty = PackageDB mempty mempty = PackageDB mempty
@ -26,11 +26,19 @@ instance Monoid PackageDB where
data PackageInfo = PackageInfo data PackageInfo = PackageInfo
{ piVersion :: Version { piVersion :: Version
, piDeps :: Set PackageName , piDeps :: Map PackageName VersionRange
, piHasTests :: Bool , piHasTests :: Bool
, piBuildTools :: Set PackageName , piBuildTools :: Set PackageName
} }
deriving (Show, Eq, Ord) deriving (Show, Eq)
-- | Information on a package we're going to build.
data BuildInfo = BuildInfo
{ biVersion :: Version
, biUsers :: [PackageName]
, biMaintainer :: Maintainer
, biDeps :: Map PackageName VersionRange
}
data HaskellPlatform = HaskellPlatform data HaskellPlatform = HaskellPlatform
{ hpcore :: Set PackageIdentifier { hpcore :: Set PackageIdentifier