Check.hs 65 KB
Newer Older
1
2
3
4
-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.PackageDescription.Check
-- Copyright   :  Lennart Kolmodin 2008
5
-- License     :  BSD3
6
--
Duncan Coutts's avatar
Duncan Coutts committed
7
-- Maintainer  :  cabal-devel@haskell.org
8
9
-- Portability :  portable
--
Duncan Coutts's avatar
Duncan Coutts committed
10
11
12
13
14
15
16
17
-- This has code for checking for various problems in packages. There is one
-- set of checks that just looks at a 'PackageDescription' in isolation and
-- another set of checks that also looks at files in the package. Some of the
-- checks are basic sanity checks, others are portability standards that we'd
-- like to encourage. There is a 'PackageCheck' type that distinguishes the
-- different kinds of check so we can see which ones are appropriate to report
-- in different situations. This code gets uses when configuring a package when
-- we consider only basic problems. The higher standard is uses when when
Ian D. Bollinger's avatar
Ian D. Bollinger committed
18
-- preparing a source tarball and by Hackage when uploading new packages. The
Duncan Coutts's avatar
Duncan Coutts committed
19
20
21
-- reason for this is that we want to hold packages that are expected to be
-- distributed to a higher standard than packages that are only ever expected
-- to be used on the author's own environment.
22
23
24
25
26

module Distribution.PackageDescription.Check (
        -- * Package Checking
        PackageCheck(..),
        checkPackage,
27
        checkConfiguredPackage,
28
29
30
31
32

        -- ** Checking package contents
        checkPackageFiles,
        checkPackageContent,
        CheckPackageContentOps(..),
33
        checkPackageFileNames,
34
35
  ) where

36
37
import Data.Maybe
         ( isNothing, isJust, catMaybes, maybeToList, fromMaybe )
38
import Data.List  (sort, group, isPrefixOf, nub, find)
39
40
41
42
import Control.Monad
         ( filterM, liftM )
import qualified System.Directory as System
         ( doesFileExist, doesDirectoryExist )
43
import qualified Data.Map as Map
44
45

import Distribution.PackageDescription
46
import Distribution.PackageDescription.Configuration
47
         ( flattenPackageDescription, finalizePackageDescription )
48
import Distribution.Compiler
49
         ( CompilerFlavor(..), buildCompilerFlavor, CompilerId(..) )
50
import Distribution.System
51
         ( OS(..), Arch(..), buildPlatform )
52
import Distribution.License
53
         ( License(..), knownLicenses )
54
55
import Distribution.Simple.CCompiler
         ( filenameCDialect )
56
import Distribution.Simple.Utils
57
         ( cabalVersion, intercalate, parseFileGlob, FileGlob(..), lowercase )
58

59
import Distribution.Version
60
         ( Version(..)
61
         , VersionRange(..), foldVersionRange'
62
         , anyVersion, noVersion, thisVersion, laterVersion, earlierVersion
63
64
         , orLaterVersion, orEarlierVersion
         , unionVersionRanges, intersectVersionRanges
65
         , asVersionIntervals, UpperBound(..), isNoVersion )
66
import Distribution.Package
67
         ( PackageName(PackageName), packageName, packageVersion
EyalLotem's avatar
EyalLotem committed
68
         , Dependency(..), pkgName )
69

70
import Distribution.Text
71
72
73
74
         ( display, disp )
import qualified Text.PrettyPrint as Disp
import Text.PrettyPrint ((<>), (<+>))

75
76
import qualified Language.Haskell.Extension as Extension (deprecatedExtensions)
import Language.Haskell.Extension
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
77
78
         ( Language(UnknownLanguage), knownLanguages
         , Extension(..), KnownExtension(..) )
79
import System.FilePath
80
81
         ( (</>), takeExtension, isRelative, isAbsolute
         , splitDirectories,  splitPath )
82
83
import System.FilePath.Windows as FilePath.Windows
         ( isValid )
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

-- | Results of some kind of failed package check.
--
-- There are a range of severities, from merely dubious to totally insane.
-- All of them come with a human readable explanation. In future we may augment
-- them with more machine readable explanations, for example to help an IDE
-- suggest automatic corrections.
--
data PackageCheck =

       -- | This package description is no good. There's no way it's going to
       -- build sensibly. This should give an error at configure time.
       PackageBuildImpossible { explanation :: String }

       -- | A problem that is likely to affect building the package, or an
       -- issue that we'd like every package author to be aware of, even if
       -- the package is never distributed.
     | PackageBuildWarning { explanation :: String }

       -- | An issue that might not be a problem for the package author but
Ian D. Bollinger's avatar
Ian D. Bollinger committed
104
       -- might be annoying or detrimental when the package is distributed to
105
106
107
108
109
       -- users. We should encourage distributed packages to be free from these
       -- issues, but occasionally there are justifiable reasons so we cannot
       -- ban them entirely.
     | PackageDistSuspicious { explanation :: String }

Ian D. Bollinger's avatar
Ian D. Bollinger committed
110
       -- | An issue that is OK in the author's environment but is almost
111
112
113
114
       -- certain to be a portability problem for other environments. We can
       -- quite legitimately refuse to publicly distribute packages with these
       -- problems.
     | PackageDistInexcusable { explanation :: String }
115
  deriving (Eq)
116
117
118
119
120
121
122
123

instance Show PackageCheck where
    show notice = explanation notice

check :: Bool -> PackageCheck -> Maybe PackageCheck
check False _  = Nothing
check True  pc = Just pc

Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
124
125
checkSpecVersion :: PackageDescription -> [Int] -> Bool -> PackageCheck
                 -> Maybe PackageCheck
126
127
128
129
130
checkSpecVersion pkg specver cond pc
  | specVersion pkg >= Version specver [] = Nothing
  | otherwise                             = check cond pc


131
132
133
134
135
136
-- ------------------------------------------------------------
-- * Standard checks
-- ------------------------------------------------------------

-- | Check for common mistakes and problems in package descriptions.
--
Ian D. Bollinger's avatar
Ian D. Bollinger committed
137
-- This is the standard collection of checks covering all aspects except
138
139
140
-- for checks that require looking at files within the package. For those
-- see 'checkPackageFiles'.
--
141
142
143
144
145
146
147
148
149
-- It requires the 'GenericPackageDescription' and optionally a particular
-- configuration of that package. If you pass 'Nothing' then we just check
-- a version of the generic description using 'flattenPackageDescription'.
--
checkPackage :: GenericPackageDescription
             -> Maybe PackageDescription
             -> [PackageCheck]
checkPackage gpkg mpkg =
     checkConfiguredPackage pkg
150
  ++ checkConditionals gpkg
151
  ++ checkPackageVersions gpkg
152
153
154
155
  where
    pkg = fromMaybe (flattenPackageDescription gpkg) mpkg

--TODO: make this variant go away
refold's avatar
Typo.    
refold committed
156
--      we should always know the GenericPackageDescription
157
158
checkConfiguredPackage :: PackageDescription -> [PackageCheck]
checkConfiguredPackage pkg =
159
160
161
    checkSanity pkg
 ++ checkFields pkg
 ++ checkLicense pkg
162
 ++ checkSourceRepos pkg
163
 ++ checkGhcOptions pkg
Duncan Coutts's avatar
Duncan Coutts committed
164
 ++ checkCCOptions pkg
165
 ++ checkCPPOptions pkg
166
 ++ checkPaths pkg
167
 ++ checkCabalVersion pkg
168
169
170
171
172
173
174
175
176
177
178
179


-- ------------------------------------------------------------
-- * Basic sanity checks
-- ------------------------------------------------------------

-- | Check that this package description is sane.
--
checkSanity :: PackageDescription -> [PackageCheck]
checkSanity pkg =
  catMaybes [

Duncan Coutts's avatar
Duncan Coutts committed
180
    check (null . (\(PackageName n) -> n) . packageName $ pkg) $
181
182
      PackageBuildImpossible "No 'name' field."

183
  , check (null . versionBranch . packageVersion $ pkg) $
184
185
186
187
188
      PackageBuildImpossible "No 'version' field."

  , check (null (executables pkg) && isNothing (library pkg)) $
      PackageBuildImpossible
        "No executables and no library found. Nothing to do."
189

tibbe's avatar
tibbe committed
190
191
192
193
  , check (not (null duplicateNames)) $
      PackageBuildImpossible $ "Duplicate sections: " ++ commaSep duplicateNames
        ++ ". The name of every executable, test suite, and benchmark section in"
        ++ " the package must be unique."
194
  ]
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
195
196
  --TODO: check for name clashes case insensitively: windows file systems cannot
  --cope.
197

198
199
200
201
  ++ maybe []  (checkLibrary    pkg) (library pkg)
  ++ concatMap (checkExecutable pkg) (executables pkg)
  ++ concatMap (checkTestSuite  pkg) (testSuites pkg)
  ++ concatMap (checkBenchmark  pkg) (benchmarks pkg)
202
203
204

  ++ catMaybes [

205
    check (specVersion pkg > cabalVersion) $
206
      PackageBuildImpossible $
207
208
209
           "This package description follows version "
        ++ display (specVersion pkg) ++ " of the Cabal specification. This "
        ++ "tool only supports up to version " ++ display cabalVersion ++ "."
210
  ]
211
  where
212
    exeNames = map exeName $ executables pkg
213
    testNames = map testName $ testSuites pkg
tibbe's avatar
tibbe committed
214
215
    bmNames = map benchmarkName $ benchmarks pkg
    duplicateNames = dups $ exeNames ++ testNames ++ bmNames
216

217
218
checkLibrary :: PackageDescription -> Library -> [PackageCheck]
checkLibrary _pkg lib =
219
220
  catMaybes [

221
    check (not (null moduleDuplicates)) $
222
       PackageBuildImpossible $
223
224
            "Duplicate modules in library: "
         ++ commaSep (map display moduleDuplicates)
225
226
  ]

227
  where
228
    moduleDuplicates = dups (libModules lib ++
229
                             map moduleReexportName (reexportedModules lib))
Duncan Coutts's avatar
Duncan Coutts committed
230

231
232
checkExecutable :: PackageDescription -> Executable -> [PackageCheck]
checkExecutable pkg exe =
233
234
235
236
  catMaybes [

    check (null (modulePath exe)) $
      PackageBuildImpossible $
237
        "No 'main-is' field found for executable " ++ exeName exe
238
239

  , check (not (null (modulePath exe))
240
       && (not $ fileExtensionSupportedLanguage $ modulePath exe)) $
241
      PackageBuildImpossible $
242
243
244
           "The 'main-is' field must specify a '.hs' or '.lhs' file "
        ++ "(even if it is generated by a preprocessor), "
        ++ "or it may specify a C/C++/obj-C source file."
Duncan Coutts's avatar
Duncan Coutts committed
245

246
247
248
249
250
251
252
  , checkSpecVersion pkg [1,17]
          (fileExtensionSupportedLanguage (modulePath exe)
        && takeExtension (modulePath exe) `notElem` [".hs", ".lhs"]) $
      PackageDistInexcusable $
           "The package uses a C/C++/obj-C source file for the 'main-is' field. "
        ++ "To use this feature you must specify 'cabal-version: >= 1.18'."

Duncan Coutts's avatar
Duncan Coutts committed
253
  , check (not (null moduleDuplicates)) $
254
       PackageBuildImpossible $
Duncan Coutts's avatar
Duncan Coutts committed
255
            "Duplicate modules in executable '" ++ exeName exe ++ "': "
256
         ++ commaSep (map display moduleDuplicates)
257
  ]
258
259
  where
    moduleDuplicates = dups (exeModules exe)
260

261
262
checkTestSuite :: PackageDescription -> TestSuite -> [PackageCheck]
checkTestSuite pkg test =
263
264
  catMaybes [

265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
    case testInterface test of
      TestSuiteUnsupported tt@(TestTypeUnknown _ _) -> Just $
        PackageBuildWarning $
             quote (display tt) ++ " is not a known type of test suite. "
          ++ "The known test suite types are: "
          ++ commaSep (map display knownTestTypes)

      TestSuiteUnsupported tt -> Just $
        PackageBuildWarning $
             quote (display tt) ++ " is not a supported test suite version. "
          ++ "The known test suite types are: "
          ++ commaSep (map display knownTestTypes)
      _ -> Nothing

  , check (not $ null moduleDuplicates) $
280
      PackageBuildImpossible $
281
           "Duplicate modules in test suite '" ++ testName test ++ "': "
282
        ++ commaSep (map display moduleDuplicates)
283

284
285
286
  , check mainIsWrongExt $
      PackageBuildImpossible $
           "The 'main-is' field must specify a '.hs' or '.lhs' file "
287
288
        ++ "(even if it is generated by a preprocessor), "
        ++ "or it may specify a C/C++/obj-C source file."
289

290
291
292
293
294
  , checkSpecVersion pkg [1,17] (mainIsNotHsExt && not mainIsWrongExt) $
      PackageDistInexcusable $
           "The package uses a C/C++/obj-C source file for the 'main-is' field. "
        ++ "To use this feature you must specify 'cabal-version: >= 1.18'."

tibbe's avatar
tibbe committed
295
296
297
    -- Test suites might be built as (internal) libraries named after
    -- the test suite and thus their names must not clash with the
    -- name of the package.
298
299
300
301
  , check libNameClash $
      PackageBuildImpossible $
           "The test suite " ++ testName test
        ++ " has the same name as the package."
302
  ]
303
304
  where
    moduleDuplicates = dups $ testModules test
305
306

    mainIsWrongExt = case testInterface test of
307
      TestSuiteExeV10 _ f -> not $ fileExtensionSupportedLanguage f
308
309
      _                   -> False

310
311
312
313
    mainIsNotHsExt = case testInterface test of
      TestSuiteExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"]
      _                   -> False

314
315
316
317
    libNameClash = testName test `elem` [ libName
                                        | _lib <- maybeToList (library pkg)
                                        , let PackageName libName =
                                                pkgName (package pkg) ]
318

tibbe's avatar
tibbe committed
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
checkBenchmark :: PackageDescription -> Benchmark -> [PackageCheck]
checkBenchmark pkg bm =
  catMaybes [

    case benchmarkInterface bm of
      BenchmarkUnsupported tt@(BenchmarkTypeUnknown _ _) -> Just $
        PackageBuildWarning $
             quote (display tt) ++ " is not a known type of benchmark. "
          ++ "The known benchmark types are: "
          ++ commaSep (map display knownBenchmarkTypes)

      BenchmarkUnsupported tt -> Just $
        PackageBuildWarning $
             quote (display tt) ++ " is not a supported benchmark version. "
          ++ "The known benchmark types are: "
          ++ commaSep (map display knownBenchmarkTypes)
      _ -> Nothing

  , check (not $ null moduleDuplicates) $
338
      PackageBuildImpossible $
tibbe's avatar
tibbe committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
           "Duplicate modules in benchmark '" ++ benchmarkName bm ++ "': "
        ++ commaSep (map display moduleDuplicates)

  , check mainIsWrongExt $
      PackageBuildImpossible $
           "The 'main-is' field must specify a '.hs' or '.lhs' file "
        ++ "(even if it is generated by a preprocessor)."

    -- See comment for similar check on test suites.
  , check libNameClash $
      PackageBuildImpossible $
           "The benchmark " ++ benchmarkName bm
        ++ " has the same name as the package."
  ]
  where
    moduleDuplicates = dups $ benchmarkModules bm

    mainIsWrongExt = case benchmarkInterface bm of
      BenchmarkExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"]
      _                   -> False

    libNameClash = benchmarkName bm `elem` [ libName
                                           | _lib <- maybeToList (library pkg)
                                           , let PackageName libName =
                                                   pkgName (package pkg) ]

365
366
367
368
369
370
371
372
-- ------------------------------------------------------------
-- * Additional pure checks
-- ------------------------------------------------------------

checkFields :: PackageDescription -> [PackageCheck]
checkFields pkg =
  catMaybes [

373
374
375
376
377
378
379
380
    check (not . FilePath.Windows.isValid . display . packageName $ pkg) $
      PackageDistInexcusable $
           "Unfortunately, the package name '" ++ display (packageName pkg)
        ++ "' is one of the reserved system file names on Windows. Many tools "
        ++ "need to convert package names to file names so using this name "
        ++ "would cause problems."

  , check (isNothing (buildType pkg)) $
381
382
383
384
385
386
387
388
389
      PackageBuildWarning $
           "No 'build-type' specified. If you do not need a custom Setup.hs or "
        ++ "./configure script then use 'build-type: Simple'."

  , case buildType pkg of
      Just (UnknownBuildType unknown) -> Just $
        PackageBuildWarning $
             quote unknown ++ " is not a known 'build-type'. "
          ++ "The known build types are: "
390
          ++ commaSep (map display knownBuildTypes)
391
392
393
394
      _ -> Nothing

  , check (not (null unknownCompilers)) $
      PackageBuildWarning $
395
        "Unknown compiler " ++ commaSep (map quote unknownCompilers)
396
397
                            ++ " in 'tested-with' field."

398
399
400
401
  , check (not (null unknownLanguages)) $
      PackageBuildWarning $
        "Unknown languages: " ++ commaSep unknownLanguages

402
403
  , check (not (null unknownExtensions)) $
      PackageBuildWarning $
404
        "Unknown extensions: " ++ commaSep unknownExtensions
405

406
407
408
409
410
411
412
  , check (not (null languagesUsedAsExtensions)) $
      PackageBuildWarning $
           "Languages listed as extensions: "
        ++ commaSep languagesUsedAsExtensions
        ++ ". Languages must be specified in either the 'default-language' "
        ++ " or the 'other-languages' field."

413
414
415
416
  , check (not (null deprecatedExtensions)) $
      PackageDistSuspicious $
           "Deprecated extensions: "
        ++ commaSep (map (quote . display . fst) deprecatedExtensions)
EyalLotem's avatar
EyalLotem committed
417
        ++ ". " ++ unwords
418
419
420
421
             [ "Instead of '" ++ display ext
            ++ "' use '" ++ display replacement ++ "'."
             | (ext, Just replacement) <- deprecatedExtensions ]

422
423
424
425
426
427
  , check (null (category pkg)) $
      PackageDistSuspicious "No 'category' field."

  , check (null (maintainer pkg)) $
      PackageDistSuspicious "No 'maintainer' field."

428
  , check (null (synopsis pkg) && null (description pkg)) $
EyalLotem's avatar
EyalLotem committed
429
      PackageDistInexcusable "No 'synopsis' or 'description' field."
430
431
432
433
434

  , check (null (description pkg) && not (null (synopsis pkg))) $
      PackageDistSuspicious "No 'description' field."

  , check (null (synopsis pkg) && not (null (description pkg))) $
435
436
      PackageDistSuspicious "No 'synopsis' field."

Ian D. Bollinger's avatar
Ian D. Bollinger committed
437
    --TODO: recommend the bug reports URL, author and homepage fields
438
439
440
    --TODO: recommend not using the stability field
    --TODO: recommend specifying a source repo

441
442
443
  , check (length (synopsis pkg) >= 80) $
      PackageDistSuspicious
        "The 'synopsis' field is rather long (max 80 chars is recommended)."
444
445
446
447
448
449
450
451
452
453

    -- check use of impossible constraints "tested-with: GHC== 6.10 && ==6.12"
  , check (not (null testedWithImpossibleRanges)) $
      PackageDistInexcusable $
           "Invalid 'tested-with' version range: "
        ++ commaSep (map display testedWithImpossibleRanges)
        ++ ". To indicate that you have tested a package with multiple "
        ++ "different versions of the same compiler use multiple entries, "
        ++ "for example 'tested-with: GHC==6.10.4, GHC==6.12.3' and not "
        ++ "'tested-with: GHC==6.10.4 && ==6.12.3'."
454
  ]
