Skip to content
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

Add a cabal target command #9744

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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-install/cabal-install.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ library
Distribution.Client.CmdRepl
Distribution.Client.CmdRun
Distribution.Client.CmdSdist
Distribution.Client.CmdTarget
Distribution.Client.CmdTest
Distribution.Client.CmdUpdate
Distribution.Client.Compat.Directory
Expand Down
155 changes: 155 additions & 0 deletions cabal-install/src/Distribution/Client/CmdTarget.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}

module Distribution.Client.CmdTarget
( targetCommand
, targetAction
) where

import Distribution.Client.Compat.Prelude
import Prelude ()

import qualified Data.Map as Map
import Distribution.Client.CmdBuild (selectComponentTarget, selectPackageTargets)
import Distribution.Client.CmdErrorMessages
import Distribution.Client.Errors
import Distribution.Client.NixStyleOptions
( NixStyleFlags (..)
, defaultNixStyleFlags
)
import Distribution.Client.ProjectOrchestration
import Distribution.Client.ScriptUtils
( AcceptNoTargets (..)
, TargetContext (..)
, updateContextAndWriteProjectFile
, withContextAndSelectors
)
import Distribution.Client.Setup
( ConfigFlags (..)
, GlobalFlags
)
import Distribution.Client.TargetProblem
( TargetProblem'
)
import Distribution.Simple.Command
( CommandUI (..)
, usageAlternatives
)
import Distribution.Simple.Flag (fromFlagOrDefault)
import Distribution.Simple.Utils
( dieWithException
, wrapText
)
import Distribution.Verbosity
( normal
)

-------------------------------------------------------------------------------
-- Command
-------------------------------------------------------------------------------

targetCommand :: CommandUI (NixStyleFlags ())
targetCommand =
CommandUI
{ commandName = "v2-target"
, commandSynopsis = "Target disclosure."
, commandUsage = usageAlternatives "v2-target" ["[TARGETS]"]
, commandDescription = Just $ \_ ->
wrapText $
"Reveal the targets of build plan. "
++ "If no [TARGETS] are given 'all' will be used for selecting a build plan.\n\n"
++ "A [TARGETS] item can be one of these target forms;\n"
++ "- a package target (e.g. [pkg:]package)\n"
++ "- a component target (e.g. [package:][ctype:]component)\n"
++ "- all packages (e.g. all)\n"
++ "- components of a particular type (e.g. package:ctypes or all:ctypes)\n"
++ "- a module target: (e.g. [package:][ctype:]module)\n"
++ "- a filepath target: (e.g. [package:][ctype:]filepath)\n"
++ "- a script target: (e.g. path/to/script)\n\n"
++ "The ctypes can be one of: "
++ "libs or libraries, "
++ "exes or executables, "
++ "tests, "
++ "benches or benchmarks, "
++ " and flibs or foreign-libraries."
, commandNotes = Just $ \pname ->
"Examples:\n"
++ " "
++ pname
++ " v2-target all\n"
++ " Targets of the package in the current directory "
++ "or all packages in the project\n"
++ " "
++ pname
++ " v2-target pkgname\n"
++ " Targets of the package named pkgname in the project\n"
++ " "
++ pname
++ " v2-target ./pkgfoo\n"
++ " Targets of the package in the ./pkgfoo directory\n"
++ " "
++ pname
++ " v2-target cname\n"
++ " Targets of the component named cname in the project\n"
++ " "
, commandDefaultFlags = defaultNixStyleFlags ()
, commandOptions = const []
}

-------------------------------------------------------------------------------
-- Action
-------------------------------------------------------------------------------

targetAction :: NixStyleFlags () -> [String] -> GlobalFlags -> IO ()
targetAction flags@NixStyleFlags{..} ts globalFlags = do
let targetStrings = if null ts then ["all"] else ts
withContextAndSelectors RejectNoTargets Nothing flags targetStrings globalFlags BuildCommand $ \targetCtx ctx targetSelectors -> do
Comment on lines +109 to +110
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here you require (RejectNoTargets) a list of target selectors.Why?
I would think a command to list targets does not need targets to be specified.

