diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs index a396dea860c..4793c8650d7 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs @@ -29,8 +29,8 @@ tests = testGroup "Distribution.Utils.Structured" , testCase "GenericPackageDescription" $ md5Check (Proxy :: Proxy GenericPackageDescription) 0xc7d1064aaf2c9bcf92c3d7f23e6d7e94 , testCase "LocalBuildInfo" $ - md5Check (Proxy :: Proxy LocalBuildInfo) 0x0324f420f9fb98417098127a414cc7c0 -#endif + md5Check (Proxy :: Proxy LocalBuildInfo) 0xf6adad996a4bd3746405c2b7abf49fc6 +#endif ] -- -------------------------------------------------------------------- -- diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal index b1049bc5c62..2815948e735 100644 --- a/Cabal/Cabal.cabal +++ b/Cabal/Cabal.cabal @@ -60,6 +60,7 @@ library ghc-options: -Wnoncanonical-monadfail-instances exposed-modules: + Distribution.AllowNewer Distribution.Backpack.Configure Distribution.Backpack.ComponentsGraph Distribution.Backpack.ConfiguredComponent @@ -140,6 +141,7 @@ library Distribution.Simple.UserHooks Distribution.Simple.Utils Distribution.TestSuite + Distribution.Types.AllowNewer Distribution.Types.AnnotatedId Distribution.Types.ComponentInclude Distribution.Types.DumpBuildInfo diff --git a/Cabal/src/Distribution/AllowNewer.hs b/Cabal/src/Distribution/AllowNewer.hs new file mode 100644 index 00000000000..f7d5fabaf04 --- /dev/null +++ b/Cabal/src/Distribution/AllowNewer.hs @@ -0,0 +1,71 @@ +----------------------------------------------------------------------------- + +-- | Utilities to relax version bounds on dependencies +module Distribution.AllowNewer + ( relaxPackageDeps + , RelaxKind (..) + ) where + +import Distribution.Compat.Prelude + +import Distribution.Package + ( Package (..) + , packageName + ) +import qualified Distribution.PackageDescription as PD +import qualified Distribution.PackageDescription.Configuration as PD +import Distribution.Types.Dependency +import Distribution.Version + +import qualified Data.Map as Map +import Distribution.Types.AllowNewer + +data RelaxKind = RelaxLower | RelaxUpper + +-- | Relax the dependencies of this package if needed. +-- +-- Helper function used by 'removeBounds' +relaxPackageDeps + :: RelaxKind + -> RelaxDeps + -> PD.GenericPackageDescription + -> PD.GenericPackageDescription +relaxPackageDeps _ rd gpd | not (isRelaxDeps rd) = gpd -- subsumed by no-op case in 'removeBounds' +relaxPackageDeps relKind RelaxDepsAll gpd = PD.transformAllBuildDepends relaxAll gpd + where + relaxAll :: Dependency -> Dependency + relaxAll (Dependency pkgName verRange cs) = + Dependency pkgName (removeBound relKind RelaxDepModNone verRange) cs +relaxPackageDeps relKind (RelaxDepsSome depsToRelax0) gpd = + PD.transformAllBuildDepends relaxSome gpd + where + thisPkgName = packageName gpd + thisPkgId = packageId gpd + depsToRelax = Map.fromList $ mapMaybe f depsToRelax0 + + f :: RelaxedDep -> Maybe (RelaxDepSubject, RelaxDepMod) + f (RelaxedDep scope rdm p) = case scope of + RelaxDepScopeAll -> Just (p, rdm) + RelaxDepScopePackage p0 + | p0 == thisPkgName -> Just (p, rdm) + | otherwise -> Nothing + RelaxDepScopePackageId p0 + | p0 == thisPkgId -> Just (p, rdm) + | otherwise -> Nothing + + relaxSome :: Dependency -> Dependency + relaxSome d@(Dependency depName verRange cs) + | Just relMod <- Map.lookup RelaxDepSubjectAll depsToRelax = + -- a '*'-subject acts absorbing, for consistency with + -- the 'Semigroup RelaxDeps' instance + Dependency depName (removeBound relKind relMod verRange) cs + | Just relMod <- Map.lookup (RelaxDepSubjectPkg depName) depsToRelax = + Dependency depName (removeBound relKind relMod verRange) cs + | otherwise = d -- no-op + +-- | Internal helper for 'relaxPackageDeps' +removeBound :: RelaxKind -> RelaxDepMod -> VersionRange -> VersionRange +removeBound RelaxLower RelaxDepModNone = removeLowerBound +removeBound RelaxUpper RelaxDepModNone = removeUpperBound +removeBound RelaxLower RelaxDepModCaret = transformCaretLower +removeBound RelaxUpper RelaxDepModCaret = transformCaretUpper diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs index 82da0f29aac..e821c198180 100644 --- a/Cabal/src/Distribution/Simple/Configure.hs +++ b/Cabal/src/Distribution/Simple/Configure.hs @@ -162,9 +162,12 @@ import Text.PrettyPrint , ($+$) ) +import Data.Coerce (coerce) import qualified Data.Maybe as M import qualified Data.Set as Set +import Distribution.AllowNewer (RelaxKind (..), relaxPackageDeps) import qualified Distribution.Compat.NonEmptySet as NES +import Distribution.Types.AllowNewer (AllowNewer (..), AllowOlder (..)) import Distribution.Types.AnnotatedId type UseExternalInternalDeps = Bool @@ -1227,7 +1230,13 @@ configureFinalizedPackage satisfies comp compPlatform - pkg_descr0 = do + pkg_descr_before_relaxed_bounds = do + let + relax relax_kind getter = relaxPackageDeps relax_kind . fromMaybe mempty . coerce $ getter cfg + pkg_descr0 = + relax RelaxLower configAllowOlder + . relax RelaxUpper configAllowNewer + $ pkg_descr_before_relaxed_bounds (pkg_descr0', flags) <- case finalizePD (configConfigurationsFlags cfg) diff --git a/Cabal/src/Distribution/Simple/Setup/Config.hs b/Cabal/src/Distribution/Simple/Setup/Config.hs index a109a7502b9..6362a1706b3 100644 --- a/Cabal/src/Distribution/Simple/Setup/Config.hs +++ b/Cabal/src/Distribution/Simple/Setup/Config.hs @@ -62,6 +62,7 @@ import Distribution.Compat.Semigroup (Last' (..), Option' (..)) import Distribution.Compat.Stack import Distribution.Simple.Setup.Common +import Distribution.Types.AllowNewer (AllowNewer (..), AllowOlder (..), RelaxDeps (..)) -- ------------------------------------------------------------ @@ -220,6 +221,12 @@ data ConfigFlags = ConfigFlags -- ^ Allow depending on private sublibraries. This is used by external -- tools (like cabal-install) so they can add multiple-public-libraries -- compatibility to older ghcs by checking visibility externally. + , configAllowNewer :: Maybe AllowNewer + -- ^ Ignore upper bounds on all or some dependencies. + -- Nothing means option not set. + , configAllowOlder :: Maybe AllowOlder + -- ^ Ignore lower bounds on all or some dependencies. + -- Nothing means option not set. } deriving (Generic, Read, Show, Typeable) @@ -288,6 +295,8 @@ instance Eq ConfigFlags where && equal configDebugInfo && equal configDumpBuildInfo && equal configUseResponseFiles + && equal configAllowNewer + && equal configAllowOlder where equal f = on (==) f a b @@ -342,6 +351,8 @@ defaultConfigFlags progDb = , configDebugInfo = Flag NoDebugInfo , configDumpBuildInfo = NoFlag , configUseResponseFiles = NoFlag + , configAllowNewer = Nothing + , configAllowOlder = Nothing } {- FOURMOLU_ENABLE -} @@ -828,8 +839,58 @@ configureOptions showOrParseArgs = configAllowDependingOnPrivateLibs (\v flags -> flags{configAllowDependingOnPrivateLibs = v}) trueArg + , option + "" + ["allow-older"] + ( "Ignore lower bounds in all dependencies or for the given DEPS." + ++ " DEPS is a comma or space separated list of DEP or PKG:DEP," + ++ " where PKG or DEP can be *." + ) + configAllowOlder + (\v flags -> flags{configAllowOlder = v}) + ( optArg + "DEPS" + (fmap (Just . AllowOlder) parseRelaxDeps) + (Just $ AllowOlder RelaxDepsAll) + (relaxDepsPrinter . fmap unAllowOlder) + ) + , option + "" + ["allow-newer"] + ( "Ignore upper bounds in all dependencies or for the given DEPS." + ++ " DEPS is a comma or space separated list of DEP or PKG:DEP," + ++ " where PKG or DEP can be *." + ) + configAllowNewer + (\v flags -> flags{configAllowNewer = v}) + ( optArg + "DEPS" + (fmap (Just . AllowNewer) parseRelaxDeps) + (Just $ AllowNewer RelaxDepsAll) + (relaxDepsPrinter . fmap unAllowNewer) + ) ] where + relaxDepsParser :: CabalParsing m => m RelaxDeps + relaxDepsParser = do + rs <- parsecOptCommaList parsec + if null rs + then -- This error is not displayed by the argument parser, + -- but its nice to have anyway. + + fail $ + "empty argument list is not allowed. " + ++ "Note: use --allow-newer/--allow-older without the equals sign to permit all " + ++ "packages to use newer versions." + else return . RelaxDepsSome $ rs + + relaxDepsPrinter :: Maybe RelaxDeps -> [Maybe String] + relaxDepsPrinter Nothing = [] + relaxDepsPrinter (Just RelaxDepsAll) = [Nothing] + relaxDepsPrinter (Just (RelaxDepsSome pkgs)) = map (Just . prettyShow) pkgs + + parseRelaxDeps = parsecToReadE ("Not a valid list of DEPS: " ++) relaxDepsParser + liftInstallDirs = liftOption configInstallDirs (\v flags -> flags{configInstallDirs = v}) diff --git a/cabal-install/src/Distribution/Client/Types/AllowNewer.hs b/Cabal/src/Distribution/Types/AllowNewer.hs similarity index 97% rename from cabal-install/src/Distribution/Client/Types/AllowNewer.hs rename to Cabal/src/Distribution/Types/AllowNewer.hs index 0a5700174b8..4f2a27e9e5f 100644 --- a/cabal-install/src/Distribution/Client/Types/AllowNewer.hs +++ b/Cabal/src/Distribution/Types/AllowNewer.hs @@ -1,6 +1,6 @@ {-# LANGUAGE DeriveGeneric #-} -module Distribution.Client.Types.AllowNewer +module Distribution.Types.AllowNewer ( AllowNewer (..) , AllowOlder (..) , RelaxDeps (..) @@ -12,15 +12,15 @@ module Distribution.Client.Types.AllowNewer , isRelaxDeps ) where -import Distribution.Client.Compat.Prelude -import Prelude () +import Distribution.Compat.Prelude -import Distribution.Parsec (parsecLeadingCommaNonEmpty) +import Distribution.Parsec (CabalParsing, Parsec (parsec), parsecLeadingCommaNonEmpty) import Distribution.Types.PackageId (PackageId, PackageIdentifier (..)) import Distribution.Types.PackageName (PackageName, mkPackageName) import Distribution.Types.Version (nullVersion) import qualified Distribution.Compat.CharParsing as P +import Distribution.Pretty (Pretty (pretty)) import qualified Text.PrettyPrint as Disp -- $setup diff --git a/cabal-install/cabal-install.cabal b/cabal-install/cabal-install.cabal index f3f6be8a778..a3e53fa8452 100644 --- a/cabal-install/cabal-install.cabal +++ b/cabal-install/cabal-install.cabal @@ -179,7 +179,6 @@ library Distribution.Client.TargetSelector Distribution.Client.Targets Distribution.Client.Types - Distribution.Client.Types.AllowNewer Distribution.Client.Types.BuildResults Distribution.Client.Types.ConfiguredId Distribution.Client.Types.ConfiguredPackage diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index a40e31636cc..e6dfd39bfaf 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -84,15 +84,17 @@ import Distribution.Client.Setup , reportCommand , uploadCommand ) -import Distribution.Client.Types +import Distribution.Types.AllowNewer ( AllowNewer (..) , AllowOlder (..) - , LocalRepo (..) , RelaxDeps (..) + , isRelaxDeps + ) +import Distribution.Client.Types + ( LocalRepo (..) , RemoteRepo (..) , RepoName (..) , emptyRemoteRepo - , isRelaxDeps , unRepoName ) import Distribution.Client.Types.Credentials (Password (..), Username (..)) @@ -526,6 +528,8 @@ instance Semigroup SavedConfig where , configDumpBuildInfo = combine configDumpBuildInfo , configAllowDependingOnPrivateLibs = combine configAllowDependingOnPrivateLibs + , configAllowNewer = combineMonoid savedConfigureFlags configAllowNewer + , configAllowOlder = combineMonoid savedConfigureFlags configAllowOlder } where combine = combine' savedConfigureFlags @@ -543,10 +547,6 @@ instance Semigroup SavedConfig where , -- TODO: NubListify configPreferences = lastNonEmpty configPreferences , configSolver = combine configSolver - , configAllowNewer = - combineMonoid savedConfigureExFlags configAllowNewer - , configAllowOlder = - combineMonoid savedConfigureExFlags configAllowOlder , configWriteGhcEnvironmentFilesPolicy = combine configWriteGhcEnvironmentFilesPolicy } @@ -1103,14 +1103,12 @@ commentSavedConfig = do } , savedInstallFlags = defaultInstallFlags , savedClientInstallFlags = defaultClientInstallFlags - , savedConfigureExFlags = - defaultConfigExFlags - { configAllowNewer = Just (AllowNewer mempty) - , configAllowOlder = Just (AllowOlder mempty) - } + , savedConfigureExFlags = defaultConfigExFlags , savedConfigureFlags = (defaultConfigFlags defaultProgramDb) { configUserInstall = toFlag defaultUserInstall + , configAllowNewer = Just (AllowNewer mempty) + , configAllowOlder = Just (AllowOlder mempty) } , savedUserInstallDirs = fmap toFlag userInstallDirs , savedGlobalInstallDirs = fmap toFlag globalInstallDirs @@ -1231,12 +1229,7 @@ configFieldDescriptions src = ++ name ++ "' field is case sensitive, use 'True' or 'False'." ) - ] - ++ toSavedConfig - liftConfigExFlag - (configureExOptions ParseArgs src) - [] - [ let pkgs = + , let pkgs = (Just . AllowOlder . RelaxDepsSome) `fmap` parsecOptCommaList parsec parseAllowOlder = @@ -1265,6 +1258,11 @@ configFieldDescriptions src = configAllowNewer (\v flags -> flags{configAllowNewer = v}) ] + ++ toSavedConfig + liftConfigExFlag + (configureExOptions ParseArgs src) + [] + [] ++ toSavedConfig liftInstallFlag (installOptions ParseArgs) diff --git a/cabal-install/src/Distribution/Client/Configure.hs b/cabal-install/src/Distribution/Client/Configure.hs index d0abdac3430..a4a50c555d2 100644 --- a/cabal-install/src/Distribution/Client/Configure.hs +++ b/cabal-install/src/Distribution/Client/Configure.hs @@ -130,6 +130,7 @@ import Distribution.Version ) import System.FilePath (()) +import Distribution.Types.AllowNewer (AllowOlder(..), AllowNewer (..)) -- | Choose the Cabal version such that the setup scripts compiled against this -- version will support the given command-line flags. Currently, it implements no @@ -430,9 +431,9 @@ planLocalPackage resolverParams :: DepResolverParams resolverParams = removeLowerBounds - (fromMaybe (AllowOlder mempty) $ configAllowOlder configExFlags) + (fromMaybe (AllowOlder mempty) $ configAllowOlder configFlags) . removeUpperBounds - (fromMaybe (AllowNewer mempty) $ configAllowNewer configExFlags) + (fromMaybe (AllowNewer mempty) $ configAllowNewer configFlags) . addPreferences -- preferences from the config file or command line [ PackageVersionPreference name ver diff --git a/cabal-install/src/Distribution/Client/Dependency.hs b/cabal-install/src/Distribution/Client/Dependency.hs index 5bc5ec51b86..69883d248c2 100644 --- a/cabal-install/src/Distribution/Client/Dependency.hs +++ b/cabal-install/src/Distribution/Client/Dependency.hs @@ -77,19 +77,17 @@ import Distribution.Client.Dependency.Types ) import Distribution.Client.SolverInstallPlan (SolverInstallPlan) import qualified Distribution.Client.SolverInstallPlan as SolverInstallPlan -import Distribution.Client.Types +import Distribution.Types.AllowNewer ( AllowNewer (..) , AllowOlder (..) - , PackageSpecifier (..) - , RelaxDepMod (..) - , RelaxDepScope (..) - , RelaxDepSubject (..) , RelaxDeps (..) - , RelaxedDep (..) + , isRelaxDeps + ) +import Distribution.Client.Types + ( PackageSpecifier (..) , SourcePackageDb (SourcePackageDb) , UnresolvedPkgLoc , UnresolvedSourcePackage - , isRelaxDeps , pkgSpecifierConstraints , pkgSpecifierTarget ) @@ -163,6 +161,7 @@ import Data.List ) import qualified Data.Map as Map import qualified Data.Set as Set +import Distribution.AllowNewer (RelaxKind (..), relaxPackageDeps) -- ------------------------------------------------------------ @@ -528,8 +527,6 @@ removeUpperBounds (AllowNewer relDeps) = removeBounds RelaxUpper relDeps removeLowerBounds :: AllowOlder -> DepResolverParams -> DepResolverParams removeLowerBounds (AllowOlder relDeps) = removeBounds RelaxLower relDeps -data RelaxKind = RelaxLower | RelaxUpper - -- | Common internal implementation of 'removeLowerBounds'/'removeUpperBounds' removeBounds :: RelaxKind -> RelaxDeps -> DepResolverParams -> DepResolverParams removeBounds _ rd params | not (isRelaxDeps rd) = params -- no-op optimisation @@ -547,54 +544,6 @@ removeBounds relKind relDeps params = { srcpkgDescription = relaxPackageDeps relKind relDeps (srcpkgDescription srcPkg) } --- | Relax the dependencies of this package if needed. --- --- Helper function used by 'removeBounds' -relaxPackageDeps - :: RelaxKind - -> RelaxDeps - -> PD.GenericPackageDescription - -> PD.GenericPackageDescription -relaxPackageDeps _ rd gpd | not (isRelaxDeps rd) = gpd -- subsumed by no-op case in 'removeBounds' -relaxPackageDeps relKind RelaxDepsAll gpd = PD.transformAllBuildDepends relaxAll gpd - where - relaxAll :: Dependency -> Dependency - relaxAll (Dependency pkgName verRange cs) = - Dependency pkgName (removeBound relKind RelaxDepModNone verRange) cs -relaxPackageDeps relKind (RelaxDepsSome depsToRelax0) gpd = - PD.transformAllBuildDepends relaxSome gpd - where - thisPkgName = packageName gpd - thisPkgId = packageId gpd - depsToRelax = Map.fromList $ mapMaybe f depsToRelax0 - - f :: RelaxedDep -> Maybe (RelaxDepSubject, RelaxDepMod) - f (RelaxedDep scope rdm p) = case scope of - RelaxDepScopeAll -> Just (p, rdm) - RelaxDepScopePackage p0 - | p0 == thisPkgName -> Just (p, rdm) - | otherwise -> Nothing - RelaxDepScopePackageId p0 - | p0 == thisPkgId -> Just (p, rdm) - | otherwise -> Nothing - - relaxSome :: Dependency -> Dependency - relaxSome d@(Dependency depName verRange cs) - | Just relMod <- Map.lookup RelaxDepSubjectAll depsToRelax = - -- a '*'-subject acts absorbing, for consistency with - -- the 'Semigroup RelaxDeps' instance - Dependency depName (removeBound relKind relMod verRange) cs - | Just relMod <- Map.lookup (RelaxDepSubjectPkg depName) depsToRelax = - Dependency depName (removeBound relKind relMod verRange) cs - | otherwise = d -- no-op - --- | Internal helper for 'relaxPackageDeps' -removeBound :: RelaxKind -> RelaxDepMod -> VersionRange -> VersionRange -removeBound RelaxLower RelaxDepModNone = removeLowerBound -removeBound RelaxUpper RelaxDepModNone = removeUpperBound -removeBound RelaxLower RelaxDepModCaret = transformCaretLower -removeBound RelaxUpper RelaxDepModCaret = transformCaretUpper - -- | Supply defaults for packages without explicit Setup dependencies -- -- Note: It's important to apply 'addDefaultSetupDepends' after diff --git a/cabal-install/src/Distribution/Client/Install.hs b/cabal-install/src/Distribution/Client/Install.hs index 93ad8e5ae2e..9a4156a4ba0 100644 --- a/cabal-install/src/Distribution/Client/Install.hs +++ b/cabal-install/src/Distribution/Client/Install.hs @@ -267,6 +267,7 @@ import Distribution.Version ) import qualified Data.ByteString as BS +import Distribution.Types.AllowNewer (AllowOlder(..), AllowNewer (..)) -- TODO: @@ -678,11 +679,11 @@ planPackages allowOlder = fromMaybe (AllowOlder mempty) - (configAllowOlder configExFlags) + (configAllowOlder configFlags) allowNewer = fromMaybe (AllowNewer mempty) - (configAllowNewer configExFlags) + (configAllowNewer configFlags) -- | Remove the provided targets from the install plan. pruneInstallPlan diff --git a/cabal-install/src/Distribution/Client/ProjectConfig.hs b/cabal-install/src/Distribution/Client/ProjectConfig.hs index 2a0f82215c2..2f137d173ae 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig.hs @@ -221,6 +221,7 @@ import System.IO ( IOMode (ReadMode) , withBinaryFile ) +import Distribution.Types.AllowNewer (AllowOlder(..), AllowNewer (..)) ---------------------------------------- -- Resolving configuration to settings diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index cf39d2940ee..4985b197fc5 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -35,7 +35,7 @@ import Distribution.Client.Compat.Prelude import Distribution.Types.Flag (FlagName, parsecFlagAssignment) import Distribution.Client.ProjectConfig.Types -import Distribution.Client.Types.AllowNewer (AllowNewer (..), AllowOlder (..)) +import Distribution.Types.AllowNewer (AllowNewer (..), AllowOlder (..)) import Distribution.Client.Types.Repo (LocalRepo (..), RemoteRepo (..), emptyRemoteRepo) import Distribution.Client.Types.RepoName (RepoName (..), unRepoName) import Distribution.Client.Types.SourceRepo (SourceRepoList, sourceRepositoryPackageGrammar) @@ -631,6 +631,8 @@ convertLegacyAllPackageFlags globalFlags configFlags configExFlags installFlags , configHcFlavor = projectConfigHcFlavor , configHcPath = projectConfigHcPath , configHcPkg = projectConfigHcPkg + , configAllowOlder = projectConfigAllowOlder + , configAllowNewer = projectConfigAllowNewer , -- configProgramPathExtra = projectConfigProgPathExtra DELETE ME configInstallDirs = projectConfigInstallDirs , -- configUserInstall = projectConfigUserInstall, @@ -642,8 +644,6 @@ convertLegacyAllPackageFlags globalFlags configFlags configExFlags installFlags , configExConstraints = projectConfigConstraints , configPreferences = projectConfigPreferences , configSolver = projectConfigSolver - , configAllowOlder = projectConfigAllowOlder - , configAllowNewer = projectConfigAllowNewer , configWriteGhcEnvironmentFilesPolicy = projectConfigWriteGhcEnvironmentFilesPolicy } = configExFlags @@ -901,6 +901,8 @@ convertToLegacySharedConfig , configDistPref = projectConfigDistDir , configPackageDBs = projectConfigPackageDBs , configInstallDirs = projectConfigInstallDirs + , configAllowOlder = projectConfigAllowOlder + , configAllowNewer = projectConfigAllowNewer } configExFlags = @@ -911,8 +913,6 @@ convertToLegacySharedConfig , configExConstraints = projectConfigConstraints , configPreferences = projectConfigPreferences , configSolver = projectConfigSolver - , configAllowOlder = projectConfigAllowOlder - , configAllowNewer = projectConfigAllowNewer , configWriteGhcEnvironmentFilesPolicy = projectConfigWriteGhcEnvironmentFilesPolicy } @@ -1035,6 +1035,8 @@ convertToLegacyAllPackageConfig , configUseResponseFiles = mempty , configDumpBuildInfo = mempty , configAllowDependingOnPrivateLibs = mempty + , configAllowNewer = Nothing + , configAllowOlder = Nothing } haddockFlags = @@ -1111,6 +1113,8 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , configUseResponseFiles = mempty , configDumpBuildInfo = packageConfigDumpBuildInfo , configAllowDependingOnPrivateLibs = mempty + , configAllowNewer = Nothing + , configAllowOlder = Nothing } installFlags = @@ -1325,6 +1329,18 @@ legacySharedConfigFieldDescrs constraintSrc = (fmap readPackageDb parsecToken) configPackageDBs (\v conf -> conf{configPackageDBs = v}) + , monoidFieldParsec + "allow-older" + (maybe mempty pretty) + (fmap Just parsec) + (fmap unAllowOlder . configAllowOlder) + (\v conf -> conf{configAllowOlder = fmap AllowOlder v}) + , monoidFieldParsec + "allow-newer" + (maybe mempty pretty) + (fmap Just parsec) + (fmap unAllowNewer . configAllowNewer) + (\v conf -> conf{configAllowNewer = fmap AllowNewer v}) ] . filterFields (["verbose", "builddir"] ++ map optionName installDirsOptions) . commandOptionsToFields @@ -1345,18 +1361,6 @@ legacySharedConfigFieldDescrs constraintSrc = parsec configPreferences (\v conf -> conf{configPreferences = v}) - , monoidFieldParsec - "allow-older" - (maybe mempty pretty) - (fmap Just parsec) - (fmap unAllowOlder . configAllowOlder) - (\v conf -> conf{configAllowOlder = fmap AllowOlder v}) - , monoidFieldParsec - "allow-newer" - (maybe mempty pretty) - (fmap Just parsec) - (fmap unAllowNewer . configAllowNewer) - (\v conf -> conf{configAllowNewer = fmap AllowNewer v}) ] . filterFields [ "cabal-lib-version" diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs index 3ae80d86d31..57dfb9b8573 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs @@ -32,7 +32,7 @@ import Distribution.Client.Dependency.Types import Distribution.Client.Targets ( UserConstraint ) -import Distribution.Client.Types.AllowNewer (AllowNewer (..), AllowOlder (..)) +import Distribution.Types.AllowNewer (AllowNewer (..), AllowOlder (..)) import Distribution.Client.Types.Repo (LocalRepo, RemoteRepo) import Distribution.Client.Types.SourceRepo (SourceRepoList) import Distribution.Client.Types.WriteGhcEnvironmentFilesPolicy (WriteGhcEnvironmentFilesPolicy) diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index 7d7aaa9efa1..834074b63e6 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -4252,6 +4252,8 @@ setupHsConfigureFlags configPrograms_ = mempty -- never use, shouldn't exist configUseResponseFiles = mempty configAllowDependingOnPrivateLibs = Flag $ not $ libraryVisibilitySupported pkgConfigCompiler + configAllowNewer = Nothing + configAllowOlder = Nothing cidToGivenComponent :: ConfiguredId -> GivenComponent cidToGivenComponent (ConfiguredId srcid mb_cn cid) = GivenComponent (packageName srcid) ln cid diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index 460decd55cd..f9987769381 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -92,7 +92,6 @@ module Distribution.Client.Setup import Distribution.Client.Compat.Prelude hiding (get) import Prelude () -import Distribution.Client.Types.AllowNewer (AllowNewer (..), AllowOlder (..), RelaxDeps (..)) import Distribution.Client.Types.Credentials (Password (..), Username (..)) import Distribution.Client.Types.Repo (LocalRepo (..), RemoteRepo (..)) import Distribution.Client.Types.WriteGhcEnvironmentFilesPolicy @@ -148,9 +147,7 @@ import Distribution.Parsec import Distribution.ReadE ( ReadE (..) , parsecToReadE - , parsecToReadEErr , succeedReadE - , unexpectMsgString ) import Distribution.Simple.Command hiding (boolOpt, boolOpt') import qualified Distribution.Simple.Command as Command @@ -662,7 +659,9 @@ filterConfigureFlags flags cabalLibVersion -- Note: this is not in the wrong place. configConstraints gets -- repopulated in flags_1_19_1 but it needs to be set to empty for -- newer versions first. - configConstraints = [] + configConstraints = [], + configAllowNewer = Nothing, + configAllowOlder = Nothing } flags_3_11_0 = @@ -831,8 +830,6 @@ data ConfigExFlags = ConfigExFlags , configExConstraints :: [(UserConstraint, ConstraintSource)] , configPreferences :: [PackageVersionConstraint] , configSolver :: Flag PreSolver - , configAllowNewer :: Maybe AllowNewer - , configAllowOlder :: Maybe AllowOlder , configWriteGhcEnvironmentFilesPolicy :: Flag WriteGhcEnvironmentFilesPolicy } @@ -925,30 +922,6 @@ configureExOptions _showOrParseArgs src = (map prettyShow) ) , optionSolver configSolver (\v flags -> flags{configSolver = v}) - , option - [] - ["allow-older"] - ("Ignore lower bounds in all dependencies or DEPS") - (fmap unAllowOlder . configAllowOlder) - (\v flags -> flags{configAllowOlder = fmap AllowOlder v}) - ( optArg - "DEPS" - (parsecToReadEErr unexpectMsgString relaxDepsParser) - (Just RelaxDepsAll) - relaxDepsPrinter - ) - , option - [] - ["allow-newer"] - ("Ignore upper bounds in all dependencies or DEPS") - (fmap unAllowNewer . configAllowNewer) - (\v flags -> flags{configAllowNewer = fmap AllowNewer v}) - ( optArg - "DEPS" - (parsecToReadEErr unexpectMsgString relaxDepsParser) - (Just RelaxDepsAll) - relaxDepsPrinter - ) , option [] ["write-ghc-environment-files"] @@ -983,22 +956,6 @@ writeGhcEnvironmentFilesPolicyPrinter = \case (Flag WriteGhcEnvironmentFilesOnlyForGhc844AndNewer) -> ["ghc8.4.4+"] NoFlag -> [] -relaxDepsParser :: CabalParsing m => m (Maybe RelaxDeps) -relaxDepsParser = do - rs <- P.sepBy parsec (P.char ',') - if null rs - then - fail $ - "empty argument list is not allowed. " - ++ "Note: use --allow-newer without the equals sign to permit all " - ++ "packages to use newer versions." - else return . Just . RelaxDepsSome . toList $ rs - -relaxDepsPrinter :: (Maybe RelaxDeps) -> [Maybe String] -relaxDepsPrinter Nothing = [] -relaxDepsPrinter (Just RelaxDepsAll) = [Nothing] -relaxDepsPrinter (Just (RelaxDepsSome pkgs)) = map (Just . prettyShow) $ pkgs - instance Monoid ConfigExFlags where mempty = gmempty mappend = (<>) diff --git a/cabal-install/src/Distribution/Client/Types.hs b/cabal-install/src/Distribution/Client/Types.hs index 710960ee939..338932d1376 100644 --- a/cabal-install/src/Distribution/Client/Types.hs +++ b/cabal-install/src/Distribution/Client/Types.hs @@ -21,8 +21,7 @@ -- -- Various common data types for the entire cabal-install system module Distribution.Client.Types - ( module Distribution.Client.Types.AllowNewer - , module Distribution.Client.Types.ConfiguredId + ( module Distribution.Client.Types.ConfiguredId , module Distribution.Client.Types.ConfiguredPackage , module Distribution.Client.Types.BuildResults , module Distribution.Client.Types.PackageLocation @@ -34,7 +33,6 @@ module Distribution.Client.Types , module Distribution.Client.Types.WriteGhcEnvironmentFilesPolicy ) where -import Distribution.Client.Types.AllowNewer import Distribution.Client.Types.BuildResults import Distribution.Client.Types.ConfiguredId import Distribution.Client.Types.ConfiguredPackage diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs b/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs index 0ff8e280823..cd085322cfb 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs @@ -38,7 +38,7 @@ import Distribution.Client.IndexUtils.IndexState (RepoIndexState (..), TotalInde import Distribution.Client.IndexUtils.Timestamp (Timestamp, epochTimeToTimestamp) import Distribution.Client.Targets import Distribution.Client.Types (RepoName (..), WriteGhcEnvironmentFilesPolicy) -import Distribution.Client.Types.AllowNewer +import Distribution.Types.AllowNewer import Distribution.Client.Types.OverwritePolicy (OverwritePolicy) import Distribution.Solver.Types.OptionalStanza (OptionalStanza (..), OptionalStanzaMap, OptionalStanzaSet, optStanzaSetFromList, optStanzaTabulate) import Distribution.Solver.Types.PackageConstraint (PackageProperty (..)) diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Described.hs b/cabal-install/tests/UnitTests/Distribution/Client/Described.hs index fbd544a9a0b..c46a8ae880a 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Described.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Described.hs @@ -18,7 +18,7 @@ import Distribution.Client.IndexUtils.IndexState (RepoIndexState, TotalIndexStat import Distribution.Client.IndexUtils.Timestamp (Timestamp) import Distribution.Client.Targets (UserConstraint) import Distribution.Client.Types (RepoName) -import Distribution.Client.Types.AllowNewer (RelaxDepSubject, RelaxDeps, RelaxedDep) +import Distribution.Types.AllowNewer (RelaxDepSubject, RelaxDeps, RelaxedDep) tests :: TestTree tests = diff --git a/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs b/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs index 66b9649db11..45acfd00b92 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs @@ -19,7 +19,7 @@ import Distribution.Client.IndexUtils.IndexState (RepoIndexState, TotalIndexStat import Distribution.Client.IndexUtils.Timestamp (Timestamp) import Distribution.Client.Targets (UserConstraint) import Distribution.Client.Types (RepoName) -import Distribution.Client.Types.AllowNewer (RelaxDepSubject, RelaxDeps, RelaxedDep) +import Distribution.Types.AllowNewer (RelaxDepSubject, RelaxDeps, RelaxedDep) ------------------------------------------------------------------------------- -- BuildReport diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs index b1108d77701..94084e8fc80 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs @@ -66,6 +66,7 @@ import Data.TreeDiff.QuickCheck import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck +import Distribution.Types.AllowNewer tests :: [TestTree] tests = diff --git a/cabal-install/tests/UnitTests/Distribution/Client/TreeDiffInstances.hs b/cabal-install/tests/UnitTests/Distribution/Client/TreeDiffInstances.hs index 495c4cbf402..6a64934606c 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/TreeDiffInstances.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/TreeDiffInstances.hs @@ -20,6 +20,7 @@ import Distribution.Client.Types import Distribution.Client.Types.OverwritePolicy (OverwritePolicy) import Distribution.Client.Types.SourceRepo (SourceRepositoryPackage) +import Distribution.Types.AllowNewer import Distribution.Simple.Compiler (PackageDB) import Data.TreeDiff.Class diff --git a/changelog.d/pr-9016 b/changelog.d/pr-9016 new file mode 100644 index 00000000000..01dae4550aa --- /dev/null +++ b/changelog.d/pr-9016 @@ -0,0 +1,14 @@ +synopsis: Add --allow-newer and --allow-older to ./Setup.hs configure +packages: Cabal +prs: #9016 +issues: #7445 #5407 #7859 +significance: significant + +description: { + +- --allow-newer and --allow-older flag are now again supported by ./Setup.hs configure +- This feature can be used when dependencies have are provided externally, + it is desired to check if their versions match, but some checks should be ignored. +- Historical note: These options where moved to Cabal in 2016 (#3165) and removed again in 2017 (#4527). + +} diff --git a/doc/setup-commands.rst b/doc/setup-commands.rst index 24016c2c267..30004dc822e 100644 --- a/doc/setup-commands.rst +++ b/doc/setup-commands.rst @@ -987,6 +987,76 @@ Miscellaneous options Windows the ``cabal`` should do the right thing and hence should normally not require this flag. +.. option:: --allow-newer[=pkgs], --allow-older[=pkgs] + + Selectively relax upper or lower bounds in dependencies without + editing the package description respectively. + + Note: These options work the same for ``./Setup.hs configure`` and + ``cabal``. Thus the following description uses the ``cabal`` command. + Some features of these options are only necessary for the ``cabal`` + command, but also exist in ``./Setup.hs configure`` for symmetry. + + The following description focuses on upper bounds and the + :option:`--allow-newer` flag, but applies analogously to + :option:`--allow-older` and lower bounds. :option:`--allow-newer` + and :option:`--allow-older` can be used at the same time. + + If you want to install a package A that depends on B >= 1.0 && < + 2.0, but you have the version 2.0 of B installed, you can compile A + against B 2.0 by using ``cabal install --allow-newer=B A``. This + works for the whole package index: if A also depends on C that in + turn depends on B < 2.0, C's dependency on B will be also relaxed. + + Example: + + :: + + $ cd foo + $ cabal configure + Resolving dependencies... + cabal: Could not resolve dependencies: + [...] + $ cabal configure --allow-newer + Resolving dependencies... + Configuring foo... + + Additional examples: + + :: + + # Relax upper bounds in all dependencies. + $ cabal install --allow-newer foo + + # Relax upper bounds only in dependencies on bar, baz and quux. + $ cabal install --allow-newer=bar,baz,quux foo + + # Relax the upper bound on bar and force bar==2.1. + $ cabal install --allow-newer=bar --constraint="bar==2.1" foo + + It's also possible to limit the scope of :option:`--allow-newer` to single + packages with the ``--allow-newer=scope:dep`` syntax. This means + that the dependency on ``dep`` will be relaxed only for the package + ``scope``. + + Example: + + :: + + # Relax upper bound in foo's dependency on base; also relax upper bound in + # every package's dependency on lens. + $ cabal install --allow-newer=foo:base,lens + + # Relax upper bounds in foo's dependency on base and bar's dependency + # on time; also relax the upper bound in the dependency on lens specified by + # any package. + $ cabal install --allow-newer=foo:base,lens --allow-newer=bar:time + + Finally, one can enable :option:`--allow-newer` permanently by setting + ``allow-newer: True`` in the :ref:`config file `. Enabling + 'allow-newer' selectively is also supported in the config file + (``allow-newer: foo, bar, baz:base``). + .. _setup-build: runhaskell Setup.hs build