Skip to content
Snippets Groups Projects
Commit 4ef1098f authored by Musab Guma'a's avatar Musab Guma'a Committed by Mergify
Browse files

pretty-print run targets on failure

parent b2c3de34
No related branches found
No related tags found
No related merge requests found
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PatternSynonyms #-}
module Distribution.Types.ComponentName (
ComponentName(..),
ComponentName(.., CFLibName, CExeName, CTestName, CBenchName),
showComponentName,
componentNameRaw,
componentNameStanza,
componentNameString,
) where
......@@ -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
......@@ -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
......@@ -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
......@@ -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 [] = ""
......
......@@ -27,7 +27,8 @@ import Distribution.Client.CmdErrorMessages
( renderTargetSelector, showTargetSelector,
renderTargetProblem,
renderTargetProblemNoTargets, plural, targetSelectorPluralPkgs,
targetSelectorFilter, renderListCommaAnd )
targetSelectorFilter, renderListCommaAnd,
renderListPretty )
import Distribution.Client.TargetProblem
( TargetProblem (..) )
......@@ -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 )
......@@ -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 )
......@@ -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 "
......
......@@ -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
......@@ -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)
......
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.
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment