Install.hs 54.5 KB
Newer Older
1
2
-----------------------------------------------------------------------------
-- |
3
-- Module      :  Distribution.Client.Install
4
5
6
-- Copyright   :  (c) 2005 David Himmelstrup
--                    2007 Bjorn Bringert
--                    2007-2010 Duncan Coutts
7
8
-- License     :  BSD-like
--
9
-- Maintainer  :  cabal-devel@haskell.org
10
11
12
13
14
-- Stability   :  provisional
-- Portability :  portable
--
-- High level interface to package installation.
-----------------------------------------------------------------------------
15
module Distribution.Client.Install (
16
17
18
19
20
21
22
23
24
25
26
27
    -- * High-level interface
    install,

    -- * Lower-level interface that allows to manipulate the install plan
    makeInstallContext,
    makeInstallPlan,
    processInstallPlan,
    InstallArgs,
    InstallContext,

    -- * Prune certain packages from the install plan
    pruneInstallPlan
28
  ) where
29

30
import Data.List
31
         ( unfoldr, nub, sort, (\\) )
32
import qualified Data.Set as S
Duncan Coutts's avatar
Duncan Coutts committed
33
import Data.Maybe
34
         ( isJust, fromMaybe, maybeToList )
35
import Control.Exception as Exception
36
37
         ( Exception(toException), bracket, catches, Handler(Handler), handleJust
         , IOException, SomeException )
Duncan Coutts's avatar
Duncan Coutts committed
38
39
import System.Exit
         ( ExitCode )
40
import Distribution.Compat.Exception
41
         ( catchIO, catchExit )
42
import Control.Monad
43
         ( when, unless )
44
import System.Directory
Duncan Coutts's avatar
Duncan Coutts committed
45
         ( getTemporaryDirectory, doesFileExist, createDirectoryIfMissing )
Duncan Coutts's avatar
Duncan Coutts committed
46
import System.FilePath
Duncan Coutts's avatar
Duncan Coutts committed
47
         ( (</>), (<.>), takeDirectory )
Duncan Coutts's avatar
Duncan Coutts committed
48
import System.IO
49
         ( openFile, IOMode(WriteMode), hClose )
50
51
import System.IO.Error
         ( isDoesNotExistError, ioeGetFileName )
bjorn@bringert.net's avatar
bjorn@bringert.net committed
52

53
import Distribution.Client.Targets
54
import Distribution.Client.Dependency
55
56
import Distribution.Client.Dependency.Types
         ( Solver(..) )
Duncan Coutts's avatar
Duncan Coutts committed
57
import Distribution.Client.FetchUtils
58
import qualified Distribution.Client.Haddock as Haddock (regenerateHaddockIndex)
59
import Distribution.Client.IndexUtils as IndexUtils
60
         ( getSourcePackages, getInstalledPackages )
61
62
63
import qualified Distribution.Client.InstallPlan as InstallPlan
import Distribution.Client.InstallPlan (InstallPlan)
import Distribution.Client.Setup
64
65
         ( GlobalFlags(..)
         , ConfigFlags(..), configureCommand, filterConfigureFlags
66
         , ConfigExFlags(..), InstallFlags(..) )
Duncan Coutts's avatar
Duncan Coutts committed
67
import Distribution.Client.Config
68
         ( defaultCabalDir, defaultUserInstall )
69
70
71
import Distribution.Client.Sandbox.Timestamp
         ( withUpdateTimestamps )
import Distribution.Client.Sandbox.Types
72
73
         ( SandboxPackageInfo(..), UseSandbox(..), isUseSandbox
         , whenUsingSandbox )
74
import Distribution.Client.Tar (extractTarGzFile)
75
import Distribution.Client.Types as Source
76
77
import Distribution.Client.BuildReports.Types
         ( ReportLevel(..) )
78
import Distribution.Client.SetupWrapper
Duncan Coutts's avatar
Duncan Coutts committed
79
         ( setupWrapper, SetupScriptOptions(..), defaultSetupScriptOptions )
David Himmelstrup's avatar
David Himmelstrup committed
80
import qualified Distribution.Client.BuildReports.Anonymous as BuildReports
Duncan Coutts's avatar
Duncan Coutts committed
81
82
import qualified Distribution.Client.BuildReports.Storage as BuildReports
         ( storeAnonymous, storeLocal, fromInstallPlan )
83
import qualified Distribution.Client.InstallSymlink as InstallSymlink
84
         ( symlinkBinaries )
85
import qualified Distribution.Client.PackageIndex as SourcePackageIndex
86
import qualified Distribution.Client.Win32SelfUpgrade as Win32SelfUpgrade
87
import qualified Distribution.Client.World as World
88
import qualified Distribution.InstalledPackageInfo as Installed
89
import Paths_cabal_install (getBinDir)
90
import Distribution.Client.JobControl
91

92
import Distribution.Simple.Compiler
93
         ( CompilerId(..), Compiler(compilerId), compilerFlavor
94
         , PackageDB(..), PackageDBStack )
refold's avatar
refold committed
95
96
import Distribution.Simple.Program (ProgramConfiguration,
                                    defaultProgramConfiguration)
97
import qualified Distribution.Simple.InstallDirs as InstallDirs
98
99
import qualified Distribution.Simple.PackageIndex as PackageIndex
import Distribution.Simple.PackageIndex (PackageIndex)
100
import Distribution.Simple.Setup
101
         ( haddockCommand, HaddockFlags(..)
102
103
104
         , buildCommand, BuildFlags(..), emptyBuildFlags
         , toFlag, fromFlag, fromFlagOrDefault, flagToMaybe )
import qualified Distribution.Simple.Setup as Cabal
TillmannRendel's avatar
TillmannRendel committed
105
106
107
         ( Flag(..)
         , installCommand, InstallFlags(..), emptyInstallFlags
         , testCommand, TestFlags(..), emptyTestFlags )
108
import Distribution.Simple.Utils
109
         ( rawSystemExit, comparing, writeFileAtomic )
110
111
import Distribution.Simple.InstallDirs as InstallDirs
         ( PathTemplate, fromPathTemplate, toPathTemplate, substPathTemplate
112
         , initialPathTemplateEnv, installDirsTemplateEnv )
