Skip to content

Allow new-run to run tests and benchmarks too #4861

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cabal/doc/nix-local-build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ cabal new-run
``cabal new-run [TARGET [ARGS]]`` runs the executable specified by the
target, which can be a component, a package or can be left blank, as
long as it can uniquely identify an executable within the project.
Tests and benchmarks are also treated as executables.

See `the new-build section <#cabal-new-build>`__ for the target syntax.

Expand Down
71 changes: 40 additions & 31 deletions cabal-install/Distribution/Client/CmdRun.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Distribution.Simple.Setup
import Distribution.Simple.Command
( CommandUI(..), usageAlternatives )
import Distribution.Types.ComponentName
( componentNameString )
( showComponentName )
import Distribution.Text
( display )
import Distribution.Verbosity
Expand Down Expand Up @@ -68,12 +68,13 @@ runCommand = Client.installCommand {
commandUsage = usageAlternatives "new-run"
[ "[TARGET] [FLAGS] [-- EXECUTABLE_FLAGS]" ],
commandDescription = Just $ \pname -> wrapText $
"Runs the specified executable, first ensuring it is up to date.\n\n"
"Runs the specified executable-like component (an executable, a test, "
++ "or a benchmark), first ensuring it is up to date.\n\n"

++ "Any executable in any package in the project can be specified. "
++ "A package can be specified if contains just one executable. "
++ "The default is to use the package in the current directory if it "
++ "contains just one executable.\n\n"
++ "Any executable-like component in any package in the project can be "
++ "specified. A package can be specified if contains just one "
++ "executable-like. The default is to use the package in the current "
++ "directory if it contains just one executable-like.\n\n"

++ "Extra arguments can be passed to the program, but use '--' to "
++ "separate arguments for the program from arguments for " ++ pname
Expand All @@ -87,21 +88,22 @@ runCommand = Client.installCommand {
commandNotes = Just $ \pname ->
"Examples:\n"
++ " " ++ pname ++ " new-run\n"
++ " Run the executable in the package in the current directory\n"
++ " Run the executable-like in the package in the current directory\n"
++ " " ++ pname ++ " new-run foo-tool\n"
++ " Run the named executable (in any package in the project)\n"
++ " Run the named executable-like (in any package in the project)\n"
++ " " ++ pname ++ " new-run pkgfoo:foo-tool\n"
++ " Run the executable 'foo-tool' in the package 'pkgfoo'\n"
++ " Run the executable-like 'foo-tool' in the package 'pkgfoo'\n"
++ " " ++ pname ++ " new-run foo -O2 -- dothing --fooflag\n"
++ " Build with '-O2' and run the program, passing it extra arguments.\n\n"

++ cmdCommonHelpTextNewBuildBeta
}


-- | The @build@ command does a lot. It brings the install plan up to date,
-- selects that part of the plan needed by the given or implicit targets and
-- then executes the plan.
-- | The @run@ command runs a specified executable-like component, building it
-- first if necessary. The component can be either an executable, a test,
-- or a benchmark. This is particularly useful for passing arguments to
-- exes/tests/benchs by simply appending them after a @--@.
--
-- For more details on how this works, see the module
-- "Distribution.Client.ProjectOrchestration"
Expand Down Expand Up @@ -259,6 +261,8 @@ singleExeOrElse :: IO (UnitId, UnqualComponentName) -> TargetsMap -> IO (UnitId,
singleExeOrElse action targetsMap =
case Set.toList . distinctTargetComponents $ targetsMap
of [(unitId, CExeName component)] -> return (unitId, component)
[(unitId, CTestName component)] -> return (unitId, component)
[(unitId, CBenchName component)] -> return (unitId, component)
_ -> action

-- | Filter the 'ElaboratedInstallPlan' keeping only the
Expand Down Expand Up @@ -307,31 +311,35 @@ selectPackageTargets targetSelector targets
| otherwise
= Left (TargetProblemNoTargets targetSelector)
where
-- Targets that can be executed
targetsExecutableLike =
concatMap (\kind -> filterTargetsKind kind targets)
[ExeKind, TestKind, BenchKind]
(targetsExesBuildable,
targetsExesBuildable') = selectBuildableTargets'
. filterTargetsKind ExeKind
$ targets
targetsExesBuildable') = selectBuildableTargets' targetsExecutableLike

targetsExes = forgetTargetsDetail
. filterTargetsKind ExeKind
$ targets
targetsExes = forgetTargetsDetail targetsExecutableLike


-- | For a 'TargetComponent' 'TargetSelector', check if the component can be
-- selected.
--
-- For the @run@ command we just need to check it is a executable, in addition
-- For the @run@ command we just need to check it is a executable-like
-- (an executable, a test, or a benchmark), in addition
-- to the basic checks on being buildable etc.
--
selectComponentTarget :: SubComponentTarget
-> AvailableTarget k -> Either TargetProblem k
selectComponentTarget subtarget@WholeComponent t
| CExeName _ <- availableTargetComponentName t
= either (Left . TargetProblemCommon) return $
selectComponentTargetBasic subtarget t
| otherwise
= Left (TargetProblemComponentNotExe (availableTargetPackageId t)
(availableTargetComponentName t))
= case availableTargetComponentName t
of CExeName _ -> component
CTestName _ -> component
CBenchName _ -> component
_ -> Left (TargetProblemComponentNotExe pkgid cname)
where pkgid = availableTargetPackageId t
cname = availableTargetComponentName t
component = either (Left . TargetProblemCommon) return $
selectComponentTargetBasic subtarget t

selectComponentTarget subtarget t
= Left (TargetProblemIsSubComponent (availableTargetPackageId t)
Expand Down Expand Up @@ -395,12 +403,13 @@ renderTargetProblem (TargetProblemNoTargets targetSelector) =
renderTargetProblem (TargetProblemMatchesMultiple targetSelector targets) =
"The run command is for running a single executable at once. The target '"
++ showTargetSelector targetSelector ++ "' refers to "
++ renderTargetSelector targetSelector ++ " which includes the executables "
++ renderListCommaAnd
[ display name
| cname@CExeName{} <- map availableTargetComponentName targets
, let Just name = componentNameString cname
]
++ renderTargetSelector targetSelector ++ " which includes "
++ renderListCommaAnd ( ("the "++) <$>
showComponentName <$>
availableTargetComponentName <$>
foldMap
(\kind -> filterTargetsKind kind targets)
[ExeKind, TestKind, BenchKind] )
++ "."

renderTargetProblem (TargetProblemMultipleTargets selectorMap) =
Expand Down
2 changes: 2 additions & 0 deletions cabal-install/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Completed the 'new-run' command (#4477). The functionality is the
same of the old 'run' command but using nix-style builds.
Additionally, it can run executables across packages in a project.
Tests and benchmarks are also treated as executables, providing a
quick way to pass them arguments.
* Completed the 'new-bench' command (#3638). Same as above.
* Completed the 'new-exec' command (#3638). Same as above.
* Added a preliminary 'new-install' command (#4558, nonlocal exes
Expand Down
33 changes: 2 additions & 31 deletions cabal-install/tests/IntegrationTests2.hs
Original file line number Diff line number Diff line change
Expand Up @@ -869,44 +869,15 @@ testTargetProblemsRun config reportSubCase = do
[ ( CmdRun.TargetProblemNoTargets, mkTargetPackage "p-0.1" )
]

reportSubCase "test-only"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super happy of simply removing this test.

It's invalid with this change, as https://github.com/haskell/cabal/blob/fcabd87406effc0c265312eb38509804682e4623/cabal-install/tests/IntegrationTests2/targets/test-only/p.cabal has only test-suite stanza, but now has an executable.

Let's change that package to be lib-only (you cannot run that).

What is pity, we don't have any positive tests for CmdRun in IntegrationsTests2.hs. We really should add them, so the things working now continue working in the future.

reportSubCase "lib-only"
assertProjectTargetProblems
"targets/test-only" config
"targets/lib-only" config
CmdRun.selectPackageTargets
CmdRun.selectComponentTarget
CmdRun.TargetProblemCommon
[ ( CmdRun.TargetProblemNoExes, mkTargetPackage "p-0.1" )
]

reportSubCase "variety"
assertProjectTargetProblems
"targets/variety" config
CmdRun.selectPackageTargets
CmdRun.selectComponentTarget
CmdRun.TargetProblemCommon $
[ ( const (CmdRun.TargetProblemComponentNotExe "p-0.1" cname)
, mkTargetComponent "p-0.1" cname )
| cname <- [ CLibName, CFLibName "libp",
CTestName "a-testsuite", CBenchName "a-benchmark" ]
] ++
[ ( const (CmdRun.TargetProblemIsSubComponent
"p-0.1" cname (ModuleTarget modname))
, mkTargetModule "p-0.1" cname modname )
| (cname, modname) <- [ (CTestName "a-testsuite", "TestModule")
, (CBenchName "a-benchmark", "BenchModule")
, (CExeName "an-exe", "ExeModule")
, (CLibName, "P")
]
] ++
[ ( const (CmdRun.TargetProblemIsSubComponent
"p-0.1" cname (FileTarget fname))
, mkTargetFile "p-0.1" cname fname)
| (cname, fname) <- [ (CTestName "a-testsuite", "Test.hs")
, (CBenchName "a-benchmark", "Bench.hs")
, (CExeName "an-exe", "Main.hs")
]
]


testTargetProblemsTest :: ProjectConfig -> (String -> IO ()) -> Assertion
testTargetProblemsTest config reportSubCase = do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: p
version: 0.1
build-type: Simple
cabal-version: >= 1.2

library
exposed-modules: P
build-depends: base
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ Building executable 'bar' for MultipleExes-1.0..
# cabal new-run
Up to date
# cabal new-run
cabal: The run command is for running a single executable at once. The target '' refers to the package MultipleExes-1.0 which includes the executables foo and bar.
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'.
# cabal new-run
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 executables foo and bar.
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'.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Building executable 'foo-exe' for bar-1.0..
# cabal new-run
cabal: No targets given and there is no package in the current directory. Use the target 'all' for all packages in the project or specify packages or components by name or location. See 'cabal build --help' for more details on target options.
# cabal new-run
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 executables foo-exe and bar-exe.
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'.
# cabal new-run
cabal: Ambiguous target 'foo-exe'. It could be:
bar:foo-exe (component)
Expand Down