{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Module exporting the 'NamedComponent' type and related functions.

module Stack.Types.NamedComponent
  ( NamedComponent (..)
  , renderComponent
  , renderComponentTo
  , renderPkgComponents
  , renderPkgComponent
  , exeComponents
  , testComponents
  , benchComponents
  , subLibComponents
  , isCLib
  , isCSubLib
  , isCExe
  , isCTest
  , isCBench
  , isPotentialDependency
  , splitComponents
  ) where

import qualified Data.Set as Set
import qualified Data.Text as T
import           Stack.Prelude

-- | Type representing components of a fully-resolved Cabal package.

data NamedComponent
  = CLib
    -- The \'main\' unnamed library component.

  | CSubLib !Text
    -- A named \'subsidiary\' or \'ancillary\` library component (sub-library).

  | CFlib !Text
    -- A foreign library.

  | CExe !Text
    -- A named executable component.

  | CTest !Text
    -- A named test-suite component.

  | CBench !Text
    -- A named benchmark component.

  deriving (NamedComponent -> NamedComponent -> Bool
(NamedComponent -> NamedComponent -> Bool)
-> (NamedComponent -> NamedComponent -> Bool) -> Eq NamedComponent
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NamedComponent -> NamedComponent -> Bool
== :: NamedComponent -> NamedComponent -> Bool
$c/= :: NamedComponent -> NamedComponent -> Bool
/= :: NamedComponent -> NamedComponent -> Bool
Eq, Eq NamedComponent
Eq NamedComponent =>
(NamedComponent -> NamedComponent -> Ordering)
-> (NamedComponent -> NamedComponent -> Bool)
-> (NamedComponent -> NamedComponent -> Bool)
-> (NamedComponent -> NamedComponent -> Bool)
-> (NamedComponent -> NamedComponent -> Bool)
-> (NamedComponent -> NamedComponent -> NamedComponent)
-> (NamedComponent -> NamedComponent -> NamedComponent)
-> Ord NamedComponent
NamedComponent -> NamedComponent -> Bool
NamedComponent -> NamedComponent -> Ordering
NamedComponent -> NamedComponent -> NamedComponent
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: NamedComponent -> NamedComponent -> Ordering
compare :: NamedComponent -> NamedComponent -> Ordering
$c< :: NamedComponent -> NamedComponent -> Bool
< :: NamedComponent -> NamedComponent -> Bool
$c<= :: NamedComponent -> NamedComponent -> Bool
<= :: NamedComponent -> NamedComponent -> Bool
$c> :: NamedComponent -> NamedComponent -> Bool
> :: NamedComponent -> NamedComponent -> Bool
$c>= :: NamedComponent -> NamedComponent -> Bool
>= :: NamedComponent -> NamedComponent -> Bool
$cmax :: NamedComponent -> NamedComponent -> NamedComponent
max :: NamedComponent -> NamedComponent -> NamedComponent
$cmin :: NamedComponent -> NamedComponent -> NamedComponent
min :: NamedComponent -> NamedComponent -> NamedComponent
Ord, Int -> NamedComponent -> ShowS
[NamedComponent] -> ShowS
NamedComponent -> String
(Int -> NamedComponent -> ShowS)
-> (NamedComponent -> String)
-> ([NamedComponent] -> ShowS)
-> Show NamedComponent
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NamedComponent -> ShowS
showsPrec :: Int -> NamedComponent -> ShowS
$cshow :: NamedComponent -> String
show :: NamedComponent -> String
$cshowList :: [NamedComponent] -> ShowS
showList :: [NamedComponent] -> ShowS
Show)

-- | Render a component to anything with an "IsString" instance. For 'Text'

-- prefer 'renderComponent'.

renderComponentTo :: IsString a => NamedComponent -> a
renderComponentTo :: forall a. IsString a => NamedComponent -> a
renderComponentTo = String -> a
forall a. IsString a => String -> a
fromString (String -> a) -> (NamedComponent -> String) -> NamedComponent -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack (Text -> String)
-> (NamedComponent -> Text) -> NamedComponent -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NamedComponent -> Text
renderComponent

renderComponent :: NamedComponent -> Text
renderComponent :: NamedComponent -> Text
renderComponent NamedComponent
CLib = Text
"lib"
renderComponent (CSubLib Text
x) = Text
"sub-lib:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x
renderComponent (CFlib Text
x) = Text
"flib:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x
renderComponent (CExe Text
x) = Text
"exe:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x
renderComponent (CTest Text
x) = Text
"test:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x
renderComponent (CBench Text
x) = Text
"bench:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x

renderPkgComponents :: [(PackageName, NamedComponent)] -> Text
renderPkgComponents :: [(PackageName, NamedComponent)] -> Text
renderPkgComponents = Text -> [Text] -> Text
T.intercalate Text
" " ([Text] -> Text)
-> ([(PackageName, NamedComponent)] -> [Text])
-> [(PackageName, NamedComponent)]
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((PackageName, NamedComponent) -> Text)
-> [(PackageName, NamedComponent)] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (PackageName, NamedComponent) -> Text
renderPkgComponent

renderPkgComponent :: (PackageName, NamedComponent) -> Text
renderPkgComponent :: (PackageName, NamedComponent) -> Text
renderPkgComponent (PackageName
pkg, NamedComponent
comp) =
  PackageName -> Text
forall a. IsString a => PackageName -> a
fromPackageName PackageName
pkg Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
":" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> NamedComponent -> Text
renderComponent NamedComponent
comp

exeComponents :: Set NamedComponent -> Set Text
exeComponents :: Set NamedComponent -> Set Text
exeComponents = [Text] -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList ([Text] -> Set Text)
-> (Set NamedComponent -> [Text]) -> Set NamedComponent -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NamedComponent -> Maybe Text) -> [NamedComponent] -> [Text]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe NamedComponent -> Maybe Text
mExeName ([NamedComponent] -> [Text])
-> (Set NamedComponent -> [NamedComponent])
-> Set NamedComponent
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set NamedComponent -> [NamedComponent]
forall a. Set a -> [a]
Set.toList
 where
  mExeName :: NamedComponent -> Maybe Text
