Skip to content

Commit

Permalink
hooks: Implicitly depend on hooks-exe
Browse files Browse the repository at this point in the history
The `hooks-exe` package enables `SetupHooks` values to be converted into
a `Setup.hs` executable which can be executed independently of Cabal.
The `Setup.hs` executable wrapping `SetupHooks` is quite important to
preserve the interface used by other tools when packages migrate to
`Hooks` from `Custom`.

Even though `hooks-exe` is an internal dependency required by the `Setup.hs`
wrapper around `SetupHooks`, it is a dependency nonetheless.

Given the internal nature of `hooks-exe`, we don't want to impose on our
users the obligation to add a dependency on `hooks-exe` in their
setup-depends field. Instead, we want `hooks-exe` to be implicitly added
to the setup dependencies. This commit does that exactly.
  • Loading branch information
alt-romes committed Apr 18, 2024
1 parent 96b06ad commit eef7121
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 23 deletions.
63 changes: 42 additions & 21 deletions cabal-install/src/Distribution/Client/Dependency.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ module Distribution.Client.Dependency
, addDefaultSetupDependencies
, addSetupCabalMinVersionConstraint
, addSetupCabalMaxVersionConstraint
, setImplicitSetupInfo
, extendSetupInfoDeps
) where

import Distribution.Client.Compat.Prelude
Expand Down Expand Up @@ -591,49 +593,68 @@ removeBound RelaxUpper RelaxDepModNone = removeUpperBound
removeBound RelaxLower RelaxDepModCaret = transformCaretLower
removeBound RelaxUpper RelaxDepModCaret = transformCaretUpper

