{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}

-- | Utilities to help format error messages for the various CLI commands.
module Distribution.Client.CmdErrorMessages
  ( module Distribution.Client.CmdErrorMessages
  , module Distribution.Client.TargetSelector
  ) where

import Distribution.Client.Compat.Prelude
import Prelude ()

import Distribution.Client.ProjectPlanning
  ( AvailableTarget (..)
  , AvailableTargetStatus (..)
  , CannotPruneDependencies (..)
  , TargetRequested (..)
  )
import Distribution.Client.TargetProblem
  ( TargetProblem (..)
  , TargetProblem'
  )
import Distribution.Client.TargetSelector
  ( ComponentKind (..)
  , ComponentKindFilter
  , SubComponentTarget (..)
  , TargetSelector (..)
  , componentKind
  , showTargetSelector
  )

import Distribution.Package
  ( PackageId
  , PackageName
  , packageId
  , packageName
  )
import Distribution.Simple.Utils
  ( dieWithException
  )
import Distribution.Solver.Types.OptionalStanza
  ( OptionalStanza (..)
  )
import Distribution.Types.ComponentName
  ( ComponentName (..)
  , showComponentName
  )
import Distribution.Types.LibraryName
  ( LibraryName (..)
  )

import qualified Data.List.NonEmpty as NE
import Distribution.Client.Errors

-----------------------
-- Singular or plural
--

-- | A tag used in rendering messages to distinguish singular or plural.
data Plural = Singular | Plural

-- | Used to render a singular or plural version of something
--
-- > plural (listPlural theThings) "it is" "they are"
plural :: Plural -> a -> a -> a
plural :: forall a. Plural -> a -> a -> a
plural Plural
Singular a
si a
_pl = a
si
plural Plural
Plural a
_si a
pl = a
pl

-- | Singular for singleton lists and plural otherwise.
listPlural :: [a] -> Plural
listPlural :: forall a. [a] -> Plural
listPlural [a
_] = Plural
Singular
listPlural [a]
_ = Plural
Plural

--------------------
-- Rendering lists
--