mExeName (CExe Text
name) = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name
  mExeName NamedComponent
_ = Maybe Text
forall a. Maybe a
Nothing

testComponents :: Set NamedComponent -> Set Text
testComponents :: Set NamedComponent -> Set Text
testComponents = [Text] -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList ([Text] -> Set Text)
-> (Set NamedComponent -> [Text]) -> Set NamedComponent -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NamedComponent -> Maybe Text) -> [NamedComponent] -> [Text]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe NamedComponent -> Maybe Text
mTestName ([NamedComponent] -> [Text])
-> (Set NamedComponent -> [NamedComponent])
-> Set NamedComponent
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set NamedComponent -> [NamedComponent]
forall a. Set a -> [a]
Set.toList
 where
  mTestName :: NamedComponent -> Maybe Text
mTestName (CTest Text
name) = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name
  mTestName NamedComponent
_ = Maybe Text
forall a. Maybe a
Nothing

benchComponents :: Set NamedComponent -> Set Text
benchComponents :: Set NamedComponent -> Set Text
benchComponents = [Text] -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList ([Text] -> Set Text)
-> (Set NamedComponent -> [Text]) -> Set NamedComponent -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NamedComponent -> Maybe Text) -> [NamedComponent] -> [Text]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe NamedComponent -> Maybe Text
mBenchName ([NamedComponent] -> [Text])
-> (Set NamedComponent -> [NamedComponent])
-> Set NamedComponent
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set NamedComponent -> [NamedComponent]
forall a. Set a -> [a]
Set.toList
 where
  mBenchName :: NamedComponent -> Maybe Text
mBenchName (CBench Text
name) = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name
  mBenchName NamedComponent
_ = Maybe Text
forall a. Maybe a
Nothing

subLibComponents :: Set NamedComponent -> Set Text
subLibComponents :: Set NamedComponent -> Set Text
subLibComponents = [Text] -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList ([Text] -> Set Text)
-> (Set NamedComponent -> [Text]) -> Set NamedComponent -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NamedComponent -> Maybe Text) -> [NamedComponent] -> [Text]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe NamedComponent -> Maybe Text
mSubLibName ([NamedComponent] -> [Text])
-> (Set NamedComponent -> [NamedComponent])
-> Set NamedComponent
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Set NamedComponent -> [NamedComponent]
forall a. Set a -> [a]
Set.toList
 where
  mSubLibName :: NamedComponent -> Maybe Text
mSubLibName (CSubLib Text
name) = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name
  mSubLibName NamedComponent
_ = Maybe Text
forall a. Maybe a
Nothing

isCLib :: NamedComponent -> Bool
isCLib :: NamedComponent -> Bool
isCLib CLib{} = Bool
True
isCLib NamedComponent
_ = Bool
False

isCSubLib :: NamedComponent -> Bool
isCSubLib :: NamedComponent -> Bool
isCSubLib CSubLib{} = Bool
True
isCSubLib NamedComponent
_ = Bool
False