455
456
  where
    unknownCompilers  = [ name | (OtherCompiler name, _) <- testedWith pkg ]
457
458
    unknownLanguages  = [ name | bi <- allBuildInfo pkg
                               , UnknownLanguage name <- allLanguages bi ]
459
    unknownExtensions = [ name | bi <- allBuildInfo pkg
460
461
                               , UnknownExtension name <- allExtensions bi
                               , name `notElem` map display knownLanguages ]
462
463
464
    deprecatedExtensions = nub $ catMaybes
      [ find ((==ext) . fst) Extension.deprecatedExtensions
      | bi <- allBuildInfo pkg
Ian Lynagh's avatar
Ian Lynagh committed
465
      , ext <- allExtensions bi ]
466
467
468
469
    languagesUsedAsExtensions =
      [ name | bi <- allBuildInfo pkg
             , UnknownExtension name <- allExtensions bi
             , name `elem` map display knownLanguages ]
470

471
472
473
474
475
476
    testedWithImpossibleRanges =
      [ Dependency (PackageName (display compiler)) vr
      | (compiler, vr) <- testedWith pkg
      , isNoVersion vr ]


477
478
479
480
checkLicense :: PackageDescription -> [PackageCheck]
checkLicense pkg =
  catMaybes [

481
    check (license pkg == UnspecifiedLicense) $
482
      PackageDistInexcusable
483
        "The 'license' field is missing."
484

485
486
487
  , check (license pkg == AllRightsReserved) $
      PackageDistSuspicious
        "The 'license' is AllRightsReserved. Is that really what you want?"
488
489
490
  , case license pkg of
      UnknownLicense l -> Just $
        PackageBuildWarning $
491
492
493
             quote ("license: " ++ l) ++ " is not a recognised license. The "
          ++ "known licenses are: "
          ++ commaSep (map display knownLicenses)
494
495
      _ -> Nothing

496
497
498
  , check (license pkg == BSD4) $
      PackageDistSuspicious $
           "Using 'license: BSD4' is almost always a misunderstanding. 'BSD4' "
499
500
        ++ "refers to the old 4-clause BSD license with the advertising "
        ++ "clause. 'BSD3' refers the new 3-clause BSD license."
501

502
503
504
505
506
507
508
509
510
511
  , case unknownLicenseVersion (license pkg) of
      Just knownVersions -> Just $
        PackageDistSuspicious $
             "'license: " ++ display (license pkg) ++ "' is not a known "
          ++ "version of that license. The known versions are "
          ++ commaSep (map display knownVersions)
          ++ ". If this is not a mistake and you think it should be a known "
          ++ "version then please file a ticket."
      _ -> Nothing

512
513
514
  , check (license pkg `notElem` [ AllRightsReserved
                                 , UnspecifiedLicense, PublicDomain]
           -- *AllRightsReserved and PublicDomain are not strictly
515
           -- licenses so don't need license files.
Duncan Coutts's avatar
Duncan Coutts committed
516
        && null (licenseFiles pkg)) $
517
518
      PackageDistSuspicious "A 'license-file' is not specified."
  ]
519
520
521
522
523
524
525
  where
    unknownLicenseVersion (GPL  (Just v))
      | v `notElem` knownVersions = Just knownVersions
      where knownVersions = [ v' | GPL  (Just v') <- knownLicenses ]
    unknownLicenseVersion (LGPL (Just v))
      | v `notElem` knownVersions = Just knownVersions
      where knownVersions = [ v' | LGPL (Just v') <- knownLicenses ]
526
527
528
    unknownLicenseVersion (AGPL (Just v))
      | v `notElem` knownVersions = Just knownVersions
      where knownVersions = [ v' | AGPL (Just v') <- knownLicenses ]
529
530
531
    unknownLicenseVersion (Apache  (Just v))
      | v `notElem` knownVersions = Just knownVersions
      where knownVersions = [ v' | Apache  (Just v') <- knownLicenses ]
532
    unknownLicenseVersion _ = Nothing
533

