Skip to content

Commit

Permalink
pretty-print run targets on failure
Browse files Browse the repository at this point in the history
  • Loading branch information
mgsium authored and ulysses4ever committed Aug 10, 2022
1 parent 6c79621 commit 24b37c7
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 24 deletions.
43 changes: 33 additions & 10 deletions Cabal-syntax/src/Distribution/Types/ComponentName.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PatternSynonyms #-}

module Distribution.Types.ComponentName (
ComponentName(..),
ComponentName(.., CFLibName, CExeName, CTestName, CBenchName),
showComponentName,
componentNameRaw,
componentNameStanza,
componentNameString,
) where
Expand All @@ -21,12 +23,32 @@ import qualified Distribution.Compat.CharParsing as P

-- Libraries live in a separate namespace, so must distinguish
data ComponentName = CLibName LibraryName
| CFLibName UnqualComponentName
| CExeName UnqualComponentName
| CTestName UnqualComponentName
| CBenchName UnqualComponentName
| CNotLibName NotLibComponentName
deriving (Eq, Generic, Ord, Read, Show, Typeable)

data NotLibComponentName
= CNLFLibName { toCompName :: UnqualComponentName }
| CNLExeName { toCompName :: UnqualComponentName }
| CNLTestName { toCompName :: UnqualComponentName }
| CNLBenchName { toCompName :: UnqualComponentName }
deriving (Eq, Generic, Ord, Read, Show, Typeable)

pattern CFLibName :: UnqualComponentName -> ComponentName
pattern CFLibName n = CNotLibName (CNLFLibName n)

pattern CExeName :: UnqualComponentName -> ComponentName
pattern CExeName n = CNotLibName (CNLExeName n)

pattern CTestName :: UnqualComponentName -> ComponentName
pattern CTestName n = CNotLibName (CNLTestName n)