isCExe :: NamedComponent -> Bool
isCExe :: NamedComponent -> Bool
isCExe CExe{} = Bool
True
isCExe NamedComponent
_ = Bool
False

isCTest :: NamedComponent -> Bool
isCTest :: NamedComponent -> Bool
isCTest CTest{} = Bool
True
isCTest NamedComponent
_ = Bool
False

isCBench :: NamedComponent -> Bool
isCBench :: NamedComponent -> Bool
isCBench CBench{} = Bool
True
isCBench NamedComponent
_ = Bool
False

isPotentialDependency :: NamedComponent -> Bool
isPotentialDependency :: NamedComponent -> Bool
isPotentialDependency NamedComponent
v = NamedComponent -> Bool
isCLib NamedComponent
v Bool -> Bool -> Bool
|| NamedComponent -> Bool
isCSubLib NamedComponent
v Bool -> Bool -> Bool
|| NamedComponent -> Bool
isCExe NamedComponent
v

-- | A function to split the given list of components into sets of the names of

-- the named components by the type of component (sub-libraries, executables,

-- test-suites, benchmarks), ignoring any 'main' unnamed library component or

-- foreign library component. This function should be used very sparingly; more

-- often than not, you can keep/parse the components split from the start.

splitComponents ::
     [NamedComponent]
  -> ( Set Text
       -- ^ Sub-libraries.

     , Set Text
       -- ^ Executables.

     , Set Text
       -- ^ Test-suites.

     , Set Text
       -- ^ Benchmarks.

     )
splitComponents :: [NamedComponent] -> (Set Text, Set Text, Set Text, Set Text)
splitComponents =
  ([Text] -> [Text])
-> ([Text] -> [Text])
-> ([Text] -> [Text])
-> ([Text] -> [Text])
-> [NamedComponent]
-> (Set Text, Set Text, Set Text, Set Text)
forall {a} {a} {a} {a}.
(Ord a, Ord a, Ord a, Ord a) =>
([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [Text]
forall a. a -> a
id [Text] -> [Text]
forall a. a -> a
id [Text] -> [Text]
forall a. a -> a
id [Text] -> [Text]
forall a. a -> a
id
 where
  run :: ([a] -> [a]) -> Set a
run [a] -> [a]
c = [a] -> Set a
forall a. Ord a => [a] -> Set a
Set.fromList ([a] -> Set a) -> [a] -> Set a
forall a b. (a -> b) -> a -> b
$ [a] -> [a]
c []
  go :: ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b [] = (([Text] -> [a]) -> Set a
forall {a} {a}. Ord a => ([a] -> [a]) -> Set a
run [Text] -> [a]
s, ([Text] -> [a]) -> Set a
forall {a} {a}. Ord a => ([a] -> [a]) -> Set a
run [Text] -> [a]
e, ([Text] -> [a]) -> Set a
forall {a} {a}. Ord a => ([a] -> [a]) -> Set a
run [Text] -> [a]
t, ([Text] -> [a]) -> Set a
forall {a} {a}. Ord a => ([a] -> [a]) -> Set a
run [Text] -> [a]
b)
  go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b (NamedComponent
CLib : [NamedComponent]
xs) = ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b [NamedComponent]
xs
  go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b (CSubLib Text
x : [NamedComponent]
xs) = ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go ([Text] -> [a]
s ([Text] -> [a]) -> ([Text] -> [Text]) -> [Text] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
x:)) [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b [NamedComponent]
xs
  -- Ignore foreign libraries, for now.

  go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b (CFlib Text
_ : [NamedComponent]
xs) = ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b [NamedComponent]
xs
  go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b (CExe Text
x : [NamedComponent]
xs) = ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [a]
s ([Text] -> [a]
e ([Text] -> [a]) -> ([Text] -> [Text]) -> [Text] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
x:)) [Text] -> [a]
t [Text] -> [a]
b [NamedComponent]
xs
  go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b (CTest Text
x : [NamedComponent]
xs) = ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [a]
s [Text] -> [a]
e ([Text] -> [a]
t ([Text] -> [a]) -> ([Text] -> [Text]) -> [Text] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
x:)) [Text] -> [a]
b [NamedComponent]
xs
  go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t [Text] -> [a]
b (CBench Text
x : [NamedComponent]
xs) = ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> ([Text] -> [a])
-> [NamedComponent]
-> (Set a, Set a, Set a, Set a)
go [Text] -> [a]
s [Text] -> [a]
e [Text] -> [a]
t ([Text] -> [a]
b ([Text] -> [a]) -> ([Text] -> [Text]) -> [Text] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
x:)) [NamedComponent]
xs