diff --git a/cabal-install/cabal-install.cabal b/cabal-install/cabal-install.cabal index cef5fbd8277..94080878afa 100644 --- a/cabal-install/cabal-install.cabal +++ b/cabal-install/cabal-install.cabal @@ -110,6 +110,7 @@ library Distribution.Client.CmdRepl Distribution.Client.CmdRun Distribution.Client.CmdSdist + Distribution.Client.CmdTarget Distribution.Client.CmdTest Distribution.Client.CmdUpdate Distribution.Client.Compat.Directory diff --git a/cabal-install/src/Distribution/Client/CmdTarget.hs b/cabal-install/src/Distribution/Client/CmdTarget.hs new file mode 100644 index 00000000000..dbfa2c51884 --- /dev/null +++ b/cabal-install/src/Distribution/Client/CmdTarget.hs @@ -0,0 +1,198 @@ +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} + +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.InstallPlan +import qualified Distribution.Client.InstallPlan as InstallPlan +import Distribution.Client.NixStyleOptions + ( NixStyleFlags (..) + , defaultNixStyleFlags + ) +import Distribution.Client.ProjectOrchestration +import Distribution.Client.ProjectPlanning +import Distribution.Client.Setup + ( ConfigFlags (..) + , GlobalFlags + ) +import Distribution.Client.TargetProblem + ( TargetProblem' + ) +import Distribution.Package +import Distribution.Simple.Command + ( CommandUI (..) + , usageAlternatives + ) +import Distribution.Simple.Flag (fromFlagOrDefault) +import Distribution.Simple.Utils + ( safeHead + , wrapText + ) +import Distribution.Verbosity + ( normal + ) +import Text.PrettyPrint +import qualified Text.PrettyPrint as Pretty + +------------------------------------------------------------------------------- +-- Command +------------------------------------------------------------------------------- + +targetCommand :: CommandUI (NixStyleFlags ()) +targetCommand = + CommandUI + { commandName = "v2-target" + , commandSynopsis = "Disclose selected targets." + , commandUsage = usageAlternatives "v2-target" ["[TARGETS]"] + , commandDescription = + Just . const . render $ + vcat + [ intro + , vcat $ punctuate (text "\n") [targetForms, ctypes, Pretty.empty] + ] + , commandNotes = Just $ \pname -> render $ examples pname + , commandDefaultFlags = defaultNixStyleFlags () + , commandOptions = const [] + } + where + intro = + text . wrapText $ + "Discover targets in a project for use with other commands taking [TARGETS].\n\n" + ++ "Discloses fully-qualified targets from a selection of target form" + ++ " [TARGETS] (or 'all' if none given). Can also check if a target form is" + ++ " unique as some commands require a unique TARGET." + + targetForms = + vcat + [ text "A [TARGETS] item can be one of these target forms:" + , nest 1 . vcat $ + (char '-' <+>) + <$> [ text "a package target (e.g. [pkg:]package)" + , text "a component target (e.g. [package:][ctype:]component)" + , text "all packages (e.g. all)" + , text "components of a particular type (e.g. package:ctypes or all:ctypes)" + , text "a module target: (e.g. [package:][ctype:]module)" + , text "a filepath target: (e.g. [package:][ctype:]filepath)" + ] + ] + + ctypes = + vcat + [ text "The ctypes, in short form and (long form), can be one of:" + , nest 1 . vcat $ + (char '-' <+>) + <$> [ "libs" <+> parens "libraries" + , "exes" <+> parens "executables" + , "tests" + , "benches" <+> parens "benchmarks" + , "flibs" <+> parens "foreign-libraries" + ] + ] + + examples pname = + vcat + [ text "Examples" Pretty.<> colon + , nest 2 $ + vcat + [ vcat + [ text pname <+> text "v2-target all" + , nest 2 $ text "Targets of the package in the current directory or all packages in the project" + ] + , vcat + [ text pname <+> text "v2-target pkgname" + , nest 2 $ text "Targets of the package named pkgname in the project" + ] + , vcat + [ text pname <+> text "v2-target ./pkgfoo" + , nest 2 $ text "Targets of the package in the ./pkgfoo directory" + ] + , vcat + [ text pname <+> text "v2-target cname" + , nest 2 $ text "Targets of the component named cname in the project" + ] + ] + ] + +------------------------------------------------------------------------------- +-- Action +------------------------------------------------------------------------------- + +targetAction :: NixStyleFlags () -> [String] -> GlobalFlags -> IO () +targetAction flags@NixStyleFlags{..} ts globalFlags = do + ProjectBaseContext + { distDirLayout + , cabalDirLayout + , projectConfig + , localPackages + } <- + establishProjectBaseContext verbosity cliConfig OtherCommand + + (_, elaboratedPlan, _, _, _) <- + rebuildInstallPlan + verbosity + distDirLayout + cabalDirLayout + projectConfig + localPackages + Nothing + + targetSelectors <- + either (reportTargetSelectorProblems verbosity) return + =<< readTargetSelectors localPackages Nothing targetStrings + + targets :: TargetsMap <- + either (reportBuildTargetProblems verbosity) return $ + resolveTargets + selectPackageTargets + selectComponentTarget + elaboratedPlan + Nothing + targetSelectors + + printTargetForms targets elaboratedPlan + where + verbosity = fromFlagOrDefault normal (configVerbosity configFlags) + targetStrings = if null ts then ["all"] else ts + cliConfig = + commandLineFlagsToProjectConfig + globalFlags + flags + mempty + +reportBuildTargetProblems :: Verbosity -> [TargetProblem'] -> IO a +reportBuildTargetProblems verbosity = reportTargetProblems verbosity "target" + +printTargetForms :: TargetsMap -> ElaboratedInstallPlan -> IO () +printTargetForms targets elaboratedPlan = + putStrLn . render $ + vcat + [ text "Fully qualified target forms" Pretty.<> colon + , nest 1 $ vcat [text "-" <+> text tf | tf <- targetForms] + ] + where + localPkgs = + [x | Configured x@ElaboratedConfiguredPackage{elabLocalToProject = True} <- InstallPlan.toList elaboratedPlan] + + targetForm ct x = + let pkgId@PackageIdentifier{pkgName = n} = elabPkgSourceId x + in render $ pretty n Pretty.<> colon Pretty.<> text (showComponentTarget pkgId ct) + + targetForms = + sort $ + catMaybes + [ targetForm ct <$> pkg + | (u :: UnitId, xs) <- Map.toAscList targets + , let pkg = safeHead $ filter ((== u) . elabUnitId) localPkgs + , (ct :: ComponentTarget, _) <- xs + ] diff --git a/cabal-install/src/Distribution/Client/Main.hs b/cabal-install/src/Distribution/Client/Main.hs index 2f191676c65..228583a0ed3 100644 --- a/cabal-install/src/Distribution/Client/Main.hs +++ b/cabal-install/src/Distribution/Client/Main.hs @@ -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 @@ -465,6 +466,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 diff --git a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs index fef9f6efde4..a14d43e4b99 100644 --- a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs +++ b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs @@ -934,7 +934,6 @@ distinctTargetComponents targetsMap = ------------------------------------------------------------------------------ -- Displaying what we plan to do --- -- | Print a user-oriented presentation of the install plan, indicating what -- will be built. diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index c68f0dec44a..8e5494477cd 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -282,6 +282,7 @@ globalCommand commands = , "unpack" , "init" , "configure" + , "target" , "build" , "clean" , "run" @@ -334,7 +335,8 @@ globalCommand commands = , "v1-register" , "v1-reconfigure" , -- v2 commands, nix-style - "v2-build" + "v2-target" + , "v2-build" , "v2-configure" , "v2-repl" , "v2-freeze" @@ -381,6 +383,7 @@ globalCommand commands = , addCmd "path" , par , startGroup "project building and installing" + , addCmd "target" , addCmd "build" , addCmd "install" , addCmd "haddock" @@ -406,6 +409,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" diff --git a/changelog.d/pr-9744.md b/changelog.d/pr-9744.md new file mode 100644 index 00000000000..4bfc590f042 --- /dev/null +++ b/changelog.d/pr-9744.md @@ -0,0 +1,10 @@ +--- +synopsis: Discovery targets in a project +packages: [cabal-install] +prs: 9744 +issues: [4070,8953] +--- + +Adds a `cabal target` command for discovering, disclosing and checking selected +targets. The returned list shows targets in fully-qualified form. These are +unambiguous and can be used with other commands expecting `[TARGETS]`.