1
+ -- | cabal-install CLI command: build
2
+ --
3
+ module Distribution.Client.CmdShowBuildInfo (
4
+ -- * The @build@ CLI and action
5
+ showBuildInfoCommand ,
6
+ showBuildInfoAction
7
+ ) where
8
+
9
+ import Distribution.Client.ProjectOrchestration
10
+ import Distribution.Client.CmdErrorMessages
11
+ import Distribution.Client.CmdInstall.ClientInstallFlags
12
+
13
+ import Distribution.Client.Setup
14
+ ( GlobalFlags , ConfigFlags (.. ), ConfigExFlags , InstallFlags )
15
+ import qualified Distribution.Client.Setup as Client
16
+ import Distribution.Simple.Setup
17
+ ( HaddockFlags , fromFlagOrDefault , TestFlags )
18
+ import Distribution.Simple.Command
19
+ ( CommandUI (.. ), usageAlternatives )
20
+ import Distribution.Verbosity
21
+ ( Verbosity , silent )
22
+ import Distribution.Simple.Utils
23
+ ( wrapText , die' )
24
+ import Distribution.Types.UnitId (UnitId )
25
+
26
+ import qualified Data.Map as Map
27
+ import qualified Distribution.Simple.Setup as Cabal
28
+ import Distribution.Client.SetupWrapper
29
+ import Distribution.Simple.Program ( defaultProgramDb )
30
+ import qualified Distribution.Client.InstallPlan as InstallPlan
31
+ import Distribution.Client.ProjectPlanning.Types
32
+ import Distribution.Client.ProjectPlanning (
33
+ setupHsConfigureFlags , setupHsConfigureArgs ,
34
+ setupHsBuildFlags , setupHsBuildArgs ,
35
+ setupHsScriptOptions
36
+ )
37
+ import Distribution.Client.DistDirLayout (distBuildDirectory )
38
+ import Distribution.Client.Types ( PackageLocation (.. ), GenericReadyPackage (.. ) )
39
+ import Distribution.Client.JobControl (newLock , Lock )
40
+ import Distribution.Simple.Configure (tryGetPersistBuildConfig )
41
+ import Data.List (find )
42
+
43
+ showBuildInfoCommand :: CommandUI (ConfigFlags , ConfigExFlags , InstallFlags , HaddockFlags , TestFlags )
44
+ showBuildInfoCommand = Client. installCommand {
45
+ commandName = " new-show-build-info" ,
46
+ commandSynopsis = " Show project build information" ,
47
+ commandUsage = usageAlternatives " new-show-build-info" [ " [TARGETS] [FLAGS]" ],
48
+ commandDescription = Just $ \ _ -> wrapText $
49
+ " Build one or more targets from within the project. The available "
50
+ ++ " targets are the packages in the project as well as individual "
51
+ ++ " components within those packages, including libraries, executables, "
52
+ ++ " test-suites or benchmarks. Targets can be specified by name or "
53
+ ++ " location. If no target is specified then the default is to build "
54
+ ++ " the package in the current directory.\n\n "
55
+
56
+ ++ " Dependencies are built or rebuilt as necessary. Additional "
57
+ ++ " configuration flags can be specified on the command line and these "
58
+ ++ " extend the project configuration from the 'cabal.project', "
59
+ ++ " 'cabal.project.local' and other files." ,
60
+ commandNotes = Just $ \ pname ->
61
+ " Examples:\n "
62
+ ++ " " ++ pname ++ " new-build\n "
63
+ ++ " Build the package in the current directory or all packages in the project\n "
64
+ ++ " " ++ pname ++ " new-build pkgname\n "
65
+ ++ " Build the package named pkgname in the project\n "
66
+ ++ " " ++ pname ++ " new-build ./pkgfoo\n "
67
+ ++ " Build the package in the ./pkgfoo directory\n "
68
+ ++ " " ++ pname ++ " new-build cname\n "
69
+ ++ " Build the component named cname module Distribution.Client.InstallPlanin the project\n "
70
+ ++ " " ++ pname ++ " new-build cname --module Distribution.Client.InstallPlanenable-profiling\n "
71
+ ++ " Build the component in profilingmodule Distribution.Client.InstallPlan mode (including dependencies as needed)\n\n "
72
+
73
+ ++ cmdCommonHelpTextNewBuildBeta
74
+ }
75
+
76
+
77
+ -- | The @build@ command does a lot. It brings the install plan up to date,
78
+ -- selects that part of the plan needed by the given or implicit targets and
79
+ -- then executes the plan.
80
+ --
81
+ -- For more details on how this works, see the module
82
+ -- "Distribution.Client.ProjectOrchestration"
83
+ --
84
+ showBuildInfoAction :: (ConfigFlags , ConfigExFlags , InstallFlags , HaddockFlags , TestFlags )
85
+ -> [String ] -> GlobalFlags -> IO ()
86
+ showBuildInfoAction (configFlags, configExFlags, installFlags, haddockFlags, testFlags)
87
+ targetStrings globalFlags = do
88
+
89
+ baseCtx <- establishProjectBaseContext verbosity cliConfig
90
+ let baseCtx' = baseCtx {
91
+ buildSettings = (buildSettings baseCtx) {
92
+ buildSettingDryRun = True
93
+ }
94
+ }
95
+
96
+ targetSelectors <- either (reportTargetSelectorProblems verbosity) return
97
+ =<< readTargetSelectors (localPackages baseCtx') Nothing targetStrings
98
+
99
+ buildCtx <-
100
+ runProjectPreBuildPhase verbosity baseCtx' $ \ elaboratedPlan -> do
101
+ -- Interpret the targets on the command line as build targets
102
+ -- (as opposed to say repl or haddock targets).
103
+ targets <- either (reportTargetProblems verbosity) return
104
+ $ resolveTargets
105
+ selectPackageTargets
106
+ selectComponentTarget
107
+ TargetProblemCommon
108
+ elaboratedPlan
109
+ Nothing
110
+ targetSelectors
111
+
112
+ -- Don't prune the plan though, as we want a list of all configured packages
113
+ return (elaboratedPlan, targets)
114
+
115
+ scriptLock <- newLock
116
+ showTargets verbosity baseCtx' buildCtx scriptLock
117
+
118
+ where
119
+ -- Default to silent verbosity otherwise it will pollute our json output
120
+ verbosity = fromFlagOrDefault silent (configVerbosity configFlags)
121
+ cliConfig = commandLineFlagsToProjectConfig
122
+ globalFlags configFlags configExFlags
123
+ installFlags defaultClientInstallFlags
124
+ haddockFlags
125
+ testFlags
126
+
127
+ -- Pretty nasty piecemeal out of json, but I can't see a way to retrieve output of the setupWrapper'd tasks
128
+ showTargets :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> IO ()
129
+ showTargets verbosity baseCtx buildCtx lock = do
130
+ putStr " ["
131
+ mapM_ showSeparated (zip [0 .. ] targets)
132
+ putStrLn " ]"
133
+ where configured = [p | InstallPlan. Configured p <- InstallPlan. toList (elaboratedPlanOriginal buildCtx)]
134
+ targets = fst <$> (Map. toList . targetsMap $ buildCtx)
135
+ doShowInfo unitId = showInfo verbosity baseCtx buildCtx lock configured unitId
136
+ showSeparated (idx, unitId)
137
+ | idx == length targets - 1 = doShowInfo unitId
138
+ | otherwise = doShowInfo unitId >> putStrLn " ,"
139
+
140
+ showInfo :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> [ElaboratedConfiguredPackage ] -> UnitId -> IO ()
141
+ showInfo verbosity baseCtx buildCtx lock pkgs targetUnitId
142
+ | Nothing <- mbPkg = die' verbosity $ " No unit " ++ show targetUnitId
143
+ | Just pkg <- mbPkg = do
144
+ let shared = elaboratedShared buildCtx
145
+ install = elaboratedPlanOriginal buildCtx
146
+ dirLayout = distDirLayout baseCtx
147
+ buildDir = distBuildDirectory dirLayout (elabDistDirParams shared pkg)
148
+ flags = setupHsBuildFlags pkg shared verbosity buildDir
149
+ args = setupHsBuildArgs pkg
150
+ srcDir = case (elabPkgSourceLocation pkg) of
151
+ LocalUnpackedPackage fp -> fp
152
+ _ -> " "
153
+ scriptOptions = setupHsScriptOptions
154
+ (ReadyPackage pkg)
155
+ install
156
+ shared
157
+ dirLayout
158
+ srcDir
159
+ buildDir
160
+ False
161
+ lock
162
+ configureFlags = setupHsConfigureFlags (ReadyPackage pkg) shared verbosity buildDir
163
+ configureArgs = setupHsConfigureArgs pkg
164
+ -- Configure the package if there's no existing config
165
+ lbi <- tryGetPersistBuildConfig buildDir
166
+ case lbi of
167
+ Left _ -> setupWrapper
168
+ verbosity
169
+ scriptOptions
170
+ (Just $ elabPkgDescription pkg)
171
+ (Cabal. configureCommand defaultProgramDb)
172
+ (const $ configureFlags)
173
+ (const configureArgs)
174
+ Right _ -> pure ()
175
+ setupWrapper
176
+ verbosity
177
+ scriptOptions
178
+ (Just $ elabPkgDescription pkg)
179
+ (Cabal. showBuildInfoCommand defaultProgramDb)
180
+ (const flags)
181
+ (const args)
182
+ where mbPkg = find ((targetUnitId == ) . elabUnitId) pkgs
183
+
184
+ -- | This defines what a 'TargetSelector' means for the @write-autogen-files@ command.
185
+ -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to,
186
+ -- or otherwise classifies the problem.
187
+ --
188
+ -- For the @write-autogen-files@ command select all components except non-buildable and disabled
189
+ -- tests\/benchmarks, fail if there are no such components
190
+ --
191
+ selectPackageTargets :: TargetSelector
192
+ -> [AvailableTarget k ] -> Either TargetProblem [k ]
193
+ selectPackageTargets targetSelector targets
194
+
195
+ -- If there are any buildable targets then we select those
196
+ | not (null targetsBuildable)
197
+ = Right targetsBuildable
198
+
199
+ -- If there are targets but none are buildable then we report those
200
+ | not (null targets)
201
+ = Left (TargetProblemNoneEnabled targetSelector targets')
202
+
203
+ -- If there are no targets at all then we report that
204
+ | otherwise
205
+ = Left (TargetProblemNoTargets targetSelector)
206
+ where
207
+ targets' = forgetTargetsDetail targets
208
+ targetsBuildable = selectBuildableTargetsWith
209
+ (buildable targetSelector)
210
+ targets
211
+
212
+ -- When there's a target filter like "pkg:tests" then we do select tests,
213
+ -- but if it's just a target like "pkg" then we don't build tests unless
214
+ -- they are requested by default (i.e. by using --enable-tests)
215
+ buildable (TargetPackage _ _ Nothing ) TargetNotRequestedByDefault = False
216
+ buildable (TargetAllPackages Nothing ) TargetNotRequestedByDefault = False
217
+ buildable _ _ = True
218
+
219
+ -- | For a 'TargetComponent' 'TargetSelector', check if the component can be
220
+ -- selected.
221
+ --
222
+ -- For the @build@ command we just need the basic checks on being buildable etc.
223
+ --
224
+ selectComponentTarget :: SubComponentTarget
225
+ -> AvailableTarget k -> Either TargetProblem k
226
+ selectComponentTarget subtarget =
227
+ either (Left . TargetProblemCommon ) Right
228
+ . selectComponentTargetBasic subtarget
229
+
230
+
231
+ -- | The various error conditions that can occur when matching a
232
+ -- 'TargetSelector' against 'AvailableTarget's for the @build@ command.
233
+ --
234
+ data TargetProblem =
235
+ TargetProblemCommon TargetProblemCommon
236
+
237
+ -- | The 'TargetSelector' matches targets but none are buildable
238
+ | TargetProblemNoneEnabled TargetSelector [AvailableTarget () ]
239
+
240
+ -- | There are no targets at all
241
+ | TargetProblemNoTargets TargetSelector
242
+ deriving (Eq , Show )
243
+
244
+ reportTargetProblems :: Verbosity -> [TargetProblem ] -> IO a
245
+ reportTargetProblems verbosity =
246
+ die' verbosity . unlines . map renderTargetProblem
247
+
248
+ renderTargetProblem :: TargetProblem -> String
249
+ renderTargetProblem (TargetProblemCommon problem) =
250
+ renderTargetProblemCommon " build" problem
251
+ renderTargetProblem (TargetProblemNoneEnabled targetSelector targets) =
252
+ renderTargetProblemNoneEnabled " build" targetSelector targets
253
+ renderTargetProblem(TargetProblemNoTargets targetSelector) =
254
+ renderTargetProblemNoTargets " build" targetSelector
0 commit comments