module Distribution.Backpack.ComponentsGraph (
ComponentsGraph,
ComponentsWithDeps,
mkComponentsGraph,
componentsGraphToList,
dispComponentsWithDeps,
componentCycleMsg
) where
import Prelude ()
import Distribution.Compat.Prelude
import Distribution.Package
import Distribution.PackageDescription as PD hiding (Flag)
import Distribution.Simple.BuildToolDepends
import Distribution.Simple.LocalBuildInfo
import Distribution.Types.ComponentRequestedSpec
import Distribution.Types.UnqualComponentName
import Distribution.Compat.Graph (Graph, Node(..))
import qualified Distribution.Compat.Graph as Graph
import Distribution.Utils.Generic
import Distribution.Pretty (pretty)
import Text.PrettyPrint
type ComponentsGraph = Graph (Node ComponentName Component)
type ComponentsWithDeps = [(Component, [ComponentName])]
dispComponentsWithDeps :: ComponentsWithDeps -> Doc
dispComponentsWithDeps graph =
vcat [ hang (text "component" <+> pretty (componentName c)) 4
(vcat [ text "dependency" <+> pretty cdep | cdep <- cdeps ])
| (c, cdeps) <- graph ]
mkComponentsGraph :: ComponentRequestedSpec
-> PackageDescription
-> Either [ComponentName] ComponentsGraph
mkComponentsGraph enabled pkg_descr =
let g = Graph.fromDistinctList
[ N c (componentName c) (componentDeps c)
| c <- pkgBuildableComponents pkg_descr
, componentEnabled enabled c ]
in case Graph.cycles g of
[] -> Right g
ccycles -> Left [ componentName c | N c _ _ <- concat ccycles ]
where
componentDeps component =
(CExeName <$> getAllInternalToolDependencies pkg_descr bi)
++ [ if pkgname == packageName pkg_descr
then CLibName LMainLibName
else CLibName (LSubLibName toolname)
| Dependency pkgname _ _ <- targetBuildDepends bi
, let toolname = packageNameToUnqualComponentName pkgname
, toolname `elem` internalPkgDeps ]
where
bi = componentBuildInfo component
internalPkgDeps = map (conv . libName) (allLibraries pkg_descr)
conv LMainLibName = packageNameToUnqualComponentName $ packageName pkg_descr
conv (LSubLibName s) = s
componentsGraphToList :: ComponentsGraph
-> ComponentsWithDeps
componentsGraphToList =
map (\(N c _ cs) -> (c, cs)) . Graph.revTopSort
componentCycleMsg :: [ComponentName] -> Doc
componentCycleMsg cnames =
text $ "Components in the package depend on each other in a cyclic way:\n "
++ intercalate " depends on "
[ "'" ++ showComponentName cname ++ "'"
| cname <- cnames ++ maybeToList (safeHead cnames) ]