113
import Distribution.Package
114
         ( PackageIdentifier, PackageId, packageName, packageVersion
115
         , Package(..), PackageFixedDeps(..)
116
         , Dependency(..), thisPackageVersion, InstalledPackageId )
117
118
import qualified Distribution.PackageDescription as PackageDescription
import Distribution.PackageDescription
119
120
         ( PackageDescription, GenericPackageDescription(..), Flag(..)
         , FlagName(..), FlagAssignment )
121
import Distribution.PackageDescription.Configuration
122
         ( finalizePackageDescription )
123
import Distribution.Version
124
         ( Version, anyVersion, thisVersion )
125
import Distribution.Simple.Utils as Utils
126
         ( notice, info, warn, debugNoWrap, die, intercalate, withTempDirectory )
127
import Distribution.Client.Utils
128
129
         ( numberOfProcessors, inDir, mergeBy, MergeResult(..)
         , tryCanonicalizePath )
130
import Distribution.System
131
         ( Platform, OS(Windows), buildOS )
132
133
import Distribution.Text
         ( display )
Duncan Coutts's avatar
Duncan Coutts committed
134
import Distribution.Verbosity as Verbosity
135
         ( Verbosity, showForCabal, normal, verbose )
136
import Distribution.Simple.BuildPaths ( exeExtension )
bjorn@bringert.net's avatar
bjorn@bringert.net committed
137

138
139
140
141
142
143
144
145
146
147
148
--TODO:
-- * assign flags to packages individually
--   * complain about flags that do not apply to any package given as target
--     so flags do not apply to dependencies, only listed, can use flag
--     constraints for dependencies
--   * only record applicable flags in world file
-- * allow flag constraints
-- * allow installed constraints
-- * allow flag and installed preferences
-- * change world file to use cabal section syntax
--   * allow persistent configure flags for each package individually
149

150
151
152
153
154
155
-- ------------------------------------------------------------
-- * Top level user actions
-- ------------------------------------------------------------

-- | Installs the packages needed to satisfy a list of dependencies.
--
156
install
157
  :: Verbosity
158
  -> PackageDBStack
159
160
  -> [Repo]
  -> Compiler
161
  -> Platform
162
  -> ProgramConfiguration
163
  -> UseSandbox
164
  -> Maybe SandboxPackageInfo
165
  -> GlobalFlags
166
  -> ConfigFlags
167
  -> ConfigExFlags
168
  -> InstallFlags
169
  -> HaddockFlags
170
  -> [UserTarget]
171
  -> IO ()
172
install verbosity packageDBs repos comp platform conf useSandbox mSandboxPkgInfo
refold's avatar
refold committed
173
174
  globalFlags configFlags configExFlags installFlags haddockFlags
  userTargets0 = do
175

176
    installContext <- makeInstallContext verbosity args (Just userTargets0)
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
177
    installPlan    <- foldProgress logMsg die' return =<<
178
179
180
181
182
                      makeInstallPlan verbosity args installContext

    processInstallPlan verbosity args installContext installPlan
  where
    args :: InstallArgs
183
    args = (packageDBs, repos, comp, platform, conf, useSandbox, mSandboxPkgInfo,
184
185
186
            globalFlags, configFlags, configExFlags, installFlags,
            haddockFlags)

Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
187
188
189
190
191
192
193
194
    die' message = die (message ++ if isUseSandbox useSandbox
                                   then installFailedInSandbox else [])
    -- TODO: use a better error message, remove duplication.
    installFailedInSandbox =
      "Note: when using a sandbox, all packages are required to have \
      \consistent dependencies. \
      \Try reinstalling/unregistering the offending packages or \
      \recreating the sandbox."
195
196
    logMsg message rest = debugNoWrap verbosity message >> rest

refold's avatar
refold committed
197
-- TODO: Make InstallContext a proper datatype with documented fields.
198
199
200
201
-- | Common context for makeInstallPlan and processInstallPlan.
type InstallContext = ( PackageIndex, SourcePackageDb
                      , [UserTarget], [PackageSpecifier SourcePackage] )

refold's avatar
refold committed
202
203
-- TODO: Make InstallArgs a proper datatype with documented fields or just get
-- rid of it completely.
204
205
206
207
-- | Initial arguments given to 'install' or 'makeInstallContext'.
type InstallArgs = ( PackageDBStack
                   , [Repo]
                   , Compiler
208
                   , Platform
209
                   , ProgramConfiguration
210
                   , UseSandbox
211
                   , Maybe SandboxPackageInfo
212
213
214
215
216
217
218
                   , GlobalFlags
                   , ConfigFlags
                   , ConfigExFlags
                   , InstallFlags
                   , HaddockFlags )

-- | Make an install context given install arguments.
219
makeInstallContext :: Verbosity -> InstallArgs -> Maybe [UserTarget]
220
221
                      -> IO InstallContext
makeInstallContext verbosity
222
  (packageDBs, repos, comp, _, conf,_,_,
223
   globalFlags, _, _, _, _) mUserTargets = do
224

225
226
    installedPkgIndex <- getInstalledPackages verbosity comp packageDBs conf
    sourcePkgDb       <- getSourcePackages    verbosity repos
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
    (userTargets, pkgSpecifiers) <- case mUserTargets of
      Nothing           ->
        -- We want to distinguish between the case where the user has given an
        -- empty list of targets on the command-line and the case where we
        -- specifically want to have an empty list of targets.
        return ([], [])
      Just userTargets0 -> do
        -- For install, if no target is given it means we use the current
        -- directory as the single target.
        let userTargets | null userTargets0 = [UserTargetLocalDir "."]
                        | otherwise         = userTargets0

        pkgSpecifiers <- resolveUserTargets verbosity
                         (fromFlag $ globalWorldFile globalFlags)
                         (packageIndex sourcePkgDb)
                         userTargets
        return (userTargets, pkgSpecifiers)
245
246

    return (installedPkgIndex, sourcePkgDb, userTargets, pkgSpecifiers)
247

248
249
250
251
-- | Make an install plan given install context and install arguments.
makeInstallPlan :: Verbosity -> InstallArgs -> InstallContext
                -> IO (Progress String String InstallPlan)
makeInstallPlan verbosity
252
  (_, _, comp, platform, _, _, mSandboxPkgInfo,
253
254
255
256
257
258
259
   _, configFlags, configExFlags, installFlags,
   _)
  (installedPkgIndex, sourcePkgDb,
   _, pkgSpecifiers) = do

    solver <- chooseSolver verbosity (fromFlag (configSolver configExFlags))
              (compilerId comp)
