Skip to content

Commit

Permalink
Render project configs in provenance message
Browse files Browse the repository at this point in the history
- Use real-life example from Cabal project in doctest
  • Loading branch information
philderbeast committed May 10, 2024
1 parent 47e7295 commit b0c0c77
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}

module Distribution.Solver.Types.ProjectConfigPath
(
Expand All @@ -11,6 +10,7 @@ module Distribution.Solver.Types.ProjectConfigPath

-- * Messages
, docProjectConfigPath
, docProjectConfigPaths
, cyclicalImportMsg
, docProjectConfigPathFailReason

Expand Down Expand Up @@ -56,13 +56,51 @@ instance Structured ProjectConfigPath
-- imported by: B.config
-- imported by: A.project
-- @
-- >>> render . docProjectConfigPath $ ProjectConfigPath $ "D.config" :| ["C.config", "B.config", "A.project" ]
-- >>> render . docProjectConfigPath $ ProjectConfigPath $ "D.config" :| ["C.config", "B.config", "A.project"]
-- "D.config\n imported by: C.config\n imported by: B.config\n imported by: A.project"
docProjectConfigPath :: ProjectConfigPath -> Doc
docProjectConfigPath (ProjectConfigPath (p :| [])) = text p
docProjectConfigPath (ProjectConfigPath (p :| ps)) = vcat $
text p : [ text " " <+> text "imported by:" <+> text l | l <- ps ]

-- | Renders the paths as a list without showing which path imports another,
-- like this;
-- @
-- - cabal.project
-- - project-cabal/constraints.config
-- - project-cabal/ghc-latest.config
-- - project-cabal/ghc-options.config
-- - project-cabal/pkgs.config
-- - project-cabal/pkgs/benchmarks.config
-- - project-cabal/pkgs/buildinfo.config
-- - project-cabal/pkgs/cabal.config
-- - project-cabal/pkgs/install.config
-- - project-cabal/pkgs/integration-tests.config
-- - project-cabal/pkgs/tests.config
-- @
--
-- >>> :{
-- do
-- let ps =
-- [ ProjectConfigPath ("cabal.project" :| [])
-- , ProjectConfigPath ("project-cabal/constraints.config" :| ["cabal.project"])
-- , ProjectConfigPath ("project-cabal/ghc-latest.config" :| ["cabal.project"])
-- , ProjectConfigPath ("project-cabal/ghc-options.config" :| ["cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs.config" :| ["cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs/benchmarks.config" :| ["project-cabal/pkgs.config","cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs/buildinfo.config" :| ["project-cabal/pkgs.config","cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs/cabal.config" :| ["project-cabal/pkgs.config","cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs/install.config" :| ["project-cabal/pkgs.config","cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs/integration-tests.config" :| ["project-cabal/pkgs.config","cabal.project"])
-- , ProjectConfigPath ("project-cabal/pkgs/tests.config" :| ["project-cabal/pkgs.config","cabal.project"])
-- ]
-- return . render $ docProjectConfigPaths ps
-- :}
-- "- cabal.project\n- project-cabal/constraints.config\n- project-cabal/ghc-latest.config\n- project-cabal/ghc-options.config\n- project-cabal/pkgs.config\n- project-cabal/pkgs/benchmarks.config\n- project-cabal/pkgs/buildinfo.config\n- project-cabal/pkgs/cabal.config\n- project-cabal/pkgs/install.config\n- project-cabal/pkgs/integration-tests.config\n- project-cabal/pkgs/tests.config"
docProjectConfigPaths :: [ProjectConfigPath] -> Doc
docProjectConfigPaths ps = vcat
[ text "-" <+> text p | ProjectConfigPath (p :| _) <- ps ]

-- | A message for a cyclical import, assuming the head of the path is the
-- duplicate.
cyclicalImportMsg :: ProjectConfigPath -> Doc
Expand Down
10 changes: 5 additions & 5 deletions cabal-install/src/Distribution/Client/ProjectConfig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ module Distribution.Client.ProjectConfig
) where

import Distribution.Client.Compat.Prelude
import Text.PrettyPrint (render)
import Text.PrettyPrint (nest, render, text, vcat)
import Prelude ()

import Distribution.Client.Glob
Expand Down Expand Up @@ -882,10 +882,10 @@ renderBadPackageLocations (BadPackageLocations provenance bpls)
renderErrors f = unlines (map f bpls)

renderExplicit =
"When using configuration(s) from "
++ intercalate ", " (render . docProjectConfigPath <$> mapMaybe getExplicit (Set.toList provenance))
++ ", the following errors occurred:\n"
++ renderErrors renderBadPackageLocation
"When using configuration from:\n"
++ render (nest 2 . docProjectConfigPaths $ mapMaybe getExplicit (Set.toList provenance))
++ "\nThe following errors occurred:\n"
++ render (nest 2 $ vcat ((text "-" <+>) . text <$> map renderBadPackageLocation bpls))

getExplicit (Explicit path) = Just path
getExplicit Implicit = Nothing
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import: missing/pkgs.config
2 changes: 2 additions & 0 deletions cabal-testsuite/PackageTests/ConditionalAndImport/cabal.out
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,5 @@ After searching the rest of the dependency tree exhaustively, these were the goa
Error: [Cabal-7090]
Error parsing project file <ROOT>/bad-conditional.project:
Cannot set compiler in a conditional clause of a cabal project file
# checking that missing package message lists configuration provenance
# cabal v2-build
11 changes: 11 additions & 0 deletions cabal-testsuite/PackageTests/ConditionalAndImport/cabal.test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,15 @@ main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do
badIf <- fails $ cabal' "v2-build" [ "--project-file=bad-conditional.project" ]
assertOutputContains "Cannot set compiler in a conditional clause of a cabal project file" badIf

log "checking that missing package message lists configuration provenance"
missing <- fails $ cabal' "v2-build" [ "--project-file=cabal-missing-package.project" ]
assertOutputContains
"When using configuration from: \
\ - cabal-missing-package.project \
\ - missing/pkgs.config \
\ - missing/pkgs/default.config \
\The following errors occurred: \
\ - The package location 'pkg-doesnt-exist' does not exist."
missing

return ()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import: pkgs/default.config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: pkg-doesnt-exist
6 changes: 6 additions & 0 deletions changelog.d/issue-9971
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
synopsis: Renders project configuration provenance as a list of canonical paths
packages: cabal-install cabal-install-solver
prs: #9985
issues: #9971

description: Removes interleaved rendering of project imports.

0 comments on commit b0c0c77

Please sign in to comment.