{-# LANGUAGE NoImplicitPrelude   #-}
{-# LANGUAGE NoFieldSelectors    #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings   #-}

module Stack.Types.Project
  ( Project (..)
  ) where

import           Data.Aeson.Types ( ToJSON (..), (.=), object )
import qualified Data.Map as Map
import qualified Data.Set as Set
import           Stack.Prelude
import           Stack.Types.Curator ( Curator )

-- | A project is a collection of packages. We can have multiple stack.yaml

-- files, but only one of them may contain project information.

data Project = Project
  { Project -> Maybe String
userMsg :: !(Maybe String)
    -- ^ A warning message to display to the user when the auto generated

    -- config may have issues.

  , Project -> [RelFilePath]
packages :: ![RelFilePath]
    -- ^ Packages which are actually part of the project (as opposed

    -- to dependencies).

  , Project -> [RawPackageLocation]
extraDeps :: ![RawPackageLocation]
    -- ^ Dependencies defined within the stack.yaml file, to be applied on top

    -- of the snapshot.

  , Project -> Map PackageName (Map FlagName Bool)
flagsByPkg :: !(Map PackageName (Map FlagName Bool))
    -- ^ Flags to be applied on top of the snapshot flags.

  , Project -> RawSnapshotLocation
resolver :: !RawSnapshotLocation
    -- ^ How we resolve which @Snapshot@ to use

  , Project -> Maybe WantedCompiler
compiler :: !(Maybe WantedCompiler)
    -- ^ Override the compiler in 'projectResolver'

  , Project -> [String]
extraPackageDBs :: ![FilePath]
  , Project -> Maybe Curator
curator :: !(Maybe Curator)
    -- ^ Extra configuration intended exclusively for usage by the curator tool.

    -- In other words, this is /not/ part of the documented and exposed Stack

    -- API. SUBJECT TO CHANGE.

  , Project -> Set PackageName
dropPackages :: !(Set PackageName)
    -- ^ Packages to drop from the 'projectResolver'.

  }
  deriving Int -> Project -> ShowS
[Project] -> ShowS
Project -> String
(Int -> Project -> ShowS)
-> (Project -> String) -> ([Project] -> ShowS) -> Show Project
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Project -> ShowS
showsPrec :: Int -> Project -> ShowS
$cshow :: Project -> String
show :: Project -> String
$cshowList :: [Project] -> ShowS
showList :: [Project] -> ShowS
Show

instance ToJSON Project where
  -- Expanding the constructor fully to ensure we don't miss any fields.

  toJSON :: Project -> Value
toJSON Project
project = [Pair] -> Value
object ([Pair] -> Value) -> [Pair] -> Value
forall a b. (a -> b) -> a -> b
$ [[Pair]] -> [Pair]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    [ [Pair]
-> (WantedCompiler -> [Pair]) -> Maybe WantedCompiler -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\WantedCompiler
cv -> [Key
"compiler" Key -> WantedCompiler -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= WantedCompiler
cv]) Project
project.compiler
    , [Pair] -> (String -> [Pair]) -> Maybe String -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\String
msg -> [Key
"user-message" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= String
msg]) Project
project.userMsg
    , [ Key
"extra-package-dbs" Key -> [String] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= Project
project.extraPackageDBs
      | Bool -> Bool
not ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Project
project.extraPackageDBs)
      ]
    , [ Key
"extra-deps" Key -> [RawPackageLocation] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= Project
project.extraDeps | Bool -> Bool
not ([RawPackageLocation] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Project
project.extraDeps) ]
    , [ Key
"flags" Key
-> Map (CabalString PackageName) (Map (CabalString FlagName) Bool)
-> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= (Map FlagName Bool -> Map (CabalString FlagName) Bool)
-> Map (CabalString PackageName) (Map FlagName Bool)
-> Map (CabalString PackageName) (Map (CabalString FlagName) Bool)
forall a b.
(a -> b)
-> Map (CabalString PackageName) a
-> Map (CabalString PackageName) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Map FlagName Bool -> Map (CabalString FlagName) Bool
forall a v. Map a v -> Map (CabalString a) v
toCabalStringMap (Map PackageName (Map FlagName Bool)
-> Map (CabalString PackageName) (Map FlagName Bool)
forall a v. Map a v -> Map (CabalString a) v
toCabalStringMap Project
project.flagsByPkg)
      | Bool -> Bool
not (Map PackageName (Map FlagName Bool) -> Bool
forall k a. Map k a -> Bool
Map.null Project
project.flagsByPkg)
      ]
    , [Key
"packages" Key -> [RelFilePath] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= Project
project.packages]
    , [Key
"resolver" Key -> RawSnapshotLocation -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= Project
project.resolver]
    , [Pair] -> (Curator -> [Pair]) -> Maybe Curator -> [Pair]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\Curator
c -> [Key
"curator" Key -> Curator -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= Curator
c]) Project
project.curator
    , [ Key
"drop-packages" Key -> Set (CabalString PackageName) -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= (PackageName -> CabalString PackageName)
-> Set PackageName -> Set (CabalString PackageName)
forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map PackageName -> CabalString PackageName
forall a. a -> CabalString a
CabalString Project
project.dropPackages
      | Bool -> Bool
not (Set PackageName -> Bool
forall a. Set a -> Bool
Set.null Project
project.dropPackages)
      ]
    ]