260
    notice verbosity "Resolving dependencies..."
261
262
263
    return $ planPackages comp platform mSandboxPkgInfo solver
      configFlags configExFlags installFlags
      installedPkgIndex sourcePkgDb pkgSpecifiers
264

265
266
267
268
269
-- | Given an install plan, perform the actual installations.
processInstallPlan :: Verbosity -> InstallArgs -> InstallContext
                   -> InstallPlan
                   -> IO ()
processInstallPlan verbosity
270
  args@(_,_, _, _, _, _, _, _, _, _, installFlags, _)
271
272
  (installedPkgIndex, sourcePkgDb,
   userTargets, pkgSpecifiers) installPlan = do
273
274
    checkPrintPlan verbosity installedPkgIndex installPlan sourcePkgDb
      installFlags pkgSpecifiers
275

276
277
    unless dryRun $ do
      installPlan' <- performInstallations verbosity
278
279
                      args installedPkgIndex installPlan
      postInstallActions verbosity args userTargets installPlan'
280
  where
281
    dryRun = fromFlag (installDryRun installFlags)
282

283
284
285
-- ------------------------------------------------------------
-- * Installation planning
-- ------------------------------------------------------------
286

287
planPackages :: Compiler
288
             -> Platform
289
             -> Maybe SandboxPackageInfo
290
             -> Solver
291
292
293
             -> ConfigFlags
             -> ConfigExFlags
             -> InstallFlags
294
             -> PackageIndex
295
296
             -> SourcePackageDb
             -> [PackageSpecifier SourcePackage]
297
             -> Progress String String InstallPlan
298
299
planPackages comp platform mSandboxPkgInfo solver
             configFlags configExFlags installFlags
300
             installedPkgIndex sourcePkgDb pkgSpecifiers =
301

302
        resolveDependencies
303
          platform (compilerId comp)
304
          solver
305
          resolverParams
306

307
    >>= if onlyDeps then pruneInstallPlan pkgSpecifiers else return
308

309
310
311
  where
    resolverParams =

Andres Löh's avatar
Andres Löh committed
312
313
314
        setMaxBackjumps (if maxBackjumps < 0 then Nothing
                                             else Just maxBackjumps)

315
316
      . setIndependentGoals independentGoals

Andres Löh's avatar
Andres Löh committed
317
      . setReorderGoals reorderGoals
Andres Löh's avatar
Andres Löh committed
318
319

      . setAvoidReinstalls avoidReinstalls
320

321
322
      . setShadowPkgs shadowPkgs

323
      . setPreferenceDefault (if upgradeDeps then PreferAllLatest
324
325
326
327
328
329
330
331
332
                                             else PreferLatestForSelected)

      . addPreferences
          -- preferences from the config file or command line
          [ PackageVersionPreference name ver
          | Dependency name ver <- configPreferences configExFlags ]

      . addConstraints
          -- version constraints from the config file or command line
333
            (map userToPackageConstraint (configExConstraints configExFlags))
334
335
336
337

      . addConstraints
          --FIXME: this just applies all flags to all targets which
          -- is silly. We should check if the flags are appropriate
338
          [ PackageConstraintFlags (pkgSpecifierTarget pkgSpecifier) flags
339
340
          | let flags = configConfigurationsFlags configFlags
          , not (null flags)
341
342
343
344
345
          , pkgSpecifier <- pkgSpecifiers ]

      . addConstraints
          [ PackageConstraintStanzas (pkgSpecifierTarget pkgSpecifier) stanzas
          | pkgSpecifier <- pkgSpecifiers ]
346

347
348
      . maybe id applySandboxInstallPolicy mSandboxPkgInfo

349
350
      . (if reinstall then reinstallTargets else id)

351
      $ standardInstallPolicy
352
        installedPkgIndex sourcePkgDb pkgSpecifiers
353

354
355
356
357
    stanzas = concat
        [ if testsEnabled then [TestStanzas] else []
        , if benchmarksEnabled then [BenchStanzas] else []
        ]
358
    testsEnabled = fromFlagOrDefault False $ configTests configFlags
359
    benchmarksEnabled = fromFlagOrDefault False $ configBenchmarks configFlags
360

361
362
363
364
    reinstall        = fromFlag (installReinstall        installFlags)
    reorderGoals     = fromFlag (installReorderGoals     installFlags)
    independentGoals = fromFlag (installIndependentGoals installFlags)
    avoidReinstalls  = fromFlag (installAvoidReinstalls  installFlags)
365
    shadowPkgs       = fromFlag (installShadowPkgs       installFlags)
366
367
368
    maxBackjumps     = fromFlag (installMaxBackjumps     installFlags)
    upgradeDeps      = fromFlag (installUpgradeDeps      installFlags)
    onlyDeps         = fromFlag (installOnlyDeps         installFlags)
369

370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
-- | Remove the provided targets from the install plan.
pruneInstallPlan :: Package pkg => [PackageSpecifier pkg] -> InstallPlan
                    -> Progress String String InstallPlan
pruneInstallPlan pkgSpecifiers =
  -- TODO: this is a general feature and should be moved to D.C.Dependency
  -- Also, the InstallPlan.remove should return info more precise to the
  -- problem, rather than the very general PlanProblem type.
  either (Fail . explain) Done
  . InstallPlan.remove (\pkg -> packageName pkg `elem` targetnames)
  where
    explain :: [InstallPlan.PlanProblem] -> String
    explain problems =
      "Cannot select only the dependencies (as requested by the "
      ++ "'--only-dependencies' flag), "
      ++ (case pkgids of
             [pkgid] -> "the package " ++ display pkgid ++ " is "
             _       -> "the packages "
                        ++ intercalate ", " (map display pkgids) ++ " are ")
      ++ "required by a dependency of one of the other targets."
      where
        pkgids =
          nub [ depid
              | InstallPlan.PackageMissingDeps _ depids <- problems
              , depid <- depids
              , packageName depid `elem` targetnames ]

    targetnames  = map pkgSpecifierTarget pkgSpecifiers

398
399
400
401
-- ------------------------------------------------------------
-- * Informational messages
-- ------------------------------------------------------------

