1 {-# LANGUAGE DataKinds #-}
2 {-# LANGUAGE DeriveGeneric #-}
4 -----------------------------------------------------------------------------
6 -----------------------------------------------------------------------------
9 -- Module : Distribution.Client.Config
10 -- Copyright : (c) David Himmelstrup 2005
13 -- Maintainer : lemmih@gmail.com
14 -- Stability : provisional
15 -- Portability : portable
17 -- Utilities for handling saved state such as known packages, known servers and
18 -- downloaded packages.
19 module Distribution
.Client
.Config
24 , showConfigWithComments
29 , defaultScriptBuildsDir
39 , configFieldDescriptions
43 , withProgramOptionsFields
46 , createDefaultConfigFile
51 import Distribution
.Client
.Compat
.Prelude
52 import Distribution
.Compat
.Environment
(lookupEnv
)
55 import Language
.Haskell
.Extension
(Language
(Haskell2010
))
57 import Distribution
.Deprecated
.ViewAsFieldDescr
61 import Distribution
.Client
.BuildReports
.Types
64 import Distribution
.Client
.CmdInstall
.ClientInstallFlags
65 ( ClientInstallFlags
(..)
66 , clientInstallOptions
67 , defaultClientInstallFlags
69 import qualified Distribution
.Client
.Init
.Defaults
as IT
70 import qualified Distribution
.Client
.Init
.Types
as IT
73 import Distribution
.Client
.Setup
80 , defaultConfigExFlags
89 import Distribution
.Client
.Types
100 import Distribution
.Client
.Types
.Credentials
105 import Distribution
.Utils
.NubList
112 import qualified Data
.ByteString
as BS
113 import qualified Data
.Map
as M
114 import Distribution
.Client
.Errors
115 import Distribution
.Client
.HttpUtils
118 import Distribution
.Client
.ParseUtils
123 import Distribution
.Client
.ProjectFlags
(ProjectFlags
(..))
124 import Distribution
.Client
.ReplFlags
125 import Distribution
.Client
.Version
126 ( cabalInstallVersion
128 import qualified Distribution
.Compat
.CharParsing
as P
129 import Distribution
.Compat
.Environment
132 import Distribution
.Compiler
133 ( CompilerFlavor
(..)
134 , defaultCompilerFlavor
136 import Distribution
.Deprecated
.ParseUtils
157 import qualified Distribution
.Deprecated
.ParseUtils
as ParseUtils
160 import Distribution
.Parsec
(ParsecParser
, parsecFilePath
, parsecOptCommaList
, parsecToken
)
161 import Distribution
.Simple
.Command
162 ( CommandUI
(commandOptions
)
163 , ShowOrParseArgs
(..)
164 , commandDefaultFlags
166 import Distribution
.Simple
.Compiler
167 ( DebugInfoLevel
(..)
168 , OptimisationLevel
(..)
170 import Distribution
.Simple
.InstallDirs
176 import Distribution
.Simple
.Program
179 import Distribution
.Simple
.Setup
180 ( BenchmarkFlags
(..)
181 , CommonSetupFlags
(..)
187 , defaultBenchmarkFlags
189 , defaultHaddockFlags
200 import Distribution
.Simple
.Utils
208 import Distribution
.Solver
.Types
.ConstraintSource
209 import Distribution
.Utils
.Path
(getSymbolicPath
, unsafeMakeSymbolicPath
)
210 import Distribution
.Verbosity
218 import System
.Directory
219 ( XdgDirectory
(XdgCache
, XdgConfig
, XdgState
)
220 , createDirectoryIfMissing
223 , getAppUserDataDirectory
228 import System
.FilePath
233 import System
.IO.Error
234 ( isDoesNotExistError
236 import Text
.PrettyPrint
239 import qualified Text
.PrettyPrint
as Disp
244 import Text
.PrettyPrint
.HughesPJ
251 -- * Configuration saved in the config file
255 data SavedConfig
= SavedConfig
256 { savedGlobalFlags
:: GlobalFlags
257 , savedInitFlags
:: IT
.InitFlags
258 , savedInstallFlags
:: InstallFlags
259 , savedClientInstallFlags
:: ClientInstallFlags
260 , savedConfigureFlags
:: ConfigFlags
261 , savedConfigureExFlags
:: ConfigExFlags
262 , savedUserInstallDirs
:: InstallDirs
(Flag PathTemplate
)
263 , savedGlobalInstallDirs
:: InstallDirs
(Flag PathTemplate
)
264 , savedUploadFlags
:: UploadFlags
265 , savedReportFlags
:: ReportFlags
266 , savedHaddockFlags
:: HaddockFlags
267 , savedTestFlags
:: TestFlags
268 , savedBenchmarkFlags
:: BenchmarkFlags
269 , savedProjectFlags
:: ProjectFlags
270 , savedReplMulti
:: Flag
Bool
274 instance Monoid SavedConfig
where
278 instance Semigroup SavedConfig
where
281 { savedGlobalFlags
= combinedSavedGlobalFlags
282 , savedInitFlags
= combinedSavedInitFlags
283 , savedInstallFlags
= combinedSavedInstallFlags
284 , savedClientInstallFlags
= combinedSavedClientInstallFlags
285 , savedConfigureFlags
= combinedSavedConfigureFlags
286 , savedConfigureExFlags
= combinedSavedConfigureExFlags
287 , savedUserInstallDirs
= combinedSavedUserInstallDirs
288 , savedGlobalInstallDirs
= combinedSavedGlobalInstallDirs
289 , savedUploadFlags
= combinedSavedUploadFlags
290 , savedReportFlags
= combinedSavedReportFlags
291 , savedHaddockFlags
= combinedSavedHaddockFlags
292 , savedTestFlags
= combinedSavedTestFlags
293 , savedBenchmarkFlags
= combinedSavedBenchmarkFlags
294 , savedProjectFlags
= combinedSavedProjectFlags
295 , savedReplMulti
= combinedSavedReplMulti
298 -- This is ugly, but necessary. If we're mappending two config files, we
299 -- want the values of the *non-empty* list fields from the second one to
300 -- \*override* the corresponding values from the first one. Default
301 -- behaviour (concatenation) is confusing and makes some use cases (see
302 -- #1884) impossible.
304 -- However, we also want to allow specifying multiple values for a list
305 -- field in a *single* config file. For example, we want the following to
308 -- remote-repo: hackage.haskell.org:http://hackage.haskell.org/
309 -- remote-repo: private-collection:http://hackage.local/
311 -- So we can't just wrap the list fields inside Flags; we have to do some
312 -- special-casing just for SavedConfig.
314 -- NB: the signature prevents us from using 'combine' on lists.
315 combine
' :: (SavedConfig
-> flags
) -> (flags
-> Flag a
) -> Flag a
316 combine
' field subfield
=
317 (subfield
. field
$ a
) `mappend`
(subfield
. field
$ b
)
321 => (SavedConfig
-> flags
)
324 combineMonoid field subfield
=
325 (subfield
. field
$ a
) `mappend`
(subfield
. field
$ b
)
327 lastNonEmpty
' :: (SavedConfig
-> flags
) -> (flags
-> [a
]) -> [a
]
328 lastNonEmpty
' field subfield
=
329 let a
' = subfield
. field
$ a
330 b
' = subfield
. field
$ b
336 :: (Eq a
, Monoid a
) => (SavedConfig
-> flags
) -> (flags
-> a
) -> a
337 lastNonMempty
' field subfield
=
338 let a
' = subfield
. field
$ a
339 b
' = subfield
. field
$ b
340 in if b
' == mempty
then a
' else b
'
343 :: (SavedConfig
-> flags
)
344 -> (flags
-> NubList a
)
346 lastNonEmptyNL
' field subfield
=
347 let a
' = subfield
. field
$ a
348 b
' = subfield
. field
$ b
349 in case fromNubList b
' of
353 combinedSavedGlobalFlags
=
355 { globalVersion
= combine globalVersion
356 , globalNumericVersion
= combine globalNumericVersion
357 , globalConfigFile
= combine globalConfigFile
358 , globalConstraintsFile
= combine globalConstraintsFile
359 , globalRemoteRepos
= lastNonEmptyNL globalRemoteRepos
360 , globalCacheDir
= combine globalCacheDir
361 , globalLocalNoIndexRepos
= lastNonEmptyNL globalLocalNoIndexRepos
362 , globalActiveRepos
= combine globalActiveRepos
363 , globalLogsDir
= combine globalLogsDir
364 , globalIgnoreExpiry
= combine globalIgnoreExpiry
365 , globalHttpTransport
= combine globalHttpTransport
366 , globalNix
= combine globalNix
367 , globalStoreDir
= combine globalStoreDir
368 , globalProgPathExtra
= lastNonEmptyNL globalProgPathExtra
371 combine
= combine
' savedGlobalFlags
372 lastNonEmptyNL
= lastNonEmptyNL
' savedGlobalFlags
374 combinedSavedInitFlags
=
376 { IT
.applicationDirs
= combineMonoid savedInitFlags IT
.applicationDirs
377 , IT
.author
= combine IT
.author
378 , IT
.buildTools
= combineMonoid savedInitFlags IT
.buildTools
379 , IT
.cabalVersion
= combine IT
.cabalVersion
380 , IT
.category
= combine IT
.category
381 , IT
.dependencies
= combineMonoid savedInitFlags IT
.dependencies
382 , IT
.email
= combine IT
.email
383 , IT
.exposedModules
= combineMonoid savedInitFlags IT
.exposedModules
384 , IT
.extraSrc
= combineMonoid savedInitFlags IT
.extraSrc
385 , IT
.extraDoc
= combineMonoid savedInitFlags IT
.extraDoc
386 , IT
.homepage
= combine IT
.homepage
387 , IT
.initHcPath
= combine IT
.initHcPath
388 , IT
.initVerbosity
= combine IT
.initVerbosity
389 , IT
.initializeTestSuite
= combine IT
.initializeTestSuite
390 , IT
.interactive
= combine IT
.interactive
391 , IT
.language
= combine IT
.language
392 , IT
.license
= combine IT
.license
393 , IT
.mainIs
= combine IT
.mainIs
394 , IT
.minimal
= combine IT
.minimal
395 , IT
.noComments
= combine IT
.noComments
396 , IT
.otherExts
= combineMonoid savedInitFlags IT
.otherExts
397 , IT
.otherModules
= combineMonoid savedInitFlags IT
.otherModules
398 , IT
.overwrite
= combine IT
.overwrite
399 , IT
.packageDir
= combine IT
.packageDir
400 , IT
.packageName
= combine IT
.packageName
401 , IT
.packageType
= combine IT
.packageType
402 , IT
.quiet
= combine IT
.quiet
403 , IT
.simpleProject
= combine IT
.simpleProject
404 , IT
.sourceDirs
= combineMonoid savedInitFlags IT
.sourceDirs
405 , IT
.synopsis
= combine IT
.synopsis
406 , IT
.testDirs
= combineMonoid savedInitFlags IT
.testDirs
407 , IT
.version
= combine IT
.version
410 combine
= combine
' savedInitFlags
412 combinedSavedInstallFlags
=
414 { installDocumentation
= combine installDocumentation
415 , installHaddockIndex
= combine installHaddockIndex
416 , installDryRun
= combine installDryRun
417 , installOnlyDownload
= combine installOnlyDownload
418 , installDest
= combine installDest
419 , installMaxBackjumps
= combine installMaxBackjumps
420 , installReorderGoals
= combine installReorderGoals
421 , installCountConflicts
= combine installCountConflicts
422 , installFineGrainedConflicts
= combine installFineGrainedConflicts
423 , installMinimizeConflictSet
= combine installMinimizeConflictSet
424 , installIndependentGoals
= combine installIndependentGoals
425 , installPreferOldest
= combine installPreferOldest
426 , installShadowPkgs
= combine installShadowPkgs
427 , installStrongFlags
= combine installStrongFlags
428 , installAllowBootLibInstalls
= combine installAllowBootLibInstalls
429 , installOnlyConstrained
= combine installOnlyConstrained
430 , installReinstall
= combine installReinstall
431 , installAvoidReinstalls
= combine installAvoidReinstalls
432 , installOverrideReinstall
= combine installOverrideReinstall
433 , installUpgradeDeps
= combine installUpgradeDeps
434 , installOnly
= combine installOnly
435 , installOnlyDeps
= combine installOnlyDeps
436 , installIndexState
= combine installIndexState
437 , installRootCmd
= combine installRootCmd
438 , installSummaryFile
= lastNonEmptyNL installSummaryFile
439 , installLogFile
= combine installLogFile
440 , installBuildReports
= combine installBuildReports
441 , installReportPlanningFailure
= combine installReportPlanningFailure
442 , installSymlinkBinDir
= combine installSymlinkBinDir
443 , installPerComponent
= combine installPerComponent
444 , installNumJobs
= combine installNumJobs
445 , installUseSemaphore
= combine installUseSemaphore
446 , installKeepGoing
= combine installKeepGoing
447 , installRunTests
= combine installRunTests
448 , installOfflineMode
= combine installOfflineMode
451 combine
= combine
' savedInstallFlags
452 lastNonEmptyNL
= lastNonEmptyNL
' savedInstallFlags
454 combinedSavedClientInstallFlags
=
456 { cinstInstallLibs
= combine cinstInstallLibs
457 , cinstEnvironmentPath
= combine cinstEnvironmentPath
458 , cinstOverwritePolicy
= combine cinstOverwritePolicy
459 , cinstInstallMethod
= combine cinstInstallMethod
460 , cinstInstalldir
= combine cinstInstalldir
463 combine
= combine
' savedClientInstallFlags
465 combinedSavedCommonFlags which
=
467 { setupDistPref
= combine setupDistPref
468 , setupWorkingDir
= combine setupWorkingDir
469 , setupCabalFilePath
= combine setupCabalFilePath
470 , setupVerbosity
= combine setupVerbosity
471 , setupTargets
= lastNonEmpty setupTargets
474 lastNonEmpty
= lastNonEmpty
' which
475 combine
= combine
' which
477 combinedSavedConfigureFlags
=
479 { configCommonFlags
= combinedSavedCommonFlags
(configCommonFlags
. savedConfigureFlags
)
480 , configPrograms_
= configPrograms_
. savedConfigureFlags
$ b
481 , -- TODO: NubListify
482 configProgramPaths
= lastNonEmpty configProgramPaths
483 , -- TODO: NubListify
484 configProgramArgs
= lastNonEmpty configProgramArgs
485 , configProgramPathExtra
= lastNonEmptyNL configProgramPathExtra
486 , configInstantiateWith
= lastNonEmpty configInstantiateWith
487 , configHcFlavor
= combine configHcFlavor
488 , configHcPath
= combine configHcPath
489 , configHcPkg
= combine configHcPkg
490 , configVanillaLib
= combine configVanillaLib
491 , configProfLib
= combine configProfLib
492 , configProf
= combine configProf
493 , configSharedLib
= combine configSharedLib
494 , configStaticLib
= combine configStaticLib
495 , configDynExe
= combine configDynExe
496 , configFullyStaticExe
= combine configFullyStaticExe
497 , configProfExe
= combine configProfExe
498 , configProfDetail
= combine configProfDetail
499 , configProfLibDetail
= combine configProfLibDetail
500 , -- TODO: NubListify
501 configConfigureArgs
= lastNonEmpty configConfigureArgs
502 , configOptimization
= combine configOptimization
503 , configDebugInfo
= combine configDebugInfo
504 , configProgPrefix
= combine configProgPrefix
505 , configProgSuffix
= combine configProgSuffix
506 , -- Parametrised by (Flag PathTemplate), so safe to use 'mappend'.
508 (configInstallDirs
. savedConfigureFlags
$ a
)
509 `mappend`
(configInstallDirs
. savedConfigureFlags
$ b
)
510 , configScratchDir
= combine configScratchDir
511 , -- TODO: NubListify
512 configExtraLibDirs
= lastNonEmpty configExtraLibDirs
513 , configExtraLibDirsStatic
= lastNonEmpty configExtraLibDirsStatic
514 , -- TODO: NubListify
515 configExtraFrameworkDirs
= lastNonEmpty configExtraFrameworkDirs
516 , -- TODO: NubListify
517 configExtraIncludeDirs
= lastNonEmpty configExtraIncludeDirs
518 , configDeterministic
= combine configDeterministic
519 , configIPID
= combine configIPID
520 , configCID
= combine configCID
521 , configUserInstall
= combine configUserInstall
522 , -- TODO: NubListify
523 configPackageDBs
= lastNonEmpty configPackageDBs
524 , configGHCiLib
= combine configGHCiLib
525 , configSplitSections
= combine configSplitSections
526 , configSplitObjs
= combine configSplitObjs
527 , configStripExes
= combine configStripExes
528 , configStripLibs
= combine configStripLibs
529 , -- TODO: NubListify
530 configConstraints
= lastNonEmpty configConstraints
531 , -- TODO: NubListify
532 configDependencies
= lastNonEmpty configDependencies
533 , configPromisedDependencies
= lastNonEmpty configPromisedDependencies
534 , -- TODO: NubListify
535 configConfigurationsFlags
= lastNonMempty configConfigurationsFlags
536 , configTests
= combine configTests
537 , configBenchmarks
= combine configBenchmarks
538 , configCoverage
= combine configCoverage
539 , configLibCoverage
= combine configLibCoverage
540 , configExactConfiguration
= combine configExactConfiguration
541 , configFlagError
= combine configFlagError
542 , configRelocatable
= combine configRelocatable
543 , configUseResponseFiles
= combine configUseResponseFiles
544 , configDumpBuildInfo
= combine configDumpBuildInfo
545 , configAllowDependingOnPrivateLibs
=
546 combine configAllowDependingOnPrivateLibs
547 , configCoverageFor
= combine configCoverageFor
550 combine
= combine
' savedConfigureFlags
551 lastNonEmpty
= lastNonEmpty
' savedConfigureFlags
552 lastNonEmptyNL
= lastNonEmptyNL
' savedConfigureFlags
553 lastNonMempty
= lastNonMempty
' savedConfigureFlags
555 combinedSavedConfigureExFlags
=
557 { configCabalVersion
= combine configCabalVersion
558 , configAppend
= combine configAppend
559 , configBackup
= combine configBackup
560 , -- TODO: NubListify
561 configExConstraints
= lastNonEmpty configExConstraints
562 , -- TODO: NubListify
563 configPreferences
= lastNonEmpty configPreferences
564 , configSolver
= combine configSolver
566 combineMonoid savedConfigureExFlags configAllowNewer
568 combineMonoid savedConfigureExFlags configAllowOlder
569 , configWriteGhcEnvironmentFilesPolicy
=
570 combine configWriteGhcEnvironmentFilesPolicy
573 combine
= combine
' savedConfigureExFlags
574 lastNonEmpty
= lastNonEmpty
' savedConfigureExFlags
576 -- Parametrised by (Flag PathTemplate), so safe to use 'mappend'.
577 combinedSavedUserInstallDirs
=
578 savedUserInstallDirs a
579 `mappend` savedUserInstallDirs b
581 -- Parametrised by (Flag PathTemplate), so safe to use 'mappend'.
582 combinedSavedGlobalInstallDirs
=
583 savedGlobalInstallDirs a
584 `mappend` savedGlobalInstallDirs b
586 combinedSavedUploadFlags
=
588 { uploadCandidate
= combine uploadCandidate
589 , uploadDoc
= combine uploadDoc
590 , uploadToken
= combine uploadToken
591 , uploadUsername
= combine uploadUsername
592 , uploadPassword
= combine uploadPassword
593 , uploadPasswordCmd
= combine uploadPasswordCmd
594 , uploadVerbosity
= combine uploadVerbosity
597 combine
= combine
' savedUploadFlags
599 combinedSavedReportFlags
=
601 { reportToken
= combine reportToken
602 , reportUsername
= combine reportUsername
603 , reportPassword
= combine reportPassword
604 , reportVerbosity
= combine reportVerbosity
607 combine
= combine
' savedReportFlags
609 combinedSavedHaddockFlags
=
611 { haddockCommonFlags
= combinedSavedCommonFlags
(haddockCommonFlags
. savedHaddockFlags
)
612 , -- TODO: NubListify
613 haddockProgramPaths
= lastNonEmpty haddockProgramPaths
614 , -- TODO: NubListify
615 haddockProgramArgs
= lastNonEmpty haddockProgramArgs
616 , haddockHoogle
= combine haddockHoogle
617 , haddockHtml
= combine haddockHtml
618 , haddockHtmlLocation
= combine haddockHtmlLocation
619 , haddockForHackage
= combine haddockForHackage
620 , haddockExecutables
= combine haddockExecutables
621 , haddockTestSuites
= combine haddockTestSuites
622 , haddockBenchmarks
= combine haddockBenchmarks
623 , haddockForeignLibs
= combine haddockForeignLibs
624 , haddockInternal
= combine haddockInternal
625 , haddockCss
= combine haddockCss
626 , haddockLinkedSource
= combine haddockLinkedSource
627 , haddockQuickJump
= combine haddockQuickJump
628 , haddockHscolourCss
= combine haddockHscolourCss
629 , haddockContents
= combine haddockContents
630 , haddockKeepTempFiles
= combine haddockKeepTempFiles
631 , haddockIndex
= combine haddockIndex
632 , haddockBaseUrl
= combine haddockBaseUrl
633 , haddockLib
= combine haddockLib
634 , haddockOutputDir
= combine haddockOutputDir
637 combine
= combine
' savedHaddockFlags
638 lastNonEmpty
= lastNonEmpty
' savedHaddockFlags
640 combinedSavedTestFlags
=
642 { testCommonFlags
= combinedSavedCommonFlags
(testCommonFlags
. savedTestFlags
)
643 , testHumanLog
= combine testHumanLog
644 , testMachineLog
= combine testMachineLog
645 , testShowDetails
= combine testShowDetails
646 , testKeepTix
= combine testKeepTix
647 , testWrapper
= combine testWrapper
648 , testFailWhenNoTestSuites
= combine testFailWhenNoTestSuites
649 , testOptions
= lastNonEmpty testOptions
652 combine
= combine
' savedTestFlags
653 lastNonEmpty
= lastNonEmpty
' savedTestFlags
655 combinedSavedBenchmarkFlags
=
657 { benchmarkCommonFlags
= combinedSavedCommonFlags
(benchmarkCommonFlags
. savedBenchmarkFlags
)
658 , benchmarkOptions
= lastNonEmpty benchmarkOptions
661 lastNonEmpty
= lastNonEmpty
' savedBenchmarkFlags
663 combinedSavedReplMulti
= combine
' savedReplMulti
id
665 combinedSavedProjectFlags
=
667 { flagProjectDir
= combine flagProjectDir
668 , flagProjectFile
= combine flagProjectFile
669 , flagIgnoreProject
= combine flagIgnoreProject
672 combine
= combine
' savedProjectFlags
680 -- | These are the absolute basic defaults. The fields that must be
681 -- initialised. When we load the config from the file we layer the loaded
682 -- values over these ones, so any missing fields in the file take their values
684 baseSavedConfig
:: IO SavedConfig
686 userPrefix
<- defaultInstallPrefix
687 cacheDir
<- defaultCacheDir
688 logsDir
<- defaultLogsDir
691 { savedConfigureFlags
=
693 { configHcFlavor
= toFlag defaultCompiler
694 , configUserInstall
= toFlag defaultUserInstall
695 , configCommonFlags
=
697 { setupVerbosity
= toFlag normal
700 , savedUserInstallDirs
=
702 { prefix
= toFlag
(toPathTemplate userPrefix
)
706 { globalCacheDir
= toFlag cacheDir
707 , globalLogsDir
= toFlag logsDir
711 -- | This is the initial configuration that we write out to the config file
712 -- if the file does not exist (or the config we use if the file cannot be read
713 -- for some other reason). When the config gets loaded it gets layered on top
714 -- of 'baseSavedConfig' so we do not need to include it into the initial
715 -- values we save into the config file.
716 initialSavedConfig
:: IO SavedConfig
717 initialSavedConfig
= do
718 cacheDir
<- defaultCacheDir
719 logsDir
<- defaultLogsDir
720 installPath
<- defaultInstallPath
725 { globalCacheDir
= toFlag cacheDir
726 , globalRemoteRepos
= toNubList
[defaultRemoteRepo
]
728 , savedInstallFlags
=
730 { installSummaryFile
= toNubList
[toPathTemplate
(logsDir
</> "build.log")]
731 , installBuildReports
= toFlag NoReports
732 , installNumJobs
= toFlag Nothing
734 , savedClientInstallFlags
=
736 { cinstInstalldir
= toFlag installPath
740 -- | Issue a warning if both @$XDG_CONFIG_HOME/cabal/config@ and
741 -- @~/.cabal@ exists.
742 warnOnTwoConfigs
:: Verbosity
-> IO ()
743 warnOnTwoConfigs verbosity
= do
744 defaultDir
<- getAppUserDataDirectory
"cabal"
745 xdgCfgDir
<- getXdgDirectory XdgConfig
"cabal"
746 when (defaultDir
/= xdgCfgDir
) $ do
747 dotCabalExists
<- doesDirectoryExist defaultDir
748 let xdgCfg
= xdgCfgDir
</> "config"
749 xdgCfgExists
<- doesFileExist xdgCfg
750 when (dotCabalExists
&& xdgCfgExists
) $
756 <> " exist - ignoring the former.\n"
757 <> "It is advisable to remove one of them. In that case, we will use the remaining one by default (unless '$CABAL_DIR' is explicitly set)."
759 -- | If @CABAL\_DIR@ is set, return @Just@ its value. Otherwise, if
760 -- @~/.cabal@ exists and @$XDG_CONFIG_HOME/cabal/config@ does not
761 -- exist, return @Just "~/.cabal"@. Otherwise, return @Nothing@. If
762 -- this function returns Nothing, then it implies that we are not
763 -- using a single directory for everything, but instead use XDG paths.
764 -- Fundamentally, this function is used to implement transparent
765 -- backwards compatibility with pre-XDG versions of cabal-install.
766 maybeGetCabalDir
:: IO (Maybe FilePath)
767 maybeGetCabalDir
= do
768 mDir
<- lookupEnv
"CABAL_DIR"
770 Just dir
-> return $ Just dir
772 defaultDir
<- getAppUserDataDirectory
"cabal"
773 dotCabalExists
<- doesDirectoryExist defaultDir
774 xdgCfg
<- getXdgDirectory XdgConfig
("cabal" </> "config")
775 xdgCfgExists
<- doesFileExist xdgCfg
776 if dotCabalExists
&& not xdgCfgExists
777 then return $ Just defaultDir
780 -- | The default behaviour of cabal-install is to use the XDG
781 -- directory standard. However, if @CABAL_DIR@ is set, we instead use
782 -- that directory as a single store for everything cabal-related, like
783 -- the old @~/.cabal@ behaviour. Also, for backwards compatibility,
784 -- if @~/.cabal@ exists we treat that as equivalent to @CABAL_DIR@
785 -- being set. This function abstracts that decision-making.
786 getDefaultDir
:: XdgDirectory
-> FilePath -> IO FilePath
787 getDefaultDir xdg subdir
= do
788 mDir
<- maybeGetCabalDir
790 Just dir
-> return $ dir
</> subdir
791 Nothing
-> getXdgDirectory xdg
$ "cabal" </> subdir
793 -- | The default prefix used for installation.
794 defaultInstallPrefix
:: IO FilePath
795 defaultInstallPrefix
= do
796 mDir
<- maybeGetCabalDir
801 dir
<- getHomeDirectory
802 return $ dir
</> ".local"
804 defaultConfigFile
:: IO FilePath
806 getDefaultDir XdgConfig
"config"
808 defaultCacheHome
:: IO FilePath
810 getDefaultDir XdgCache
""
812 defaultCacheDir
:: IO FilePath
814 getDefaultDir XdgCache
"packages"
816 defaultScriptBuildsDir
:: IO FilePath
817 defaultScriptBuildsDir
=
818 getDefaultDir XdgCache
"script-builds"
820 defaultStoreDir
:: IO FilePath
822 getDefaultDir XdgState
"store"
824 defaultLogsDir
:: IO FilePath
826 getDefaultDir XdgCache
"logs"
828 defaultReportsDir
:: IO FilePath
830 getDefaultDir XdgCache
"reports"
832 defaultInstallPath
:: IO FilePath
833 defaultInstallPath
= do
834 mDir
<- maybeGetCabalDir
837 return $ dir
</> "bin"
839 dir
<- getHomeDirectory
840 return $ dir
</> ".local" </> "bin"
842 defaultCompiler
:: CompilerFlavor
843 defaultCompiler
= fromMaybe GHC defaultCompilerFlavor
845 defaultUserInstall
:: Bool
846 defaultUserInstall
= True
848 -- We do per-user installs by default on all platforms. We used to default to
849 -- global installs on Windows but that no longer works on Windows Vista or 7.
851 defaultRemoteRepo
:: RemoteRepo
852 defaultRemoteRepo
= RemoteRepo name uri Nothing
[] 0 False
854 str
= "hackage.haskell.org"
856 uri
= URI
"http:" (Just
(URIAuth
"" str
"")) "/" "" ""
858 -- Note that lots of old config files will have the old url
859 -- http://hackage.haskell.org/packages/archive
860 -- but new config files can use the new url (without the /packages/archive)
861 -- and avoid having to do a http redirect
863 -- For the default repo we know extra information, fill this in.
865 -- We need this because the 'defaultRemoteRepo' above is only used for the
866 -- first time when a config file is made. So for users with older config files
867 -- we might have only have older info. This lets us fill that in even for old
870 addInfoForKnownRepos
:: RemoteRepo
-> RemoteRepo
871 addInfoForKnownRepos repo
872 | remoteRepoName repo
== remoteRepoName defaultRemoteRepo
=
873 useSecure
. tryHttps
. fixOldURI
$ repo
876 | isOldHackageURI
(remoteRepoURI r
) =
877 r
{remoteRepoURI
= remoteRepoURI defaultRemoteRepo
}
880 tryHttps r
= r
{remoteRepoShouldTryHttps
= True}
884 { remoteRepoSecure
= secure
885 , remoteRepoRootKeys
= []
886 , remoteRepoKeyThreshold
= 0
888 | secure
/= Just
False =
890 { -- Use hackage-security by default unless you opt-out with
892 remoteRepoSecure
= Just
True
893 , remoteRepoRootKeys
= defaultHackageRemoteRepoKeys
894 , remoteRepoKeyThreshold
= defaultHackageRemoteRepoKeyThreshold
897 addInfoForKnownRepos other
= other
899 -- | The current hackage.haskell.org repo root keys that we ship with cabal.
902 -- This lets us bootstrap trust in this repo without user intervention.
903 -- These keys need to be periodically updated when new root keys are added.
904 -- See the root key procedures for details.
906 defaultHackageRemoteRepoKeys
:: [String]
907 defaultHackageRemoteRepoKeys
=
908 -- Key owners and public keys are provided as a convenience to readers.
909 -- The canonical source for this mapping data is the hackage-root-keys
910 -- repository and Hackage's root.json file.
913 -- * https://github.com/haskell-infra/hackage-root-keys
914 -- * https://hackage.haskell.org/root.json
915 -- Please consult root.json on Hackage to map key IDs to public keys,
916 -- and the hackage-root-keys repository to map public keys to their
918 [ -- Adam Gundry (uRPdSiL3/MNsk50z6NB55ABo0OrrNDXigtCul4vtzmw=)
919 "fe331502606802feac15e514d9b9ea83fee8b6ffef71335479a2e68d84adc6b0"
920 , -- Gershom Bazerman (bYoUXXQ9TtX10UriaMiQtTccuXPGnmldP68djzZ7cLo=)
921 "1ea9ba32c526d1cc91ab5e5bd364ec5e9e8cb67179a471872f6e26f0ae773d42"
922 , -- John Wiegley (zazm5w480r+zPO6Z0+8fjGuxZtb9pAuoVmQ+VkuCvgU=)
923 "0a5c7ea47cd1b15f01f5f51a33adda7e655bc0f0b0615baa8e271f4c3351e21d"
924 , -- Norman Ramsey (ZI8di3a9Un0s2RBrt5GwVRvfOXVuywADfXGPZfkiDb0=)
925 "51f0161b906011b52c6613376b1ae937670da69322113a246a09f807c62f6921"
926 , -- Mathieu Boespflug (ydN1nGGQ79K1Q0nN+ul+Ln8MxikTB95w0YdGd3v3kmg=)
927 "be75553f3c7ba1dbe298da81f1d1b05c9d39dd8ed2616c9bddf1525ca8c03e48"
928 , -- Joachim Breitner (5iUgwqZCWrCJktqMx0bBMIuoIyT4A1RYGozzchRN9rA=)
929 "d26e46f3b631aae1433b89379a6c68bd417eb5d1c408f0643dcc07757fece522"
932 -- | The required threshold of root key signatures for hackage.haskell.org
933 defaultHackageRemoteRepoKeyThreshold
:: Int
934 defaultHackageRemoteRepoKeyThreshold
= 3
938 -- * Config file reading
942 -- | Loads the main configuration, and applies additional defaults to give the
943 -- effective configuration. To loads just what is actually in the config file,
944 -- use 'loadRawConfig'.
945 loadConfig
:: Verbosity
-> Flag
FilePath -> IO SavedConfig
946 loadConfig verbosity configFileFlag
= do
947 warnOnTwoConfigs verbosity
948 config
<- loadRawConfig verbosity configFileFlag
949 extendToEffectiveConfig config
951 extendToEffectiveConfig
:: SavedConfig
-> IO SavedConfig
952 extendToEffectiveConfig config
= do
953 base
<- baseSavedConfig
954 let effective0
= base `mappend` config
955 globalFlags0
= savedGlobalFlags effective0
960 { globalRemoteRepos
=
962 (map addInfoForKnownRepos
)
963 (globalRemoteRepos globalFlags0
)
968 -- | Like 'loadConfig' but does not apply any additional defaults, it just
969 -- loads what is actually in the config file. This is thus suitable for
970 -- comparing or editing a config file, but not suitable for using as the
971 -- effective configuration.
972 loadRawConfig
:: Verbosity
-> Flag
FilePath -> IO SavedConfig
973 loadRawConfig verbosity configFileFlag
= do
974 (source
, configFile
) <- getConfigFilePathAndSource configFileFlag
975 minp
<- readConfigFile mempty configFile
979 "Config file path source is " ++ sourceMsg source
++ "."
980 -- 2021-10-07, issue #7705
981 -- Only create default config file if name was not given explicitly
982 -- via option --config-file or environment variable.
985 notice verbosity msgNotFound
986 createDefaultConfigFile verbosity
[] configFile
987 CommandlineOption
-> failNoConfigFile
988 EnvironmentVariable
-> failNoConfigFile
991 |
null configFile
= "Config file name is empty"
992 |
otherwise = unwords ["Config file not found:", configFile
]
994 dieWithException verbosity
$ FailNoConfigFile msgNotFound
995 Just
(ParseOk ws conf
) -> do
998 unlines (map (showPWarning configFile
) ws
)
1000 Just
(ParseFailed err
) -> do
1001 let (line
, msg
) = locatedErrorMsg err
1002 errLineNo
= maybe "" (\n -> ':' : show n
) line
1003 dieWithException verbosity
$ ParseFailedErr configFile msg errLineNo
1005 sourceMsg CommandlineOption
= "commandline option"
1006 sourceMsg EnvironmentVariable
= "environment variable CABAL_CONFIG"
1007 sourceMsg Default
= "default config file"
1009 -- | Provenance of the config file.
1010 data ConfigFileSource
1012 | EnvironmentVariable
1015 -- | Returns the config file path, without checking that the file exists.
1016 -- The order of precedence is: input flag, CABAL_CONFIG, default location.
1017 getConfigFilePath
:: Flag
FilePath -> IO FilePath
1018 getConfigFilePath
= fmap snd . getConfigFilePathAndSource
1020 getConfigFilePathAndSource
:: Flag
FilePath -> IO (ConfigFileSource
, FilePath)
1021 getConfigFilePathAndSource configFileFlag
=
1025 [ (CommandlineOption
, return . flagToMaybe
$ configFileFlag
)
1026 , (EnvironmentVariable
, lookup "CABAL_CONFIG" `
liftM` getEnvironment
)
1027 , (Default
, Just `
liftM` defaultConfigFile
)
1030 getSource
[] = error "no config file path candidate found."
1031 getSource
((source
, action
) : xs
) =
1032 action
>>= maybe (getSource xs
) (return . (,) source
)
1035 :: SavedConfig
-> FilePath -> IO (Maybe (ParseResult SavedConfig
))
1036 readConfigFile initial file
=
1039 (Just
. parseConfig
(ConstraintSourceMainConfig file
) initial
)
1042 handleNotExists action
= catchIO action
$ \ioe
->
1043 if isDoesNotExistError ioe
1047 createDefaultConfigFile
:: Verbosity
-> [String] -> FilePath -> IO SavedConfig
1048 createDefaultConfigFile verbosity extraLines filePath
= do
1049 commentConf
<- commentSavedConfig
1050 initialConf
<- initialSavedConfig
1051 extraConf
<- parseExtraLines verbosity extraLines
1052 notice verbosity
$ "Writing default configuration to " ++ filePath
1053 writeConfigFile filePath commentConf
(initialConf `mappend` extraConf
)
1056 writeConfigFile
:: FilePath -> SavedConfig
-> SavedConfig
-> IO ()
1057 writeConfigFile file comments vals
= do
1058 let tmpFile
= file
<.> "tmp"
1059 createDirectoryIfMissing
True (takeDirectory file
)
1061 explanation
++ showConfigWithComments comments vals
++ "\n"
1062 renameFile tmpFile file
1066 [ "-- This is the configuration file for the 'cabal' command line tool."
1068 , "-- The available configuration options are listed below."
1069 , "-- Some of them have default values listed."
1071 , "-- Lines (like this one) beginning with '--' are comments."
1072 , "-- Be careful with spaces and indentation because they are"
1073 , "-- used to indicate layout for nested sections."
1075 , "-- This config file was generated using the following versions"
1076 , "-- of Cabal and cabal-install:"
1077 , "-- Cabal library version: " ++ prettyShow cabalVersion
1078 , "-- cabal-install version: " ++ prettyShow cabalInstallVersion
1083 -- | These are the default values that get used in Cabal if a no value is
1084 -- given. We use these here to include in comments when we write out the
1085 -- initial config file so that the user can see what default value they are
1087 commentSavedConfig
:: IO SavedConfig
1088 commentSavedConfig
= do
1089 userInstallDirs
<- defaultInstallDirs defaultCompiler
True True
1090 globalInstallDirs
<- defaultInstallDirs defaultCompiler
False True
1093 { savedGlobalFlags
=
1095 { globalRemoteRepos
= toNubList
[defaultRemoteRepo
]
1096 , globalNix
= mempty
1100 { IT
.interactive
= toFlag
False
1101 , IT
.cabalVersion
= toFlag IT
.defaultCabalVersion
1102 , IT
.language
= toFlag Haskell2010
1103 , IT
.license
= NoFlag
1104 , IT
.sourceDirs
= Flag
[IT
.defaultSourceDir
]
1105 , IT
.applicationDirs
= Flag
[IT
.defaultApplicationDir
]
1106 , IT
.quiet
= Flag
False
1107 , IT
.noComments
= Flag
False
1108 , IT
.minimal
= Flag
False
1109 , IT
.simpleProject
= Flag
False
1111 , savedInstallFlags
= defaultInstallFlags
1112 , savedClientInstallFlags
= defaultClientInstallFlags
1113 , savedConfigureExFlags
=
1114 defaultConfigExFlags
1115 { configAllowNewer
= Just
(AllowNewer mempty
)
1116 , configAllowOlder
= Just
(AllowOlder mempty
)
1118 , savedConfigureFlags
=
1119 (defaultConfigFlags defaultProgramDb
)
1120 { configUserInstall
= toFlag defaultUserInstall
1122 , savedUserInstallDirs
= fmap toFlag userInstallDirs
1123 , savedGlobalInstallDirs
= fmap toFlag globalInstallDirs
1124 , savedUploadFlags
= commandDefaultFlags uploadCommand
1125 , savedReportFlags
= commandDefaultFlags reportCommand
1126 , savedHaddockFlags
= defaultHaddockFlags
1127 , savedTestFlags
= defaultTestFlags
1128 , savedBenchmarkFlags
= defaultBenchmarkFlags
1130 conf1
<- extendToEffectiveConfig conf0
1131 let globalFlagsConf1
= savedGlobalFlags conf1
1134 { savedGlobalFlags
=
1136 { globalRemoteRepos
=
1138 (map removeRootKeys
)
1139 (globalRemoteRepos globalFlagsConf1
)
1144 -- Most people don't want to see default root keys, so don't print them.
1145 removeRootKeys
:: RemoteRepo
-> RemoteRepo
1146 removeRootKeys r
= r
{remoteRepoRootKeys
= []}
1148 -- | All config file fields.
1149 configFieldDescriptions
:: ConstraintSource
-> [FieldDescr SavedConfig
]
1150 configFieldDescriptions src
=
1153 (commandOptions
(globalCommand
[]) ParseArgs
)
1154 ["version", "numeric-version", "config-file"]
1158 (configureOptions ParseArgs
)
1159 ( ["builddir", "constraint", "dependency", "promised-dependency", "ipid"]
1160 ++ map fieldName installDirsFields
1162 -- This is only here because viewAsFieldDescr gives us a parser
1163 -- that only recognises 'ghc' etc, the case-sensitive flag names, not
1164 -- what the normal case-insensitive parser gives us.
1167 (fromFlagOrDefault Disp
.empty . fmap pretty
)
1168 (Flag
<$> parsec
<|
> pure NoFlag
)
1170 (\v flags
-> flags
{configHcFlavor
= v
})
1171 , -- TODO: The following is a temporary fix. The "optimization"
1172 -- and "debug-info" fields are OptArg, and viewAsFieldDescr
1173 -- fails on that. Instead of a hand-written hackaged parser
1174 -- and printer, we should handle this case properly in the
1179 flags
{configOptimization
= v
}
1181 $ let name
= "optimization"
1185 Flag NoOptimisation
-> Disp
.text
"False"
1186 Flag NormalOptimisation
-> Disp
.text
"True"
1187 Flag MaximumOptimisation
-> Disp
.text
"2"
1190 ( \line str _
-> case () of
1192 | str
== "False" -> ParseOk
[] (Flag NoOptimisation
)
1193 | str
== "True" -> ParseOk
[] (Flag NormalOptimisation
)
1194 | str
== "0" -> ParseOk
[] (Flag NoOptimisation
)
1195 | str
== "1" -> ParseOk
[] (Flag NormalOptimisation
)
1196 | str
== "2" -> ParseOk
[] (Flag MaximumOptimisation
)
1197 | lstr
== "false" -> ParseOk
[caseWarning
] (Flag NoOptimisation
)
1201 (Flag NormalOptimisation
)
1202 |
otherwise -> ParseFailed
(NoParse name line
)
1204 lstr
= lowercase str
1209 ++ "' field is case sensitive, use 'True' or 'False'."
1211 , liftField configDebugInfo
(\v flags
-> flags
{configDebugInfo
= v
}) $
1212 let name
= "debug-info"
1216 Flag NoDebugInfo
-> Disp
.text
"False"
1217 Flag MinimalDebugInfo
-> Disp
.text
"1"
1218 Flag NormalDebugInfo
-> Disp
.text
"True"
1219 Flag MaximalDebugInfo
-> Disp
.text
"3"
1222 ( \line str _
-> case () of
1224 | str
== "False" -> ParseOk
[] (Flag NoDebugInfo
)
1225 | str
== "True" -> ParseOk
[] (Flag NormalDebugInfo
)
1226 | str
== "0" -> ParseOk
[] (Flag NoDebugInfo
)
1227 | str
== "1" -> ParseOk
[] (Flag MinimalDebugInfo
)
1228 | str
== "2" -> ParseOk
[] (Flag NormalDebugInfo
)
1229 | str
== "3" -> ParseOk
[] (Flag MaximalDebugInfo
)
1230 | lstr
== "false" -> ParseOk
[caseWarning
] (Flag NoDebugInfo
)
1231 | lstr
== "true" -> ParseOk
[caseWarning
] (Flag NormalDebugInfo
)
1232 |
otherwise -> ParseFailed
(NoParse name line
)
1234 lstr
= lowercase str
1239 ++ "' field is case sensitive, use 'True' or 'False'."
1244 (configureExOptions ParseArgs src
)
1247 (Just
. AllowOlder
. RelaxDepsSome
)
1248 `
fmap` parsecOptCommaList parsec
1250 ( (Just
. AllowOlder
. toRelaxDeps
)
1254 in simpleFieldParsec
1256 (showRelaxDeps
. fmap unAllowOlder
)
1259 (\v flags
-> flags
{configAllowOlder
= v
})
1261 (Just
. AllowNewer
. RelaxDepsSome
)
1262 `
fmap` parsecOptCommaList parsec
1264 ( (Just
. AllowNewer
. toRelaxDeps
)
1268 in simpleFieldParsec
1270 (showRelaxDeps
. fmap unAllowNewer
)
1273 (\v flags
-> flags
{configAllowNewer
= v
})
1277 (installOptions ParseArgs
)
1278 ["dry-run", "only", "only-dependencies", "dependencies-only"]
1281 liftClientInstallFlag
1282 (clientInstallOptions ParseArgs
)
1287 (commandOptions uploadCommand ParseArgs
)
1288 ["verbose", "check", "documentation", "publish"]
1292 (commandOptions reportCommand ParseArgs
)
1293 ["verbose", "token", "username", "password"]
1295 -- FIXME: this is a hack, hiding the user name and password.
1296 -- But otherwise it masks the upload ones. Either need to
1297 -- share the options or make then distinct. In any case
1298 -- they should probably be per-server.
1305 ++ [ viewAsFieldDescr
$
1307 (setupDistPref
. configCommonFlags
. savedConfigureFlags
)
1309 updSavedCommonSetupFlags
(\common
-> common
{setupDistPref
= distPref
})
1314 toSavedConfig lift options exclusions replacements
=
1315 [ lift
(fromMaybe field replacement
)
1317 , let field
= viewAsFieldDescr opt
1318 name
= fieldName field
1319 replacement
= find ((== name
) . fieldName
) replacements
1320 , name `
notElem` exclusions
1323 showRelaxDeps Nothing
= mempty
1324 showRelaxDeps
(Just rd
)
1325 | isRelaxDeps rd
= Disp
.text
"True"
1326 |
otherwise = Disp
.text
"False"
1328 toRelaxDeps
True = RelaxDepsAll
1329 toRelaxDeps
False = mempty
1331 updSavedCommonSetupFlags
1332 :: (CommonSetupFlags
-> CommonSetupFlags
)
1335 updSavedCommonSetupFlags setFlag config
=
1337 { savedConfigureFlags
=
1338 let flags
= savedConfigureFlags config
1339 common
= configCommonFlags flags
1340 in flags
{configCommonFlags
= setFlag common
}
1341 , savedHaddockFlags
=
1342 let flags
= savedHaddockFlags config
1343 common
= haddockCommonFlags flags
1344 in flags
{haddockCommonFlags
= setFlag common
}
1346 let flags
= savedTestFlags config
1347 common
= testCommonFlags flags
1348 in flags
{testCommonFlags
= setFlag common
}
1349 , savedBenchmarkFlags
=
1350 let flags
= savedBenchmarkFlags config
1351 common
= benchmarkCommonFlags flags
1352 in flags
{benchmarkCommonFlags
= setFlag common
}
1355 -- TODO: next step, make the deprecated fields elicit a warning.
1357 deprecatedFieldDescriptions
:: [FieldDescr SavedConfig
]
1358 deprecatedFieldDescriptions
=
1364 (fromNubList
. globalRemoteRepos
)
1365 (\rs cfg
-> cfg
{globalRemoteRepos
= toNubList rs
})
1369 (Disp
.text
. fromFlagOrDefault
"")
1370 (optionalFlag parsecFilePath
)
1372 (\d cfg
-> cfg
{globalCacheDir
= d
})
1376 (Disp
.text
. fromFlagOrDefault
"" . fmap unToken
)
1377 (optionalFlag
(fmap Token parsecToken
))
1379 (\d cfg
-> cfg
{uploadToken
= d
})
1383 (Disp
.text
. fromFlagOrDefault
"" . fmap unUsername
)
1384 (optionalFlag
(fmap Username parsecToken
))
1386 (\d cfg
-> cfg
{uploadUsername
= d
})
1390 (Disp
.text
. fromFlagOrDefault
"" . fmap unPassword
)
1391 (optionalFlag
(fmap Password parsecToken
))
1393 (\d cfg
-> cfg
{uploadPassword
= d
})
1396 "hackage-password-command"
1399 (fromFlagOrDefault
[] . uploadPasswordCmd
)
1400 (\d cfg
-> cfg
{uploadPasswordCmd
= Flag d
})
1403 (modifyFieldName
("user-" ++) . liftUserInstallDirs
)
1406 (modifyFieldName
("global-" ++) . liftGlobalInstallDirs
)
1409 optionalFlag
:: ParsecParser a
-> ParsecParser
(Flag a
)
1410 optionalFlag p
= toFlag
<$> p
<|
> pure mempty
1412 modifyFieldName
:: (String -> String) -> FieldDescr a
-> FieldDescr a
1413 modifyFieldName f d
= d
{fieldName
= f
(fieldName d
)}
1416 :: FieldDescr
(InstallDirs
(Flag PathTemplate
))
1417 -> FieldDescr SavedConfig
1418 liftUserInstallDirs
=
1420 savedUserInstallDirs
1421 (\flags conf
-> conf
{savedUserInstallDirs
= flags
})
1423 liftGlobalInstallDirs
1424 :: FieldDescr
(InstallDirs
(Flag PathTemplate
))
1425 -> FieldDescr SavedConfig
1426 liftGlobalInstallDirs
=
1428 savedGlobalInstallDirs
1429 (\flags conf
-> conf
{savedGlobalInstallDirs
= flags
})
1431 liftGlobalFlag
:: FieldDescr GlobalFlags
-> FieldDescr SavedConfig
1435 (\flags conf
-> conf
{savedGlobalFlags
= flags
})
1437 liftConfigFlag
:: FieldDescr ConfigFlags
-> FieldDescr SavedConfig
1441 (\flags conf
-> conf
{savedConfigureFlags
= flags
})
1443 liftConfigExFlag
:: FieldDescr ConfigExFlags
-> FieldDescr SavedConfig
1446 savedConfigureExFlags
1447 (\flags conf
-> conf
{savedConfigureExFlags
= flags
})
1449 liftInstallFlag
:: FieldDescr InstallFlags
-> FieldDescr SavedConfig
1453 (\flags conf
-> conf
{savedInstallFlags
= flags
})
1455 liftClientInstallFlag
:: FieldDescr ClientInstallFlags
-> FieldDescr SavedConfig
1456 liftClientInstallFlag
=
1458 savedClientInstallFlags
1459 (\flags conf
-> conf
{savedClientInstallFlags
= flags
})
1461 liftUploadFlag
:: FieldDescr UploadFlags
-> FieldDescr SavedConfig
1465 (\flags conf
-> conf
{savedUploadFlags
= flags
})
1467 liftReportFlag
:: FieldDescr ReportFlags
-> FieldDescr SavedConfig
1471 (\flags conf
-> conf
{savedReportFlags
= flags
})
1473 liftReplFlag
:: FieldDescr
(Flag
Bool) -> FieldDescr SavedConfig
1477 (\flags conf
-> conf
{savedReplMulti
= flags
})
1483 -> ParseResult SavedConfig
1484 parseConfig src initial
= \str
-> do
1485 fields
<- readFields str
1486 let (knownSections
, others
) = partition isKnownSection fields
1487 config
<- parse others
1488 let init0
= savedInitFlags config
1489 user0
= savedUserInstallDirs config
1490 global0
= savedGlobalInstallDirs config
1491 (remoteRepoSections0
, localRepoSections0
, haddockFlags
, initFlags
, user
, global
, paths
, args
) <-
1494 ([], [], savedHaddockFlags config
, init0
, user0
, global0
, [], [])
1497 let remoteRepoSections
=
1499 . nubBy ((==) `on` remoteRepoName
)
1500 $ remoteRepoSections0
1502 let localRepoSections
=
1504 . nubBy ((==) `on` localRepoName
)
1505 $ localRepoSections0
1507 return . fixConfigMultilines
$
1509 { savedGlobalFlags
=
1510 (savedGlobalFlags config
)
1511 { globalRemoteRepos
= toNubList remoteRepoSections
1512 , globalLocalNoIndexRepos
= toNubList localRepoSections
1513 , -- the global extra prog path comes from the configure flag prog path
1514 globalProgPathExtra
= configProgramPathExtra
(savedConfigureFlags config
)
1516 , savedConfigureFlags
=
1517 (savedConfigureFlags config
)
1518 { configProgramPaths
= paths
1519 , configProgramArgs
= args
1521 , savedHaddockFlags
= haddockFlags
1522 , savedInitFlags
= initFlags
1523 , savedUserInstallDirs
= user
1524 , savedGlobalInstallDirs
= global
1527 isKnownSection
(ParseUtils
.Section _
"repository" _ _
) = True
1528 isKnownSection
(ParseUtils
.F _
"remote-repo" _
) = True
1529 isKnownSection
(ParseUtils
.Section _
"haddock" _ _
) = True
1530 isKnownSection
(ParseUtils
.Section _
"init" _ _
) = True
1531 isKnownSection
(ParseUtils
.Section _
"install-dirs" _ _
) = True
1532 isKnownSection
(ParseUtils
.Section _
"program-locations" _ _
) = True
1533 isKnownSection
(ParseUtils
.Section _
"program-default-options" _ _
) = True
1534 isKnownSection _
= False
1536 -- Attempt to split fields that can represent lists of paths into
1537 -- actual lists on failure, leave the field untouched.
1538 splitMultiPath
:: [String] -> [String]
1539 splitMultiPath
[s
] = case runP
0 "" (parseOptCommaList parseTokenQ
) s
of
1540 ParseOk _ res
-> res
1542 splitMultiPath xs
= xs
1545 map unsafeMakeSymbolicPath
. splitMultiPath
. map getSymbolicPath
1547 -- This is a fixup, pending a full config parser rewrite, to
1548 -- ensure that config fields which can be comma-separated lists
1549 -- actually parse as comma-separated lists.
1550 fixConfigMultilines conf
=
1552 { savedConfigureFlags
=
1553 let scf
= savedConfigureFlags conf
1555 { configProgramPathExtra
=
1558 (fromNubList
$ configProgramPathExtra scf
)
1559 , configExtraLibDirs
=
1561 (configExtraLibDirs scf
)
1562 , configExtraLibDirsStatic
=
1564 (configExtraLibDirsStatic scf
)
1565 , configExtraFrameworkDirs
=
1567 (configExtraFrameworkDirs scf
)
1568 , configExtraIncludeDirs
=
1570 (configExtraIncludeDirs scf
)
1571 , configConfigureArgs
=
1573 (configConfigureArgs scf
)
1575 , savedGlobalFlags
=
1576 let sgf
= savedGlobalFlags conf
1578 { globalProgPathExtra
=
1581 (fromNubList
$ globalProgPathExtra sgf
)
1587 ( configFieldDescriptions src
1588 ++ deprecatedFieldDescriptions
1593 (rs
, ls
, h
, i
, u
, g
, p
, a
)
1594 (ParseUtils
.Section lineno
"repository" name fs
) = do
1596 maybe (ParseFailed
$ NoParse
"repository name" lineno
) return $
1598 r
' <- parseFields remoteRepoFields
(emptyRemoteRepo name
') fs
1599 r
'' <- postProcessRepo lineno name r
'
1601 Left local
-> return (rs
, local
: ls
, h
, i
, u
, g
, p
, a
)
1602 Right remote
-> return (remote
: rs
, ls
, h
, i
, u
, g
, p
, a
)
1604 (rs
, ls
, h
, i
, u
, g
, p
, a
)
1605 (ParseUtils
.F lno
"remote-repo" raw
) = do
1606 let mr
' = simpleParsec raw
1607 r
' <- maybe (ParseFailed
$ NoParse
"remote-repo" lno
) return mr
'
1608 return (r
' : rs
, ls
, h
, i
, u
, g
, p
, a
)
1610 accum@(rs
, ls
, h
, i
, u
, g
, p
, a
)
1611 (ParseUtils
.Section _
"haddock" name fs
)
1613 h
' <- parseFields haddockFlagsFields h fs
1614 return (rs
, ls
, h
', i
, u
, g
, p
, a
)
1616 warning
"The 'haddock' section should be unnamed"
1619 accum@(rs
, ls
, h
, i
, u
, g
, p
, a
)
1620 (ParseUtils
.Section _
"init" name fs
)
1622 i
' <- parseFields initFlagsFields i fs
1623 return (rs
, ls
, h
, i
', u
, g
, p
, a
)
1625 warning
"The 'init' section should be unnamed"
1628 accum@(rs
, ls
, h
, i
, u
, g
, p
, a
)
1629 (ParseUtils
.Section _
"install-dirs" name fs
)
1630 | name
' == "user" = do
1631 u
' <- parseFields installDirsFields u fs
1632 return (rs
, ls
, h
, i
, u
', g
, p
, a
)
1633 | name
' == "global" = do
1634 g
' <- parseFields installDirsFields g fs
1635 return (rs
, ls
, h
, i
, u
, g
', p
, a
)
1637 warning
"The 'install-paths' section should be for 'user' or 'global'"
1640 name
' = lowercase name
1642 accum@(rs
, ls
, h
, i
, u
, g
, p
, a
)
1643 (ParseUtils
.Section _
"program-locations" name fs
)
1645 p
' <- parseFields withProgramsFields p fs
1646 return (rs
, ls
, h
, i
, u
, g
, p
', a
)
1648 warning
"The 'program-locations' section should be unnamed"
1651 accum@(rs
, ls
, h
, i
, u
, g
, p
, a
)
1652 (ParseUtils
.Section _
"program-default-options" name fs
)
1654 a
' <- parseFields withProgramOptionsFields a fs
1655 return (rs
, ls
, h
, i
, u
, g
, p
, a
')
1657 warning
"The 'program-default-options' section should be unnamed"
1659 parseSections
accum f
= do
1660 warning
$ "Unrecognized stanza on line " ++ show (lineNo f
)
1663 postProcessRepo
:: Int -> String -> RemoteRepo
-> ParseResult
(Either LocalRepo RemoteRepo
)
1664 postProcessRepo lineno reponameStr repo0
= do
1665 when (null reponameStr
) $
1666 syntaxError lineno
$
1667 "a 'repository' section requires the "
1668 ++ "repository name as an argument"
1671 maybe (fail $ "Invalid repository name " ++ reponameStr
) return $
1672 simpleParsec reponameStr
1674 case uriScheme
(remoteRepoURI repo0
) of
1675 -- TODO: check that there are no authority, query or fragment
1676 -- Note: the trailing colon is important
1677 "file+noindex:" -> do
1678 let uri
= remoteRepoURI repo0
1679 return $ Left
$ LocalRepo reponame
(uriPath uri
) (uriFragment uri
== "#shared-cache")
1681 let repo
= repo0
{remoteRepoName
= reponame
}
1683 when (remoteRepoKeyThreshold repo
> length (remoteRepoRootKeys repo
)) $
1685 "'key-threshold' for repository "
1686 ++ show (remoteRepoName repo
)
1687 ++ " higher than number of keys"
1689 when (not (null (remoteRepoRootKeys repo
)) && remoteRepoSecure repo
/= Just
True) $
1691 "'root-keys' for repository "
1692 ++ show (remoteRepoName repo
)
1693 ++ " non-empty, but 'secure' not set to True."
1697 showConfig
:: SavedConfig
-> String
1698 showConfig
= showConfigWithComments mempty
1700 showConfigWithComments
:: SavedConfig
-> SavedConfig
-> String
1701 showConfigWithComments comment vals
=
1704 (uncurry ppRemoteRepoSection
)
1705 (zip (getRemoteRepos comment
) (getRemoteRepos vals
)) of
1707 (x
: xs
) -> foldl' (\r r
' -> r
$+$ Disp
.text
"" $+$ r
') x xs
1710 (skipSomeFields
(configFieldDescriptions ConstraintSourceUnknown
))
1718 (fmap savedHaddockFlags mcomment
)
1719 (savedHaddockFlags vals
)
1725 (fmap savedInitFlags mcomment
)
1726 (savedInitFlags vals
)
1728 $+$ installDirsSection
"user" savedUserInstallDirs
1730 $+$ installDirsSection
"global" savedGlobalInstallDirs
1732 $+$ configFlagsSection
1737 $+$ configFlagsSection
1738 "program-default-options"
1739 withProgramOptionsFields
1742 getRemoteRepos
= fromNubList
. globalRemoteRepos
. savedGlobalFlags
1743 mcomment
= Just comment
1744 installDirsSection name field
=
1749 (fmap field mcomment
)
1751 configFlagsSection name fields field
=
1756 (fmap (field
. savedConfigureFlags
) mcomment
)
1757 ((field
. savedConfigureFlags
) vals
)
1759 -- skip fields based on field name. currently only skips "remote-repo",
1760 -- because that is rendered as a section. (see 'ppRemoteRepoSection'.)
1761 skipSomeFields
= filter ((/= "remote-repo") . fieldName
)
1763 -- | Fields for the 'install-dirs' sections.
1764 installDirsFields
:: [FieldDescr
(InstallDirs
(Flag PathTemplate
))]
1765 installDirsFields
= map viewAsFieldDescr installDirsOptions
1767 ppRemoteRepoSection
:: RemoteRepo
-> RemoteRepo
-> Doc
1768 ppRemoteRepoSection def vals
=
1771 (unRepoName
(remoteRepoName vals
))
1776 remoteRepoFields
:: [FieldDescr RemoteRepo
]
1781 (parseTokenQ
>>= parseURI
')
1783 (\x repo
-> repo
{remoteRepoURI
= x
})
1787 (Just `
fmap` parsec
)
1789 (\x repo
-> repo
{remoteRepoSecure
= x
})
1795 (\x repo
-> repo
{remoteRepoRootKeys
= x
})
1800 remoteRepoKeyThreshold
1801 (\x repo
-> repo
{remoteRepoKeyThreshold
= x
})
1804 parseURI
' uriString
=
1805 case parseURI uriString
of
1806 Nothing
-> fail $ "remote-repo: no parse on " ++ show uriString
1807 Just uri
-> return uri
1809 showSecure Nothing
= mempty
-- default 'secure' setting
1810 showSecure
(Just
True) = text
"True" -- user explicitly enabled it
1811 showSecure
(Just
False) = text
"False" -- user explicitly disabled it
1813 -- If the key-threshold is set to 0, we omit it as this is the default
1814 -- and it looks odd to have a value for key-threshold but not for 'secure'
1815 -- (note that an empty list of keys is already omitted by default, since
1816 -- that is what we do for all list fields)
1817 showThreshold
0 = mempty
1818 showThreshold t
= text
(show t
)
1820 -- | Fields for the 'haddock' section.
1821 haddockFlagsFields
:: [FieldDescr HaddockFlags
]
1822 haddockFlagsFields
=
1824 | opt
<- haddockOptions ParseArgs
1825 , let field
= viewAsFieldDescr opt
1826 name
= fieldName field
1827 , name `
notElem` exclusions
1830 exclusions
= ["verbose", "builddir", "for-hackage"]
1832 -- | Fields for the 'init' section.
1833 initFlagsFields
:: [FieldDescr IT
.InitFlags
]
1836 | opt
<- initOptions ParseArgs
1837 , let field
= viewAsFieldDescr opt
1838 name
= fieldName field
1839 , name `
notElem` exclusions
1853 , "extra-source-file"
1867 -- | Fields for the 'program-locations' section.
1868 withProgramsFields
:: [FieldDescr
[(String, FilePath)]]
1869 withProgramsFields
=
1870 map viewAsFieldDescr
$
1878 -- | Fields for the 'program-default-options' section.
1879 withProgramOptionsFields
:: [FieldDescr
[(String, [String])]]
1880 withProgramOptionsFields
=
1881 map viewAsFieldDescr
$
1882 programDbOptions defaultProgramDb ParseArgs
id (++)
1884 parseExtraLines
:: Verbosity
-> [String] -> IO SavedConfig
1885 parseExtraLines verbosity extraLines
=
1887 (ConstraintSourceMainConfig
"additional lines")
1889 (toUTF8BS
(unlines extraLines
)) of
1891 let (line
, msg
) = locatedErrorMsg err
1892 errLineNo
= maybe "" (\n -> ':' : show n
) line
1893 in dieWithException verbosity
$ ParseExtraLinesFailedErr msg errLineNo
1894 ParseOk
[] r
-> return r
1896 dieWithException verbosity
$ ParseExtraLinesOkError ws
1898 -- | Get the differences (as a pseudo code diff) between the user's
1899 -- config file and the one that cabal would generate if it didn't exist.
1900 userConfigDiff
:: Verbosity
-> GlobalFlags
-> [String] -> IO [String]
1901 userConfigDiff verbosity globalFlags extraLines
= do
1902 userConfig
<- loadRawConfig normal
(globalConfigFile globalFlags
)
1903 extraConfig
<- parseExtraLines verbosity extraLines
1904 testConfig
<- initialSavedConfig
1906 reverse . foldl' createDiff
[] . M
.toList
$
1909 (M
.fromList
. map justFst
$ filterShow testConfig
)
1910 (M
.fromList
. map justSnd
$ filterShow
(userConfig `mappend` extraConfig
))
1912 justFst
(a
, b
) = (a
, (Just b
, Nothing
))
1913 justSnd
(a
, b
) = (a
, (Nothing
, Just b
))
1915 combine
(Nothing
, Just b
) (Just a
, Nothing
) = (Just a
, Just b
)
1916 combine
(Just a
, Nothing
) (Nothing
, Just b
) = (Just a
, Just b
)
1919 "Can't happen : userConfigDiff "
1924 createDiff
:: [String] -> (String, (Maybe String, Maybe String)) -> [String]
1925 createDiff acc
(key
, (Just a
, Just b
))
1928 ("+ " ++ key
++ ": " ++ b
)
1929 : ("- " ++ key
++ ": " ++ a
)
1931 createDiff acc
(key
, (Nothing
, Just b
)) = ("+ " ++ key
++ ": " ++ b
) : acc
1932 createDiff acc
(key
, (Just a
, Nothing
)) = ("- " ++ key
++ ": " ++ a
) : acc
1933 createDiff acc
(_
, (Nothing
, Nothing
)) = acc
1935 filterShow
:: SavedConfig
-> [(String, String)]
1938 . filter (\s
-> not (null s
) && ':' `
elem` s
)
1944 nonComment
('-' : '-' : _
) = []
1945 nonComment
(x
: xs
) = x
: nonComment xs
1947 topAndTail
= reverse . dropWhile isSpace . reverse . dropWhile isSpace
1950 let (left
, right
) = break (== ':') s
1951 in (topAndTail left
, topAndTail
(drop 1 right
))
1953 -- | Update the user's config file keeping the user's customizations.
1954 userConfigUpdate
:: Verbosity
-> GlobalFlags
-> [String] -> IO ()
1955 userConfigUpdate verbosity globalFlags extraLines
= do
1956 userConfig
<- loadRawConfig normal
(globalConfigFile globalFlags
)
1957 extraConfig
<- parseExtraLines verbosity extraLines
1958 newConfig
<- initialSavedConfig
1959 commentConf
<- commentSavedConfig
1960 cabalFile
<- getConfigFilePath
$ globalConfigFile globalFlags
1961 let backup
= cabalFile
++ ".backup"
1962 notice verbosity
$ "Renaming " ++ cabalFile
++ " to " ++ backup
++ "."
1963 renameFile cabalFile backup
1964 notice verbosity
$ "Writing merged config to " ++ cabalFile
++ "."
1968 (newConfig `mappend` userConfig `mappend` extraConfig
)