If you want to just list the targets you probably do not need all most of this function, but only the elaborated plan.

withContextAndSelectors is what powers cabal run myscript.hs unless you want to support cabal target myscript.hs you won't need it. If you do not use it, cabal target will only work in a project context. This is what I would expect.

runProjectPreBuildPhase rebuilds the project plan and then uses the function you pass to trim it down to only the required targets. Again, if you just want to list the available targets, you don't need to trim anything. Also it marks the up-to-date targets as 'installed', which means you won't get them from InstallPlan.executionOrder.

baseCtx <- case targetCtx of
ProjectContext -> return ctx
GlobalContext -> return ctx
ScriptContext path exemeta -> updateContextAndWriteProjectFile ctx path exemeta

buildCtx <-
runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do
-- Interpret the targets on the command line as build targets
-- (as opposed to say repl or haddock targets).
targets <-
either (reportBuildTargetProblems verbosity) return $
resolveTargets
selectPackageTargets
selectComponentTarget
elaboratedPlan
Nothing
targetSelectors

let elaboratedPlan' =
pruneInstallPlanToTargets
TargetActionConfigure
targets
elaboratedPlan
elaboratedPlan'' <-
if buildSettingOnlyDeps (buildSettings baseCtx)
then
either (reportCannotPruneDependencies verbosity) return $
pruneInstallPlanToDependencies
(Map.keysSet targets)
elaboratedPlan'
else return elaboratedPlan'

return (elaboratedPlan'', targets)

printPlanTargetForms verbosity buildCtx
where
verbosity = fromFlagOrDefault normal (configVerbosity configFlags)