402
403
-- | Perform post-solver checks of the install plan and print it if
-- either requested or needed.
404
405
406
checkPrintPlan :: Verbosity
               -> PackageIndex
               -> InstallPlan
407
               -> SourcePackageDb
408
               -> InstallFlags
409
               -> [PackageSpecifier SourcePackage]
410
               -> IO ()
411
412
checkPrintPlan verbosity installed installPlan sourcePkgDb
  installFlags pkgSpecifiers = do
413

414
415
416
417
418
419
420
421
  -- User targets that are already installed.
  let preExistingTargets =
        [ p | let tgts = map pkgSpecifierTarget pkgSpecifiers,
              InstallPlan.PreExisting p <- InstallPlan.toList installPlan,
              packageName p `elem` tgts ]

  -- If there's nothing to install, we print the already existing
  -- target packages as an explanation.
422
  when nothingToInstall $
423
424
425
426
    notice verbosity $ unlines $
         "All the requested packages are already installed:"
       : map (display . packageId) preExistingTargets
      ++ ["Use --reinstall if you want to reinstall anyway."]
427

428
  let lPlan = linearizeInstallPlan installed installPlan
429
430
  -- Are any packages classified as reinstalls?
  let reinstalledPkgs = concatMap (extractReinstalls . snd) lPlan
431
432
433
434
435
436
437
438
  -- Packages that are already broken.
  let oldBrokenPkgs =
          map Installed.installedPackageId
        . PackageIndex.reverseDependencyClosure installed
        . map (Installed.installedPackageId . fst)
        . PackageIndex.brokenPackages
        $ installed
  let excluded = reinstalledPkgs ++ oldBrokenPkgs
439
  -- Packages that are reverse dependencies of replaced packages are very
440
441
442
  -- likely to be broken. We exclude packages that are already broken.
  let newBrokenPkgs =
        filter (\ p -> not (Installed.installedPackageId p `elem` excluded))
443
444
               (PackageIndex.reverseDependencyClosure installed reinstalledPkgs)
  let containsReinstalls = not (null reinstalledPkgs)
445
  let breaksPkgs         = not (null newBrokenPkgs)
446
447
448
449
450
451
452
453

  let adaptedVerbosity
        | containsReinstalls && not overrideReinstall = verbosity `max` verbose
        | otherwise                                   = verbosity

  -- We print the install plan if we are in a dry-run or if we are confronted
  -- with a dangerous install plan.
  when (dryRun || containsReinstalls && not overrideReinstall) $
454
455
    printPlan (dryRun || breaksPkgs && not overrideReinstall)
      adaptedVerbosity lPlan sourcePkgDb
456

457
458
459
460
461
462
463
464
  -- If the install plan is dangerous, we print various warning messages. In
  -- particular, if we can see that packages are likely to be broken, we even
  -- bail out (unless installation has been forced with --force-reinstalls).
  when containsReinstalls $ do
    if breaksPkgs
      then do
        (if dryRun || overrideReinstall then warn verbosity else die) $ unlines $
            "The following packages are likely to be broken by the reinstalls:"
465
          : map (display . Installed.sourcePackageId) newBrokenPkgs
466
467
468
469
470
471
472
          ++ if overrideReinstall
               then if dryRun then [] else
                 ["Continuing even though the plan contains dangerous reinstalls."]
               else
                 ["Use --force-reinstalls if you want to install anyway."]
      else unless dryRun $ warn verbosity
             "Note that reinstalls are always dangerous. Continuing anyway..."
473
474
475

  where
    nothingToInstall = null (InstallPlan.ready installPlan)
476
477

    dryRun            = fromFlag (installDryRun            installFlags)
478
    overrideReinstall = fromFlag (installOverrideReinstall installFlags)
479

480
481
482
linearizeInstallPlan :: PackageIndex
                     -> InstallPlan
                     -> [(ConfiguredPackage, PackageStatus)]
483
484
linearizeInstallPlan installedPkgIndex plan =
    unfoldr next plan
485
486
487
  where
    next plan' = case InstallPlan.ready plan' of
      []      -> Nothing