-- | Render a list of things in the style @foo, bar and baz@
renderListCommaAnd :: [String] -> String
renderListCommaAnd :: [String] -> String
renderListCommaAnd [] = String
""
renderListCommaAnd [String
x] = String
x
renderListCommaAnd [String
x, String
x'] = String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" and " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
x'
renderListCommaAnd (String
x : [String]
xs) = String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
renderListCommaAnd [String]
xs

renderListTabular :: [String] -> String
renderListTabular :: [String] -> String
renderListTabular = (String
"\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> ([String] -> String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
unlines ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
"| * " String -> String -> String
forall a. [a] -> [a] -> [a]
++)

renderListPretty :: [String] -> String
renderListPretty :: [String] -> String
renderListPretty [String]
xs =
  if [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
xs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
5
    then [String] -> String
renderListTabular [String]
xs
    else [String] -> String
renderListCommaAnd [String]
xs

-- | Render a list of things in the style @blah blah; this that; and the other@
renderListSemiAnd :: [String] -> String
renderListSemiAnd :: [String] -> String
renderListSemiAnd [] = String
""
renderListSemiAnd [String
x] = String
x
renderListSemiAnd [String
x, String
x'] = String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"; and " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
x'
renderListSemiAnd (String
x : [String]
xs) = String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"; " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
renderListSemiAnd [String]
xs

-- | When rendering lists of things it often reads better to group related
-- things, e.g. grouping components by package name
--
-- > renderListSemiAnd
-- >   [     "the package " ++ prettyShow pkgname ++ " components "
-- >      ++ renderListCommaAnd showComponentName components
-- >   | (pkgname, components) <- sortGroupOn packageName allcomponents ]
sortGroupOn :: Ord b => (a -> b) -> [a] -> [(b, [a])]
sortGroupOn :: forall b a. Ord b => (a -> b) -> [a] -> [(b, [a])]
sortGroupOn a -> b
key =
  (NonEmpty a -> (b, [a])) -> [NonEmpty a] -> [(b, [a])]
forall a b. (a -> b) -> [a] -> [b]
map (\(a
x :| [a]
xs) -> (a -> b
key a
x, a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
xs))
    ([NonEmpty a] -> [(b, [a])])
-> ([a] -> [NonEmpty a]) -> [a] -> [(b, [a])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> Bool) -> [a] -> [NonEmpty a]
forall (f :: * -> *) a.
Foldable f =>
(a -> a -> Bool) -> f a -> [NonEmpty a]
NE.groupBy (b -> b -> Bool
forall a. Eq a => a -> a -> Bool
(==) (b -> b -> Bool) -> (a -> b) -> a -> a -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` a -> b
key)
    ([a] -> [NonEmpty a]) -> ([a] -> [a]) -> [a] -> [NonEmpty a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> Ordering) -> [a] -> [a]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (b -> b -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (b -> b -> Ordering) -> (a -> b) -> a -> a -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` a -> b
key)

----------------------------------------------------
-- Rendering for a few project and package types
--

renderTargetSelector :: TargetSelector -> String
renderTargetSelector :: TargetSelector -> String
renderTargetSelector (TargetPackage TargetImplicitCwd
_ [PackageId]
pkgids Maybe ComponentKindFilter
Nothing) =
  String
"the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> String -> String -> String
forall a. Plural -> a -> a -> a
plural ([PackageId] -> Plural
forall a. [a] -> Plural
listPlural [PackageId]
pkgids) String
"package" String
"packages"
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
renderListCommaAnd ((PackageId -> String) -> [PackageId] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map PackageId -> String
forall a. Pretty a => a -> String
prettyShow [PackageId]
pkgids)
renderTargetSelector (TargetPackage TargetImplicitCwd
_ [PackageId]
pkgids (Just ComponentKindFilter
kfilter)) =
  String
"the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural ComponentKindFilter
kfilter
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> String -> String -> String
forall a. Plural -> a -> a -> a
plural ([PackageId] -> Plural
forall a. [a] -> Plural
listPlural [PackageId]
pkgids) String
"package" String
"packages"
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
renderListCommaAnd ((PackageId -> String) -> [PackageId] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map PackageId -> String
forall a. Pretty a => a -> String
prettyShow [PackageId]
pkgids)
renderTargetSelector (TargetPackageNamed PackageName
pkgname Maybe ComponentKindFilter
Nothing) =
  String
"the package " String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
renderTargetSelector (TargetPackageNamed PackageName
pkgname (Just ComponentKindFilter
kfilter)) =
  String
"the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural ComponentKindFilter
kfilter
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
renderTargetSelector (TargetAllPackages Maybe ComponentKindFilter
Nothing) =
  String
"all the packages in the project"
renderTargetSelector (TargetAllPackages (Just ComponentKindFilter
kfilter)) =
  String
"all the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural ComponentKindFilter
kfilter
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in the project"
renderTargetSelector (TargetComponent PackageId
pkgid ComponentName
cname SubComponentTarget
subtarget) =
  SubComponentTarget -> String
renderSubComponentTarget SubComponentTarget
subtarget
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> ComponentName -> String
renderComponentName (PackageId -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName PackageId
pkgid) ComponentName
cname
renderTargetSelector (TargetComponentUnknown PackageName
pkgname (Left UnqualComponentName
ucname) SubComponentTarget
subtarget) =
  SubComponentTarget -> String
renderSubComponentTarget SubComponentTarget
subtarget
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"the component "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
ucname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
renderTargetSelector (TargetComponentUnknown PackageName
pkgname (Right ComponentName
cname) SubComponentTarget
subtarget) =
  SubComponentTarget -> String
renderSubComponentTarget SubComponentTarget
subtarget
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> ComponentName -> String
renderComponentName PackageName
pkgname ComponentName
cname

renderSubComponentTarget :: SubComponentTarget -> String
renderSubComponentTarget :: SubComponentTarget -> String
renderSubComponentTarget SubComponentTarget
WholeComponent = String
""
renderSubComponentTarget (FileTarget String
filename) =
  String
"the file " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in "
renderSubComponentTarget (ModuleTarget ModuleName
modname) =
  String
"the module " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ModuleName -> String
forall a. Pretty a => a -> String
prettyShow ModuleName
modname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in "

renderOptionalStanza :: Plural -> OptionalStanza -> String
renderOptionalStanza :: Plural -> OptionalStanza -> String
renderOptionalStanza Plural
Singular OptionalStanza
TestStanzas = String
"test suite"
renderOptionalStanza Plural
Plural OptionalStanza
TestStanzas = String
"test suites"
renderOptionalStanza Plural
Singular OptionalStanza
BenchStanzas = String
"benchmark"
renderOptionalStanza Plural
Plural OptionalStanza
BenchStanzas = String
"benchmarks"

-- | The optional stanza type (test suite or benchmark), if it is one.
optionalStanza :: ComponentName -> Maybe OptionalStanza
optionalStanza :: ComponentName -> Maybe OptionalStanza
optionalStanza (CTestName UnqualComponentName
_) = OptionalStanza -> Maybe OptionalStanza
forall a. a -> Maybe a
Just OptionalStanza
TestStanzas
optionalStanza (CBenchName UnqualComponentName
_) = OptionalStanza -> Maybe OptionalStanza
forall a. a -> Maybe a
Just OptionalStanza
BenchStanzas
optionalStanza ComponentName
_ = Maybe OptionalStanza
forall a. Maybe a
Nothing

-- | Does the 'TargetSelector' potentially refer to one package or many?
targetSelectorPluralPkgs :: TargetSelector -> Plural
targetSelectorPluralPkgs :: TargetSelector -> Plural
targetSelectorPluralPkgs (TargetAllPackages Maybe ComponentKindFilter
_) = Plural
Plural
targetSelectorPluralPkgs (TargetPackage TargetImplicitCwd
_ [PackageId]
pids Maybe ComponentKindFilter
_) = [PackageId] -> Plural
forall a. [a] -> Plural
listPlural [PackageId]
pids
targetSelectorPluralPkgs (TargetPackageNamed PackageName
_ Maybe ComponentKindFilter
_) = Plural
Singular
targetSelectorPluralPkgs TargetComponent{} = Plural
Singular
targetSelectorPluralPkgs TargetComponentUnknown{} = Plural
Singular

-- | Does the 'TargetSelector' refer to packages or to components?
targetSelectorRefersToPkgs :: TargetSelector -> Bool
targetSelectorRefersToPkgs :: TargetSelector -> Bool
targetSelectorRefersToPkgs (TargetAllPackages Maybe ComponentKindFilter
mkfilter) = Maybe ComponentKindFilter -> Bool
forall a. Maybe a -> Bool
isNothing Maybe ComponentKindFilter
mkfilter
targetSelectorRefersToPkgs (TargetPackage TargetImplicitCwd
_ [PackageId]
_ Maybe ComponentKindFilter
mkfilter) = Maybe ComponentKindFilter -> Bool
forall a. Maybe a -> Bool
isNothing Maybe ComponentKindFilter
mkfilter
targetSelectorRefersToPkgs (TargetPackageNamed PackageName
_ Maybe ComponentKindFilter
mkfilter) = Maybe ComponentKindFilter -> Bool
forall a. Maybe a -> Bool
isNothing Maybe ComponentKindFilter
mkfilter
targetSelectorRefersToPkgs TargetComponent{} = Bool
False
targetSelectorRefersToPkgs TargetComponentUnknown{} = Bool
False

targetSelectorFilter :: TargetSelector -> Maybe ComponentKindFilter
targetSelectorFilter :: TargetSelector -> Maybe ComponentKindFilter
targetSelectorFilter (TargetPackage TargetImplicitCwd
_ [PackageId]
_ Maybe ComponentKindFilter
mkfilter) = Maybe ComponentKindFilter
mkfilter
targetSelectorFilter (TargetPackageNamed PackageName
_ Maybe ComponentKindFilter
mkfilter) = Maybe ComponentKindFilter
mkfilter
targetSelectorFilter (TargetAllPackages Maybe ComponentKindFilter
mkfilter) = Maybe ComponentKindFilter
mkfilter
targetSelectorFilter TargetComponent{} = Maybe ComponentKindFilter
forall a. Maybe a
Nothing
targetSelectorFilter TargetComponentUnknown{} = Maybe ComponentKindFilter
forall a. Maybe a
Nothing

renderComponentName :: PackageName -> ComponentName -> String
renderComponentName :: PackageName -> ComponentName -> String
renderComponentName PackageName
pkgname (CLibName LibraryName
LMainLibName) = String
"library " String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
renderComponentName PackageName
_ (CLibName (LSubLibName UnqualComponentName
name)) = String
"library " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
name
renderComponentName PackageName
_ (CFLibName UnqualComponentName
name) = String
"foreign library " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
name
renderComponentName PackageName
_ (CExeName UnqualComponentName
name) = String
"executable " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
name
renderComponentName PackageName
_ (CTestName UnqualComponentName
name) = String
"test suite " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
name
renderComponentName PackageName
_ (CBenchName UnqualComponentName
name) = String
"benchmark " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
name

renderComponentKind :: Plural -> ComponentKind -> String
renderComponentKind :: Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Singular ComponentKindFilter
ckind = case ComponentKindFilter
ckind of
  ComponentKindFilter
LibKind -> String
"library" -- internal/sub libs?
  ComponentKindFilter
FLibKind -> String
"foreign library"
  ComponentKindFilter
ExeKind -> String
"executable"
  ComponentKindFilter
TestKind -> String
"test suite"
  ComponentKindFilter
BenchKind -> String
"benchmark"
renderComponentKind Plural
Plural ComponentKindFilter
ckind = case ComponentKindFilter
ckind of
  ComponentKindFilter
LibKind -> String
"libraries" -- internal/sub libs?
  ComponentKindFilter
FLibKind -> String
"foreign libraries"
  ComponentKindFilter
ExeKind -> String
"executables"
  ComponentKindFilter
TestKind -> String
"test suites"
  ComponentKindFilter
BenchKind -> String
"benchmarks"

-------------------------------------------------------
-- Rendering error messages for TargetProblem
--

-- | Default implementation of 'reportTargetProblems' simply renders one problem per line.
reportTargetProblems :: Verbosity -> String -> [TargetProblem'] -> IO a
reportTargetProblems :: forall a. Verbosity -> String -> [TargetProblem'] -> IO a
reportTargetProblems Verbosity
verbosity String
verb =
  Verbosity -> CabalInstallException -> IO a
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalInstallException -> IO a)
-> ([TargetProblem'] -> CabalInstallException)
-> [TargetProblem']
-> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> CabalInstallException
CmdErrorMessages ([String] -> CabalInstallException)
-> ([TargetProblem'] -> [String])
-> [TargetProblem']
-> CabalInstallException
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TargetProblem' -> String) -> [TargetProblem'] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> (Void -> String) -> TargetProblem' -> String
forall a. String -> (a -> String) -> TargetProblem a -> String
renderTargetProblem String
verb Void -> String
forall a. Void -> a
absurd)

-- | Default implementation of 'renderTargetProblem'.
renderTargetProblem
  :: String
  -- ^ verb
  -> (a -> String)
  -- ^ how to render custom problems
  -> TargetProblem a
  -> String
renderTargetProblem :: forall a. String -> (a -> String) -> TargetProblem a -> String
renderTargetProblem String
_verb a -> String
f (CustomTargetProblem a
x) = a -> String
f a
x
renderTargetProblem String
verb a -> String
_ (TargetProblemNoneEnabled TargetSelector
targetSelector [AvailableTarget ()]
targets) =
  String -> TargetSelector -> [AvailableTarget ()] -> String
renderTargetProblemNoneEnabled String
verb TargetSelector
targetSelector [AvailableTarget ()]
targets
renderTargetProblem String
verb a -> String
_ (TargetProblemNoTargets TargetSelector
targetSelector) =
  String -> TargetSelector -> String
renderTargetProblemNoTargets String
verb TargetSelector
targetSelector
renderTargetProblem String
verb a -> String
_ (TargetNotInProject PackageName
pkgname) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", it is not "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"in this project (either directly or indirectly). If you want to add it "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"to the project then edit the cabal.project file."
renderTargetProblem String
verb a -> String
_ (TargetAvailableInIndex PackageName
pkgname) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", it is not "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"in this project (either directly or indirectly), but it is in the current "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"package index. If you want to add it to the project then edit the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"cabal.project file."
renderTargetProblem String
verb a -> String
_ (TargetComponentNotProjectLocal PackageId
pkgid ComponentName
cname SubComponentTarget
_) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
cname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageId -> String
forall a. Pretty a => a -> String
prettyShow PackageId
pkgid
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is not local to the project, and cabal "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"does not currently support building test suites or benchmarks of "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"non-local dependencies. To run test suites or benchmarks from "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"dependencies you can unpack the package locally and adjust the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"cabal.project file to include that package directory."
renderTargetProblem String
verb a -> String
_ (TargetComponentNotBuildable PackageId
pkgid ComponentName
cname SubComponentTarget
_) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
cname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because it is "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"marked as 'buildable: False' within the '"
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow (PackageId -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName PackageId
pkgid)
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".cabal' file (at least for the current configuration). If you believe it "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"should be buildable then check the .cabal file to see if the buildable "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"property is conditional on flags. Alternatively you may simply have to "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"edit the .cabal file to declare it as buildable and fix any resulting "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"build problems."
renderTargetProblem String
verb a -> String
_ (TargetOptionalStanzaDisabledByUser PackageId
_ ComponentName
cname SubComponentTarget
_) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
cname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"building "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
compkinds
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" has been explicitly disabled in the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"configuration. You can adjust this configuration in the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"cabal.project{.local} file either for all packages in the project or on "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"a per-package basis. Note that if you do not explicitly disable "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
compkinds
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" then the solver will merely try to make a plan with "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"them available, so you may wish to explicitly enable them which will "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"require the solver to find a plan with them available or to fail with an "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"explanation."
  where
    compkinds :: String
compkinds = Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural (ComponentName -> ComponentKindFilter
componentKind ComponentName
cname)
renderTargetProblem String
verb a -> String
_ (TargetOptionalStanzaDisabledBySolver PackageId
pkgid ComponentName
cname SubComponentTarget
_) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
cname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"solver did not find a plan that included the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
compkinds
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" for "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageId -> String
forall a. Pretty a => a -> String
prettyShow PackageId
pkgid
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
". It is probably worth trying again with "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
compkinds
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" explicitly enabled in the configuration in the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"cabal.project{.local} file. This will ask the solver to find a plan with "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
compkinds
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" available. It will either fail with an "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"explanation or find a different plan that uses different versions of some "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"other packages. Use the '--dry-run' flag to see package versions and "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"check that you are happy with the choices."
  where
    compkinds :: String
compkinds = Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural (ComponentName -> ComponentKindFilter
componentKind ComponentName
cname)
renderTargetProblem String
verb a -> String
_ (TargetProblemUnknownComponent PackageName
pkgname Either UnqualComponentName ComponentName
ecname) =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ( case Either UnqualComponentName ComponentName
ecname of
          Left UnqualComponentName
ucname -> String
"component " String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnqualComponentName -> String
forall a. Pretty a => a -> String
prettyShow UnqualComponentName
ucname
          Right ComponentName
cname -> PackageName -> ComponentName -> String
renderComponentName PackageName
pkgname ComponentName
cname
       )
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" from the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", because the package does not contain a "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ( case Either UnqualComponentName ComponentName
ecname of
          Left UnqualComponentName
_ -> String
"component"
          Right ComponentName
cname -> Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Singular (ComponentName -> ComponentKindFilter
componentKind ComponentName
cname)
       )
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" with that name."
renderTargetProblem String
verb a -> String
_ (TargetProblemNoSuchPackage PackageId
pkgid) =
  String
"Internal error when trying to "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageId -> String
forall a. Pretty a => a -> String
prettyShow PackageId
pkgid
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
". The package is not in the set of available targets "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"for the project plan, which would suggest an inconsistency "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"between readTargetSelectors and resolveTargets."
renderTargetProblem String
verb a -> String
_ (TargetProblemNoSuchComponent PackageId
pkgid ComponentName
cname) =
  String
"Internal error when trying to "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
cname
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" from the package "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageId -> String
forall a. Pretty a => a -> String
prettyShow PackageId
pkgid
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
". The package,component pair is not in the set of available targets "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"for the project plan, which would suggest an inconsistency "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"between readTargetSelectors and resolveTargets."

------------------------------------------------------------
-- Rendering error messages for TargetProblemNoneEnabled
--

-- | Several commands have a @TargetProblemNoneEnabled@ problem constructor.
-- This renders an error message for those cases.
renderTargetProblemNoneEnabled
  :: String
  -> TargetSelector
  -> [AvailableTarget ()]
  -> String
renderTargetProblemNoneEnabled :: String -> TargetSelector -> [AvailableTarget ()] -> String
renderTargetProblemNoneEnabled String
verb TargetSelector
targetSelector [AvailableTarget ()]
targets =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ TargetSelector -> String
renderTargetSelector TargetSelector
targetSelector
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because none of the components are available to build: "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
renderListSemiAnd
      [ case (AvailableTargetStatus ()
status, Maybe OptionalStanza
mstanza) of
        (AvailableTargetStatus ()
TargetDisabledByUser, Just OptionalStanza
stanza) ->
          [String] -> String
renderListCommaAnd
            [ String
"the " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
availableTargetComponentName
            | AvailableTarget{ComponentName
availableTargetComponentName :: ComponentName
availableTargetComponentName :: forall k. AvailableTarget k -> ComponentName
availableTargetComponentName} <- [AvailableTarget ()]
targets'
            ]
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> String -> String -> String
forall a. Plural -> a -> a -> a
plural ([AvailableTarget ()] -> Plural
forall a. [a] -> Plural
listPlural [AvailableTarget ()]
targets') String
" is " String
" are "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" not available because building "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> OptionalStanza -> String
renderOptionalStanza Plural
Plural OptionalStanza
stanza
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" has been disabled in the configuration"
        (AvailableTargetStatus ()
TargetDisabledBySolver, Just OptionalStanza
stanza) ->
          [String] -> String
renderListCommaAnd
            [ String
"the " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
availableTargetComponentName
            | AvailableTarget{ComponentName
availableTargetComponentName :: forall k. AvailableTarget k -> ComponentName
availableTargetComponentName :: ComponentName
availableTargetComponentName} <- [AvailableTarget ()]
targets'
            ]
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> String -> String -> String
forall a. Plural -> a -> a -> a
plural ([AvailableTarget ()] -> Plural
forall a. [a] -> Plural
listPlural [AvailableTarget ()]
targets') String
" is " String
" are "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"not available because the solver picked a plan that does not "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"include the "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> OptionalStanza -> String
renderOptionalStanza Plural
Plural OptionalStanza
stanza
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", perhaps because no such plan exists. To see the error message "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"explaining the problems with such plans, force the solver to "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"include the "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> OptionalStanza -> String
renderOptionalStanza Plural
Plural OptionalStanza
stanza
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" for all "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"packages, by adding the line 'tests: True' to the "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'cabal.project.local' file."
        (AvailableTargetStatus ()
TargetNotBuildable, Maybe OptionalStanza
_) ->
          [String] -> String
renderListCommaAnd
            [ String
"the " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
availableTargetComponentName
            | AvailableTarget{ComponentName
availableTargetComponentName :: forall k. AvailableTarget k -> ComponentName
availableTargetComponentName :: ComponentName
availableTargetComponentName} <- [AvailableTarget ()]
targets'
            ]
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> String -> String -> String
forall a. Plural -> a -> a -> a
plural ([AvailableTarget ()] -> Plural
forall a. [a] -> Plural
listPlural [AvailableTarget ()]
targets') String
" is " String
" are all "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"marked as 'buildable: False'"
        (AvailableTargetStatus ()
TargetNotLocal, Maybe OptionalStanza
_) ->
          [String] -> String
renderListCommaAnd
            [ String
"the " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
availableTargetComponentName
            | AvailableTarget{ComponentName
availableTargetComponentName :: forall k. AvailableTarget k -> ComponentName
availableTargetComponentName :: ComponentName
availableTargetComponentName} <- [AvailableTarget ()]
targets'
            ]
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" cannot be built because cabal does not currently support "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"building test suites or benchmarks of non-local dependencies"
        (TargetBuildable () TargetRequested
TargetNotRequestedByDefault, Just OptionalStanza
stanza) ->
          [String] -> String
renderListCommaAnd
            [ String
"the " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ComponentName -> String
showComponentName ComponentName
availableTargetComponentName
            | AvailableTarget{ComponentName
availableTargetComponentName :: forall k. AvailableTarget k -> ComponentName
availableTargetComponentName :: ComponentName
availableTargetComponentName} <- [AvailableTarget ()]
targets'
            ]
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" will not be built because "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> OptionalStanza -> String
renderOptionalStanza Plural
Plural OptionalStanza
stanza
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" are not built by default in the current configuration (but you "
            String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"can still build them specifically)" -- TODO: say how
        (AvailableTargetStatus (), Maybe OptionalStanza)
_ ->
          String -> String
forall a. HasCallStack => String -> a
error (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
            String
"renderBuildTargetProblem: unexpected status "
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ (AvailableTargetStatus (), Maybe OptionalStanza) -> String
forall a. Show a => a -> String
show (AvailableTargetStatus ()
status, Maybe OptionalStanza
mstanza)
      | ((AvailableTargetStatus ()
status, Maybe OptionalStanza
mstanza), [AvailableTarget ()]
targets') <- (AvailableTarget ()
 -> (AvailableTargetStatus (), Maybe OptionalStanza))
-> [AvailableTarget ()]
-> [((AvailableTargetStatus (), Maybe OptionalStanza),
     [AvailableTarget ()])]
forall b a. Ord b => (a -> b) -> [a] -> [(b, [a])]
sortGroupOn AvailableTarget ()
-> (AvailableTargetStatus (), Maybe OptionalStanza)
forall {k}.
AvailableTarget k
-> (AvailableTargetStatus k, Maybe OptionalStanza)
groupingKey [AvailableTarget ()]
targets
      ]
  where
    groupingKey :: AvailableTarget k
-> (AvailableTargetStatus k, Maybe OptionalStanza)
groupingKey AvailableTarget k
t =
      ( AvailableTarget k -> AvailableTargetStatus k
forall k. AvailableTarget k -> AvailableTargetStatus k
availableTargetStatus AvailableTarget k
t
      , case AvailableTarget k -> AvailableTargetStatus k
forall k. AvailableTarget k -> AvailableTargetStatus k
availableTargetStatus AvailableTarget k
t of
          AvailableTargetStatus k
TargetNotBuildable -> Maybe OptionalStanza
forall a. Maybe a
Nothing
          AvailableTargetStatus k
TargetNotLocal -> Maybe OptionalStanza
forall a. Maybe a
Nothing
          AvailableTargetStatus k
_ -> ComponentName -> Maybe OptionalStanza
optionalStanza (AvailableTarget k -> ComponentName
forall k. AvailableTarget k -> ComponentName
availableTargetComponentName AvailableTarget k
t)
      )

------------------------------------------------------------
-- Rendering error messages for TargetProblemNoneEnabled
--

-- | Several commands have a @TargetProblemNoTargets@ problem constructor.
-- This renders an error message for those cases.
renderTargetProblemNoTargets :: String -> TargetSelector -> String
renderTargetProblemNoTargets :: String -> TargetSelector -> String
renderTargetProblemNoTargets String
verb TargetSelector
targetSelector =
  String
"Cannot "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
verb
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ TargetSelector -> String
renderTargetSelector TargetSelector
targetSelector
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" because "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ TargetSelector -> String
reason TargetSelector
targetSelector
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
". "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"Check the .cabal "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> String -> String -> String
forall a. Plural -> a -> a -> a
plural
      (TargetSelector -> Plural
targetSelectorPluralPkgs TargetSelector
targetSelector)
      String
"file for the package and make sure that it properly declares "
      String
"files for the packages and make sure that they properly declare "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"the components that you expect."
  where
    reason :: TargetSelector -> String
reason (TargetPackage TargetImplicitCwd
_ [PackageId]
_ Maybe ComponentKindFilter
Nothing) =
      String
"it does not contain any components at all"
    reason (TargetPackage TargetImplicitCwd
_ [PackageId]
_ (Just ComponentKindFilter
kfilter)) =
      String
"it does not contain any " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural ComponentKindFilter
kfilter
    reason (TargetPackageNamed PackageName
_ Maybe ComponentKindFilter
Nothing) =
      String
"it does not contain any components at all"
    reason (TargetPackageNamed PackageName
_ (Just ComponentKindFilter
kfilter)) =
      String
"it does not contain any " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural ComponentKindFilter
kfilter
    reason (TargetAllPackages Maybe ComponentKindFilter
Nothing) =
      String
"none of them contain any components at all"
    reason (TargetAllPackages (Just ComponentKindFilter
kfilter)) =
      String
"none of the packages contain any "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ Plural -> ComponentKindFilter -> String
renderComponentKind Plural
Plural ComponentKindFilter
kfilter
    reason ts :: TargetSelector
ts@TargetComponent{} =
      String -> String
forall a. HasCallStack => String -> a
error (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
"renderTargetProblemNoTargets: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ TargetSelector -> String
forall a. Show a => a -> String
show TargetSelector
ts
    reason ts :: TargetSelector
ts@TargetComponentUnknown{} =
      String -> String
forall a. HasCallStack => String -> a
error (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
"renderTargetProblemNoTargets: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ TargetSelector -> String
forall a. Show a => a -> String
show TargetSelector
ts

-----------------------------------------------------------
-- Rendering error messages for CannotPruneDependencies
--

renderCannotPruneDependencies :: CannotPruneDependencies -> String
renderCannotPruneDependencies :: CannotPruneDependencies -> String
renderCannotPruneDependencies (CannotPruneDependencies [(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
brokenPackages) =
  String
"Cannot select only the dependencies (as requested by the "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'--only-dependencies' flag), "
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ ( case [PackageId]
pkgids of
          [PackageId
pkgid] -> String
"the package " String -> String -> String
forall a. [a] -> [a] -> [a]
++ PackageId -> String
forall a. Pretty a => a -> String
prettyShow PackageId
pkgid String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is "
          [PackageId]
_ ->
            String
"the packages "
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
renderListCommaAnd ((PackageId -> String) -> [PackageId] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map PackageId -> String
forall a. Pretty a => a -> String
prettyShow [PackageId]
pkgids)
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" are "
       )
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"required by a dependency of one of the other targets."
  where
    -- throw away the details and just list the deps that are needed
    pkgids :: [PackageId]
    pkgids :: [PackageId]
pkgids = [PackageId] -> [PackageId]
forall a. Eq a => [a] -> [a]
nub ([PackageId] -> [PackageId])
-> ([(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
    -> [PackageId])
-> [(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
-> [PackageId]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ElaboratedPlanPackage -> PackageId)
-> [ElaboratedPlanPackage] -> [PackageId]
forall a b. (a -> b) -> [a] -> [b]
map ElaboratedPlanPackage -> PackageId
forall pkg. Package pkg => pkg -> PackageId
packageId ([ElaboratedPlanPackage] -> [PackageId])
-> ([(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
    -> [ElaboratedPlanPackage])
-> [(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
-> [PackageId]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ElaboratedPlanPackage, [ElaboratedPlanPackage])
 -> [ElaboratedPlanPackage])
-> [(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
-> [ElaboratedPlanPackage]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (ElaboratedPlanPackage, [ElaboratedPlanPackage])
-> [ElaboratedPlanPackage]
forall a b. (a, b) -> b
snd ([(ElaboratedPlanPackage, [ElaboratedPlanPackage])] -> [PackageId])
-> [(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
-> [PackageId]
forall a b. (a -> b) -> a -> b
$ [(ElaboratedPlanPackage, [ElaboratedPlanPackage])]
brokenPackages

{-
           ++ "Syntax:\n"
           ++ " - build [package]\n"
           ++ " - build [package:]component\n"
           ++ " - build [package:][component:]module\n"
           ++ " - build [package:][component:]file\n"
           ++ " where\n"
           ++ "  package is a package name, package dir or .cabal file\n\n"
           ++ "Examples:\n"
           ++ " - build foo            -- package name\n"
           ++ " - build tests          -- component name\n"
           ++ "    (name of library, executable, test-suite or benchmark)\n"
           ++ " - build Data.Foo       -- module name\n"
           ++ " - build Data/Foo.hsc   -- file name\n\n"
           ++ "An ambiguous target can be qualified by package, component\n"
           ++ "and/or component kind (lib|exe|test|bench|flib)\n"
           ++ " - build foo:tests      -- component qualified by package\n"
           ++ " - build tests:Data.Foo -- module qualified by component\n"
           ++ " - build lib:foo        -- component qualified by kind"
-}