534
535
536
537
538
539
540
541
542
543
checkSourceRepos :: PackageDescription -> [PackageCheck]
checkSourceRepos pkg =
  catMaybes $ concat [[

    case repoKind repo of
      RepoKindUnknown kind -> Just $ PackageDistInexcusable $
        quote kind ++ " is not a recognised kind of source-repository. "
                   ++ "The repo kind is usually 'head' or 'this'"
      _ -> Nothing

EyalLotem's avatar
EyalLotem committed
544
  , check (isNothing (repoType repo)) $
545
546
547
      PackageDistInexcusable
        "The source-repository 'type' is a required field."

EyalLotem's avatar
EyalLotem committed
548
  , check (isNothing (repoLocation repo)) $
549
550
551
      PackageDistInexcusable
        "The source-repository 'location' is a required field."

EyalLotem's avatar
EyalLotem committed
552
  , check (repoType repo == Just CVS && isNothing (repoModule repo)) $
553
554
555
      PackageDistInexcusable
        "For a CVS source-repository, the 'module' is a required field."

EyalLotem's avatar
EyalLotem committed
556
  , check (repoKind repo == RepoThis && isNothing (repoTag repo)) $
557
558
559
560
561
562
563
564
565
566
567
568
569
      PackageDistInexcusable $
           "For the 'this' kind of source-repository, the 'tag' is a required "
        ++ "field. It should specify the tag corresponding to this version "
        ++ "or release of the package."

  , check (maybe False System.FilePath.isAbsolute (repoSubdir repo)) $
      PackageDistInexcusable
        "The 'subdir' field of a source-repository must be a relative path."
  ]
  | repo <- sourceRepos pkg ]

--TODO: check location looks like a URL for some repo types.

570
571
572
573
574
575
checkGhcOptions :: PackageDescription -> [PackageCheck]
checkGhcOptions pkg =
  catMaybes [

    check has_WerrorWall $
      PackageDistInexcusable $
576
577
578
           "'ghc-options: -Wall -Werror' makes the package very easy to "
        ++ "break with future GHC versions because new GHC versions often "
        ++ "add new warnings. Use just 'ghc-options: -Wall' instead."
579
580
581
582

  , check (not has_WerrorWall && has_Werror) $
      PackageDistSuspicious $
           "'ghc-options: -Werror' makes the package easy to "
583
584
        ++ "break with future GHC versions because new GHC versions often "
        ++ "add new warnings."
585

Duncan Coutts's avatar
Duncan Coutts committed
586
  , checkFlags ["-fasm"] $
587
      PackageDistInexcusable $
588
589
           "'ghc-options: -fasm' is unnecessary and will not work on CPU "
        ++ "architectures other than x86, x86-64, ppc or sparc."
590

Duncan Coutts's avatar
Duncan Coutts committed
591
592
  , checkFlags ["-fvia-C"] $
      PackageDistSuspicious $
593
594
595
596
           "'ghc-options: -fvia-C' is usually unnecessary. If your package "
        ++ "needs -via-C for correctness rather than performance then it "
        ++ "is using the FFI incorrectly and will probably not work with GHC "
        ++ "6.10 or later."
Duncan Coutts's avatar
Duncan Coutts committed
597

598
599
600
601
602
  , checkFlags ["-fdefer-type-errors"] $
      PackageDistInexcusable $
          "'ghc-options: -fdefer-type-errors' is fine during development but "
       ++ "is not appropriate for a distributed package."

Duncan Coutts's avatar
Duncan Coutts committed
603
604
605
  , checkFlags ["-fhpc"] $
      PackageDistInexcusable $
        "'ghc-options: -fhpc' is not appropriate for a distributed package."
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
606

607
    -- -dynamic is not a debug flag
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
608
609
  , check (any (\opt -> "-d" `isPrefixOf` opt && opt /= "-dynamic")
           all_ghc_options) $
Duncan Coutts's avatar
Duncan Coutts committed
610
      PackageDistInexcusable $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
611
612
        "'ghc-options: -d*' debug flags are not appropriate "
        ++ "for a distributed package."
Duncan Coutts's avatar
Duncan Coutts committed
613
614

  , checkFlags ["-prof"] $
615
616
617
618
      PackageBuildWarning $
           "'ghc-options: -prof' is not necessary and will lead to problems "
        ++ "when used on a library. Use the configure flag "
        ++ "--enable-library-profiling and/or --enable-executable-profiling."
Duncan Coutts's avatar
Duncan Coutts committed
619
620

  , checkFlags ["-o"] $
621
      PackageBuildWarning $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
622
623
           "'ghc-options: -o' is not needed. "
        ++ "The output files are named automatically."
Duncan Coutts's avatar
Duncan Coutts committed
624
625

  , checkFlags ["-hide-package"] $
626
      PackageBuildWarning $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
627
628
      "'ghc-options: -hide-package' is never needed. "
      ++ "Cabal hides all packages."
Duncan Coutts's avatar
Duncan Coutts committed
629

Duncan Coutts's avatar
Duncan Coutts committed
630
  , checkFlags ["--make"] $
631
      PackageBuildWarning $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
632
      "'ghc-options: --make' is never needed. Cabal uses this automatically."
Duncan Coutts's avatar
Duncan Coutts committed
633

Duncan Coutts's avatar
Duncan Coutts committed
634
635
  , checkFlags ["-main-is"] $
      PackageDistSuspicious $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
636
      "'ghc-options: -main-is' is not portable."
Duncan Coutts's avatar
Duncan Coutts committed
637
638

  , checkFlags ["-O0", "-Onot"] $
639
      PackageDistSuspicious $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
640
641
      "'ghc-options: -O0' is not needed. "
      ++ "Use the --disable-optimization configure flag."
Duncan Coutts's avatar
Duncan Coutts committed
642
643

  , checkFlags [ "-O", "-O1"] $
644
      PackageDistInexcusable $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
645
646
647
      "'ghc-options: -O' is not needed. "
      ++ "Cabal automatically adds the '-O' flag. "
      ++ "Setting it yourself interferes with the --disable-optimization flag."
648

Duncan Coutts's avatar
Duncan Coutts committed
649
  , checkFlags ["-O2"] $
650
      PackageDistSuspicious $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
651
652
653
      "'ghc-options: -O2' is rarely needed. "
      ++ "Check that it is giving a real benefit "
      ++ "and not just imposing longer compile times on your users."
654

Duncan Coutts's avatar
Duncan Coutts committed
655
  , checkFlags ["-split-objs"] $
656
      PackageBuildWarning $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
657
658
        "'ghc-options: -split-objs' is not needed. "
        ++ "Use the --enable-split-objs configure flag."
Duncan Coutts's avatar
Duncan Coutts committed
659

660
  , checkFlags ["-optl-Wl,-s", "-optl-s"] $
661
      PackageDistInexcusable $
662
663
664
665
666
667
           "'ghc-options: -optl-Wl,-s' is not needed and is not portable to all"
        ++ " operating systems. Cabal 1.4 and later automatically strip"
        ++ " executables. Cabal also has a flag --disable-executable-stripping"
        ++ " which is necessary when building packages for some Linux"
        ++ " distributions and using '-optl-Wl,-s' prevents that from working."

Duncan Coutts's avatar
Duncan Coutts committed
668
669
  , checkFlags ["-fglasgow-exts"] $
      PackageDistSuspicious $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
670
671
        "Instead of 'ghc-options: -fglasgow-exts' it is preferable to use "
        ++ "the 'extensions' field."
Duncan Coutts's avatar
Duncan Coutts committed
672

673
674
675
676
677
  , checkProfFlags ["-auto-all"] $
      PackageDistSuspicious $
        "'ghc-prof-options: -auto-all' is fine during development, but "
        ++ "not recommended in a distributed package. "

678
679
680
681
682
  , check ("-threaded" `elem` lib_ghc_options) $
      PackageDistSuspicious $
           "'ghc-options: -threaded' has no effect for libraries. It should "
        ++ "only be used for executables."

Duncan Coutts's avatar
Duncan Coutts committed
683
  , checkAlternatives "ghc-options" "extensions"
684
685
      [ (flag, display extension) | flag <- all_ghc_options
                                  , Just extension <- [ghcExtension flag] ]
Duncan Coutts's avatar
Duncan Coutts committed
686
687

  , checkAlternatives "ghc-options" "extensions"
688
      [ (flag, extension) | flag@('-':'X':extension) <- all_ghc_options ]
Duncan Coutts's avatar
Duncan Coutts committed
689
690
691
692
693
694
695
696
697
698
699
700
701

  , checkAlternatives "ghc-options" "cpp-options" $
         [ (flag, flag) | flag@('-':'D':_) <- all_ghc_options ]
      ++ [ (flag, flag) | flag@('-':'U':_) <- all_ghc_options ]

  , checkAlternatives "ghc-options" "include-dirs"
      [ (flag, dir) | flag@('-':'I':dir) <- all_ghc_options ]

  , checkAlternatives "ghc-options" "extra-libraries"
      [ (flag, lib) | flag@('-':'l':lib) <- all_ghc_options ]

  , checkAlternatives "ghc-options" "extra-lib-dirs"
      [ (flag, dir) | flag@('-':'L':dir) <- all_ghc_options ]
702
703
704
705
706
707
708
709
  ]

  where
    has_WerrorWall = flip any ghc_options $ \opts ->
                               "-Werror" `elem` opts
                           && ("-Wall"   `elem` opts || "-W" `elem` opts)
    has_Werror     = any (\opts -> "-Werror" `elem` opts) ghc_options

