{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}

module Distribution.Client.ProjectBuilding.PackageFileMonitor where

import Distribution.Client.Compat.Prelude
import Prelude ()

import Distribution.Client.ProjectBuilding.Types
import Distribution.Client.ProjectPlanning
import Distribution.Client.ProjectPlanning.Types
import Distribution.Client.RebuildMonad

import Distribution.Client.DistDirLayout
import Distribution.Client.FileMonitor
import Distribution.Client.Types hiding
  ( BuildFailure (..)
  , BuildOutcome
  , BuildOutcomes
  , BuildResult (..)
  )

import Distribution.InstalledPackageInfo (InstalledPackageInfo)
import Distribution.Simple.LocalBuildInfo
  ( ComponentName (..)
  )

import qualified Data.Set as Set
import Distribution.Client.Init.Types (removeExistingFile, runPromptIO)

-----------------------------
-- Package change detection
--

-- | As part of the dry run for local unpacked packages we have to check if the
-- package config or files have changed. That is the purpose of
-- 'PackageFileMonitor' and 'checkPackageFileMonitorChanged'.
--
-- When a package is (re)built, the monitor must be updated to reflect the new
-- state of the package. Because we sometimes build without reconfiguring the
-- state updates are split into two, one for package config changes and one
-- for other changes. This is the purpose of 'updatePackageConfigFileMonitor'
-- and 'updatePackageBuildFileMonitor'.
data PackageFileMonitor = PackageFileMonitor
  { PackageFileMonitor -> FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig :: FileMonitor ElaboratedConfiguredPackage ()
  , PackageFileMonitor
-> FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild :: FileMonitor (Set ComponentName) BuildResultMisc
  , PackageFileMonitor -> FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo)
  }

-- | This is all the components of the 'BuildResult' other than the
-- @['InstalledPackageInfo']@.
--
-- We have to split up the 'BuildResult' components since they get produced
-- at different times (or rather, when different things change).
type BuildResultMisc = (DocsResult, TestsResult)

newPackageFileMonitor
  :: ElaboratedSharedConfig
  -> DistDirLayout
  -> DistDirParams
  -> PackageFileMonitor
newPackageFileMonitor :: ElaboratedSharedConfig
-> DistDirLayout -> DistDirParams -> PackageFileMonitor
newPackageFileMonitor
  ElaboratedSharedConfig
shared
  DistDirLayout{DistDirParams -> String -> String
distPackageCacheFile :: DistDirParams -> String -> String
distPackageCacheFile :: DistDirLayout -> DistDirParams -> String -> String
distPackageCacheFile}
  DistDirParams
