Skip to content

Commit 45b37b8

Browse files
committed
Hooks: use the appropriate Cabal unit ID
This commit updates the logic in Distribution.Client.Dependency, namely addDefaultSetupDependencies, to add an implicit Cabal dependency for the custom setup stanza of packages with build-type: Hooks. This ensures we always pick a version of Cabal that is compatible with whatever other libraries the custom-setup stanza depends on (such as Cabal-hooks). Test in T11331. Fixes #11331
1 parent 6cc9c63 commit 45b37b8

15 files changed

Lines changed: 192 additions & 1 deletion

File tree

cabal-install/src/Distribution/Client/Dependency.hs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,14 @@ addDefaultSetupDependencies defaultSetupDeps params =
638638
pkgdesc
639639
{ PD.setupBuildInfo =
640640
case PD.setupBuildInfo pkgdesc of
641-
Just sbi -> Just sbi
641+
Just sbi ->
642+
let
643+
sbi' =
644+
case PD.buildType pkgdesc of
645+
PD.Hooks -> addCabalDepForHooks sbi
646+
_ -> sbi
647+
in
648+
Just sbi'
642649
Nothing -> case defaultSetupDeps srcpkg of
643650
Nothing -> Nothing
644651
Just deps
@@ -657,6 +664,21 @@ addDefaultSetupDependencies defaultSetupDeps params =
657664
gpkgdesc = srcpkgDescription srcpkg
658665
pkgdesc = PD.packageDescription gpkgdesc
659666

667+
-- | Add an implicit dependency on 'Cabal' for a @build-type: Hooks@ package
668+
-- that doesn't explicitly depend on 'Cabal'.
669+
--
670+
-- This ensures the solver picks a consistent version of 'Cabal' when other
671+
-- packages in the 'setup-depends' stanza depend on 'Cabal'.
672+
-- See https://github.com/haskell/cabal/issues/11331.
673+
addCabalDepForHooks :: PD.SetupBuildInfo -> PD.SetupBuildInfo
674+
addCabalDepForHooks sbi@(PD.SetupBuildInfo{PD.setupDepends = deps})
675+
| any ((== cabalPkgName) . depPkgName) deps =
676+
sbi
677+
| otherwise =
678+
sbi{PD.setupDepends = Dependency cabalPkgName anyVersion mainLibSet : deps}
679+
where
680+
cabalPkgName = mkPackageName "Cabal"
681+
660682
-- | If a package has a custom setup then we need to add a setup-depends
661683
-- on Cabal.
662684
addSetupCabalMinVersionConstraint
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cabal-version: 2.4
2+
name: Cabal
3+
version: 3.16.666.0
4+
library
5+
default-language: Haskell2010
6+
build-depends: stub == 0.1
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cabal-version: 2.4
2+
name: Cabal
3+
version: 3.16.777.0
4+
library
5+
default-language: Haskell2010
6+
build-depends: base, stub == 0.2
7+
exposed-modules:
8+
Distribution.Simple.SetupHooks
9+
Distribution.Simple
10+
hs-source-dirs: src
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Distribution.Simple ( defaultMainWithSetupHooks ) where
2+
3+
import System.Exit (exitFailure)
4+
import Distribution.Simple.SetupHooks ( SetupHooks )
5+
6+
defaultMainWithSetupHooks :: SetupHooks -> IO ()
7+
defaultMainWithSetupHooks _ = do
8+
putStrLn "Chosen GOOD Cabal"
9+
exitFailure
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Distribution.Simple.SetupHooks where
2+
3+
data SetupHooks = SetupHooks
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
3+
module Main where
4+
5+
-- Cabal
6+
import Distribution.Simple ( defaultMainWithSetupHooks )
7+
8+
-- T11331
9+
import SetupHooks ( setupHooks )
10+
11+
--------------------------------------------------------------------------------
12+
13+
main :: IO ()
14+
main = defaultMainWithSetupHooks setupHooks
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module SetupHooks (setupHooks) where
2+
3+
-- fancy-hooks
4+
import FancyHooks (setupHooks)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
cabal-version: 3.14
2+
name: T11331
3+
version: 0.1.0.0
4+
synopsis: Test for Cabal bug 11331
5+
license: BSD-3-Clause
6+
author: NA
7+
maintainer: NA
8+
category: Testing
9+
build-type: Hooks
10+
11+
custom-setup
12+
setup-depends: fancy-hooks
13+
14+
library
15+
default-language: Haskell2010
16+
build-depends: stub == 0.1
17+
18+
-- See cabal.test.hs for explanation of this test.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
packages: .
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import Test.Cabal.Prelude
2+
3+
{- Test for https://github.com/haskell/cabal/issues/11331
4+
5+
This test works by having a package database with two Cabal libraries in it,
6+
a good one (Cabal-good) and a poisoned one (Cabal-bad).
7+
8+
Cabal-good depends on stub == 0.2 and Cabal-bad depends on stub == 0.1.
9+
10+
Moreover, we have a fancy-hooks package in the package database, that has been
11+
built against Cabal-good.
12+
13+
T11331 has the following Cabal file:
14+
15+
T11331.setup --> fancy-hooks
16+
T11331.lib --> stub == 0.1
17+
18+
The test checks that, for the setup component, we correctly use Cabal-good
19+
and not Cabal-bad, as only Cabal-good is compatible with fancy-hooks (correct
20+
ABI hash of Cabal dependency).
21+
-}
22+
main :: IO ()
23+
main = setupAndCabalTest $ recordMode DoNotRecord $ withPackageDb $ do
24+
-- Build good package set 'fancy-hooks -> Cabal-good -> stub-0.2' first.
25+
withDirectory "stub-0.2" $ do
26+
setup "configure" []
27+
setup "build" []
28+
setup "register" ["--inplace"]
29+
withDirectory "Cabal-good" $ do
30+
setup "configure" []
31+
setup "build" []
32+
setup "register" ["--inplace"]
33+
withDirectory "fancy-hooks" $ do
34+
setup "configure" []
35+
setup "build" []
36+
setup "register" ["--inplace"]
37+
38+
-- Now build bad package set 'Cabal-bad -> stub-0.1'.
39+
withDirectory "stub-0.1" $ do
40+
setup "configure" []
41+
setup "build" []
42+
setup "register" ["--inplace"]
43+
withDirectory "Cabal-bad" $ do
44+
setup "configure" []
45+
setup "build" []
46+
setup "register" ["--inplace"]
47+
48+
-- Now try to build 'T11331' with cabal-install, using the package database
49+
-- that we carefully crafted above. This tests that cabal-install picks
50+
-- 'Cabal-good' for the setup component of 'T11331', otherwise we will fail.
51+
dbDir <- testPackageDbDir <$> getTestEnv
52+
53+
-- This fails because the fake Cabal-good defaultMain doesn't do anything
54+
-- except print "Chosen GOOD Cabal".
55+
res <- fails $ cabal' "build" [ "--package-db=" ++ dbDir, "T11331" ]
56+
assertOutputContains "Chosen GOOD Cabal" res

0 commit comments

Comments
 (0)