pattern CBenchName :: UnqualComponentName -> ComponentName
pattern CBenchName n = CNotLibName (CNLBenchName n)
{-# COMPLETE CLibName, CFLibName, CExeName, CTestName, CBenchName #-}

instance Binary NotLibComponentName
instance Structured NotLibComponentName

instance Binary ComponentName
instance Structured ComponentName

Expand Down Expand Up @@ -59,6 +81,10 @@ showComponentName (CExeName name) = "executable '" ++ prettyShow name ++ "'"
showComponentName (CTestName name) = "test suite '" ++ prettyShow name ++ "'"
showComponentName (CBenchName name) = "benchmark '" ++ prettyShow name ++ "'"

componentNameRaw :: ComponentName -> String
componentNameRaw l@(CLibName _) = showComponentName l
componentNameRaw (CNotLibName x) = prettyShow $ toCompName x

componentNameStanza :: ComponentName -> String
componentNameStanza (CLibName lib) = libraryNameStanza lib
componentNameStanza (CFLibName name) = "foreign-library " ++ prettyShow name
Expand All @@ -71,8 +97,5 @@ componentNameStanza (CBenchName name) = "benchmark " ++ prettyShow name
-- @Nothing@ if the 'ComponentName' was for the public
-- library.
componentNameString :: ComponentName -> Maybe UnqualComponentName
componentNameString (CLibName lib) = libraryNameString lib
componentNameString (CFLibName n) = Just n
componentNameString (CExeName n) = Just n
componentNameString (CTestName n) = Just n
componentNameString (CBenchName n) = Just n
componentNameString (CLibName lib) = libraryNameString lib
componentNameString (CNotLibName x) = Just $ toCompName x
7 changes: 7 additions & 0 deletions cabal-install/src/Distribution/Client/CmdErrorMessages.hs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ renderListCommaAnd [x] = x
renderListCommaAnd [x,x'] = x ++ " and " ++ x'
renderListCommaAnd (x:xs) = x ++ ", " ++ renderListCommaAnd xs

renderListTabular :: [String] -> String
renderListTabular = ("\n"++) . unlines . map ("| * "++)

renderListPretty :: [String] -> String
renderListPretty xs = if length xs > 5 then renderListTabular xs
else renderListCommaAnd xs

-- | Render a list of things in the style @blah blah; this that; and the other@
renderListSemiAnd :: [String] -> String
renderListSemiAnd [] = ""
Expand Down
23 changes: 12 additions & 11 deletions cabal-install/src/Distribution/Client/CmdRun.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import Distribution.Client.CmdErrorMessages
( renderTargetSelector, showTargetSelector,
renderTargetProblem,
renderTargetProblemNoTargets, plural, targetSelectorPluralPkgs,
targetSelectorFilter, renderListCommaAnd )
targetSelectorFilter, renderListCommaAnd,
renderListPretty )
import Distribution.Client.TargetProblem
( TargetProblem (..) )

Expand All @@ -42,11 +43,11 @@ import Distribution.Simple.Flag
import Distribution.Simple.Command
( CommandUI(..), usageAlternatives )
import Distribution.Types.ComponentName
( showComponentName )
( componentNameRaw )
import Distribution.Verbosity
( normal, silent )
import Distribution.Simple.Utils
( wrapText, die', info, notice )
( wrapText, die', info, notice, safeHead )
import Distribution.Client.ProjectPlanning
( ElaboratedConfiguredPackage(..)
, ElaboratedInstallPlan, binDirectoryFor )
Expand All @@ -64,6 +65,7 @@ import Distribution.Types.UnitId
import Distribution.Client.ScriptUtils
( AcceptNoTargets(..), withContextAndSelectors, updateContextAndWriteProjectFile, TargetContext(..) )

import Data.List (group)
import qualified Data.Set as Set
import System.Directory
( doesFileExist )
Expand Down Expand Up @@ -424,14 +426,13 @@ renderRunProblem :: RunProblem -> String
renderRunProblem (TargetProblemMatchesMultiple targetSelector targets) =
"The run command is for running a single executable at once. The target '"
++ showTargetSelector targetSelector ++ "' refers to "
++ renderTargetSelector targetSelector ++ " which includes "
++ renderListCommaAnd ( ("the "++) <$>
showComponentName <$>
availableTargetComponentName <$>
foldMap
(\kind -> filterTargetsKind kind targets)
[ExeKind, TestKind, BenchKind] )
++ "."
++ renderTargetSelector targetSelector ++ " which includes \n"
++ unlines ((\(label, xs) -> "- " ++ label ++ ": " ++ renderListPretty xs)
<$> (zip ["executables", "test-suites", "benchmarks"]
$ filter (not . null) . map removeDuplicates
$ map (componentNameRaw . availableTargetComponentName)
<$> (flip filterTargetsKind $ targets) <$> [ExeKind, TestKind, BenchKind] ))
where removeDuplicates = catMaybes . map safeHead . group . sort

renderRunProblem (TargetProblemMultipleTargets selectorMap) =
"The run command is for running a single executable at once. The targets "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Building executable 'bar' for MultipleExes-1.0..
# cabal v2-run
Up to date
# cabal v2-run
Error: cabal: The run command is for running a single executable at once. The target '' refers to the package MultipleExes-1.0 which includes the executable 'foo' and the executable 'bar'.
Error: cabal: The run command is for running a single executable at once. The target '' refers to the package MultipleExes-1.0 which includes
- executables: bar and foo
# cabal v2-run
Error: cabal: The run command is for running a single executable at once. The target 'MultipleExes' refers to the package MultipleExes-1.0 which includes the executable 'foo' and the executable 'bar'.
Error: cabal: The run command is for running a single executable at once. The target 'MultipleExes' refers to the package MultipleExes-1.0 which includes
- executables: bar and foo
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Building executable 'foo-exe' for bar-1.0..
# cabal v2-run
Error: cabal: No targets given and there is no package in the current directory. Specify packages or components by name or location. See 'cabal build --help' for more details on target options.
# cabal v2-run
Error: cabal: The run command is for running a single executable at once. The target 'bar' refers to the package bar-1.0 which includes the executable 'foo-exe' and the executable 'bar-exe'.
Error: cabal: The run command is for running a single executable at once. The target 'bar' refers to the package bar-1.0 which includes
- executables: bar-exe and foo-exe
# cabal v2-run
Error: cabal: Ambiguous target 'foo-exe'. It could be:
bar:foo-exe (component)
Expand Down
11 changes: 11 additions & 0 deletions changelog.d/issue-8189
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
synopsis: Pretty-print run targets on failure
packages: cabal-install
prs: #8234
issues: #8189

description: {

- Targets of the `run` command are pretty-printed when failing due to multiple targets.
- Duplicate targets are removed in the output.

}

0 comments on commit 24b37c7

Please sign in to comment.