Skip to content

Commit 6926b83

Browse files
jappeace-slothjappeace
authored andcommitted
Changes the error message from:
``` Error: The following packages are broken because other packages they depend on are missing. These broken packages must be rebuilt before they can be used. planned package consumer-0.1.0.0 is broken due to missing package framework-0.1.0.0+95RTb42ZWxa9J13cUStM0q ```` To ``` Error: The following packages are broken because other packages they depend on are missing. These broken packages must be rebuilt before they can be used. planned package consumer-0.1.0.0 is broken due to missing package framework-0.1.0.0 (has unfilled signature: App) The package is installed as indefinite. To use it, rebuild it in the same cabal project as the consumer so cabal can fill the signatures. ``` Hopefully it gives more guidence on what's going on to the user. I encountered this when trying to use backpack in a nix setup (for example jappeace-sloth/prrrrrrrrr#2) It keeps on wanting to build everything locally and I couldn't understand why. I still don't fully understand why it can't have partially filled modules upstream. It claims it's because of nix but I don't understand it.
1 parent 48d01f8 commit 6926b83

11 files changed

Lines changed: 157 additions & 17 deletions

File tree

Cabal/src/Distribution/Backpack/Configure.hs

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import qualified Distribution.Compat.Graph as Graph
3131
import Distribution.InstalledPackageInfo
3232
( InstalledPackageInfo
3333
, emptyInstalledPackageInfo
34+
, requiredSignatures
3435
)
3536
import qualified Distribution.InstalledPackageInfo as Installed
3637
import Distribution.ModuleName
@@ -261,6 +262,17 @@ toComponentLocalBuildInfos
261262
packageDependsIndex = PackageIndex.fromList (lefts local_graph)
262263
fullIndex = Graph.fromDistinctList local_graph
263264

265+
let -- Map from dependency UnitId to its PackageId, built from includes
266+
-- of all ready components. Used to resolve opaque hashed UnitIds
267+
-- in broken-package error messages.
268+
depPkgMap :: Map UnitId PackageId
269+
depPkgMap = Map.fromList
270+
[ (unDefUnitId (ci_id ci), ci_pkgid ci)
271+
| rc <- graph
272+
, Right instc <- [rc_i rc]
273+
, ci <- instc_includes instc
274+
]
275+
264276
case Graph.broken fullIndex of
265277
[] -> return ()
266278
-- If there are promised dependencies, we don't know what the dependencies
@@ -270,26 +282,25 @@ toComponentLocalBuildInfos
270282
broken
271283
| not (null promisedPkgDeps) -> return ()
272284
| otherwise ->
273-
-- TODO: ppr this
274-
dieProgress . text $
275-
"The following packages are broken because other"
276-
++ " packages they depend on are missing. These broken "
277-
++ "packages must be rebuilt before they can be used.\n"
278-
-- TODO: Undupe.
279-
++ unlines
280-
[ "installed package "
281-
++ prettyShow (packageId pkg)
282-
++ " is broken due to missing package "
283-
++ intercalate ", " (map prettyShow deps)
285+
dieProgress $
286+
text "The following packages are broken because other"
287+
<+> text "packages they depend on are missing. These broken"
288+
<+> text "packages must be rebuilt before they can be used."
289+
$$ nest 2 (vcat $
290+
[ hang (text "installed package" <+> pretty (packageId pkg)) 4
291+
(text "is broken due to missing package"
292+
<+> hsep (punctuate comma (map pretty deps)))
284293
| (Left pkg, deps) <- broken
285294
]
286-
++ unlines
287-
[ "planned package "
288-
++ prettyShow (packageId pkg)
289-
++ " is broken due to missing package "
290-
++ intercalate ", " (map prettyShow deps)
295+
++
296+
[ hang (text "planned package" <+> pretty (packageId pkg)) 4
297+
(vcat $
298+
text "is broken due to missing package"
299+
: [ nest 2 (dispMissingDep installedPackageSet depPkgMap dep)
300+
| dep <- deps
301+
])
291302
| (Right pkg, deps) <- broken
292-
]
303+
])
293304

294305
-- In this section, we'd like to look at the 'packageDependsIndex'
295306
-- and see if we've picked multiple versions of the same
@@ -338,6 +349,39 @@ toComponentLocalBuildInfos
338349
-- forM clbis $ \(clbi,deps) -> info verbosity $ "UNIT" ++ hashUnitId (componentUnitId clbi) ++ "\n" ++ intercalate "\n" (map hashUnitId deps)
339350
return (clbis, packageDependsIndex)
340351

352+
-- | Pretty-print a missing dependency, resolving opaque hashed 'UnitId's
353+
-- to their human-readable package id and signature info when possible.
354+
--
355+
-- When an indefinite Backpack package is installed separately (e.g. via
356+
-- nix callCabal2nix), only the indefinite variant (with unfilled signatures)
357+
-- exists in the package DB. The consumer needs an instantiated variant
358+
-- which was never built. The fix is to add both packages to the same
359+
-- cabal project so cabal can fill the signatures.
360+
dispMissingDep
361+
:: InstalledPackageIndex -- ^ all installed packages
362+
-> Map UnitId PackageId -- ^ dep UnitId to its PackageId (from includes)
363+
-> UnitId -- ^ the missing dependency
364+
-> Doc
365+
dispMissingDep installedPkgSet depPkgMap uid =
366+
case Map.lookup uid depPkgMap of
367+
Just pkgid ->
368+
let ipiSigs = [ sigs
369+
| ipi <- PackageIndex.lookupSourcePackageId installedPkgSet pkgid
370+
, let sigs = requiredSignatures ipi
371+
, not (Set.null sigs)
372+
]
373+
in case ipiSigs of
374+
(sigs : _) ->
375+
pretty pkgid
376+
<+> parens (text "has unfilled"
377+
<+> (if Set.size sigs > 1 then text "signatures:" else text "signature:")
378+
<+> hsep (punctuate comma (map pretty (Set.toList sigs))))
379+
$$ nest 2 (text "The package is installed as indefinite."
380+
$$ text "To use it, rebuild it in the same cabal project as the"
381+
<+> text "consumer so cabal can fill the signatures.")
382+
[] -> pretty pkgid <+> parens (pretty uid)
383+
Nothing -> pretty uid
384+
341385
-- Build ComponentLocalBuildInfo for each component we are going
342386
-- to build.
343387
--
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cabal-version: 3.0
2+
name: Fail5
3+
version: 0.1.0.0
4+
build-type: Simple
5+
6+
library framework
7+
signatures: App
8+
hs-source-dirs: repo/framework-0.1.0.0/src-sig
9+
build-depends: base
10+
default-language: Haskell2010
11+
visibility: public
12+
13+
library app-impl
14+
exposed-modules: App
15+
hs-source-dirs: repo/app-impl-0.1.0.0
16+
build-depends: base
17+
default-language: Haskell2010
18+
visibility: public
19+
20+
executable consumer
21+
main-is: Main.hs
22+
build-depends: base, Fail5:framework, Fail5:app-impl
23+
hs-source-dirs: repo/consumer-0.1.0.0
24+
default-language: Haskell2010
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module App where
2+
appMessage :: String
3+
appMessage = "Hello from app-impl"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cabal-version: 3.0
2+
name: app-impl
3+
version: 0.1.0.0
4+
build-type: Simple
5+
6+
library
7+
exposed-modules: App
8+
build-depends: base
9+
default-language: Haskell2010
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import App (appMessage)
2+
main :: IO ()
3+
main = putStrLn appMessage
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cabal-version: 3.0
2+
name: consumer
3+
version: 0.1.0.0
4+
build-type: Simple
5+
6+
executable consumer
7+
main-is: Main.hs
8+
build-depends: base, framework, app-impl
9+
default-language: Haskell2010
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cabal-version: 3.0
2+
name: framework
3+
version: 0.1.0.0
4+
build-type: Simple
5+
6+
library
7+
signatures: App
8+
hs-source-dirs: src-sig
9+
build-depends: base
10+
default-language: Haskell2010
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
signature App where
2+
appMessage :: String
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Setup configure
2+
Configuring consumer-0.1.0.0...
3+
Error:
4+
The following packages are broken because other packages they depend on are missing. These broken packages must be rebuilt before they can be used.
5+
planned package consumer-0.1.0.0
6+
is broken due to missing package
7+
framework-0.1.0.0 (has unfilled signature: App)
8+
The package is installed as indefinite.
9+
To use it, rebuild it in the same cabal project as the consumer so cabal can fill the signatures.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Test.Cabal.Prelude
2+
main = setupAndCabalTest $ do
3+
skipUnlessGhcVersion ">= 8.1"
4+
withPackageDb $ do
5+
-- Install framework WITHOUT instantiation (simulates nix callCabal2nix)
6+
recordMode DoNotRecord $
7+
withDirectory "repo/framework-0.1.0.0" $ setup_install []
8+
-- Install the App implementation package separately
9+
recordMode DoNotRecord $
10+
withDirectory "repo/app-impl-0.1.0.0" $ setup_install []
11+
-- Configure consumer — should fail because the instantiated
12+
-- framework (with App=app-impl:App) was never built.
13+
-- The exact error message is checked via the .out file.
14+
withDirectory "repo/consumer-0.1.0.0" $ do
15+
fails $ setup' "configure" []
16+
return ()

0 commit comments

Comments
 (0)