dparams =
    PackageFileMonitor
      { pkgFileMonitorConfig :: FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig =
          FileMonitor
            { fileMonitorCacheFile :: String
fileMonitorCacheFile = DistDirParams -> String -> String
distPackageCacheFile DistDirParams
dparams String
"config"
            , fileMonitorKeyValid :: ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage -> Bool
fileMonitorKeyValid = ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage -> Bool
forall a. Eq a => a -> a -> Bool
(==) (ElaboratedConfiguredPackage
 -> ElaboratedConfiguredPackage -> Bool)
-> (ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage)
-> ElaboratedConfiguredPackage
-> ElaboratedConfiguredPackage
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` ElaboratedSharedConfig
-> ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage
normaliseConfiguredPackage ElaboratedSharedConfig
shared
            , fileMonitorCheckIfOnlyValueChanged :: Bool
fileMonitorCheckIfOnlyValueChanged = Bool
False
            }
      , pkgFileMonitorBuild :: FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild =
          FileMonitor
            { fileMonitorCacheFile :: String
fileMonitorCacheFile = DistDirParams -> String -> String
distPackageCacheFile DistDirParams
dparams String
"build"
            , fileMonitorKeyValid :: Set ComponentName -> Set ComponentName -> Bool
fileMonitorKeyValid = \Set ComponentName
componentsToBuild Set ComponentName
componentsAlreadyBuilt ->
                Set ComponentName
componentsToBuild Set ComponentName -> Set ComponentName -> Bool
forall a. Ord a => Set a -> Set a -> Bool
`Set.isSubsetOf` Set ComponentName
componentsAlreadyBuilt
            , fileMonitorCheckIfOnlyValueChanged :: Bool
fileMonitorCheckIfOnlyValueChanged = Bool
True
            }
      , pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg =
          String -> FileMonitor () (Maybe InstalledPackageInfo)
forall a b. Eq a => String -> FileMonitor a b
newFileMonitor (DistDirParams -> String -> String
distPackageCacheFile DistDirParams
dparams String
"registration")
      }

-- | Helper function for 'checkPackageFileMonitorChanged',
-- 'updatePackageConfigFileMonitor' and 'updatePackageBuildFileMonitor'.
--
-- It selects the info from a 'ElaboratedConfiguredPackage' that are used by
-- the 'FileMonitor's (in the 'PackageFileMonitor') to detect value changes.
packageFileMonitorKeyValues
  :: ElaboratedConfiguredPackage
  -> (ElaboratedConfiguredPackage, Set ComponentName)
packageFileMonitorKeyValues :: ElaboratedConfiguredPackage
-> (ElaboratedConfiguredPackage, Set ComponentName)
packageFileMonitorKeyValues ElaboratedConfiguredPackage
elab =
  (ElaboratedConfiguredPackage
elab_config, Set ComponentName
buildComponents)
  where
    -- The first part is the value used to guard (re)configuring the package.
    -- That is, if this value changes then we will reconfigure.
    -- The ElaboratedConfiguredPackage consists mostly (but not entirely) of
    -- information that affects the (re)configure step. But those parts that
    -- do not affect the configure step need to be nulled out. Those parts are
    -- the specific targets that we're going to build.
    --

    -- Additionally we null out the parts that don't affect the configure step because they're simply
    -- about how tests or benchmarks are run

    -- TODO there may be more things to null here too, in the future.

    elab_config :: ElaboratedConfiguredPackage
    elab_config :: ElaboratedConfiguredPackage
elab_config =
      ElaboratedConfiguredPackage
elab
        { elabBuildTargets = []
        , elabTestTargets = []
        , elabBenchTargets = []
        , elabReplTarget = []
        , elabHaddockTargets = []
        , elabBuildHaddocks = False
        , elabTestMachineLog = Nothing
        , elabTestHumanLog = Nothing
        , elabTestShowDetails = Nothing
        , elabTestKeepTix = False
        , elabTestTestOptions = []
        , elabBenchmarkOptions = []
        }

    -- The second part is the value used to guard the build step. So this is
    -- more or less the opposite of the first part, as it's just the info about
    -- what targets we're going to build.
    --
    buildComponents :: Set ComponentName
    buildComponents :: Set ComponentName
buildComponents = ElaboratedConfiguredPackage -> Set ComponentName
elabBuildTargetWholeComponents ElaboratedConfiguredPackage
elab

-- | Do all the checks on whether a package has changed and thus needs either
-- rebuilding or reconfiguring and rebuilding.
checkPackageFileMonitorChanged
  :: PackageFileMonitor
  -> ElaboratedConfiguredPackage
  -> FilePath
  -> [BuildStatus]
  -> IO (Either BuildStatusRebuild BuildResult)
checkPackageFileMonitorChanged :: PackageFileMonitor
-> ElaboratedConfiguredPackage
-> String
-> [BuildStatus]
-> IO (Either BuildStatusRebuild BuildResult)
checkPackageFileMonitorChanged
  PackageFileMonitor{FileMonitor () (Maybe InstalledPackageInfo)
FileMonitor (Set ComponentName) BuildResultMisc
FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig :: PackageFileMonitor -> FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorBuild :: PackageFileMonitor
-> FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorReg :: PackageFileMonitor -> FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorConfig :: FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorBuild :: FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo)
..}
  ElaboratedConfiguredPackage
pkg
  String
srcdir
  [BuildStatus]
depsBuildStatus = do
    -- TODO: [nice to have] some debug-level message about file
    -- changes, like rerunIfChanged
    MonitorChanged ElaboratedConfiguredPackage ()
configChanged <-
      FileMonitor ElaboratedConfiguredPackage ()
-> String
-> ElaboratedConfiguredPackage
-> IO (MonitorChanged ElaboratedConfiguredPackage ())
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b -> String -> a -> IO (MonitorChanged a b)
checkFileMonitorChanged
        FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig
        String
srcdir
        ElaboratedConfiguredPackage
pkgconfig
    case MonitorChanged ElaboratedConfiguredPackage ()
configChanged of
      MonitorChanged MonitorChangedReason ElaboratedConfiguredPackage
monitorReason ->
        Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildStatusRebuild -> Either BuildStatusRebuild BuildResult
forall a b. a -> Either a b
Left (MonitorChangedReason () -> BuildStatusRebuild
BuildStatusConfigure MonitorChangedReason ()
monitorReason'))
        where
          monitorReason' :: MonitorChangedReason ()
monitorReason' = (ElaboratedConfiguredPackage -> ())
-> MonitorChangedReason ElaboratedConfiguredPackage
-> MonitorChangedReason ()
forall a b.
(a -> b) -> MonitorChangedReason a -> MonitorChangedReason b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> ElaboratedConfiguredPackage -> ()
forall a b. a -> b -> a
const ()) MonitorChangedReason ElaboratedConfiguredPackage
monitorReason
      MonitorUnchanged () [MonitorFilePath]
_
        -- The configChanged here includes the identity of the dependencies,
        -- so depsBuildStatus is just needed for the changes in the content
        -- of dependencies.
        | (BuildStatus -> Bool) -> [BuildStatus] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any BuildStatus -> Bool
buildStatusRequiresBuild [BuildStatus]
depsBuildStatus -> do
            MonitorChanged () (Maybe InstalledPackageInfo)
regChanged <- FileMonitor () (Maybe InstalledPackageInfo)
-> String
-> ()
-> IO (MonitorChanged () (Maybe InstalledPackageInfo))
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b -> String -> a -> IO (MonitorChanged a b)
checkFileMonitorChanged FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg String
srcdir ()
            let mreg :: Maybe (Maybe InstalledPackageInfo)
mreg = MonitorChanged () (Maybe InstalledPackageInfo)
-> Maybe (Maybe InstalledPackageInfo)
forall a b. MonitorChanged a b -> Maybe b
changedToMaybe MonitorChanged () (Maybe InstalledPackageInfo)
regChanged
            Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildStatusRebuild -> Either BuildStatusRebuild BuildResult
forall a b. a -> Either a b
Left (Maybe (Maybe InstalledPackageInfo)
-> BuildReason -> BuildStatusRebuild
BuildStatusBuild Maybe (Maybe InstalledPackageInfo)
mreg BuildReason
BuildReasonDepsRebuilt))
        | Bool
otherwise -> do
            MonitorChanged (Set ComponentName) BuildResultMisc
buildChanged <-
              FileMonitor (Set ComponentName) BuildResultMisc
-> String
-> Set ComponentName
-> IO (MonitorChanged (Set ComponentName) BuildResultMisc)
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b -> String -> a -> IO (MonitorChanged a b)
checkFileMonitorChanged
                FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild
                String
srcdir
                Set ComponentName
buildComponents
            MonitorChanged () (Maybe InstalledPackageInfo)
regChanged <-
              FileMonitor () (Maybe InstalledPackageInfo)
-> String
-> ()
-> IO (MonitorChanged () (Maybe InstalledPackageInfo))
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b -> String -> a -> IO (MonitorChanged a b)
checkFileMonitorChanged
                FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg
                String
srcdir
                ()
            let mreg :: Maybe (Maybe InstalledPackageInfo)
mreg = MonitorChanged () (Maybe InstalledPackageInfo)
-> Maybe (Maybe InstalledPackageInfo)
forall a b. MonitorChanged a b -> Maybe b
changedToMaybe MonitorChanged () (Maybe InstalledPackageInfo)
regChanged
            case (MonitorChanged (Set ComponentName) BuildResultMisc
buildChanged, MonitorChanged () (Maybe InstalledPackageInfo)
regChanged) of
              (MonitorChanged (MonitoredValueChanged Set ComponentName
prevBuildComponents), MonitorChanged () (Maybe InstalledPackageInfo)
_) ->
                Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildStatusRebuild -> Either BuildStatusRebuild BuildResult
forall a b. a -> Either a b
Left (Maybe (Maybe InstalledPackageInfo)
-> BuildReason -> BuildStatusRebuild
BuildStatusBuild Maybe (Maybe InstalledPackageInfo)
mreg BuildReason
buildReason))
                where
                  buildReason :: BuildReason
buildReason = Set ComponentName -> BuildReason
BuildReasonExtraTargets Set ComponentName
prevBuildComponents
              (MonitorChanged MonitorChangedReason (Set ComponentName)
monitorReason, MonitorChanged () (Maybe InstalledPackageInfo)
_) ->
                Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildStatusRebuild -> Either BuildStatusRebuild BuildResult
forall a b. a -> Either a b
Left (Maybe (Maybe InstalledPackageInfo)
-> BuildReason -> BuildStatusRebuild
BuildStatusBuild Maybe (Maybe InstalledPackageInfo)
mreg BuildReason
buildReason))
                where
                  buildReason :: BuildReason
buildReason = MonitorChangedReason () -> BuildReason
BuildReasonFilesChanged MonitorChangedReason ()
monitorReason'
                  monitorReason' :: MonitorChangedReason ()
monitorReason' = (Set ComponentName -> ())
-> MonitorChangedReason (Set ComponentName)
-> MonitorChangedReason ()
forall a b.
(a -> b) -> MonitorChangedReason a -> MonitorChangedReason b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> Set ComponentName -> ()
forall a b. a -> b -> a
const ()) MonitorChangedReason (Set ComponentName)
monitorReason
              (MonitorUnchanged BuildResultMisc
_ [MonitorFilePath]
_, MonitorChanged MonitorChangedReason ()
monitorReason) ->
                -- this should only happen if the file is corrupt or been
                -- manually deleted. We don't want to bother with another
                -- phase just for this, so we'll reregister by doing a build.
                Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildStatusRebuild -> Either BuildStatusRebuild BuildResult
forall a b. a -> Either a b
Left (Maybe (Maybe InstalledPackageInfo)
-> BuildReason -> BuildStatusRebuild
BuildStatusBuild Maybe (Maybe InstalledPackageInfo)
forall a. Maybe a
Nothing BuildReason
buildReason))
                where
                  buildReason :: BuildReason
buildReason = MonitorChangedReason () -> BuildReason
BuildReasonFilesChanged MonitorChangedReason ()
monitorReason'
                  monitorReason' :: MonitorChangedReason ()
monitorReason' = (() -> ()) -> MonitorChangedReason () -> MonitorChangedReason ()
forall a b.
(a -> b) -> MonitorChangedReason a -> MonitorChangedReason b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> () -> ()
forall a b. a -> b -> a
const ()) MonitorChangedReason ()
monitorReason
              (MonitorUnchanged BuildResultMisc
_ [MonitorFilePath]
_, MonitorUnchanged Maybe InstalledPackageInfo
_ [MonitorFilePath]
_)
                | ElaboratedConfiguredPackage -> Bool
pkgHasEphemeralBuildTargets ElaboratedConfiguredPackage
pkg ->
                    Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildStatusRebuild -> Either BuildStatusRebuild BuildResult
forall a b. a -> Either a b
Left (Maybe (Maybe InstalledPackageInfo)
-> BuildReason -> BuildStatusRebuild
BuildStatusBuild Maybe (Maybe InstalledPackageInfo)
mreg BuildReason
buildReason))
                where
                  buildReason :: BuildReason
buildReason = BuildReason
BuildReasonEphemeralTargets
              (MonitorUnchanged BuildResultMisc
buildResult [MonitorFilePath]
_, MonitorUnchanged Maybe InstalledPackageInfo
_ [MonitorFilePath]
_) ->
                Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either BuildStatusRebuild BuildResult
 -> IO (Either BuildStatusRebuild BuildResult))
-> Either BuildStatusRebuild BuildResult
-> IO (Either BuildStatusRebuild BuildResult)
forall a b. (a -> b) -> a -> b
$
                  BuildResult -> Either BuildStatusRebuild BuildResult
forall a b. b -> Either a b
Right
                    BuildResult
                      { buildResultDocs :: DocsResult
buildResultDocs = DocsResult
docsResult
                      , buildResultTests :: TestsResult
buildResultTests = TestsResult
testsResult
                      , buildResultLogFile :: Maybe String
buildResultLogFile = Maybe String
forall a. Maybe a
Nothing
                      }
                where
                  (DocsResult
docsResult, TestsResult
testsResult) = BuildResultMisc
buildResult
    where
      (ElaboratedConfiguredPackage
pkgconfig, Set ComponentName
buildComponents) = ElaboratedConfiguredPackage
-> (ElaboratedConfiguredPackage, Set ComponentName)
packageFileMonitorKeyValues ElaboratedConfiguredPackage
pkg
      changedToMaybe :: MonitorChanged a b -> Maybe b
      changedToMaybe :: forall a b. MonitorChanged a b -> Maybe b
changedToMaybe (MonitorChanged MonitorChangedReason a
_) = Maybe b
forall a. Maybe a
Nothing
      changedToMaybe (MonitorUnchanged b
x [MonitorFilePath]
_) = b -> Maybe b
forall a. a -> Maybe a
Just b
x

updatePackageConfigFileMonitor
  :: PackageFileMonitor
  -> FilePath
  -> ElaboratedConfiguredPackage
  -> IO ()
updatePackageConfigFileMonitor :: PackageFileMonitor
-> String -> ElaboratedConfiguredPackage -> IO ()
updatePackageConfigFileMonitor
  PackageFileMonitor{FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig :: PackageFileMonitor -> FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig :: FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig}
  String
srcdir
  ElaboratedConfiguredPackage
pkg =
    FileMonitor ElaboratedConfiguredPackage ()
-> String
-> Maybe MonitorTimestamp
-> [MonitorFilePath]
-> ElaboratedConfiguredPackage
-> ()
-> IO ()
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b
-> String
-> Maybe MonitorTimestamp
-> [MonitorFilePath]
-> a
-> b
-> IO ()
updateFileMonitor
      FileMonitor ElaboratedConfiguredPackage ()
pkgFileMonitorConfig
      String
srcdir
      Maybe MonitorTimestamp
forall a. Maybe a
Nothing
      []
      ElaboratedConfiguredPackage
pkgconfig
      ()
    where
      (ElaboratedConfiguredPackage
pkgconfig, Set ComponentName
_buildComponents) = ElaboratedConfiguredPackage
-> (ElaboratedConfiguredPackage, Set ComponentName)
packageFileMonitorKeyValues ElaboratedConfiguredPackage
pkg

updatePackageBuildFileMonitor
  :: PackageFileMonitor
  -> FilePath
  -> MonitorTimestamp
  -> ElaboratedConfiguredPackage
  -> BuildStatusRebuild
  -> [MonitorFilePath]
  -> BuildResultMisc
  -> IO ()
updatePackageBuildFileMonitor :: PackageFileMonitor
-> String
-> MonitorTimestamp
-> ElaboratedConfiguredPackage
-> BuildStatusRebuild
-> [MonitorFilePath]
-> BuildResultMisc
-> IO ()
updatePackageBuildFileMonitor
  PackageFileMonitor{FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild :: PackageFileMonitor
-> FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild :: FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild}
  String
srcdir
  MonitorTimestamp
timestamp
  ElaboratedConfiguredPackage
pkg
  BuildStatusRebuild
pkgBuildStatus
  [MonitorFilePath]
monitors
  BuildResultMisc
buildResult =
    FileMonitor (Set ComponentName) BuildResultMisc
-> String
-> Maybe MonitorTimestamp
-> [MonitorFilePath]
-> Set ComponentName
-> BuildResultMisc
-> IO ()
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b
-> String
-> Maybe MonitorTimestamp
-> [MonitorFilePath]
-> a
-> b
-> IO ()
updateFileMonitor
      FileMonitor (Set ComponentName) BuildResultMisc
pkgFileMonitorBuild
      String
srcdir
      (MonitorTimestamp -> Maybe MonitorTimestamp
forall a. a -> Maybe a
Just MonitorTimestamp
timestamp)
      [MonitorFilePath]
monitors
      Set ComponentName
buildComponents'
      BuildResultMisc
buildResult
    where
      (ElaboratedConfiguredPackage
_pkgconfig, Set ComponentName
buildComponents) = ElaboratedConfiguredPackage
-> (ElaboratedConfiguredPackage, Set ComponentName)
packageFileMonitorKeyValues ElaboratedConfiguredPackage
pkg

      -- If the only thing that's changed is that we're now building extra
      -- components, then we can avoid later unnecessary rebuilds by saving the
      -- total set of components that have been built, namely the union of the
      -- existing ones plus the new ones. If files also changed this would be
      -- the wrong thing to do. Note that we rely on the
      -- fileMonitorCheckIfOnlyValueChanged = True mode to get this guarantee
      -- that it's /only/ the value that changed not any files that changed.
      buildComponents' :: Set ComponentName
buildComponents' =
        case BuildStatusRebuild
pkgBuildStatus of
          BuildStatusBuild Maybe (Maybe InstalledPackageInfo)
_ (BuildReasonExtraTargets Set ComponentName
prevBuildComponents) ->
            Set ComponentName
buildComponents Set ComponentName -> Set ComponentName -> Set ComponentName
forall a. Ord a => Set a -> Set a -> Set a
`Set.union` Set ComponentName
prevBuildComponents
          BuildStatusRebuild
_ -> Set ComponentName
buildComponents

updatePackageRegFileMonitor
  :: PackageFileMonitor
  -> FilePath
  -> Maybe InstalledPackageInfo
  -> IO ()
updatePackageRegFileMonitor :: PackageFileMonitor -> String -> Maybe InstalledPackageInfo -> IO ()
updatePackageRegFileMonitor
  PackageFileMonitor{FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg :: PackageFileMonitor -> FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg}
  String
srcdir
  Maybe InstalledPackageInfo
mipkg =
    FileMonitor () (Maybe InstalledPackageInfo)
-> String
-> Maybe MonitorTimestamp
-> [MonitorFilePath]
-> ()
-> Maybe InstalledPackageInfo
-> IO ()
forall a b.
(Binary a, Structured a, Binary b, Structured b) =>
FileMonitor a b
-> String
-> Maybe MonitorTimestamp
-> [MonitorFilePath]
-> a
-> b
-> IO ()
updateFileMonitor
      FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg
      String
srcdir
      Maybe MonitorTimestamp
forall a. Maybe a
Nothing
      []
      ()
      Maybe InstalledPackageInfo
mipkg

invalidatePackageRegFileMonitor :: PackageFileMonitor -> IO ()
invalidatePackageRegFileMonitor :: PackageFileMonitor -> IO ()
invalidatePackageRegFileMonitor PackageFileMonitor{FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg :: PackageFileMonitor -> FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg} =
  PromptIO () -> IO ()
forall a. PromptIO a -> IO a
runPromptIO (PromptIO () -> IO ()) -> PromptIO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> PromptIO ()
forall (m :: * -> *). Interactive m => String -> m ()
removeExistingFile (FileMonitor () (Maybe InstalledPackageInfo) -> String
forall a b. FileMonitor a b -> String
fileMonitorCacheFile FileMonitor () (Maybe InstalledPackageInfo)
pkgFileMonitorReg)