module Distribution.Backpack.ConfiguredComponent (
ConfiguredComponent(..),
cc_name,
cc_cid,
cc_pkgid,
toConfiguredComponent,
toConfiguredComponents,
dispConfiguredComponent,
ConfiguredComponentMap,
extendConfiguredComponentMap,
newPackageDepsBehaviour
) where
import Prelude ()
import Distribution.Compat.Prelude hiding ((<>))
import Distribution.Backpack.Id
import Distribution.Types.AnnotatedId
import Distribution.Types.Dependency
import Distribution.Types.ExeDependency
import Distribution.Types.IncludeRenaming
import Distribution.Types.ComponentId
import Distribution.Types.PackageId
import Distribution.Types.PackageName
import Distribution.Types.Mixin
import Distribution.Types.ComponentName
import Distribution.Types.LibraryName
import Distribution.Types.UnqualComponentName
import Distribution.Types.ComponentInclude
import Distribution.Package
import Distribution.PackageDescription as PD hiding (Flag)
import Distribution.Simple.BuildToolDepends
import Distribution.Simple.Setup as Setup
import Distribution.Simple.LocalBuildInfo
import Distribution.Version
import Distribution.Utils.LogProgress
import Distribution.Utils.MapAccum
import Distribution.Utils.Generic
import Control.Monad
import qualified Data.Set as Set
import qualified Data.Map as Map
import Distribution.Pretty
import Text.PrettyPrint
data ConfiguredComponent
= ConfiguredComponent {
cc_ann_id :: AnnotatedId ComponentId,
cc_component :: Component,
cc_public :: Bool,
cc_exe_deps :: [AnnotatedId ComponentId],
cc_includes :: [ComponentInclude ComponentId IncludeRenaming]
}
cc_cid :: ConfiguredComponent -> ComponentId
cc_cid = ann_id . cc_ann_id
cc_pkgid :: ConfiguredComponent -> PackageId
cc_pkgid = ann_pid . cc_ann_id
cc_name :: ConfiguredComponent -> ComponentName
cc_name = ann_cname . cc_ann_id
dispConfiguredComponent :: ConfiguredComponent -> Doc
dispConfiguredComponent cc =
hang (text "component" <+> pretty (cc_cid cc)) 4
(vcat [ hsep $ [ text "include", pretty (ci_id incl), pretty (ci_renaming incl) ]
| incl <- cc_includes cc
])
mkConfiguredComponent
:: PackageDescription
-> ComponentId
-> [AnnotatedId ComponentId]
-> [AnnotatedId ComponentId]
-> Component
-> LogProgress ConfiguredComponent
mkConfiguredComponent pkg_descr this_cid lib_deps exe_deps component = do
explicit_includes <- forM (mixins bi) $ \(Mixin name rns) -> do
let keys = fixFakePkgName pkg_descr name
aid <- case Map.lookup keys deps_map of
Nothing ->
dieProgress $
text "Mix-in refers to non-existent package" <+>
quotes (pretty name) $$
text "(did you forget to add the package to build-depends?)"
Just r -> return r
return ComponentInclude {
ci_ann_id = aid,
ci_renaming = rns,
ci_implicit = False
}
let used_explicitly = Set.fromList (map ci_id explicit_includes)
implicit_includes
= map (\aid -> ComponentInclude {
ci_ann_id = aid,
ci_renaming = defaultIncludeRenaming,
ci_implicit = True
})
$ filter (flip Set.notMember used_explicitly . ann_id) lib_deps
return ConfiguredComponent {
cc_ann_id = AnnotatedId {
ann_id = this_cid,
ann_pid = package pkg_descr,
ann_cname = componentName component
},
cc_component = component,
cc_public = is_public,
cc_exe_deps = exe_deps,
cc_includes = explicit_includes ++ implicit_includes
}
where
bi = componentBuildInfo component
deps_map = Map.fromList [ ((packageName dep, ann_cname dep), dep)
| dep <- lib_deps ]
is_public = componentName component == CLibName LMainLibName
type ConfiguredComponentMap =
Map PackageName (Map ComponentName (AnnotatedId ComponentId))
toConfiguredComponent
:: PackageDescription
-> ComponentId
-> ConfiguredComponentMap
-> ConfiguredComponentMap
-> Component
-> LogProgress ConfiguredComponent
toConfiguredComponent pkg_descr this_cid lib_dep_map exe_dep_map component = do
lib_deps <-
if newPackageDepsBehaviour pkg_descr
then fmap concat $ forM (targetBuildDepends bi) $ \(Dependency name _ sublibs) -> do
let (pn, _) = fixFakePkgName pkg_descr name
pkg <- case Map.lookup pn lib_dep_map of
Nothing ->
dieProgress $
text "Dependency on unbuildable" <+>
text "package" <+> pretty pn
Just p -> return p
forM (Set.toList sublibs) $ \lib ->
let comp = CLibName lib in
case Map.lookup (CLibName $ LSubLibName $ packageNameToUnqualComponentName name) pkg
<|> Map.lookup comp pkg
of
Nothing ->
dieProgress $
text "Dependency on unbuildable" <+>
text (showLibraryName lib) <+>
text "from" <+> pretty pn
Just v -> return v
else return old_style_lib_deps
mkConfiguredComponent
pkg_descr this_cid
lib_deps exe_deps component
where
bi = componentBuildInfo component
old_style_lib_deps = [ e
| (pn, comp_map) <- Map.toList lib_dep_map
, pn /= packageName pkg_descr
, (cn, e) <- Map.toList comp_map
, cn == CLibName LMainLibName ]
exe_deps = ordNub $
[ exe
| ExeDependency pn cn _ <- getAllToolDependencies pkg_descr bi
, Just exe <- [Map.lookup (CExeName cn) =<< Map.lookup pn exe_dep_map]
]
toConfiguredComponent'
:: Bool
-> FlagAssignment
-> PackageDescription
-> Bool
-> Flag String
-> Flag ComponentId
-> ConfiguredComponentMap
-> Component
-> LogProgress ConfiguredComponent
toConfiguredComponent' use_external_internal_deps flags
pkg_descr deterministic ipid_flag cid_flag
dep_map component = do
cc <- toConfiguredComponent
pkg_descr this_cid
dep_map dep_map component
return $ if use_external_internal_deps
then cc { cc_public = True }
else cc
where
this_cid = computeComponentId deterministic ipid_flag cid_flag (package pkg_descr)
(componentName component) (Just (deps, flags))
deps = [ ann_id aid | m <- Map.elems dep_map
, aid <- Map.elems m ]
extendConfiguredComponentMap
:: ConfiguredComponent
-> ConfiguredComponentMap
-> ConfiguredComponentMap
extendConfiguredComponentMap cc =
Map.insertWith Map.union
(pkgName (cc_pkgid cc))
(Map.singleton (cc_name cc) (cc_ann_id cc))
toConfiguredComponents
:: Bool
-> FlagAssignment
-> Bool
-> Flag String
-> Flag ComponentId
-> PackageDescription
-> ConfiguredComponentMap
-> [Component]
-> LogProgress [ConfiguredComponent]
toConfiguredComponents
use_external_internal_deps flags deterministic ipid_flag cid_flag pkg_descr
dep_map comps
= fmap snd (mapAccumM go dep_map comps)
where
go m component = do
cc <- toConfiguredComponent'
use_external_internal_deps flags pkg_descr
deterministic ipid_flag cid_flag
m component
return (extendConfiguredComponentMap cc m, cc)
newPackageDepsBehaviourMinVersion :: Version
newPackageDepsBehaviourMinVersion = mkVersion [1,7,1]
newPackageDepsBehaviour :: PackageDescription -> Bool
newPackageDepsBehaviour pkg =
specVersion pkg >= newPackageDepsBehaviourMinVersion
fixFakePkgName :: PackageDescription -> PackageName -> (PackageName, ComponentName)
fixFakePkgName pkg_descr pn =
if subLibName `elem` internalLibraries
then (packageName pkg_descr, CLibName (LSubLibName subLibName))
else (pn, CLibName LMainLibName )
where
subLibName = packageNameToUnqualComponentName pn
internalLibraries = mapMaybe (libraryNameString . libName) (allLibraries pkg_descr)