Commit 5f5d9598 authored by Duncan Coutts's avatar Duncan Coutts

Split types out of ProjectBuilding to avoid cycles

We're going to need ProjectPlanOutput to import the ProjectBuilding
types, but this would cause a cycle with ProjectPlanning. So do the same
thing we did with ProjectPlanning and move the types out.
parent ca4f0f1d
{-# LANGUAGE CPP, BangPatterns, RecordWildCards, NamedFieldPuns,
DeriveGeneric, DeriveDataTypeable, GeneralizedNewtypeDeriving,
ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoMonoLocalBinds #-}
......@@ -41,6 +40,7 @@ import Distribution.Client.RebuildMonad
import Distribution.Client.ProjectConfig
import Distribution.Client.ProjectPlanning
import Distribution.Client.ProjectPlanning.Types
import Distribution.Client.ProjectBuilding.Types
import Distribution.Client.Types
hiding (BuildOutcomes, BuildOutcome,
......@@ -87,7 +87,6 @@ import Control.Monad
import Control.Exception
import Data.List
import Data.Maybe
import Data.Typeable
import System.FilePath
import System.IO
......@@ -146,122 +145,12 @@ import System.Directory
-- * Dry run: what bits of the 'ElaboratedInstallPlan' will we execute?
------------------------------------------------------------------------------
-- | The 'BuildStatus' of every package in the 'ElaboratedInstallPlan'.
--
-- This is used as the result of the dry-run of building an install plan.
--
type BuildStatusMap = Map UnitId BuildStatus
-- | The build status for an individual package is the state that the
-- package is in /prior/ to initiating a (re)build.
--
-- This should not be confused with a 'BuildResult' which is the result
-- /after/ successfully building a package.
--
-- It serves two purposes:
--
-- * For dry-run output, it lets us explain to the user if and why a package
-- is going to be (re)built.
--
-- * It tell us what step to start or resume building from, and carries
-- enough information for us to be able to do so.
--
data BuildStatus =
-- Refer to ProjectBuilding.Types for details of these important types:
-- | The package is in the 'InstallPlan.PreExisting' state, so does not
-- need building.
BuildStatusPreExisting
-- | The package is in the 'InstallPlan.Installed' state, so does not
-- need building.
| BuildStatusInstalled
-- | The package has not been downloaded yet, so it will have to be
-- downloaded, unpacked and built.
| BuildStatusDownload
-- | The package has not been unpacked yet, so it will have to be
-- unpacked and built.
| BuildStatusUnpack FilePath
-- | The package exists in a local dir already, and just needs building
-- or rebuilding. So this can only happen for 'BuildInplaceOnly' style
-- packages.
| BuildStatusRebuild FilePath BuildStatusRebuild
-- | The package exists in a local dir already, and is fully up to date.
-- So this package can be put into the 'InstallPlan.Installed' state
-- and it does not need to be built.
| BuildStatusUpToDate BuildResult
-- | This is primarily here for debugging. It's not actually used anywhere.
--
buildStatusToString :: BuildStatus -> String
buildStatusToString BuildStatusPreExisting = "BuildStatusPreExisting"
buildStatusToString BuildStatusInstalled = "BuildStatusInstalled"
buildStatusToString BuildStatusDownload = "BuildStatusDownload"
buildStatusToString (BuildStatusUnpack fp) = "BuildStatusUnpack " ++ show fp
buildStatusToString (BuildStatusRebuild fp _) = "BuildStatusRebuild " ++ show fp
buildStatusToString (BuildStatusUpToDate _) = "BuildStatusUpToDate"
-- | For a package that is going to be built or rebuilt, the state it's in now.
--
-- So again, this tells us why a package needs to be rebuilt and what build
-- phases need to be run. The 'MonitorChangedReason' gives us details like
-- which file changed, which is mainly for high verbosity debug output.
--
data BuildStatusRebuild =
-- | The package configuration changed, so the configure and build phases
-- needs to be (re)run.
BuildStatusConfigure (MonitorChangedReason ())
-- | The configuration has not changed but the build phase needs to be
-- rerun. We record the reason the (re)build is needed.
--
-- The optional registration info here tells us if we've registered the
-- package already, or if we still need to do that after building.
-- @Just Nothing@ indicates that we know that no registration is
-- necessary (e.g., executable.)
--
| BuildStatusBuild (Maybe (Maybe InstalledPackageInfo)) BuildReason
data BuildReason =
-- | The dependencies of this package have been (re)built so the build
-- phase needs to be rerun.
--
BuildReasonDepsRebuilt
-- | Changes in files within the package (or first run or corrupt cache)
| BuildReasonFilesChanged (MonitorChangedReason ())
-- | An important special case is that no files have changed but the
-- set of components the /user asked to build/ has changed. We track the
-- set of components /we have built/, which of course only grows (until
-- some other change resets it).
--
-- The @Set 'ComponentName'@ is the set of components we have built
-- previously. When we update the monitor we take the union of the ones
-- we have built previously with the ones the user has asked for this
-- time and save those. See 'updatePackageBuildFileMonitor'.
--
| BuildReasonExtraTargets (Set ComponentName)
-- | Although we're not going to build any additional targets as a whole,
-- we're going to build some part of a component or run a repl or any
-- other action that does not result in additional persistent artifacts.
--
| BuildReasonEphemeralTargets
-- | Which 'BuildStatus' values indicate we'll have to do some build work of
-- some sort. In particular we use this as part of checking if any of a
-- package's deps have changed.
--
buildStatusRequiresBuild :: BuildStatus -> Bool
buildStatusRequiresBuild BuildStatusPreExisting = False
buildStatusRequiresBuild BuildStatusInstalled = False
buildStatusRequiresBuild BuildStatusUpToDate {} = False
buildStatusRequiresBuild _ = True
-- type BuildStatusMap = ...
-- data BuildStatus = ...
-- data BuildStatusRebuild = ...
-- data BuildReason = ...
-- | Do the dry run pass. This is a prerequisite of 'rebuildTargets'.
--
......@@ -607,56 +496,13 @@ invalidatePackageRegFileMonitor PackageFileMonitor{pkgFileMonitorReg} =
-- * Doing it: executing an 'ElaboratedInstallPlan'
------------------------------------------------------------------------------
-- | A summary of the outcome for building a whole set of packages.
--
type BuildOutcomes = Map UnitId BuildOutcome
-- | A summary of the outcome for building a single package: either success
-- or failure.
--
type BuildOutcome = Either BuildFailure BuildResult
-- | Information arising from successfully building a single package.
--
data BuildResult = BuildResult {
buildResultDocs :: DocsResult,
buildResultTests :: TestsResult,
buildResultLogFile :: Maybe FilePath,
-- | If the build was for a library, this field will be @Just@;
-- otherwise, it will be @Nothing@. What about internal
-- libraries? This never occurs, because a build result is either
-- for a per-component build (in which case there won't
-- be multiple libraries), or a package with no internal
-- libraries (internal libraries with Custom setups are NOT
-- supported, and even if they were supported, we could
-- assume the Cabal library version was recent enough to
-- support per-component build.).
buildResultLibInfo :: Maybe InstalledPackageInfo
}
deriving Show
-- Refer to ProjectBuilding.Types for details of these important types:
-- | Information arising from the failure to build a single package.
--
data BuildFailure = BuildFailure {
buildFailureLogFile :: Maybe FilePath,
buildFailureReason :: BuildFailureReason
}
deriving (Show, Typeable)
instance Exception BuildFailure
-- | Detail on the reason that a package failed to build.
--
data BuildFailureReason = DependentFailed PackageId
| DownloadFailed SomeException
| UnpackFailed SomeException
| ConfigureFailed SomeException
| BuildFailed SomeException
| ReplFailed SomeException
| HaddocksFailed SomeException
| TestsFailed SomeException
| InstallFailed SomeException
deriving Show
-- type BuildOutcomes = ...
-- type BuildOutcome = ...
-- data BuildResult = ...
-- data BuildFailure = ...
-- data BuildFailureReason = ...
-- | Build things for real.
--
......
{-# LANGUAGE DeriveDataTypeable #-}
-- | Types for the "Distribution.Client.ProjectBuilding"
--
-- Moved out to avoid module cycles.
--
module Distribution.Client.ProjectBuilding.Types (
-- * Pre-build status
BuildStatusMap,
BuildStatus(..),
buildStatusRequiresBuild,
buildStatusToString,
BuildStatusRebuild(..),
BuildReason(..),
MonitorChangedReason(..),
-- * Build outcomes
BuildOutcomes,
BuildOutcome,
BuildResult(..),
BuildFailure(..),
BuildFailureReason(..),
) where
import Distribution.Client.Types (DocsResult, TestsResult)
import Distribution.Client.FileMonitor (MonitorChangedReason(..))
import Distribution.Package (UnitId, PackageId)
import Distribution.InstalledPackageInfo (InstalledPackageInfo)
import Distribution.Simple.LocalBuildInfo (ComponentName)
import Data.Map (Map)
import Data.Set (Set)
import Data.Typeable (Typeable)
import Control.Exception (Exception, SomeException)
------------------------------------------------------------------------------
-- Pre-build status: result of the dry run
--
-- | The 'BuildStatus' of every package in the 'ElaboratedInstallPlan'.
--
-- This is used as the result of the dry-run of building an install plan.
--
type BuildStatusMap = Map UnitId BuildStatus
-- | The build status for an individual package is the state that the
-- package is in /prior/ to initiating a (re)build.
--
-- This should not be confused with a 'BuildResult' which is the result
-- /after/ successfully building a package.
--
-- It serves two purposes:
--
-- * For dry-run output, it lets us explain to the user if and why a package
-- is going to be (re)built.
--
-- * It tell us what step to start or resume building from, and carries
-- enough information for us to be able to do so.
--
data BuildStatus =
-- | The package is in the 'InstallPlan.PreExisting' state, so does not
-- need building.
BuildStatusPreExisting
-- | The package is in the 'InstallPlan.Installed' state, so does not
-- need building.
| BuildStatusInstalled
-- | The package has not been downloaded yet, so it will have to be
-- downloaded, unpacked and built.
| BuildStatusDownload
-- | The package has not been unpacked yet, so it will have to be
-- unpacked and built.
| BuildStatusUnpack FilePath
-- | The package exists in a local dir already, and just needs building
-- or rebuilding. So this can only happen for 'BuildInplaceOnly' style
-- packages.
| BuildStatusRebuild FilePath BuildStatusRebuild
-- | The package exists in a local dir already, and is fully up to date.
-- So this package can be put into the 'InstallPlan.Installed' state
-- and it does not need to be built.
| BuildStatusUpToDate BuildResult
-- | Which 'BuildStatus' values indicate we'll have to do some build work of
-- some sort. In particular we use this as part of checking if any of a
-- package's deps have changed.
--
buildStatusRequiresBuild :: BuildStatus -> Bool
buildStatusRequiresBuild BuildStatusPreExisting = False
buildStatusRequiresBuild BuildStatusInstalled = False
buildStatusRequiresBuild BuildStatusUpToDate {} = False
buildStatusRequiresBuild _ = True
-- | This is primarily here for debugging. It's not actually used anywhere.
--
buildStatusToString :: BuildStatus -> String
buildStatusToString BuildStatusPreExisting = "BuildStatusPreExisting"
buildStatusToString BuildStatusInstalled = "BuildStatusInstalled"
buildStatusToString BuildStatusDownload = "BuildStatusDownload"
buildStatusToString (BuildStatusUnpack fp) = "BuildStatusUnpack " ++ show fp
buildStatusToString (BuildStatusRebuild fp _) = "BuildStatusRebuild " ++ show fp
buildStatusToString (BuildStatusUpToDate _) = "BuildStatusUpToDate"
-- | For a package that is going to be built or rebuilt, the state it's in now.
--
-- So again, this tells us why a package needs to be rebuilt and what build
-- phases need to be run. The 'MonitorChangedReason' gives us details like
-- which file changed, which is mainly for high verbosity debug output.
--
data BuildStatusRebuild =
-- | The package configuration changed, so the configure and build phases
-- needs to be (re)run.
BuildStatusConfigure (MonitorChangedReason ())
-- | The configuration has not changed but the build phase needs to be
-- rerun. We record the reason the (re)build is needed.
--
-- The optional registration info here tells us if we've registered the
-- package already, or if we still need to do that after building.
-- @Just Nothing@ indicates that we know that no registration is
-- necessary (e.g., executable.)
--
| BuildStatusBuild (Maybe (Maybe InstalledPackageInfo)) BuildReason
data BuildReason =
-- | The dependencies of this package have been (re)built so the build
-- phase needs to be rerun.
--
BuildReasonDepsRebuilt
-- | Changes in files within the package (or first run or corrupt cache)
| BuildReasonFilesChanged (MonitorChangedReason ())
-- | An important special case is that no files have changed but the
-- set of components the /user asked to build/ has changed. We track the
-- set of components /we have built/, which of course only grows (until
-- some other change resets it).
--
-- The @Set 'ComponentName'@ is the set of components we have built
-- previously. When we update the monitor we take the union of the ones
-- we have built previously with the ones the user has asked for this
-- time and save those. See 'updatePackageBuildFileMonitor'.
--
| BuildReasonExtraTargets (Set ComponentName)
-- | Although we're not going to build any additional targets as a whole,
-- we're going to build some part of a component or run a repl or any
-- other action that does not result in additional persistent artifacts.
--
| BuildReasonEphemeralTargets
------------------------------------------------------------------------------
-- Build outcomes: result of the build
--
-- | A summary of the outcome for building a whole set of packages.
--
type BuildOutcomes = Map UnitId BuildOutcome
-- | A summary of the outcome for building a single package: either success
-- or failure.
--
type BuildOutcome = Either BuildFailure BuildResult
-- | Information arising from successfully building a single package.
--
data BuildResult = BuildResult {
buildResultDocs :: DocsResult,
buildResultTests :: TestsResult,
buildResultLogFile :: Maybe FilePath,
-- | If the build was for a library, this field will be @Just@;
-- otherwise, it will be @Nothing@. What about internal
-- libraries? This never occurs, because a build result is either
-- for a per-component build (in which case there won't
-- be multiple libraries), or a package with no internal
-- libraries (internal libraries with Custom setups are NOT
-- supported, and even if they were supported, we could
-- assume the Cabal library version was recent enough to
-- support per-component build.).
buildResultLibInfo :: Maybe InstalledPackageInfo
}
deriving Show
-- | Information arising from the failure to build a single package.
--
data BuildFailure = BuildFailure {
buildFailureLogFile :: Maybe FilePath,
buildFailureReason :: BuildFailureReason
}
deriving (Show, Typeable)
instance Exception BuildFailure
-- | Detail on the reason that a package failed to build.
--
data BuildFailureReason = DependentFailed PackageId
| DownloadFailed SomeException
| UnpackFailed SomeException
| ConfigureFailed SomeException
| BuildFailed SomeException
| ReplFailed SomeException
| HaddocksFailed SomeException
| TestsFailed SomeException
| InstallFailed SomeException
deriving Show
......@@ -278,6 +278,7 @@ executable cabal
Distribution.Client.PackageUtils
Distribution.Client.ParseUtils
Distribution.Client.ProjectBuilding
Distribution.Client.ProjectBuilding.Types
Distribution.Client.ProjectConfig
Distribution.Client.ProjectConfig.Types
Distribution.Client.ProjectConfig.Legacy
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment