diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal index 62ff7e99e42338d39e6118973508392a00258f03..8e9181bfbd5be4d08ed9999e0aa8df563dd949ed 100644 --- a/Cabal/Cabal.cabal +++ b/Cabal/Cabal.cabal @@ -59,6 +59,8 @@ extra-source-files: tests/ParserTests/errors/noVersion2.errors tests/ParserTests/errors/range-ge-wild.cabal tests/ParserTests/errors/range-ge-wild.errors + tests/ParserTests/errors/removed-fields.cabal + tests/ParserTests/errors/removed-fields.errors tests/ParserTests/errors/spdx-1.cabal tests/ParserTests/errors/spdx-1.errors tests/ParserTests/errors/spdx-2.cabal diff --git a/Cabal/Distribution/FieldGrammar/Class.hs b/Cabal/Distribution/FieldGrammar/Class.hs index 9400e04085f7d84804bd1d3e26a222fdcdfc43b2..ef895198e74f33845c8473bfccd1f6af4caf65bb 100644 --- a/Cabal/Distribution/FieldGrammar/Class.hs +++ b/Cabal/Distribution/FieldGrammar/Class.hs @@ -95,6 +95,13 @@ class FieldGrammar g where -> g s a -> g s a + -- | Removed in. If we occur removed field, parsing fails. + removedIn + :: CabalSpecVersion -- ^ version + -> String -- ^ removal message + -> g s a + -> g s a + -- | Annotate field with since spec-version. availableSince :: CabalSpecVersion -- ^ spec version diff --git a/Cabal/Distribution/FieldGrammar/FieldDescrs.hs b/Cabal/Distribution/FieldGrammar/FieldDescrs.hs index 4bd50d4604b020c025dc32c5106056763e2cd32f..e1e44a20898f7db48f6469ed85a0729e05190a77 100644 --- a/Cabal/Distribution/FieldGrammar/FieldDescrs.hs +++ b/Cabal/Distribution/FieldGrammar/FieldDescrs.hs @@ -82,5 +82,6 @@ instance FieldGrammar FieldDescrs where prefixedFields _fnPfx _l = F mempty knownField _ = pure () deprecatedSince _ _ x = x + removedIn _ _ x = x availableSince _ _ = id hiddenField _ = F mempty diff --git a/Cabal/Distribution/FieldGrammar/Parsec.hs b/Cabal/Distribution/FieldGrammar/Parsec.hs index 7ec44690ae4e7a16483bca92f52749c91b8b1a79..c6834e81f8c5277a29c2bc916f7f388bf62659c2 100644 --- a/Cabal/Distribution/FieldGrammar/Parsec.hs +++ b/Cabal/Distribution/FieldGrammar/Parsec.hs @@ -72,8 +72,8 @@ import Distribution.Simple.Utils (fromUTF8BS) import Prelude () import qualified Data.ByteString as BS -import qualified Data.Set as Set import qualified Data.Map.Strict as Map +import qualified Data.Set as Set import qualified Text.Parsec as P import qualified Text.Parsec.Error as P @@ -253,8 +253,33 @@ instance FieldGrammar ParsecFieldGrammar where "The field " <> show name <> " is deprecated in the Cabal specification version " ++ showCabalSpecVersion vs ++ ". " ++ msg parser v values + | otherwise = parser v values + removedIn vs msg (ParsecFG names prefixes parser) = ParsecFG names prefixes parser' where + parser' v values + | v >= vs = do + let msg' = if null msg then "" else ' ' : msg + let unknownFields = Map.intersection values $ Map.fromSet (const ()) names + let namePos = + [ (name, pos) + | (name, fields) <- Map.toList unknownFields + , MkNamelessField pos _ <- fields + ] + + let makeMsg name = "The field " <> show name <> " is removed in the Cabal specification version " ++ showCabalSpecVersion vs ++ "." ++ msg' + + case namePos of + -- no fields => proceed (with empty values, to be sure) + [] -> parser v mempty + + -- if there's single field: fail fatally with it + ((name, pos) : rest) -> do + for_ rest $ \(name', pos') -> parseFailure pos' $ makeMsg name' + parseFatalFailure pos $ makeMsg name + + | otherwise = parser v values + knownField fn = ParsecFG (Set.singleton fn) Set.empty (\_ _ -> pure ()) hiddenField = id diff --git a/Cabal/Distribution/FieldGrammar/Pretty.hs b/Cabal/Distribution/FieldGrammar/Pretty.hs index d6180f738978456f28e905313897ebb75edd93bc..894fb3628743ce35f220e4a7580a289ac8bb9bfc 100644 --- a/Cabal/Distribution/FieldGrammar/Pretty.hs +++ b/Cabal/Distribution/FieldGrammar/Pretty.hs @@ -75,7 +75,11 @@ instance FieldGrammar PrettyFieldGrammar where ] knownField _ = pure () - deprecatedSince _ _ x = x + deprecatedSince _ _ x = x + -- TODO: as PrettyFieldGrammar isn't aware of cabal-version: we output the field + -- this doesn't affect roundtrip as `removedIn` fields cannot be parsed + -- so invalid documents can be only manually constructed. + removedIn _ _ x = x availableSince _ _ = id hiddenField _ = PrettyFG (\_ -> mempty) diff --git a/Cabal/Distribution/PackageDescription/FieldGrammar.hs b/Cabal/Distribution/PackageDescription/FieldGrammar.hs index 9fb1fc70b50688a1e02043b0313e3ad6dfa1aa73..f10ac16828b14f77a6645ee5d1f75c23b199fd2f 100644 --- a/Cabal/Distribution/PackageDescription/FieldGrammar.hs +++ b/Cabal/Distribution/PackageDescription/FieldGrammar.hs @@ -380,6 +380,8 @@ buildInfoFieldGrammar = BuildInfo <*> monoidalFieldAla "build-tools" (alaList CommaFSep) L.buildTools ^^^ deprecatedSince CabalSpecV2_0 "Please use 'build-tool-depends' field" + ^^^ removedIn CabalSpecV3_0 + "Please use 'build-tool-depends' field." <*> monoidalFieldAla "build-tool-depends" (alaList CommaFSep) L.buildToolDepends -- {- ^^^ availableSince [2,0] [] -} -- here, we explicitly want to recognise build-tool-depends for all Cabal files @@ -414,6 +416,8 @@ buildInfoFieldGrammar = BuildInfo <*> monoidalFieldAla "extensions" (alaList' FSep MQuoted) L.oldExtensions ^^^ deprecatedSince CabalSpecV1_12 "Please use 'default-extensions' or 'other-extensions' fields." + ^^^ removedIn CabalSpecV3_0 + "Please use 'default-extensions' or 'other-extensions' fields." <*> monoidalFieldAla "extra-libraries" (alaList' VCat Token) L.extraLibs <*> monoidalFieldAla "extra-ghci-libraries" (alaList' VCat Token) L.extraGHCiLibs <*> monoidalFieldAla "extra-bundled-libraries" (alaList' VCat Token) L.extraBundledLibs @@ -443,6 +447,7 @@ hsSourceDirsGrammar = (++) <*> monoidalFieldAla "hs-source-dir" (alaList' FSep FilePathNT) wrongLens --- https://github.com/haskell/cabal/commit/49e3cdae3bdf21b017ccd42e66670ca402e22b44 ^^^ deprecatedSince CabalSpecV1_2 "Please use 'hs-source-dirs'" + ^^^ removedIn CabalSpecV3_0 "Please use 'hs-source-dirs' field." where -- TODO: make pretty printer aware of CabalSpecVersion wrongLens :: Functor f => LensLike' f BuildInfo [FilePath] diff --git a/Cabal/doc/cabaldomain.py b/Cabal/doc/cabaldomain.py index fd2f1846bd207dce65a59d495ca282f92315346b..d0cc9d3e17d783250662e51e2061b4e41b24b110 100644 --- a/Cabal/doc/cabaldomain.py +++ b/Cabal/doc/cabaldomain.py @@ -13,7 +13,10 @@ Most directives have at least following optional arguments `:deprecated: 1.24` `:deprecated:` - Feature was deprecatead, and optionally since which version. + Feature was deprecated, and optionally since which version. + +`:removed: 3.0` + Feature was removed `:synopsis: Short desc` Text used as short description on reference page. @@ -164,12 +167,14 @@ class Meta(object): def __init__(self, since=None, deprecated=None, + removed=None, synopsis=None, title=None, section=None, index=0): self.since = since self.deprecated = deprecated + self.removed = removed self.synopsis = synopsis self.title = title self.section = section @@ -213,6 +218,7 @@ class CabalSection(Directive): option_spec = { 'name': lambda x: x, 'deprecated': parse_deprecated, + 'removed': StrictVersion, 'since' : StrictVersion, 'synopsis' : lambda x:x, } @@ -259,6 +265,7 @@ class CabalSection(Directive): meta = Meta(since=self.options.get('since'), deprecated=self.options.get('deprecated'), + removed=self.options.get('removed'), synopsis=self.options.get('synopsis'), index = num, title = title) @@ -274,6 +281,7 @@ class CabalObject(ObjectDescription): option_spec = { 'noindex' : directives.flag, 'deprecated': parse_deprecated, + 'removed' : StrictVersion, 'since' : StrictVersion, 'synopsis' : lambda x:x } @@ -299,6 +307,7 @@ class CabalObject(ObjectDescription): title = find_section_title(self.state.parent) return Meta(since=self.options.get('since'), deprecated=self.options.get('deprecated'), + removed=self.options.get('removed'), title=title, index = num, synopsis=self.options.get('synopsis')) @@ -409,6 +418,18 @@ class CabalObject(ObjectDescription): field += field_body field_list.insert(0, field) + if self.cabal_meta.removed is not None: + field = nodes.field('') + field_name = nodes.field_name('Removed', 'Removed') + if isinstance(self.cabal_meta.removed, StrictVersion): + since = 'Cabal ' + str(self.cabal_meta.removed) + else: + since = '' + + field_body = nodes.field_body(since, nodes.paragraph(since, since)) + field += field_name + field += field_body + field_list.insert(0, field) return result class CabalPackageSection(CabalObject): @@ -459,6 +480,7 @@ class CabalField(CabalObject): option_spec = { 'noindex' : directives.flag, 'deprecated': parse_deprecated, + 'removed' : StrictVersion, 'since' : StrictVersion, 'synopsis' : lambda x:x } @@ -702,6 +724,11 @@ def render_deprecated(deprecated): else: return 'deprecated' +def render_removed(deprecated, removed): + if isinstance(deprecated, StrictVersion): + return 'removed in: ' + str(removed) + '; deprecated since: '+str(deprecated) + else: + return 'removed in: ' + str(removed) def render_meta(meta): ''' @@ -709,6 +736,8 @@ def render_meta(meta): Will render either deprecated or since info ''' + if meta.removed is not None: + return render_removed(meta.deprecated, meta.removed) if meta.deprecated is not None: return render_deprecated(meta.deprecated) elif meta.since is not None: diff --git a/Cabal/doc/developing-packages.rst b/Cabal/doc/developing-packages.rst index 3a2f65235015788fcb90e47c8ef155f4c9846f53..1ee81d94ea154eaf668c97c4850c4f5f49f80149 100644 --- a/Cabal/doc/developing-packages.rst +++ b/Cabal/doc/developing-packages.rst @@ -2173,7 +2173,8 @@ system-dependent values for these fields. :pkg-field:`other-extensions` declarations. .. pkg-field:: extensions: identifier list - :deprecated: + :deprecated: 1.12 + :removed: 3.0 Deprecated in favor of :pkg-field:`default-extensions`. @@ -2230,7 +2231,8 @@ system-dependent values for these fields. compatibility. .. pkg-field:: build-tools: program list - :deprecated: + :deprecated: 2.0 + :removed: 3.0 Deprecated in favor of :pkg-field:`build-tool-depends`, but :ref:`see below for backwards compatibility information <buildtoolsbc>`. diff --git a/Cabal/doc/file-format-changelog.rst b/Cabal/doc/file-format-changelog.rst index e0745622917fdff3c40e2b2d53055c4a1ec0d00a..ef26050520af2bdb8988f4801c20f646eecd422a 100644 --- a/Cabal/doc/file-format-changelog.rst +++ b/Cabal/doc/file-format-changelog.rst @@ -22,13 +22,16 @@ relative to the respective preceding *published* version. ``cabal-version: 3.0`` ---------------------- -* Added the `extra-dynamic-library-flavours` field to specify non-trivial - variants of dynamic flavours. It is `extra-library-flavours` but for +* Added the :pkg-field:`extra-dynamic-library-flavours` field to specify non-trivial + variants of dynamic flavours. It is :pkg-field:`extra-library-flavours` but for shared libraries. Mainly useful for GHC's RTS library. * License fields use identifiers from SPDX License List version ``3.3 2018-10-24`` +* Remove deprecated ``hs-source-dir``, :pkg-field:`extensions` and + :pkg-field:`build-tools` fields. + ``cabal-version: 2.4`` ---------------------- diff --git a/Cabal/tests/ParserTests.hs b/Cabal/tests/ParserTests.hs index c1df7d46e3eebd6da6d9d76131fb59a8fd2a16db..4a5a7430adea1c2d8e581732aac92bd3007570f8 100644 --- a/Cabal/tests/ParserTests.hs +++ b/Cabal/tests/ParserTests.hs @@ -106,6 +106,7 @@ errorTests = testGroup "errors" , errorTest "spdx-1.cabal" , errorTest "spdx-2.cabal" , errorTest "spdx-3.cabal" + , errorTest "removed-fields.cabal" ] errorTest :: FilePath -> TestTree diff --git a/Cabal/tests/ParserTests/errors/removed-fields.cabal b/Cabal/tests/ParserTests/errors/removed-fields.cabal new file mode 100644 index 0000000000000000000000000000000000000000..dbee53f75444718f8c8d33d37f435f47ec41aa5f --- /dev/null +++ b/Cabal/tests/ParserTests/errors/removed-fields.cabal @@ -0,0 +1,14 @@ +cabal-version: 2.5 +name: removed-fields +version: 0 +synopsis: some fields are removed +build-type: Simple + +library + default-language: Haskell2010 + exposed-modules: RemovedFields + + build-depends: base, containers + + extensions: CPP + extensions: DeriveFunctor diff --git a/Cabal/tests/ParserTests/errors/removed-fields.errors b/Cabal/tests/ParserTests/errors/removed-fields.errors new file mode 100644 index 0000000000000000000000000000000000000000..e41a0aee8266050b380668d68e94251e6a9536ed --- /dev/null +++ b/Cabal/tests/ParserTests/errors/removed-fields.errors @@ -0,0 +1,3 @@ +VERSION: Just (mkVersion [2,5]) +removed-fields.cabal:13:3: The field "extensions" is removed in the Cabal specification version 3.0. Please use 'default-extensions' or 'other-extensions' fields. +removed-fields.cabal:14:3: The field "extensions" is removed in the Cabal specification version 3.0. Please use 'default-extensions' or 'other-extensions' fields.