-- cabal-helper: Simple interface to Cabal's configuration state
-- Copyright (C) 2015-2018  Daniel Gröber <cabal-helper@dxld.at>
--
-- SPDX-License-Identifier: Apache-2.0
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0

{-# LANGUAGE DeriveGeneric, DeriveDataTypeable, DefaultSignatures,
  StandaloneDeriving, GADTs, DataKinds, KindSignatures, RankNTypes, PolyKinds #-}

{-|
Module      : CabalHelper.Compiletime.Types
Description : Types used throughout
License     : Apache-2.0
-}

module CabalHelper.Compiletime.Types where

import Cabal.Plan
  ( PlanJson )
import Data.ByteString (ByteString)
import Data.IORef
import Data.Version
import Data.Typeable
import GHC.Generics
import System.FilePath (takeDirectory)
import System.Posix.Types
import CabalHelper.Compiletime.Types.RelativePath
import CabalHelper.Compiletime.Types.Cabal
import CabalHelper.Shared.InterfaceTypes

import Data.List.NonEmpty (NonEmpty)
--import qualified Data.List.NonEmpty as NonEmpty
import Data.Map.Strict (Map)
--import qualified Data.Map.Strict as Strict

-- | The kind of project being managed by a 'QueryEnv' (pun intended). Used
-- as a phantom-type variable throughout to make the project type being
-- passed into various functions correspond to the correct implementation.
data ProjType
    = Cabal CabalProjType -- ^ @cabal@ project.
    | Stack -- ^ @stack@ project.
      deriving (ProjType -> ProjType -> Bool
(ProjType -> ProjType -> Bool)
-> (ProjType -> ProjType -> Bool) -> Eq ProjType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ProjType -> ProjType -> Bool
$c/= :: ProjType -> ProjType -> Bool
== :: ProjType -> ProjType -> Bool
$c== :: ProjType -> ProjType -> Bool
Eq, Eq ProjType
Eq ProjType =>
(ProjType -> ProjType -> Ordering)
-> (ProjType -> ProjType -> Bool)
-> (ProjType -> ProjType -> Bool)
-> (ProjType -> ProjType -> Bool)
-> (ProjType -> ProjType -> Bool)
-> (ProjType -> ProjType -> ProjType)
-> (ProjType -> ProjType -> ProjType)
-> Ord ProjType
ProjType -> ProjType -> Bool
ProjType -> ProjType -> Ordering
ProjType -> ProjType -> ProjType
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
min :: ProjType -> ProjType -> ProjType
$cmin :: ProjType -> ProjType -> ProjType
max :: ProjType -> ProjType -> ProjType
$cmax :: ProjType -> ProjType -> ProjType
>= :: ProjType -> ProjType -> Bool
$c>= :: ProjType -> ProjType -> Bool
> :: ProjType -> ProjType -> Bool
$c> :: ProjType -> ProjType -> Bool
<= :: ProjType -> ProjType -> Bool
$c<= :: ProjType -> ProjType -> Bool
< :: ProjType -> ProjType -> Bool
$c< :: ProjType -> ProjType -> Bool
compare :: ProjType -> ProjType -> Ordering
$ccompare :: ProjType -> ProjType -> Ordering
$cp1Ord :: Eq ProjType
Ord, Int -> ProjType -> ShowS
[ProjType] -> ShowS
ProjType -> String
(Int -> ProjType -> ShowS)
-> (ProjType -> String) -> ([ProjType] -> ShowS) -> Show ProjType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ProjType] -> ShowS
$cshowList :: [ProjType] -> ShowS
show :: ProjType -> String
$cshow :: ProjType -> String
showsPrec :: Int -> ProjType -> ShowS
$cshowsPrec :: Int -> ProjType -> ShowS
Show, ReadPrec [ProjType]
ReadPrec ProjType
Int -> ReadS ProjType
ReadS [ProjType]
(Int -> ReadS ProjType)
-> ReadS [ProjType]
-> ReadPrec ProjType
-> ReadPrec [ProjType]
-> Read ProjType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ProjType]
$creadListPrec :: ReadPrec [ProjType]
readPrec :: ReadPrec ProjType
$creadPrec :: ReadPrec ProjType
readList :: ReadS [ProjType]
$creadList :: ReadS [ProjType]
readsPrec :: Int -> ReadS ProjType
$creadsPrec :: Int -> ReadS ProjType
Read)

-- | The kind of a @cabal@ project.
data CabalProjType
    = CV1 -- ^ @cabal v1-build@ project.
    | CV2 -- ^ @cabal v2-build@ project.
      deriving (CabalProjType -> CabalProjType -> Bool
(CabalProjType -> CabalProjType -> Bool)
-> (CabalProjType -> CabalProjType -> Bool) -> Eq CabalProjType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CabalProjType -> CabalProjType -> Bool
$c/= :: CabalProjType -> CabalProjType -> Bool
== :: CabalProjType -> CabalProjType -> Bool
$c== :: CabalProjType -> CabalProjType -> Bool
Eq, Eq CabalProjType
Eq CabalProjType =>
(CabalProjType -> CabalProjType -> Ordering)
-> (CabalProjType -> CabalProjType -> Bool)
-> (CabalProjType -> CabalProjType -> Bool)
-> (CabalProjType -> CabalProjType -> Bool)
-> (CabalProjType -> CabalProjType -> Bool)
-> (CabalProjType -> CabalProjType -> CabalProjType)
-> (CabalProjType -> CabalProjType -> CabalProjType)
-> Ord CabalProjType
CabalProjType -> CabalProjType -> Bool
CabalProjType -> CabalProjType -> Ordering
CabalProjType -> CabalProjType -> CabalProjType
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
min :: CabalProjType -> CabalProjType -> CabalProjType
$cmin :: CabalProjType -> CabalProjType -> CabalProjType
max :: CabalProjType -> CabalProjType -> CabalProjType
$cmax :: CabalProjType -> CabalProjType -> CabalProjType
>= :: CabalProjType -> CabalProjType -> Bool
$c>= :: CabalProjType -> CabalProjType -> Bool
> :: CabalProjType -> CabalProjType -> Bool
$c> :: CabalProjType -> CabalProjType -> Bool
<= :: CabalProjType -> CabalProjType -> Bool
$c<= :: CabalProjType -> CabalProjType -> Bool
< :: CabalProjType -> CabalProjType -> Bool
$c< :: CabalProjType -> CabalProjType -> Bool
compare :: CabalProjType -> CabalProjType -> Ordering
$ccompare :: CabalProjType -> CabalProjType -> Ordering
$cp1Ord :: Eq CabalProjType
Ord, Int -> CabalProjType -> ShowS
[CabalProjType] -> ShowS
CabalProjType -> String
(Int -> CabalProjType -> ShowS)
-> (CabalProjType -> String)
-> ([CabalProjType] -> ShowS)
-> Show CabalProjType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CabalProjType] -> ShowS
$cshowList :: [CabalProjType] -> ShowS
show :: CabalProjType -> String
$cshow :: CabalProjType -> String
showsPrec :: Int -> CabalProjType -> ShowS
$cshowsPrec :: Int -> CabalProjType -> ShowS
Show, ReadPrec [CabalProjType]
ReadPrec CabalProjType
Int -> ReadS CabalProjType
ReadS [CabalProjType]
(Int -> ReadS CabalProjType)
-> ReadS [CabalProjType]
-> ReadPrec CabalProjType
-> ReadPrec [CabalProjType]
-> Read CabalProjType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [CabalProjType]
$creadListPrec :: ReadPrec [CabalProjType]
readPrec :: ReadPrec CabalProjType
$creadPrec :: ReadPrec CabalProjType
readList :: ReadS [CabalProjType]
$creadList :: ReadS [CabalProjType]
readsPrec :: Int -> ReadS CabalProjType
$creadsPrec :: Int -> ReadS CabalProjType
Read)