710
711
712
713
714
    (ghc_options, ghc_prof_options) =
      unzip . map (\bi -> (hcOptions GHC bi, ghcProfOptions bi))
      $ (allBuildInfo pkg)
    all_ghc_options      = concat ghc_options
    all_ghc_prof_options = concat ghc_prof_options
715
    lib_ghc_options = maybe [] (hcOptions GHC . libBuildInfo) (library pkg)
716

717
718
719
720
721
    checkFlags,checkProfFlags :: [String] -> PackageCheck -> Maybe PackageCheck
    checkFlags     flags = doCheckFlags flags all_ghc_options
    checkProfFlags flags = doCheckFlags flags all_ghc_prof_options

    doCheckFlags   flags opts = check (any (`elem` flags) opts)
Duncan Coutts's avatar
Duncan Coutts committed
722
723

    ghcExtension ('-':'f':name) = case name of
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
      "allow-overlapping-instances"    -> enable  OverlappingInstances
      "no-allow-overlapping-instances" -> disable OverlappingInstances
      "th"                             -> enable  TemplateHaskell
      "no-th"                          -> disable TemplateHaskell
      "ffi"                            -> enable  ForeignFunctionInterface
      "no-ffi"                         -> disable ForeignFunctionInterface
      "fi"                             -> enable  ForeignFunctionInterface
      "no-fi"                          -> disable ForeignFunctionInterface
      "monomorphism-restriction"       -> enable  MonomorphismRestriction
      "no-monomorphism-restriction"    -> disable MonomorphismRestriction
      "mono-pat-binds"                 -> enable  MonoPatBinds
      "no-mono-pat-binds"              -> disable MonoPatBinds
      "allow-undecidable-instances"    -> enable  UndecidableInstances
      "no-allow-undecidable-instances" -> disable UndecidableInstances
      "allow-incoherent-instances"     -> enable  IncoherentInstances
      "no-allow-incoherent-instances"  -> disable IncoherentInstances
      "arrows"                         -> enable  Arrows
      "no-arrows"                      -> disable Arrows
      "generics"                       -> enable  Generics
      "no-generics"                    -> disable Generics
      "implicit-prelude"               -> enable  ImplicitPrelude
      "no-implicit-prelude"            -> disable ImplicitPrelude
      "implicit-params"                -> enable  ImplicitParams
      "no-implicit-params"             -> disable ImplicitParams
      "bang-patterns"                  -> enable  BangPatterns
      "no-bang-patterns"               -> disable BangPatterns
      "scoped-type-variables"          -> enable  ScopedTypeVariables
      "no-scoped-type-variables"       -> disable ScopedTypeVariables
      "extended-default-rules"         -> enable  ExtendedDefaultRules
      "no-extended-default-rules"      -> disable ExtendedDefaultRules
754
      _                                -> Nothing
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
755
    ghcExtension "-cpp"             = enable CPP
Duncan Coutts's avatar
Duncan Coutts committed
756
757
    ghcExtension _                  = Nothing

Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
758
759
760
    enable  e = Just (EnableExtension e)
    disable e = Just (DisableExtension e)

