<commit_before>-- | See <https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst>

module Distribution.Backpack.ComponentsGraph (
    ComponentsGraph,
    dispComponentsGraph,
    toComponentsGraph,
    componentCycleMsg
) where

import Distribution.Package
import Distribution.PackageDescription as PD hiding (Flag)
import Distribution.Simple.LocalBuildInfo
import Distribution.Types.ComponentRequestedSpec
import Distribution.Simple.Utils
import Distribution.Compat.Graph (Node(..))
import qualified Distribution.Compat.Graph as Graph

import Distribution.Text
    ( Text(disp) )
import Text.PrettyPrint

------------------------------------------------------------------------------
-- Components graph
------------------------------------------------------------------------------

-- | A components graph is a source level graph tracking the
-- dependencies between components in a package.
type ComponentsGraph = [(Component, [ComponentName])]

-- | Pretty-print a 'ComponentsGraph'.
dispComponentsGraph :: ComponentsGraph -> Doc
dispComponentsGraph graph =
    vcat [ hang (text "component" <+> disp (componentName c)) 4
                (vcat [ text "dependency" <+> disp cdep | cdep <- cdeps ])
         | (c, cdeps) <- graph ]

-- | Given the package description and the set of package names which
-- are considered internal (the current package name and any internal
-- libraries are considered internal), create a graph of dependencies
-- between the components.  This is NOT necessarily the build order
-- (although it is in the absence of Backpack.)
toComponentsGraph :: ComponentRequestedSpec
                  -> PackageDescription
                  -> Either [ComponentName] ComponentsGraph
toComponentsGraph enabled pkg_descr =
    let g = Graph.fromList [ N c (componentName c) (componentDeps c)
                           | c <- pkgBuildableComponents pkg_descr
                           , componentEnabled enabled c ]
    in case Graph.cycles g of
          []     -> Right (map (\(N c _ cs) -> (c, cs)) (Graph.revTopSort g))
          ccycles -> Left  [ componentName c | N c _ _ <- concat ccycles ]
  where
    -- The dependencies for the given component
    componentDeps component =
         [ CExeName toolname | Dependency pkgname _
                               <- buildTools bi
                             , let toolname = unPackageName pkgname
                             , toolname `elem` map exeName
                               (executables pkg_descr) ]

      ++ [ if pkgname == packageName pkg_descr
            then CLibName
            else CSubLibName toolname
            | Dependency pkgname _
                               <- targetBuildDepends bi<commit_msg>Update toComponentsGraph comment.<commit_after>-- | See <https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst>

module Distribution.Backpack.ComponentsGraph (
    ComponentsGraph,
    dispComponentsGraph,
    toComponentsGraph,
    componentCycleMsg
) where

import Distribution.Package
import Distribution.PackageDescription as PD hiding (Flag)
import Distribution.Simple.LocalBuildInfo
import Distribution.Types.ComponentRequestedSpec
import Distribution.Simple.Utils
import Distribution.Compat.Graph (Node(..))
import qualified Distribution.Compat.Graph as Graph

import Distribution.Text
    ( Text(disp) )
import Text.PrettyPrint

------------------------------------------------------------------------------
-- Components graph
------------------------------------------------------------------------------

-- | A components graph is a source level graph tracking the
-- dependencies between components in a package.
type ComponentsGraph = [(Component, [ComponentName])]

-- | Pretty-print a 'ComponentsGraph'.
dispComponentsGraph :: ComponentsGraph -> Doc
dispComponentsGraph graph =
    vcat [ hang (text "component" <+> disp (componentName c)) 4
                (vcat [ text "dependency" <+> disp cdep | cdep <- cdeps ])
         | (c, cdeps) <- graph ]

-- | Given the package description and a 'PackageDescription' (used
-- to determine if a package name is internal or not), create a graph of
-- dependencies between the components.  This is NOT necessarily the
-- build order (although it is in the absence of Backpack.)
toComponentsGraph :: ComponentRequestedSpec
                  -> PackageDescription
                  -> Either [ComponentName] ComponentsGraph
toComponentsGraph enabled pkg_descr =
    let g = Graph.fromList [ N c (componentName c) (componentDeps c)
                           | c <- pkgBuildableComponents pkg_descr
                           , componentEnabled enabled c ]
    in case Graph.cycles g of
          []     -> Right (map (\(N c _ cs) -> (c, cs)) (Graph.revTopSort g))
          ccycles -> Left  [ componentName c | N c _ _ <- concat ccycles ]
  where
    -- The dependencies for the given component
    componentDeps component =
         [ CExeName toolname | Dependency pkgname _
                               <- buildTools bi
                             , let toolname = unPackageName pkgname
                             , toolname `elem` map exeName
                               (executables pkg_descr) ]

      ++ [ if pkgname == packageName pkg_descr
            then CLibName
            else CSubLibName toolname
            | Dependency pkgname _
                               <- targetBuildDepends bi
{'fraction_non_alphanumeric': 0.13135593220338984, 'fraction_numerical': 0.0018422991893883567, 'mean_word_length': 1.9994475138121548, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2358732', 'n_tokens_mistral': 1335, 'n_tokens_neox': 1268, 'n_words': 428}