-- | A "singleton" datatype for 'ProjType' which allows us to establish a
-- correspondence between a runtime representation of 'ProjType' to the
-- compile-time value at the type level.
--
-- If you just want to know the runtime 'ProjType' use 'demoteSProjType' to
-- convert to that.
data SProjType pt where
    SCabal :: !(SCabalProjType pt) -> SProjType ('Cabal pt)
    SStack :: SProjType 'Stack

deriving instance Show (SProjType pt)

-- | This is a singleton, like 'SProjType', but restricted to just the
-- Cabal project types. We use this to restrict some functions which don't
-- make sense for Stack to just the Cabal project types.
data SCabalProjType pt where
    SCV1 :: SCabalProjType 'CV1
    SCV2 :: SCabalProjType 'CV2

deriving instance Show (SCabalProjType pt)

demoteSProjType :: SProjType pt -> ProjType
demoteSProjType :: SProjType pt -> ProjType
demoteSProjType (SCabal SCV1) = CabalProjType -> ProjType
Cabal CabalProjType
CV1
demoteSProjType (SCabal SCV2) = CabalProjType -> ProjType
Cabal CabalProjType
CV2
demoteSProjType SStack = ProjType
Stack

-- | Location of a project context. This is usually just the path project's
-- top-level source code directory together with an optional project-type
-- specific config file path.
--
-- To find any recognized default project contexts in a given directory
-- use 'Distribution.Helper.Discover.findProjects'.
--
-- Build tools usually allow the user to specify the location of their
-- project config files manually, so we also support passing this path here
-- with the @*File@ constructors.
--
-- === Correspondence between Project and Package Source Directories
--
-- Note that the project's source directory does not necessarily correspond
-- to the directory containing the project config file, though in some
-- cases it does.
--
-- For example @cabal v2-build@ allows the @cabal.project@ file to be
-- positively anywhere in the filesystem when specified via the
-- @--cabal-project@ command-line flag, corresponding to the
-- 'ProjLocV2File' constructor here. This config file can then refer to
-- package directories with absolute paths in the @packages:@ declaration.
--
-- Hence it isn't actually possible to find /one/ directory which contains
-- the whole project's source code but rather we have to consider each
-- package's source directory individually, see 'Package.pSourceDir'
data ProjLoc (pt :: ProjType) where
    -- | A fully specified @cabal v1-build@ project context. Here you can
    -- specify both the path to the @.cabal@ file and the source directory
    -- of the package. The cabal file path corresponds to the
    -- @--cabal-file=PATH@ flag on the @cabal@ command line.
    --
    -- Note that more than one such files existing in a package directory
    -- is a user error and while cabal will still complain about that we
    -- won't.
    --
    -- Also note that for this project type the concepts of project and
    -- package coincide.
    ProjLocV1CabalFile :: { ProjLoc ('Cabal 'CV1) -> String
plCabalFile :: !FilePath, ProjLoc ('Cabal 'CV1) -> String
plProjectDirV1 :: !FilePath } -> ProjLoc ('Cabal 'CV1)

    -- | A @cabal v1-build@ project context. Essentially the same as
    -- 'ProjLocV1CabalFile' but this will dynamically search for the cabal
    -- file for you as cabal-install does by default.
    --
    -- If more than one @.cabal@ file is found in the given directory we
    -- will shamelessly throw a obscure exception so prefer
    -- 'ProjLocV1CabalFile' if you don't want that to happen. This mainly
    -- exists for easy upgrading from the @cabal-helper-0.8@ series.
    ProjLocV1Dir :: { plProjectDirV1 :: !FilePath } -> ProjLoc ('Cabal 'CV1)

    -- | A @cabal v2-build@ project context. The path to the
    -- @cabal.project@ file, though you can call it whatever you like. This
    -- configuration file then points to the packages that make up this
    -- project. This corresponds to the @--cabal-project=PATH@ flag on the
    -- @cabal@ command line.
    ProjLocV2File    :: { ProjLoc ('Cabal 'CV2) -> String
plCabalProjectFile :: !FilePath, ProjLoc ('Cabal 'CV2) -> String
plProjectDirV2 :: !FilePath } -> ProjLoc ('Cabal 'CV2)

    -- | This is equivalent to 'ProjLocV2File' but using the default
    -- @cabal.project@ file name in the given directory.
    ProjLocV2Dir     :: { plProjectDirV2 :: !FilePath } -> ProjLoc ('Cabal 'CV2)

    -- | A @stack@ project context. Specify the path to the @stack.yaml@
    -- file here. This configuration file then points to the packages that
    -- make up this project. Corresponds to @stack@'s @--stack-yaml=PATH@
    -- command line flag if different from the default name, @stack.yaml@.
    --
    -- Note: with Stack the invariant @takeDirectory plStackYaml == projdir@ holds.
    ProjLocStackYaml :: { ProjLoc 'Stack -> String
plStackYaml :: !FilePath } -> ProjLoc 'Stack

deriving instance Show (ProjLoc pt)

plV1Dir :: ProjLoc ('Cabal 'CV1) -> FilePath
plV1Dir :: ProjLoc ('Cabal 'CV1) -> String
plV1Dir ProjLocV1CabalFile {String
plProjectDirV1 :: String
plProjectDirV1 :: ProjLoc ('Cabal 'CV1) -> String
plProjectDirV1} = String
plProjectDirV1
plV1Dir ProjLocV1Dir {String
plProjectDirV1 :: String
plProjectDirV1 :: ProjLoc ('Cabal 'CV1) -> String
plProjectDirV1} = String
plProjectDirV1

plCabalProjectDir :: ProjLoc ('Cabal cpt) -> FilePath
plCabalProjectDir :: ProjLoc ('Cabal cpt) -> String
plCabalProjectDir ProjLocV1CabalFile {String
plProjectDirV1 :: String
plProjectDirV1 :: ProjLoc ('Cabal 'CV1) -> String
plProjectDirV1} = String
plProjectDirV1
plCabalProjectDir ProjLocV1Dir  {String
plProjectDirV1 :: String
plProjectDirV1 :: ProjLoc ('Cabal 'CV1) -> String
plProjectDirV1} = String
plProjectDirV1
plCabalProjectDir ProjLocV2File {String
plProjectDirV2 :: String
plProjectDirV2 :: ProjLoc ('Cabal 'CV2) -> String
plProjectDirV2} = String
plProjectDirV2
plCabalProjectDir ProjLocV2Dir  {String
plProjectDirV2 :: String
plProjectDirV2 :: ProjLoc ('Cabal 'CV2) -> String
plProjectDirV2} = String
plProjectDirV2

plStackProjectDir :: ProjLoc 'Stack -> FilePath
plStackProjectDir :: ProjLoc 'Stack -> String
plStackProjectDir ProjLocStackYaml {String
plStackYaml :: String
plStackYaml :: ProjLoc 'Stack -> String
plStackYaml} = ShowS
takeDirectory String
plStackYaml

projTypeOfProjLoc :: ProjLoc pt -> SProjType pt
projTypeOfProjLoc :: ProjLoc pt -> SProjType pt
projTypeOfProjLoc ProjLocV1CabalFile{} = SCabalProjType 'CV1 -> SProjType ('Cabal 'CV1)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType 'CV1
SCV1
projTypeOfProjLoc ProjLocV1Dir{}       = SCabalProjType 'CV1 -> SProjType ('Cabal 'CV1)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType 'CV1
SCV1
projTypeOfProjLoc ProjLocV2File{}      = SCabalProjType 'CV2 -> SProjType ('Cabal 'CV2)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType 'CV2
SCV2
projTypeOfProjLoc ProjLocV2Dir{}       = SCabalProjType 'CV2 -> SProjType ('Cabal 'CV2)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType 'CV2
SCV2
projTypeOfProjLoc ProjLocStackYaml{}   = SProjType pt
SProjType 'Stack
SStack

-- | A build directory for a certain project type. The @pt@ type variable
-- must be compatible with the 'ProjLoc' used. This is enforced by the type
-- system so you can't get this wrong.
data DistDir (pt :: ProjType) where
    -- | A build-directory for cabal, aka. dist-dir in Cabal
    -- terminology. 'SCabalProjType' specifies whether we should use
    -- /v2-build/ or /v1-build/. This choice must correspond to
    -- 'ProjLoc' \'s project type.
    DistDirCabal :: !(SCabalProjType pt) -> !FilePath -> DistDir ('Cabal pt)

    -- | A build-directory for stack, aka. /work-dir/. Optionally override
    -- Stack's /work-dir/. If you just want to use Stack's default set to
    -- @Nothing@
    DistDirStack :: !(Maybe RelativePath) -> DistDir 'Stack

deriving instance Show (DistDir pt)

projTypeOfDistDir :: DistDir pt -> SProjType pt
projTypeOfDistDir :: DistDir pt -> SProjType pt
projTypeOfDistDir (DistDirCabal pt :: SCabalProjType pt
pt _) = SCabalProjType pt -> SProjType ('Cabal pt)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType pt
pt
projTypeOfDistDir DistDirStack{} = SProjType pt
SProjType 'Stack
SStack

-- | General purpose existential wrapper. Useful for hiding a phantom type
-- argument.
--
-- Say you have:
--
-- @
-- {-\# LANGUAGE DataKinds, GADTS \#-}
-- data K = A | B | ...
-- data Q k where
--   QA :: ... -> Q 'A
--   QB :: ... -> Q 'B
-- @
--
-- and you want a list of @Q@. You can use @Ex@ to hide the phantom type
-- argument and recover it later by matching on the GADT constructors:
--
-- @
-- qa :: Q A
-- qa = QA
--
-- qb :: Q B
-- qb = QB
--
-- mylist :: [Ex Q]
-- mylist = [Ex qa, Ex qb]
-- @
data Ex a = forall x. Ex (a x)

-- | Environment for running a 'Query'. The constructor is not exposed in the
-- API to allow extending it with more fields without breaking user code.
--
-- To create a 'QueryEnv' use the 'mkQueryEnv' smart constructor instead. Some
-- field accessors are exported and may be used to override the defaults filled
-- in by 'mkQueryEnv'. See below.
--
-- Note that this environment contains an 'IORef' used as a cache. If you want
-- to take advantage of this you should not simply discard the value returned by
-- the smart constructor after one use.
type QueryEnv pt = QueryEnvI QueryCache pt

data QueryEnvI c (pt :: ProjType) = QueryEnv
    { QueryEnvI c pt -> ReadProcessWithCwdAndEnv
qeReadProcess :: !ReadProcessWithCwdAndEnv
    -- ^ Field accessor for 'QueryEnv'. Function used to to start processes
    -- and capture output. Useful if you need to, for example, redirect
    -- standard error output of programs started by cabal-helper.

    , QueryEnvI c pt -> CallProcessWithCwdAndEnv ()
qeCallProcess :: !(CallProcessWithCwdAndEnv ())
    -- ^ Field accessor for 'QueryEnv'. Function used to to start processes
    -- without capturing output. See also 'qeReadProcess'.

    , QueryEnvI c pt -> Programs
qePrograms     :: !Programs
    -- ^ Field accessor for 'QueryEnv'. Paths to various programs we use.

    , QueryEnvI c pt -> ProjLoc pt
qeProjLoc      :: !(ProjLoc pt)
    -- ^ Field accessor for 'QueryEnv'. Defines path to the project directory,
    -- i.e. a directory containing a @cabal.project@ file

    , QueryEnvI c pt -> DistDir pt
qeDistDir      :: !(DistDir pt)
    -- ^ Field accessor for 'QueryEnv'. Defines path to the @dist/@ or
    -- @dist-newstyle/@ directory, aka. /builddir/ in Cabal terminology.

    , QueryEnvI c pt -> IORef (c pt)
qeCacheRef     :: !(IORef (c pt))
    -- ^ Cache for query results, only accessible when type parameter @c@ is
    -- instantiated with 'QueryCache'. This is the case wherever the type alias
    -- 'QueryEnv' is used.

    , QueryEnvI c pt -> IORef (CacheKeyCache pt)
qeCacheKeys    :: IORef (CacheKeyCache pt)
    }

projTypeOfQueryEnv :: QueryEnvI c pt -> SProjType pt
projTypeOfQueryEnv :: QueryEnvI c pt -> SProjType pt
projTypeOfQueryEnv = ProjLoc pt -> SProjType pt
forall (pt :: ProjType). ProjLoc pt -> SProjType pt
projTypeOfProjLoc (ProjLoc pt -> SProjType pt)
-> (QueryEnvI c pt -> ProjLoc pt) -> QueryEnvI c pt -> SProjType pt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QueryEnvI c pt -> ProjLoc pt
forall (c :: ProjType -> *) (pt :: ProjType).
QueryEnvI c pt -> ProjLoc pt
qeProjLoc

type ReadProcessWithCwdAndEnv   =
  String -> CallProcessWithCwdAndEnv String

type CallProcessWithCwdAndEnv a =
  Maybe FilePath -> [(String, EnvOverride)] -> FilePath -> [String] -> IO a

-- | Full instansiation of 'QueryCacheI', with all cache fields visible
type QueryCache
  = QueryCacheI
      PreInfo
      Programs
      ProjInfo
      UnitInfo

-- | 'QueryCacheI', only instantiated with 'PreInfo' cache.
type QCPreInfo progs proj_info unit_info
  = QueryCacheI
      PreInfo
      progs
      proj_info
      unit_info

-- | 'QueryCacheI', only instantiated with 'PreInfo' and configured
-- 'Programs' cache.
type QCProgs proj_info unit_info
  = QueryCacheI
      PreInfo
      Programs
      proj_info
      unit_info

data QueryCacheI pre_info progs proj_info unit_info pt = QueryCache
    { QueryCacheI pre_info progs proj_info unit_info pt
-> Maybe ((ProjConf pt, ProjConfModTimes), pre_info pt)
qcPreInfo
        :: !(Maybe ((ProjConf pt, ProjConfModTimes), pre_info pt))
    , QueryCacheI pre_info progs proj_info unit_info pt
-> Maybe (Programs, progs)
qcConfProgs :: !(Maybe (Programs, progs))
    , QueryCacheI pre_info progs proj_info unit_info pt
-> Maybe ((ProjConf pt, ProjConfModTimes), proj_info pt)
qcProjInfo
        :: !(Maybe ((ProjConf pt, ProjConfModTimes), proj_info pt))
    , QueryCacheI pre_info progs proj_info unit_info pt
-> Map DistDirLib unit_info
qcUnitInfos :: !(Map DistDirLib unit_info)
    }

data CacheKeyCache pt = CacheKeyCache
    { CacheKeyCache pt -> Maybe (ProjConf pt, ProjConfModTimes)
ckcProjConf :: !(Maybe (ProjConf pt, ProjConfModTimes))
    }

newtype DistDirLib = DistDirLib FilePath
    deriving (DistDirLib -> DistDirLib -> Bool
(DistDirLib -> DistDirLib -> Bool)
-> (DistDirLib -> DistDirLib -> Bool) -> Eq DistDirLib
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DistDirLib -> DistDirLib -> Bool
$c/= :: DistDirLib -> DistDirLib -> Bool
== :: DistDirLib -> DistDirLib -> Bool
$c== :: DistDirLib -> DistDirLib -> Bool
Eq, Eq DistDirLib
Eq DistDirLib =>
(DistDirLib -> DistDirLib -> Ordering)
-> (DistDirLib -> DistDirLib -> Bool)
-> (DistDirLib -> DistDirLib -> Bool)
-> (DistDirLib -> DistDirLib -> Bool)
-> (DistDirLib -> DistDirLib -> Bool)
-> (DistDirLib -> DistDirLib -> DistDirLib)
-> (DistDirLib -> DistDirLib -> DistDirLib)
-> Ord DistDirLib
DistDirLib -> DistDirLib -> Bool
DistDirLib -> DistDirLib -> Ordering
DistDirLib -> DistDirLib -> DistDirLib
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
min :: DistDirLib -> DistDirLib -> DistDirLib
$cmin :: DistDirLib -> DistDirLib -> DistDirLib
max :: DistDirLib -> DistDirLib -> DistDirLib
$cmax :: DistDirLib -> DistDirLib -> DistDirLib
>= :: DistDirLib -> DistDirLib -> Bool
$c>= :: DistDirLib -> DistDirLib -> Bool
> :: DistDirLib -> DistDirLib -> Bool
$c> :: DistDirLib -> DistDirLib -> Bool
<= :: DistDirLib -> DistDirLib -> Bool
$c<= :: DistDirLib -> DistDirLib -> Bool
< :: DistDirLib -> DistDirLib -> Bool
$c< :: DistDirLib -> DistDirLib -> Bool
compare :: DistDirLib -> DistDirLib -> Ordering
$ccompare :: DistDirLib -> DistDirLib -> Ordering
$cp1Ord :: Eq DistDirLib
Ord, ReadPrec [DistDirLib]
ReadPrec DistDirLib
Int -> ReadS DistDirLib
ReadS [DistDirLib]
(Int -> ReadS DistDirLib)
-> ReadS [DistDirLib]
-> ReadPrec DistDirLib
-> ReadPrec [DistDirLib]
-> Read DistDirLib
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [DistDirLib]
$creadListPrec :: ReadPrec [DistDirLib]
readPrec :: ReadPrec DistDirLib
$creadPrec :: ReadPrec DistDirLib
readList :: ReadS [DistDirLib]
$creadList :: ReadS [DistDirLib]
readsPrec :: Int -> ReadS DistDirLib
$creadsPrec :: Int -> ReadS DistDirLib
Read, Int -> DistDirLib -> ShowS
[DistDirLib] -> ShowS
DistDirLib -> String
(Int -> DistDirLib -> ShowS)
-> (DistDirLib -> String)
-> ([DistDirLib] -> ShowS)
-> Show DistDirLib
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DistDirLib] -> ShowS
$cshowList :: [DistDirLib] -> ShowS
show :: DistDirLib -> String
$cshow :: DistDirLib -> String
showsPrec :: Int -> DistDirLib -> ShowS
$cshowsPrec :: Int -> DistDirLib -> ShowS
Show)

type Package pt = Package' (NonEmpty (Unit pt))

-- | A 'Package' is a named collection of many 'Unit's.
data Package' units = Package
    { Package' units -> String
pPackageName :: !String
    , Package' units -> String
pSourceDir   :: !FilePath
    , Package' units -> CabalFile
pCabalFile   :: !CabalFile
    , Package' units -> [(String, Bool)]
pFlags       :: ![(String, Bool)]
    -- | Cabal flags to set when configuring and building this package.
    , Package' units -> units
pUnits       :: !units
    } deriving (Int -> Package' units -> ShowS
[Package' units] -> ShowS
Package' units -> String
(Int -> Package' units -> ShowS)
-> (Package' units -> String)
-> ([Package' units] -> ShowS)
-> Show (Package' units)
forall units. Show units => Int -> Package' units -> ShowS
forall units. Show units => [Package' units] -> ShowS
forall units. Show units => Package' units -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Package' units] -> ShowS
$cshowList :: forall units. Show units => [Package' units] -> ShowS
show :: Package' units -> String
$cshow :: forall units. Show units => Package' units -> String
showsPrec :: Int -> Package' units -> ShowS
$cshowsPrec :: forall units. Show units => Int -> Package' units -> ShowS
Show)

-- | A 'Unit' is essentially a "build target". It is used to refer to a set
-- of components (exes, libs, tests etc.) which are managed by a certain
-- instance of the Cabal build-system[1]. We may get information on the
-- components in a unit by retriving the corresponding 'UnitInfo'.
--
-- \[1]: No I'm not talking about the cabal-install /build-tool/, I'm
-- talking about the Cabal /build-system/. Note the distinction. Both
-- cabal-install and Stack use the Cabal build-system (aka @lib:Cabal@)
-- underneath.
--
-- Note that a 'Unit' value is only valid within the 'QueryEnv' context it
-- was created in, this is however this is not enforced by the
-- API. Furthermore if the user changes the underlying project
-- configuration while your application is running even a properly scoped
-- 'Unit' could become invalid because the component it belongs to was
-- removed from the cabal file.
data Unit pt = Unit
    { Unit pt -> UnitId
uUnitId      :: !UnitId
    , Unit pt -> Package' ()
uPackage     :: !(Package' ())
    , Unit pt -> DistDirLib
uDistDir     :: !DistDirLib
    , Unit pt -> UnitImpl pt
uImpl        :: !(UnitImpl pt)
    } deriving (Int -> Unit pt -> ShowS
[Unit pt] -> ShowS
Unit pt -> String
(Int -> Unit pt -> ShowS)
-> (Unit pt -> String) -> ([Unit pt] -> ShowS) -> Show (Unit pt)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (pt :: ProjType). Int -> Unit pt -> ShowS
forall (pt :: ProjType). [Unit pt] -> ShowS
forall (pt :: ProjType). Unit pt -> String
showList :: [Unit pt] -> ShowS
$cshowList :: forall (pt :: ProjType). [Unit pt] -> ShowS
show :: Unit pt -> String
$cshow :: forall (pt :: ProjType). Unit pt -> String
showsPrec :: Int -> Unit pt -> ShowS
$cshowsPrec :: forall (pt :: ProjType). Int -> Unit pt -> ShowS
Show)

data UnitImpl pt where
  UnitImplV1 :: UnitImpl ('Cabal 'CV1)

  UnitImplV2 ::
    { UnitImpl ('Cabal 'CV2) -> [(ChComponentName, String)]
uiV2Components       :: ![(ChComponentName, String)]
    , UnitImpl ('Cabal 'CV2) -> Bool
uiV2OnlyDependencies :: !Bool
    } -> UnitImpl ('Cabal 'CV2)

  UnitImplStack :: UnitImpl 'Stack

deriving instance Show (UnitImpl pt)

-- | This returns the component a 'Unit' corresponds to. This information is
-- only available if the correspondence happens to be unique and known before
-- querying setup-config for the respective project type. Currently this only
-- applies to @pt=@'V2'.
--
-- This is intended to be used as an optimization, to allow reducing the number
-- of helper invocations for clients that don't need to know the entire project
-- structure.
uComponentName :: Unit pt -> Maybe ChComponentName
uComponentName :: Unit pt -> Maybe ChComponentName
uComponentName Unit { uImpl :: forall (pt :: ProjType). Unit pt -> UnitImpl pt
uImpl=UnitImplV2 { uiV2Components :: UnitImpl ('Cabal 'CV2) -> [(ChComponentName, String)]
uiV2Components=[(comp :: ChComponentName
comp, _)] } } =
    ChComponentName -> Maybe ChComponentName
forall a. a -> Maybe a
Just ChComponentName
comp
uComponentName _ =
    Maybe ChComponentName
forall a. Maybe a
Nothing

-- | The @setup-config@ header. Note that Cabal writes all the package names in
-- the header using 'Data.ByteString.Char8' and hence all characters are
-- truncated from Unicode codepoints to 8-bit Latin-1.
--
-- We can be fairly confident that 'uhSetupId' and 'uhCompilerId' won\'t have
-- names that cause trouble here so it's ok to look at them but user packages
-- are free to have any unicode name.
data UnitHeader = UnitHeader
    { UnitHeader -> (ByteString, Version)
uhPackageId  :: !(ByteString, Version)
      -- ^ Name and version of the source package. This is only going to be
      -- usable for unicode package names starting with @Cabal-3.0.0.0@. See
      -- 'uiPackageId' for an alternative that always works.
    , UnitHeader -> (ByteString, Version)
uhSetupId    :: !(ByteString, Version)
      -- ^ Name and version of the @Setup.hs@ implementation. We expect
      -- @"Cabal"@ here, naturally.
    , UnitHeader -> (ByteString, Version)
uhCompilerId :: !(ByteString, Version)
      -- ^ Name and version of the compiler that was used to build
      -- Setup.hs. WARNING: This does not identify the GHC version the project
      -- is configured to use!
    } deriving (UnitHeader -> UnitHeader -> Bool
(UnitHeader -> UnitHeader -> Bool)
-> (UnitHeader -> UnitHeader -> Bool) -> Eq UnitHeader
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UnitHeader -> UnitHeader -> Bool
$c/= :: UnitHeader -> UnitHeader -> Bool
== :: UnitHeader -> UnitHeader -> Bool
$c== :: UnitHeader -> UnitHeader -> Bool
Eq, Eq UnitHeader
Eq UnitHeader =>
(UnitHeader -> UnitHeader -> Ordering)
-> (UnitHeader -> UnitHeader -> Bool)
-> (UnitHeader -> UnitHeader -> Bool)
-> (UnitHeader -> UnitHeader -> Bool)
-> (UnitHeader -> UnitHeader -> Bool)
-> (UnitHeader -> UnitHeader -> UnitHeader)
-> (UnitHeader -> UnitHeader -> UnitHeader)
-> Ord UnitHeader
UnitHeader -> UnitHeader -> Bool
UnitHeader -> UnitHeader -> Ordering
UnitHeader -> UnitHeader -> UnitHeader
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
min :: UnitHeader -> UnitHeader -> UnitHeader
$cmin :: UnitHeader -> UnitHeader -> UnitHeader
max :: UnitHeader -> UnitHeader -> UnitHeader
$cmax :: UnitHeader -> UnitHeader -> UnitHeader
>= :: UnitHeader -> UnitHeader -> Bool
$c>= :: UnitHeader -> UnitHeader -> Bool
> :: UnitHeader -> UnitHeader -> Bool
$c> :: UnitHeader -> UnitHeader -> Bool
<= :: UnitHeader -> UnitHeader -> Bool
$c<= :: UnitHeader -> UnitHeader -> Bool
< :: UnitHeader -> UnitHeader -> Bool
$c< :: UnitHeader -> UnitHeader -> Bool
compare :: UnitHeader -> UnitHeader -> Ordering
$ccompare :: UnitHeader -> UnitHeader -> Ordering
$cp1Ord :: Eq UnitHeader
Ord, ReadPrec [UnitHeader]
ReadPrec UnitHeader
Int -> ReadS UnitHeader
ReadS [UnitHeader]
(Int -> ReadS UnitHeader)
-> ReadS [UnitHeader]
-> ReadPrec UnitHeader
-> ReadPrec [UnitHeader]
-> Read UnitHeader
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [UnitHeader]
$creadListPrec :: ReadPrec [UnitHeader]
readPrec :: ReadPrec UnitHeader
$creadPrec :: ReadPrec UnitHeader
readList :: ReadS [UnitHeader]
$creadList :: ReadS [UnitHeader]
readsPrec :: Int -> ReadS UnitHeader
$creadsPrec :: Int -> ReadS UnitHeader
Read, Int -> UnitHeader -> ShowS
[UnitHeader] -> ShowS
UnitHeader -> String
(Int -> UnitHeader -> ShowS)
-> (UnitHeader -> String)
-> ([UnitHeader] -> ShowS)
-> Show UnitHeader
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnitHeader] -> ShowS
$cshowList :: [UnitHeader] -> ShowS
show :: UnitHeader -> String
$cshow :: UnitHeader -> String
showsPrec :: Int -> UnitHeader -> ShowS
$cshowsPrec :: Int -> UnitHeader -> ShowS
Show)

newtype UnitId = UnitId String
    deriving (UnitId -> UnitId -> Bool
(UnitId -> UnitId -> Bool)
-> (UnitId -> UnitId -> Bool) -> Eq UnitId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UnitId -> UnitId -> Bool
$c/= :: UnitId -> UnitId -> Bool
== :: UnitId -> UnitId -> Bool
$c== :: UnitId -> UnitId -> Bool
Eq, Eq UnitId
Eq UnitId =>
(UnitId -> UnitId -> Ordering)
-> (UnitId -> UnitId -> Bool)
-> (UnitId -> UnitId -> Bool)
-> (UnitId -> UnitId -> Bool)
-> (UnitId -> UnitId -> Bool)
-> (UnitId -> UnitId -> UnitId)
-> (UnitId -> UnitId -> UnitId)
-> Ord UnitId
UnitId -> UnitId -> Bool
UnitId -> UnitId -> Ordering
UnitId -> UnitId -> UnitId
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
min :: UnitId -> UnitId -> UnitId
$cmin :: UnitId -> UnitId -> UnitId
max :: UnitId -> UnitId -> UnitId
$cmax :: UnitId -> UnitId -> UnitId
>= :: UnitId -> UnitId -> Bool
$c>= :: UnitId -> UnitId -> Bool
> :: UnitId -> UnitId -> Bool
$c> :: UnitId -> UnitId -> Bool
<= :: UnitId -> UnitId -> Bool
$c<= :: UnitId -> UnitId -> Bool
< :: UnitId -> UnitId -> Bool
$c< :: UnitId -> UnitId -> Bool
compare :: UnitId -> UnitId -> Ordering
$ccompare :: UnitId -> UnitId -> Ordering
$cp1Ord :: Eq UnitId
Ord, ReadPrec [UnitId]
ReadPrec UnitId
Int -> ReadS UnitId
ReadS [UnitId]
(Int -> ReadS UnitId)
-> ReadS [UnitId]
-> ReadPrec UnitId
-> ReadPrec [UnitId]
-> Read UnitId
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [UnitId]
$creadListPrec :: ReadPrec [UnitId]
readPrec :: ReadPrec UnitId
$creadPrec :: ReadPrec UnitId
readList :: ReadS [UnitId]
$creadList :: ReadS [UnitId]
readsPrec :: Int -> ReadS UnitId
$creadsPrec :: Int -> ReadS UnitId
Read, Int -> UnitId -> ShowS
[UnitId] -> ShowS
UnitId -> String
(Int -> UnitId -> ShowS)
-> (UnitId -> String) -> ([UnitId] -> ShowS) -> Show UnitId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnitId] -> ShowS
$cshowList :: [UnitId] -> ShowS
show :: UnitId -> String
$cshow :: UnitId -> String
showsPrec :: Int -> UnitId -> ShowS
$cshowsPrec :: Int -> UnitId -> ShowS
Show)

-- | The information extracted from a 'Unit'\'s on-disk configuration cache.
data UnitInfo = UnitInfo
    { UnitInfo -> UnitId
uiUnitId                :: !UnitId
    -- ^ A unique identifier of this unit within the originating project.

    , UnitInfo -> (String, Version)
uiPackageId             :: !(String, Version)
    -- ^ The package-name and version this unit belongs to.

    , UnitInfo -> Map ChComponentName ChComponentInfo
uiComponents            :: !(Map ChComponentName ChComponentInfo)
    -- ^ The components of the unit: libraries, executables, test-suites,
    -- benchmarks and so on.

    , UnitInfo -> (String, Version)
uiCompilerId            :: !(String, Version)
    -- ^ The version of GHC the unit is configured to use

    , UnitInfo -> [(String, Bool)]
uiPackageFlags          :: !([(String, Bool)])
    -- ^ Flag definitions from cabal file

    , UnitInfo -> [(String, Bool)]
uiConfigFlags           :: ![(String, Bool)]
    -- ^ Flag assignments from active configuration

    , UnitInfo -> [(String, Bool)]
uiNonDefaultConfigFlags :: ![(String, Bool)]
    -- ^ Flag assignments from setup-config which differ from the default
    -- setting. This can also include flags which cabal decided to modify,
    -- i.e. don't rely on these being the flags set by the user directly.

    , UnitInfo -> UnitModTimes
uiModTimes              :: !UnitModTimes
    -- ^ Key for cache invalidation. When this is not equal to the value
    -- returned by 'getUnitModTimes' this 'UnitInfo' is considered invalid.
    } deriving (UnitInfo -> UnitInfo -> Bool
(UnitInfo -> UnitInfo -> Bool)
-> (UnitInfo -> UnitInfo -> Bool) -> Eq UnitInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UnitInfo -> UnitInfo -> Bool
$c/= :: UnitInfo -> UnitInfo -> Bool
== :: UnitInfo -> UnitInfo -> Bool
$c== :: UnitInfo -> UnitInfo -> Bool
Eq, Eq UnitInfo
Eq UnitInfo =>
(UnitInfo -> UnitInfo -> Ordering)
-> (UnitInfo -> UnitInfo -> Bool)
-> (UnitInfo -> UnitInfo -> Bool)
-> (UnitInfo -> UnitInfo -> Bool)
-> (UnitInfo -> UnitInfo -> Bool)
-> (UnitInfo -> UnitInfo -> UnitInfo)
-> (UnitInfo -> UnitInfo -> UnitInfo)
-> Ord UnitInfo
UnitInfo -> UnitInfo -> Bool
UnitInfo -> UnitInfo -> Ordering
UnitInfo -> UnitInfo -> UnitInfo
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
min :: UnitInfo -> UnitInfo -> UnitInfo
$cmin :: UnitInfo -> UnitInfo -> UnitInfo
max :: UnitInfo -> UnitInfo -> UnitInfo
$cmax :: UnitInfo -> UnitInfo -> UnitInfo
>= :: UnitInfo -> UnitInfo -> Bool
$c>= :: UnitInfo -> UnitInfo -> Bool
> :: UnitInfo -> UnitInfo -> Bool
$c> :: UnitInfo -> UnitInfo -> Bool
<= :: UnitInfo -> UnitInfo -> Bool
$c<= :: UnitInfo -> UnitInfo -> Bool
< :: UnitInfo -> UnitInfo -> Bool
$c< :: UnitInfo -> UnitInfo -> Bool
compare :: UnitInfo -> UnitInfo -> Ordering
$ccompare :: UnitInfo -> UnitInfo -> Ordering
$cp1Ord :: Eq UnitInfo
Ord, ReadPrec [UnitInfo]
ReadPrec UnitInfo
Int -> ReadS UnitInfo
ReadS [UnitInfo]
(Int -> ReadS UnitInfo)
-> ReadS [UnitInfo]
-> ReadPrec UnitInfo
-> ReadPrec [UnitInfo]
-> Read UnitInfo
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [UnitInfo]
$creadListPrec :: ReadPrec [UnitInfo]
readPrec :: ReadPrec UnitInfo
$creadPrec :: ReadPrec UnitInfo
readList :: ReadS [UnitInfo]
$creadList :: ReadS [UnitInfo]
readsPrec :: Int -> ReadS UnitInfo
$creadsPrec :: Int -> ReadS UnitInfo
Read, Int -> UnitInfo -> ShowS
[UnitInfo] -> ShowS
UnitInfo -> String
(Int -> UnitInfo -> ShowS)
-> (UnitInfo -> String) -> ([UnitInfo] -> ShowS) -> Show UnitInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnitInfo] -> ShowS
$cshowList :: [UnitInfo] -> ShowS
show :: UnitInfo -> String
$cshow :: UnitInfo -> String
showsPrec :: Int -> UnitInfo -> ShowS
$cshowsPrec :: Int -> UnitInfo -> ShowS
Show)

-- | Files relevant to the project-scope configuration. We gather them here so
-- we can refer to their paths conveniently throughout the code. These files are
-- not necessarily guaranteed to even exist.
data ProjConf pt where
  ProjConfV1 ::
    { ProjConf ('Cabal 'CV1) -> String
pcV1CabalFile :: !FilePath
    } -> ProjConf ('Cabal 'CV1)

  ProjConfV2 ::
    { ProjConf ('Cabal 'CV2) -> String
pcV2CabalProjFile       :: !FilePath
    , ProjConf ('Cabal 'CV2) -> String
pcV2CabalProjLocalFile  :: !FilePath
    , ProjConf ('Cabal 'CV2) -> String
pcV2CabalProjFreezeFile :: !FilePath
    } -> ProjConf ('Cabal 'CV2)

  ProjConfStack ::
    { ProjConf 'Stack -> String
pcStackYaml :: !FilePath
    } -> ProjConf 'Stack

projTypeOfProjConf :: ProjConf pt -> SProjType pt
projTypeOfProjConf :: ProjConf pt -> SProjType pt
projTypeOfProjConf ProjConfV1{}    = SCabalProjType 'CV1 -> SProjType ('Cabal 'CV1)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType 'CV1
SCV1
projTypeOfProjConf ProjConfV2{}    = SCabalProjType 'CV2 -> SProjType ('Cabal 'CV2)
forall (pt :: CabalProjType).
SCabalProjType pt -> SProjType ('Cabal pt)
SCabal SCabalProjType 'CV2
SCV2
projTypeOfProjConf ProjConfStack{} = SProjType pt
SProjType 'Stack
SStack


-- This is supposed to be opaque, as it's only meant to be used only for cache
-- invalidation.
newtype ProjConfModTimes = ProjConfModTimes [(FilePath, EpochTime)]
    deriving (ProjConfModTimes -> ProjConfModTimes -> Bool
(ProjConfModTimes -> ProjConfModTimes -> Bool)
-> (ProjConfModTimes -> ProjConfModTimes -> Bool)
-> Eq ProjConfModTimes
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ProjConfModTimes -> ProjConfModTimes -> Bool
$c/= :: ProjConfModTimes -> ProjConfModTimes -> Bool
== :: ProjConfModTimes -> ProjConfModTimes -> Bool
$c== :: ProjConfModTimes -> ProjConfModTimes -> Bool
Eq, Int -> ProjConfModTimes -> ShowS
[ProjConfModTimes] -> ShowS
ProjConfModTimes -> String
(Int -> ProjConfModTimes -> ShowS)
-> (ProjConfModTimes -> String)
-> ([ProjConfModTimes] -> ShowS)
-> Show ProjConfModTimes
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ProjConfModTimes] -> ShowS
$cshowList :: [ProjConfModTimes] -> ShowS
show :: ProjConfModTimes -> String
$cshow :: ProjConfModTimes -> String
showsPrec :: Int -> ProjConfModTimes -> ShowS
$cshowsPrec :: Int -> ProjConfModTimes -> ShowS
Show)

-- | Project-scope information cache.
data ProjInfo pt = ProjInfo
  { ProjInfo pt -> NonEmpty (Package pt)
piPackages         :: !(NonEmpty (Package pt))
  , ProjInfo pt -> ProjInfoImpl pt
piImpl             :: !(ProjInfoImpl pt)
  , ProjInfo pt -> ProjConfModTimes
piProjConfModTimes :: !ProjConfModTimes
  -- ^ Key for cache invalidation. When this is not equal to the return
  -- value of 'getProjConfModTime' this 'ProjInfo' is considered invalid.
  } deriving (Int -> ProjInfo pt -> ShowS
[ProjInfo pt] -> ShowS
ProjInfo pt -> String
(Int -> ProjInfo pt -> ShowS)
-> (ProjInfo pt -> String)
-> ([ProjInfo pt] -> ShowS)
-> Show (ProjInfo pt)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (pt :: ProjType). Int -> ProjInfo pt -> ShowS
forall (pt :: ProjType). [ProjInfo pt] -> ShowS
forall (pt :: ProjType). ProjInfo pt -> String
showList :: [ProjInfo pt] -> ShowS
$cshowList :: forall (pt :: ProjType). [ProjInfo pt] -> ShowS
show :: ProjInfo pt -> String
$cshow :: forall (pt :: ProjType). ProjInfo pt -> String
showsPrec :: Int -> ProjInfo pt -> ShowS
$cshowsPrec :: forall (pt :: ProjType). Int -> ProjInfo pt -> ShowS
Show)

data ProjInfoImpl pt where
  ProjInfoV1 ::
    { ProjInfoImpl ('Cabal 'CV1) -> UnitHeader
piV1SetupHeader  :: !UnitHeader
    , ProjInfoImpl ('Cabal 'CV1) -> CabalVersion
piV1CabalVersion :: !CabalVersion
    } -> ProjInfoImpl ('Cabal 'CV1)

  ProjInfoV2 ::
    { ProjInfoImpl ('Cabal 'CV2) -> PlanJson
piV2Plan         :: !PlanJson
    , ProjInfoImpl ('Cabal 'CV2) -> EpochTime
piV2PlanModTime  :: !EpochTime
    , ProjInfoImpl ('Cabal 'CV2) -> (String, Version)
piV2CompilerId   :: !(String, Version)
    } -> ProjInfoImpl ('Cabal 'CV2)

  ProjInfoStack :: ProjInfoImpl 'Stack

instance Show (ProjInfoImpl pt) where
    show :: ProjInfoImpl pt -> String
show ProjInfoV1 {..} = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ "ProjInfoV1 {"
      , "piV1SetupHeader = ", UnitHeader -> String
forall a. Show a => a -> String
show UnitHeader
piV1SetupHeader, ", "
      , "}"
      ]
    show ProjInfoV2 {..} = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ "ProjInfoV2 {"
      , "piV2Plan = ", PlanJson -> String
forall a. Show a => a -> String
show PlanJson
piV2Plan, ", "
      , "piV2PlanModTime = ", EpochTime -> String
forall a. Show a => a -> String
show EpochTime
piV2PlanModTime, ", "
      , "piV2CompilerId = ", (String, Version) -> String
forall a. Show a => a -> String
show (String, Version)
piV2CompilerId
      , "}"
      ]
    show ProjInfoStack{} = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ "ProjInfoStack {"
      , "}"
      ]

data UnitModTimes = UnitModTimes
    { UnitModTimes -> Maybe (String, EpochTime)
umtPkgYaml     :: !(Maybe (FilePath, EpochTime))
    , UnitModTimes -> (String, EpochTime)
umtCabalFile   :: !(FilePath, EpochTime)
    , UnitModTimes -> Maybe (String, EpochTime)
umtSetupConfig :: !(Maybe (FilePath, EpochTime))
    } deriving (UnitModTimes -> UnitModTimes -> Bool
(UnitModTimes -> UnitModTimes -> Bool)
-> (UnitModTimes -> UnitModTimes -> Bool) -> Eq UnitModTimes
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UnitModTimes -> UnitModTimes -> Bool
$c/= :: UnitModTimes -> UnitModTimes -> Bool
== :: UnitModTimes -> UnitModTimes -> Bool
$c== :: UnitModTimes -> UnitModTimes -> Bool
Eq, Eq UnitModTimes
Eq UnitModTimes =>
(UnitModTimes -> UnitModTimes -> Ordering)
-> (UnitModTimes -> UnitModTimes -> Bool)
-> (UnitModTimes -> UnitModTimes -> Bool)
-> (UnitModTimes -> UnitModTimes -> Bool)
-> (UnitModTimes -> UnitModTimes -> Bool)
-> (UnitModTimes -> UnitModTimes -> UnitModTimes)
-> (UnitModTimes -> UnitModTimes -> UnitModTimes)
-> Ord UnitModTimes
UnitModTimes -> UnitModTimes -> Bool
UnitModTimes -> UnitModTimes -> Ordering
UnitModTimes -> UnitModTimes -> UnitModTimes
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
min :: UnitModTimes -> UnitModTimes -> UnitModTimes
$cmin :: UnitModTimes -> UnitModTimes -> UnitModTimes
max :: UnitModTimes -> UnitModTimes -> UnitModTimes
$cmax :: UnitModTimes -> UnitModTimes -> UnitModTimes
>= :: UnitModTimes -> UnitModTimes -> Bool
$c>= :: UnitModTimes -> UnitModTimes -> Bool
> :: UnitModTimes -> UnitModTimes -> Bool
$c> :: UnitModTimes -> UnitModTimes -> Bool
<= :: UnitModTimes -> UnitModTimes -> Bool
$c<= :: UnitModTimes -> UnitModTimes -> Bool
< :: UnitModTimes -> UnitModTimes -> Bool
$c< :: UnitModTimes -> UnitModTimes -> Bool
compare :: UnitModTimes -> UnitModTimes -> Ordering
$ccompare :: UnitModTimes -> UnitModTimes -> Ordering
$cp1Ord :: Eq UnitModTimes
Ord, ReadPrec [UnitModTimes]
ReadPrec UnitModTimes
Int -> ReadS UnitModTimes
ReadS [UnitModTimes]
(Int -> ReadS UnitModTimes)
-> ReadS [UnitModTimes]
-> ReadPrec UnitModTimes
-> ReadPrec [UnitModTimes]
-> Read UnitModTimes
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [UnitModTimes]
$creadListPrec :: ReadPrec [UnitModTimes]
readPrec :: ReadPrec UnitModTimes
$creadPrec :: ReadPrec UnitModTimes
readList :: ReadS [UnitModTimes]
$creadList :: ReadS [UnitModTimes]
readsPrec :: Int -> ReadS UnitModTimes
$creadsPrec :: Int -> ReadS UnitModTimes
Read, Int -> UnitModTimes -> ShowS
[UnitModTimes] -> ShowS
UnitModTimes -> String
(Int -> UnitModTimes -> ShowS)
-> (UnitModTimes -> String)
-> ([UnitModTimes] -> ShowS)
-> Show UnitModTimes
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnitModTimes] -> ShowS
$cshowList :: [UnitModTimes] -> ShowS
show :: UnitModTimes -> String
$cshow :: UnitModTimes -> String
showsPrec :: Int -> UnitModTimes -> ShowS
$cshowsPrec :: Int -> UnitModTimes -> ShowS
Show)
data PreInfo pt where
  PreInfoCabal :: PreInfo ('Cabal cpt)
  PreInfoStack ::
    { PreInfo 'Stack -> StackProjPaths
piStackProjPaths :: !StackProjPaths
    } -> PreInfo 'Stack

instance Show (PreInfo pt) where
    show :: PreInfo pt -> String
show PreInfoCabal{} = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ "PreInfoCabal {"
      , "}"
      ]
    show PreInfoStack {..} = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ "PreInfoStack {"
      , "piStackProjPaths = ", StackProjPaths -> String
forall a. Show a => a -> String
show StackProjPaths
piStackProjPaths
      , "}"
      ]

newtype CabalFile = CabalFile FilePath
    deriving (Int -> CabalFile -> ShowS
[CabalFile] -> ShowS
CabalFile -> String
(Int -> CabalFile -> ShowS)
-> (CabalFile -> String)
-> ([CabalFile] -> ShowS)
-> Show CabalFile
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CabalFile] -> ShowS
$cshowList :: [CabalFile] -> ShowS
show :: CabalFile -> String
$cshow :: CabalFile -> String
showsPrec :: Int -> CabalFile -> ShowS
$cshowsPrec :: Int -> CabalFile -> ShowS
Show)

data StackProjPaths = StackProjPaths
    { StackProjPaths -> PackageDbDir
sppGlobalPkgDb :: !PackageDbDir
    , StackProjPaths -> PackageDbDir
sppSnapPkgDb   :: !PackageDbDir
    , StackProjPaths -> PackageDbDir
sppLocalPkgDb  :: !PackageDbDir
    , StackProjPaths -> String
sppCompExe     :: !FilePath
    } deriving (Int -> StackProjPaths -> ShowS
[StackProjPaths] -> ShowS
StackProjPaths -> String
(Int -> StackProjPaths -> ShowS)
-> (StackProjPaths -> String)
-> ([StackProjPaths] -> ShowS)
-> Show StackProjPaths
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [StackProjPaths] -> ShowS
$cshowList :: [StackProjPaths] -> ShowS
show :: StackProjPaths -> String
$cshow :: StackProjPaths -> String
showsPrec :: Int -> StackProjPaths -> ShowS
$cshowsPrec :: Int -> StackProjPaths -> ShowS
Show)


-- Beware: GHC 8.0.2 doesn't like these being recursively defined for some
-- reason so just keep them unrolled.
type Verbose = (?verbose :: Word -> Bool)
type Env     = ( ?progs :: Programs
               , ?verbose :: Word -> Bool)
type Progs   = (?progs :: Programs)

-- | Configurable paths to various programs we use.
data Programs = Programs
    { Programs -> String
cabalProgram    :: !FilePath
      -- ^ The path to the @cabal@ program.
    , Programs -> [String]
cabalProjArgs   :: ![String]
    , Programs -> [String]
cabalUnitArgs   :: ![String]

    , Programs -> String
stackProgram    :: !FilePath
      -- ^ The path to the @stack@ program.
    , Programs -> [String]
stackProjArgs   :: ![String]
    , Programs -> [String]
stackUnitArgs   :: ![String]
    , Programs -> [(String, EnvOverride)]
stackEnv        :: ![(String, EnvOverride)]
      --  ^ TODO: Stack doesn't support passing the compiler as a
      --  commandline option so we meddle with PATH instead. We should
      --  patch that upstream.

    , Programs -> String
ghcProgram    :: !FilePath
    -- ^ The path to the @ghc@ program.

    , Programs -> String
ghcPkgProgram :: !FilePath
    -- ^ The path to the @ghc-pkg@ program. If not changed it will be derived
    -- from the path to 'ghcProgram'.

    , Programs -> String
haddockProgram :: !FilePath
    -- ^ The path to the @haddock@ program. If not changed it will be
    -- derived from the path to 'ghcProgram'.
    } deriving (Programs -> Programs -> Bool
(Programs -> Programs -> Bool)
-> (Programs -> Programs -> Bool) -> Eq Programs
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Programs -> Programs -> Bool
$c/= :: Programs -> Programs -> Bool
== :: Programs -> Programs -> Bool
$c== :: Programs -> Programs -> Bool
Eq, Eq Programs
Eq Programs =>
(Programs -> Programs -> Ordering)
-> (Programs -> Programs -> Bool)
-> (Programs -> Programs -> Bool)
-> (Programs -> Programs -> Bool)
-> (Programs -> Programs -> Bool)
-> (Programs -> Programs -> Programs)
-> (Programs -> Programs -> Programs)
-> Ord Programs
Programs -> Programs -> Bool
Programs -> Programs -> Ordering
Programs -> Programs -> Programs
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
min :: Programs -> Programs -> Programs
$cmin :: Programs -> Programs -> Programs
max :: Programs -> Programs -> Programs
$cmax :: Programs -> Programs -> Programs
>= :: Programs -> Programs -> Bool
$c>= :: Programs -> Programs -> Bool
> :: Programs -> Programs -> Bool
$c> :: Programs -> Programs -> Bool
<= :: Programs -> Programs -> Bool
$c<= :: Programs -> Programs -> Bool
< :: Programs -> Programs -> Bool
$c< :: Programs -> Programs -> Bool
compare :: Programs -> Programs -> Ordering
$ccompare :: Programs -> Programs -> Ordering
$cp1Ord :: Eq Programs
Ord, Int -> Programs -> ShowS
[Programs] -> ShowS
Programs -> String
(Int -> Programs -> ShowS)
-> (Programs -> String) -> ([Programs] -> ShowS) -> Show Programs
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Programs] -> ShowS
$cshowList :: [Programs] -> ShowS
show :: Programs -> String
$cshow :: Programs -> String
showsPrec :: Int -> Programs -> ShowS
$cshowsPrec :: Int -> Programs -> ShowS
Show, ReadPrec [Programs]
ReadPrec Programs
Int -> ReadS Programs
ReadS [Programs]
(Int -> ReadS Programs)
-> ReadS [Programs]
-> ReadPrec Programs
-> ReadPrec [Programs]
-> Read Programs
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Programs]
$creadListPrec :: ReadPrec [Programs]
readPrec :: ReadPrec Programs
$creadPrec :: ReadPrec Programs
readList :: ReadS [Programs]
$creadList :: ReadS [Programs]
readsPrec :: Int -> ReadS Programs
$creadsPrec :: Int -> ReadS Programs
Read, (forall x. Programs -> Rep Programs x)
-> (forall x. Rep Programs x -> Programs) -> Generic Programs
forall x. Rep Programs x -> Programs
forall x. Programs -> Rep Programs x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Programs x -> Programs
$cfrom :: forall x. Programs -> Rep Programs x
Generic, Typeable)

-- | By default all programs use their unqualified names, i.e. they will be
-- searched for on @PATH@.
defaultPrograms :: Programs
defaultPrograms :: Programs
defaultPrograms =
  String
-> [String]
-> [String]
-> String
-> [String]
-> [String]
-> [(String, EnvOverride)]
-> String
-> String
-> String
-> Programs
Programs "cabal" [] []  "stack" [] [] [] "ghc" "ghc-pkg" "haddock"

data EnvOverride
    = EnvUnset
    | EnvSet String
    | EnvAppend String
    | EnvPrepend String
      deriving (EnvOverride -> EnvOverride -> Bool
(EnvOverride -> EnvOverride -> Bool)
-> (EnvOverride -> EnvOverride -> Bool) -> Eq EnvOverride
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EnvOverride -> EnvOverride -> Bool
$c/= :: EnvOverride -> EnvOverride -> Bool
== :: EnvOverride -> EnvOverride -> Bool
$c== :: EnvOverride -> EnvOverride -> Bool
Eq, Eq EnvOverride
Eq EnvOverride =>
(EnvOverride -> EnvOverride -> Ordering)
-> (EnvOverride -> EnvOverride -> Bool)
-> (EnvOverride -> EnvOverride -> Bool)
-> (EnvOverride -> EnvOverride -> Bool)
-> (EnvOverride -> EnvOverride -> Bool)
-> (EnvOverride -> EnvOverride -> EnvOverride)
-> (EnvOverride -> EnvOverride -> EnvOverride)
-> Ord EnvOverride
EnvOverride -> EnvOverride -> Bool
EnvOverride -> EnvOverride -> Ordering
EnvOverride -> EnvOverride -> EnvOverride
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
min :: EnvOverride -> EnvOverride -> EnvOverride
$cmin :: EnvOverride -> EnvOverride -> EnvOverride
max :: EnvOverride -> EnvOverride -> EnvOverride
$cmax :: EnvOverride -> EnvOverride -> EnvOverride
>= :: EnvOverride -> EnvOverride -> Bool
$c>= :: EnvOverride -> EnvOverride -> Bool
> :: EnvOverride -> EnvOverride -> Bool
$c> :: EnvOverride -> EnvOverride -> Bool
<= :: EnvOverride -> EnvOverride -> Bool
$c<= :: EnvOverride -> EnvOverride -> Bool
< :: EnvOverride -> EnvOverride -> Bool
$c< :: EnvOverride -> EnvOverride -> Bool
compare :: EnvOverride -> EnvOverride -> Ordering
$ccompare :: EnvOverride -> EnvOverride -> Ordering
$cp1Ord :: Eq EnvOverride
Ord, Int -> EnvOverride -> ShowS
[EnvOverride] -> ShowS
EnvOverride -> String
(Int -> EnvOverride -> ShowS)
-> (EnvOverride -> String)
-> ([EnvOverride] -> ShowS)
-> Show EnvOverride
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EnvOverride] -> ShowS
$cshowList :: [EnvOverride] -> ShowS
show :: EnvOverride -> String
$cshow :: EnvOverride -> String
showsPrec :: Int -> EnvOverride -> ShowS
$cshowsPrec :: Int -> EnvOverride -> ShowS
Show, ReadPrec [EnvOverride]
ReadPrec EnvOverride
Int -> ReadS EnvOverride
ReadS [EnvOverride]
(Int -> ReadS EnvOverride)
-> ReadS [EnvOverride]
-> ReadPrec EnvOverride
-> ReadPrec [EnvOverride]
-> Read EnvOverride
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [EnvOverride]
$creadListPrec :: ReadPrec [EnvOverride]
readPrec :: ReadPrec EnvOverride
$creadPrec :: ReadPrec EnvOverride
readList :: ReadS [EnvOverride]
$creadList :: ReadS [EnvOverride]
readsPrec :: Int -> ReadS EnvOverride
$creadsPrec :: Int -> ReadS EnvOverride
Read, (forall x. EnvOverride -> Rep EnvOverride x)
-> (forall x. Rep EnvOverride x -> EnvOverride)
-> Generic EnvOverride
forall x. Rep EnvOverride x -> EnvOverride
forall x. EnvOverride -> Rep EnvOverride x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep EnvOverride x -> EnvOverride
$cfrom :: forall x. EnvOverride -> Rep EnvOverride x
Generic, Typeable)

data CompileOptions = CompileOptions
    { CompileOptions -> Bool
oVerbose       :: Bool
    , CompileOptions -> Maybe PackageDbDir
oCabalPkgDb    :: Maybe PackageDbDir
    , CompileOptions -> Maybe Version
oCabalVersion  :: Maybe Version
    , CompileOptions -> Programs
oPrograms      :: Programs
    }

oCabalProgram :: Env => FilePath
oCabalProgram :: String
oCabalProgram = Programs -> String
cabalProgram ?progs::Programs
Programs
?progs

defaultCompileOptions :: CompileOptions
defaultCompileOptions :: CompileOptions
defaultCompileOptions =
    Bool
-> Maybe PackageDbDir
-> Maybe Version
-> Programs
-> CompileOptions
CompileOptions Bool
False Maybe PackageDbDir
forall a. Maybe a
Nothing Maybe Version
forall a. Maybe a
Nothing Programs
defaultPrograms

newtype PackageDbDir = PackageDbDir { PackageDbDir -> String
unPackageDbDir :: FilePath }
    deriving (Int -> PackageDbDir -> ShowS
[PackageDbDir] -> ShowS
PackageDbDir -> String
(Int -> PackageDbDir -> ShowS)
-> (PackageDbDir -> String)
-> ([PackageDbDir] -> ShowS)
-> Show PackageDbDir
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PackageDbDir] -> ShowS
$cshowList :: [PackageDbDir] -> ShowS
show :: PackageDbDir -> String
$cshow :: PackageDbDir -> String
showsPrec :: Int -> PackageDbDir -> ShowS
$cshowsPrec :: Int -> PackageDbDir -> ShowS
Show)
newtype PackageEnvFile = PackageEnvFile { PackageEnvFile -> String
unPackageEnvFile :: FilePath }
    deriving (Int -> PackageEnvFile -> ShowS
[PackageEnvFile] -> ShowS
PackageEnvFile -> String
(Int -> PackageEnvFile -> ShowS)
-> (PackageEnvFile -> String)
-> ([PackageEnvFile] -> ShowS)
-> Show PackageEnvFile
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PackageEnvFile] -> ShowS
$cshowList :: [PackageEnvFile] -> ShowS
show :: PackageEnvFile -> String
$cshow :: PackageEnvFile -> String
showsPrec :: Int -> PackageEnvFile -> ShowS
$cshowsPrec :: Int -> PackageEnvFile -> ShowS
Show)