stack-2.9.1: src/Stack/Types/SourceMap.hs
{-# LANGUAGE NoImplicitPrelude #-}
-- | A sourcemap maps a package name to how it should be built,
-- including source code, flags, options, etc. This module contains
-- various stages of source map construction. See the
-- @build_overview.md@ doc for details on these stages.
module Stack.Types.SourceMap
( -- * Different source map types
SMWanted (..)
, SMActual (..)
, Target (..)
, PackageType (..)
, SMTargets (..)
, SourceMap (..)
-- * Helper types
, FromSnapshot (..)
, DepPackage (..)
, ProjectPackage (..)
, CommonPackage (..)
, GlobalPackageVersion (..)
, GlobalPackage (..)
, isReplacedGlobal
, SourceMapHash (..)
, smRelDir
) where
import qualified Data.Text as T
import qualified Pantry.SHA256 as SHA256
import Path
import Stack.Prelude
import Stack.Types.Compiler
import Stack.Types.NamedComponent
import Distribution.PackageDescription (GenericPackageDescription)
-- | Common settings for both dependency and project package.
data CommonPackage = CommonPackage
{ cpGPD :: !(IO GenericPackageDescription)
, cpName :: !PackageName
, cpFlags :: !(Map FlagName Bool)
-- ^ overrides default flags
, cpGhcOptions :: ![Text] -- also lets us know if we're doing profiling
, cpCabalConfigOpts :: ![Text]
, cpHaddocks :: !Bool
}
-- | Flag showing if package comes from a snapshot
-- needed to ignore dependency bounds between such packages
data FromSnapshot
= FromSnapshot
| NotFromSnapshot
deriving (Show)
-- | A view of a dependency package, specified in stack.yaml
data DepPackage = DepPackage
{ dpCommon :: !CommonPackage
, dpLocation :: !PackageLocation
, dpHidden :: !Bool
-- ^ Should the package be hidden after registering?
-- Affects the script interpreter's module name import parser.
, dpFromSnapshot :: !FromSnapshot
-- ^ Needed to ignore bounds between snapshot packages
-- See https://github.com/commercialhaskell/stackage/issues/3185
}
-- | A view of a project package needed for resolving components
data ProjectPackage = ProjectPackage
{ ppCommon :: !CommonPackage
, ppCabalFP :: !(Path Abs File)
, ppResolvedDir :: !(ResolvedPath Dir)
}
-- | A view of a package installed in the global package database also
-- could include marker for a replaced global package (could be replaced
-- because of a replaced dependency)
data GlobalPackage
= GlobalPackage !Version
| ReplacedGlobalPackage ![PackageName]
deriving Eq
isReplacedGlobal :: GlobalPackage -> Bool
isReplacedGlobal (ReplacedGlobalPackage _) = True
isReplacedGlobal (GlobalPackage _) = False
-- | A source map with information on the wanted (but not actual)
-- compiler. This is derived by parsing the @stack.yaml@ file for
-- @packages@, @extra-deps@, their configuration (e.g., flags and
-- options), and parsing the snapshot it refers to. It does not
-- include global packages or any information from the command line.
--
-- Invariant: a @PackageName@ appears in either 'smwProject' or
-- 'smwDeps', but not both.
data SMWanted = SMWanted
{ smwCompiler :: !WantedCompiler
, smwProject :: !(Map PackageName ProjectPackage)
, smwDeps :: !(Map PackageName DepPackage)
, smwSnapshotLocation :: !RawSnapshotLocation
-- ^ Where this snapshot is loaded from.
}
-- | Adds in actual compiler information to 'SMWanted', in particular
-- the contents of the global package database.
--
-- Invariant: a @PackageName@ appears in only one of the @Map@s.
data SMActual global = SMActual
{ smaCompiler :: !ActualCompiler
, smaProject :: !(Map PackageName ProjectPackage)
, smaDeps :: !(Map PackageName DepPackage)
, smaGlobal :: !(Map PackageName global)
}
newtype GlobalPackageVersion = GlobalPackageVersion Version
-- | How a package is intended to be built
data Target
= TargetAll !PackageType
-- ^ Build all of the default components.
| TargetComps !(Set NamedComponent)
-- ^ Only build specific components
data PackageType = PTProject | PTDependency
deriving (Eq, Show)
-- | Builds on an 'SMActual' by resolving the targets specified on the
-- command line, potentially adding in new dependency packages in the
-- process.
data SMTargets = SMTargets
{ smtTargets :: !(Map PackageName Target)
, smtDeps :: !(Map PackageName DepPackage)
}
-- | The final source map, taking an 'SMTargets' and applying all
-- command line flags and GHC options.
data SourceMap = SourceMap
{ smTargets :: !SMTargets
-- ^ Doesn't need to be included in the hash, does not affect the
-- source map.
, smCompiler :: !ActualCompiler
-- ^ Need to hash the compiler version _and_ its installation
-- path. Ideally there would be some kind of output from GHC
-- telling us some unique ID for the compiler itself.
, smProject :: !(Map PackageName ProjectPackage)
-- ^ Doesn't need to be included in hash, doesn't affect any of
-- the packages that get stored in the snapshot database.
, smDeps :: !(Map PackageName DepPackage)
-- ^ Need to hash all of the immutable dependencies, can ignore
-- the mutable dependencies.
, smGlobal :: !(Map PackageName GlobalPackage)
-- ^ Doesn't actually need to be hashed, implicitly captured by
-- smCompiler. Can be broken if someone installs new global
-- packages. We can document that as not supported, _or_ we could
-- actually include all of this in the hash and make Stack more
-- resilient.
}
-- | A unique hash for the immutable portions of a 'SourceMap'.
newtype SourceMapHash = SourceMapHash SHA256
-- | Returns relative directory name with source map's hash
smRelDir :: (MonadThrow m) => SourceMapHash -> m (Path Rel Dir)
smRelDir (SourceMapHash smh) = parseRelDir $ T.unpack $ SHA256.toHexText smh