1
1
{-# LANGUAGE RecordWildCards #-}
2
2
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3
+ {-# LANGUAGE ScopedTypeVariables #-}
3
4
-- | DSL for testing the modular solver
4
5
module UnitTests.Distribution.Solver.Modular.DSL (
5
6
ExampleDependency (.. )
@@ -29,25 +30,30 @@ module UnitTests.Distribution.Solver.Modular.DSL (
29
30
, runProgress
30
31
) where
31
32
33
+ import Prelude ()
34
+ import Distribution.Client.Compat.Prelude
35
+
32
36
-- base
33
37
import Data.Either (partitionEithers )
34
- import Data.Maybe (catMaybes , isNothing )
35
- import Data.List (elemIndex , nub )
36
- import Data.Monoid
38
+ import Data.List (elemIndex )
37
39
import Data.Ord (comparing )
38
40
import qualified Data.Map as Map
39
41
40
42
-- Cabal
41
- import qualified Distribution.Compiler as C
42
- import qualified Distribution.InstalledPackageInfo as C
43
- import qualified Distribution.Package as C
43
+ import qualified Distribution.Compiler as C
44
+ import qualified Distribution.InstalledPackageInfo as IPI
45
+ import Distribution.License (License (.. ))
46
+ import qualified Distribution.ModuleName as Module
47
+ import qualified Distribution.Package as C
44
48
hiding (HasUnitId (.. ))
45
- import qualified Distribution.PackageDescription as C
46
- import qualified Distribution.Simple.PackageIndex as C.PackageIndex
49
+ import qualified Distribution.PackageDescription as C
50
+ import qualified Distribution.PackageDescription.Check as C
51
+ import qualified Distribution.Simple.PackageIndex as C.PackageIndex
47
52
import Distribution.Simple.Setup (BooleanFlag (.. ))
48
- import qualified Distribution.System as C
49
- import qualified Distribution.Version as C
50
- import Language.Haskell.Extension (Extension (.. ), Language )
53
+ import qualified Distribution.System as C
54
+ import Distribution.Text (display )
55
+ import qualified Distribution.Version as C
56
+ import Language.Haskell.Extension (Extension (.. ), Language (.. ))
51
57
52
58
-- cabal-install
53
59
import Distribution.Client.Dependency
@@ -246,59 +252,103 @@ type ExampleDb = [Either ExampleInstalled ExampleAvailable]
246
252
247
253
type DependencyTree a = C. CondTree C. ConfVar [C. Dependency ] a
248
254
255
+ type DependencyComponent a = ( C. Condition C. ConfVar
256
+ , DependencyTree a
257
+ , Maybe (DependencyTree a ))
258
+
249
259
exDbPkgs :: ExampleDb -> [ExamplePkgName ]
250
260
exDbPkgs = map (either exInstName exAvName)
251
261
252
262
exAvSrcPkg :: ExampleAvailable -> UnresolvedSourcePackage
253
263
exAvSrcPkg ex =
254
- let (libraryDeps, exts, mlang, pcpkgs, exes) = splitTopLevel ( CD. libraryDeps (exAvDeps ex))
264
+ let pkgId = exAvPkgId ex
255
265
testSuites = [(name, deps) | (CD. ComponentTest name, deps) <- CD. toList (exAvDeps ex)]
256
266
executables = [(name, deps) | (CD. ComponentExe name, deps) <- CD. toList (exAvDeps ex)]
257
- in SourcePackage {
258
- packageInfoId = exAvPkgId ex
259
- , packageSource = LocalTarballPackage " <<path>>"
260
- , packageDescrOverride = Nothing
261
- , packageDescription = C. GenericPackageDescription {
262
- C. packageDescription = C. emptyPackageDescription {
263
- C. package = exAvPkgId ex
264
- , C. library = error " not yet configured: library"
265
- , C. subLibraries = error " not yet configured: subLibraries"
266
- , C. executables = error " not yet configured: executables"
267
- , C. testSuites = error " not yet configured: testSuites"
268
- , C. benchmarks = error " not yet configured: benchmarks"
269
- , C. buildDepends = error " not yet configured: buildDepends"
270
- , C. setupBuildInfo = Just C. SetupBuildInfo {
271
- C. setupDepends = mkSetupDeps (CD. setupDeps (exAvDeps ex)),
272
- C. defaultSetupDepends = False
273
- }
274
- }
275
- , C. genPackageFlags = nub $ concatMap extractFlags $
276
- CD. libraryDeps (exAvDeps ex)
277
- ++ concatMap snd testSuites
278
- ++ concatMap snd executables
279
- , C. condLibrary = Just (mkCondTree
280
- (extsLib exts <> langLib mlang <> pcpkgLib pcpkgs <> buildtoolsLib exes)
281
- disableLib
282
- (Buildable libraryDeps))
283
- , C. condSubLibraries = []
284
- , C. condExecutables =
285
- let mkTree = mkCondTree mempty disableExe . Buildable
286
- in map (\ (t, deps) -> (t, mkTree deps)) executables
287
- , C. condTestSuites =
288
- let mkTree = mkCondTree mempty disableTest . Buildable
289
- in map (\ (t, deps) -> (t, mkTree deps)) testSuites
290
- , C. condBenchmarks = []
291
- }
292
- }
267
+ setup = case CD. setupDeps (exAvDeps ex) of
268
+ [] -> Nothing
269
+ deps -> Just C. SetupBuildInfo {
270
+ C. setupDepends = mkSetupDeps deps,
271
+ C. defaultSetupDepends = False
272
+ }
273
+ package = SourcePackage {
274
+ packageInfoId = pkgId
275
+ , packageSource = LocalTarballPackage " <<path>>"
276
+ , packageDescrOverride = Nothing
277
+ , packageDescription = C. GenericPackageDescription {
278
+ C. packageDescription = C. emptyPackageDescription {
279
+ C. package = pkgId
280
+ , C. library = error " not yet configured: library"
281
+ , C. subLibraries = error " not yet configured: subLibraries"
282
+ , C. executables = error " not yet configured: executables"
283
+ , C. testSuites = error " not yet configured: testSuites"
284
+ , C. benchmarks = error " not yet configured: benchmarks"
285
+ , C. buildDepends = error " not yet configured: buildDepends"
286
+ , C. setupBuildInfo = setup
287
+ , C. license = BSD3
288
+ , C. buildType = if isNothing setup
289
+ then Just C. Simple
290
+ else Just C. Custom
291
+ , C. category = " category"
292
+ , C. maintainer = " maintainer"
293
+ , C. description = " description"
294
+ , C. synopsis = " synopsis"
295
+ , C. licenseFiles = [" LICENSE" ]
296
+ , C. specVersionRaw = Left $ C. mkVersion [1 ,12 ]
297
+ }
298
+ , C. genPackageFlags = nub $ concatMap extractFlags $
299
+ CD. libraryDeps (exAvDeps ex)
300
+ ++ concatMap snd testSuites
301
+ ++ concatMap snd executables
302
+ , C. condLibrary =
303
+ let mkLib bi = mempty { C. libBuildInfo = bi }
304
+ in Just $ mkCondTree defaultLib mkLib $ mkBuildInfoTree $
305
+ Buildable (CD. libraryDeps (exAvDeps ex))
306
+ , C. condSubLibraries = []
307
+ , C. condExecutables =
308
+ let mkTree = mkCondTree defaultExe mkExe . mkBuildInfoTree . Buildable
309
+ mkExe bi = mempty { C. buildInfo = bi }
310
+ in map (\ (t, deps) -> (t, mkTree deps)) executables
311
+ , C. condTestSuites =
312
+ let mkTree = mkCondTree defaultTest mkTest . mkBuildInfoTree . Buildable
313
+ mkTest bi = mempty { C. testBuildInfo = bi }
314
+ in map (\ (t, deps) -> (t, mkTree deps)) testSuites
315
+ , C. condBenchmarks = []
316
+ }
317
+ }
318
+ pkgCheckErrors =
319
+ -- We ignore these warnings because some unit tests test that the
320
+ -- solver allows unknown extensions/languages when the compiler
321
+ -- supports them.
322
+ let ignore = [" Unknown extensions:" , " Unknown languages:" ]
323
+ in [ err | err <- C. checkPackage (packageDescription package) Nothing
324
+ , not $ any (`isPrefixOf` C. explanation err) ignore ]
325
+ in if null pkgCheckErrors
326
+ then package
327
+ else error $ " invalid GenericPackageDescription for package "
328
+ ++ display pkgId ++ " : " ++ show pkgCheckErrors
293
329
where
330
+ defaultTopLevelBuildInfo :: C. BuildInfo
331
+ defaultTopLevelBuildInfo = mempty { C. defaultLanguage = Just Haskell98 }
332
+
333
+ defaultLib :: C. Library
334
+ defaultLib = mempty { C. exposedModules = [Module. fromString " Module" ] }
335
+
336
+ defaultExe :: C. Executable
337
+ defaultExe = mempty { C. modulePath = " Main.hs" }
338
+
339
+ defaultTest :: C. TestSuite
340
+ defaultTest = mempty {
341
+ C. testInterface = C. TestSuiteExeV10 (C. mkVersion [1 ,0 ]) " Test.hs"
342
+ }
343
+
294
344
-- Split the set of dependencies into the set of dependencies of the library,
295
345
-- the dependencies of the test suites and extensions.
296
346
splitTopLevel :: [ExampleDependency ]
297
347
-> ( [ExampleDependency ]
298
348
, [Extension ]
299
349
, Maybe Language
300
350
, [(ExamplePkgName , ExamplePkgVersion )] -- pkg-config
301
- , [(ExamplePkgName , Maybe Int )]
351
+ , [(ExamplePkgName , Maybe Int )] -- build tools
302
352
)
303
353
splitTopLevel [] =
304
354
([] , [] , Nothing , [] , [] )
@@ -343,22 +393,52 @@ exAvSrcPkg ex =
343
393
extractFlags (ExLang _) = []
344
394
extractFlags (ExPkg _) = []
345
395
346
- mkCondTree :: Monoid a => a -> (a -> a ) -> Dependencies -> DependencyTree a
347
- mkCondTree x dontBuild NotBuildable =
396
+ -- Convert a tree of BuildInfos into a tree of a specific component type.
397
+ -- 'defaultTopLevel' contains the default values for the component, and
398
+ -- 'mkComponent' creates a component from a 'BuildInfo'.
399
+ mkCondTree :: forall a . Semigroup a =>
400
+ a -> (C. BuildInfo -> a )
401
+ -> DependencyTree C. BuildInfo
402
+ -> DependencyTree a
403
+ mkCondTree defaultTopLevel mkComponent (C. CondNode topData topConstraints topComps) =
404
+ C. CondNode {
405
+ C. condTreeData =
406
+ defaultTopLevel <> mkComponent (defaultTopLevelBuildInfo <> topData)
407
+ , C. condTreeConstraints = topConstraints
408
+ , C. condTreeComponents = goComponents topComps
409
+ }
410
+ where
411
+ go :: DependencyTree C. BuildInfo -> DependencyTree a
412
+ go (C. CondNode ctData constraints comps) =
413
+ C. CondNode (mkComponent ctData) constraints (goComponents comps)
414
+
415
+ goComponents :: [DependencyComponent C. BuildInfo ]
416
+ -> [DependencyComponent a ]
417
+ goComponents comps = [(cond, go t, go <$> me) | (cond, t, me) <- comps]
418
+
419
+ mkBuildInfoTree :: Dependencies -> DependencyTree C. BuildInfo
420
+ mkBuildInfoTree NotBuildable =
348
421
C. CondNode {
349
- C. condTreeData = dontBuild x
422
+ C. condTreeData = mempty { C. buildable = False }
350
423
, C. condTreeConstraints = []
351
424
, C. condTreeComponents = []
352
425
}
353
- mkCondTree x dontBuild (Buildable deps) =
354
- let (directDeps, flaggedDeps) = splitDeps deps
426
+ mkBuildInfoTree (Buildable deps) =
427
+ let (libraryDeps, exts, mlang, pcpkgs, buildTools) = splitTopLevel deps
428
+ (directDeps, flaggedDeps) = splitDeps libraryDeps
429
+ bi = mempty {
430
+ C. otherExtensions = exts
431
+ , C. defaultLanguage = mlang
432
+ , C. buildTools = map mkDirect buildTools
433
+ , C. pkgconfigDepends = [mkDirect (n, (Just v)) | (n,v) <- pcpkgs]
434
+ }
355
435
in C. CondNode {
356
- C. condTreeData = x -- Necessary for language extensions
436
+ C. condTreeData = bi -- Necessary for language extensions
357
437
-- TODO: Arguably, build-tools dependencies should also
358
438
-- effect constraints on conditional tree. But no way to
359
439
-- distinguish between them
360
440
, C. condTreeConstraints = map mkDirect directDeps
361
- , C. condTreeComponents = map ( mkFlagged dontBuild) flaggedDeps
441
+ , C. condTreeComponents = map mkFlagged flaggedDeps
362
442
}
363
443
364
444
mkDirect :: (ExamplePkgName , Maybe ExamplePkgVersion ) -> C. Dependency
@@ -367,23 +447,20 @@ exAvSrcPkg ex =
367
447
where
368
448
v = C. mkVersion [n, 0 , 0 ]
369
449
370
- mkFlagged :: Monoid a
371
- => (a -> a )
372
- -> (ExampleFlagName , Dependencies , Dependencies )
373
- -> (C. Condition C. ConfVar
374
- , DependencyTree a , Maybe (DependencyTree a ))
375
- mkFlagged dontBuild (f, a, b) = ( C. Var (C. Flag (C. FlagName f))
376
- , mkCondTree mempty dontBuild a
377
- , Just (mkCondTree mempty dontBuild b)
450
+ mkFlagged :: (ExampleFlagName , Dependencies , Dependencies )
451
+ -> ( C. Condition C. ConfVar
452
+ , DependencyTree C. BuildInfo
453
+ , Maybe (DependencyTree C. BuildInfo ))
454
+ mkFlagged (f, a, b) = ( C. Var (C. Flag (C. FlagName f))
455
+ , mkBuildInfoTree a
456
+ , Just (mkBuildInfoTree b)
378
457
)
379
458
380
459
-- Split a set of dependencies into direct dependencies and flagged
381
460
-- dependencies. A direct dependency is a tuple of the name of package and
382
461
-- maybe its version (no version means any version) meant to be converted
383
462
-- to a 'C.Dependency' with 'mkDirect' for example. A flagged dependency is
384
463
-- the set of dependencies guarded by a flag.
385
- --
386
- -- TODO: Take care of flagged language extensions and language flavours.
387
464
splitDeps :: [ExampleDependency ]
388
465
-> ( [(ExamplePkgName , Maybe Int )]
389
466
, [(ExampleFlagName , Dependencies , Dependencies )]
@@ -399,55 +476,24 @@ exAvSrcPkg ex =
399
476
splitDeps (ExFlag f a b: deps) =
400
477
let (directDeps, flaggedDeps) = splitDeps deps
401
478
in (directDeps, (f, a, b): flaggedDeps)
402
- splitDeps (_ : deps ) = splitDeps deps
479
+ splitDeps (dep : _ ) = error $ " Unexpected dependency: " ++ show dep
403
480
404
- -- Currently we only support simple setup dependencies
481
+ -- custom-setup only supports simple dependencies
405
482
mkSetupDeps :: [ExampleDependency ] -> [C. Dependency ]
406
483
mkSetupDeps deps =
407
484
let (directDeps, [] ) = splitDeps deps in map mkDirect directDeps
408
485
409
- -- A 'C.Library' with just the given extensions in its 'BuildInfo'
410
- extsLib :: [Extension ] -> C. Library
411
- extsLib es = mempty { C. libBuildInfo = mempty { C. otherExtensions = es } }
412
-
413
- -- A 'C.Library' with just the given extensions in its 'BuildInfo'
414
- langLib :: Maybe Language -> C. Library
415
- langLib (Just lang) = mempty { C. libBuildInfo = mempty { C. defaultLanguage = Just lang } }
416
- langLib _ = mempty
417
-
418
- disableLib :: C. Library -> C. Library
419
- disableLib lib =
420
- lib { C. libBuildInfo = (C. libBuildInfo lib) { C. buildable = False }}
421
-
422
- disableTest :: C. TestSuite -> C. TestSuite
423
- disableTest test =
424
- test { C. testBuildInfo = (C. testBuildInfo test) { C. buildable = False }}
425
-
426
- disableExe :: C. Executable -> C. Executable
427
- disableExe exe =
428
- exe { C. buildInfo = (C. buildInfo exe) { C. buildable = False }}
429
-
430
- -- A 'C.Library' with just the given pkgconfig-depends in its 'BuildInfo'
431
- pcpkgLib :: [(ExamplePkgName , ExamplePkgVersion )] -> C. Library
432
- pcpkgLib ds = mempty { C. libBuildInfo = mempty { C. pkgconfigDepends = [mkDirect (n, (Just v)) | (n,v) <- ds] } }
433
-
434
- buildtoolsLib :: [(ExamplePkgName , Maybe Int )] -> C. Library
435
- buildtoolsLib ds = mempty { C. libBuildInfo = mempty {
436
- C. buildTools = map mkDirect ds
437
- } }
438
-
439
-
440
486
exAvPkgId :: ExampleAvailable -> C. PackageIdentifier
441
487
exAvPkgId ex = C. PackageIdentifier {
442
488
pkgName = C. mkPackageName (exAvName ex)
443
489
, pkgVersion = C. mkVersion [exAvVersion ex, 0 , 0 ]
444
490
}
445
491
446
- exInstInfo :: ExampleInstalled -> C . InstalledPackageInfo
447
- exInstInfo ex = C . emptyInstalledPackageInfo {
448
- C . installedUnitId = C. mkUnitId (exInstHash ex)
449
- , C . sourcePackageId = exInstPkgId ex
450
- , C . depends = map C. mkUnitId (exInstBuildAgainst ex)
492
+ exInstInfo :: ExampleInstalled -> IPI . InstalledPackageInfo
493
+ exInstInfo ex = IPI . emptyInstalledPackageInfo {
494
+ IPI . installedUnitId = C. mkUnitId (exInstHash ex)
495
+ , IPI . sourcePackageId = exInstPkgId ex
496
+ , IPI . depends = map C. mkUnitId (exInstBuildAgainst ex)
451
497
}
452
498
453
499
exInstPkgId :: ExampleInstalled -> C. PackageIdentifier
0 commit comments