reportBuildTargetProblems :: Verbosity -> [TargetProblem'] -> IO a
reportBuildTargetProblems verbosity problems =
reportTargetProblems verbosity "target" problems

reportCannotPruneDependencies :: Verbosity -> CannotPruneDependencies -> IO a
reportCannotPruneDependencies verbosity =
dieWithException verbosity . ReportCannotPruneDependencies . renderCannotPruneDependencies
2 changes: 2 additions & 0 deletions cabal-install/src/Distribution/Client/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ import qualified Distribution.Client.CmdPath as CmdPath
import qualified Distribution.Client.CmdRepl as CmdRepl
import qualified Distribution.Client.CmdRun as CmdRun
import qualified Distribution.Client.CmdSdist as CmdSdist
import qualified Distribution.Client.CmdTarget as CmdTarget
import qualified Distribution.Client.CmdTest as CmdTest
import qualified Distribution.Client.CmdUpdate as CmdUpdate

Expand Down Expand Up @@ -455,6 +456,7 @@ mainWorker args = do
, newCmd CmdExec.execCommand CmdExec.execAction
, newCmd CmdClean.cleanCommand CmdClean.cleanAction
, newCmd CmdSdist.sdistCommand CmdSdist.sdistAction
, newCmd CmdTarget.targetCommand CmdTarget.targetAction
, legacyCmd configureExCommand configureAction
, legacyCmd buildCommand buildAction
, legacyCmd replCommand replAction
Expand Down
58 changes: 57 additions & 1 deletion cabal-install/src/Distribution/Client/ProjectOrchestration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ module Distribution.Client.ProjectOrchestration
, pruneInstallPlanToDependencies
, CannotPruneDependencies (..)
, printPlan
, printPlanTargetForms

-- * Build phase: now do it.
, runProjectBuildPhase
Expand Down Expand Up @@ -934,7 +935,62 @@ distinctTargetComponents targetsMap =

------------------------------------------------------------------------------
-- Displaying what we plan to do
--

-- | Print available target forms.
printPlanTargetForms
:: Verbosity
-> ProjectBuildContext
-> IO ()
printPlanTargetForms
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function shows every single single component in elaboratedPlanToExecute. This does not correspond to the list of available targets.

E.g.

✦ ~/code/cabal branchless/09946f1d1fa1217f4480d9ac919e2b264b5a3ecb*
λ $(cabal list-bin cabal) target
...
 - uuid-types:lib
 - vector-algorithms:lib
 - vector-binary-instances:lib
 - vector-stream:lib
 - vector-th-unbox:lib
 - vector:lib
 - wherefrom-compat:lib
 - witherable:lib
 - zinza:lib
 - zlib:lib

✦ ~/code/cabal branchless/09946f1d1fa1217f4480d9ac919e2b264b5a3ecb* 10s
λ $(cabal list-bin cabal) build zlib:lib
Warning: this is a debug build of cabal-install with assertions enabled.
Error: [Cabal-7130]
Internal error in target matching: could not make an unambiguous fully qualified target selector for 'zlib:lib'.
We made the target 'zlib:lib' (unknown-component) that was expected to be unambiguous but matches the following targets:
'zlib:lib', matching:
  - zlib:lib (unknown-component)
  - :pkg:zlib:lib:zlib:file:lib (unknown-file)

Note: Cabal expects to be able to make a single fully qualified name for a target or provide a more specific error. Our failure to do so is a bug in cabal. Tracking issue: https://github.com/haskell/cabal/issues/8684

Hint: this may be caused by trying to build a package that exists in the project directory but is missing from the 'packages' stanza in your cabal project file.

verbosity
ProjectBuildContext{elaboratedPlanToExecute = elaboratedPlan}
| not (null pkgs) = noticeNoWrap verbosity . unlines $ map showPkgAndReason pkgs
| otherwise = return ()
where
pkgs :: [GenericReadyPackage ElaboratedConfiguredPackage]
pkgs =
sortBy
(compare `on` showPkgAndReason)
(InstallPlan.executionOrder elaboratedPlan)

showPkgAndReason :: ElaboratedReadyPackage -> String
showPkgAndReason (ReadyPackage elab) =
unwords $
filter (not . null) $
[ " -"
, concat . filter (not . null) $
[ prettyShow $ packageName (packageId elab)
, case elabPkgOrComp elab of
ElabPackage _ -> showTargets elab
ElabComponent comp -> ":" ++ showComp elab comp
]
]

showComp :: ElaboratedConfiguredPackage -> ElaboratedComponent -> String
showComp elab comp =
maybe "custom" prettyShow (compComponentName comp)
++ if Map.null (elabInstantiatedWith elab)
then ""
else
" with "
++ intercalate
", "
-- TODO: Abbreviate the UnitIds
[ prettyShow k ++ "=" ++ prettyShow v
| (k, v) <- Map.toList (elabInstantiatedWith elab)
]

showTargets :: ElaboratedConfiguredPackage -> String
showTargets elab
| null (elabBuildTargets elab) = ""
| otherwise =
"("
++ intercalate
", "
[ showComponentTarget (packageId elab) t
| t <- elabBuildTargets elab
]
++ ")"

-- | Print a user-oriented presentation of the install plan, indicating what
-- will be built.
Expand Down
6 changes: 5 additions & 1 deletion cabal-install/src/Distribution/Client/Setup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ globalCommand commands =
, "unpack"
, "init"
, "configure"
, "target"
, "build"
, "clean"
, "run"
Expand Down Expand Up @@ -327,7 +328,8 @@ globalCommand commands =
, "v1-register"
, "v1-reconfigure"
, -- v2 commands, nix-style
"v2-build"
"v2-target"
, "v2-build"
, "v2-configure"
, "v2-repl"
, "v2-freeze"
Expand Down Expand Up @@ -374,6 +376,7 @@ globalCommand commands =
, addCmd "path"
, par
, startGroup "project building and installing"
, addCmd "target"
, addCmd "build"
, addCmd "install"
, addCmd "haddock"
Expand All @@ -399,6 +402,7 @@ globalCommand commands =
, addCmd "hscolour"
, par
, startGroup "new-style projects (forwards-compatible aliases)"
, addCmd "v2-target"
, addCmd "v2-build"
, addCmd "v2-configure"
, addCmd "v2-repl"
Expand Down
Loading