Skip to content

Allow limiting the scope of '--allow-newer'. #3171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions Cabal/Distribution/Simple/Configure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ import qualified Data.ByteString.Lazy.Char8 as BLC8
import Data.List
( (\\), nub, partition, isPrefixOf, inits, stripPrefix )
import Data.Maybe
( isNothing, catMaybes, fromMaybe, isJust )
( isNothing, catMaybes, fromMaybe, mapMaybe, isJust )
import Data.Either
( partitionEithers )
import qualified Data.Set as Set
Expand Down Expand Up @@ -315,7 +315,9 @@ configure (pkg_descr0', pbi) cfg = do
-- Ignore '--allow-newer' when we're given '--exact-configuration'.
if fromFlagOrDefault False (configExactConfiguration cfg)
then pkg_descr0'
else relaxPackageDeps (configAllowNewer cfg) pkg_descr0'
else relaxPackageDeps
(fromMaybe AllowNewerNone $ configAllowNewer cfg)
pkg_descr0'

setupMessage verbosity "Configuring" (packageId pkg_descr0)

Expand Down Expand Up @@ -794,18 +796,28 @@ dependencySatisfiable
isInternalDep = not . null
$ PackageIndex.lookupDependency internalPackageSet d

-- | Relax the dependencies of this package if needed
-- | Relax the dependencies of this package if needed.
relaxPackageDeps :: AllowNewer -> GenericPackageDescription
-> GenericPackageDescription
relaxPackageDeps AllowNewerNone = id
relaxPackageDeps AllowNewerAll =
transformAllBuildDepends $ \(Dependency pkgName verRange) ->
Dependency pkgName (removeUpperBound verRange)
relaxPackageDeps (AllowNewerSome pkgNames) =
transformAllBuildDepends $ \d@(Dependency pkgName verRange) ->
if pkgName `elem` pkgNames
then Dependency pkgName (removeUpperBound verRange)
else d
relaxPackageDeps AllowNewerNone gpd = gpd
relaxPackageDeps AllowNewerAll gpd = transformAllBuildDepends relaxAll gpd
where
relaxAll = \(Dependency pkgName verRange) ->
Dependency pkgName (removeUpperBound verRange)
relaxPackageDeps (AllowNewerSome allowNewerDeps') gpd =
transformAllBuildDepends relaxSome gpd
where
thisPkgName = packageName gpd
allowNewerDeps = mapMaybe f allowNewerDeps'

f (Setup.AllowNewerDep p) = Just p
f (Setup.AllowNewerDepScoped scope p) | scope == thisPkgName = Just p
| otherwise = Nothing

relaxSome = \d@(Dependency depName verRange) ->
if depName `elem` allowNewerDeps
then Dependency depName (removeUpperBound verRange)
else d

-- | Finalize a generic package description. The workhorse is
-- 'finalizePackageDescription' but there's a bit of other nattering
Expand Down
64 changes: 40 additions & 24 deletions Cabal/Distribution/Simple/Setup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module Distribution.Simple.Setup (

GlobalFlags(..), emptyGlobalFlags, defaultGlobalFlags, globalCommand,
ConfigFlags(..), emptyConfigFlags, defaultConfigFlags, configureCommand,
AllowNewer(..), isAllowNewer,
AllowNewer(..), AllowNewerDep(..), isAllowNewer,
configAbsolutePaths, readPackageDbList, showPackageDbList,
CopyFlags(..), emptyCopyFlags, defaultCopyFlags, copyCommand,
InstallFlags(..), emptyInstallFlags, defaultInstallFlags, installCommand,
Expand Down Expand Up @@ -86,11 +86,12 @@ import Distribution.Utils.NubList
import Distribution.Compat.Binary (Binary)
import Distribution.Compat.Semigroup as Semi

import Control.Monad (liftM)
import Data.List ( sort )
import Data.Maybe ( listToMaybe )
import Data.Char ( isSpace, isAlpha )
import GHC.Generics (Generic)
import Control.Applicative as A ( Applicative(..), (<*) )
import Control.Monad ( liftM )
import Data.List ( sort )
import Data.Maybe ( listToMaybe )
import Data.Char ( isSpace, isAlpha )
import GHC.Generics ( Generic )

-- FIXME Not sure where this should live
defaultDistPref :: FilePath
Expand Down Expand Up @@ -266,13 +267,29 @@ data AllowNewer =
AllowNewerNone

-- | Ignore upper bounds in dependencies on the given packages.
| AllowNewerSome [PackageName]
| AllowNewerSome [AllowNewerDep]

-- | Ignore upper bounds in dependencies on all packages.
| AllowNewerAll
deriving (Eq, Ord, Read, Show, Generic)
deriving (Read, Show, Generic)

-- | Dependencies can be relaxed either for all packages in the install plan, or
-- only for some packages.
data AllowNewerDep = AllowNewerDep PackageName
| AllowNewerDepScoped PackageName PackageName
deriving (Read, Show, Generic)

instance Text AllowNewerDep where
disp (AllowNewerDep p0) = disp p0
disp (AllowNewerDepScoped p0 p1) = disp p0 Disp.<> Disp.colon Disp.<> disp p1

parse = scopedP Parse.<++ normalP
where
scopedP = AllowNewerDepScoped `fmap` parse A.<* Parse.char ':' A.<*> parse
normalP = AllowNewerDep `fmap` parse

instance Binary AllowNewer
instance Binary AllowNewerDep

instance Semigroup AllowNewer where
AllowNewerNone <> r = r
Expand All @@ -291,19 +308,15 @@ isAllowNewer AllowNewerNone = False
isAllowNewer (AllowNewerSome _) = True
isAllowNewer AllowNewerAll = True

allowNewerParser :: ReadE AllowNewer
allowNewerParser = ReadE $ \s ->
case readPToMaybe pkgsParser s of
Just pkgs -> Right . AllowNewerSome $ pkgs
Nothing -> Left ("Cannot parse the list of packages: " ++ s)
where
pkgsParser = Parse.sepBy1 parse (Parse.char ',')
allowNewerParser :: Parse.ReadP r (Maybe AllowNewer)
allowNewerParser =
(Just . AllowNewerSome) `fmap` Parse.sepBy1 parse (Parse.char ',')

allowNewerPrinter :: AllowNewer -> [Maybe String]
allowNewerPrinter AllowNewerNone = []
allowNewerPrinter AllowNewerAll = [Nothing]
allowNewerPrinter (AllowNewerSome pkgs) =
[Just . intercalate "," . map display $ pkgs]
allowNewerPrinter :: (Maybe AllowNewer) -> [Maybe String]
allowNewerPrinter Nothing = []
allowNewerPrinter (Just AllowNewerNone) = []
allowNewerPrinter (Just AllowNewerAll) = [Nothing]
allowNewerPrinter (Just (AllowNewerSome pkgs)) = map (Just . display) $ pkgs

-- | Flags to @configure@ command.
--
Expand Down Expand Up @@ -375,8 +388,9 @@ data ConfigFlags = ConfigFlags {
-- ^Halt and show an error message indicating an error in flag assignment
configRelocatable :: Flag Bool, -- ^ Enable relocatable package built
configDebugInfo :: Flag DebugInfoLevel, -- ^ Emit debug info.
configAllowNewer :: AllowNewer -- ^ Ignore upper bounds on all or some
-- dependencies.
configAllowNewer :: Maybe AllowNewer
-- ^ Ignore upper bounds on all or some dependencies. Wrapped in 'Maybe' to
-- distinguish between "default" and "explicitly disabled".
}
deriving (Generic, Read, Show)

Expand Down Expand Up @@ -423,7 +437,7 @@ defaultConfigFlags progConf = emptyConfigFlags {
configFlagError = NoFlag,
configRelocatable = Flag False,
configDebugInfo = Flag NoDebugInfo,
configAllowNewer = AllowNewerNone
configAllowNewer = Nothing
}

configureCommand :: ProgramConfiguration -> CommandUI ConfigFlags
Expand Down Expand Up @@ -669,7 +683,9 @@ configureOptions showOrParseArgs =
,option [] ["allow-newer"]
("Ignore upper bounds in all dependencies or DEPS")
configAllowNewer (\v flags -> flags { configAllowNewer = v})
(optArg "DEPS" allowNewerParser AllowNewerAll allowNewerPrinter)
(optArg "DEPS"
(readP_to_E ("Cannot parse the list of packages: " ++) allowNewerParser)
(Just AllowNewerAll) allowNewerPrinter)

,option "" ["exact-configuration"]
"All direct dependencies and flags are provided on the command line."
Expand Down
22 changes: 20 additions & 2 deletions Cabal/doc/installing-packages.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -982,8 +982,26 @@ be controlled with the following command line options.
$ cabal install --allow-newer=bar --constraint="bar==2.1" foo
~~~~~~~~~~~~~~~~

It's also possible to enable `--allow-newer` permanently by setting
`allow-newer: True` in the `~/.cabal/config` file.
It's also possible to limit the scope of `--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 `--allow-newer` permanently by setting `allow-newer:
True` in the `~/.cabal/config` file. Enabling 'allow-newer' selectively is
also supported in the config file (`allow-newer: foo, bar, baz:base`).

`--constraint=`_constraint_
: Restrict solutions involving a package to a given version range.
Expand Down
9 changes: 9 additions & 0 deletions Cabal/tests/PackageTests/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,15 @@ nonSharedLibTests config =
shouldFail $ cabal "configure" ["--enable-benchmarks", "--enable-tests"]
cabal "configure" ["--enable-benchmarks", "--enable-tests"
,"--allow-newer"]
shouldFail $ cabal "configure" ["--allow-newer=Foo:base"]
shouldFail $ cabal "configure" ["--allow-newer=Foo:base"
,"--enable-tests", "--enable-benchmarks"]
cabal "configure" ["--allow-newer=AllowNewer:base"]
cabal "configure" ["--allow-newer=AllowNewer:base"
,"--allow-newer=Foo:base"]
cabal "configure" ["--allow-newer=AllowNewer:base"
,"--allow-newer=Foo:base"
,"--enable-tests", "--enable-benchmarks"]

-- Test that Cabal can choose flags to disable building a component when that
-- component's dependencies are unavailable. The build should succeed without
Expand Down
20 changes: 17 additions & 3 deletions cabal-install/Distribution/Client/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import Distribution.Simple.Compiler
( DebugInfoLevel(..), OptimisationLevel(..) )
import Distribution.Simple.Setup
( ConfigFlags(..), configureOptions, defaultConfigFlags
, AllowNewer(..)
, HaddockFlags(..), haddockOptions, defaultHaddockFlags
, installDirsOptions, optionDistPref
, programConfigurationPaths', programConfigurationOptions
Expand All @@ -75,7 +76,7 @@ import Distribution.ParseUtils
, locatedErrorMsg, showPWarning
, readFields, warning, lineNo
, simpleField, listField, spaceListField
, parseFilePathQ, parseTokenQ )
, parseFilePathQ, parseOptCommaList, parseTokenQ )
import Distribution.Client.ParseUtils
( parseFields, ppFields, ppSection )
import Distribution.Client.HttpUtils
Expand Down Expand Up @@ -107,7 +108,7 @@ import Data.Monoid
import Control.Monad
( when, unless, foldM, liftM, liftM2 )
import qualified Distribution.Compat.ReadP as Parse
( option )
( (<++), option )
import Distribution.Compat.Semigroup
( Semigroup((<>)) )
import qualified Text.PrettyPrint as Disp
Expand Down Expand Up @@ -639,7 +640,8 @@ commentSavedConfig = do
savedInstallFlags = defaultInstallFlags,
savedConfigureExFlags = defaultConfigExFlags,
savedConfigureFlags = (defaultConfigFlags defaultProgramConfiguration) {
configUserInstall = toFlag defaultUserInstall
configUserInstall = toFlag defaultUserInstall,
configAllowNewer = Just AllowNewerNone
},
savedUserInstallDirs = fmap toFlag userInstallDirs,
savedGlobalInstallDirs = fmap toFlag globalInstallDirs,
Expand Down Expand Up @@ -668,6 +670,18 @@ configFieldDescriptions src =
[simpleField "compiler"
(fromFlagOrDefault Disp.empty . fmap Text.disp) (optional Text.parse)
configHcFlavor (\v flags -> flags { configHcFlavor = v })
,let showAllowNewer Nothing = mempty
showAllowNewer (Just AllowNewerNone) = Disp.text "False"
showAllowNewer (Just _) = Disp.text "True"

toAllowNewer True = Just AllowNewerAll
toAllowNewer False = Just AllowNewerNone

pkgs = (Just . AllowNewerSome) `fmap` parseOptCommaList Text.parse
parseAllowNewer = (toAllowNewer `fmap` Text.parse) Parse.<++ pkgs in
simpleField "allow-newer"
showAllowNewer parseAllowNewer
configAllowNewer (\v flags -> flags { configAllowNewer = v })
-- TODO: The following is a temporary fix. The "optimization"
-- and "debug-info" fields are OptArg, and viewAsFieldDescr
-- fails on that. Instead of a hand-written hackaged parser
Expand Down
9 changes: 6 additions & 3 deletions cabal-install/Distribution/Client/Configure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ import Distribution.Simple.Compiler
( Compiler, CompilerInfo, compilerInfo, PackageDB(..), PackageDBStack )
import Distribution.Simple.Program (ProgramConfiguration )
import Distribution.Simple.Setup
( ConfigFlags(..), fromFlag, toFlag, flagToMaybe, fromFlagOrDefault )
( ConfigFlags(..), AllowNewer(..)
, fromFlag, toFlag, flagToMaybe, fromFlagOrDefault )
import Distribution.Simple.PackageIndex
( InstalledPackageIndex, lookupPackageName )
import Distribution.Simple.Utils
Expand Down Expand Up @@ -86,7 +87,8 @@ chooseCabalVersion configFlags maybeVersion =
where
-- Cabal < 1.19.2 doesn't support '--exact-configuration' which is needed
-- for '--allow-newer' to work.
allowNewer = isAllowNewer (configAllowNewer configFlags)
allowNewer = isAllowNewer
(fromMaybe AllowNewerNone $ configAllowNewer configFlags)

defaultVersionRange = if allowNewer
then orLaterVersion (Version [1,19,2] [])
Expand Down Expand Up @@ -288,7 +290,8 @@ planLocalPackage verbosity comp platform configFlags configExFlags
fromFlagOrDefault False $ configBenchmarks configFlags

resolverParams =
removeUpperBounds (configAllowNewer configFlags)
removeUpperBounds
(fromMaybe AllowNewerNone $ configAllowNewer configFlags)

. addPreferences
-- preferences from the config file or command line
Expand Down
3 changes: 2 additions & 1 deletion cabal-install/Distribution/Client/Install.hs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import qualified Distribution.Simple.Configure as Configure
import Distribution.Simple.Setup
( haddockCommand, HaddockFlags(..)
, buildCommand, BuildFlags(..), emptyBuildFlags
, AllowNewer(..)
, toFlag, fromFlag, fromFlagOrDefault, flagToMaybe, defaultDistPref )
import qualified Distribution.Simple.Setup as Cabal
( Flag(..)
Expand Down Expand Up @@ -417,7 +418,7 @@ planPackages comp platform mSandboxPkgInfo solver
maxBackjumps = fromFlag (installMaxBackjumps installFlags)
upgradeDeps = fromFlag (installUpgradeDeps installFlags)
onlyDeps = fromFlag (installOnlyDeps installFlags)
allowNewer = (configAllowNewer configFlags)
allowNewer = fromMaybe AllowNewerNone (configAllowNewer configFlags)

-- | Remove the provided targets from the install plan.
pruneInstallPlan :: Package targetpkg
Expand Down
2 changes: 1 addition & 1 deletion cabal-install/Distribution/Client/Setup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ filterConfigureFlags flags cabalLibVersion
configConstraints = [],
-- Passing '--allow-newer' to Setup.hs is unnecessary, we use
-- '--exact-configuration' instead.
configAllowNewer = Cabal.AllowNewerNone
configAllowNewer = Just Cabal.AllowNewerNone
}

-- Cabal < 1.23 doesn't know about '--profiling-detail'.
Expand Down
4 changes: 4 additions & 0 deletions cabal-install/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
* New config file field: 'extra-framework-dirs' (extra locations
to find OS X frameworks in). Can be also specified as an argument
for 'install' and 'configure' commands (#3158).
* It's now possible to limit the scope of '--allow-newer' to
single packages in the install plan (#2756).
* Full '--allow-newer' syntax is now supported in the config file
(that is, 'allow-newer: base, ghc-prim, some-package:vector') (#3171).

1.22.0.0 Johan Tibell <johan.tibell@gmail.com> January 2015
* New command: user-config (#2159).
Expand Down