-- | Supply defaults for packages without explicit Setup dependencies
-- | Supply defaults for packages without explicit Setup dependencies.
-- It also serves to add the implicit dependency on @hooks-exe@ needed to
-- compile the @Setup.hs@ executable produced from 'SetupHooks' when
-- @build-type: Hooks@. The first argument function determines which implicit
-- dependencies are needed (including the one on @hooks-exe@).
--
-- Note: It's important to apply 'addDefaultSetupDepends' after
-- 'addSourcePackages'. Otherwise, the packages inserted by
-- 'addSourcePackages' won't have upper bounds in dependencies relaxed.
addDefaultSetupDependencies
:: (UnresolvedSourcePackage -> Maybe [Dependency])
:: (Maybe [Dependency] -> PD.BuildType -> Maybe PD.SetupBuildInfo -> Maybe PD.SetupBuildInfo)
-- ^ Function to update the SetupBuildInfo of the package using those dependencies
-> (UnresolvedSourcePackage -> Maybe [Dependency])
-- ^ Function to determine extra setup dependencies
-> DepResolverParams
-> DepResolverParams
addDefaultSetupDependencies defaultSetupDeps params =
addDefaultSetupDependencies applyDefaultSetupDeps defaultSetupDeps params =
params
{ depResolverSourcePkgIndex =
fmap applyDefaultSetupDeps (depResolverSourcePkgIndex params)
fmap go (depResolverSourcePkgIndex params)
}
where
applyDefaultSetupDeps :: UnresolvedSourcePackage -> UnresolvedSourcePackage
applyDefaultSetupDeps srcpkg =
go :: UnresolvedSourcePackage -> UnresolvedSourcePackage
go srcpkg =
srcpkg
{ srcpkgDescription =
gpkgdesc
{ PD.packageDescription =
pkgdesc
{ PD.setupBuildInfo =
case PD.setupBuildInfo pkgdesc of
Just sbi -> Just sbi
Nothing -> case defaultSetupDeps srcpkg of
Nothing -> Nothing
Just deps
| isCustom ->
Just
PD.SetupBuildInfo
{ PD.defaultSetupDepends = True
, PD.setupDepends = deps
}
| otherwise -> Nothing
{ PD.setupBuildInfo = applyDefaultSetupDeps (defaultSetupDeps srcpkg) (PD.buildType pkgdesc) (PD.setupBuildInfo pkgdesc)
}
}
}
where
isCustom = PD.buildType pkgdesc == PD.Custom || PD.buildType pkgdesc == PD.Hooks
gpkgdesc = srcpkgDescription srcpkg
pkgdesc = PD.packageDescription gpkgdesc

setImplicitSetupInfo :: Maybe [Dependency] -> PD.BuildType -> Maybe PD.SetupBuildInfo -> Maybe PD.SetupBuildInfo
setImplicitSetupInfo mdeps buildty msetupinfo =
case msetupinfo of
Just sbi -> Just sbi
Nothing -> case mdeps of
Nothing -> Nothing
Just deps
| isCustom ->
Just
PD.SetupBuildInfo
{ PD.defaultSetupDepends = True
, PD.setupDepends = deps
}
| otherwise -> Nothing
where
isCustom = buildty == PD.Custom || buildty == PD.Hooks

extendSetupInfoDeps :: Maybe [Dependency] -> PD.BuildType -> Maybe PD.SetupBuildInfo -> Maybe PD.SetupBuildInfo
extendSetupInfoDeps mDeps buildTy mSetupInfo
| Nothing <- mSetupInfo
= assert (buildTy /= PD.Hooks) -- Hooks needs explicit setup-depends
Nothing
| Just setupInfo <- mSetupInfo
= Just setupInfo{PD.setupDepends = PD.setupDepends setupInfo ++ fromMaybe [] mDeps}

-- | If a package has a custom setup then we need to add a setup-depends
-- on Cabal.
addSetupCabalMinVersionConstraint
Expand Down Expand Up @@ -713,7 +734,7 @@ standardInstallPolicy
-> [PackageSpecifier UnresolvedSourcePackage]
-> DepResolverParams
standardInstallPolicy installedPkgIndex sourcePkgDb pkgSpecifiers =
addDefaultSetupDependencies mkDefaultSetupDeps $
addDefaultSetupDependencies setImplicitSetupInfo mkDefaultSetupDeps $
basicInstallPolicy
installedPkgIndex
sourcePkgDb
Expand Down
8 changes: 8 additions & 0 deletions cabal-install/src/Distribution/Client/ProjectPlanning.hs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ import Distribution.Client.ProjectPlanOutput
import Distribution.Client.ProjectPlanning.SetupPolicy
( NonSetupLibDepSolverPlanPackage (..)
, mkDefaultSetupDeps
, mkHooksSetupImplicitDeps
, packageSetupScriptSpecVersion
, packageSetupScriptStyle
)
Expand Down Expand Up @@ -1261,6 +1262,13 @@ planPackages
. removeLowerBounds solverSettingAllowOlder
. removeUpperBounds solverSettingAllowNewer
. addDefaultSetupDependencies
extendSetupInfoDeps
( mkHooksSetupImplicitDeps
. PD.packageDescription
. srcpkgDescription
)
. addDefaultSetupDependencies
setImplicitSetupInfo
( mkDefaultSetupDeps comp platform
. PD.packageDescription
. srcpkgDescription
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@
-- In cases 1 and 2 we obviously have to build an external Setup.hs script,
-- while in case 4 we can use the internal library API.
--
-- Since @3.14.0.0@ we must also consider the @Setup.hs@ scripts constructed
-- from 'SetupHooks' values, because these generated @Setup.hs@ scripts depend
-- on the @hooks-exe@ package (which creates an executable from 'SetupHooks').
-- Therefore, 'SetupPolicy' is also concerned with augmenting the setup
-- dependencies with @hooks-exe@ when @build-type: Hooks@.
--
-- @since 3.12.0.0
module Distribution.Client.ProjectPlanning.SetupPolicy
( mkDefaultSetupDeps
, mkHooksSetupImplicitDeps
, packageSetupScriptStyle
, packageSetupScriptSpecVersion
, NonSetupLibDepSolverPlanPackage (..)
Expand Down Expand Up @@ -158,6 +165,20 @@ mkDefaultSetupDeps compiler platform pkg =
csvToVersion :: CabalSpecVersion -> Version
csvToVersion = mkVersion . cabalSpecMinimumLibraryVersion

-- | Returns an implicit dependency on @hooks-exe@ needed to create a
-- @Setup.hs@ executable from a 'SetupHooks' value, if @build-type: Hooks@.
--
-- @since 3.14.0.0
mkHooksSetupImplicitDeps
:: PackageDescription
-> Maybe [Dependency]
mkHooksSetupImplicitDeps pkg
| Hooks <- buildType pkg
= Just [Dependency hooksExePkgname anyVersion mainLibSet] -- TODO:FOR:SAM: What version should we constrain hooks-exe to?
| otherwise
= Nothing


-- | A newtype for 'SolverPlanPackage' for which the
-- dependency graph considers only dependencies on libraries which are
-- NOT from setup dependencies. Used to compute the set
Expand Down Expand Up @@ -217,9 +238,10 @@ packageSetupScriptSpecVersion _ pkg libDepGraph deps =
fromMaybe [] $
Graph.closure libDepGraph (CD.setupDeps deps)

cabalPkgname, basePkgname :: PackageName
cabalPkgname, basePkgname, hooksExePkgname :: PackageName
cabalPkgname = mkPackageName "Cabal"
basePkgname = mkPackageName "base"
hooksExePkgname = mkPackageName "hooks-exe"

legacyCustomSetupPkgs :: Compiler -> Platform -> [PackageName]
legacyCustomSetupPkgs compiler (Platform _ os) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ build-type: Hooks
extra-doc-files: CHANGELOG.md

custom-setup
setup-depends: base, Cabal, Cabal-syntax, Cabal-hooks, hooks-exe
setup-depends: base, Cabal, Cabal-syntax, Cabal-hooks
-- Note that we do not include hooks-exe in this cabal package.
-- When using build-type: Hooks, an implicit setup dependency should be
-- introduced in hooks-exe in order to construct the Setup.hs executable
-- from the hooks.
-- This softly doubles as a test for that.

library
exposed-modules: MyLib
Expand Down

0 comments on commit eef7121

Please sign in to comment.