488
489
490
491
492
493
494
495
496
      (pkg:_) -> Just ((pkg, status), plan'')
        where
          pkgid  = packageId pkg
          status = packageStatus installedPkgIndex pkg
          plan'' = InstallPlan.completed pkgid
                     (BuildOk DocsNotTried TestsNotTried)
                     (InstallPlan.processing [pkg] plan')
          --FIXME: This is a bit of a hack,
          -- pretending that each package is installed
497

498
499
data PackageStatus = NewPackage
                   | NewVersion [Version]
500
                   | Reinstall  [InstalledPackageId] [PackageChange]
501
502
503

type PackageChange = MergeResult PackageIdentifier PackageIdentifier

504
505
506
extractReinstalls :: PackageStatus -> [InstalledPackageId]
extractReinstalls (Reinstall ipids _) = ipids
extractReinstalls _                   = []
507
508
509
510
511
512

packageStatus :: PackageIndex -> ConfiguredPackage -> PackageStatus
packageStatus installedPkgIndex cpkg =
  case PackageIndex.lookupPackageName installedPkgIndex
                                      (packageName cpkg) of
    [] -> NewPackage
refold's avatar
refold committed
513
514
    ps ->  case filter ((==packageId cpkg)
                        . Installed.sourcePackageId) (concatMap snd ps) of
515
516
517
      []           -> NewVersion (map fst ps)
      pkgs@(pkg:_) -> Reinstall (map Installed.installedPackageId pkgs)
                                (changes pkg cpkg)
518
519
520
521
522
523

  where

    changes :: Installed.InstalledPackageInfo
            -> ConfiguredPackage
            -> [MergeResult PackageIdentifier PackageIdentifier]
refold's avatar
refold committed
524
525
526
527
528
529
530
531
532
533
534
    changes pkg pkg' =
      filter changed
      $ mergeBy (comparing packageName)
        -- get dependencies of installed package (convert to source pkg ids via
        -- index)
        (nub . sort . concatMap
         (maybeToList . fmap Installed.sourcePackageId .
          PackageIndex.lookupInstalledPackageId installedPkgIndex) .
         Installed.depends $ pkg)
        -- get dependencies of configured package
        (nub . sort . depends $ pkg')
535
536
537
538

    changed (InBoth    pkgid pkgid') = pkgid /= pkgid'
    changed _                        = True

539
540
541
printPlan :: Bool -- is dry run
          -> Verbosity
          -> [(ConfiguredPackage, PackageStatus)]
542
          -> SourcePackageDb
543
          -> IO ()
544
printPlan dryRun verbosity plan sourcePkgDb = case plan of
545
546
547
  []   -> return ()
  pkgs
    | verbosity >= Verbosity.verbose -> notice verbosity $ unlines $
548
        ("In order, the following " ++ wouldWill ++ " be installed:")
549
550
      : map showPkgAndReason pkgs
    | otherwise -> notice verbosity $ unlines $
refold's avatar
refold committed
551
552
        ("In order, the following " ++ wouldWill
         ++ " be installed (use -v for more details):")
553
      : map showPkg pkgs
554
  where
555
556
557
    wouldWill | dryRun    = "would"
              | otherwise = "will"

558
559
560
    showPkg (pkg, _) = display (packageId pkg) ++
                       showLatest (pkg)

561
    showPkgAndReason (pkg', pr) = display (packageId pkg') ++
562
          showLatest pkg' ++
563
564
          showFlagAssignment (nonDefaultFlags pkg') ++
          showStanzas (stanzas pkg') ++ " " ++
565
          case pr of
566
567
568
            NewPackage     -> "(new package)"
            NewVersion _   -> "(new version)"
            Reinstall _ cs -> "(reinstall)" ++ case cs of
569
570
571
                []   -> ""
                diff -> " changes: "  ++ intercalate ", " (map change diff)

572
    showLatest :: ConfiguredPackage -> String
573
574
575
576
577
578
    showLatest pkg = case mLatestVersion of
        Just latestVersion ->
            if pkgVersion /= latestVersion
            then (" (latest: " ++ display latestVersion ++ ")")
            else ""
        Nothing -> ""
579
580
      where
        pkgVersion    = packageVersion pkg
581
582
583
584
585
586
        mLatestVersion :: Maybe Version
        mLatestVersion = case SourcePackageIndex.lookupPackageName
                                (packageIndex sourcePkgDb)
                                (packageName pkg) of
            [] -> Nothing
            x -> Just $ packageVersion $ last x
587

588
589
590
591
    toFlagAssignment :: [Flag] -> FlagAssignment
    toFlagAssignment = map (\ f -> (flagName f, flagDefault f))

    nonDefaultFlags :: ConfiguredPackage -> FlagAssignment
592
    nonDefaultFlags (ConfiguredPackage spkg fa _ _) =
593
594
595
596
597
      let defaultAssignment =
            toFlagAssignment
             (genPackageFlags (Source.packageDescription spkg))
      in  fa \\ defaultAssignment

598
599
600
601
602
603
604
605
    stanzas :: ConfiguredPackage -> [OptionalStanza]
    stanzas (ConfiguredPackage _ _ sts _) = sts

    showStanzas :: [OptionalStanza] -> String
    showStanzas = concatMap ((' ' :) . showStanza)
    showStanza TestStanzas  = "*test"
    showStanza BenchStanzas = "*bench"

606
    -- FIXME: this should be a proper function in a proper place
607
    showFlagAssignment :: FlagAssignment -> String
608
609
610
611
612
    showFlagAssignment = concatMap ((' ' :) . showFlagValue)
    showFlagValue (f, True)   = '+' : showFlagName f
    showFlagValue (f, False)  = '-' : showFlagName f
    showFlagName (FlagName f) = f

613
614
615
616
617
    change (OnlyInLeft pkgid)        = display pkgid ++ " removed"
    change (InBoth     pkgid pkgid') = display pkgid ++ " -> "
                                    ++ display (packageVersion pkgid')
    change (OnlyInRight      pkgid') = display pkgid' ++ " added"

618
619
620
621
622
623
624
625
626
627
-- ------------------------------------------------------------
-- * Post installation stuff
-- ------------------------------------------------------------

-- | Various stuff we do after successful or unsuccessfully installing a bunch
-- of packages. This includes:
--
--  * build reporting, local and remote
--  * symlinking binaries
--  * updating indexes
628
--  * updating world file
629
630
631
--  * error reporting
--
postInstallActions :: Verbosity
632
                   -> InstallArgs
633
                   -> [UserTarget]
634
635
636
                   -> InstallPlan
                   -> IO ()
postInstallActions verbosity
637
638
  (packageDBs, _, comp, platform, conf, useSandbox, mSandboxPkgInfo
  ,globalFlags, configFlags, _, installFlags, _)
639
  targets installPlan = do
640

641
  unless oneShot $
642
    World.insert verbosity worldFile
643
644
645
      --FIXME: does not handle flags
      [ World.WorldPkgInfo dep []
      | UserTargetNamed dep <- targets ]
646

647
  let buildReports = BuildReports.fromInstallPlan installPlan
refold's avatar
refold committed
648
649
  BuildReports.storeLocal (installSummaryFile installFlags) buildReports
    (InstallPlan.planPlatform installPlan)
650
651
652
653
654
  when (reportingLevel >= AnonymousReports) $
    BuildReports.storeAnonymous buildReports
  when (reportingLevel == DetailedReports) $
    storeDetailedBuildReports verbosity logsDir buildReports

655
  regenerateHaddockIndex verbosity packageDBs comp platform conf
656
657
658
659
660
661
                         configFlags installFlags installPlan

  symlinkBinaries verbosity configFlags installFlags installPlan

  printBuildFailures installPlan

662
663
664
  updateSandboxTimestampsFile useSandbox mSandboxPkgInfo
                              comp platform installPlan

665
666
  where
    reportingLevel = fromFlag (installBuildReports installFlags)
667
    logsDir        = fromFlag (globalLogsDir globalFlags)
668
669
    oneShot        = fromFlag (installOneShot installFlags)
    worldFile      = fromFlag $ globalWorldFile globalFlags
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706

storeDetailedBuildReports :: Verbosity -> FilePath
                          -> [(BuildReports.BuildReport, Repo)] -> IO ()
storeDetailedBuildReports verbosity logsDir reports = sequence_
  [ do dotCabal <- defaultCabalDir
       let logFileName = display (BuildReports.package report) <.> "log"
           logFile     = logsDir </> logFileName
           reportsDir  = dotCabal </> "reports" </> remoteRepoName remoteRepo
           reportFile  = reportsDir </> logFileName

       handleMissingLogFile $ do
         buildLog <- readFile logFile
         createDirectoryIfMissing True reportsDir -- FIXME
         writeFile reportFile (show (BuildReports.show report, buildLog))

  | (report, Repo { repoKind = Left remoteRepo }) <- reports
  , isLikelyToHaveLogFile (BuildReports.installOutcome report) ]

  where
    isLikelyToHaveLogFile BuildReports.ConfigureFailed {} = True
    isLikelyToHaveLogFile BuildReports.BuildFailed     {} = True
    isLikelyToHaveLogFile BuildReports.InstallFailed   {} = True
    isLikelyToHaveLogFile BuildReports.InstallOk       {} = True
    isLikelyToHaveLogFile _                               = False

    handleMissingLogFile = Exception.handleJust missingFile $ \ioe ->
      warn verbosity $ "Missing log file for build report: "
                    ++ fromMaybe ""  (ioeGetFileName ioe)

    missingFile ioe
      | isDoesNotExistError ioe  = Just ioe
    missingFile _                = Nothing


regenerateHaddockIndex :: Verbosity
                       -> [PackageDB]
                       -> Compiler
707
                       -> Platform
708
709
710
711
712
                       -> ProgramConfiguration
                       -> ConfigFlags
                       -> InstallFlags
                       -> InstallPlan
                       -> IO ()
713
regenerateHaddockIndex verbosity packageDBs comp platform conf
714
715
716
717
718
719
720
721
722
723
724
725
726
727
                       configFlags installFlags installPlan
  | haddockIndexFileIsRequested && shouldRegenerateHaddockIndex = do

  defaultDirs <- InstallDirs.defaultInstallDirs
                   (compilerFlavor comp)
                   (fromFlag (configUserInstall configFlags))
                   True
  let indexFileTemplate = fromFlag (installHaddockIndex installFlags)
      indexFile = substHaddockIndexFileName defaultDirs indexFileTemplate

  notice verbosity $
     "Updating documentation index " ++ indexFile

  --TODO: might be nice if the install plan gave us the new InstalledPackageInfo
728
729
  installedPkgIndex <- getInstalledPackages verbosity comp packageDBs conf
  Haddock.regenerateHaddockIndex verbosity installedPkgIndex conf indexFile
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756

  | otherwise = return ()
  where
    haddockIndexFileIsRequested =
         fromFlag (installDocumentation installFlags)
      && isJust (flagToMaybe (installHaddockIndex installFlags))

    -- We want to regenerate the index if some new documentation was actually
    -- installed. Since the index is per-user, we don't do it for global
    -- installs or special cases where we're installing into a specific db.
    shouldRegenerateHaddockIndex = normalUserInstall
                                && someDocsWereInstalled installPlan
      where
        someDocsWereInstalled = any installedDocs . InstallPlan.toList
        normalUserInstall     = (UserPackageDB `elem` packageDBs)
                             && all (not . isSpecificPackageDB) packageDBs

        installedDocs (InstallPlan.Installed _ (BuildOk DocsOk _)) = True
        installedDocs _                                            = False
        isSpecificPackageDB (SpecificPackageDB _) = True
        isSpecificPackageDB _                     = False

    substHaddockIndexFileName defaultDirs = fromPathTemplate
                                          . substPathTemplate env
      where
        env  = env0 ++ installDirsTemplateEnv absoluteDirs
        env0 = InstallDirs.compilerTemplateEnv (compilerId comp)
757
            ++ InstallDirs.platformTemplateEnv platform
758
759
760
761
762
763
        absoluteDirs = InstallDirs.substituteInstallDirTemplates
                         env0 templateDirs
        templateDirs = InstallDirs.combineInstallDirs fromFlagOrDefault
                         defaultDirs (configInstallDirs configFlags)


764
symlinkBinaries :: Verbosity
765
                -> ConfigFlags
766
                -> InstallFlags
767
                -> InstallPlan -> IO ()
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
symlinkBinaries verbosity configFlags installFlags plan = do
  failed <- InstallSymlink.symlinkBinaries configFlags installFlags plan
  case failed of
    [] -> return ()
    [(_, exe, path)] ->
      warn verbosity $
           "could not create a symlink in " ++ bindir ++ " for "
        ++ exe ++ " because the file exists there already but is not "
        ++ "managed by cabal. You can create a symlink for this executable "
        ++ "manually if you wish. The executable file has been installed at "
        ++ path
    exes ->
      warn verbosity $
           "could not create symlinks in " ++ bindir ++ " for "
        ++ intercalate ", " [ exe | (_, exe, _) <- exes ]
        ++ " because the files exist there already and are not "
        ++ "managed by cabal. You can create symlinks for these executables "
        ++ "manually if you wish. The executable files have been installed at "
        ++ intercalate ", " [ path | (_, _, path) <- exes ]
  where
788
    bindir = fromFlag (installSymlinkBinDir installFlags)
789

790

791
printBuildFailures :: InstallPlan -> IO ()
792
793
794
795
796
797
798
799
800
801
802
803
printBuildFailures plan =
  case [ (pkg, reason)
       | InstallPlan.Failed pkg reason <- InstallPlan.toList plan ] of
    []     -> return ()
    failed -> die . unlines
            $ "Error: some packages failed to install:"
            : [ display (packageId pkg) ++ printFailureReason reason
              | (pkg, reason) <- failed ]
  where
    printFailureReason reason = case reason of
      DependentFailed pkgid -> " depends on " ++ display pkgid
                            ++ " which failed to install."
804
805
      DownloadFailed  e -> " failed while downloading the package."
                        ++ " The exception was:\n  " ++ show e
806
807
808
809
810
811
      UnpackFailed    e -> " failed while unpacking the package."
                        ++ " The exception was:\n  " ++ show e
      ConfigureFailed e -> " failed during the configure step."
                        ++ " The exception was:\n  " ++ show e
      BuildFailed     e -> " failed during the building phase."
                        ++ " The exception was:\n  " ++ show e
812
813
      TestsFailed     e -> " failed during the tests phase."
                        ++ " The exception was:\n  " ++ show e
814
815
816
      InstallFailed   e -> " failed during the final install step."
                        ++ " The exception was:\n  " ++ show e

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
-- | If we're working inside a sandbox and some add-source deps were installed,
-- update the timestamps of those deps.
updateSandboxTimestampsFile :: UseSandbox -> Maybe SandboxPackageInfo
                        -> Compiler -> Platform -> InstallPlan
                        -> IO ()
updateSandboxTimestampsFile (UseSandbox sandboxDir)
                            (Just (SandboxPackageInfo _ _ _ allAddSourceDeps))
                            comp platform installPlan =
  withUpdateTimestamps sandboxDir (compilerId comp) platform $ \_ -> do
    let allInstalled = [ pkg | InstallPlan.Installed pkg _
                            <- InstallPlan.toList installPlan ]
        allSrcPkgs   = [ pkg | ConfiguredPackage pkg _ _ _ <- allInstalled ]
        allPaths     = [ pth | LocalUnpackedPackage pth
                            <- map packageSource allSrcPkgs]
    allPathsCanonical <- mapM tryCanonicalizePath allPaths
    return $! filter (`S.member` allAddSourceDeps) allPathsCanonical

updateSandboxTimestampsFile _ _ _ _ _ = return ()
835
836
837
838
839
840
841
842
843
844

-- ------------------------------------------------------------
-- * Actually do the installations
-- ------------------------------------------------------------

data InstallMisc = InstallMisc {
    rootCmd    :: Maybe FilePath,
    libVersion :: Maybe Version
  }

refold's avatar
refold committed
845
846
847
848
-- | If logging is enabled, contains location of the log file and the verbosity
-- level for logging.
type UseLogFile = Maybe (PackageIdentifier -> FilePath, Verbosity)

849
performInstallations :: Verbosity
850
                     -> InstallArgs
851
                     -> PackageIndex
852
853
854
                     -> InstallPlan
                     -> IO InstallPlan
performInstallations verbosity
855
  (packageDBs, _, comp, _, conf, useSandbox, _,
856
   globalFlags, configFlags, configExFlags, installFlags, haddockFlags)
857
  installedPkgIndex installPlan = do
858

859
860
861
862
863
864
  -- With 'install -j' it can be a bit hard to tell whether a sandbox is used.
  whenUsingSandbox useSandbox $ \sandboxDir ->
    when parallelBuild $
      notice verbosity $ "Notice: installing into a sandbox located at "
                         ++ sandboxDir

865
866
867
868
  jobControl   <- if parallelBuild then newParallelJobControl
                                   else newSerialJobControl
  buildLimit   <- newJobLimit numJobs
  fetchLimit   <- newJobLimit (min numJobs numFetchJobs)
refold's avatar
refold committed
869
870
  installLock  <- newLock -- serialise installation
  cacheLock    <- newLock -- serialise access to setup exe cache
871

refold's avatar
refold committed
872
  executeInstallPlan verbosity jobControl useLogFile installPlan $ \cpkg ->
873
    installConfiguredPackage platform compid configFlags
874
                             cpkg $ \configFlags' src pkg pkgoverride ->
875
876
      fetchSourcePackage verbosity fetchLimit src $ \src' ->
        installLocalPackage verbosity buildLimit (packageId pkg) src' $ \mpath ->
refold's avatar
refold committed
877
          installUnpackedPackage verbosity buildLimit installLock numJobs
refold's avatar
refold committed
878
                                 (setupScriptOptions installedPkgIndex cacheLock)
879
                                 miscOptions configFlags' installFlags haddockFlags
880
                                 compid platform pkg pkgoverride mpath useLogFile
881
882
883
884
885

  where
    platform = InstallPlan.planPlatform installPlan
    compid   = InstallPlan.planCompiler installPlan

886
887
888
889
    numJobs  = case installNumJobs installFlags of
      Cabal.NoFlag        -> 1
      Cabal.Flag Nothing  -> numberOfProcessors
      Cabal.Flag (Just n) -> n
refold's avatar
refold committed
890
    numFetchJobs  = 2
891
892
    parallelBuild = numJobs >= 2

refold's avatar
refold committed
893
    setupScriptOptions index lock = SetupScriptOptions {
894
895
      useCabalVersion  = maybe anyVersion thisVersion (libVersion miscOptions),
      useCompiler      = Just comp,
896
      usePlatform      = Just platform,
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
      -- Hack: we typically want to allow the UserPackageDB for finding the
      -- Cabal lib when compiling any Setup.hs even if we're doing a global
      -- install. However we also allow looking in a specific package db.
      usePackageDB     = if UserPackageDB `elem` packageDBs
                           then packageDBs
                           else let (db@GlobalPackageDB:dbs) = packageDBs
                                 in db : UserPackageDB : dbs,
                                --TODO: use Ord instance:
                                -- insert UserPackageDB packageDBs
      usePackageIndex  = if UserPackageDB `elem` packageDBs
                           then Just index
                           else Nothing,
      useProgramConfig = conf,
      useDistPref      = fromFlagOrDefault
                           (useDistPref defaultSetupScriptOptions)
                           (configDistPref configFlags),
      useLoggingHandle = Nothing,
914
      useWorkingDir    = Nothing,
refold's avatar
refold committed
915
      forceExternalSetupMethod = parallelBuild,
refold's avatar
refold committed
916
      setupCacheLock   = Just lock
917
918
    }
    reportingLevel = fromFlag (installBuildReports installFlags)
919
    logsDir        = fromFlag (globalLogsDir globalFlags)
refold's avatar
refold committed
920
921
922
923
924

    -- Should the build output be written to a log file instead of stdout?
    useLogFile :: UseLogFile
    useLogFile = fmap ((\f -> (f, loggingVerbosity)) . substLogFileName)
                 logFileTemplate
925
      where
refold's avatar
refold committed
926
927
928
929
930
931
932
        installLogFile' = flagToMaybe $ installLogFile installFlags
        defaultTemplate = toPathTemplate $ logsDir </> "$pkgid" <.> "log"

        -- If the user has specified --remote-build-reporting=detailed, use the
        -- default log file location. If the --build-log option is set, use the
        -- provided location. Otherwise don't use logging, unless building in
        -- parallel (in which case the default location is used).
933
        logFileTemplate :: Maybe PathTemplate
refold's avatar
refold committed
934
935
936
937
938
939
940
941
942
943
944
945
946
947
        logFileTemplate
          | useDefaultTemplate = Just defaultTemplate
          | otherwise          = installLogFile'

        -- If the user has specified --remote-build-reporting=detailed or
        -- --build-log, use more verbose logging.
        loggingVerbosity :: Verbosity
        loggingVerbosity | overrideVerbosity = max Verbosity.verbose verbosity
                         | otherwise         = verbosity

        useDefaultTemplate :: Bool
        useDefaultTemplate
          | reportingLevel == DetailedReports = True
          | isJust installLogFile'            = False
948
          | parallelBuild                     = True
refold's avatar
refold committed
949
950
951
952
953
954
          | otherwise                         = False

        overrideVerbosity :: Bool
        overrideVerbosity
          | reportingLevel == DetailedReports = True
          | isJust installLogFile'            = True
955
          | parallelBuild                     = False
refold's avatar
refold committed
956
          | otherwise                         = False
957
958

    substLogFileName :: PathTemplate -> PackageIdentifier -> FilePath
959
960
961
    substLogFileName template pkg = fromPathTemplate
                                  . substPathTemplate env
                                  $ template
refold's avatar
refold committed
962
963
      where env = initialPathTemplateEnv (packageId pkg)
                  (compilerId comp) platform
refold's avatar
refold committed
964

965
966
    miscOptions  = InstallMisc {
      rootCmd    = if fromFlag (configUserInstall configFlags)
967
                      || (isUseSandbox useSandbox)
968
969
                     then Nothing      -- ignore --root-cmd if --user
                                       -- or working inside a sandbox.
970
971
972
973
974
                     else flagToMaybe (installRootCmd installFlags),
      libVersion = flagToMaybe (configCabalVersion configExFlags)
    }


975
976
executeInstallPlan :: Verbosity
                   -> JobControl IO (PackageId, BuildResult)
refold's avatar
refold committed
977
                   -> UseLogFile
978
979
980
                   -> InstallPlan
                   -> (ConfiguredPackage -> IO BuildResult)
                   -> IO InstallPlan
refold's avatar
refold committed
981
executeInstallPlan verbosity jobCtl useLogFile plan0 installPkg =
982
    tryNewTasks 0 plan0
983
  where
984
985
986
987
988
989
    tryNewTasks taskCount plan = do
      case InstallPlan.ready plan of
        [] | taskCount == 0 -> return plan
           | otherwise      -> waitForTasks taskCount plan
        pkgs                -> do
          sequence_
refold's avatar
refold committed
990
            [ do info verbosity $ "Ready to install " ++ display pkgid
991
992
993
994
995
996
997
998
999
1000
1001
                 spawnJob jobCtl $ do
                   buildResult <- installPkg pkg
                   return (packageId pkg, buildResult)
            | pkg <- pkgs
            , let pkgid = packageId pkg]

          let taskCount' = taskCount + length pkgs
              plan'      = InstallPlan.processing pkgs plan
          waitForTasks taskCount' plan'

    waitForTasks taskCount plan = do
refold's avatar
refold committed
1002
      info verbosity $ "Waiting for install task to finish..."
1003
      (pkgid, buildResult) <- collectJob jobCtl
refold's avatar
refold committed
1004
      printBuildResult pkgid buildResult
1005
1006
1007
1008
      let taskCount' = taskCount-1
          plan'      = updatePlan pkgid buildResult plan
      tryNewTasks taskCount' plan'

refold's avatar
refold committed
1009
    updatePlan :: PackageIdentifier -> BuildResult -> InstallPlan -> InstallPlan
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
    updatePlan pkgid (Right buildSuccess) =
      InstallPlan.completed pkgid buildSuccess

    updatePlan pkgid (Left buildFailure) =
      InstallPlan.failed    pkgid buildFailure depsFailure
      where
        depsFailure = DependentFailed pkgid
        -- So this first pkgid failed for whatever reason (buildFailure).
        -- All the other packages that depended on this pkgid, which we
        -- now cannot build, we mark as failing due to 'DependentFailed'
        -- which kind of means it was not their fault.
1021

refold's avatar
refold committed
1022
1023
1024
1025
1026
1027
1028
    -- Print last 10 lines of the build log if something went wrong, and
    -- 'Installed $PKGID' otherwise.
    printBuildResult :: PackageId -> BuildResult -> IO ()
    printBuildResult pkgid buildResult = case buildResult of
        (Right _) -> notice verbosity $ "Installed " ++ display pkgid
        (Left _)  -> do
          notice verbosity $ "Failed to install " ++ display pkgid
1029
1030
1031
1032
          when (verbosity >= normal) $
            case useLogFile of
              Nothing                 -> return ()
              Just (mkLogFileName, _) -> do
1033
1034
                let logName = mkLogFileName pkgid
                    n       = 10
1035
                putStr $ "Last " ++ (show n)
1036
                  ++ " lines of the build log ( " ++ logName ++ " ):\n"
1037
                printLastNLines logName n
refold's avatar
refold committed
1038
1039
1040
1041
1042

    printLastNLines :: FilePath -> Int -> IO ()
    printLastNLines path n = do
      lns <- fmap lines $ readFile path
      let len = length lns
1043
1044
      let toDrop = if (len > n && n > 0) then (len - n) else 0
      mapM_ putStrLn (drop toDrop lns)
1045

1046
-- | Call an installer for an 'SourcePackage' but override the configure
1047
-- flags with the ones given by the 'ConfiguredPackage'. In particular the
1048
1049
1050
1051
-- 'ConfiguredPackage' specifies an exact 'FlagAssignment' and exactly
-- versioned package dependencies. So we ignore any previous partial flag
-- assignment or dependency constraints and use the new ones.
--
1052
installConfiguredPackage :: Platform -> CompilerId
1053
                         ->  ConfigFlags -> ConfiguredPackage
1054
                         -> (ConfigFlags -> PackageLocation (Maybe FilePath)
1055
1056
                                         -> PackageDescription
                                         -> PackageDescriptionOverride -> a)
1057
                         -> a
1058
installConfiguredPackage platform comp configFlags
refold's avatar
refold committed
1059
1060
  (ConfiguredPackage (SourcePackage _ gpkg source pkgoverride)
   flags stanzas deps)
1061
  installPkg = installPkg configFlags {
1062
    configConfigurationsFlags = flags,