Duncan Coutts's avatar
Duncan Coutts committed
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
checkCCOptions :: PackageDescription -> [PackageCheck]
checkCCOptions pkg =
  catMaybes [

    checkAlternatives "cc-options" "include-dirs"
      [ (flag, dir) | flag@('-':'I':dir) <- all_ccOptions ]

  , checkAlternatives "cc-options" "extra-libraries"
      [ (flag, lib) | flag@('-':'l':lib) <- all_ccOptions ]

  , checkAlternatives "cc-options" "extra-lib-dirs"
      [ (flag, dir) | flag@('-':'L':dir) <- all_ccOptions ]

  , checkAlternatives "ld-options" "extra-libraries"
      [ (flag, lib) | flag@('-':'l':lib) <- all_ldOptions ]

  , checkAlternatives "ld-options" "extra-lib-dirs"
      [ (flag, dir) | flag@('-':'L':dir) <- all_ldOptions ]
779
780
781
782
783
784
785

  , checkCCFlags [ "-O", "-Os", "-O0", "-O1", "-O2", "-O3" ] $
      PackageDistSuspicious $
           "'cc-options: -O[n]' is generally not needed. When building with "
        ++ " optimisations Cabal automatically adds '-O2' for C code. "
        ++ "Setting it yourself interferes with the --disable-optimization "
        ++ "flag."
Duncan Coutts's avatar
Duncan Coutts committed
786
787
788
789
790
791
792
  ]

  where all_ccOptions = [ opts | bi <- allBuildInfo pkg
                              , opts <- ccOptions bi ]
        all_ldOptions = [ opts | bi <- allBuildInfo pkg
                               , opts <- ldOptions bi ]

793
794
795
        checkCCFlags :: [String] -> PackageCheck -> Maybe PackageCheck
        checkCCFlags flags = check (any (`elem` flags) all_ccOptions)

796
797
798
799
800
801
802
803
804
checkCPPOptions :: PackageDescription -> [PackageCheck]
checkCPPOptions pkg =
  catMaybes [
    checkAlternatives "cpp-options" "include-dirs"
      [ (flag, dir) | flag@('-':'I':dir) <- all_cppOptions]
    ]
  where all_cppOptions = [ opts | bi <- allBuildInfo pkg
                                , opts <- cppOptions bi ]

Duncan Coutts's avatar
Duncan Coutts committed
805
806
807
808
809
810
811
812
checkAlternatives :: String -> String -> [(String, String)] -> Maybe PackageCheck
checkAlternatives badField goodField flags =
  check (not (null badFlags)) $
    PackageBuildWarning $
         "Instead of " ++ quote (badField ++ ": " ++ unwords badFlags)
      ++ " use " ++ quote (goodField ++ ": " ++ unwords goodFlags)

  where (badFlags, goodFlags) = unzip flags
813

814
815
checkPaths :: PackageDescription -> [PackageCheck]
checkPaths pkg =
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
  [ PackageBuildWarning $
         quote (kind ++ ": " ++ path)
      ++ " is a relative path outside of the source tree. "
      ++ "This will not work when generating a tarball with 'sdist'."
  | (path, kind) <- relPaths ++ absPaths
  , isOutsideTree path ]
  ++
  [ PackageDistInexcusable $
      quote (kind ++ ": " ++ path) ++ " is an absolute directory."
  | (path, kind) <- relPaths
  , isAbsolute path ]
  ++
  [ PackageDistInexcusable $
         quote (kind ++ ": " ++ path) ++ " points inside the 'dist' "
      ++ "directory. This is not reliable because the location of this "
      ++ "directory is configurable by the user (or package manager). In "
      ++ "addition the layout of the 'dist' directory is subject to change "
      ++ "in future versions of Cabal."
  | (path, kind) <- relPaths ++ absPaths
  , isInsideDist path ]
  ++
  [ PackageDistInexcusable $
         "The 'ghc-options' contains the path '" ++ path ++ "' which points "
      ++ "inside the 'dist' directory. This is not reliable because the "
      ++ "location of this directory is configurable by the user (or package "
      ++ "manager). In addition the layout of the 'dist' directory is subject "
      ++ "to change in future versions of Cabal."
843
  | bi <- allBuildInfo pkg
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  , (GHC, flags) <- options bi
  , path <- flags
  , isInsideDist path ]
  where
    isOutsideTree path = case splitDirectories path of
      "..":_     -> True
      ".":"..":_ -> True
      _          -> False
    isInsideDist path = case map lowercase (splitDirectories path) of
      "dist"    :_ -> True
      ".":"dist":_ -> True
      _            -> False
    -- paths that must be relative
    relPaths =
858
859
860
861
862
         [ (path, "extra-src-files") | path <- extraSrcFiles pkg ]
      ++ [ (path, "extra-tmp-files") | path <- extraTmpFiles pkg ]
      ++ [ (path, "extra-doc-files") | path <- extraDocFiles pkg ]
      ++ [ (path, "data-files")      | path <- dataFiles     pkg ]
      ++ [ (path, "data-dir")        | path <- [dataDir      pkg]]
863
864
865
866
867
868
869
870
871
872
873
874
      ++ concat
         [    [ (path, "c-sources")        | path <- cSources        bi ]
           ++ [ (path, "install-includes") | path <- installIncludes bi ]
           ++ [ (path, "hs-source-dirs")   | path <- hsSourceDirs    bi ]
         | bi <- allBuildInfo pkg ]
    -- paths that are allowed to be absolute
    absPaths = concat
      [    [ (path, "includes")         | path <- includes        bi ]
        ++ [ (path, "include-dirs")     | path <- includeDirs     bi ]
        ++ [ (path, "extra-lib-dirs")   | path <- extraLibDirs    bi ]
      | bi <- allBuildInfo pkg ]

Ian D. Bollinger's avatar
Ian D. Bollinger committed
875
--TODO: check sets of paths that would be interpreted differently between Unix
876
877
878
879
-- and windows, ie case-sensitive or insensitive. Things that might clash, or
-- conversely be distinguished.

--TODO: use the tar path checks on all the above paths
880

