Skip to content

Commit e92d657

Browse files
committed
Parse Bool fields using more cunning, allow new parses with a warning
We want to allow case-insensitive parsing however we don't want packages being uploaded to hackage that will break older versions of Cabal. If we allow new valid parses then we will end up breaking stuff. So what we really want to do is allow new parses but warn if they're not ones that older versions of Cabal would have allowed. So long as hackage rejects pakcages that have parse warnings then we can prevent new .cabal files appearing on hackage that would break older Cabal versions. Our current parser (ReadP) does not support warnings so we have to handle the bool fields specially in the parser wrapper layer that we added to handle errors and warnings. This can go away when we use a parser with support for error and warning messages.
1 parent 75867d1 commit e92d657

3 files changed

Lines changed: 24 additions & 9 deletions

File tree

Distribution/InstalledPackageInfo.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ import Distribution.ParseUtils (
5858
FieldDescr(..), readFields, ParseResult(..), PError(..), PWarning,
5959
Field(F), simpleField, listField, parseLicenseQ, ppField, ppFields,
6060
parseFilePathQ, parseTokenQ, parseModuleNameQ, parsePackageNameQ,
61-
showFilePath, showToken, parseOptVersion, parseQuoted,
61+
showFilePath, showToken, boolField, parseOptVersion, parseQuoted,
6262
showFreeText)
6363
import Distribution.License ( License(..) )
6464
import Distribution.Package
@@ -238,8 +238,7 @@ parseFreeText = ReadP.munch (const True)
238238

239239
installedFieldDescrs :: [FieldDescr InstalledPackageInfo]
240240
installedFieldDescrs = [
241-
simpleField "exposed"
242-
disp parse
241+
boolField "exposed"
243242
exposed (\val pkg -> pkg{exposed=val})
244243
, listField "exposed-modules"
245244
text parseModuleNameQ

Distribution/PackageDescription/Parse.hs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,7 @@ storeXFieldsExe _ _ = Nothing
201201

202202
binfoFieldDescrs :: [FieldDescr BuildInfo]
203203
binfoFieldDescrs =
204-
[ simpleField "buildable"
205-
disp parse
204+
[ boolField "buildable"
206205
buildable (\val binfo -> binfo{buildable=val})
207206
, commaListField "build-tools"
208207
disp parseBuildTool
@@ -276,8 +275,7 @@ flagFieldDescrs =
276275
[ simpleField "description"
277276
showFreeText (munch (const True))
278277
flagDescription (\val fl -> fl{ flagDescription = val })
279-
, simpleField "default"
280-
disp parse
278+
, boolField "default"
281279
flagDefault (\val fl -> fl{ flagDefault = val })
282280
]
283281

Distribution/ParseUtils.hs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ module Distribution.ParseUtils (
5555
parseSepList, parseCommaList, parseOptCommaList,
5656
showFilePath, showToken, showTestedWith, showFreeText,
5757
field, simpleField, listField, commaListField, optsField, liftField,
58-
parseQuoted,
58+
boolField, parseQuoted,
5959

6060
UnrecFieldParser, warnUnrec, ignoreUnrec,
6161
) where
@@ -68,7 +68,7 @@ import Distribution.Compat.ReadP as ReadP hiding (get)
6868
import Distribution.ReadE
6969
import Distribution.Text
7070
( Text(..) )
71-
import Distribution.Simple.Utils (intercalate)
71+
import Distribution.Simple.Utils (intercalate, lowercase)
7272
import Language.Haskell.Extension (Extension)
7373

7474
import Text.PrettyPrint.HughesPJ hiding (braces)
@@ -206,6 +206,24 @@ optsField name flavor get set =
206206
| f == f' = (f, opts ++ opts') : rest
207207
| otherwise = (f',opts') : update f opts rest
208208

209+
-- TODO: this is a bit smelly hack. It's because we want to parse bool fields
210+
-- liberally but not accept new parses. We cannot do that with ReadP
211+
-- because it does not support warnings. We need a new parser framwork!
212+
boolField :: String -> (b -> Bool) -> (Bool -> b -> b) -> FieldDescr b
213+
boolField name get set = liftField get set (FieldDescr name showF readF)
214+
where
215+
showF = text . show
216+
readF line str _
217+
| str == "True" = ParseOk [] True
218+
| str == "False" = ParseOk [] False
219+
| lstr == "true" = ParseOk [caseWarning] True
220+
| lstr == "false" = ParseOk [caseWarning] False
221+
| otherwise = ParseFailed (NoParse name line)
222+
where
223+
lstr = lowercase str
224+
caseWarning = PWarning
225+
"Bool fields are case sensitive, use 'True' or 'False'."
226+
209227
ppFields :: a -> [FieldDescr a] -> Doc
210228
ppFields _ [] = empty
211229
ppFields pkg' ((FieldDescr name getter _):flds) =

0 commit comments

Comments
 (0)