{-# LANGUAGE DeriveGeneric, DeriveDataTypeable, GeneralizedNewtypeDeriving #-} -- | Handling project configuration, types. -- module Distribution.Client.ProjectConfig.Types ( -- * Types for project config ProjectConfig(..), ProjectConfigBuildOnly(..), ProjectConfigShared(..), ProjectConfigProvenance(..), PackageConfig(..), -- * Resolving configuration SolverSettings(..), BuildTimeSettings(..), -- * Extra useful Monoids MapLast(..), MapMappend(..), ) where import Distribution.Client.Compat.Prelude import Prelude () import Distribution.Client.Types.Repo ( RemoteRepo, LocalRepo ) import Distribution.Client.Types.AllowNewer ( AllowNewer(..), AllowOlder(..) ) import Distribution.Client.Types.WriteGhcEnvironmentFilesPolicy ( WriteGhcEnvironmentFilesPolicy ) import Distribution.Client.Dependency.Types ( PreSolver ) import Distribution.Client.Targets ( UserConstraint ) import Distribution.Client.BuildReports.Types ( ReportLevel(..) ) import Distribution.Client.Types.SourceRepo (SourceRepoList) import Distribution.Client.IndexUtils.IndexState ( TotalIndexState ) import Distribution.Client.IndexUtils.ActiveRepos ( ActiveRepos ) import Distribution.Client.CmdInstall.ClientInstallFlags ( ClientInstallFlags(..) ) import Distribution.Solver.Types.Settings import Distribution.Solver.Types.ConstraintSource import Distribution.Package ( PackageName, PackageId, UnitId ) import Distribution.Types.PackageVersionConstraint ( PackageVersionConstraint ) import Distribution.Version ( Version ) import Distribution.System ( Platform ) import Distribution.PackageDescription ( FlagAssignment ) import Distribution.Simple.Compiler ( Compiler, CompilerFlavor , OptimisationLevel(..), ProfDetailLevel, DebugInfoLevel(..) ) import Distribution.Simple.Setup ( Flag, HaddockTarget(..), TestShowDetails(..) ) import Distribution.Simple.InstallDirs ( PathTemplate ) import Distribution.Utils.NubList ( NubList ) import qualified Data.Map as Map ------------------------------- -- Project config types -- -- | This type corresponds directly to what can be written in the -- @cabal.project@ file. Other sources of configuration can also be injected -- into this type, such as the user-wide @~/.cabal/config@ file and the -- command line of @cabal configure@ or @cabal build@. -- -- Since it corresponds to the external project file it is an instance of -- 'Monoid' and all the fields can be empty. This also means there has to -- be a step where we resolve configuration. At a minimum resolving means -- applying defaults but it can also mean merging information from multiple -- sources. For example for package-specific configuration the project file -- can specify configuration that applies to all local packages, and then -- additional configuration for a specific package. -- -- Future directions: multiple profiles, conditionals. If we add these -- features then the gap between configuration as written in the config file -- and resolved settings we actually use will become even bigger. -- data ProjectConfig = ProjectConfig { -- | Packages in this project, including local dirs, local .cabal files -- local and remote tarballs. When these are file globs, they must -- match at least one package. projectPackages :: [String], -- | Like 'projectConfigPackageGlobs' but /optional/ in the sense that -- file globs are allowed to match nothing. The primary use case for -- this is to be able to say @optional-packages: */@ to automagically -- pick up deps that we unpack locally without erroring when -- there aren't any. projectPackagesOptional :: [String], -- | Packages in this project from remote source repositories. projectPackagesRepo :: [SourceRepoList], -- | Packages in this project from hackage repositories. projectPackagesNamed :: [PackageVersionConstraint], -- See respective types for an explanation of what these -- values are about: projectConfigBuildOnly :: ProjectConfigBuildOnly, projectConfigShared :: ProjectConfigShared, projectConfigProvenance :: Set ProjectConfigProvenance, -- | Configuration to be applied to *all* packages, -- whether named in `cabal.project` or not. projectConfigAllPackages :: PackageConfig, -- | Configuration to be applied to *local* packages; i.e., -- any packages which are explicitly named in `cabal.project`. projectConfigLocalPackages :: PackageConfig, projectConfigSpecificPackage :: MapMappend PackageName PackageConfig } deriving (Eq, Show, Generic, Typeable) -- | That part of the project configuration that only affects /how/ we build -- and not the /value/ of the things we build. This means this information -- does not need to be tracked for changes since it does not affect the -- outcome. -- data ProjectConfigBuildOnly = ProjectConfigBuildOnly { projectConfigVerbosity :: Flag Verbosity, projectConfigDryRun :: Flag Bool, projectConfigOnlyDeps :: Flag Bool, projectConfigSummaryFile :: NubList PathTemplate, projectConfigLogFile :: Flag PathTemplate, projectConfigBuildReports :: Flag ReportLevel, projectConfigReportPlanningFailure :: Flag Bool, projectConfigSymlinkBinDir :: Flag FilePath, projectConfigOneShot :: Flag Bool, projectConfigNumJobs :: Flag (Maybe Int), projectConfigKeepGoing :: Flag Bool, projectConfigOfflineMode :: Flag Bool, projectConfigKeepTempFiles :: Flag Bool, projectConfigHttpTransport :: Flag String, projectConfigIgnoreExpiry :: Flag Bool, projectConfigCacheDir :: Flag FilePath, projectConfigLogsDir :: Flag FilePath, projectConfigClientInstallFlags :: ClientInstallFlags } deriving (Eq, Show, Generic) -- | Project configuration that is shared between all packages in the project. -- In particular this includes configuration that affects the solver. -- data ProjectConfigShared = ProjectConfigShared { projectConfigDistDir :: Flag FilePath, projectConfigConfigFile :: Flag FilePath, projectConfigProjectFile :: Flag FilePath, projectConfigIgnoreProject :: Flag Bool, projectConfigHcFlavor :: Flag CompilerFlavor, projectConfigHcPath :: Flag FilePath, projectConfigHcPkg :: Flag FilePath, projectConfigHaddockIndex :: Flag PathTemplate, -- Things that only make sense for manual mode, not --local mode -- too much control! --projectConfigUserInstall :: Flag Bool, --projectConfigInstallDirs :: InstallDirs (Flag PathTemplate), --TODO: [required eventually] decide what to do with InstallDirs -- currently we don't allow it to be specified in the config file --projectConfigPackageDBs :: [Maybe PackageDB], -- configuration used both by the solver and other phases projectConfigRemoteRepos :: NubList RemoteRepo, -- ^ Available Hackage servers. projectConfigLocalNoIndexRepos :: NubList LocalRepo, projectConfigActiveRepos :: Flag ActiveRepos, projectConfigIndexState :: Flag TotalIndexState, projectConfigStoreDir :: Flag FilePath, -- solver configuration projectConfigConstraints :: [(UserConstraint, ConstraintSource)], projectConfigPreferences :: [PackageVersionConstraint], projectConfigCabalVersion :: Flag Version, --TODO: [required eventually] unused projectConfigSolver :: Flag PreSolver, projectConfigAllowOlder :: Maybe AllowOlder, projectConfigAllowNewer :: Maybe AllowNewer, projectConfigWriteGhcEnvironmentFilesPolicy :: Flag WriteGhcEnvironmentFilesPolicy, projectConfigMaxBackjumps :: Flag Int, projectConfigReorderGoals :: Flag ReorderGoals, projectConfigCountConflicts :: Flag CountConflicts, projectConfigFineGrainedConflicts :: Flag FineGrainedConflicts, projectConfigMinimizeConflictSet :: Flag MinimizeConflictSet, projectConfigStrongFlags :: Flag StrongFlags, projectConfigAllowBootLibInstalls :: Flag AllowBootLibInstalls, projectConfigOnlyConstrained :: Flag OnlyConstrained, projectConfigPerComponent :: Flag Bool, projectConfigIndependentGoals :: Flag IndependentGoals, projectConfigProgPathExtra :: NubList FilePath -- More things that only make sense for manual mode, not --local mode -- too much control! --projectConfigShadowPkgs :: Flag Bool, --projectConfigReinstall :: Flag Bool, --projectConfigAvoidReinstalls :: Flag Bool, --projectConfigOverrideReinstall :: Flag Bool, --projectConfigUpgradeDeps :: Flag Bool } deriving (Eq, Show, Generic) -- | Specifies the provenance of project configuration, whether defaults were -- used or if the configuration was read from an explicit file path. data ProjectConfigProvenance -- | The configuration is implicit due to no explicit configuration -- being found. See 'Distribution.Client.ProjectConfig.readProjectConfig' -- for how implicit configuration is determined. = Implicit -- | The path the project configuration was explicitly read from. -- | The configuration was explicitly read from the specified 'FilePath'. | Explicit FilePath deriving (Eq, Ord, Show, Generic) -- | Project configuration that is specific to each package, that is where we -- can in principle have different values for different packages in the same -- project. -- data PackageConfig = PackageConfig { packageConfigProgramPaths :: MapLast String FilePath, packageConfigProgramArgs :: MapMappend String [String], packageConfigProgramPathExtra :: NubList FilePath, packageConfigFlagAssignment :: FlagAssignment, packageConfigVanillaLib :: Flag Bool, packageConfigSharedLib :: Flag Bool, packageConfigStaticLib :: Flag Bool, packageConfigDynExe :: Flag Bool, packageConfigFullyStaticExe :: Flag Bool, packageConfigProf :: Flag Bool, --TODO: [code cleanup] sort out packageConfigProfLib :: Flag Bool, -- this duplication packageConfigProfExe :: Flag Bool, -- and consistency packageConfigProfDetail :: Flag ProfDetailLevel, packageConfigProfLibDetail :: Flag ProfDetailLevel, packageConfigConfigureArgs :: [String], packageConfigOptimization :: Flag OptimisationLevel, packageConfigProgPrefix :: Flag PathTemplate, packageConfigProgSuffix :: Flag PathTemplate, packageConfigExtraLibDirs :: [FilePath], packageConfigExtraFrameworkDirs :: [FilePath], packageConfigExtraIncludeDirs :: [FilePath], packageConfigGHCiLib :: Flag Bool, packageConfigSplitSections :: Flag Bool, packageConfigSplitObjs :: Flag Bool, packageConfigStripExes :: Flag Bool, packageConfigStripLibs :: Flag Bool, packageConfigTests :: Flag Bool, packageConfigBenchmarks :: Flag Bool, packageConfigCoverage :: Flag Bool, packageConfigRelocatable :: Flag Bool, packageConfigDebugInfo :: Flag DebugInfoLevel, packageConfigRunTests :: Flag Bool, --TODO: [required eventually] use this packageConfigDocumentation :: Flag Bool, --TODO: [required eventually] use this -- Haddock options packageConfigHaddockHoogle :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockHtml :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockHtmlLocation :: Flag String, --TODO: [required eventually] use this packageConfigHaddockForeignLibs :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockExecutables :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockTestSuites :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockBenchmarks :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockInternal :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockCss :: Flag FilePath, --TODO: [required eventually] use this packageConfigHaddockLinkedSource :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockQuickJump :: Flag Bool, --TODO: [required eventually] use this packageConfigHaddockHscolourCss :: Flag FilePath, --TODO: [required eventually] use this packageConfigHaddockContents :: Flag PathTemplate, --TODO: [required eventually] use this packageConfigHaddockForHackage :: Flag HaddockTarget, -- Test options packageConfigTestHumanLog :: Flag PathTemplate, packageConfigTestMachineLog :: Flag PathTemplate, packageConfigTestShowDetails :: Flag TestShowDetails, packageConfigTestKeepTix :: Flag Bool, packageConfigTestWrapper :: Flag FilePath, packageConfigTestFailWhenNoTestSuites :: Flag Bool, packageConfigTestTestOptions :: [PathTemplate], -- Benchmark options packageConfigBenchmarkOptions :: [PathTemplate] } deriving (Eq, Show, Generic) instance Binary ProjectConfig instance Binary ProjectConfigBuildOnly instance Binary ProjectConfigShared instance Binary ProjectConfigProvenance instance Binary PackageConfig instance Structured ProjectConfig instance Structured ProjectConfigBuildOnly instance Structured ProjectConfigShared instance Structured ProjectConfigProvenance instance Structured PackageConfig -- | Newtype wrapper for 'Map' that provides a 'Monoid' instance that takes -- the last value rather than the first value for overlapping keys. newtype MapLast k v = MapLast { getMapLast :: Map k v } deriving (Eq, Show, Functor, Generic, Binary, Typeable) instance (Structured k, Structured v) => Structured (MapLast k v) instance Ord k => Monoid (MapLast k v) where mempty = MapLast Map.empty mappend = (<>) instance Ord k => Semigroup (MapLast k v) where MapLast a <> MapLast b = MapLast $ Map.union b a -- rather than Map.union which is the normal Map monoid instance -- | Newtype wrapper for 'Map' that provides a 'Monoid' instance that -- 'mappend's values of overlapping keys rather than taking the first. newtype MapMappend k v = MapMappend { getMapMappend :: Map k v } deriving (Eq, Show, Functor, Generic, Binary, Typeable) instance (Structured k, Structured v) => Structured (MapMappend k v) instance (Semigroup v, Ord k) => Monoid (MapMappend k v) where mempty = MapMappend Map.empty mappend = (<>) instance (Semigroup v, Ord k) => Semigroup (MapMappend k v) where MapMappend a <> MapMappend b = MapMappend (Map.unionWith (<>) a b) -- rather than Map.union which is the normal Map monoid instance instance Monoid ProjectConfig where mempty = gmempty mappend = (<>) instance Semigroup ProjectConfig where (<>) = gmappend instance Monoid ProjectConfigBuildOnly where mempty = gmempty mappend = (<>) instance Semigroup ProjectConfigBuildOnly where (<>) = gmappend instance Monoid ProjectConfigShared where mempty = gmempty mappend = (<>) instance Semigroup ProjectConfigShared where (<>) = gmappend instance Monoid PackageConfig where mempty = gmempty mappend = (<>) instance Semigroup PackageConfig where (<>) = gmappend ---------------------------------------- -- Resolving configuration to settings -- -- | Resolved configuration for the solver. The idea is that this is easier to -- use than the raw configuration because in the raw configuration everything -- is optional (monoidial). In the 'BuildTimeSettings' every field is filled -- in, if only with the defaults. -- -- Use 'resolveSolverSettings' to make one from the project config (by -- applying defaults etc). -- data SolverSettings = SolverSettings { solverSettingRemoteRepos :: [RemoteRepo], -- ^ Available Hackage servers. solverSettingLocalNoIndexRepos :: [LocalRepo], solverSettingConstraints :: [(UserConstraint, ConstraintSource)], solverSettingPreferences :: [PackageVersionConstraint], solverSettingFlagAssignment :: FlagAssignment, -- ^ For all local packages solverSettingFlagAssignments :: Map PackageName FlagAssignment, solverSettingCabalVersion :: Maybe Version, --TODO: [required eventually] unused solverSettingSolver :: PreSolver, solverSettingAllowOlder :: AllowOlder, solverSettingAllowNewer :: AllowNewer, solverSettingMaxBackjumps :: Maybe Int, solverSettingReorderGoals :: ReorderGoals, solverSettingCountConflicts :: CountConflicts, solverSettingFineGrainedConflicts :: FineGrainedConflicts, solverSettingMinimizeConflictSet :: MinimizeConflictSet, solverSettingStrongFlags :: StrongFlags, solverSettingAllowBootLibInstalls :: AllowBootLibInstalls, solverSettingOnlyConstrained :: OnlyConstrained, solverSettingIndexState :: Maybe TotalIndexState, solverSettingActiveRepos :: Maybe ActiveRepos, solverSettingIndependentGoals :: IndependentGoals -- Things that only make sense for manual mode, not --local mode -- too much control! --solverSettingShadowPkgs :: Bool, --solverSettingReinstall :: Bool, --solverSettingAvoidReinstalls :: Bool, --solverSettingOverrideReinstall :: Bool, --solverSettingUpgradeDeps :: Bool } deriving (Eq, Show, Generic, Typeable) instance Binary SolverSettings instance Structured SolverSettings -- | Resolved configuration for things that affect how we build and not the -- value of the things we build. The idea is that this is easier to use than -- the raw configuration because in the raw configuration everything is -- optional (monoidial). In the 'BuildTimeSettings' every field is filled in, -- if only with the defaults. -- -- Use 'resolveBuildTimeSettings' to make one from the project config (by -- applying defaults etc). -- data BuildTimeSettings = BuildTimeSettings { buildSettingDryRun :: Bool, buildSettingOnlyDeps :: Bool, buildSettingSummaryFile :: [PathTemplate], buildSettingLogFile :: Maybe (Compiler -> Platform -> PackageId -> UnitId -> FilePath), buildSettingLogVerbosity :: Verbosity, buildSettingBuildReports :: ReportLevel, buildSettingReportPlanningFailure :: Bool, buildSettingSymlinkBinDir :: [FilePath], buildSettingOneShot :: Bool, buildSettingNumJobs :: Int, buildSettingKeepGoing :: Bool, buildSettingOfflineMode :: Bool, buildSettingKeepTempFiles :: Bool, buildSettingRemoteRepos :: [RemoteRepo], buildSettingLocalNoIndexRepos :: [LocalRepo], buildSettingCacheDir :: FilePath, buildSettingHttpTransport :: Maybe String, buildSettingIgnoreExpiry :: Bool, buildSettingProgPathExtra :: [FilePath] }