881
882
-- | Check that the package declares the version in the @\"cabal-version\"@
-- field correctly.
883
884
885
886
887
--
checkCabalVersion :: PackageDescription -> [PackageCheck]
checkCabalVersion pkg =
  catMaybes [

888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
    -- check syntax of cabal-version field
    check (specVersion pkg >= Version [1,10] []
           && not simpleSpecVersionRangeSyntax) $
      PackageBuildWarning $
           "Packages relying on Cabal 1.10 or later must only specify a "
        ++ "version range of the form 'cabal-version: >= x.y'. Use "
        ++ "'cabal-version: >= " ++ display (specVersion pkg) ++ "'."

    -- check syntax of cabal-version field
  , check (specVersion pkg < Version [1,9] []
           && not simpleSpecVersionRangeSyntax) $
      PackageDistSuspicious $
           "It is recommended that the 'cabal-version' field only specify a "
        ++ "version range of the form '>= x.y'. Use "
        ++ "'cabal-version: >= " ++ display (specVersion pkg) ++ "'. "
        ++ "Tools based on Cabal 1.10 and later will ignore upper bounds."

    -- check syntax of cabal-version field
  , checkVersion [1,12] simpleSpecVersionSyntax $
      PackageBuildWarning $
           "With Cabal 1.10 or earlier, the 'cabal-version' field must use "
        ++ "range syntax rather than a simple version number. Use "
        ++ "'cabal-version: >= " ++ display (specVersion pkg) ++ "'."

912
913
    -- check use of test suite sections
  , checkVersion [1,8] (not (null $ testSuites pkg)) $
914
      PackageDistInexcusable $
915
916
           "The 'test-suite' section is new in Cabal 1.10. "
        ++ "Unfortunately it messes up the parser in older Cabal versions "
Duncan Coutts's avatar
Duncan Coutts committed
917
        ++ "so you must specify at least 'cabal-version: >= 1.8', but note "
918
        ++ "that only Cabal 1.10 and later can actually run such test suites."
919

920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
    -- check use of default-language field
    -- note that we do not need to do an equivalent check for the
    -- other-language field since that one does not change behaviour
  , checkVersion [1,10] (any isJust (buildInfoField defaultLanguage)) $
      PackageBuildWarning $
           "To use the 'default-language' field the package needs to specify "
        ++ "at least 'cabal-version: >= 1.10'."

  , check (specVersion pkg >= Version [1,10] []
           && (any isNothing (buildInfoField defaultLanguage))) $
      PackageBuildWarning $
           "Packages using 'cabal-version: >= 1.10' must specify the "
        ++ "'default-language' field for each component (e.g. Haskell98 or "
        ++ "Haskell2010). If a component uses different languages in "
        ++ "different modules then list the other ones in the "
        ++ "'other-languages' field."

937
    -- check use of reexported-modules sections
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
938
939
  , checkVersion [1,21]
    (maybe False (not.null.reexportedModules) (library pkg)) $
940
941
942
943
      PackageDistInexcusable $
           "To use the 'reexported-module' field the package needs to specify "
        ++ "at least 'cabal-version: >= 1.21'."

944
945
946
    -- check use of thinning and renaming
  , checkVersion [1,21] (not (null depsUsingThinningRenamingSyntax)) $
      PackageDistInexcusable $
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
947
948
           "The package uses "
        ++ "thinning and renaming in the 'build-depends' field: "
949
950
951
952
        ++ commaSep (map display depsUsingThinningRenamingSyntax)
        ++ ". To use this new syntax, the package needs to specify at least"
        ++ "'cabal-version: >= 1.21'."

953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
    -- check use of default-extensions field
    -- don't need to do the equivalent check for other-extensions
  , checkVersion [1,10] (any (not . null) (buildInfoField defaultExtensions)) $
      PackageBuildWarning $
           "To use the 'default-extensions' field the package needs to specify "
        ++ "at least 'cabal-version: >= 1.10'."

    -- check use of extensions field
  , check (specVersion pkg >= Version [1,10] []
           && (any (not . null) (buildInfoField oldExtensions))) $
      PackageBuildWarning $
           "For packages using 'cabal-version: >= 1.10' the 'extensions' "
        ++ "field is deprecated. The new 'default-extensions' field lists "
        ++ "extensions that are used in all modules in the component, while "
        ++ "the 'other-extensions' field lists extensions that are used in "
        ++ "some modules, e.g. via the {-# LANGUAGE #-} pragma."

970
    -- check use of "foo (>= 1.0 && < 1.4) || >=1.8 " version-range syntax
971
  , checkVersion [1,8] (not (null versionRangeExpressions)) $
972
973
974
      PackageDistInexcusable $
           "The package uses full version-range expressions "
        ++ "in a 'build-depends' field: "
975
        ++ commaSep (map displayRawDependency versionRangeExpressions)
976
977
978
979
980
        ++ ". To use this new syntax the package needs to specify at least "
        ++ "'cabal-version: >= 1.8'. Alternatively, if broader compatibility "
        ++ "is important, then convert to conjunctive normal form, and use "
        ++ "multiple 'build-depends:' lines, one conjunct per line."

981
    -- check use of "build-depends: foo == 1.*" syntax
982
  , checkVersion [1,6] (not (null depsUsingWildcardSyntax)) $
983
984
985
986
      PackageDistInexcusable $
           "The package uses wildcard syntax in the 'build-depends' field: "
        ++ commaSep (map display depsUsingWildcardSyntax)
        ++ ". To use this new syntax the package need to specify at least "
Ian D. Bollinger's avatar
Ian D. Bollinger committed
987
        ++ "'cabal-version: >= 1.6'. Alternatively, if broader compatibility "
988
989
        ++ "is important then use: " ++ commaSep
           [ display (Dependency name (eliminateWildcardSyntax versionRange))
990
991
           | Dependency name versionRange <- depsUsingWildcardSyntax ]

992
993
994
995
996
    -- check use of "tested-with: GHC (>= 1.0 && < 1.4) || >=1.8 " syntax
  , checkVersion [1,8] (not (null testedWithVersionRangeExpressions)) $
      PackageDistInexcusable $
           "The package uses full version-range expressions "
        ++ "in a 'tested-with' field: "
997
        ++ commaSep (map displayRawDependency testedWithVersionRangeExpressions)
998
999
1000
        ++ ". To use this new syntax the package needs to specify at least "
        ++ "'cabal-version: >= 1.8'."

For faster browsing, not all history is shown. View entire blame