packages feed

cabal-install 2.2.0.0 → 2.4.0.0

raw patch · 103 files changed

+4517/−10188 lines, 103 filesdep +parsecdep +textdep +zip-archivedep −QuickCheckdep −cabal-installdep −pretty-showdep ~Cabaldep ~arraydep ~asyncbinary-added

Dependencies added: parsec, text, zip-archive

Dependencies removed: QuickCheck, cabal-install, pretty-show, tagged, tasty, tasty-hunit, tasty-quickcheck

Dependency ranges changed: Cabal, array, async, base, binary, bytestring, containers, deepseq, directory, edit-distance, filepath, hashable, mtl, network, network-uri, process, random, stm, tar, time, zlib

Files

Distribution/Client/Check.hs view
@@ -25,7 +25,7 @@ import Distribution.PackageDescription.Parsec        (parseGenericPackageDescription, runParseResult) import Distribution.Parsec.Common                    (PWarning (..), showPError, showPWarning)-import Distribution.Simple.Utils                     (defaultPackageDesc, die', warn, wrapText)+import Distribution.Simple.Utils                     (defaultPackageDesc, die', notice, warn) import Distribution.Verbosity                        (Verbosity)  import qualified Data.ByteString  as BS@@ -45,6 +45,8 @@             die' verbosity $ "Failed parsing \"" ++ fpath ++ "\"."         Right x  -> return (warnings, x) +-- | Note: must be called with the CWD set to the directory containing+-- the '.cabal' file. check :: Verbosity -> IO Bool check verbosity = do     pdfile <- defaultPackageDesc verbosity@@ -66,7 +68,7 @@     --      Hovever, this is the same way hackage does it, so we will yield     --      the exact same errors as it will.     let pkg_desc = flattenPackageDescription ppd-    ioChecks <- checkPackageFiles pkg_desc "."+    ioChecks <- checkPackageFiles verbosity pkg_desc "."     let packageChecks = ioChecks ++ checkPackage ppd (Just pkg_desc) ++ ws'         buildImpossible = [ x | x@PackageBuildImpossible {} <- packageChecks ]         buildWarning    = [ x | x@PackageBuildWarning {}    <- packageChecks ]@@ -75,19 +77,19 @@         distInexusable  = [ x | x@PackageDistInexcusable {} <- packageChecks ]      unless (null buildImpossible) $ do-        putStrLn "The package will not build sanely due to these errors:"+        warn verbosity "The package will not build sanely due to these errors:"         printCheckMessages buildImpossible      unless (null buildWarning) $ do-        putStrLn "The following warnings are likely to affect your build negatively:"+        warn verbosity "The following warnings are likely to affect your build negatively:"         printCheckMessages buildWarning      unless (null distSuspicious) $ do-        putStrLn "These warnings may cause trouble when distributing the package:"+        warn verbosity "These warnings may cause trouble when distributing the package:"         printCheckMessages distSuspicious      unless (null distInexusable) $ do-        putStrLn "The following errors will cause portability problems on other environments:"+        warn verbosity "The following errors will cause portability problems on other environments:"         printCheckMessages distInexusable      let isDistError (PackageDistSuspicious     {}) = False@@ -98,13 +100,12 @@         errors = filter isDistError packageChecks      unless (null errors) $-        putStrLn "Hackage would reject this package."+        warn verbosity "Hackage would reject this package."      when (null packageChecks) $-        putStrLn "No errors or warnings could be found in the package."+        notice verbosity "No errors or warnings could be found in the package."      return (not . any isCheckError $ packageChecks)    where-    printCheckMessages = traverse_ (putStrLn . format . explanation)-    format = wrapText . ("* "++)+    printCheckMessages = traverse_ (warn verbosity . explanation)
Distribution/Client/CmdBench.hs view
@@ -81,7 +81,7 @@     baseCtx <- establishProjectBaseContext verbosity cliConfig      targetSelectors <- either (reportTargetSelectorProblems verbosity) return-                   =<< readTargetSelectors (localPackages baseCtx) targetStrings+                   =<< readTargetSelectors (localPackages baseCtx) (Just BenchKind) targetStrings      buildCtx <-       runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do@@ -100,6 +100,7 @@                          selectComponentTarget                          TargetProblemCommon                          elaboratedPlan+                         Nothing                          targetSelectors              let elaboratedPlan' = pruneInstallPlanToTargets
Distribution/Client/CmdBuild.hs view
@@ -78,7 +78,7 @@     baseCtx <- establishProjectBaseContext verbosity cliConfig      targetSelectors <- either (reportTargetSelectorProblems verbosity) return-                   =<< readTargetSelectors (localPackages baseCtx) targetStrings+                   =<< readTargetSelectors (localPackages baseCtx) Nothing targetStrings      buildCtx <-       runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do@@ -91,6 +91,7 @@                          selectComponentTarget                          TargetProblemCommon                          elaboratedPlan+                         Nothing                          targetSelectors              let elaboratedPlan' = pruneInstallPlanToTargets
+ Distribution/Client/CmdClean.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE RecordWildCards #-}+module Distribution.Client.CmdClean (cleanCommand, cleanAction) where++import Prelude ()+import Distribution.Client.Compat.Prelude++import Distribution.Client.DistDirLayout+    ( DistDirLayout(..), defaultDistDirLayout )+import Distribution.Client.ProjectConfig+    ( findProjectRoot )+import Distribution.Client.Setup+    ( GlobalFlags )+import Distribution.ReadE ( succeedReadE )+import Distribution.Simple.Setup+    ( Flag(..), toFlag, fromFlagOrDefault, flagToList, flagToMaybe+    , optionDistPref, optionVerbosity, falseArg+    )+import Distribution.Simple.Command+    ( CommandUI(..), option, reqArg )+import Distribution.Simple.Utils+    ( info, die', wrapText, handleDoesNotExist )+import Distribution.Verbosity+    ( Verbosity, normal )++import Control.Exception+    ( throwIO )+import System.Directory+    ( removeDirectoryRecursive, doesDirectoryExist )++data CleanFlags = CleanFlags+    { cleanSaveConfig :: Flag Bool+    , cleanVerbosity :: Flag Verbosity+    , cleanDistDir :: Flag FilePath+    , cleanProjectFile :: Flag FilePath+    } deriving (Eq)++defaultCleanFlags :: CleanFlags+defaultCleanFlags = CleanFlags+    { cleanSaveConfig = toFlag False+    , cleanVerbosity = toFlag normal+    , cleanDistDir = NoFlag+    , cleanProjectFile = mempty+    }++cleanCommand :: CommandUI CleanFlags+cleanCommand = CommandUI+    { commandName = "new-clean"+    , commandSynopsis = "Clean the package store and remove temporary files."+    , commandUsage = \pname ->+        "Usage: " ++ pname ++ " new-clean [FLAGS]\n"+    , commandDescription  = Just $ \_ -> wrapText $+        "Removes all temporary files created during the building process "+     ++ "(.hi, .o, preprocessed sources, etc.) and also empties out the "+     ++ "local caches (by default).\n\n"+    , commandNotes = Nothing+    , commandDefaultFlags = defaultCleanFlags+    , commandOptions = \showOrParseArgs ->+        [ optionVerbosity+            cleanVerbosity (\v flags -> flags { cleanVerbosity = v })+        , optionDistPref+            cleanDistDir (\dd flags -> flags { cleanDistDir = dd })+            showOrParseArgs+        , option [] ["project-file"]+            "Set the name of the cabal.project file to search for in parent directories"+            cleanProjectFile (\pf flags -> flags {cleanProjectFile = pf})+            (reqArg "FILE" (succeedReadE Flag) flagToList)+        , option ['s'] ["save-config"]+            "Save configuration, only remove build artifacts"+            cleanSaveConfig (\sc flags -> flags { cleanSaveConfig = sc })+            falseArg+        ]+  }++cleanAction :: CleanFlags -> [String] -> GlobalFlags -> IO ()+cleanAction CleanFlags{..} extraArgs _ = do+    let verbosity = fromFlagOrDefault normal cleanVerbosity+        saveConfig = fromFlagOrDefault False cleanSaveConfig+        mdistDirectory = flagToMaybe cleanDistDir+        mprojectFile = flagToMaybe cleanProjectFile++    unless (null extraArgs) $+        die' verbosity $ "'clean' doesn't take any extra arguments: " ++ unwords extraArgs++    projectRoot <- either throwIO return =<< findProjectRoot Nothing mprojectFile++    let distLayout = defaultDistDirLayout projectRoot mdistDirectory++    if saveConfig+        then do+            let buildRoot = distBuildRootDirectory distLayout+                unpackedSrcRoot = distUnpackedSrcRootDirectory distLayout++            buildRootExists <- doesDirectoryExist buildRoot+            unpackedSrcRootExists <- doesDirectoryExist unpackedSrcRoot++            when buildRootExists $ do+                info verbosity ("Deleting build root (" ++ buildRoot ++ ")")+                handleDoesNotExist () $ removeDirectoryRecursive buildRoot++            when unpackedSrcRootExists $ do+                info verbosity ("Deleting unpacked source root (" ++ unpackedSrcRoot ++ ")")+                handleDoesNotExist () $ removeDirectoryRecursive unpackedSrcRoot+        else do+            let distRoot = distDirectory distLayout++            info verbosity ("Deleting dist-newstyle (" ++ distRoot ++ ")")+            handleDoesNotExist () $ removeDirectoryRecursive distRoot
Distribution/Client/CmdErrorMessages.hs view
@@ -197,6 +197,12 @@  ++ "in this project (either directly or indirectly). If you want to add it "  ++ "to the project then edit the cabal.project file." +renderTargetProblemCommon verb (TargetAvailableInIndex pkgname) =+    "Cannot " ++ verb ++ " the package " ++ display pkgname ++ ", it is not "+ ++ "in this project (either directly or indirectly), but it is in the current "+ ++ "package index. If you want to add it to the project then edit the "+ ++ "cabal.project file."+ renderTargetProblemCommon verb (TargetComponentNotProjectLocal pkgid cname _) =     "Cannot " ++ verb ++ " the " ++ showComponentName cname ++ " because the "  ++ "package " ++ display pkgid ++ " is not local to the project, and cabal "
Distribution/Client/CmdFreeze.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, NamedFieldPuns, RecordWildCards #-}+{-# LANGUAGE NamedFieldPuns, RecordWildCards #-}  -- | cabal-install CLI command: freeze --@@ -209,7 +209,6 @@       :: Map PackageName [(UserConstraint, ConstraintSource)]       -> Map PackageName [(UserConstraint, ConstraintSource)]     deleteLocalPackagesVersionConstraints =-#if MIN_VERSION_containers(0,5,0)       Map.mergeWithKey         (\_pkgname () constraints ->             case filter (not . isVersionConstraint . fst) constraints of@@ -217,15 +216,6 @@               constraints' -> Just constraints')         (const Map.empty) id         localPackages-#else-      Map.mapMaybeWithKey-        (\pkgname constraints ->-            if pkgname `Map.member` localPackages-              then case filter (not . isVersionConstraint . fst) constraints of-                     []           -> Nothing-                     constraints' -> Just constraints'-              else Just constraints)-#endif      isVersionConstraint (UserConstraint _ (PackagePropertyVersion _)) = True     isVersionConstraint _                                             = False
Distribution/Client/CmdHaddock.hs view
@@ -77,7 +77,7 @@     baseCtx <- establishProjectBaseContext verbosity cliConfig      targetSelectors <- either (reportTargetSelectorProblems verbosity) return-                   =<< readTargetSelectors (localPackages baseCtx) targetStrings+                   =<< readTargetSelectors (localPackages baseCtx) Nothing targetStrings      buildCtx <-       runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do@@ -94,6 +94,7 @@                          selectComponentTarget                          TargetProblemCommon                          elaboratedPlan+                         Nothing                          targetSelectors              let elaboratedPlan' = pruneInstallPlanToTargets
Distribution/Client/CmdInstall.hs view
@@ -1,4 +1,7 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ViewPatterns #-}  -- | cabal-install CLI command: build@@ -11,7 +14,8 @@     -- * Internals exposed for testing     TargetProblem(..),     selectPackageTargets,-    selectComponentTarget+    selectComponentTarget,+    establishDummyProjectBaseContext   ) where  import Prelude ()@@ -19,56 +23,135 @@  import Distribution.Client.ProjectOrchestration import Distribution.Client.CmdErrorMessages+import Distribution.Client.CmdSdist  import Distribution.Client.Setup-         ( GlobalFlags, ConfigFlags(..), ConfigExFlags, InstallFlags )+         ( GlobalFlags(..), ConfigFlags(..), ConfigExFlags, InstallFlags+         , configureExOptions, installOptions, liftOptions )+import Distribution.Solver.Types.ConstraintSource+         ( ConstraintSource(..) ) import Distribution.Client.Types-         ( PackageSpecifier(NamedPackage), UnresolvedSourcePackage )-import Distribution.Client.ProjectPlanning.Types-         ( pkgConfigCompiler )+         ( PackageSpecifier(..), PackageLocation(..), UnresolvedSourcePackage )+import qualified Distribution.Client.InstallPlan as InstallPlan+import Distribution.Package+         ( Package(..), PackageName, mkPackageName )+import Distribution.Types.PackageId+         ( PackageIdentifier(..) ) import Distribution.Client.ProjectConfig.Types-         ( ProjectConfig, ProjectConfigBuildOnly(..)-         , projectConfigLogsDir, projectConfigStoreDir, projectConfigShared-         , projectConfigBuildOnly, projectConfigDistDir-         , projectConfigConfigFile )+         ( ProjectConfig(..), ProjectConfigShared(..)+         , ProjectConfigBuildOnly(..), PackageConfig(..)+         , getMapLast, getMapMappend, projectConfigLogsDir+         , projectConfigStoreDir, projectConfigBuildOnly+         , projectConfigDistDir, projectConfigConfigFile )+import Distribution.Simple.Program.Db+         ( userSpecifyPaths, userSpecifyArgss, defaultProgramDb+         , modifyProgramSearchPath )+import Distribution.Simple.Program.Find+         ( ProgramSearchPathEntry(..) ) import Distribution.Client.Config-         ( defaultCabalDir )+         ( getCabalDir )+import Distribution.Simple.PackageIndex+         ( InstalledPackageIndex, lookupPackageName, lookupUnitId )+import Distribution.Types.InstalledPackageInfo+         ( InstalledPackageInfo(..) )+import Distribution.Types.Version+         ( nullVersion )+import Distribution.Types.VersionRange+         ( thisVersion )+import Distribution.Solver.Types.PackageConstraint+         ( PackageProperty(..) )+import Distribution.Client.IndexUtils+         ( getSourcePackages, getInstalledPackages ) import Distribution.Client.ProjectConfig-         ( readGlobalConfig, resolveBuildTimeSettings )+         ( readGlobalConfig, projectConfigWithBuilderRepoContext+         , resolveBuildTimeSettings, withProjectOrGlobalConfig ) import Distribution.Client.DistDirLayout-         ( defaultDistDirLayout, distDirectory, mkCabalDirLayout-         , ProjectRoot(ProjectRootImplicit), distProjectCacheDirectory-         , storePackageDirectory, cabalStoreDirLayout )+         ( defaultDistDirLayout, DistDirLayout(..), mkCabalDirLayout+         , ProjectRoot(ProjectRootImplicit)+         , storePackageDirectory, cabalStoreDirLayout+         , CabalDirLayout(..), StoreDirLayout(..) ) import Distribution.Client.RebuildMonad          ( runRebuild ) import Distribution.Client.InstallSymlink          ( symlinkBinary ) import Distribution.Simple.Setup-         ( Flag(Flag), HaddockFlags, fromFlagOrDefault, flagToMaybe )+         ( Flag(Flag), HaddockFlags, fromFlagOrDefault, flagToMaybe, toFlag+         , trueArg, configureOptions, haddockOptions, flagToList )+import Distribution.Solver.Types.SourcePackage+         ( SourcePackage(..) )+import Distribution.ReadE+         ( succeedReadE ) import Distribution.Simple.Command-         ( CommandUI(..), usageAlternatives )+         ( CommandUI(..), ShowOrParseArgs(..), OptionField(..)+         , option, usageAlternatives, reqArg )+import Distribution.Simple.Configure+         ( configCompilerEx ) import Distribution.Simple.Compiler-         ( compilerId )-import Distribution.Types.PackageName-         ( mkPackageName )+         ( Compiler(..), CompilerId(..), CompilerFlavor(..) )+import Distribution.Simple.GHC+         ( ghcPlatformAndVersionString+         , GhcImplInfo(..), getImplInfo+         , GhcEnvironmentFileEntry(..)+         , renderGhcEnvironmentFile, readGhcEnvironmentFile, ParseErrorExc ) import Distribution.Types.UnitId          ( UnitId ) import Distribution.Types.UnqualComponentName          ( UnqualComponentName, unUnqualComponentName ) import Distribution.Verbosity-         ( Verbosity, normal )+         ( Verbosity, normal, lessVerbose ) import Distribution.Simple.Utils-         ( wrapText, die', notice-         , withTempDirectory, createDirectoryIfMissingVerbose )+         ( wrapText, die', notice, warn+         , withTempDirectory, createDirectoryIfMissingVerbose+         , ordNub )+import Distribution.Utils.Generic+         ( writeFileAtomic )+import Distribution.Text+         ( simpleParse ) +import Control.Exception+         ( catch )+import Control.Monad+         ( mapM, mapM_ )+import qualified Data.ByteString.Lazy.Char8 as BS+import Data.Either+         ( partitionEithers )+import Data.Ord+         ( comparing, Down(..) ) import qualified Data.Map as Map-import System.Directory ( getTemporaryDirectory, makeAbsolute )-import System.FilePath ( (</>) )+import Distribution.Utils.NubList+         ( fromNubList )+import System.Directory+         ( getHomeDirectory, doesFileExist, createDirectoryIfMissing+         , getTemporaryDirectory, makeAbsolute, doesDirectoryExist )+import System.FilePath+         ( (</>), takeDirectory, takeBaseName ) -import qualified Distribution.Client.CmdBuild as CmdBuild+data NewInstallFlags = NewInstallFlags+  { ninstInstallLibs :: Flag Bool+  , ninstEnvironmentPath :: Flag FilePath+  } -installCommand :: CommandUI (ConfigFlags, ConfigExFlags-                            ,InstallFlags, HaddockFlags)+defaultNewInstallFlags :: NewInstallFlags+defaultNewInstallFlags = NewInstallFlags+  { ninstInstallLibs = toFlag False+  , ninstEnvironmentPath = mempty+  }++newInstallOptions :: ShowOrParseArgs -> [OptionField NewInstallFlags]+newInstallOptions _ =+  [ option [] ["lib"]+    "Install libraries rather than executables from the target package."+    ninstInstallLibs (\v flags -> flags { ninstInstallLibs = v })+    trueArg+  , option [] ["package-env", "env"]+    "Set the environment file that may be modified."+    ninstEnvironmentPath (\pf flags -> flags { ninstEnvironmentPath = pf })+    (reqArg "ENV" (succeedReadE Flag) flagToList)+  ]++installCommand :: CommandUI ( ConfigFlags, ConfigExFlags, InstallFlags+                            , HaddockFlags, NewInstallFlags+                            ) installCommand = CommandUI   { commandName         = "new-install"   , commandSynopsis     = "Install packages."@@ -95,13 +178,40 @@       ++ "    Install the package in the ./pkgfoo directory\n"        ++ cmdCommonHelpTextNewBuildBeta-  , commandOptions = commandOptions CmdBuild.buildCommand-  , commandDefaultFlags = commandDefaultFlags CmdBuild.buildCommand+  , commandOptions      = \showOrParseArgs ->+        liftOptions get1 set1+        -- Note: [Hidden Flags]+        -- hide "constraint", "dependency", and+        -- "exact-configuration" from the configure options.+        (filter ((`notElem` ["constraint", "dependency"+                            , "exact-configuration"])+                 . optionName) $ configureOptions showOrParseArgs)+     ++ liftOptions get2 set2 (configureExOptions showOrParseArgs ConstraintSourceCommandlineFlag)+     ++ liftOptions get3 set3+        -- hide "target-package-db" flag from the+        -- install options.+        (filter ((`notElem` ["target-package-db"])+                 . optionName) $+                               installOptions showOrParseArgs)+       ++ liftOptions get4 set4+          -- hide "target-package-db" flag from the+          -- install options.+          (filter ((`notElem` ["v", "verbose"])+                  . optionName) $+                                haddockOptions showOrParseArgs)+     ++ liftOptions get5 set5 (newInstallOptions showOrParseArgs)+  , commandDefaultFlags = (mempty, mempty, mempty, mempty, defaultNewInstallFlags)   }+  where+    get1 (a,_,_,_,_) = a; set1 a (_,b,c,d,e) = (a,b,c,d,e)+    get2 (_,b,_,_,_) = b; set2 b (a,_,c,d,e) = (a,b,c,d,e)+    get3 (_,_,c,_,_) = c; set3 c (a,b,_,d,e) = (a,b,c,d,e)+    get4 (_,_,_,d,_) = d; set4 d (a,b,c,_,e) = (a,b,c,d,e)+    get5 (_,_,_,_,e) = e; set5 e (a,b,c,d,_) = (a,b,c,d,e)   -- | The @install@ command actually serves four different needs. It installs:--- * Nonlocal exes:+-- * exes: --   For example a program from hackage. The behavior is similar to the old --   install command, except that now conflicts between separate runs of the --   command are impossible thanks to the store.@@ -109,16 +219,17 @@ --   symlinked uin the directory specified by --symlink-bindir. --   To do this we need a dummy projectBaseContext containing the targets as --   estra packages and using a temporary dist directory.--- * Nonlocal libraries (TODO see #4558)--- * Local exes         (TODO see #4558)--- * Local libraries    (TODO see #4558)+-- * libraries+--   Libraries install through a similar process, but using GHC environment+--   files instead of symlinks. This means that 'new-install'ing libraries+--   only works on GHC >= 8.0. -- -- For more details on how this works, see the module -- "Distribution.Client.ProjectOrchestration" ---installAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)+installAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, NewInstallFlags)             -> [String] -> GlobalFlags -> IO ()-installAction (configFlags, configExFlags, installFlags, haddockFlags)+installAction (configFlags, configExFlags, installFlags, haddockFlags, newInstallFlags)             targetStrings globalFlags = do   -- We never try to build tests/benchmarks for remote packages.   -- So we set them as disabled by default and error if they are explicitly@@ -130,26 +241,227 @@     die' verbosity $ "--enable-benchmarks was specified, but benchmarks can't "                   ++ "be enabled in a remote package" -  -- We need a place to put a temporary dist directory+  let+    withProject = do+      let verbosity' = lessVerbose verbosity++      -- First, we need to learn about what's available to be installed.+      localBaseCtx <- establishProjectBaseContext verbosity' cliConfig+      let localDistDirLayout = distDirLayout localBaseCtx+      pkgDb <- projectConfigWithBuilderRepoContext verbosity' (buildSettings localBaseCtx) (getSourcePackages verbosity)++      let+        (targetStrings', packageIds) = partitionEithers . flip fmap targetStrings $+          \str -> case simpleParse str of+            Just (pkgId :: PackageId)+              | pkgVersion pkgId /= nullVersion -> Right pkgId+            _ -> Left str+        packageSpecifiers = flip fmap packageIds $ \case+          PackageIdentifier{..}+            | pkgVersion == nullVersion -> NamedPackage pkgName []+            | otherwise ->+              NamedPackage pkgName [PackagePropertyVersion (thisVersion pkgVersion)]+        packageTargets = flip TargetPackageNamed Nothing . pkgName <$> packageIds++      if null targetStrings'+        then return (packageSpecifiers, packageTargets, projectConfig localBaseCtx)+        else do+          targetSelectors <- either (reportTargetSelectorProblems verbosity) return+                        =<< readTargetSelectors (localPackages localBaseCtx) Nothing targetStrings'++          (specs, selectors) <- withInstallPlan verbosity' localBaseCtx $ \elaboratedPlan _ -> do+            -- Split into known targets and hackage packages.+            (targets, hackageNames) <- case+              resolveTargets+                selectPackageTargets+                selectComponentTarget+                TargetProblemCommon+                elaboratedPlan+                (Just pkgDb)+                targetSelectors of+              Right targets -> do+                -- Everything is a local dependency.+                return (targets, [])+              Left errs -> do+                -- Not everything is local.+                let+                  (errs', hackageNames) = partitionEithers . flip fmap errs $ \case+                    TargetProblemCommon (TargetAvailableInIndex name) -> Right name+                    err -> Left err++                when (not . null $ errs') $ reportTargetProblems verbosity errs'++                let+                  targetSelectors' = flip filter targetSelectors $ \case+                    TargetComponentUnknown name _ _+                      | name `elem` hackageNames -> False+                    TargetPackageNamed name _+                      | name `elem` hackageNames -> False+                    _ -> True++                -- This can't fail, because all of the errors are removed (or we've given up).+                targets <- either (reportTargetProblems verbosity) return $ resolveTargets+                    selectPackageTargets+                    selectComponentTarget+                    TargetProblemCommon+                    elaboratedPlan+                    Nothing+                    targetSelectors'++                return (targets, hackageNames)++            let+              planMap = InstallPlan.toMap elaboratedPlan+              targetIds = Map.keys targets++              sdistize (SpecificSourcePackage spkg@SourcePackage{..}) = SpecificSourcePackage spkg'+                where+                  sdistPath = distSdistFile localDistDirLayout packageInfoId TargzFormat+                  spkg' = spkg { packageSource = LocalTarballPackage sdistPath }+              sdistize named = named++              local = sdistize <$> localPackages localBaseCtx++              gatherTargets :: UnitId -> TargetSelector+              gatherTargets targetId = TargetPackageNamed pkgName Nothing+                where+                  Just targetUnit = Map.lookup targetId planMap+                  PackageIdentifier{..} = packageId targetUnit++              targets' = fmap gatherTargets targetIds++              hackagePkgs :: [PackageSpecifier UnresolvedSourcePackage]+              hackagePkgs = flip NamedPackage [] <$> hackageNames+              hackageTargets :: [TargetSelector]+              hackageTargets = flip TargetPackageNamed Nothing <$> hackageNames++            createDirectoryIfMissing True (distSdistDirectory localDistDirLayout)++            unless (Map.null targets) $+              mapM_+                (\(SpecificSourcePackage pkg) -> packageToSdist verbosity+                  (distProjectRootDirectory localDistDirLayout) (Archive TargzFormat)+                  (distSdistFile localDistDirLayout (packageId pkg) TargzFormat) pkg+                ) (localPackages localBaseCtx)++            if null targets+              then return (hackagePkgs, hackageTargets)+              else return (local ++ hackagePkgs, targets' ++ hackageTargets)++          return (specs ++ packageSpecifiers, selectors ++ packageTargets, projectConfig localBaseCtx)++    withoutProject globalConfig = do+      let+        parsePkg pkgName+          | Just (pkg :: PackageId) <- simpleParse pkgName = return pkg+          | otherwise = die' verbosity ("Invalid package ID: " ++ pkgName)+      packageIds <- mapM parsePkg targetStrings+      let+        packageSpecifiers = flip fmap packageIds $ \case+          PackageIdentifier{..}+            | pkgVersion == nullVersion -> NamedPackage pkgName []+            | otherwise ->+              NamedPackage pkgName [PackagePropertyVersion (thisVersion pkgVersion)]+        packageTargets = flip TargetPackageNamed Nothing . pkgName <$> packageIds+      return (packageSpecifiers, packageTargets, globalConfig <> cliConfig)++  (specs, selectors, config) <- withProjectOrGlobalConfig verbosity globalConfigFlag+                                  withProject withoutProject++  home <- getHomeDirectory+  let+    ProjectConfig {+      projectConfigShared = ProjectConfigShared {+        projectConfigHcFlavor,+        projectConfigHcPath,+        projectConfigHcPkg+      },+      projectConfigLocalPackages = PackageConfig {+        packageConfigProgramPaths,+        packageConfigProgramArgs,+        packageConfigProgramPathExtra+      }+    } = config++    hcFlavor = flagToMaybe projectConfigHcFlavor+    hcPath   = flagToMaybe projectConfigHcPath+    hcPkg    = flagToMaybe projectConfigHcPkg++    progDb =+        userSpecifyPaths (Map.toList (getMapLast packageConfigProgramPaths))+      . userSpecifyArgss (Map.toList (getMapMappend packageConfigProgramArgs))+      . modifyProgramSearchPath+          (++ [ ProgramSearchPathDir dir+              | dir <- fromNubList packageConfigProgramPathExtra ])+      $ defaultProgramDb++  (compiler@Compiler { compilerId =+    compilerId@(CompilerId compilerFlavor compilerVersion) }, platform, progDb') <-+      configCompilerEx hcFlavor hcPath hcPkg progDb verbosity++  let+    globalEnv name =+      home </> ".ghc" </> ghcPlatformAndVersionString platform compilerVersion+           </> "environments" </> name+    localEnv dir =+      dir </> ".ghc.environment." ++ ghcPlatformAndVersionString platform compilerVersion++    GhcImplInfo{ supportsPkgEnvFiles } = getImplInfo compiler+    -- Why? We know what the first part will be, we only care about the packages.+    filterEnvEntries = filter $ \case+      GhcEnvFilePackageId _ -> True+      _ -> False++  envFile <- case flagToMaybe (ninstEnvironmentPath newInstallFlags) of+    Just spec+      -- Is spec a bare word without any "pathy" content, then it refers to+      -- a named global environment.+      | takeBaseName spec == spec -> return (globalEnv spec)+      | otherwise -> do+        spec' <- makeAbsolute spec+        isDir <- doesDirectoryExist spec'+        if isDir+          -- If spec is a directory, then make an ambient environment inside+          -- that directory.+          then return (localEnv spec')+          -- Otherwise, treat it like a literal file path.+          else return spec'+    Nothing -> return (globalEnv "default")++  envFileExists <- doesFileExist envFile+  envEntries <- filterEnvEntries <$> if+    (compilerFlavor == GHC || compilerFlavor == GHCJS)+      && supportsPkgEnvFiles && envFileExists+    then catch (readGhcEnvironmentFile envFile) $ \(_ :: ParseErrorExc) ->+      warn verbosity ("The environment file " ++ envFile +++        " is unparsable. Libraries cannot be installed.") >> return []+    else return []++  cabalDir <- getCabalDir+  let+    mstoreDir   = flagToMaybe (globalStoreDir globalFlags)+    mlogsDir    = flagToMaybe (globalLogsDir globalFlags)+    cabalLayout = mkCabalDirLayout cabalDir mstoreDir mlogsDir+    packageDbs  = storePackageDBStack (cabalStoreDirLayout cabalLayout) compilerId++  installedIndex <- getInstalledPackages verbosity compiler packageDbs progDb'++  let (envSpecs, envEntries') = environmentFileToSpecifiers installedIndex envEntries++  -- Second, we need to use a fake project to let Cabal build the+  -- installables correctly. For that, we need a place to put a+  -- temporary dist directory.   globalTmp <- getTemporaryDirectory   withTempDirectory     verbosity     globalTmp     "cabal-install."     $ \tmpDir -> do--    let packageNames = mkPackageName <$> targetStrings-        packageSpecifiers =-          (\pname -> NamedPackage pname []) <$> packageNames-     baseCtx <- establishDummyProjectBaseContext                  verbosity-                 cliConfig+                 config                  tmpDir-                 packageSpecifiers--    let targetSelectors = [ TargetPackageNamed pn Nothing-                          | pn <- packageNames ]+                 (envSpecs ++ specs)      buildCtx <-       runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do@@ -161,7 +473,8 @@                          selectComponentTarget                          TargetProblemCommon                          elaboratedPlan-                         targetSelectors+                         Nothing+                         selectors              let elaboratedPlan' = pruneInstallPlanToTargets                                     TargetActionBuild@@ -180,33 +493,84 @@      buildOutcomes <- runProjectBuildPhase verbosity baseCtx buildCtx -    let compiler = pkgConfigCompiler $ elaboratedShared buildCtx-    let mkPkgBinDir = (</> "bin") .-                      storePackageDirectory-                         (cabalStoreDirLayout $ cabalDirLayout baseCtx)-                         (compilerId compiler)+    let+      mkPkgBinDir = (</> "bin") .+                    storePackageDirectory+                       (cabalStoreDirLayout $ cabalDirLayout baseCtx)+                       compilerId+      installLibs = fromFlagOrDefault False (ninstInstallLibs newInstallFlags) -    -- If there are exes, symlink them-    let symlinkBindirUnknown =-          "symlink-bindir is not defined. Set it in your cabal config file "-          ++ "or use --symlink-bindir=<path>"-    symlinkBindir <- fromFlagOrDefault (die' verbosity symlinkBindirUnknown)-                   $ fmap makeAbsolute-                   $ projectConfigSymlinkBinDir-                   $ projectConfigBuildOnly-                   $ projectConfig $ baseCtx-    createDirectoryIfMissingVerbose verbosity False symlinkBindir-    traverse_ (symlinkBuiltPackage verbosity mkPkgBinDir symlinkBindir)-          $ Map.toList $ targetsMap buildCtx+    when (not installLibs) $ do+      -- If there are exes, symlink them+      let symlinkBindirUnknown =+            "symlink-bindir is not defined. Set it in your cabal config file "+            ++ "or use --symlink-bindir=<path>"+      symlinkBindir <- fromFlagOrDefault (die' verbosity symlinkBindirUnknown)+                    $ fmap makeAbsolute+                    $ projectConfigSymlinkBinDir+                    $ projectConfigBuildOnly+                    $ projectConfig $ baseCtx+      createDirectoryIfMissingVerbose verbosity False symlinkBindir+      traverse_ (symlinkBuiltPackage verbosity mkPkgBinDir symlinkBindir)+            $ Map.toList $ targetsMap buildCtx     runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes++    when installLibs $+      if supportsPkgEnvFiles+        then do+          -- Why do we get it again? If we updated a globalPackage then we need+          -- the new version.+          installedIndex' <- getInstalledPackages verbosity compiler packageDbs progDb'+          let+            getLatest = fmap (head . snd) . take 1 . sortBy (comparing (Down . fst))+                      . lookupPackageName installedIndex'+            globalLatest = concat (getLatest <$> globalPackages)++            baseEntries =+              GhcEnvFileClearPackageDbStack : fmap GhcEnvFilePackageDb packageDbs+            globalEntries = GhcEnvFilePackageId . installedUnitId <$> globalLatest+            pkgEntries = ordNub $+                  globalEntries+              ++ envEntries'+              ++ entriesForLibraryComponents (targetsMap buildCtx)+            contents' = renderGhcEnvironmentFile (baseEntries ++ pkgEntries)+          createDirectoryIfMissing True (takeDirectory envFile)+          writeFileAtomic envFile (BS.pack contents')+        else+          warn verbosity $+              "The current compiler doesn't support safely installing libraries, "+            ++ "so only executables will be available. (Library installation is "+            ++ "supported on GHC 8.0+ only)"   where     configFlags' = disableTestsBenchsByDefault configFlags     verbosity = fromFlagOrDefault normal (configVerbosity configFlags')     cliConfig = commandLineFlagsToProjectConfig                   globalFlags configFlags' configExFlags                   installFlags haddockFlags+    globalConfigFlag = projectConfigConfigFile (projectConfigShared cliConfig) +globalPackages :: [PackageName]+globalPackages = mkPackageName <$>+  [ "ghc", "hoopl", "bytestring", "unix", "base", "time", "hpc", "filepath"+  , "process", "array", "integer-gmp", "containers", "ghc-boot", "binary"+  , "ghc-prim", "ghci", "rts", "terminfo", "transformers", "deepseq"+  , "ghc-boot-th", "pretty", "template-haskell", "directory", "text"+  , "bin-package-db"+  ] +environmentFileToSpecifiers :: InstalledPackageIndex -> [GhcEnvironmentFileEntry]+                            -> ([PackageSpecifier a], [GhcEnvironmentFileEntry])+environmentFileToSpecifiers ipi = foldMap $ \case+    (GhcEnvFilePackageId unitId)+        | Just InstalledPackageInfo{ sourcePackageId = PackageIdentifier{..}, installedUnitId }+          <- lookupUnitId ipi unitId+        , let pkgSpec = NamedPackage pkgName [PackagePropertyVersion (thisVersion pkgVersion)]+        -> if pkgName `elem` globalPackages+          then ([pkgSpec], [])+          else ([pkgSpec], [GhcEnvFilePackageId installedUnitId])+    _ -> ([], [])++ -- | Disables tests and benchmarks if they weren't explicitly enabled. disableTestsBenchsByDefault :: ConfigFlags -> ConfigFlags disableTestsBenchsByDefault configFlags =@@ -238,6 +602,20 @@     exe     $ unUnqualComponentName exe +-- | Create 'GhcEnvironmentFileEntry's for packages with exposed libraries.+entriesForLibraryComponents :: TargetsMap -> [GhcEnvironmentFileEntry]+entriesForLibraryComponents = Map.foldrWithKey' (\k v -> mappend (go k v)) []+  where+    hasLib :: (ComponentTarget, [TargetSelector]) -> Bool+    hasLib (ComponentTarget CLibName _,        _) = True+    hasLib (ComponentTarget (CSubLibName _) _, _) = True+    hasLib _                                      = False++    go :: UnitId -> [(ComponentTarget, [TargetSelector])] -> [GhcEnvironmentFileEntry]+    go unitId targets+      | any hasLib targets = [GhcEnvFilePackageId unitId]+      | otherwise          = []+ -- | Create a dummy project context, without a .cabal or a .cabal.project file -- (a place where to put a temporary dist directory is still needed) establishDummyProjectBaseContext@@ -250,7 +628,7 @@   -> IO ProjectBaseContext establishDummyProjectBaseContext verbosity cliConfig tmpDir localPackages = do -    cabalDir <- defaultCabalDir+    cabalDir <- getCabalDir      -- Create the dist directories     createDirectoryIfMissingVerbose verbosity True $ distDirectory distDirLayout@@ -264,9 +642,12 @@     let projectConfig = globalConfig <> cliConfig      let ProjectConfigBuildOnly {-          projectConfigLogsDir,-          projectConfigStoreDir+          projectConfigLogsDir         } = projectConfigBuildOnly projectConfig++        ProjectConfigShared {+          projectConfigStoreDir+        } = projectConfigShared projectConfig          mlogsDir = flagToMaybe projectConfigLogsDir         mstoreDir = flagToMaybe projectConfigStoreDir
+ Distribution/Client/CmdLegacy.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-}+module Distribution.Client.CmdLegacy ( legacyCmd, legacyWrapperCmd, newCmd ) where++import Prelude ()+import Distribution.Client.Compat.Prelude++import Distribution.Client.Sandbox+    ( loadConfigOrSandboxConfig, findSavedDistPref )+import qualified Distribution.Client.Setup as Client+import Distribution.Client.SetupWrapper+    ( SetupScriptOptions(..), setupWrapper, defaultSetupScriptOptions )+import qualified Distribution.Simple.Setup as Setup+import Distribution.Simple.Command+import Distribution.Simple.Utils+    ( warn, wrapText )+import Distribution.Verbosity +    ( Verbosity, normal )++import Control.Exception+    ( SomeException(..), try )+import qualified Data.Text as T++-- Tweaked versions of code from Main.+regularCmd :: (HasVerbosity flags) => CommandUI flags -> (flags -> [String] -> globals -> IO action) -> Bool -> CommandSpec (globals -> IO action)+regularCmd ui action shouldWarn =+        CommandSpec ui ((flip commandAddAction) (\flags extra globals -> showWarning flags >> action flags extra globals)) NormalCommand+    where+        showWarning flags = if shouldWarn +            then warn (verbosity flags) (deprecationNote (commandName ui) ++ "\n")+            else return ()++wrapperCmd :: Monoid flags => CommandUI flags -> (flags -> Setup.Flag Verbosity) -> (flags -> Setup.Flag String) -> Bool -> CommandSpec (Client.GlobalFlags -> IO ())+wrapperCmd ui verbosity' distPref shouldWarn =+  CommandSpec ui (\ui' -> wrapperAction ui' verbosity' distPref shouldWarn) NormalCommand++wrapperAction :: Monoid flags => CommandUI flags  -> (flags -> Setup.Flag Verbosity) -> (flags -> Setup.Flag String) -> Bool -> Command (Client.GlobalFlags -> IO ())+wrapperAction command verbosityFlag distPrefFlag shouldWarn =+  commandAddAction command+    { commandDefaultFlags = mempty } $ \flags extraArgs globalFlags -> do+    let verbosity' = Setup.fromFlagOrDefault normal (verbosityFlag flags)++    if shouldWarn+        then warn verbosity' (deprecationNote (commandName command) ++ "\n")+        else return ()++    load <- try (loadConfigOrSandboxConfig verbosity' globalFlags)+    let config = either (\(SomeException _) -> mempty) snd load+    distPref <- findSavedDistPref config (distPrefFlag flags)+    let setupScriptOptions = defaultSetupScriptOptions { useDistPref = distPref }++    let command' = command { commandName = T.unpack . T.replace "v1-" "" . T.pack . commandName $ command }++    setupWrapper verbosity' setupScriptOptions Nothing+                 command' (const flags) (const extraArgs)++--++class HasVerbosity a where +    verbosity :: a -> Verbosity++instance HasVerbosity (Setup.Flag Verbosity) where+    verbosity = Setup.fromFlagOrDefault normal++instance (HasVerbosity a) => HasVerbosity (a, b) where+    verbosity (a, _) = verbosity a++instance (HasVerbosity b) => HasVerbosity (a, b, c) where+    verbosity (_ , b, _) = verbosity b++instance (HasVerbosity a) => HasVerbosity (a, b, c, d) where+    verbosity (a, _, _, _) = verbosity a++instance HasVerbosity Setup.BuildFlags where+    verbosity = verbosity . Setup.buildVerbosity++instance HasVerbosity Setup.ConfigFlags where+    verbosity = verbosity . Setup.configVerbosity++instance HasVerbosity Setup.ReplFlags where+    verbosity = verbosity . Setup.replVerbosity++instance HasVerbosity Client.FreezeFlags where+    verbosity = verbosity . Client.freezeVerbosity++instance HasVerbosity Setup.HaddockFlags where+    verbosity = verbosity . Setup.haddockVerbosity++instance HasVerbosity Client.ExecFlags where+    verbosity = verbosity . Client.execVerbosity++instance HasVerbosity Client.UpdateFlags where+    verbosity = verbosity . Client.updateVerbosity++instance HasVerbosity Setup.CleanFlags where+    verbosity = verbosity . Setup.cleanVerbosity++instance HasVerbosity Client.SDistFlags where+    verbosity = verbosity . Client.sDistVerbosity++instance HasVerbosity Client.SandboxFlags where+    verbosity = verbosity . Client.sandboxVerbosity++instance HasVerbosity Setup.DoctestFlags where+    verbosity = verbosity . Setup.doctestVerbosity++--++deprecationNote :: String -> String+deprecationNote cmd = wrapText $+    "The " ++ cmd ++ " command is a part of the legacy v1 style of cabal usage.\n\n" ++++    "Please switch to using either the new project style and the new-" ++ cmd ++ +    " command or the legacy v1-" ++ cmd ++ " alias as new-style projects will" +++    " become the default in the next version of cabal-install. Please file a" +++    " bug if you cannot replicate a working v1- use case with the new-style commands.\n\n" ++++    "For more information, see: https://wiki.haskell.org/Cabal/NewBuild\n"++legacyNote :: String -> String+legacyNote cmd = wrapText $+    "The v1-" ++ cmd ++ " command is a part of the legacy v1 style of cabal usage.\n\n" ++++    "It is a legacy feature and will be removed in a future release of cabal-install." +++    " Please file a bug if you cannot replicate a working v1- use case with the new-style" +++    " commands.\n\n" ++++    "For more information, see: https://wiki.haskell.org/Cabal/NewBuild\n"++toLegacyCmd :: (Bool -> CommandSpec (globals -> IO action)) -> [CommandSpec (globals -> IO action)]+toLegacyCmd mkSpec = [toDeprecated (mkSpec True), toLegacy (mkSpec False)]+    where+        legacyMsg = T.unpack . T.replace "v1-" "" . T.pack++        toLegacy (CommandSpec origUi@CommandUI{..} action type') = CommandSpec legUi action type'+            where+                legUi = origUi+                    { commandName = "v1-" ++ commandName+                    , commandNotes = Just $ \pname -> case commandNotes of+                        Just notes -> notes pname ++ "\n" ++ legacyNote commandName+                        Nothing -> legacyNote commandName+                    }++        toDeprecated (CommandSpec origUi@CommandUI{..} action type') = CommandSpec depUi action type'+            where+                depUi = origUi+                    { commandName = legacyMsg commandName+                    , commandUsage = legacyMsg . commandUsage+                    , commandDescription = (legacyMsg .) <$> commandDescription+                    , commandNotes = Just $ \pname -> case commandNotes of+                        Just notes -> legacyMsg (notes pname) ++ "\n" ++ deprecationNote commandName+                        Nothing -> deprecationNote commandName+                    }++legacyCmd :: (HasVerbosity flags) => CommandUI flags -> (flags -> [String] -> globals -> IO action) -> [CommandSpec (globals -> IO action)]+legacyCmd ui action = toLegacyCmd (regularCmd ui action)++legacyWrapperCmd :: Monoid flags => CommandUI flags -> (flags -> Setup.Flag Verbosity) -> (flags -> Setup.Flag String) -> [CommandSpec (Client.GlobalFlags -> IO ())]+legacyWrapperCmd ui verbosity' distPref = toLegacyCmd (wrapperCmd ui verbosity' distPref)++newCmd :: CommandUI flags -> (flags -> [String] -> globals -> IO action) -> [CommandSpec (globals -> IO action)]+newCmd origUi@CommandUI{..} action = [cmd v2Ui, cmd origUi]+    where+        cmd ui = CommandSpec ui (flip commandAddAction action) NormalCommand+        v2Msg = T.unpack . T.replace "new-" "v2-" . T.pack+        v2Ui = origUi +            { commandName = v2Msg commandName+            , commandUsage = v2Msg . commandUsage+            , commandDescription = (v2Msg .) <$> commandDescription+            , commandNotes = (v2Msg .) <$> commandDescription+            }
Distribution/Client/CmdRepl.hs view
@@ -1,4 +1,8 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}  -- | cabal-install CLI command: repl --@@ -13,33 +17,126 @@     selectComponentTarget   ) where -import Distribution.Client.ProjectOrchestration-import Distribution.Client.CmdErrorMessages+import Prelude ()+import Distribution.Client.Compat.Prelude +import Distribution.Compat.Lens+import qualified Distribution.Types.Lens as L++import Distribution.Client.CmdErrorMessages+import Distribution.Client.CmdInstall+         ( establishDummyProjectBaseContext )+import qualified Distribution.Client.InstallPlan as InstallPlan+import Distribution.Client.ProjectBuilding+         ( rebuildTargetsDryRun, improveInstallPlanWithUpToDatePackages )+import Distribution.Client.ProjectConfig+         ( ProjectConfig(..), withProjectOrGlobalConfig+         , projectConfigConfigFile, readGlobalConfig )+import Distribution.Client.ProjectOrchestration+import Distribution.Client.ProjectPlanning +       ( ElaboratedSharedConfig(..), ElaboratedInstallPlan )+import Distribution.Client.RebuildMonad+         ( runRebuild ) import Distribution.Client.Setup          ( GlobalFlags, ConfigFlags(..), ConfigExFlags, InstallFlags ) import qualified Distribution.Client.Setup as Client+import Distribution.Client.Types+         ( PackageLocation(..), PackageSpecifier(..), UnresolvedSourcePackage ) import Distribution.Simple.Setup-         ( HaddockFlags, fromFlagOrDefault )+         ( HaddockFlags, fromFlagOrDefault, replOptions+         , Flag(..), toFlag, trueArg, falseArg ) import Distribution.Simple.Command-         ( CommandUI(..), usageAlternatives )+         ( CommandUI(..), liftOption, usageAlternatives, option+         , ShowOrParseArgs, OptionField, reqArg ) import Distribution.Package-         ( packageName )+         ( Package(..), packageName, UnitId, installedUnitId )+import Distribution.PackageDescription.PrettyPrint+import Distribution.Parsec.Class+         ( Parsec(..) )+import Distribution.Pretty+         ( prettyShow )+import Distribution.ReadE+         ( ReadE, parsecToReadE )+import qualified Distribution.SPDX.License as SPDX+import Distribution.Solver.Types.SourcePackage+         ( SourcePackage(..) )+import Distribution.Types.BuildInfo+         ( BuildInfo(..), emptyBuildInfo ) import Distribution.Types.ComponentName          ( componentNameString )+import Distribution.Types.CondTree+         ( CondTree(..), traverseCondTreeC )+import Distribution.Types.Dependency+         ( Dependency(..) )+import Distribution.Types.GenericPackageDescription+         ( emptyGenericPackageDescription )+import Distribution.Types.PackageDescription+         ( PackageDescription(..), emptyPackageDescription )+import Distribution.Types.Library+         ( Library(..), emptyLibrary )+import Distribution.Types.PackageId+         ( PackageIdentifier(..) )+import Distribution.Types.Version+         ( mkVersion, version0 )+import Distribution.Types.VersionRange+         ( anyVersion ) import Distribution.Text          ( display ) import Distribution.Verbosity-         ( Verbosity, normal )+         ( Verbosity, normal, lessVerbose ) import Distribution.Simple.Utils-         ( wrapText, die', ordNub )+         ( wrapText, die', debugNoWrap, ordNub, createTempDirectory, handleDoesNotExist )+import Language.Haskell.Extension+         ( Language(..) ) +import Data.List+         ( (\\) ) import qualified Data.Map as Map import qualified Data.Set as Set-import Control.Monad (when)+import System.Directory+         ( getTemporaryDirectory, removeDirectoryRecursive )+import System.FilePath+         ( (</>) ) +type ReplFlags = [String] -replCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)+data EnvFlags = EnvFlags +  { envPackages :: [Dependency]+  , envIncludeTransitive :: Flag Bool+  , envIgnoreProject :: Flag Bool+  }++defaultEnvFlags :: EnvFlags+defaultEnvFlags = EnvFlags+  { envPackages = []+  , envIncludeTransitive = toFlag True+  , envIgnoreProject = toFlag False+  }++envOptions :: ShowOrParseArgs -> [OptionField EnvFlags]+envOptions _ =+  [ option ['b'] ["build-depends"]+    "Include an additional package in the environment presented to GHCi."+    envPackages (\p flags -> flags { envPackages = p ++ envPackages flags })+    (reqArg "DEPENDENCY" dependencyReadE (fmap prettyShow :: [Dependency] -> [String]))+  , option [] ["no-transitive-deps"]+    "Don't automatically include transitive dependencies of requested packages."+    envIncludeTransitive (\p flags -> flags { envIncludeTransitive = p })+    falseArg+  , option ['z'] ["ignore-project"]+    "Only include explicitly specified packages (and 'base')."+    envIgnoreProject (\p flags -> flags { envIgnoreProject = p })+    trueArg+  ]+  where+    dependencyReadE :: ReadE [Dependency]+    dependencyReadE =+      fmap pure $+        parsecToReadE+          ("couldn't parse dependency: " ++)+          parsec++replCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, ReplFlags, EnvFlags) replCommand = Client.installCommand {   commandName         = "new-repl",   commandSynopsis     = "Open an interactive session for the given component.",@@ -69,11 +166,36 @@      ++ "    for the component named 'cname'\n"      ++ "  " ++ pname ++ " new-repl pkgname:cname\n"      ++ "    for the component 'cname' in the package 'pkgname'\n\n"+     ++ "  " ++ pname ++ " new-repl --build-depends lens\n"+     ++ "    add the latest version of the library 'lens' to the default component "+        ++ "(or no componentif there is no project present)\n"+     ++ "  " ++ pname ++ " new-repl --build-depends \"lens >= 4.15 && < 4.18\"\n"+     ++ "    add a version (constrained between 4.15 and 4.18) of the library 'lens' "+        ++ "to the default component (or no component if there is no project present)\n" -     ++ cmdCommonHelpTextNewBuildBeta+     ++ cmdCommonHelpTextNewBuildBeta,+  commandDefaultFlags = (configFlags,configExFlags,installFlags,haddockFlags,[],defaultEnvFlags),+  commandOptions = \showOrParseArgs ->+        map liftOriginal (commandOptions Client.installCommand showOrParseArgs)+        ++ map liftReplOpts (replOptions showOrParseArgs)+        ++ map liftEnvOpts  (envOptions  showOrParseArgs)    }+  where+    (configFlags,configExFlags,installFlags,haddockFlags) = commandDefaultFlags Client.installCommand +    liftOriginal = liftOption projectOriginal updateOriginal+    liftReplOpts = liftOption projectReplOpts updateReplOpts+    liftEnvOpts  = liftOption projectEnvOpts  updateEnvOpts +    projectOriginal          (a,b,c,d,_,_) = (a,b,c,d)+    updateOriginal (a,b,c,d) (_,_,_,_,e,f) = (a,b,c,d,e,f)++    projectReplOpts  (_,_,_,_,e,_) = e+    updateReplOpts e (a,b,c,d,_,f) = (a,b,c,d,e,f)++    projectEnvOpts  (_,_,_,_,_,f) = f+    updateEnvOpts f (a,b,c,d,e,_) = (a,b,c,d,e,f)+ -- | The @repl@ command is very much like @build@. It brings the install plan -- up to date, selects that part of the plan needed by the given or implicit -- repl target and then executes the plan.@@ -85,56 +207,214 @@ -- For more details on how this works, see the module -- "Distribution.Client.ProjectOrchestration" ---replAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)+replAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, ReplFlags, EnvFlags)            -> [String] -> GlobalFlags -> IO ()-replAction (configFlags, configExFlags, installFlags, haddockFlags)+replAction (configFlags, configExFlags, installFlags, haddockFlags, replFlags, envFlags)            targetStrings globalFlags = do--    baseCtx <- establishProjectBaseContext verbosity cliConfig+    let+      ignoreProject = fromFlagOrDefault False (envIgnoreProject envFlags)+      with           = withProject    cliConfig             verbosity targetStrings+      without config = withoutProject (config <> cliConfig) verbosity targetStrings+    +    (baseCtx, targetSelectors, finalizer) <- if ignoreProject+      then do+        globalConfig <- runRebuild "" $ readGlobalConfig verbosity globalConfigFlag+        without globalConfig+      else withProjectOrGlobalConfig verbosity globalConfigFlag with without -    targetSelectors <- either (reportTargetSelectorProblems verbosity) return-                   =<< readTargetSelectors (localPackages baseCtx) targetStrings+    when (buildSettingOnlyDeps (buildSettings baseCtx)) $+      die' verbosity $ "The repl command does not support '--only-dependencies'. "+          ++ "You may wish to use 'build --only-dependencies' and then "+          ++ "use 'repl'." -    buildCtx <--      runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do+    (originalComponent, baseCtx') <- if null (envPackages envFlags)+      then return (Nothing, baseCtx)+      else+        -- Unfortunately, the best way to do this is to let the normal solver+        -- help us resolve the targets, but that isn't ideal for performance,+        -- especially in the no-project case.+        withInstallPlan (lessVerbose verbosity) baseCtx $ \elaboratedPlan _ -> do+          targets <- validatedTargets elaboratedPlan targetSelectors+          +          let+            (unitId, _) = head $ Map.toList targets+            originalDeps = installedUnitId <$> InstallPlan.directDeps elaboratedPlan unitId+            oci = OriginalComponentInfo unitId originalDeps+            Just pkgId = packageId <$> InstallPlan.lookup elaboratedPlan unitId +            baseCtx' = addDepsToProjectTarget (envPackages envFlags) pkgId baseCtx -            when (buildSettingOnlyDeps (buildSettings baseCtx)) $-              die' verbosity $ "The repl command does not support '--only-dependencies'. "-                 ++ "You may wish to use 'build --only-dependencies' and then "-                 ++ "use 'repl'."+          return (Just oci, baseCtx')+          +    -- Now, we run the solver again with the added packages. While the graph +    -- won't actually reflect the addition of transitive dependencies,+    -- they're going to be available already and will be offered to the REPL+    -- and that's good enough.+    --+    -- In addition, to avoid a *third* trip through the solver, we are +    -- replicating the second half of 'runProjectPreBuildPhase' by hand+    -- here.+    (buildCtx, replFlags') <- withInstallPlan verbosity baseCtx' $ +      \elaboratedPlan elaboratedShared' -> do+        let ProjectBaseContext{..} = baseCtx'+          +        -- Recalculate with updated project.+        targets <- validatedTargets elaboratedPlan targetSelectors -            -- Interpret the targets on the command line as repl targets-            -- (as opposed to say build or haddock targets).-            targets <- either (reportTargetProblems verbosity) return-                     $ resolveTargets-                         selectPackageTargets-                         selectComponentTarget-                         TargetProblemCommon-                         elaboratedPlan-                         targetSelectors+        let +          elaboratedPlan' = pruneInstallPlanToTargets+                              TargetActionRepl+                              targets+                              elaboratedPlan+          includeTransitive = fromFlagOrDefault True (envIncludeTransitive envFlags)+          replFlags' = case originalComponent of +            Just oci -> generateReplFlags includeTransitive elaboratedPlan' oci+            Nothing  -> []+        +        pkgsBuildStatus <- rebuildTargetsDryRun distDirLayout elaboratedShared'+                                          elaboratedPlan' -            -- Reject multiple targets, or at least targets in different-            -- components. It is ok to have two module/file targets in the-            -- same component, but not two that live in different components.-            when (Set.size (distinctTargetComponents targets) > 1) $-              reportTargetProblems verbosity-                [TargetProblemMultipleTargets targets]+        let elaboratedPlan'' = improveInstallPlanWithUpToDatePackages+                                pkgsBuildStatus elaboratedPlan'+        debugNoWrap verbosity (InstallPlan.showInstallPlan elaboratedPlan'') -            let elaboratedPlan' = pruneInstallPlanToTargets-                                    TargetActionRepl-                                    targets-                                    elaboratedPlan-            return (elaboratedPlan', targets)+        let +          buildCtx = ProjectBuildContext +            { elaboratedPlanOriginal = elaboratedPlan+            , elaboratedPlanToExecute = elaboratedPlan''+            , elaboratedShared = elaboratedShared'+            , pkgsBuildStatus+            , targetsMap = targets+            }+        return (buildCtx, replFlags') -    printPlan verbosity baseCtx buildCtx+    let buildCtx' = buildCtx+          { elaboratedShared = (elaboratedShared buildCtx)+                { pkgConfigReplOptions = replFlags ++ replFlags' }+          }+    printPlan verbosity baseCtx' buildCtx' -    buildOutcomes <- runProjectBuildPhase verbosity baseCtx buildCtx-    runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes+    buildOutcomes <- runProjectBuildPhase verbosity baseCtx' buildCtx'+    runProjectPostBuildPhase verbosity baseCtx' buildCtx' buildOutcomes+    finalizer   where     verbosity = fromFlagOrDefault normal (configVerbosity configFlags)     cliConfig = commandLineFlagsToProjectConfig                   globalFlags configFlags configExFlags                   installFlags haddockFlags+    globalConfigFlag = projectConfigConfigFile (projectConfigShared cliConfig)+    +    validatedTargets elaboratedPlan targetSelectors = do+      -- Interpret the targets on the command line as repl targets+      -- (as opposed to say build or haddock targets).+      targets <- either (reportTargetProblems verbosity) return+          $ resolveTargets+              selectPackageTargets+              selectComponentTarget+              TargetProblemCommon+              elaboratedPlan+              Nothing+              targetSelectors++      -- Reject multiple targets, or at least targets in different+      -- components. It is ok to have two module/file targets in the+      -- same component, but not two that live in different components.+      when (Set.size (distinctTargetComponents targets) > 1) $+        reportTargetProblems verbosity+          [TargetProblemMultipleTargets targets]++      return targets++data OriginalComponentInfo = OriginalComponentInfo+  { ociUnitId :: UnitId+  , ociOriginalDeps :: [UnitId]+  }+  deriving (Show)++withProject :: ProjectConfig -> Verbosity -> [String] -> IO (ProjectBaseContext, [TargetSelector], IO ())+withProject cliConfig verbosity targetStrings = do+  baseCtx <- establishProjectBaseContext verbosity cliConfig++  targetSelectors <- either (reportTargetSelectorProblems verbosity) return+                 =<< readTargetSelectors (localPackages baseCtx) (Just LibKind) targetStrings++  return (baseCtx, targetSelectors, return ())++withoutProject :: ProjectConfig -> Verbosity -> [String]  -> IO (ProjectBaseContext, [TargetSelector], IO ())+withoutProject config verbosity extraArgs = do+  unless (null extraArgs) $+    die' verbosity $ "'repl' doesn't take any extra arguments when outside a project: " ++ unwords extraArgs++  globalTmp <- getTemporaryDirectory+  tempDir <- createTempDirectory globalTmp "cabal-repl."++  -- We need to create a dummy package that lives in our dummy project.+  let+    sourcePackage = SourcePackage+      { packageInfoId        = pkgId+      , packageDescription   = genericPackageDescription+      , packageSource        = LocalUnpackedPackage tempDir+      , packageDescrOverride = Nothing+      }+    genericPackageDescription = emptyGenericPackageDescription +      & L.packageDescription .~ packageDescription+      & L.condLibrary        .~ Just (CondNode library [baseDep] [])+    packageDescription = emptyPackageDescription+      { package = pkgId+      , specVersionRaw = Left (mkVersion [2, 2])+      , licenseRaw = Left SPDX.NONE+      }+    library = emptyLibrary { libBuildInfo = buildInfo }+    buildInfo = emptyBuildInfo+      { targetBuildDepends = [baseDep]+      , defaultLanguage = Just Haskell2010+      }+    baseDep = Dependency "base" anyVersion+    pkgId = PackageIdentifier "fake-package" version0++  writeGenericPackageDescription (tempDir </> "fake-package.cabal") genericPackageDescription+  +  baseCtx <- +    establishDummyProjectBaseContext+      verbosity+      config+      tempDir+      [SpecificSourcePackage sourcePackage]++  let+    targetSelectors = [TargetPackage TargetExplicitNamed [pkgId] Nothing]+    finalizer = handleDoesNotExist () (removeDirectoryRecursive tempDir)++  return (baseCtx, targetSelectors, finalizer)++addDepsToProjectTarget :: [Dependency]+                       -> PackageId+                       -> ProjectBaseContext+                       -> ProjectBaseContext+addDepsToProjectTarget deps pkgId ctx = +    (\p -> ctx { localPackages = p }) . fmap addDeps . localPackages $ ctx+  where+    addDeps :: PackageSpecifier UnresolvedSourcePackage+            -> PackageSpecifier UnresolvedSourcePackage+    addDeps (SpecificSourcePackage pkg)+      | packageId pkg /= pkgId = SpecificSourcePackage pkg+      | SourcePackage{..} <- pkg =+        SpecificSourcePackage $ pkg { packageDescription = +          packageDescription & (\f -> L.allCondTrees $ traverseCondTreeC f)+                            %~ (deps ++)+        }+    addDeps spec = spec++generateReplFlags :: Bool -> ElaboratedInstallPlan -> OriginalComponentInfo -> ReplFlags+generateReplFlags includeTransitive elaboratedPlan OriginalComponentInfo{..} = flags+  where+    deps, deps', trans, trans' :: [UnitId]+    flags :: ReplFlags+    deps   = installedUnitId <$> InstallPlan.directDeps elaboratedPlan ociUnitId+    deps'  = deps \\ ociOriginalDeps+    trans  = installedUnitId <$> InstallPlan.dependencyClosure elaboratedPlan deps'+    trans' = trans \\ ociOriginalDeps+    flags  = ("-package-id " ++) . prettyShow <$> +      if includeTransitive then trans' else deps'  -- | This defines what a 'TargetSelector' means for the @repl@ command. -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to,
Distribution/Client/CmdRun.hs view
@@ -1,4 +1,7 @@+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}  -- | cabal-install CLI command: run --@@ -6,6 +9,7 @@     -- * The @run@ CLI and action     runCommand,     runAction,+    handleShebang,      -- * Internals exposed for testing     TargetProblem(..),@@ -20,7 +24,9 @@ import Distribution.Client.CmdErrorMessages  import Distribution.Client.Setup-         ( GlobalFlags, ConfigFlags(..), ConfigExFlags, InstallFlags )+         ( GlobalFlags(..), ConfigFlags(..), ConfigExFlags, InstallFlags )+import Distribution.Client.GlobalFlags+         ( defaultGlobalFlags ) import qualified Distribution.Client.Setup as Client import Distribution.Simple.Setup          ( HaddockFlags, fromFlagOrDefault )@@ -33,12 +39,20 @@ import Distribution.Verbosity          ( Verbosity, normal ) import Distribution.Simple.Utils-         ( wrapText, die', ordNub, info )+         ( wrapText, die', ordNub, info+         , createTempDirectory, handleDoesNotExist )+import Distribution.Client.CmdInstall+         ( establishDummyProjectBaseContext )+import Distribution.Client.ProjectConfig+         ( ProjectConfig(..), ProjectConfigShared(..)+         , withProjectOrGlobalConfig ) import Distribution.Client.ProjectPlanning          ( ElaboratedConfiguredPackage(..)          , ElaboratedInstallPlan, binDirectoryFor ) import Distribution.Client.ProjectPlanning.Types          ( dataDirsEnvironmentForPlan )+import Distribution.Client.TargetSelector+         ( TargetSelectorProblem(..), TargetString(..) ) import Distribution.Client.InstallPlan          ( toList, foldPlanPackage ) import Distribution.Types.UnqualComponentName@@ -49,12 +63,51 @@ import Distribution.Types.UnitId          ( UnitId ) +import Distribution.CabalSpecVersion+         ( cabalSpecLatest )+import Distribution.Client.Types+         ( PackageLocation(..), PackageSpecifier(..) )+import Distribution.FieldGrammar+         ( takeFields, parseFieldGrammar )+import Distribution.PackageDescription.FieldGrammar+         ( executableFieldGrammar )+import Distribution.PackageDescription.PrettyPrint+         ( writeGenericPackageDescription )+import Distribution.Parsec.Common+         ( Position(..) )+import Distribution.Parsec.ParseResult+         ( ParseResult, parseString, parseFatalFailure )+import Distribution.Parsec.Parser+         ( readFields )+import qualified Distribution.SPDX.License as SPDX+import Distribution.Solver.Types.SourcePackage as SP+         ( SourcePackage(..) )+import Distribution.Types.BuildInfo+         ( BuildInfo(..) )+import Distribution.Types.CondTree+         ( CondTree(..) )+import Distribution.Types.Executable+         ( Executable(..) )+import Distribution.Types.GenericPackageDescription as GPD+         ( GenericPackageDescription(..), emptyGenericPackageDescription )+import Distribution.Types.PackageDescription+         ( PackageDescription(..), emptyPackageDescription )+import Distribution.Types.PackageId+         ( PackageIdentifier(..) )+import Distribution.Types.Version+         ( mkVersion, version0 )+import Language.Haskell.Extension+         ( Language(..) )++import qualified Data.ByteString.Char8 as BS import qualified Data.Map as Map import qualified Data.Set as Set+import qualified Text.Parsec as P+import System.Directory+         ( getTemporaryDirectory, removeDirectoryRecursive, doesFileExist ) import System.FilePath          ( (</>) ) - runCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags) runCommand = Client.installCommand {   commandName         = "new-run",@@ -91,9 +144,8 @@      ++ "    Build with '-O2' and run the program, passing it extra arguments.\n\n"       ++ cmdCommonHelpTextNewBuildBeta-   }--+  }+  -- | The @run@ command runs a specified executable-like component, building it -- first if necessary. The component can be either an executable, a test, -- or a benchmark. This is particularly useful for passing arguments to@@ -106,17 +158,40 @@           -> [String] -> GlobalFlags -> IO () runAction (configFlags, configExFlags, installFlags, haddockFlags)             targetStrings globalFlags = do--    baseCtx <- establishProjectBaseContext verbosity cliConfig+    globalTmp <- getTemporaryDirectory+    tempDir <- createTempDirectory globalTmp "cabal-repl."+  +    let+      with = +        establishProjectBaseContext verbosity cliConfig+      without config = +        establishDummyProjectBaseContext verbosity (config <> cliConfig) tempDir [] -    targetSelectors <- either (reportTargetSelectorProblems verbosity) return-                   =<< readTargetSelectors (localPackages baseCtx)-                         (take 1 targetStrings) -- Drop the exe's args.+    baseCtx <- withProjectOrGlobalConfig verbosity globalConfigFlag with without +    let+      scriptOrError script err = do+        exists <- doesFileExist script+        if exists+          then BS.readFile script >>= handleScriptCase verbosity baseCtx tempDir+          else reportTargetSelectorProblems verbosity err+        +    (baseCtx', targetSelectors) <-+      readTargetSelectors (localPackages baseCtx) (Just ExeKind) (take 1 targetStrings)+        >>= \case+          Left err@(TargetSelectorNoTargetsInProject:_)+            | (script:_) <- targetStrings -> scriptOrError script err+          Left err@(TargetSelectorNoSuch t _:_)+            | TargetString1 script <- t   -> scriptOrError script err+          Left err@(TargetSelectorExpected t _ _:_)+            | TargetString1 script <- t   -> scriptOrError script err+          Left err   -> reportTargetSelectorProblems verbosity err+          Right sels -> return (baseCtx, sels)+         buildCtx <--      runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do+      runProjectPreBuildPhase verbosity baseCtx' $ \elaboratedPlan -> do -            when (buildSettingOnlyDeps (buildSettings baseCtx)) $+            when (buildSettingOnlyDeps (buildSettings baseCtx')) $               die' verbosity $                   "The run command does not support '--only-dependencies'. "                ++ "You may wish to use 'build --only-dependencies' and then "@@ -130,6 +205,7 @@                          selectComponentTarget                          TargetProblemCommon                          elaboratedPlan+                         Nothing                          targetSelectors              -- Reject multiple targets, or at least targets in different@@ -158,10 +234,10 @@                        ++ "phase has been reached. This is a bug.")         $ targetsMap buildCtx -    printPlan verbosity baseCtx buildCtx+    printPlan verbosity baseCtx' buildCtx -    buildOutcomes <- runProjectBuildPhase verbosity baseCtx buildCtx-    runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes+    buildOutcomes <- runProjectBuildPhase verbosity baseCtx' buildCtx+    runProjectPostBuildPhase verbosity baseCtx' buildCtx buildOutcomes       let elaboratedPlan = elaboratedPlanToExecute buildCtx@@ -212,11 +288,96 @@         progInvokeArgs  = args,         progInvokeEnv   = dataDirsEnvironmentForPlan elaboratedPlan       }+    +    handleDoesNotExist () (removeDirectoryRecursive tempDir)   where     verbosity = fromFlagOrDefault normal (configVerbosity configFlags)     cliConfig = commandLineFlagsToProjectConfig                   globalFlags configFlags configExFlags                   installFlags haddockFlags+    globalConfigFlag = projectConfigConfigFile (projectConfigShared cliConfig)++handleShebang :: String -> IO ()+handleShebang script =+  runAction (commandDefaultFlags runCommand) [script] defaultGlobalFlags++parseScriptBlock :: BS.ByteString -> ParseResult Executable+parseScriptBlock str =+    case readFields str of+        Right fs -> do+            let (fields, _) = takeFields fs+            parseFieldGrammar cabalSpecLatest fields (executableFieldGrammar "script")+        Left perr -> parseFatalFailure pos (show perr) where+            ppos = P.errorPos perr+            pos  = Position (P.sourceLine ppos) (P.sourceColumn ppos)++readScriptBlock :: Verbosity -> BS.ByteString -> IO Executable+readScriptBlock verbosity = parseString parseScriptBlock verbosity "script block"++readScriptBlockFromScript :: Verbosity -> BS.ByteString -> IO (Executable, BS.ByteString)+readScriptBlockFromScript verbosity str = +    (\x -> (x, noShebang)) <$> readScriptBlock verbosity str'+  where+    start = "{- cabal:"+    end   = "-}"++    str' = BS.unlines+          . takeWhile (/= end)+          . drop 1 . dropWhile (/= start)+          $ lines'+    +    noShebang = BS.unlines +              . filter ((/= "#!") . BS.take 2)+              $ lines'++    lines' = BS.lines str++handleScriptCase :: Verbosity+                 -> ProjectBaseContext+                 -> FilePath+                 -> BS.ByteString+                 -> IO (ProjectBaseContext, [TargetSelector])+handleScriptCase verbosity baseCtx tempDir scriptContents = do+  (executable, contents') <- readScriptBlockFromScript verbosity scriptContents+  +  -- We need to create a dummy package that lives in our dummy project.+  let+    sourcePackage = SourcePackage+      { packageInfoId        = pkgId+      , SP.packageDescription   = genericPackageDescription+      , packageSource        = LocalUnpackedPackage tempDir+      , packageDescrOverride = Nothing+      }+    genericPackageDescription = emptyGenericPackageDescription +      { GPD.packageDescription = packageDescription+      , condExecutables    = [("script", CondNode executable' targetBuildDepends [])]+      }+    executable' = executable+      { modulePath = "Main.hs"+      , buildInfo = binfo +        { defaultLanguage = +          case defaultLanguage of+            just@(Just _) -> just+            Nothing       -> Just Haskell2010+        }+      }+    binfo@BuildInfo{..} = buildInfo executable+    packageDescription = emptyPackageDescription+      { package = pkgId+      , specVersionRaw = Left (mkVersion [2, 2])+      , licenseRaw = Left SPDX.NONE+      }+    pkgId = PackageIdentifier "fake-package" version0++  writeGenericPackageDescription (tempDir </> "fake-package.cabal") genericPackageDescription+  BS.writeFile (tempDir </> "Main.hs") contents'++  let+    baseCtx' = baseCtx +      { localPackages = localPackages baseCtx ++ [SpecificSourcePackage sourcePackage] }+    targetSelectors = [TargetPackage TargetExplicitNamed [pkgId] Nothing]++  return (baseCtx', targetSelectors)  singleExeOrElse :: IO (UnitId, UnqualComponentName) -> TargetsMap -> IO (UnitId, UnqualComponentName) singleExeOrElse action targetsMap =
+ Distribution/Client/CmdSdist.hs view
@@ -0,0 +1,335 @@+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}+module Distribution.Client.CmdSdist +    ( sdistCommand, sdistAction, packageToSdist+    , SdistFlags(..), defaultSdistFlags+    , OutputFormat(..), ArchiveFormat(..) ) where++import Distribution.Client.CmdErrorMessages+    ( Plural(..), renderComponentKind )+import Distribution.Client.ProjectOrchestration+    ( ProjectBaseContext(..), establishProjectBaseContext )+import Distribution.Client.TargetSelector+    ( TargetSelector(..), ComponentKind+    , readTargetSelectors, reportTargetSelectorProblems )+import Distribution.Client.RebuildMonad+    ( runRebuild )+import Distribution.Client.Setup+    ( ArchiveFormat(..), GlobalFlags(..) )+import Distribution.Solver.Types.SourcePackage+    ( SourcePackage(..) )+import Distribution.Client.Types+    ( PackageSpecifier(..), PackageLocation(..), UnresolvedSourcePackage )+import Distribution.Client.DistDirLayout+    ( DistDirLayout(..), defaultDistDirLayout )+import Distribution.Client.ProjectConfig+    ( findProjectRoot, readProjectConfig )++import Distribution.Package+    ( Package(packageId) )+import Distribution.PackageDescription.Configuration+    ( flattenPackageDescription )+import Distribution.Pretty+    ( prettyShow )+import Distribution.ReadE+    ( succeedReadE )+import Distribution.Simple.Command+    ( CommandUI(..), option, choiceOpt, reqArg )+import Distribution.Simple.PreProcess+    ( knownSuffixHandlers )+import Distribution.Simple.Setup+    ( Flag(..), toFlag, fromFlagOrDefault, flagToList, flagToMaybe+    , optionVerbosity, optionDistPref, trueArg+    )+import Distribution.Simple.SrcDist+    ( listPackageSources )+import Distribution.Simple.Utils+    ( die', notice, withOutputMarker )+import Distribution.Types.ComponentName+    ( ComponentName, showComponentName )+import Distribution.Types.PackageName+    ( PackageName, unPackageName )+import Distribution.Verbosity+    ( Verbosity, normal )++import qualified Codec.Archive.Tar       as Tar+import qualified Codec.Archive.Tar.Entry as Tar+import qualified Codec.Archive.Zip       as Zip+import qualified Codec.Compression.GZip  as GZip+import Control.Exception+    ( throwIO )+import Control.Monad+    ( when, forM, forM_ )+import Control.Monad.Trans+    ( liftIO )+import Control.Monad.State.Lazy+    ( StateT, modify, gets, evalStateT )+import Control.Monad.Writer.Lazy+    ( WriterT, tell, execWriterT )+import Data.Bits+    ( shiftL )+import qualified Data.ByteString.Char8      as BS+import qualified Data.ByteString.Lazy.Char8 as BSL+import Data.Either+    ( partitionEithers )+import Data.List+    ( find, sortOn, nub, intercalate )+import qualified Data.Set as Set+import System.Directory+    ( getCurrentDirectory, setCurrentDirectory+    , createDirectoryIfMissing, makeAbsolute )+import System.FilePath+    ( (</>), (<.>), makeRelative, normalise, takeDirectory )++sdistCommand :: CommandUI SdistFlags+sdistCommand = CommandUI+    { commandName = "new-sdist"+    , commandSynopsis = "Generate a source distribution file (.tar.gz)."+    , commandUsage = \pname ->+        "Usage: " ++ pname ++ " new-sdist [FLAGS] [PACKAGES]\n"+    , commandDescription  = Just $ \_ ->+        "Generates tarballs of project packages suitable for upload to Hackage."+    , commandNotes = Nothing+    , commandDefaultFlags = defaultSdistFlags+    , commandOptions = \showOrParseArgs ->+        [ optionVerbosity+            sdistVerbosity (\v flags -> flags { sdistVerbosity = v })+        , optionDistPref+            sdistDistDir (\dd flags -> flags { sdistDistDir = dd })+            showOrParseArgs+        , option [] ["project-file"]+            "Set the name of the cabal.project file to search for in parent directories"+            sdistProjectFile (\pf flags -> flags { sdistProjectFile = pf })+            (reqArg "FILE" (succeedReadE Flag) flagToList)+        , option ['l'] ["list-only"]+            "Just list the sources, do not make a tarball"+            sdistListSources (\v flags -> flags { sdistListSources = v })+            trueArg+        , option ['z'] ["null-sep"]+            "Separate the source files with NUL bytes rather than newlines."+            sdistNulSeparated (\v flags -> flags { sdistNulSeparated = v })+            trueArg+        , option [] ["archive-format"] +            "Choose what type of archive to create. No effect if given with '--list-only'"+                sdistArchiveFormat (\v flags -> flags { sdistArchiveFormat = v })+            (choiceOpt+                [ (Flag TargzFormat, ([], ["targz"]),+                        "Produce a '.tar.gz' format archive (default and required for uploading to hackage)")+                , (Flag ZipFormat,   ([], ["zip"]),+                        "Produce a '.zip' format archive")+                ]+            )+        , option ['o'] ["output-dir", "outputdir"]+            "Choose the output directory of this command. '-' sends all output to stdout"+            sdistOutputPath (\o flags -> flags { sdistOutputPath = o })+            (reqArg "PATH" (succeedReadE Flag) flagToList)+        ]+    }++data SdistFlags = SdistFlags+    { sdistVerbosity     :: Flag Verbosity+    , sdistDistDir       :: Flag FilePath+    , sdistProjectFile   :: Flag FilePath+    , sdistListSources   :: Flag Bool+    , sdistNulSeparated  :: Flag Bool+    , sdistArchiveFormat :: Flag ArchiveFormat+    , sdistOutputPath    :: Flag FilePath+    }++defaultSdistFlags :: SdistFlags+defaultSdistFlags = SdistFlags+    { sdistVerbosity     = toFlag normal+    , sdistDistDir       = mempty+    , sdistProjectFile   = mempty+    , sdistListSources   = toFlag False+    , sdistNulSeparated  = toFlag False+    , sdistArchiveFormat = toFlag TargzFormat+    , sdistOutputPath    = mempty+    }++--++sdistAction :: SdistFlags -> [String] -> GlobalFlags -> IO ()+sdistAction SdistFlags{..} targetStrings globalFlags = do+    let verbosity = fromFlagOrDefault normal sdistVerbosity+        mDistDirectory = flagToMaybe sdistDistDir+        mProjectFile = flagToMaybe sdistProjectFile+        globalConfig = globalConfigFile globalFlags+        listSources = fromFlagOrDefault False sdistListSources+        nulSeparated = fromFlagOrDefault False sdistNulSeparated+        archiveFormat = fromFlagOrDefault TargzFormat sdistArchiveFormat+        mOutputPath = flagToMaybe sdistOutputPath+  +    projectRoot <- either throwIO return =<< findProjectRoot Nothing mProjectFile+    let distLayout = defaultDistDirLayout projectRoot mDistDirectory+    dir <- getCurrentDirectory+    projectConfig <- runRebuild dir $ readProjectConfig verbosity globalConfig distLayout+    baseCtx <- establishProjectBaseContext verbosity projectConfig+    let localPkgs = localPackages baseCtx++    targetSelectors <- either (reportTargetSelectorProblems verbosity) return+        =<< readTargetSelectors localPkgs Nothing targetStrings+    +    mOutputPath' <- case mOutputPath of+        Just "-"  -> return (Just "-")+        Just path -> Just <$> makeAbsolute path+        Nothing   -> return Nothing+    +    let +        format =+            if | listSources, nulSeparated -> SourceList '\0'+               | listSources               -> SourceList '\n'+               | otherwise                 -> Archive archiveFormat++        ext = case format of+                SourceList _        -> "list"+                Archive TargzFormat -> "tar.gz"+                Archive ZipFormat   -> "zip"+    +        outputPath pkg = case mOutputPath' of+            Just path+                | path == "-" -> "-"+                | otherwise   -> path </> prettyShow (packageId pkg) <.> ext+            Nothing+                | listSources -> "-"+                | otherwise   -> distSdistFile distLayout (packageId pkg) archiveFormat++    createDirectoryIfMissing True (distSdistDirectory distLayout)+    +    case reifyTargetSelectors localPkgs targetSelectors of+        Left errs -> die' verbosity . unlines . fmap renderTargetProblem $ errs+        Right pkgs +            | length pkgs > 1, not listSources, Just "-" <- mOutputPath' -> +                die' verbosity "Can't write multiple tarballs to standard output!"+            | otherwise ->+                mapM_ (\pkg -> packageToSdist verbosity (distProjectRootDirectory distLayout) format (outputPath pkg) pkg) pkgs++data IsExec = Exec | NoExec+            deriving (Show, Eq)++data OutputFormat = SourceList Char+                  | Archive ArchiveFormat+                  deriving (Show, Eq)++packageToSdist :: Verbosity -> FilePath -> OutputFormat -> FilePath -> UnresolvedSourcePackage -> IO ()+packageToSdist verbosity projectRootDir format outputFile pkg = do+    dir <- case packageSource pkg of+        LocalUnpackedPackage path -> return path+        _ -> die' verbosity "The impossible happened: a local package isn't local"+    oldPwd <- getCurrentDirectory+    setCurrentDirectory dir++    let norm flag = fmap ((flag, ) . normalise)+    (norm NoExec -> nonexec, norm Exec -> exec) <- +        listPackageSources verbosity (flattenPackageDescription $ packageDescription pkg) knownSuffixHandlers++    let write = if outputFile == "-"+          then putStr . withOutputMarker verbosity . BSL.unpack+          else BSL.writeFile outputFile+        files =  nub . sortOn snd $ nonexec ++ exec++    case format of+        SourceList nulSep -> do+            let prefix = makeRelative projectRootDir dir+            write (BSL.pack . (++ [nulSep]) . intercalate [nulSep] . fmap ((prefix </>) . snd) $ files)+            when (outputFile /= "-") $+                notice verbosity $ "Wrote source list to " ++ outputFile ++ "\n"+        Archive TargzFormat -> do+            let entriesM :: StateT (Set.Set FilePath) (WriterT [Tar.Entry] IO) ()+                entriesM = do+                    let prefix = prettyShow (packageId pkg)+                    modify (Set.insert prefix)+                    case Tar.toTarPath True prefix of+                        Left err -> liftIO $ die' verbosity ("Error packing sdist: " ++ err)+                        Right path -> tell [Tar.directoryEntry path]++                    forM_ files $ \(perm, file) -> do+                        let fileDir = takeDirectory (prefix </> file)+                            perm' = case perm of+                                Exec -> Tar.executableFilePermissions+                                NoExec -> Tar.ordinaryFilePermissions+                        needsEntry <- gets (Set.notMember fileDir)++                        when needsEntry $ do+                            modify (Set.insert fileDir)+                            case Tar.toTarPath True fileDir of+                                Left err -> liftIO $ die' verbosity ("Error packing sdist: " ++ err)+                                Right path -> tell [Tar.directoryEntry path]+                            +                        contents <- liftIO . fmap BSL.fromStrict . BS.readFile $ file+                        case Tar.toTarPath False (prefix </> file) of+                            Left err -> liftIO $ die' verbosity ("Error packing sdist: " ++ err)+                            Right path -> tell [(Tar.fileEntry path contents) { Tar.entryPermissions = perm' }]+            +            entries <- execWriterT (evalStateT entriesM mempty)+            let -- Pretend our GZip file is made on Unix.+                normalize bs = BSL.concat [first, "\x03", rest']+                    where+                        (first, rest) = BSL.splitAt 9 bs+                        rest' = BSL.tail rest+            write . normalize . GZip.compress . Tar.write $ entries+            when (outputFile /= "-") $+                notice verbosity $ "Wrote tarball sdist to " ++ outputFile ++ "\n"+        Archive ZipFormat -> do+            let prefix = prettyShow (packageId pkg)+            entries <- forM files $ \(perm, file) -> do+                let perm' = case perm of+                        -- -rwxr-xr-x+                        Exec   -> 0o010755 `shiftL` 16+                        -- -rw-r--r--+                        NoExec -> 0o010644 `shiftL` 16+                contents <- BSL.readFile file+                return $ (Zip.toEntry (prefix </> file) 0 contents) { Zip.eExternalFileAttributes = perm' }+            let archive = foldr Zip.addEntryToArchive Zip.emptyArchive entries+            write (Zip.fromArchive archive)+            when (outputFile /= "-") $+                notice verbosity $ "Wrote zip sdist to " ++ outputFile ++ "\n"+    setCurrentDirectory oldPwd++--++reifyTargetSelectors :: [PackageSpecifier UnresolvedSourcePackage] -> [TargetSelector] -> Either [TargetProblem] [UnresolvedSourcePackage]+reifyTargetSelectors pkgs sels = +    case partitionEithers (foldMap go sels) of+        ([], sels') -> Right sels'+        (errs, _)   -> Left errs+    where+        flatten (SpecificSourcePackage pkg@SourcePackage{}) = pkg+        flatten _ = error "The impossible happened: how do we not know about a local package?"+        pkgs' = fmap flatten pkgs++        getPkg pid = case find ((== pid) . packageId) pkgs' of+            Just pkg -> Right pkg+            Nothing -> error "The impossible happened: we have a reference to a local package that isn't in localPackages."+        +        go :: TargetSelector -> [Either TargetProblem UnresolvedSourcePackage]+        go (TargetPackage _ pids Nothing) = fmap getPkg pids+        go (TargetAllPackages Nothing) = Right <$> pkgs'++        go (TargetPackage _ _ (Just kind)) = [Left (AllComponentsOnly kind)]+        go (TargetAllPackages (Just kind)) = [Left (AllComponentsOnly kind)]++        go (TargetPackageNamed pname _) = [Left (NonlocalPackageNotAllowed pname)]+        go (TargetComponentUnknown pname _ _) = [Left (NonlocalPackageNotAllowed pname)]++        go (TargetComponent _ cname _) = [Left (ComponentsNotAllowed cname)]++data TargetProblem = AllComponentsOnly ComponentKind+                   | NonlocalPackageNotAllowed PackageName+                   | ComponentsNotAllowed ComponentName++renderTargetProblem :: TargetProblem -> String+renderTargetProblem (AllComponentsOnly kind) =+    "It is not possible to package only the " ++ renderComponentKind Plural kind ++ " from a package "+    ++ "for distribution. Only entire packages may be packaged for distribution."+renderTargetProblem (ComponentsNotAllowed cname) =+    "The component " ++ showComponentName cname ++ " cannot be packaged for distribution on its own. "+    ++ "Only entire packages may be packaged for distribution."+renderTargetProblem (NonlocalPackageNotAllowed pname) =+    "The package " ++ unPackageName pname ++ " cannot be packaged for distribution, because it is not "+    ++ "local to this project."+
Distribution/Client/CmdTest.hs view
@@ -50,7 +50,10 @@      ++ "Dependencies are built or rebuilt as necessary. Additional "      ++ "configuration flags can be specified on the command line and these "      ++ "extend the project configuration from the 'cabal.project', "-     ++ "'cabal.project.local' and other files.",+     ++ "'cabal.project.local' and other files.\n\n"++     ++ "To pass command-line arguments to a test suite, see the "+     ++ "new-run command.",   commandNotes        = Just $ \pname ->         "Examples:\n"      ++ "  " ++ pname ++ " new-test\n"@@ -84,7 +87,7 @@     baseCtx <- establishProjectBaseContext verbosity cliConfig      targetSelectors <- either (reportTargetSelectorProblems verbosity) return-                   =<< readTargetSelectors (localPackages baseCtx) targetStrings+                   =<< readTargetSelectors (localPackages baseCtx) (Just TestKind) targetStrings      buildCtx <-       runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do@@ -103,6 +106,7 @@                          selectComponentTarget                          TargetProblemCommon                          elaboratedPlan+                         Nothing                          targetSelectors              let elaboratedPlan' = pruneInstallPlanToTargets
Distribution/Client/CmdUpdate.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, NamedFieldPuns, RecordWildCards, ViewPatterns,+{-# LANGUAGE CPP, LambdaCase, NamedFieldPuns, RecordWildCards, ViewPatterns,              TupleSections #-}  -- | cabal-install CLI command: update@@ -8,12 +8,17 @@     updateAction,   ) where +import Prelude ()+import Distribution.Client.Compat.Prelude    + import Distribution.Client.Compat.Directory          ( setModificationTime ) import Distribution.Client.ProjectOrchestration import Distribution.Client.ProjectConfig          ( ProjectConfig(..)-         , projectConfigWithSolverRepoContext )+         , ProjectConfigShared(projectConfigConfigFile)+         , projectConfigWithSolverRepoContext+         , withProjectOrGlobalConfig ) import Distribution.Client.Types          ( Repo(..), RemoteRepo(..), isRepoRemote ) import Distribution.Client.HttpUtils@@ -29,7 +34,7 @@ import Distribution.Simple.Setup          ( HaddockFlags, fromFlagOrDefault ) import Distribution.Simple.Utils-         ( die', notice, wrapText, writeFileAtomic, noticeNoWrap, intercalate )+         ( die', notice, wrapText, writeFileAtomic, noticeNoWrap ) import Distribution.Verbosity          ( Verbosity, normal, lessVerbose ) import Distribution.Client.IndexUtils.Timestamp@@ -43,7 +48,7 @@ import qualified Distribution.Compat.ReadP  as ReadP import qualified Text.PrettyPrint           as Disp -import Control.Monad (unless, when)+import Control.Monad (mapM, mapM_) import qualified Data.ByteString.Lazy       as BS import Distribution.Client.GZipUtils (maybeDecompress) import System.FilePath ((<.>), dropExtension)@@ -109,10 +114,9 @@              -> [String] -> GlobalFlags -> IO () updateAction (configFlags, configExFlags, installFlags, haddockFlags)              extraArgs globalFlags = do--  ProjectBaseContext {-    projectConfig-  } <- establishProjectBaseContext verbosity cliConfig+  projectConfig <- withProjectOrGlobalConfig verbosity globalConfigFlag+    (projectConfig <$> establishProjectBaseContext verbosity cliConfig)+    (\globalConfig -> return $ globalConfig <> cliConfig)    projectConfigWithSolverRepoContext verbosity     (projectConfigShared projectConfig) (projectConfigBuildOnly projectConfig)@@ -165,6 +169,7 @@     cliConfig = commandLineFlagsToProjectConfig                   globalFlags configFlags configExFlags                   installFlags haddockFlags+    globalConfigFlag = projectConfigConfigFile (projectConfigShared cliConfig)  updateRepo :: Verbosity -> UpdateFlags -> RepoContext -> (Repo, IndexState)            -> IO ()
Distribution/Client/Compat/ExecutablePath.hs view
@@ -35,25 +35,6 @@ import System.Posix.Internals #endif --- GHC 7.0.* compatibility. 'System.Posix.Internals' in base-4.3.* doesn't--- provide 'peekFilePath' and 'peekFilePathLen'.-#if !MIN_VERSION_base(4,4,0)-#ifdef mingw32_HOST_OS--peekFilePath :: CWString -> IO FilePath-peekFilePath = peekCWString--#else--peekFilePath :: CString -> IO FilePath-peekFilePath = peekCString--peekFilePathLen :: CStringLen -> IO FilePath-peekFilePathLen = peekCStringLen--#endif-#endif- -- The exported function is defined outside any if-guard to make sure -- every OS implements it with the same type. 
Distribution/Client/Compat/Prelude.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE CPP #-}- -- to suppress WARNING in "Distribution.Compat.Prelude.Internal" {-# OPTIONS_GHC -fno-warn-deprecations #-} @@ -20,16 +18,5 @@  import Prelude (IO) import Distribution.Compat.Prelude.Internal hiding (IO)--#if MIN_VERSION_base(4,6,0) import Text.Read          ( readMaybe )-#endif--#if !MIN_VERSION_base(4,6,0)--- | An implementation of readMaybe, for compatibility with older base versions.-readMaybe :: Read a => String -> Maybe a-readMaybe s = case reads s of-                [(x,"")] -> Just x-                _        -> Nothing-#endif
Distribution/Client/Compat/Process.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE CPP #-}- ----------------------------------------------------------------------------- -- | -- Module      :  Distribution.Client.Compat.Process@@ -17,10 +15,6 @@ module Distribution.Client.Compat.Process (   readProcessWithExitCode ) where--#if !MIN_VERSION_base(4,6,0)-import           Prelude           hiding (catch)-#endif  import           Control.Exception (catch, throw) import           System.Exit       (ExitCode (ExitFailure))
Distribution/Client/Config.hs view
@@ -22,7 +22,7 @@     showConfigWithComments,     parseConfig, -    defaultCabalDir,+    getCabalDir,     defaultConfigFile,     defaultCacheDir,     defaultCompiler,@@ -124,7 +124,7 @@ import System.IO.Error          ( isDoesNotExistError ) import Distribution.Compat.Environment-         ( getEnvironment )+         ( getEnvironment, lookupEnv ) import Distribution.Compat.Exception          ( catchIO ) import qualified Paths_cabal_install@@ -408,12 +408,14 @@         haddockInternal      = combine haddockInternal,         haddockCss           = combine haddockCss,         haddockLinkedSource  = combine haddockLinkedSource,+        haddockQuickJump     = combine haddockQuickJump,         haddockHscolourCss   = combine haddockHscolourCss,         haddockContents      = combine haddockContents,         haddockDistPref      = combine haddockDistPref,         haddockKeepTempFiles = combine haddockKeepTempFiles,         haddockVerbosity     = combine haddockVerbosity,-        haddockCabalFilePath = combine haddockCabalFilePath+        haddockCabalFilePath = combine haddockCabalFilePath,+        haddockArgs          = lastNonEmpty haddockArgs         }         where           combine      = combine'        savedHaddockFlags@@ -431,7 +433,7 @@ -- baseSavedConfig :: IO SavedConfig baseSavedConfig = do-  userPrefix <- defaultCabalDir+  userPrefix <- getCabalDir   cacheDir   <- defaultCacheDir   logsDir    <- defaultLogsDir   worldFile  <- defaultWorldFile@@ -481,40 +483,45 @@     }   } ---TODO: misleading, there's no way to override this default---      either make it possible or rename to simply getCabalDir. defaultCabalDir :: IO FilePath defaultCabalDir = getAppUserDataDirectory "cabal" +getCabalDir :: IO FilePath+getCabalDir = do+  mDir <- lookupEnv "CABAL_DIR"+  case mDir of+    Nothing -> defaultCabalDir+    Just dir -> return dir+ defaultConfigFile :: IO FilePath defaultConfigFile = do-  dir <- defaultCabalDir+  dir <- getCabalDir   return $ dir </> "config"  defaultCacheDir :: IO FilePath defaultCacheDir = do-  dir <- defaultCabalDir+  dir <- getCabalDir   return $ dir </> "packages"  defaultLogsDir :: IO FilePath defaultLogsDir = do-  dir <- defaultCabalDir+  dir <- getCabalDir   return $ dir </> "logs"  -- | Default position of the world file defaultWorldFile :: IO FilePath defaultWorldFile = do-  dir <- defaultCabalDir+  dir <- getCabalDir   return $ dir </> "world"  defaultExtraPath :: IO [FilePath] defaultExtraPath = do-  dir <- defaultCabalDir+  dir <- getCabalDir   return [dir </> "bin"]  defaultSymlinkPath :: IO FilePath defaultSymlinkPath = do-  dir <- defaultCabalDir+  dir <- getCabalDir   return (dir </> "bin")  defaultCompiler :: CompilerFlavor
Distribution/Client/Configure.hs view
@@ -134,7 +134,7 @@         ++ message         ++ "\nTrying configure anyway."       setupWrapper verbosity (setupScriptOptions installedPkgIndex Nothing)-        Nothing configureCommand (const configFlags) extraArgs+        Nothing configureCommand (const configFlags) (const extraArgs)      Right installPlan0 ->      let installPlan = InstallPlan.configureInstallPlan configFlags installPlan0@@ -387,7 +387,7 @@                  extraArgs =    setupWrapper verbosity-    scriptOptions (Just pkg) configureCommand configureFlags extraArgs+    scriptOptions (Just pkg) configureCommand configureFlags (const extraArgs)    where     gpkg = packageDescription spkg
Distribution/Client/Dependency.hs view
@@ -946,24 +946,24 @@         (sortNubOn dependencyName required)         (sortNubOn packageName    specified) +    compSpec = enableStanzas stanzas     -- TODO: It would be nicer to use ComponentDeps here so we can be more-    -- precise in our checks. That's a bit tricky though, as this currently-    -- relies on the 'buildDepends' field of 'PackageDescription'. (OTOH, that-    -- field is deprecated and should be removed anyway.)  As long as we _do_-    -- use a flat list here, we have to allow for duplicates when we fold-    -- specifiedDeps; once we have proper ComponentDeps here we should get rid-    -- of the `nubOn` in `mergeDeps`.+    -- precise in our checks. In fact, this no longer relies on buildDepends and+    -- thus should be easier to fix. As long as we _do_ use a flat list here, we+    -- have to allow for duplicates when we fold specifiedDeps; once we have+    -- proper ComponentDeps here we should get rid of the `nubOn` in+    -- `mergeDeps`.     requiredDeps :: [Dependency]     requiredDeps =       --TODO: use something lower level than finalizePD       case finalizePD specifiedFlags-         (enableStanzas stanzas)+         compSpec          (const True)          platform cinfo          []          (packageDescription pkg) of         Right (resolvedPkg, _) ->-             externalBuildDepends resolvedPkg+             externalBuildDepends resolvedPkg compSpec           ++ maybe [] PD.setupDepends (PD.setupBuildInfo resolvedPkg)         Left  _ ->           error "configuredPackageInvalidDeps internal error"
Distribution/Client/DistDirLayout.hs view
@@ -27,10 +27,14 @@  import Distribution.Package          ( PackageId, ComponentId, UnitId )+import Distribution.Client.Setup+         ( ArchiveFormat(..) ) import Distribution.Compiler import Distribution.Simple.Compiler          ( PackageDB(..), PackageDBStack, OptimisationLevel(..) ) import Distribution.Text+import Distribution.Pretty+         ( prettyShow ) import Distribution.Types.ComponentName import Distribution.System @@ -85,10 +89,14 @@        distBuildDirectory           :: DistDirParams -> FilePath,        distBuildRootDirectory       :: FilePath, +       -- | The directory under dist where we download tarballs and source+       -- control repos to.+       --+       distDownloadSrcDirectory     :: FilePath,+        -- | The directory under dist where we put the unpacked sources of        -- packages, in those cases where it makes sense to keep the build-       -- artifacts to reduce rebuild times. These can be tarballs or could be-       -- scm repos.+       -- artifacts to reduce rebuild times.        --        distUnpackedSrcDirectory     :: PackageId -> FilePath,        distUnpackedSrcRootDirectory :: FilePath,@@ -105,6 +113,10 @@        distPackageCacheFile         :: DistDirParams -> String -> FilePath,        distPackageCacheDirectory    :: DistDirParams -> FilePath, +       -- | The location that sdists are placed by default.+       distSdistFile                :: PackageId -> ArchiveFormat -> FilePath,+       distSdistDirectory           :: FilePath,+        distTempDirectory            :: FilePath,        distBinDirectory             :: FilePath, @@ -205,12 +217,22 @@     distUnpackedSrcRootDirectory   = distDirectory </> "src"     distUnpackedSrcDirectory pkgid = distUnpackedSrcRootDirectory                                       </> display pkgid+    -- we shouldn't get name clashes so this should be fine:+    distDownloadSrcDirectory       = distUnpackedSrcRootDirectory      distProjectCacheDirectory = distDirectory </> "cache"     distProjectCacheFile name = distProjectCacheDirectory </> name      distPackageCacheDirectory params = distBuildDirectory params </> "cache"     distPackageCacheFile params name = distPackageCacheDirectory params </> name++    distSdistFile pid format = distSdistDirectory </> prettyShow pid <.> ext+        where+          ext = case format of+            TargzFormat -> "tar.gz"+            ZipFormat -> "zip"+    +    distSdistDirectory = distDirectory </> "sdist"      distTempDirectory = distDirectory </> "tmp" 
Distribution/Client/Fetch.hs view
@@ -218,6 +218,10 @@       die' verbosity $ "The 'fetch' command does not yet support remote tarballs. "          ++ "In the meantime you can use the 'unpack' commands." +    RemoteSourceRepoPackage _repo _ ->+      die' verbosity $ "The 'fetch' command does not yet support remote "+         ++ "source repositores."+     RepoTarballPackage repo pkgid _ -> do       _ <- fetchRepoTarball verbosity repoCtxt repo pkgid       return ()
Distribution/Client/FetchUtils.hs view
@@ -40,13 +40,15 @@ import Distribution.Package          ( PackageId, packageName, packageVersion ) import Distribution.Simple.Utils-         ( notice, info, debug, setupMessage )+         ( notice, info, debug, die' ) import Distribution.Text          ( display ) import Distribution.Verbosity          ( Verbosity, verboseUnmarkOutput ) import Distribution.Client.GlobalFlags          ( RepoContext(..) )+import Distribution.Client.Utils+         ( ProgressPhase(..), progressMessage )  import Data.Maybe import Data.Map (Map)@@ -81,6 +83,8 @@     LocalTarballPackage  _file      -> return True     RemoteTarballPackage _uri local -> return (isJust local)     RepoTarballPackage repo pkgid _ -> doesFileExist (packageFile repo pkgid)+    RemoteSourceRepoPackage _ local -> return (isJust local)+      -- | Checks if the package has already been fetched (or does not need -- fetching) and if so returns evidence in the form of a 'PackageLocation'@@ -97,13 +101,15 @@       return (Just $ RemoteTarballPackage uri file)     RepoTarballPackage repo pkgid (Just file) ->       return (Just $ RepoTarballPackage repo pkgid file)+    RemoteSourceRepoPackage repo (Just dir) ->+      return (Just $ RemoteSourceRepoPackage repo dir) -    RemoteTarballPackage _uri Nothing -> return Nothing+    RemoteTarballPackage     _uri Nothing -> return Nothing+    RemoteSourceRepoPackage _repo Nothing -> return Nothing     RepoTarballPackage repo pkgid Nothing ->       fmap (fmap (RepoTarballPackage repo pkgid))            (checkRepoTarballFetched repo pkgid) - -- | Like 'checkFetched' but for the specific case of a 'RepoTarballPackage'. -- checkRepoTarballFetched :: Repo -> PackageId -> IO (Maybe FilePath)@@ -130,6 +136,8 @@       return (RemoteTarballPackage uri file)     RepoTarballPackage repo pkgid (Just file) ->       return (RepoTarballPackage repo pkgid file)+    RemoteSourceRepoPackage repo (Just dir) ->+      return (RemoteSourceRepoPackage repo dir)      RemoteTarballPackage uri Nothing -> do       path <- downloadTarballPackage uri@@ -137,6 +145,8 @@     RepoTarballPackage repo pkgid Nothing -> do       local <- fetchRepoTarball verbosity repoCtxt repo pkgid       return (RepoTarballPackage repo pkgid local)+    RemoteSourceRepoPackage _repo Nothing ->+      die' verbosity "fetchPackage: source repos not supported"   where     downloadTarballPackage uri = do       transport <- repoContextGetTransport repoCtxt@@ -157,8 +167,12 @@   if fetched     then do info verbosity $ display pkgid ++ " has already been downloaded."             return (packageFile repo pkgid)-    else do setupMessage verbosity "Downloading" pkgid-            downloadRepoPackage+    else do progressMessage verbosity ProgressDownloading (display pkgid)+            res <- downloadRepoPackage+            progressMessage verbosity ProgressDownloaded (display pkgid)+            return res++   where     downloadRepoPackage = case repo of       RepoLocal{..} -> return (packageFile repo pkgid)
Distribution/Client/FileMonitor.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, DeriveGeneric, DeriveFunctor, GeneralizedNewtypeDeriving,+{-# LANGUAGE DeriveGeneric, DeriveFunctor, GeneralizedNewtypeDeriving,              NamedFieldPuns, BangPatterns #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -39,11 +39,7 @@ import Prelude () import Distribution.Client.Compat.Prelude -#if MIN_VERSION_containers(0,5,0) import qualified Data.Map.Strict as Map-#else-import qualified Data.Map        as Map-#endif import qualified Data.ByteString.Lazy as BS import qualified Distribution.Compat.Binary as Binary import qualified Data.Hashable as Hashable
Distribution/Client/GenBounds.hs view
@@ -29,7 +29,7 @@ import Distribution.Package          ( Package(..), unPackageName, packageName, packageVersion ) import Distribution.PackageDescription-         ( buildDepends )+         ( enabledBuildDepends ) import Distribution.PackageDescription.Configuration          ( finalizePD ) import Distribution.PackageDescription.Parsec@@ -122,7 +122,7 @@       Left _ -> putStrLn "finalizePD failed"       Right (pd,_) -> do         let needBounds = filter (not . hasUpperBound . depVersion) $-                         buildDepends pd+                         enabledBuildDepends pd defaultComponentRequestedSpec          if (null needBounds)           then putStrLn
Distribution/Client/Get.hs view
@@ -14,7 +14,12 @@ -----------------------------------------------------------------------------  module Distribution.Client.Get (-    get+    get,++    -- * Cloning 'SourceRepo's+    -- | Mainly exported for testing purposes+    clonePackagesFromSourceRepo,+    ClonePackageException(..),   ) where  import Prelude ()@@ -25,39 +30,33 @@ import Distribution.Simple.Setup          ( Flag(..), fromFlag, fromFlagOrDefault, flagToMaybe ) import Distribution.Simple.Utils-         ( notice, die', info, rawSystemExitCode, writeFileAtomic )+         ( notice, die', info, writeFileAtomic ) import Distribution.Verbosity          ( Verbosity )-import Distribution.Text(display)+import Distribution.Text (display) import qualified Distribution.PackageDescription as PD+import Distribution.Simple.Program+         ( programName )  import Distribution.Client.Setup          ( GlobalFlags(..), GetFlags(..), RepoContext(..) ) import Distribution.Client.Types import Distribution.Client.Targets import Distribution.Client.Dependency+import Distribution.Client.VCS import Distribution.Client.FetchUtils import qualified Distribution.Client.Tar as Tar (extractTarGzFile) import Distribution.Client.IndexUtils as IndexUtils         ( getSourcePackagesAtIndexState )-import Distribution.Client.Compat.Process-        ( readProcessWithExitCode )-import Distribution.Compat.Exception-        ( catchIO )- import Distribution.Solver.Types.SourcePackage  import Control.Exception-         ( finally )+         ( Exception(..), catch, throwIO ) import Control.Monad-         ( forM_, mapM_ )-import qualified Data.Map-import Data.Ord-         ( comparing )+         ( mapM, forM_, mapM_ )+import qualified Data.Map as Map import System.Directory-         ( createDirectoryIfMissing, doesDirectoryExist, doesFileExist-         , getCurrentDirectory, setCurrentDirectory-         )+         ( createDirectoryIfMissing, doesDirectoryExist, doesFileExist ) import System.Exit          ( ExitCode(..) ) import System.FilePath@@ -75,11 +74,11 @@     notice verbosity "No packages requested. Nothing to do."  get verbosity repoCtxt globalFlags getFlags userTargets = do-  let useFork = case (getSourceRepository getFlags) of-        NoFlag -> False-        _      -> True+  let useSourceRepo = case getSourceRepository getFlags of+                        NoFlag -> False+                        _      -> True -  unless useFork $+  unless useSourceRepo $     mapM_ (checkTarget verbosity) userTargets    let idxState = flagToMaybe $ getIndexState getFlags@@ -98,8 +97,8 @@   unless (null prefix) $     createDirectoryIfMissing True prefix -  if useFork-    then fork pkgs+  if useSourceRepo+    then clone  pkgs     else unpack pkgs    where@@ -109,11 +108,15 @@      prefix = fromFlagOrDefault "" (getDestDir getFlags) -    fork :: [UnresolvedSourcePackage] -> IO ()-    fork pkgs = do-      let kind = fromFlag . getSourceRepository $ getFlags-      branchers <- findUsableBranchers-      mapM_ (forkPackage verbosity branchers prefix kind) pkgs+    clone :: [UnresolvedSourcePackage] -> IO ()+    clone = clonePackagesFromSourceRepo verbosity prefix kind+          . map (\pkg -> (packageId pkg, packageSourceRepos pkg))+      where+        kind = fromFlag . getSourceRepository $ getFlags+        packageSourceRepos :: SourcePackage loc -> [SourceRepo]+        packageSourceRepos = PD.sourceRepos+                           . PD.packageDescription+                           . packageDescription      unpack :: [UnresolvedSourcePackage] -> IO ()     unpack pkgs = do@@ -132,6 +135,10 @@           RepoTarballPackage _repo _pkgid tarballPath ->             unpackPackage verbosity prefix pkgid descOverride tarballPath +          RemoteSourceRepoPackage _repo _ ->+            die' verbosity $ "The 'get' command does no yet support targets "+                          ++ "that are remote source repositories."+           LocalUnpackedPackage _ ->             error "Distribution.Client.Get.unpack: the impossible happened."       where@@ -178,174 +185,115 @@   -- --------------------------------------------------------------- * Forking the source repository+-- * Cloning packages from their declared source repositories -- ------------------------------------------------------------ -data BranchCmd = BranchCmd (Verbosity -> FilePath -> IO ExitCode) -data Brancher = Brancher-    { brancherBinary :: String-    , brancherBuildCmd :: PD.SourceRepo -> Maybe BranchCmd-    }+data ClonePackageException =+       ClonePackageNoSourceRepos       PackageId+     | ClonePackageNoSourceReposOfKind PackageId (Maybe RepoKind)+     | ClonePackageNoRepoType          PackageId SourceRepo+     | ClonePackageUnsupportedRepoType PackageId SourceRepo RepoType+     | ClonePackageNoRepoLocation      PackageId SourceRepo+     | ClonePackageDestinationExists   PackageId FilePath Bool+     | ClonePackageFailedWithExitCode  PackageId SourceRepo String ExitCode+  deriving (Show, Eq) --- | The set of all supported branch drivers.-allBranchers :: [(PD.RepoType, Brancher)]-allBranchers =-    [ (PD.Bazaar, branchBzr)-    , (PD.Darcs, branchDarcs)-    , (PD.Git, branchGit)-    , (PD.Mercurial, branchHg)-    , (PD.SVN, branchSvn)-    ]+instance Exception ClonePackageException where+  displayException (ClonePackageNoSourceRepos pkgid) =+       "Cannot fetch a source repository for package " ++ display pkgid+    ++ ". The package does not specify any source repositories." --- | Find which usable branch drivers (selected from 'allBranchers') are--- available and usable on the local machine.------ Each driver's main command is run with @--help@, and if the child process--- exits successfully, that brancher is considered usable.-findUsableBranchers :: IO (Data.Map.Map PD.RepoType Brancher)-findUsableBranchers = do-    let usable (_, brancher) = flip catchIO (const (return False)) $ do-         let cmd = brancherBinary brancher-         (exitCode, _, _) <- readProcessWithExitCode cmd ["--help"] ""-         return (exitCode == ExitSuccess)-    pairs <- filterM usable allBranchers-    return (Data.Map.fromList pairs)+  displayException (ClonePackageNoSourceReposOfKind pkgid repoKind) =+       "Cannot fetch a source repository for package " ++ display pkgid+    ++ ". The package does not specify a source repository of the requested "+    ++ "kind" ++ maybe "." (\k -> " (kind " ++ display k ++ ").") repoKind --- | Fork a single package from a remote source repository to the local--- file system.-forkPackage :: Verbosity-            -> Data.Map.Map PD.RepoType Brancher-               -- ^ Branchers supported by the local machine.-            -> FilePath-               -- ^ The directory in which new branches or repositories will-               -- be created.-            -> (Maybe PD.RepoKind)-               -- ^ Which repo to choose.-            -> SourcePackage loc-               -- ^ The package to fork.-            -> IO ()-forkPackage verbosity branchers prefix kind src = do-    let desc    = PD.packageDescription (packageDescription src)-        pkgid   = display (packageId src)-        pkgname = display (packageName src)-        destdir = prefix </> pkgname+  displayException (ClonePackageNoRepoType pkgid _repo) =+       "Cannot fetch the source repository for package " ++ display pkgid+    ++ ". The package's description specifies a source repository but does "+    ++ "not specify the repository 'type' field (e.g. git, darcs or hg)." -    destDirExists <- doesDirectoryExist destdir-    when destDirExists $ do-        die' verbosity ("The directory " ++ show destdir ++ " already exists, not forking.")+  displayException (ClonePackageUnsupportedRepoType pkgid _ repoType) =+       "Cannot fetch the source repository for package " ++ display pkgid+    ++ ". The repository type '" ++ display repoType+    ++ "' is not yet supported." -    destFileExists  <- doesFileExist destdir-    when destFileExists $ do-        die' verbosity ("A file " ++ show destdir ++ " is in the way, not forking.")+  displayException (ClonePackageNoRepoLocation pkgid _repo) =+       "Cannot fetch the source repository for package " ++ display pkgid+    ++ ". The package's description specifies a source repository but does "+    ++ "not specify the repository 'location' field (i.e. the URL)." -    let repos = PD.sourceRepos desc-    case findBranchCmd branchers repos kind of-        Just (BranchCmd io) -> do-            exitCode <- io verbosity destdir-            case exitCode of-                ExitSuccess -> return ()-                ExitFailure _ -> die' verbosity ("Couldn't fork package " ++ pkgid)-        Nothing -> case repos of-            [] -> die' verbosity ("Package " ++ pkgid-                       ++ " does not have any source repositories.")-            _ -> die' verbosity ("Package " ++ pkgid-                      ++ " does not have any usable source repositories.")+  displayException (ClonePackageDestinationExists pkgid dest isdir) =+       "Not fetching the source repository for package " ++ display pkgid ++ ". "+    ++ if isdir then "The destination directory " ++ dest ++ " already exists."+                else "A file " ++ dest ++ " is in the way." --- | Given a set of possible branchers, and a set of possible source--- repositories, find a repository that is both 1) likely to be specific to--- this source version and 2) is supported by the local machine.-findBranchCmd :: Data.Map.Map PD.RepoType Brancher -> [PD.SourceRepo]-                 -> (Maybe PD.RepoKind) -> Maybe BranchCmd-findBranchCmd branchers allRepos maybeKind = cmd where-    -- Sort repositories by kind, from This to Head to Unknown. Repositories-    -- with equivalent kinds are selected based on the order they appear in-    -- the Cabal description file.-    repos' = sortBy (comparing thisFirst) allRepos-    thisFirst r = case PD.repoKind r of-        PD.RepoThis -> 0 :: Int-        PD.RepoHead -> case PD.repoTag r of-            -- If the type is 'head' but the author specified a tag, they-            -- probably meant to create a 'this' repository but screwed up.-            Just _ -> 0-            Nothing -> 1-        PD.RepoKindUnknown _ -> 2+  displayException (ClonePackageFailedWithExitCode+                      pkgid repo vcsprogname exitcode) =+       "Failed to fetch the source repository for package " ++ display pkgid+    ++ maybe "" (", repository location " ++) (PD.repoLocation repo) ++ " ("+    ++ vcsprogname ++ " failed with " ++ show exitcode ++ ")." -    -- If the user has specified the repo kind, filter out the repositories-    -- she's not interested in.-    repos = maybe repos' (\k -> filter ((==) k . PD.repoKind) repos') maybeKind -    repoBranchCmd repo = do-        t <- PD.repoType repo-        brancher <- Data.Map.lookup t branchers-        brancherBuildCmd brancher repo+-- | Given a bunch of package ids and their corresponding available+-- 'SourceRepo's, pick a single 'SourceRepo' for each one and clone into+-- new subdirs of the given directory.+--+clonePackagesFromSourceRepo :: Verbosity+                            -> FilePath            -- ^ destination dir prefix+                            -> Maybe RepoKind      -- ^ preferred 'RepoKind'+                            -> [(PackageId, [SourceRepo])]+                                                   -- ^ the packages and their+                                                   -- available 'SourceRepo's+                            -> IO ()+clonePackagesFromSourceRepo verbosity destDirPrefix+                            preferredRepoKind pkgrepos = do -    cmd = listToMaybe (mapMaybe repoBranchCmd repos)+    -- Do a bunch of checks and collect the required info+    pkgrepos' <- mapM preCloneChecks pkgrepos --- | Branch driver for Bazaar.-branchBzr :: Brancher-branchBzr = Brancher "bzr" $ \repo -> do-    src <- PD.repoLocation repo-    let args dst = case PD.repoTag repo of-         Just tag -> ["branch", src, dst, "-r", "tag:" ++ tag]-         Nothing -> ["branch", src, dst]-    return $ BranchCmd $ \verbosity dst -> do-        notice verbosity ("bzr: branch " ++ show src)-        rawSystemExitCode verbosity "bzr" (args dst)+    -- Configure the VCS drivers for all the repository types we may need+    vcss <- configureVCSs verbosity $+              Map.fromList [ (vcsRepoType vcs, vcs)+                           | (_, _, vcs, _) <- pkgrepos' ] --- | Branch driver for Darcs.-branchDarcs :: Brancher-branchDarcs = Brancher "darcs" $ \repo -> do-    src <- PD.repoLocation repo-    let args dst = case PD.repoTag repo of-         Just tag -> ["get", src, dst, "-t", tag]-         Nothing -> ["get", src, dst]-    return $ BranchCmd $ \verbosity dst -> do-        notice verbosity ("darcs: get " ++ show src)-        rawSystemExitCode verbosity "darcs" (args dst)+    -- Now execute all the required commands for each repo+    sequence_+      [ cloneSourceRepo verbosity vcs' repo destDir+          `catch` \exitcode ->+           throwIO (ClonePackageFailedWithExitCode+                      pkgid repo (programName (vcsProgram vcs)) exitcode)+      | (pkgid, repo, vcs, destDir) <- pkgrepos'+      , let Just vcs' = Map.lookup (vcsRepoType vcs) vcss+      ] --- | Branch driver for Git.-branchGit :: Brancher-branchGit = Brancher "git" $ \repo -> do-    src <- PD.repoLocation repo-    let postClone verbosity dst = case PD.repoTag repo of-         Just t -> do-             cwd <- getCurrentDirectory-             setCurrentDirectory dst-             finally-                 (rawSystemExitCode verbosity "git" ["checkout", t])-                 (setCurrentDirectory cwd)-         Nothing -> return ExitSuccess-    return $ BranchCmd $ \verbosity dst -> do-        notice verbosity ("git: clone " ++ show src)-        code <- rawSystemExitCode verbosity "git" (["clone", src, dst] ++-                    case PD.repoBranch repo of-                        Nothing -> []-                        Just b -> ["--branch", b])-        case code of-            ExitFailure _ -> return code-            ExitSuccess -> postClone verbosity  dst+  where+    preCloneChecks :: (PackageId, [SourceRepo])+                   -> IO (PackageId, SourceRepo, VCS Program, FilePath)+    preCloneChecks (pkgid, repos) = do+      repo <- case selectPackageSourceRepo preferredRepoKind repos of+        Just repo            -> return repo+        Nothing | null repos -> throwIO (ClonePackageNoSourceRepos pkgid)+        Nothing              -> throwIO (ClonePackageNoSourceReposOfKind+                                           pkgid preferredRepoKind) --- | Branch driver for Mercurial.-branchHg :: Brancher-branchHg = Brancher "hg" $ \repo -> do-    src <- PD.repoLocation repo-    let branchArgs = case PD.repoBranch repo of-         Just b -> ["--branch", b]-         Nothing -> []-    let tagArgs = case PD.repoTag repo of-         Just t -> ["--rev", t]-         Nothing -> []-    let args dst = ["clone", src, dst] ++ branchArgs ++ tagArgs-    return $ BranchCmd $ \verbosity dst -> do-        notice verbosity ("hg: clone " ++ show src)-        rawSystemExitCode verbosity "hg" (args dst)+      vcs <- case validateSourceRepo repo of+        Right (_, _, _, vcs) -> return vcs+        Left SourceRepoRepoTypeUnspecified ->+          throwIO (ClonePackageNoRepoType pkgid repo) --- | Branch driver for Subversion.-branchSvn :: Brancher-branchSvn = Brancher "svn" $ \repo -> do-    src <- PD.repoLocation repo-    let args dst = ["checkout", src, dst]-    return $ BranchCmd $ \verbosity dst -> do-        notice verbosity ("svn: checkout " ++ show src)-        rawSystemExitCode verbosity "svn" (args dst)+        Left (SourceRepoRepoTypeUnsupported repoType) ->+          throwIO (ClonePackageUnsupportedRepoType pkgid repo repoType)++        Left SourceRepoLocationUnspecified ->+          throwIO (ClonePackageNoRepoLocation pkgid repo)++      let destDir = destDirPrefix </> display (packageName pkgid)+      destDirExists  <- doesDirectoryExist destDir+      destFileExists <- doesFileExist      destDir+      when (destDirExists || destFileExists) $+        throwIO (ClonePackageDestinationExists pkgid destDir destDirExists)++      return (pkgid, repo, vcs, destDir)+
Distribution/Client/Haddock.hs view
@@ -40,7 +40,7 @@                        -> IO () regenerateHaddockIndex verbosity pkgs progdb index = do       (paths, warns) <- haddockPackagePaths pkgs' Nothing-      let paths' = [ (interface, html) | (interface, Just html) <- paths]+      let paths' = [ (interface, html) | (interface, Just html, _) <- paths]       forM_ warns (debug verbosity)        (confHaddock, _, _) <-
Distribution/Client/Init.hs view
@@ -288,7 +288,7 @@   return $ flags { extraSrc = extraSrcFiles }  defaultChangeLog :: FilePath-defaultChangeLog = "ChangeLog.md"+defaultChangeLog = "CHANGELOG.md"  -- | Try to guess things to include in the extra-source-files field. --   For now, we just look for things in the root directory named
Distribution/Client/Install.hs view
@@ -80,7 +80,7 @@          , ConfigFlags(..), configureCommand, filterConfigureFlags          , ConfigExFlags(..), InstallFlags(..) ) import Distribution.Client.Config-         ( defaultCabalDir, defaultUserInstall )+         ( getCabalDir, defaultUserInstall ) import Distribution.Client.Sandbox.Timestamp          ( withUpdateTimestamps ) import Distribution.Client.Sandbox.Types@@ -160,9 +160,9 @@          , withTempDirectory ) import Distribution.Client.Utils          ( determineNumJobs, logDirChange, mergeBy, MergeResult(..)-         , tryCanonicalizePath )+         , tryCanonicalizePath, ProgressPhase(..), progressMessage ) import Distribution.System-         ( Platform, OS(Windows), buildOS )+         ( Platform, OS(Windows), buildOS, buildPlatform ) import Distribution.Text          ( display ) import Distribution.Verbosity as Verbosity@@ -858,7 +858,7 @@ storeDetailedBuildReports :: Verbosity -> FilePath                           -> [(BuildReports.BuildReport, Maybe Repo)] -> IO () storeDetailedBuildReports verbosity logsDir reports = sequence_-  [ do dotCabal <- defaultCabalDir+  [ do dotCabal <- getCabalDir        let logFileName = display (BuildReports.package report) <.> "log"            logFile     = logsDir </> logFileName            reportsDir  = dotCabal </> "reports" </> remoteRepoName remoteRepo@@ -1197,7 +1197,7 @@     -- otherwise.     printBuildResult :: PackageId -> UnitId -> BuildOutcome -> IO ()     printBuildResult pkgid uid buildOutcome = case buildOutcome of-        (Right _) -> notice verbosity $ "Installed " ++ display pkgid+        (Right _) -> progressMessage verbosity ProgressCompleted (display pkgid)         (Left _)  -> do           notice verbosity $ "Failed to install " ++ display pkgid           when (verbosity >= normal) $@@ -1285,6 +1285,9 @@     LocalUnpackedPackage dir ->       installPkg (Just dir) +    RemoteSourceRepoPackage _repo dir ->+      installPkg (Just dir)+     LocalTarballPackage tarballPath ->       installLocalTarballPackage verbosity         pkgid tarballPath distPref installPkg@@ -1297,7 +1300,6 @@       installLocalTarballPackage verbosity         pkgid tarballPath distPref installPkg - installLocalTarballPackage   :: Verbosity   -> PackageIdentifier -> FilePath -> FilePath@@ -1396,14 +1398,12 @@   logDirChange (maybe (const (return ())) appendFile mLogPath) workingDir $ do     -- Configure phase     onFailure ConfigureFailed $ do-      when (numJobs > 1) $ notice verbosity $-        "Configuring " ++ display pkgid ++ "..."+      noticeProgress ProgressStarting       setup configureCommand configureFlags mLogPath      -- Build phase       onFailure BuildFailed $ do-        when (numJobs > 1) $ notice verbosity $-          "Building " ++ display pkgid ++ "..."+        noticeProgress ProgressBuilding         setup buildCommand' buildFlags mLogPath      -- Doc generation phase@@ -1450,6 +1450,12 @@     uid              = installedUnitId rpkg     cinfo            = compilerInfo comp     buildCommand'    = buildCommand progdb+    dispname         = display pkgid+    isParallelBuild  = numJobs >= 2++    noticeProgress phase = when isParallelBuild $+        progressMessage verbosity phase dispname+     buildFlags   _   = emptyBuildFlags {       buildDistPref  = configDistPref configFlags,       buildVerbosity = toFlag verbosity'@@ -1551,7 +1557,7 @@           scriptOptions { useLoggingHandle = logFileHandle                         , useWorkingDir    = workingDir }           (Just pkg)-          cmd flags [])+          cmd flags (const []))   -- helper@@ -1593,7 +1599,7 @@     (CompilerId compFlavor _) = compilerInfoId cinfo      exeInstallPaths defaultDirs =-      [ InstallDirs.bindir absoluteDirs </> exeName <.> exeExtension+      [ InstallDirs.bindir absoluteDirs </> exeName <.> exeExtension buildPlatform       | exe <- PackageDescription.executables pkg       , PackageDescription.buildable (PackageDescription.buildInfo exe)       , let exeName = prefix ++ display (PackageDescription.exeName exe) ++ suffix
Distribution/Client/InstallPlan.hs view
@@ -62,6 +62,7 @@   showInstallPlan,    -- * Graph-like operations+  dependencyClosure,   reverseTopologicalOrder,   reverseDependencyClosure,   ) where@@ -402,6 +403,15 @@                         -> [GenericPlanPackage ipkg srcpkg] reverseTopologicalOrder plan = Graph.revTopSort (planGraph plan) ++-- | Return the packages in the plan that are direct or indirect dependencies of+-- the given packages.+--+dependencyClosure :: GenericInstallPlan ipkg srcpkg+                  -> [UnitId]+                  -> [GenericPlanPackage ipkg srcpkg]+dependencyClosure plan = fromMaybe []+                       . Graph.closure (planGraph plan)  -- | Return the packages in the plan that depend directly or indirectly on the -- given packages.
Distribution/Client/List.hs view
@@ -470,7 +470,7 @@                            source,     dependencies =       combine (map (SourceDependency . simplifyDependency)-               . Source.buildDepends) source+               . Source.allBuildDepends) source       (map InstalledDependency . Installed.depends) installed,     haddockHtml  = fromMaybe "" . join                  . fmap (listToMaybe . Installed.haddockHTMLs)
Distribution/Client/Outdated.hs view
@@ -27,12 +27,12 @@ import Distribution.Solver.Types.PackageIndex import Distribution.Client.Sandbox.PackageEnvironment -import Distribution.Package                          (PackageName-                                                     ,packageVersion)-import Distribution.PackageDescription               (buildDepends)+import Distribution.Package                          (PackageName, packageVersion)+import Distribution.PackageDescription               (allBuildDepends) import Distribution.PackageDescription.Configuration (finalizePD) import Distribution.Simple.Compiler                  (Compiler, compilerInfo)-import Distribution.Simple.Setup                     (fromFlagOrDefault)+import Distribution.Simple.Setup+       (fromFlagOrDefault, flagToMaybe) import Distribution.Simple.Utils        (die', notice, debug, tryFindPackageDesc) import Distribution.System                           (Platform)@@ -61,6 +61,8 @@   let freezeFile    = fromFlagOrDefault False (outdatedFreezeFile outdatedFlags)       newFreezeFile = fromFlagOrDefault False                       (outdatedNewFreezeFile outdatedFlags)+      mprojectFile  = flagToMaybe+                      (outdatedProjectFile outdatedFlags)       simpleOutput  = fromFlagOrDefault False                       (outdatedSimpleOutput outdatedFlags)       quiet         = fromFlagOrDefault False (outdatedQuiet outdatedFlags)@@ -76,13 +78,17 @@                           in \pkgname -> pkgname `S.member` minorSet       verbosity     = if quiet then silent else verbosity0 +  when (not newFreezeFile && isJust mprojectFile) $+    die' verbosity $+      "--project-file must only be used with --new-freeze-file."+   sourcePkgDb <- IndexUtils.getSourcePackages verbosity repoContext   let pkgIndex = packageIndex sourcePkgDb   deps <- if freezeFile           then depsFromFreezeFile verbosity           else if newFreezeFile-               then depsFromNewFreezeFile verbosity-               else depsFromPkgDesc       verbosity comp platform+               then depsFromNewFreezeFile verbosity mprojectFile+               else depsFromPkgDesc verbosity comp platform   debug verbosity $ "Dependencies loaded: "     ++ (intercalate ", " $ map display deps)   let outdatedDeps = listOutdated deps pkgIndex@@ -124,11 +130,10 @@   return deps  -- | Read the list of dependencies from the new-style freeze file.-depsFromNewFreezeFile :: Verbosity -> IO [Dependency]-depsFromNewFreezeFile verbosity = do+depsFromNewFreezeFile :: Verbosity -> Maybe FilePath -> IO [Dependency]+depsFromNewFreezeFile verbosity mprojectFile = do   projectRoot <- either throwIO return =<<-                 findProjectRoot Nothing-                 {- TODO: Support '--project-file': -} Nothing+                 findProjectRoot Nothing mprojectFile   let distDirLayout = defaultDistDirLayout projectRoot                       {- TODO: Support dist dir override -} Nothing   projectConfig  <- runRebuild (distProjectRootDirectory distDirLayout) $@@ -136,8 +141,8 @@   let ucnstrs = map fst . projectConfigConstraints . projectConfigShared                 $ projectConfig       deps    = userConstraintsToDependencies ucnstrs-  debug verbosity-    "Reading the list of dependencies from the new-style freeze file"+  debug verbosity $+    "Reading the list of dependencies from the new-style freeze file " ++ distProjectFile distDirLayout "freeze"   return deps  -- | Read the list of dependencies from the package description.@@ -152,7 +157,7 @@   case epd of     Left _        -> die' verbosity "finalizePD failed"     Right (pd, _) -> do-      let bd = buildDepends pd+      let bd = allBuildDepends pd       debug verbosity         "Reading the list of dependencies from the package description"       return bd
Distribution/Client/PackageHash.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE RecordWildCards, NamedFieldPuns, GeneralizedNewtypeDeriving #-}-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE RecordWildCards, NamedFieldPuns #-}+{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}  -- | Functions to calculate nix-style hashes for package ids. --@@ -135,22 +135,22 @@                     | otherwise     = take (n-1) s ++ "_"  -- | On macOS we shorten the name very aggressively.  The mach-o linker on--- macOS has a limited load command size, to which the name of the lirbary+-- macOS has a limited load command size, to which the name of the library -- as well as its relative path (\@rpath) entry count.  To circumvent this, -- on macOS the libraries are not stored as --  @store/<libraryname>/libHS<libraryname>.dylib@--- where libraryname contains the librarys name, version and abi hash, but in+-- where libraryname contains the libraries name, version and abi hash, but in --  @store/lib/libHS<very short libraryname>.dylib@ -- where the very short library name drops all vowels from the package name, -- and truncates the hash to 4 bytes. ----- We therefore only need one \@rpath entry to @store/lib@ instead of one+-- We therefore we only need one \@rpath entry to @store/lib@ instead of one -- \@rpath entry for each library. And the reduced library name saves some -- additional space. -- -- This however has two major drawbacks:--- 1) Packages can easier collide due to the shortened hash.--- 2) The lirbaries are *not* prefix relocateable anymore as they all end up+-- 1) Packages can collide more easily due to the shortened hash.+-- 2) The libraries are *not* prefix relocatable anymore as they all end up --    in the same @store/lib@ folder. -- -- The ultimate solution would have to include generating proxy dynamic@@ -211,11 +211,25 @@        pkgHashExtraFrameworkDirs  :: [FilePath],        pkgHashExtraIncludeDirs    :: [FilePath],        pkgHashProgPrefix          :: Maybe PathTemplate,-       pkgHashProgSuffix          :: Maybe PathTemplate+       pkgHashProgSuffix          :: Maybe PathTemplate, +       -- Haddock options+       pkgHashDocumentation       :: Bool,+       pkgHashHaddockHoogle       :: Bool,+       pkgHashHaddockHtml         :: Bool,+       pkgHashHaddockHtmlLocation :: Maybe String,+       pkgHashHaddockForeignLibs  :: Bool,+       pkgHashHaddockExecutables  :: Bool,+       pkgHashHaddockTestSuites   :: Bool,+       pkgHashHaddockBenchmarks   :: Bool,+       pkgHashHaddockInternal     :: Bool,+       pkgHashHaddockCss          :: Maybe FilePath,+       pkgHashHaddockLinkedSource :: Bool,+       pkgHashHaddockQuickJump    :: Bool,+       pkgHashHaddockContents     :: Maybe PathTemplate+ --     TODO: [required eventually] pkgHashToolsVersions     ? --     TODO: [required eventually] pkgHashToolsExtraOptions ?---     TODO: [research required] and what about docs?      }   deriving Show @@ -248,7 +262,7 @@     -- the default value for that feature. So if we avoid adding entries with     -- the default value then most of the time adding new features will not     -- change the hashes of existing packages and so fewer packages will need-    -- to be rebuilt. +    -- to be rebuilt.      --TODO: [nice to have] ultimately we probably want to put this config info     -- into the ghc-pkg db. At that point this should probably be changed to@@ -276,8 +290,8 @@       , opt   "ghci-lib"    False display pkgHashGHCiLib       , opt   "prof-lib"    False display pkgHashProfLib       , opt   "prof-exe"    False display pkgHashProfExe-      , opt   "prof-lib-detail" ProfDetailDefault showProfDetailLevel pkgHashProfLibDetail -      , opt   "prof-exe-detail" ProfDetailDefault showProfDetailLevel pkgHashProfExeDetail +      , opt   "prof-lib-detail" ProfDetailDefault showProfDetailLevel pkgHashProfLibDetail+      , opt   "prof-exe-detail" ProfDetailDefault showProfDetailLevel pkgHashProfExeDetail       , opt   "hpc"          False display pkgHashCoverage       , opt   "optimisation" NormalOptimisation (show . fromEnum) pkgHashOptimization       , opt   "split-objs"   False display pkgHashSplitObjs@@ -290,6 +304,21 @@       , opt   "extra-include-dirs" [] unwords pkgHashExtraIncludeDirs       , opt   "prog-prefix" Nothing (maybe "" fromPathTemplate) pkgHashProgPrefix       , opt   "prog-suffix" Nothing (maybe "" fromPathTemplate) pkgHashProgSuffix++      , opt   "documentation"  False display pkgHashDocumentation+      , opt   "haddock-hoogle" False display pkgHashHaddockHoogle+      , opt   "haddock-html"   False display pkgHashHaddockHtml+      , opt   "haddock-html-location" Nothing (fromMaybe "") pkgHashHaddockHtmlLocation+      , opt   "haddock-foreign-libraries" False display pkgHashHaddockForeignLibs+      , opt   "haddock-executables" False display pkgHashHaddockExecutables+      , opt   "haddock-tests" False display pkgHashHaddockTestSuites+      , opt   "haddock-benchmarks" False display pkgHashHaddockBenchmarks+      , opt   "haddock-internal" False display pkgHashHaddockInternal+      , opt   "haddock-css" Nothing (fromMaybe "") pkgHashHaddockCss+      , opt   "haddock-hyperlink-source" False display pkgHashHaddockLinkedSource+      , opt   "haddock-quickjump" False display pkgHashHaddockQuickJump+      , opt   "haddock-contents-location" Nothing (maybe "" fromPathTemplate) pkgHashHaddockContents+       ] ++ Map.foldrWithKey (\prog args acc -> opt (prog ++ "-options") [] unwords args : acc) [] pkgHashProgramArgs   where     entry key     format value = Just (key ++ ": " ++ format value)@@ -315,7 +344,7 @@ -- package ids.  newtype HashValue = HashValue BS.ByteString-  deriving (Eq, Show, Typeable)+  deriving (Eq, Generic, Show, Typeable)  instance Binary HashValue where   put (HashValue digest) = put digest@@ -354,4 +383,3 @@       (hash, trailing) | not (BS.null hash) && BS.null trailing         -> HashValue hash       _ -> error "hashFromTUF: cannot decode base16 hash"-
Distribution/Client/PackageUtils.hs view
@@ -16,18 +16,20 @@  import Distribution.Package          ( packageVersion, packageName )+import Distribution.Types.ComponentRequestedSpec+         ( ComponentRequestedSpec ) import Distribution.Types.Dependency import Distribution.Types.UnqualComponentName import Distribution.PackageDescription-         ( PackageDescription(..), libName )+         ( PackageDescription(..), libName, enabledBuildDepends ) import Distribution.Version          ( withinRange, isAnyVersion )  -- | The list of dependencies that refer to external packages -- rather than internal package components. ---externalBuildDepends :: PackageDescription -> [Dependency]-externalBuildDepends pkg = filter (not . internal) (buildDepends pkg)+externalBuildDepends :: PackageDescription -> ComponentRequestedSpec -> [Dependency]+externalBuildDepends pkg spec = filter (not . internal) (enabledBuildDepends pkg spec)   where     -- True if this dependency is an internal one (depends on a library     -- defined in the same package).
Distribution/Client/ProjectBuilding.hs view
@@ -60,11 +60,15 @@ import           Distribution.Client.FetchUtils import           Distribution.Client.GlobalFlags (RepoContext) import qualified Distribution.Client.Tar as Tar-import           Distribution.Client.Setup (filterConfigureFlags)+import           Distribution.Client.Setup+                   ( filterConfigureFlags, filterHaddockArgs+                   , filterHaddockFlags ) import           Distribution.Client.SourceFiles import           Distribution.Client.SrcDist (allPackageSourceFiles)-import           Distribution.Client.Utils (removeExistingFile)+import           Distribution.Client.Utils+                   ( ProgressPhase(..), progressMessage, removeExistingFile ) +import           Distribution.Compat.Lens import           Distribution.Package hiding (InstalledPackageId, installedPackageId) import qualified Distribution.PackageDescription as PD import           Distribution.InstalledPackageInfo (InstalledPackageInfo)@@ -72,15 +76,16 @@ import           Distribution.Simple.BuildPaths (haddockDirName) import qualified Distribution.Simple.InstallDirs as InstallDirs import           Distribution.Types.BuildType+import           Distribution.Types.PackageDescription.Lens (componentModules) import           Distribution.Simple.Program import qualified Distribution.Simple.Setup as Cabal import           Distribution.Simple.Command (CommandUI) import qualified Distribution.Simple.Register as Cabal-import           Distribution.Simple.LocalBuildInfo (ComponentName)+import           Distribution.Simple.LocalBuildInfo (ComponentName(..)) import           Distribution.Simple.Compiler                    ( Compiler, compilerId, PackageDB(..) ) -import           Distribution.Simple.Utils hiding (matchFileGlob)+import           Distribution.Simple.Utils import           Distribution.Version import           Distribution.Verbosity import           Distribution.Text@@ -96,6 +101,7 @@  import           Control.Monad import           Control.Exception+import           Data.Function (on) import           Data.Maybe  import           System.FilePath@@ -203,6 +209,11 @@           -- artifacts under the shared dist directory.           dryRunLocalPkg pkg depsBuildStatus srcdir +        Just (RemoteSourceRepoPackage _repo srcdir) ->+          -- At this point, source repos are essentially the same as local+          -- dirs, since we've already download them.+          dryRunLocalPkg pkg depsBuildStatus srcdir+         -- The three tarball cases are handled the same as each other,         -- though depending on the build style.         Just (LocalTarballPackage    tarball) ->@@ -249,7 +260,7 @@             return (BuildStatusUpToDate buildResult)       where         packageFileMonitor =-          newPackageFileMonitor distDirLayout (elabDistDirParams shared pkg)+          newPackageFileMonitor shared distDirLayout (elabDistDirParams shared pkg)   -- | A specialised traversal over the packages in an install plan.@@ -328,11 +339,20 @@ -- type BuildResultMisc = (DocsResult, TestsResult) -newPackageFileMonitor :: DistDirLayout -> DistDirParams -> PackageFileMonitor-newPackageFileMonitor DistDirLayout{distPackageCacheFile} dparams =+newPackageFileMonitor :: ElaboratedSharedConfig+                      -> DistDirLayout+                      -> DistDirParams+                      -> PackageFileMonitor+newPackageFileMonitor shared+                      DistDirLayout{distPackageCacheFile}+                      dparams =     PackageFileMonitor {       pkgFileMonitorConfig =-        newFileMonitor (distPackageCacheFile dparams "config"),+        FileMonitor {+          fileMonitorCacheFile = distPackageCacheFile dparams "config",+          fileMonitorKeyValid = (==) `on` normaliseConfiguredPackage shared,+          fileMonitorCheckIfOnlyValueChanged = False+        },        pkgFileMonitorBuild =         FileMonitor {@@ -366,11 +386,12 @@     --     elab_config =         elab {-            elabBuildTargets  = [],-            elabTestTargets   = [],+            elabBuildTargets   = [],+            elabTestTargets    = [],             elabBenchTargets   = [],-            elabReplTarget    = Nothing,-            elabBuildHaddocks = False+            elabReplTarget     = Nothing,+            elabHaddockTargets = [],+            elabBuildHaddocks  = False         }      -- The second part is the value used to guard the build step. So this is@@ -919,32 +940,26 @@     --TODO: [required feature] docs and tests     --TODO: [required feature] sudo re-exec -    let dispname = case elabPkgOrComp pkg of-            ElabPackage _ -> display pkgid-                ++ " (all, legacy fallback)"-            ElabComponent comp -> display pkgid-                ++ " (" ++ maybe "custom" display (compComponentName comp) ++ ")"-     -- Configure phase-    when isParallelBuild $-      notice verbosity $ "Configuring " ++ dispname ++ "..."+    noticeProgress ProgressStarting+     annotateFailure mlogFile ConfigureFailed $       setup' configureCommand configureFlags configureArgs      -- Build phase-    when isParallelBuild $-      notice verbosity $ "Building " ++ dispname ++ "..."+    noticeProgress ProgressBuilding+     annotateFailure mlogFile BuildFailed $       setup buildCommand buildFlags      -- Haddock phase     whenHaddock $ do-      when isParallelBuild $-        notice verbosity $ "Generating " ++ dispname ++ " documentation..."+      noticeProgress ProgressHaddock       annotateFailureNoLog HaddocksFailed $         setup haddockCommand haddockFlags      -- Install phase+    noticeProgress ProgressInstalling     annotateFailure mlogFile InstallFailed $ do        let copyPkgFiles tmpDir = do@@ -1017,6 +1032,8 @@     let docsResult  = DocsNotTried         testsResult = TestsNotTried +    noticeProgress ProgressCompleted+     return BuildResult {        buildResultDocs    = docsResult,        buildResultTests   = testsResult,@@ -1028,17 +1045,26 @@     uid    = installedUnitId rpkg     compid = compilerId compiler +    dispname = case elabPkgOrComp pkg of+        ElabPackage _ -> display pkgid+            ++ " (all, legacy fallback)"+        ElabComponent comp -> display pkgid+            ++ " (" ++ maybe "custom" display (compComponentName comp) ++ ")"++    noticeProgress phase = when isParallelBuild $+        progressMessage verbosity phase dispname+     isParallelBuild = buildSettingNumJobs >= 2      whenHaddock action-      | elabBuildHaddocks pkg = action-      | otherwise             = return ()+      | hasValidHaddockTargets pkg = action+      | otherwise                  = return ()      configureCommand = Cabal.configureCommand defaultProgramDb     configureFlags v = flip filterConfigureFlags v $                        setupHsConfigureFlags rpkg pkgshared                                              verbosity builddir-    configureArgs    = setupHsConfigureArgs pkg+    configureArgs _  = setupHsConfigureArgs pkg      buildCommand     = Cabal.buildCommand defaultProgramDb     buildFlags   _   = setupHsBuildFlags pkg pkgshared verbosity builddir@@ -1064,9 +1090,9 @@                                          isParallelBuild cacheLock      setup :: CommandUI flags -> (Version -> flags) -> IO ()-    setup cmd flags = setup' cmd flags []+    setup cmd flags = setup' cmd flags (const []) -    setup' :: CommandUI flags -> (Version -> flags) -> [String] -> IO ()+    setup' :: CommandUI flags -> (Version -> flags) -> (Version -> [String]) -> IO ()     setup' cmd flags args =       withLogging $ \mLogFileHandle ->         setupWrapper@@ -1097,6 +1123,27 @@         Just logFile -> withFile logFile AppendMode (action . Just)  +hasValidHaddockTargets :: ElaboratedConfiguredPackage -> Bool+hasValidHaddockTargets ElaboratedConfiguredPackage{..}+  | not elabBuildHaddocks = False+  | otherwise             = any componentHasHaddocks components+  where+    components = elabBuildTargets ++ elabTestTargets ++ elabBenchTargets+              ++ maybeToList elabReplTarget ++ elabHaddockTargets++    componentHasHaddocks :: ComponentTarget -> Bool+    componentHasHaddocks (ComponentTarget name _) =+      case name of+        CLibName      -> hasHaddocks+        CSubLibName _ -> elabHaddockInternal    && hasHaddocks+        CFLibName   _ -> elabHaddockForeignLibs && hasHaddocks+        CExeName    _ -> elabHaddockExecutables && hasHaddocks+        CTestName   _ -> elabHaddockTestSuites  && hasHaddocks+        CBenchName  _ -> elabHaddockBenchmarks  && hasHaddocks+      where+        hasHaddocks = not (null (elabPkgDescription ^. componentModules name))++ buildInplaceUnpackedPackage :: Verbosity                             -> DistDirLayout                             -> BuildTimeSettings -> Lock -> Lock@@ -1220,7 +1267,7 @@         -- Haddock phase         whenHaddock $           annotateFailureNoLog HaddocksFailed $ do-            setup haddockCommand haddockFlags []+            setup haddockCommand haddockFlags haddockArgs             let haddockTarget = elabHaddockForHackage pkg             when (haddockTarget == Cabal.ForHackage) $ do               let dest = distDirectory </> name <.> "tar.gz"@@ -1241,7 +1288,7 @@      isParallelBuild = buildSettingNumJobs >= 2 -    packageFileMonitor = newPackageFileMonitor distDirLayout dparams+    packageFileMonitor = newPackageFileMonitor pkgshared distDirLayout dparams      whenReConfigure action = case buildStatus of       BuildStatusConfigure _ -> action@@ -1267,8 +1314,8 @@       | otherwise                     = action      whenHaddock action-      | elabBuildHaddocks pkg = action-      | otherwise            = return ()+      | hasValidHaddockTargets pkg = action+      | otherwise                  = return ()      whenReRegister  action       = case buildStatus of@@ -1282,45 +1329,48 @@     configureFlags v = flip filterConfigureFlags v $                        setupHsConfigureFlags rpkg pkgshared                                              verbosity builddir-    configureArgs    = setupHsConfigureArgs pkg+    configureArgs _  = setupHsConfigureArgs pkg      buildCommand     = Cabal.buildCommand defaultProgramDb     buildFlags   _   = setupHsBuildFlags pkg pkgshared                                          verbosity builddir-    buildArgs        = setupHsBuildArgs  pkg+    buildArgs     _  = setupHsBuildArgs  pkg      testCommand      = Cabal.testCommand -- defaultProgramDb     testFlags    _   = setupHsTestFlags pkg pkgshared                                          verbosity builddir-    testArgs         = setupHsTestArgs  pkg+    testArgs      _  = setupHsTestArgs  pkg      benchCommand     = Cabal.benchmarkCommand     benchFlags    _  = setupHsBenchFlags pkg pkgshared                                           verbosity builddir-    benchArgs        = setupHsBenchArgs  pkg+    benchArgs     _  = setupHsBenchArgs  pkg      replCommand      = Cabal.replCommand defaultProgramDb     replFlags _      = setupHsReplFlags pkg pkgshared                                         verbosity builddir-    replArgs         = setupHsReplArgs  pkg+    replArgs _       = setupHsReplArgs  pkg      haddockCommand   = Cabal.haddockCommand-    haddockFlags _   = setupHsHaddockFlags pkg pkgshared+    haddockFlags v   = flip filterHaddockFlags v $+                       setupHsHaddockFlags pkg pkgshared                                            verbosity builddir+    haddockArgs    v = flip filterHaddockArgs v $+                       setupHsHaddockArgs pkg      scriptOptions    = setupHsScriptOptions rpkg plan pkgshared                                             srcdir builddir                                             isParallelBuild cacheLock      setupInteractive :: CommandUI flags-                     -> (Version -> flags) -> [String] -> IO ()+                     -> (Version -> flags) -> (Version -> [String]) -> IO ()     setupInteractive cmd flags args =       setupWrapper verbosity                    scriptOptions { isInteractive = True }                    (Just (elabPkgDescription pkg))                    cmd flags args -    setup :: CommandUI flags -> (Version -> flags) -> [String] -> IO ()+    setup :: CommandUI flags -> (Version -> flags) -> (Version -> [String]) -> IO ()     setup cmd flags args =       setupWrapper verbosity                    scriptOptions@@ -1335,7 +1385,7 @@                                 pkg pkgshared                                 verbosity builddir                                 pkgConfDest-        setup Cabal.registerCommand registerFlags []+        setup Cabal.registerCommand registerFlags (const [])  withTempInstalledPackageInfoFile :: Verbosity -> FilePath                                   -> (FilePath -> IO ())@@ -1395,4 +1445,3 @@   where     handler :: Exception e => e -> IO a     handler = throwIO . BuildFailure mlogFile . annotate . toException-
Distribution/Client/ProjectBuilding/Types.hs view
@@ -204,4 +204,3 @@                         | BenchFailed     SomeException                         | InstallFailed   SomeException   deriving Show-
Distribution/Client/ProjectConfig.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, RecordWildCards, NamedFieldPuns, DeriveDataTypeable #-}+{-# LANGUAGE CPP, RecordWildCards, NamedFieldPuns, DeriveDataTypeable, LambdaCase #-}  -- | Handling project configuration. --@@ -22,6 +22,7 @@     readProjectConfig,     readGlobalConfig,     readProjectLocalFreezeConfig,+    withProjectOrGlobalConfig,     writeProjectLocalExtraConfig,     writeProjectLocalFreezeConfig,     writeProjectConfigFile,@@ -33,7 +34,7 @@     BadPackageLocation(..),     BadPackageLocationMatch(..),     findProjectPackages,-    readSourcePackage,+    fetchAndReadSourcePackages,      -- * Resolving configuration     lookupLocalPackageConfig,@@ -57,6 +58,9 @@ import Distribution.Client.RebuildMonad import Distribution.Client.Glob          ( isTrivialFilePathGlob )+import Distribution.Client.VCS+         ( validateSourceRepos, SourceRepoProblem(..)+         , VCS(..), knownVCSs, configureVCS, syncSourceRepos )  import Distribution.Client.Types import Distribution.Client.DistDirLayout@@ -67,6 +71,9 @@          ( ReportLevel(..) ) import Distribution.Client.Config          ( loadConfig, getConfigFilePath )+import Distribution.Client.HttpUtils+         ( HttpTransport, configureTransport, transportCheckHttps+         , downloadURI )  import Distribution.Solver.Types.SourcePackage import Distribution.Solver.Types.Settings@@ -78,10 +85,16 @@ import Distribution.Types.Dependency import Distribution.System          ( Platform )-import Distribution.PackageDescription-         ( SourceRepo(..) )+import Distribution.Types.GenericPackageDescription+         ( GenericPackageDescription ) import Distribution.PackageDescription.Parsec-         ( readGenericPackageDescription )+         ( parseGenericPackageDescription )+import Distribution.Parsec.ParseResult+         ( runParseResult )+import Distribution.Parsec.Common as NewParser+         ( PError, PWarning, showPWarning )+import Distribution.Types.SourceRepo+         ( SourceRepo(..), RepoType(..), ) import Distribution.Simple.Compiler          ( Compiler, compilerInfo ) import Distribution.Simple.Program@@ -95,27 +108,42 @@          ( PathTemplate, fromPathTemplate          , toPathTemplate, substPathTemplate, initialPathTemplateEnv ) import Distribution.Simple.Utils-         ( die', warn )+         ( die', warn, notice, info, createDirectoryIfMissingVerbose ) import Distribution.Client.Utils          ( determineNumJobs ) import Distribution.Utils.NubList          ( fromNubList ) import Distribution.Verbosity          ( Verbosity, modifyVerbosity, verbose )+import Distribution.Version+         ( Version ) import Distribution.Text-import Distribution.ParseUtils+import Distribution.ParseUtils as OldParser          ( ParseResult(..), locatedErrorMsg, showPWarning ) +import qualified Codec.Archive.Tar       as Tar+import qualified Codec.Archive.Tar.Entry as Tar+import qualified Distribution.Client.Tar as Tar+import qualified Distribution.Client.GZipUtils as GZipUtils+ import Control.Monad import Control.Monad.Trans (liftIO) import Control.Exception import Data.Either+import qualified Data.ByteString      as BS+import qualified Data.ByteString.Lazy as LBS import qualified Data.Map as Map import Data.Set (Set) import qualified Data.Set as Set+import qualified Data.Hashable as Hashable+import Numeric (showHex)+ import System.FilePath hiding (combine)+import System.IO+         ( withBinaryFile, IOMode(ReadMode) ) import System.Directory-import Network.URI (URI(..), URIAuth(..), parseAbsoluteURI)+import Network.URI+         ( URI(..), URIAuth(..), parseAbsoluteURI, uriToString )   ----------------------------------------@@ -411,45 +439,63 @@ renderBadProjectRoot (BadProjectRootExplicitFile projectFile) =     "The given project file '" ++ projectFile ++ "' does not exist." +withProjectOrGlobalConfig :: Verbosity +                          -> Flag FilePath+                          -> IO a+                          -> (ProjectConfig -> IO a)+                          -> IO a+withProjectOrGlobalConfig verbosity globalConfigFlag with without = do+  globalConfig <- runRebuild "" $ readGlobalConfig verbosity globalConfigFlag +  let+    res' = catch with+      $ \case+        (BadPackageLocations prov locs) +          | prov == Set.singleton Implicit+          , let +            isGlobErr (BadLocGlobEmptyMatch _) = True+            isGlobErr _ = False+          , any isGlobErr locs ->+            without globalConfig+        err -> throwIO err++  catch res'+    $ \case+      (BadProjectRootExplicitFile "") -> without globalConfig+      err -> throwIO err+ -- | Read all the config relevant for a project. This includes the project -- file if any, plus other global config. ---readProjectConfig :: Verbosity -> Flag FilePath -> DistDirLayout -> Rebuild ProjectConfig+readProjectConfig :: Verbosity+                  -> Flag FilePath+                  -> DistDirLayout+                  -> Rebuild ProjectConfig readProjectConfig verbosity configFileFlag distDirLayout = do-    global <- readGlobalConfig             verbosity configFileFlag-    local  <- readProjectLocalConfig       verbosity distDirLayout-    freeze <- readProjectLocalFreezeConfig verbosity distDirLayout-    extra  <- readProjectLocalExtraConfig  verbosity distDirLayout+    global <- readGlobalConfig                verbosity configFileFlag+    local  <- readProjectLocalConfigOrDefault verbosity distDirLayout+    freeze <- readProjectLocalFreezeConfig    verbosity distDirLayout+    extra  <- readProjectLocalExtraConfig     verbosity distDirLayout     return (global <> local <> freeze <> extra)   -- | Reads an explicit @cabal.project@ file in the given project root dir, -- or returns the default project config for an implicitly defined project. ---readProjectLocalConfig :: Verbosity -> DistDirLayout -> Rebuild ProjectConfig-readProjectLocalConfig verbosity DistDirLayout{distProjectFile} = do+readProjectLocalConfigOrDefault :: Verbosity+                                -> DistDirLayout+                                -> Rebuild ProjectConfig+readProjectLocalConfigOrDefault verbosity distDirLayout = do   usesExplicitProjectRoot <- liftIO $ doesFileExist projectFile   if usesExplicitProjectRoot     then do-      monitorFiles [monitorFileHashed projectFile]-      addProjectFileProvenance <$> liftIO readProjectFile+      readProjectFile verbosity distDirLayout "" "project file"     else do       monitorFiles [monitorNonExistentFile projectFile]       return defaultImplicitProjectConfig    where-    projectFile = distProjectFile ""-    readProjectFile =-          reportParseResult verbosity "project file" projectFile-        . parseProjectConfig-      =<< readFile projectFile--    addProjectFileProvenance config =-      config {-        projectConfigProvenance =-          Set.insert (Explicit projectFile) (projectConfigProvenance config)-      }+    projectFile = distProjectFile distDirLayout ""      defaultImplicitProjectConfig :: ProjectConfig     defaultImplicitProjectConfig =@@ -470,7 +516,7 @@ readProjectLocalExtraConfig :: Verbosity -> DistDirLayout                             -> Rebuild ProjectConfig readProjectLocalExtraConfig verbosity distDirLayout =-    readProjectExtensionFile verbosity distDirLayout "local"+    readProjectFile verbosity distDirLayout "local"                              "project local configuration file"  -- | Reads a @cabal.project.freeze@ file in the given project root dir,@@ -480,19 +526,22 @@ readProjectLocalFreezeConfig :: Verbosity -> DistDirLayout                              -> Rebuild ProjectConfig readProjectLocalFreezeConfig verbosity distDirLayout =-    readProjectExtensionFile verbosity distDirLayout "freeze"+    readProjectFile verbosity distDirLayout "freeze"                              "project freeze file"  -- | Reads a named config file in the given project root dir, or returns empty. ---readProjectExtensionFile :: Verbosity -> DistDirLayout -> String -> FilePath-                         -> Rebuild ProjectConfig-readProjectExtensionFile verbosity DistDirLayout{distProjectFile}+readProjectFile :: Verbosity+                -> DistDirLayout+                -> String+                -> String+                -> Rebuild ProjectConfig+readProjectFile verbosity DistDirLayout{distProjectFile}                          extensionName extensionDescription = do     exists <- liftIO $ doesFileExist extensionFile     if exists       then do monitorFiles [monitorFileHashed extensionFile]-              liftIO readExtensionFile+              addProjectFileProvenance <$> liftIO readExtensionFile       else do monitorFiles [monitorNonExistentFile extensionFile]               return mempty   where@@ -503,7 +552,13 @@         . parseProjectConfig       =<< readFile extensionFile +    addProjectFileProvenance config =+      config {+        projectConfigProvenance =+          Set.insert (Explicit extensionFile) (projectConfigProvenance config)+      } + -- | Parse the 'ProjectConfig' format. -- -- For the moment this is implemented in terms of parsers for legacy@@ -558,7 +613,7 @@ reportParseResult :: Verbosity -> String -> FilePath -> ParseResult a -> IO a reportParseResult verbosity _filetype filename (ParseOk warnings x) = do     unless (null warnings) $-      let msg = unlines (map (showPWarning filename) warnings)+      let msg = unlines (map (OldParser.showPWarning filename) warnings)        in warn verbosity msg     return x reportParseResult verbosity filetype filename (ParseFailed err) =@@ -568,7 +623,7 @@   ------------------------------------------------ Reading packages in the project+-- Finding packages in the project --  -- | The location of a package as part of a project. Local file paths are@@ -885,35 +940,411 @@     Just x  -> return (Just x)  --- | Read the @.cabal@ file of the given package.+-------------------------------------------------+-- Fetching and reading packages in the project --++-- | Read the @.cabal@ files for a set of packages. For remote tarballs and+-- VCS source repos this also fetches them if needed.+-- -- Note here is where we convert from project-root relative paths to absolute -- paths. ---readSourcePackage :: Verbosity -> ProjectPackageLocation-                  -> Rebuild (PackageSpecifier UnresolvedSourcePackage)-readSourcePackage verbosity (ProjectPackageLocalCabalFile cabalFile) =-    readSourcePackage verbosity (ProjectPackageLocalDirectory dir cabalFile)+fetchAndReadSourcePackages+  :: Verbosity+  -> DistDirLayout+  -> ProjectConfigShared+  -> ProjectConfigBuildOnly+  -> [ProjectPackageLocation]+  -> Rebuild [PackageSpecifier (SourcePackage UnresolvedPkgLoc)]+fetchAndReadSourcePackages verbosity distDirLayout+                           projectConfigShared+                           projectConfigBuildOnly+                           pkgLocations = do++    pkgsLocalDirectory <-+      sequence+        [ readSourcePackageLocalDirectory verbosity dir cabalFile+        | location <- pkgLocations+        , (dir, cabalFile) <- projectPackageLocal location ]++    pkgsLocalTarball <-+      sequence+        [ readSourcePackageLocalTarball verbosity path+        | ProjectPackageLocalTarball path <- pkgLocations ]++    pkgsRemoteTarball <- do+      getTransport <- delayInitSharedResource $+                      configureTransport verbosity progPathExtra+                                         preferredHttpTransport+      sequence+        [ fetchAndReadSourcePackageRemoteTarball verbosity distDirLayout+                                                 getTransport uri+        | ProjectPackageRemoteTarball uri <- pkgLocations ]++    pkgsRemoteRepo <-+      syncAndReadSourcePackagesRemoteRepos+        verbosity distDirLayout+        projectConfigShared+        [ repo | ProjectPackageRemoteRepo repo <- pkgLocations ]++    let pkgsNamed =+          [ NamedPackage pkgname [PackagePropertyVersion verrange]+          | ProjectPackageNamed (Dependency pkgname verrange) <- pkgLocations ]++    return $ concat+      [ pkgsLocalDirectory+      , pkgsLocalTarball+      , pkgsRemoteTarball+      , pkgsRemoteRepo+      , pkgsNamed+      ]   where-    dir = takeDirectory cabalFile+    projectPackageLocal (ProjectPackageLocalDirectory dir file) = [(dir, file)]+    projectPackageLocal (ProjectPackageLocalCabalFile     file) = [(dir, file)]+                                                where dir = takeDirectory file+    projectPackageLocal _ = [] -readSourcePackage verbosity (ProjectPackageLocalDirectory dir cabalFile) = do+    progPathExtra = fromNubList (projectConfigProgPathExtra projectConfigShared)+    preferredHttpTransport =+      flagToMaybe (projectConfigHttpTransport projectConfigBuildOnly)++-- | A helper for 'fetchAndReadSourcePackages' to handle the case of+-- 'ProjectPackageLocalDirectory' and 'ProjectPackageLocalCabalFile'.+-- We simply read the @.cabal@ file.+--+readSourcePackageLocalDirectory+  :: Verbosity+  -> FilePath  -- ^ The package directory+  -> FilePath  -- ^ The package @.cabal@ file+  -> Rebuild (PackageSpecifier (SourcePackage UnresolvedPkgLoc))+readSourcePackageLocalDirectory verbosity dir cabalFile = do     monitorFiles [monitorFileHashed cabalFile]     root <- askRoot-    pkgdesc <- liftIO $ readGenericPackageDescription verbosity (root </> cabalFile)-    return $ SpecificSourcePackage SourcePackage {-      packageInfoId        = packageId pkgdesc,-      packageDescription   = pkgdesc,-      packageSource        = LocalUnpackedPackage (root </> dir),+    let location = LocalUnpackedPackage (root </> dir)+    liftIO $ fmap (mkSpecificSourcePackage location)+           . readSourcePackageCabalFile verbosity cabalFile+         =<< BS.readFile (root </> cabalFile)+++-- | A helper for 'fetchAndReadSourcePackages' to handle the case of+-- 'ProjectPackageLocalTarball'. We scan through the @.tar.gz@ file to find+-- the @.cabal@ file and read that.+--+readSourcePackageLocalTarball+  :: Verbosity+  -> FilePath+  -> Rebuild (PackageSpecifier (SourcePackage UnresolvedPkgLoc))+readSourcePackageLocalTarball verbosity tarballFile = do+    monitorFiles [monitorFile tarballFile]+    root <- askRoot+    let location = LocalTarballPackage (root </> tarballFile)+    liftIO $ fmap (mkSpecificSourcePackage location)+           . uncurry (readSourcePackageCabalFile verbosity)+         =<< extractTarballPackageCabalFile (root </> tarballFile)+++-- | A helper for 'fetchAndReadSourcePackages' to handle the case of+-- 'ProjectPackageRemoteTarball'. We download the tarball to the dist src dir+-- and after that handle it like the local tarball case.+--+fetchAndReadSourcePackageRemoteTarball+  :: Verbosity+  -> DistDirLayout+  -> Rebuild HttpTransport+  -> URI+  -> Rebuild (PackageSpecifier (SourcePackage UnresolvedPkgLoc))+fetchAndReadSourcePackageRemoteTarball verbosity+                                       DistDirLayout {+                                         distDownloadSrcDirectory+                                       }+                                       getTransport+                                       tarballUri =+    -- The tarball download is expensive so we use another layer of file+    -- monitor to avoid it whenever possible.+    rerunIfChanged verbosity monitor tarballUri $ do++      -- Download+      transport <- getTransport+      liftIO $ do+        transportCheckHttps verbosity transport tarballUri+        notice verbosity ("Downloading " ++ show tarballUri)+        createDirectoryIfMissingVerbose verbosity True+                                        distDownloadSrcDirectory+        _ <- downloadURI transport verbosity tarballUri tarballFile+        return ()++      -- Read+      monitorFiles [monitorFile tarballFile]+      let location = RemoteTarballPackage tarballUri tarballFile+      liftIO $ fmap (mkSpecificSourcePackage location)+             . uncurry (readSourcePackageCabalFile verbosity)+           =<< extractTarballPackageCabalFile tarballFile+  where+    tarballStem = distDownloadSrcDirectory+              </> localFileNameForRemoteTarball tarballUri+    tarballFile = tarballStem <.> "tar.gz"++    monitor :: FileMonitor URI (PackageSpecifier (SourcePackage UnresolvedPkgLoc))+    monitor = newFileMonitor (tarballStem <.> "cache")+++-- | A helper for 'fetchAndReadSourcePackages' to handle all the cases of+-- 'ProjectPackageRemoteRepo'.+--+syncAndReadSourcePackagesRemoteRepos+  :: Verbosity+  -> DistDirLayout+  -> ProjectConfigShared+  -> [SourceRepo]+  -> Rebuild [PackageSpecifier (SourcePackage UnresolvedPkgLoc)]+syncAndReadSourcePackagesRemoteRepos verbosity+                                     DistDirLayout{distDownloadSrcDirectory}+                                     ProjectConfigShared {+                                       projectConfigProgPathExtra+                                     }+                                    repos = do++    repos' <- either reportSourceRepoProblems return $+              validateSourceRepos repos++    -- All 'SourceRepo's grouped by referring to the "same" remote repo+    -- instance. So same location but can differ in commit/tag/branch/subdir.+    let reposByLocation :: Map (RepoType, String)+                               [(SourceRepo, RepoType)]+        reposByLocation = Map.fromListWith (++)+                            [ ((rtype, rloc), [(repo, vcsRepoType vcs)])+                            | (repo, rloc, rtype, vcs) <- repos' ]++    --TODO: pass progPathExtra on to 'configureVCS'+    let _progPathExtra = fromNubList projectConfigProgPathExtra+    getConfiguredVCS <- delayInitSharedResources $ \repoType ->+                          let Just vcs = Map.lookup repoType knownVCSs in+                          configureVCS verbosity {-progPathExtra-} vcs++    concat <$> sequence+      [ rerunIfChanged verbosity monitor repoGroup' $ do+          vcs' <- getConfiguredVCS repoType+          syncRepoGroupAndReadSourcePackages vcs' pathStem repoGroup'+      | repoGroup@((primaryRepo, repoType):_) <- Map.elems reposByLocation+      , let repoGroup' = map fst repoGroup+            pathStem = distDownloadSrcDirectory+                   </> localFileNameForRemoteRepo primaryRepo+            monitor :: FileMonitor+                         [SourceRepo]+                         [PackageSpecifier (SourcePackage UnresolvedPkgLoc)]+            monitor  = newFileMonitor (pathStem <.> "cache")+      ]+  where+    syncRepoGroupAndReadSourcePackages+      :: VCS ConfiguredProgram+      -> FilePath+      -> [SourceRepo]+      -> Rebuild [PackageSpecifier (SourcePackage UnresolvedPkgLoc)]+    syncRepoGroupAndReadSourcePackages vcs pathStem repoGroup = do+        liftIO $ createDirectoryIfMissingVerbose verbosity False+                                                 distDownloadSrcDirectory++        -- For syncing we don't care about different 'SourceRepo' values that+        -- are just different subdirs in the same repo.+        syncSourceRepos verbosity vcs+          [ (repo, repoPath)+          | (repo, _, repoPath) <- repoGroupWithPaths ]++        -- But for reading we go through each 'SourceRepo' including its subdir+        -- value and have to know which path each one ended up in.+        sequence+          [ readPackageFromSourceRepo repoWithSubdir repoPath+          | (_, reposWithSubdir, repoPath) <- repoGroupWithPaths+          , repoWithSubdir <- reposWithSubdir ]+      where+        -- So to do both things above, we pair them up here.+        repoGroupWithPaths =+          zipWith (\(x, y) z -> (x,y,z))+                  (Map.toList+                    (Map.fromListWith (++)+                      [ (repo { repoSubdir = Nothing }, [repo])+                      | repo <- repoGroup ]))+                  repoPaths++        -- The repos in a group are given distinct names by simple enumeration+        -- foo, foo-2, foo-3 etc+        repoPaths = pathStem+                  : [ pathStem ++ "-" ++ show (i :: Int) | i <- [2..] ]++    readPackageFromSourceRepo repo repoPath = do+        let packageDir = maybe repoPath (repoPath </>) (repoSubdir repo)+        entries <- liftIO $ getDirectoryContents packageDir+        --TODO: wrap exceptions+        case filter (\e -> takeExtension e == ".cabal") entries of+          []       -> liftIO $ throwIO NoCabalFileFound+          (_:_:_)  -> liftIO $ throwIO MultipleCabalFilesFound+          [cabalFileName] -> do+            monitorFiles [monitorFileHashed cabalFilePath]+            liftIO $ fmap (mkSpecificSourcePackage location)+                   . readSourcePackageCabalFile verbosity cabalFilePath+                 =<< BS.readFile cabalFilePath+            where+              cabalFilePath = packageDir </> cabalFileName+              location      = RemoteSourceRepoPackage repo packageDir+++    reportSourceRepoProblems :: [(SourceRepo, SourceRepoProblem)] -> Rebuild a+    reportSourceRepoProblems = liftIO . die' verbosity . renderSourceRepoProblems++    renderSourceRepoProblems :: [(SourceRepo, SourceRepoProblem)] -> String+    renderSourceRepoProblems = unlines . map show -- "TODO: the repo problems"+++-- | Utility used by all the helpers of 'fetchAndReadSourcePackages' to make an+-- appropriate @'PackageSpecifier' ('SourcePackage' (..))@ for a given package+-- from a given location.+--+mkSpecificSourcePackage :: PackageLocation FilePath+                        -> GenericPackageDescription+                        -> PackageSpecifier+                             (SourcePackage (PackageLocation (Maybe FilePath)))+mkSpecificSourcePackage location pkg =+    SpecificSourcePackage SourcePackage {+      packageInfoId        = packageId pkg,+      packageDescription   = pkg,+      --TODO: it is silly that we still have to use a Maybe FilePath here+      packageSource        = fmap Just location,       packageDescrOverride = Nothing     } -readSourcePackage _ (ProjectPackageNamed (Dependency pkgname verrange)) =-    return $ NamedPackage pkgname [PackagePropertyVersion verrange] -readSourcePackage _verbosity _ =-    fail $ "TODO: add support for fetching and reading local tarballs, remote "-        ++ "tarballs, remote repos and passing named packages through"+-- | Errors reported upon failing to parse a @.cabal@ file.+--+data CabalFileParseError =+     CabalFileParseError+       FilePath+       [PError]+       (Maybe Version) -- We might discover the spec version the package needs+       [PWarning]+  deriving (Show, Typeable)++instance Exception CabalFileParseError+++-- | Wrapper for the @.cabal@ file parser. It reports warnings on higher+-- verbosity levels and throws 'CabalFileParseError' on failure.+--+readSourcePackageCabalFile :: Verbosity+                           -> FilePath+                           -> BS.ByteString+                           -> IO GenericPackageDescription+readSourcePackageCabalFile verbosity pkgfilename content =+    case runParseResult (parseGenericPackageDescription content) of+      (warnings, Right pkg) -> do+        unless (null warnings) $+          info verbosity (formatWarnings warnings)+        return pkg++      (warnings, Left (mspecVersion, errors)) ->+        throwIO $ CabalFileParseError pkgfilename errors mspecVersion warnings+  where+    formatWarnings warnings =+        "The package description file " ++ pkgfilename+     ++ " has warnings: "+     ++ unlines (map (NewParser.showPWarning pkgfilename) warnings)+++-- | When looking for a package's @.cabal@ file we can find none, or several,+-- both of which are failures.+--+data CabalFileSearchFailure =+     NoCabalFileFound+   | MultipleCabalFilesFound+  deriving (Show, Typeable)++instance Exception CabalFileSearchFailure+++-- | Find the @.cabal@ file within a tarball file and return it by value.+--+-- Can fail with a 'Tar.FormatError' or 'CabalFileSearchFailure' exception.+--+extractTarballPackageCabalFile :: FilePath -> IO (FilePath, BS.ByteString)+extractTarballPackageCabalFile tarballFile =+    withBinaryFile tarballFile ReadMode $ \hnd -> do+      content <- LBS.hGetContents hnd+      case extractTarballPackageCabalFilePure content of+        Left (Left  e) -> throwIO e+        Left (Right e) -> throwIO e+        Right (fileName, fileContent) ->+          (,) fileName <$> evaluate (LBS.toStrict fileContent)+++-- | Scan through a tar file stream and collect the @.cabal@ file, or fail.+--+extractTarballPackageCabalFilePure :: LBS.ByteString+                                   -> Either (Either Tar.FormatError+                                                     CabalFileSearchFailure)+                                             (FilePath, LBS.ByteString)+extractTarballPackageCabalFilePure =+      check+    . accumEntryMap+    . Tar.filterEntries isCabalFile+    . Tar.read+    . GZipUtils.maybeDecompress+  where+    accumEntryMap = Tar.foldlEntries+                      (\m e -> Map.insert (Tar.entryTarPath e) e m)+                      Map.empty++    check (Left (e, _m)) = Left (Left e)+    check (Right m) = case Map.elems m of+        []     -> Left (Right NoCabalFileFound)+        [file] -> case Tar.entryContent file of+          Tar.NormalFile content _ -> Right (Tar.entryPath file, content)+          _                        -> Left (Right NoCabalFileFound)+        _files -> Left (Right MultipleCabalFilesFound)++    isCabalFile e = case splitPath (Tar.entryPath e) of+      [     _dir, file] -> takeExtension file == ".cabal"+      [".", _dir, file] -> takeExtension file == ".cabal"+      _                 -> False+++-- | The name to use for a local file for a remote tarball 'SourceRepo'.+-- This is deterministic based on the remote tarball URI, and is intended+-- to produce non-clashing file names for different tarballs.+--+localFileNameForRemoteTarball :: URI -> FilePath+localFileNameForRemoteTarball uri =+    mangleName uri+ ++ "-" ++  showHex locationHash ""+  where+    mangleName = truncateString 10 . dropExtension . dropExtension+               . takeFileName . dropTrailingPathSeparator . uriPath++    locationHash :: Word+    locationHash = fromIntegral (Hashable.hash (uriToString id uri ""))+++-- | The name to use for a local file or dir for a remote 'SourceRepo'.+-- This is deterministic based on the source repo identity details, and+-- intended to produce non-clashing file names for different repos.+--+localFileNameForRemoteRepo :: SourceRepo -> FilePath+localFileNameForRemoteRepo SourceRepo{repoType, repoLocation, repoModule} =+    maybe "" ((++ "-") . mangleName) repoLocation+ ++ showHex locationHash ""+  where+    mangleName = truncateString 10 . dropExtension+               . takeFileName . dropTrailingPathSeparator++    -- just the parts that make up the "identity" of the repo+    locationHash :: Word+    locationHash =+      fromIntegral (Hashable.hash (show repoType, repoLocation, repoModule))+++-- | Truncate a string, with a visual indication that it is truncated.+truncateString :: Int -> String -> String+truncateString n s | length s <= n = s+                   | otherwise     = take (n-1) s ++ "_"   -- TODO: add something like this, here or in the project planning
Distribution/Client/ProjectConfig/Legacy.hs view
@@ -193,7 +193,8 @@         splitConfig pc = (pc                          , mempty { packageConfigProgramPaths = packageConfigProgramPaths pc                                   , packageConfigProgramArgs  = packageConfigProgramArgs  pc-                                  , packageConfigProgramPathExtra = packageConfigProgramPathExtra pc })+                                  , packageConfigProgramPathExtra = packageConfigProgramPathExtra pc+                                  , packageConfigDocumentation = packageConfigDocumentation pc })  -- | Convert from the types currently used for the user-wide @~/.cabal/config@ -- file into the 'ProjectConfig' type.@@ -303,7 +304,8 @@       globalSandboxConfigFile = _, -- ??       globalRemoteRepos       = projectConfigRemoteRepos,       globalLocalRepos        = projectConfigLocalRepos,-      globalProgPathExtra     = projectConfigProgPathExtra+      globalProgPathExtra     = projectConfigProgPathExtra,+      globalStoreDir          = projectConfigStoreDir     } = globalFlags      ConfigFlags {@@ -388,7 +390,7 @@       configRelocatable         = packageConfigRelocatable     } = configFlags     packageConfigProgramPaths   = MapLast    (Map.fromList configProgramPaths)-    packageConfigProgramArgs    = MapMappend (Map.fromList configProgramArgs)+    packageConfigProgramArgs    = MapMappend (Map.fromListWith (++) configProgramArgs)      packageConfigCoverage       = coverage <> libcoverage     --TODO: defer this merging to the resolve phase@@ -410,6 +412,7 @@       haddockInternal           = packageConfigHaddockInternal,       haddockCss                = packageConfigHaddockCss,       haddockLinkedSource       = packageConfigHaddockLinkedSource,+      haddockQuickJump          = packageConfigHaddockQuickJump,       haddockHscolourCss        = packageConfigHaddockHscolourCss,       haddockContents           = packageConfigHaddockContents     } = haddockFlags@@ -431,8 +434,7 @@       globalLogsDir           = projectConfigLogsDir,       globalWorldFile         = _,       globalHttpTransport     = projectConfigHttpTransport,-      globalIgnoreExpiry      = projectConfigIgnoreExpiry,-      globalStoreDir          = projectConfigStoreDir+      globalIgnoreExpiry      = projectConfigIgnoreExpiry     } = globalFlags      ConfigFlags {@@ -728,12 +730,14 @@       haddockInternal      = packageConfigHaddockInternal,       haddockCss           = packageConfigHaddockCss,       haddockLinkedSource  = packageConfigHaddockLinkedSource,+      haddockQuickJump     = packageConfigHaddockQuickJump,       haddockHscolourCss   = packageConfigHaddockHscolourCss,       haddockContents      = packageConfigHaddockContents,       haddockDistPref      = mempty,       haddockKeepTempFiles = mempty,       haddockVerbosity     = mempty,-      haddockCabalFilePath = mempty+      haddockCabalFilePath = mempty,+      haddockArgs          = mempty     }  @@ -1002,7 +1006,7 @@       [ "hoogle", "html", "html-location"       , "foreign-libraries"       , "executables", "tests", "benchmarks", "all", "internal", "css"-      , "hyperlink-source", "hscolour-css"+      , "hyperlink-source", "quickjump", "hscolour-css"       , "contents-location", "keep-temp-files"       ]   . commandOptionsToFields
Distribution/Client/ProjectConfig/Types.hs view
@@ -147,8 +147,7 @@        projectConfigHttpTransport         :: Flag String,        projectConfigIgnoreExpiry          :: Flag Bool,        projectConfigCacheDir              :: Flag FilePath,-       projectConfigLogsDir               :: Flag FilePath,-       projectConfigStoreDir              :: Flag FilePath+       projectConfigLogsDir               :: Flag FilePath      }   deriving (Eq, Show, Generic) @@ -178,6 +177,7 @@        projectConfigRemoteRepos       :: NubList RemoteRepo,     -- ^ Available Hackage servers.        projectConfigLocalRepos        :: NubList FilePath,        projectConfigIndexState        :: Flag IndexState,+       projectConfigStoreDir          :: Flag FilePath,         -- solver configuration        projectConfigConstraints       :: [(UserConstraint, ConstraintSource)],@@ -270,6 +270,7 @@        packageConfigHaddockInternal     :: Flag Bool, --TODO: [required eventually] use this        packageConfigHaddockCss          :: Flag FilePath, --TODO: [required eventually] use this        packageConfigHaddockLinkedSource :: Flag Bool, --TODO: [required eventually] use this+       packageConfigHaddockQuickJump    :: Flag Bool, --TODO: [required eventually] use this        packageConfigHaddockHscolourCss  :: Flag FilePath, --TODO: [required eventually] use this        packageConfigHaddockContents     :: Flag PathTemplate, --TODO: [required eventually] use this        packageConfigHaddockForHackage   :: Flag HaddockTarget
Distribution/Client/ProjectOrchestration.hs view
@@ -47,6 +47,7 @@     commandLineFlagsToProjectConfig,      -- * Pre-build phase: decide what to do.+    withInstallPlan,     runProjectPreBuildPhase,     ProjectBuildContext(..), @@ -56,6 +57,7 @@     resolveTargets,     TargetsMap,     TargetSelector(..),+    TargetImplicitCwd(..),     PackageId,     AvailableTarget(..),     AvailableTargetStatus(..),@@ -108,14 +110,17 @@  import           Distribution.Client.Types                    ( GenericReadyPackage(..), UnresolvedSourcePackage-                   , PackageSpecifier(..) )+                   , PackageSpecifier(..)+                   , SourcePackageDb(..) )+import           Distribution.Solver.Types.PackageIndex+                   ( lookupPackageName ) import qualified Distribution.Client.InstallPlan as InstallPlan import           Distribution.Client.TargetSelector-                   ( TargetSelector(..)+                   ( TargetSelector(..), TargetImplicitCwd(..)                    , ComponentKind(..), componentKind                    , readTargetSelectors, reportTargetSelectorProblems ) import           Distribution.Client.DistDirLayout-import           Distribution.Client.Config (defaultCabalDir)+import           Distribution.Client.Config (getCabalDir) import           Distribution.Client.Setup hiding (packageName) import           Distribution.Types.ComponentName                    ( componentNameString )@@ -136,8 +141,7 @@ import           Distribution.Simple.Configure (computeEffectiveProfiling)  import           Distribution.Simple.Utils-                   ( die'-                   , notice, noticeNoWrap, debugNoWrap )+                   ( die', warn, notice, noticeNoWrap, debugNoWrap ) import           Distribution.Verbosity import           Distribution.Text import           Distribution.Simple.Compiler@@ -171,7 +175,7 @@                             -> IO ProjectBaseContext establishProjectBaseContext verbosity cliConfig = do -    cabalDir <- defaultCabalDir+    cabalDir <- getCabalDir     projectRoot <- either throwIO return =<<                    findProjectRoot Nothing mprojectFile @@ -184,10 +188,13 @@                            cliConfig      let ProjectConfigBuildOnly {-          projectConfigLogsDir,-          projectConfigStoreDir+          projectConfigLogsDir         } = projectConfigBuildOnly projectConfig +        ProjectConfigShared {+          projectConfigStoreDir+        } = projectConfigShared projectConfig+         mlogsDir = Setup.flagToMaybe projectConfigLogsDir         mstoreDir = Setup.flagToMaybe projectConfigStoreDir         cabalDirLayout = mkCabalDirLayout cabalDir mstoreDir mlogsDir@@ -243,6 +250,31 @@  -- | Pre-build phase: decide what to do. --+withInstallPlan+    :: Verbosity+    -> ProjectBaseContext+    -> (ElaboratedInstallPlan -> ElaboratedSharedConfig -> IO a)+    -> IO a+withInstallPlan+    verbosity+    ProjectBaseContext {+      distDirLayout,+      cabalDirLayout,+      projectConfig,+      localPackages+    }+    action = do+    -- Take the project configuration and make a plan for how to build+    -- everything in the project. This is independent of any specific targets+    -- the user has asked for.+    --+    (elaboratedPlan, _, elaboratedShared) <-+      rebuildInstallPlan verbosity+                         distDirLayout cabalDirLayout+                         projectConfig+                         localPackages+    action elaboratedPlan elaboratedShared+ runProjectPreBuildPhase     :: Verbosity     -> ProjectBaseContext@@ -257,7 +289,6 @@       localPackages     }     selectPlanSubset = do-     -- Take the project configuration and make a plan for how to build     -- everything in the project. This is independent of any specific targets     -- the user has asked for.@@ -440,17 +471,11 @@                           -> Either err  k )                -> (TargetProblemCommon -> err)                -> ElaboratedInstallPlan+               -> Maybe (SourcePackageDb)                -> [TargetSelector]                -> Either [err] TargetsMap resolveTargets selectPackageTargets selectComponentTarget liftProblem-               installPlan =-    --TODO: [required eventually]-    -- we cannot resolve names of packages other than those that are-    -- directly in the current plan. We ought to keep a set of the known-    -- hackage packages so we can resolve names to those. Though we don't-    -- really need that until we can do something sensible with packages-    -- outside of the project.-+               installPlan mPkgDb =       fmap mkTargetsMap     . checkErrors     . map (\ts -> (,) ts <$> checkTarget ts)@@ -531,10 +556,13 @@       . selectPackageTargets bt       $ ats +      | Just SourcePackageDb{ packageIndex } <- mPkgDb+      , let pkg = lookupPackageName packageIndex pkgname+      , not (null pkg)+      = Left (liftProblem (TargetAvailableInIndex pkgname))+       | otherwise       = Left (liftProblem (TargetNotInProject pkgname))-    --TODO: check if the package is in hackage and return different-    -- error cases here so the commands can handle things appropriately      componentTargets :: SubComponentTarget                      -> [(b, ComponentName)]@@ -705,6 +733,7 @@  data TargetProblemCommon    = TargetNotInProject                   PackageName+   | TargetAvailableInIndex               PackageName    | TargetComponentNotProjectLocal       PackageId ComponentName SubComponentTarget    | TargetComponentNotBuildable          PackageId ComponentName SubComponentTarget    | TargetOptionalStanzaDisabledByUser   PackageId ComponentName SubComponentTarget@@ -914,7 +943,7 @@         -- For all failures, print either a short summary (if we showed the        -- build log) or all details-       die' verbosity $ unlines+       dieIfNotHaddockFailure verbosity $ unlines          [ case failureClassification of              ShowBuildSummaryAndLog reason _                | verbosity > normal@@ -942,6 +971,15 @@       , InstallPlan.Configured pkg <-            maybeToList (InstallPlan.lookup plan pkgid)       ]++    dieIfNotHaddockFailure+      | all isHaddockFailure failuresClassification = warn+      | otherwise                                   = die'+      where+        isHaddockFailure (_, ShowBuildSummaryOnly   (HaddocksFailed _)  ) = True+        isHaddockFailure (_, ShowBuildSummaryAndLog (HaddocksFailed _) _) = True+        isHaddockFailure _                                                = False+      classifyBuildFailure :: BuildFailure -> BuildFailurePresentation     classifyBuildFailure BuildFailure {
Distribution/Client/ProjectPlanOutput.hs view
@@ -18,7 +18,7 @@ import           Distribution.Client.ProjectPlanning.Types import           Distribution.Client.ProjectBuilding.Types import           Distribution.Client.DistDirLayout-import           Distribution.Client.Types (confInstId)+import           Distribution.Client.Types (Repo(..), RemoteRepo(..), PackageLocation(..), confInstId) import           Distribution.Client.PackageHash (showHashValue)  import qualified Distribution.Client.InstallPlan as InstallPlan@@ -139,6 +139,7 @@         , "flags"      J..= J.object [ PD.unFlagName fn J..= v                                      | (fn,v) <- PD.unFlagAssignment (elabFlagAssignment elab) ]         , "style"      J..= J.String (style2str (elabLocalToProject elab) (elabBuildStyle elab))+        , "pkg-src"    J..= packageLocationToJ (elabPkgSourceLocation elab)         ] ++         [ "pkg-src-sha256" J..= J.String (showHashValue hash)         | Just hash <- [elabPkgSourceHash elab] ] ++@@ -168,6 +169,57 @@             ] ++             bin_file (compSolverName comp)      where+      packageLocationToJ :: PackageLocation (Maybe FilePath) -> J.Value+      packageLocationToJ pkgloc =+        case pkgloc of+          LocalUnpackedPackage local ->+            J.object [ "type" J..= J.String "local"+                     , "path" J..= J.String local+                     ]+          LocalTarballPackage local ->+            J.object [ "type" J..= J.String "local-tar"+                     , "path" J..= J.String local+                     ]+          RemoteTarballPackage uri _ ->+            J.object [ "type" J..= J.String "remote-tar"+                     , "uri"  J..= J.String (show uri)+                     ]+          RepoTarballPackage repo _ _ ->+            J.object [ "type" J..= J.String "repo-tar"+                     , "repo" J..= repoToJ repo+                     ]+          RemoteSourceRepoPackage srcRepo _ ->+            J.object [ "type" J..= J.String "source-repo"+                     , "source-repo" J..= sourceRepoToJ srcRepo+                     ]++      repoToJ :: Repo -> J.Value+      repoToJ repo =+        case repo of+          RepoLocal{..} ->+            J.object [ "type" J..= J.String "local-repo"+                     , "path" J..= J.String repoLocalDir+                     ]+          RepoRemote{..} ->+            J.object [ "type" J..= J.String "remote-repo"+                     , "uri"  J..= J.String (show (remoteRepoURI repoRemote))+                     ]+          RepoSecure{..} ->+            J.object [ "type" J..= J.String "secure-repo"+                     , "uri"  J..= J.String (show (remoteRepoURI repoRemote))+                     ]++      sourceRepoToJ :: PD.SourceRepo -> J.Value+      sourceRepoToJ PD.SourceRepo{..} =+        J.object $ filter ((/= J.Null) . snd) $+          [ "type"     J..= fmap jdisplay repoType+          , "location" J..= fmap J.String repoLocation+          , "module"   J..= fmap J.String repoModule+          , "branch"   J..= fmap J.String repoBranch+          , "tag"      J..= fmap J.String repoTag+          , "subdir"   J..= fmap J.String repoSubdir+          ]+       dist_dir = distBuildDirectory distDirLayout                     (elabDistDirParams elaboratedSharedConfig elab) @@ -510,7 +562,7 @@       Graph.revClosure packagesLibDepGraph         ( Map.keys         . Map.filter (uncurry buildAttempted)-        $ Map.intersectionWith (,) pkgBuildStatus buildOutcomes +        $ Map.intersectionWith (,) pkgBuildStatus buildOutcomes         )      -- The plan graph but only counting dependency-on-library edges@@ -881,4 +933,3 @@       UserPackageDB          -> UserPackageDB       SpecificPackageDB path -> SpecificPackageDB relpath         where relpath = makeRelative relroot path-
Distribution/Client/ProjectPlanning.hs view
@@ -56,6 +56,7 @@     setupHsCopyFlags,     setupHsRegisterFlags,     setupHsHaddockFlags,+    setupHsHaddockArgs,      packageHashInputs, @@ -86,6 +87,7 @@ import           Distribution.Client.SetupWrapper import           Distribution.Client.JobControl import           Distribution.Client.FetchUtils+import           Distribution.Client.Config import qualified Hackage.Security.Client as Sec import           Distribution.Client.Setup hiding (packageName, cabalVersion) import           Distribution.Utils.NubList@@ -142,7 +144,7 @@ import           Distribution.Backpack import           Distribution.Types.ComponentInclude -import           Distribution.Simple.Utils hiding (matchFileGlob)+import           Distribution.Simple.Utils import           Distribution.Version import           Distribution.Verbosity import           Distribution.Text@@ -294,41 +296,57 @@ rebuildProjectConfig :: Verbosity                      -> DistDirLayout                      -> ProjectConfig-                     -> IO (ProjectConfig,-                            [PackageSpecifier UnresolvedSourcePackage])+                     -> IO ( ProjectConfig+                           , [PackageSpecifier UnresolvedSourcePackage] ) rebuildProjectConfig verbosity                      distDirLayout@DistDirLayout {                        distProjectRootDirectory,                        distDirectory,                        distProjectCacheFile,-                       distProjectCacheDirectory+                       distProjectCacheDirectory,+                       distProjectFile                      }                      cliConfig = do +    fileMonitorProjectConfigKey <- do+      configPath <- getConfigFilePath projectConfigConfigFile+      return (configPath, distProjectFile "")+     (projectConfig, localPackages) <--      runRebuild distProjectRootDirectory $-      rerunIfChanged verbosity fileMonitorProjectConfig () $ do+      runRebuild distProjectRootDirectory+      $ rerunIfChanged verbosity+                       fileMonitorProjectConfig+                       fileMonitorProjectConfigKey+      $ do+          liftIO $ info verbosity "Project settings changed, reconfiguring..."+          projectConfig <- phaseReadProjectConfig+          localPackages <- phaseReadLocalPackages projectConfig+          return (projectConfig, localPackages) -        projectConfig <- phaseReadProjectConfig-        localPackages <- phaseReadLocalPackages projectConfig-        return (projectConfig, localPackages)+    info verbosity+      $ unlines+      $ ("this build was affected by the following (project) config files:" :)+      $ [ "- " ++ path+        | Explicit path <- Set.toList $ projectConfigProvenance projectConfig+        ]      return (projectConfig <> cliConfig, localPackages)    where-    ProjectConfigShared {-      projectConfigConfigFile-    } = projectConfigShared cliConfig -    fileMonitorProjectConfig = newFileMonitor (distProjectCacheFile "config")+    ProjectConfigShared { projectConfigConfigFile } =+      projectConfigShared cliConfig +    fileMonitorProjectConfig =+      newFileMonitor (distProjectCacheFile "config") :: FileMonitor+          (FilePath, FilePath)+          (ProjectConfig, [PackageSpecifier UnresolvedSourcePackage])+     -- Read the cabal.project (or implicit config) and combine it with     -- arguments from the command line     --     phaseReadProjectConfig :: Rebuild ProjectConfig     phaseReadProjectConfig = do-      liftIO $ do-        info verbosity "Project settings changed, reconfiguring..."       readProjectConfig verbosity projectConfigConfigFile distDirLayout      -- Look for all the cabal packages in the project@@ -336,8 +354,11 @@     --     phaseReadLocalPackages :: ProjectConfig                            -> Rebuild [PackageSpecifier UnresolvedSourcePackage]-    phaseReadLocalPackages projectConfig = do-      localCabalFiles <- findProjectPackages distDirLayout projectConfig+    phaseReadLocalPackages projectConfig@ProjectConfig {+                               projectConfigShared,+                               projectConfigBuildOnly+                             } = do+      pkgLocations <- findProjectPackages distDirLayout projectConfig        -- Create folder only if findProjectPackages did not throw a       -- BadPackageLocations exception.@@ -345,7 +366,10 @@         createDirectoryIfMissingVerbose verbosity True distDirectory         createDirectoryIfMissingVerbose verbosity True distProjectCacheDirectory -      mapM (readSourcePackage verbosity) localCabalFiles+      fetchAndReadSourcePackages verbosity distDirLayout+                                 projectConfigShared+                                 projectConfigBuildOnly+                                 pkgLocations   -- | Return an up-to-date elaborated install plan.@@ -586,7 +610,7 @@                        -> (Compiler, Platform, ProgramDb)                        -> PkgConfigDb                        -> SolverInstallPlan-                       -> [PackageSpecifier (SourcePackage loc)]+                       -> [PackageSpecifier (SourcePackage (PackageLocation loc))]                        -> Rebuild ( ElaboratedInstallPlan                                   , ElaboratedSharedConfig )     phaseElaboratePlan ProjectConfig {@@ -1041,6 +1065,7 @@     -- respective major Cabal version bundled with the respective GHC     -- release).     --+    -- GHC 8.4   needs  Cabal >= 2.4     -- GHC 8.4   needs  Cabal >= 2.2     -- GHC 8.2   needs  Cabal >= 2.0     -- GHC 8.0   needs  Cabal >= 1.24@@ -1052,11 +1077,12 @@     -- TODO: long-term, this compatibility matrix should be     --       stored as a field inside 'Distribution.Compiler.Compiler'     setupMinCabalVersionConstraint-      | isGHC, compVer >= mkVersion [8,4,1] = mkVersion [2,2]-        -- GHC 8.4.1-rc1 (GHC 8.4.0.20180224) still shipped with an-        -- devel snapshot of Cabal-2.1.0.0; the rule below can be+      | isGHC, compVer >= mkVersion [8,6,1] = mkVersion [2,4]+        -- GHC 8.6alpha2 (GHC 8.6.0.20180714) still shipped with a+        -- devel snapshot of Cabal-2.3.0.0; the rule below can be         -- dropped at some point-      | isGHC, compVer >= mkVersion [8,4]  = mkVersion [2,1]+      | isGHC, compVer >= mkVersion [8,6]  = mkVersion [2,3]+      | isGHC, compVer >= mkVersion [8,4]  = mkVersion [2,2]       | isGHC, compVer >= mkVersion [8,2]  = mkVersion [2,0]       | isGHC, compVer >= mkVersion [8,0]  = mkVersion [1,24]       | isGHC, compVer >= mkVersion [7,10] = mkVersion [1,22]@@ -1160,9 +1186,7 @@ --      (due to setup dependencies); we can't just look up the package name --      from the package description. ----- However, we do have the following INVARIANT: a component never directly--- depends on multiple versions of the same package.  Thus, we can--- adopt the following strategy:+-- We can adopt the following strategy: -- --      * When a package is transformed into components, record --        a mapping from SolverId to ALL of the components@@ -1175,12 +1199,12 @@ -- By the way, we can tell that SolverInstallPlan is not the "right" type -- because a SolverId cannot adequately represent all possible dependency -- solver states: we may need to record foo-0.1 multiple times in--- the solver install plan with different dependencies.  The solver probably--- doesn't handle this correctly... but it should.  The right way to solve--- this is to come up with something very much like a 'ConfiguredId', in that--- it incorporates the version choices of its dependencies, but less--- fine grained.  Fortunately, this doesn't seem to have affected anyone,--- but it is good to watch out about.+-- the solver install plan with different dependencies.  This imprecision in the+-- type currently doesn't cause any problems because the dependency solver+-- continues to enforce the single instance restriction regardless of compiler+-- version.  The right way to solve this is to come up with something very much+-- like a 'ConfiguredId', in that it incorporates the version choices of its+-- dependencies, but less fine grained.   -- | Produce an elaborated install plan using the policy for local builds with@@ -1194,7 +1218,7 @@   -> DistDirLayout   -> StoreDirLayout   -> SolverInstallPlan-  -> [PackageSpecifier (SourcePackage loc)]+  -> [PackageSpecifier (SourcePackage (PackageLocation loc))]   -> Map PackageId PackageSourceHash   -> InstallDirs.InstallDirTemplates   -> ProjectConfigShared@@ -1219,7 +1243,8 @@       ElaboratedSharedConfig {         pkgConfigPlatform      = platform,         pkgConfigCompiler      = compiler,-        pkgConfigCompilerProgs = compilerprogdb+        pkgConfigCompilerProgs = compilerprogdb,+        pkgConfigReplOptions   = []       }      preexistingInstantiatedPkgs =@@ -1385,10 +1410,14 @@                           quotes (text (componentNameStanza cname))) $ do              -- 1. Configure the component, but with a place holder ComponentId.-            cc0 <- toConfiguredComponent pd+            cc0 <- toConfiguredComponent+                    pd                     (error "Distribution.Client.ProjectPlanning.cc_cid: filled in later")-                    (Map.unionWith Map.union external_cc_map cc_map) comp+                    (Map.unionWith Map.union external_lib_cc_map cc_map)+                    (Map.unionWith Map.union external_exe_cc_map cc_map)+                    comp +             -- 2. Read out the dependencies from the ConfiguredComponent cc0             let compLibDependencies =                     -- Nub because includes can show up multiple times@@ -1472,20 +1501,31 @@             -- 'elab'.             external_lib_dep_sids = CD.select (== compSolverName) deps0             external_exe_dep_sids = CD.select (== compSolverName) exe_deps0-            -- TODO: The fact that lib SolverIds and exe SolverIds are-            -- jammed together here means that we're losing information!-            external_dep_sids = external_lib_dep_sids ++ external_exe_dep_sids-            external_dep_pkgs = concatMap mapDep external_dep_sids +            external_lib_dep_pkgs = concatMap mapDep external_lib_dep_sids++            -- Combine library and build-tool dependencies, for backwards+            -- compatibility (See issue #5412 and the documentation for+            -- InstallPlan.fromSolverInstallPlan), but prefer the versions+            -- specified as build-tools.+            external_exe_dep_pkgs =+                concatMap mapDep $+                ordNubBy (pkgName . packageId) $+                external_exe_dep_sids ++ external_lib_dep_sids+             external_exe_map = Map.fromList $                 [ (getComponentId pkg, path)-                | pkg <- external_dep_pkgs+                | pkg <- external_exe_dep_pkgs                 , Just path <- [planPackageExePath pkg] ]             exe_map1 = Map.union external_exe_map exe_map -            external_cc_map = Map.fromListWith Map.union-                            $ map mkCCMapping external_dep_pkgs-            external_lc_map = Map.fromList (map mkShapeMapping external_dep_pkgs)+            external_lib_cc_map = Map.fromListWith Map.union+                                $ map mkCCMapping external_lib_dep_pkgs+            external_exe_cc_map = Map.fromListWith Map.union+                                $ map mkCCMapping external_exe_dep_pkgs+            external_lc_map =+                Map.fromList $ map mkShapeMapping $+                external_lib_dep_pkgs ++ concatMap mapDep external_exe_dep_sids              compPkgConfigDependencies =                 [ (pn, fromMaybe (error $ "compPkgConfigDependencies: impossible! "@@ -1727,6 +1767,8 @@         elabTestTargets     = []         elabBenchTargets    = []         elabReplTarget      = Nothing+        elabHaddockTargets  = []+         elabBuildHaddocks   =           perPkgOptionFlag pkgid False packageConfigDocumentation @@ -1808,6 +1850,7 @@         elabHaddockInternal     = perPkgOptionFlag pkgid False packageConfigHaddockInternal         elabHaddockCss          = perPkgOptionMaybe pkgid packageConfigHaddockCss         elabHaddockLinkedSource = perPkgOptionFlag pkgid False packageConfigHaddockLinkedSource+        elabHaddockQuickJump    = perPkgOptionFlag pkgid False packageConfigHaddockQuickJump         elabHaddockHscolourCss  = perPkgOptionMaybe pkgid packageConfigHaddockHscolourCss         elabHaddockContents     = perPkgOptionMaybe pkgid packageConfigHaddockContents @@ -1876,12 +1919,14 @@         --TODO: localPackages is a misnomer, it's all project packages         -- here is where we decide which ones will be local!       where-        shouldBeLocal :: PackageSpecifier (SourcePackage loc) -> Maybe PackageId+        shouldBeLocal :: PackageSpecifier (SourcePackage (PackageLocation loc)) -> Maybe PackageId         shouldBeLocal NamedPackage{}              = Nothing-        shouldBeLocal (SpecificSourcePackage pkg) = Just (packageId pkg)-        -- TODO: It's not actually obvious for all of the-        -- 'ProjectPackageLocation's that they should all be local. We might-        -- need to provide the user with a choice.+        shouldBeLocal (SpecificSourcePackage pkg) +          | LocalTarballPackage _ <- packageSource pkg = Nothing+          | otherwise = Just (packageId pkg)+        -- TODO: Is it only LocalTarballPackages we can know about without +        -- them being "local" in the sense meant here?+        --         -- Also, review use of SourcePackage's loc vs ProjectPackageLocation      pkgsUseSharedLibrary :: Set PackageId@@ -2437,6 +2482,7 @@     isJust (elabReplTarget elab)  || (not . null) (elabTestTargets elab)  || (not . null) (elabBenchTargets elab)+ || (not . null) (elabHaddockTargets elab)  || (not . null) [ () | ComponentTarget _ subtarget <- elabBuildTargets elab                       , subtarget /= WholeComponent ] @@ -2535,11 +2581,22 @@         (Just tgts,  TargetActionBuild)   -> elab { elabBuildTargets = tgts }         (Just tgts,  TargetActionTest)    -> elab { elabTestTargets  = tgts }         (Just tgts,  TargetActionBench)   -> elab { elabBenchTargets  = tgts }-        (Just [tgt], TargetActionRepl)    -> elab { elabReplTarget = Just tgt }-        (Just _,     TargetActionHaddock) -> elab { elabBuildHaddocks = True }+        (Just [tgt], TargetActionRepl)    -> elab { elabReplTarget = Just tgt+                                                  , elabBuildHaddocks = False }+        (Just tgts,  TargetActionHaddock) ->+          foldr setElabHaddockTargets (elab { elabHaddockTargets = tgts+                                            , elabBuildHaddocks = True }) tgts         (Just _,     TargetActionRepl)    ->           error "pruneInstallPlanToTargets: multiple repl targets" +    setElabHaddockTargets tgt elab+      | isTestComponentTarget tgt       = elab { elabHaddockTestSuites  = True }+      | isBenchComponentTarget tgt      = elab { elabHaddockBenchmarks  = True }+      | isForeignLibComponentTarget tgt = elab { elabHaddockForeignLibs = True }+      | isExeComponentTarget tgt        = elab { elabHaddockExecutables = True }+      | isSubLibComponentTarget tgt     = elab { elabHaddockInternal    = True }+      | otherwise                       = elab+ -- | Assuming we have previously set the root build targets (i.e. the user -- targets but not rev deps yet), the first pruning pass does two things: --@@ -2560,14 +2617,16 @@     roots = mapMaybe find_root pkgs'      prune elab = PrunedPackage elab' (pruneOptionalDependencies elab')-      where elab' = addOptionalStanzas elab+      where elab' =+                setDocumentation+              $ addOptionalStanzas elab      find_root (InstallPlan.Configured (PrunedPackage elab _)) =         if not (null (elabBuildTargets elab)                     && null (elabTestTargets elab)                     && null (elabBenchTargets elab)                     && isNothing (elabReplTarget elab)-                    && not (elabBuildHaddocks elab))+                    && null (elabHaddockTargets elab))             then Just (installedUnitId elab)             else Nothing     find_root _ = Nothing@@ -2613,6 +2672,26 @@                <> optionalStanzasWithDepsAvailable availablePkgs elab pkg     addOptionalStanzas elab = elab +    setDocumentation :: ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage+    setDocumentation elab@ElaboratedConfiguredPackage { elabPkgOrComp = ElabComponent comp } =+      elab {+        elabBuildHaddocks =+            elabBuildHaddocks elab && documentationEnabled (compSolverName comp) elab+      }++      where+        documentationEnabled c =+          case c of+            CD.ComponentLib      -> const True+            CD.ComponentSubLib _ -> elabHaddockInternal+            CD.ComponentFLib _   -> elabHaddockForeignLibs+            CD.ComponentExe _    -> elabHaddockExecutables+            CD.ComponentTest _   -> elabHaddockTestSuites+            CD.ComponentBench _  -> elabHaddockBenchmarks+            CD.ComponentSetup    -> const False++    setDocumentation elab = elab+     -- Calculate package dependencies but cut out those needed only by     -- optional stanzas that we've determined we will not enable.     -- These pruned deps are not persisted in this pass since they're based on@@ -2639,6 +2718,7 @@                                   ++ elabTestTargets pkg                                   ++ elabBenchTargets pkg                                   ++ maybeToList (elabReplTarget pkg)+                                  ++ elabHaddockTargets pkg         , stanza <- maybeToList (componentOptionalStanza cname)         ] @@ -3313,13 +3393,14 @@                  -> Verbosity                  -> FilePath                  -> Cabal.ReplFlags-setupHsReplFlags _ _ verbosity builddir =+setupHsReplFlags _ sharedConfig verbosity builddir =     Cabal.ReplFlags {       replProgramPaths = mempty, --unused, set at configure time       replProgramArgs  = mempty, --unused, set at configure time       replVerbosity    = toFlag verbosity,       replDistPref     = toFlag builddir,-      replReload       = mempty  --only used as callback from repl+      replReload       = mempty, --only used as callback from repl+      replReplOptions  = pkgConfigReplOptions sharedConfig       --runtime override for repl flags     }  @@ -3371,8 +3452,6 @@                     -> Verbosity                     -> FilePath                     -> Cabal.HaddockFlags--- TODO: reconsider whether or not Executables/TestSuites/...--- needed for component setupHsHaddockFlags (ElaboratedConfiguredPackage{..}) _ verbosity builddir =     Cabal.HaddockFlags {       haddockProgramPaths  = mempty, --unused, set at configure time@@ -3388,14 +3467,21 @@       haddockInternal      = toFlag elabHaddockInternal,       haddockCss           = maybe mempty toFlag elabHaddockCss,       haddockLinkedSource  = toFlag elabHaddockLinkedSource,+      haddockQuickJump     = toFlag elabHaddockQuickJump,       haddockHscolourCss   = maybe mempty toFlag elabHaddockHscolourCss,       haddockContents      = maybe mempty toFlag elabHaddockContents,       haddockDistPref      = toFlag builddir,       haddockKeepTempFiles = mempty, --TODO: from build settings       haddockVerbosity     = toFlag verbosity,-      haddockCabalFilePath = mempty+      haddockCabalFilePath = mempty,+      haddockArgs          = mempty     } +setupHsHaddockArgs :: ElaboratedConfiguredPackage -> [String]+-- TODO: Does the issue #3335 affects test as well+setupHsHaddockArgs elab =+  map (showComponentTarget (packageId elab)) (elabHaddockTargets elab)+ {- setupHsTestFlags :: ElaboratedConfiguredPackage                  -> ElaboratedSharedConfig@@ -3498,10 +3584,7 @@ packageHashConfigInputs :: ElaboratedSharedConfig                         -> ElaboratedConfiguredPackage                         -> PackageHashConfigInputs-packageHashConfigInputs-    ElaboratedSharedConfig{..}-    ElaboratedConfiguredPackage{..} =-+packageHashConfigInputs shared@ElaboratedSharedConfig{..} pkg =     PackageHashConfigInputs {       pkgHashCompilerId          = compilerId pkgConfigCompiler,       pkgHashPlatform            = pkgConfigPlatform,@@ -3527,9 +3610,24 @@       pkgHashExtraFrameworkDirs  = elabExtraFrameworkDirs,       pkgHashExtraIncludeDirs    = elabExtraIncludeDirs,       pkgHashProgPrefix          = elabProgPrefix,-      pkgHashProgSuffix          = elabProgSuffix-    }+      pkgHashProgSuffix          = elabProgSuffix, +      pkgHashDocumentation       = elabBuildHaddocks,+      pkgHashHaddockHoogle       = elabHaddockHoogle,+      pkgHashHaddockHtml         = elabHaddockHtml,+      pkgHashHaddockHtmlLocation = elabHaddockHtmlLocation,+      pkgHashHaddockForeignLibs  = elabHaddockForeignLibs,+      pkgHashHaddockExecutables  = elabHaddockExecutables,+      pkgHashHaddockTestSuites   = elabHaddockTestSuites,+      pkgHashHaddockBenchmarks   = elabHaddockBenchmarks,+      pkgHashHaddockInternal     = elabHaddockInternal,+      pkgHashHaddockCss          = elabHaddockCss,+      pkgHashHaddockLinkedSource = elabHaddockLinkedSource,+      pkgHashHaddockQuickJump    = elabHaddockQuickJump,+      pkgHashHaddockContents     = elabHaddockContents+    }+  where+    ElaboratedConfiguredPackage{..} = normaliseConfiguredPackage shared pkg  -- | Given the 'InstalledPackageIndex' for a nix-style package store, and an -- 'ElaboratedInstallPlan', replace configured source packages by installed@@ -3584,4 +3682,3 @@ inplaceBinRoot layout config package   =  distBuildDirectory layout (elabDistDirParams config package)  </> "build"-
Distribution/Client/ProjectPlanning/Types.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE TypeFamilies #-}  -- | Types used while planning how to build everything in a project.@@ -11,6 +12,7 @@      -- * Elaborated install plan types     ElaboratedInstallPlan,+    normaliseConfiguredPackage,     ElaboratedConfiguredPackage(..),      elabDistDirParams,@@ -46,7 +48,11 @@     showBenchComponentTarget,     SubComponentTarget(..), +    isSubLibComponentTarget,+    isForeignLibComponentTarget,+    isExeComponentTarget,     isTestComponentTarget,+    isBenchComponentTarget,      -- * Setup script     SetupScriptStyle(..),@@ -79,7 +85,7 @@ import           Distribution.Simple.Compiler import           Distribution.Simple.Build.PathsModule (pkgPathEnvVar) import qualified Distribution.Simple.BuildTarget as Cabal-import           Distribution.Simple.Program.Db+import           Distribution.Simple.Program import           Distribution.ModuleName (ModuleName) import           Distribution.Simple.LocalBuildInfo (ComponentName(..)) import qualified Distribution.Simple.InstallDirs as InstallDirs@@ -94,6 +100,7 @@ import           Distribution.Simple.Utils (ordNub)  import           Data.Map (Map)+import qualified Data.Map as Map import           Data.Maybe (catMaybes) import           Data.Set (Set) import qualified Data.ByteString.Lazy as LBS@@ -141,7 +148,8 @@        -- | The programs that the compiler configured (e.g. for GHC, the progs        -- ghc & ghc-pkg). Once constructed, only the 'configuredPrograms' are        -- used.-       pkgConfigCompilerProgs :: ProgramDb+       pkgConfigCompilerProgs :: ProgramDb,+       pkgConfigReplOptions :: [String]      }   deriving (Show, Generic, Typeable)   --TODO: [code cleanup] no Eq instance@@ -273,6 +281,7 @@        elabHaddockInternal       :: Bool,        elabHaddockCss            :: Maybe FilePath,        elabHaddockLinkedSource   :: Bool,+       elabHaddockQuickJump      :: Bool,        elabHaddockHscolourCss    :: Maybe FilePath,        elabHaddockContents       :: Maybe PathTemplate, @@ -293,6 +302,8 @@        elabTestTargets           :: [ComponentTarget],        elabBenchTargets          :: [ComponentTarget],        elabReplTarget            :: Maybe ComponentTarget,+       elabHaddockTargets        :: [ComponentTarget],+        elabBuildHaddocks         :: Bool,         --pkgSourceDir ? -- currently passed in later because they can use temp locations@@ -303,6 +314,29 @@    }   deriving (Eq, Show, Generic, Typeable) +normaliseConfiguredPackage :: ElaboratedSharedConfig+                           -> ElaboratedConfiguredPackage+                           -> ElaboratedConfiguredPackage+normaliseConfiguredPackage ElaboratedSharedConfig{pkgConfigCompilerProgs} pkg =+    pkg { elabProgramArgs = Map.mapMaybeWithKey lookupFilter (elabProgramArgs pkg) }+  where+    knownProgramDb = addKnownPrograms builtinPrograms pkgConfigCompilerProgs++    pkgDesc :: PackageDescription+    pkgDesc = elabPkgDescription pkg++    removeEmpty :: [String] -> Maybe [String]+    removeEmpty [] = Nothing+    removeEmpty xs = Just xs++    lookupFilter :: String -> [String] -> Maybe [String]+    lookupFilter n args = removeEmpty $ case lookupKnownProgram n knownProgramDb of+        Just p -> programNormaliseArgs p (getVersion p) pkgDesc args+        Nothing -> args++    getVersion :: Program -> Maybe Version+    getVersion p = lookupProgram p knownProgramDb >>= programVersion+ -- | The package/component contains/is a library and so must be registered elabRequiresRegistration :: ElaboratedConfiguredPackage -> Bool elabRequiresRegistration elab =@@ -702,6 +736,22 @@ showBenchComponentTarget :: PackageId -> ComponentTarget -> Maybe String showBenchComponentTarget _ (ComponentTarget (CBenchName n) _) = Just $ display n showBenchComponentTarget _ _ = Nothing++isBenchComponentTarget :: ComponentTarget -> Bool+isBenchComponentTarget (ComponentTarget (CBenchName _) _) = True+isBenchComponentTarget _                                  = False++isForeignLibComponentTarget :: ComponentTarget -> Bool+isForeignLibComponentTarget (ComponentTarget (CFLibName _) _) = True+isForeignLibComponentTarget _                                 = False++isExeComponentTarget :: ComponentTarget -> Bool+isExeComponentTarget (ComponentTarget (CExeName _) _ ) = True+isExeComponentTarget _                                 = False++isSubLibComponentTarget :: ComponentTarget -> Bool+isSubLibComponentTarget (ComponentTarget (CSubLibName _) _) = True+isSubLibComponentTarget _                                   = False  --------------------------- -- Setup.hs script policy
Distribution/Client/RebuildMonad.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, BangPatterns #-}  -- | An abstraction for re-running actions if values or files have changed. --@@ -41,6 +41,8 @@     rerunIfChanged,      -- * Utils+    delayInitSharedResource,+    delayInitSharedResources,     matchFileGlob,     getDirectoryContentsMonitored,     createDirectoryMonitored,@@ -63,8 +65,10 @@ import Distribution.Simple.Utils (debug) import Distribution.Verbosity    (Verbosity) +import qualified Data.Map.Strict as Map import Control.Monad.State as State import Control.Monad.Reader as Reader+import Control.Concurrent.MVar (MVar, newMVar, modifyMVar) import System.FilePath import System.Directory @@ -144,6 +148,76 @@     showReason (MonitoredValueChanged _)   = "monitor value changed"     showReason  MonitorFirstRun            = "first run"     showReason  MonitorCorruptCache        = "invalid cache file"+++-- | When using 'rerunIfChanged' for each element of a list of actions, it is+-- sometimes the case that each action needs to make use of some resource. e.g.+--+-- > sequence+-- >   [ rerunIfChanged verbosity monitor key $ do+-- >       resource <- mkResource+-- >       ... -- use the resource+-- >   | ... ]+--+-- For efficiency one would like to share the resource between the actions+-- but the straightforward way of doing this means initialising it every time+-- even when no actions need re-running.+--+-- > resource <- mkResource+-- > sequence+-- >   [ rerunIfChanged verbosity monitor key $ do+-- >       ... -- use the resource+-- >   | ... ]+--+-- This utility allows one to get the best of both worlds:+--+-- > getResource <- delayInitSharedResource mkResource+-- > sequence+-- >   [ rerunIfChanged verbosity monitor key $ do+-- >       resource <- getResource+-- >       ... -- use the resource+-- >   | ... ]+--+delayInitSharedResource :: forall a. IO a -> Rebuild (Rebuild a)+delayInitSharedResource action = do+    var <- liftIO (newMVar Nothing)+    return (liftIO (getOrInitResource var))+  where+    getOrInitResource :: MVar (Maybe a) -> IO a+    getOrInitResource var =+      modifyMVar var $ \mx ->+        case mx of+          Just x  -> return (Just x, x)+          Nothing -> do+            x <- action+            return (Just x, x)+++-- | Much like 'delayInitSharedResource' but for a keyed set of resources.+--+-- > getResource <- delayInitSharedResource mkResource+-- > sequence+-- >   [ rerunIfChanged verbosity monitor key $ do+-- >       resource <- getResource key+-- >       ... -- use the resource+-- >   | ... ]+--+delayInitSharedResources :: forall k v. Ord k+                         => (k -> IO v)+                         -> Rebuild (k -> Rebuild v)+delayInitSharedResources action = do+    var <- liftIO (newMVar Map.empty)+    return (liftIO . getOrInitResource var)+  where+    getOrInitResource :: MVar (Map k v) -> k -> IO v+    getOrInitResource var k =+      modifyMVar var $ \m ->+        case Map.lookup k m of+          Just x  -> return (m, x)+          Nothing -> do+            x <- action k+            let !m' = Map.insert k x m+            return (m', x)   -- | Utility to match a file glob against the file system, starting from a
Distribution/Client/Run.hs view
@@ -125,7 +125,7 @@         return (cmd, cmdArgs ++ [script'])       _     -> do          p <- tryCanonicalizePath $-            buildPref </> exeName' </> (exeName' <.> exeExtension)+            buildPref </> exeName' </> (exeName' <.> exeExtension (hostPlatform lbi))          return (p, [])    env  <- (dataDirEnvVar:) <$> getEnvironment
Distribution/Client/Setup.hs view
@@ -24,6 +24,7 @@     , replCommand, testCommand, benchmarkCommand                         , configureExOptions, reconfigureCommand     , installCommand, InstallFlags(..), installOptions, defaultInstallFlags+    , filterHaddockArgs, filterHaddockFlags     , defaultSolver, defaultMaxBackjumps     , listCommand, ListFlags(..)     , updateCommand, UpdateFlags(..), defaultUpdateFlags@@ -48,8 +49,14 @@     , execCommand, ExecFlags(..), defaultExecFlags     , userConfigCommand, UserConfigFlags(..)     , manpageCommand+    , haddockCommand+    , cleanCommand+    , doctestCommand+    , copyCommand+    , registerCommand      , parsePackageArgs+    , liftOptions     --TODO: stop exporting these:     , showRepo     , parseRepo@@ -90,6 +97,8 @@          ( ConfigFlags(..), BuildFlags(..), ReplFlags          , TestFlags(..), BenchmarkFlags(..)          , SDistFlags(..), HaddockFlags(..)+         , CleanFlags(..), DoctestFlags(..)+         , CopyFlags(..), RegisterFlags(..)          , readPackageDbList, showPackageDbList          , Flag(..), toFlag, flagToMaybe, flagToList, maybeToFlag          , BooleanFlag(..), optionVerbosity@@ -189,6 +198,44 @@           , "new-test"           , "new-bench"           , "new-haddock"+          , "new-exec"+          , "new-update"+          , "new-install"+          , "new-clean"+          , "new-sdist"+          -- v1 commands, stateful style+          , "v1-build"+          , "v1-configure"+          , "v1-repl"+          , "v1-freeze"+          , "v1-run"+          , "v1-test"+          , "v1-bench"+          , "v1-haddock"+          , "v1-exec"+          , "v1-update"+          , "v1-install"+          , "v1-clean"+          , "v1-sdist"+          , "v1-doctest"+          , "v1-copy"+          , "v1-register"+          , "v1-reconfigure"+          , "v1-sandbox"+          -- v2 commands, nix-style+          , "v2-build"+          , "v2-configure"+          , "v2-repl"+          , "v2-freeze"+          , "v2-run"+          , "v2-test"+          , "v2-bench"+          , "v2-haddock"+          , "v2-exec"+          , "v2-update"+          , "v2-install"+          , "v2-clean"+          , "v2-sdist"           ]         maxlen    = maximum $ [length name | (name, _) <- cmdDescs]         align str = str ++ replicate (maxlen - length str) ' '@@ -256,6 +303,46 @@         , addCmd "new-bench"         , addCmd "new-freeze"         , addCmd "new-haddock"+        , addCmd "new-exec"+        , addCmd "new-update"+        , addCmd "new-install"+        , addCmd "new-clean"+        , addCmd "new-sdist"+        , par+        , startGroup "new-style projects (forwards-compatible aliases)"+        , addCmd "v2-build"+        , addCmd "v2-configure"+        , addCmd "v2-repl"+        , addCmd "v2-run"+        , addCmd "v2-test"+        , addCmd "v2-bench"+        , addCmd "v2-freeze"+        , addCmd "v2-haddock"+        , addCmd "v2-exec"+        , addCmd "v2-update"+        , addCmd "v2-install"+        , addCmd "v2-clean"+        , addCmd "v2-sdist"+        , par+        , startGroup "legacy command aliases"+        , addCmd "v1-build"+        , addCmd "v1-configure"+        , addCmd "v1-repl"+        , addCmd "v1-run"+        , addCmd "v1-test"+        , addCmd "v1-bench"+        , addCmd "v1-freeze"+        , addCmd "v1-haddock"+        , addCmd "v1-exec"+        , addCmd "v1-update"+        , addCmd "v1-install"+        , addCmd "v1-clean"+        , addCmd "v1-sdist"+        , addCmd "v1-doctest"+        , addCmd "v1-copy"+        , addCmd "v1-register"+        , addCmd "v1-reconfigure"+        , addCmd "v1-sandbox"         ] ++ if null otherCmds then [] else par                                            :startGroup "other"                                            :[addCmd n | n <- otherCmds])@@ -349,7 +436,7 @@          globalLocalRepos (\v flags -> flags { globalLocalRepos = v })          (reqArg' "DIR" (\x -> toNubList [x]) fromNubList) -      ,option [] ["logs-dir"]+      ,option [] ["logs-dir", "logsdir"]          "The location to put log files"          globalLogsDir (\v flags -> flags { globalLogsDir = v })          (reqArgFlag "DIR")@@ -359,7 +446,7 @@          globalWorldFile (\v flags -> flags { globalWorldFile = v })          (reqArgFlag "FILE") -      ,option [] ["store-dir"]+      ,option [] ["store-dir", "storedir"]          "The location of the nix-local-build store"          globalStoreDir (\v flags -> flags { globalStoreDir = v })          (reqArgFlag "DIR")@@ -371,16 +458,24 @@  configureCommand :: CommandUI ConfigFlags configureCommand = c-  { commandDefaultFlags = mempty-  , commandNotes = Just $ \pname -> (case commandNotes c of-         Nothing -> ""-         Just n  -> n pname ++ "\n")-       ++ "Examples:\n"-       ++ "  " ++ pname ++ " configure\n"-       ++ "    Configure with defaults;\n"-       ++ "  " ++ pname ++ " configure --enable-tests -fcustomflag\n"-       ++ "    Configure building package including tests,\n"-       ++ "    with some package-specific flag.\n"+  { commandName         = "configure"+  , commandDefaultFlags = mempty+  , commandDescription  = Just $ \_ -> wrapText $+         "Configure how the package is built by setting "+      ++ "package (and other) flags.\n"+      ++ "\n"+      ++ "The configuration affects several other commands, "+      ++ "including v1-build, v1-test, v1-bench, v1-run, v1-repl.\n"+  , commandUsage        = \pname ->+    "Usage: " ++ pname ++ " v1-configure [FLAGS]\n"+  , commandNotes = Just $ \pname ->+    (Cabal.programFlagsDescription defaultProgramDb ++ "\n")+      ++ "Examples:\n"+      ++ "  " ++ pname ++ " v1-configure\n"+      ++ "    Configure with defaults;\n"+      ++ "  " ++ pname ++ " v1-configure --enable-tests -fcustomflag\n"+      ++ "    Configure building package including tests,\n"+      ++ "    with some package-specific flag.\n"   }  where   c = Cabal.configureCommand defaultProgramDb@@ -613,17 +708,17 @@     , commandDescription  = Just $ \pname -> wrapText $          "Run `configure` with the most recently used flags, or append FLAGS "          ++ "to the most recently used configuration. "-         ++ "Accepts the same flags as `" ++ pname ++ " configure'. "+         ++ "Accepts the same flags as `" ++ pname ++ " v1-configure'. "          ++ "If the package has never been configured, the default flags are "          ++ "used."     , commandNotes        = Just $ \pname ->         "Examples:\n"-        ++ "  " ++ pname ++ " reconfigure\n"+        ++ "  " ++ pname ++ " v1-reconfigure\n"         ++ "    Configure with the most recently used flags.\n"-        ++ "  " ++ pname ++ " reconfigure -w PATH\n"+        ++ "  " ++ pname ++ " v1-reconfigure -w PATH\n"         ++ "    Reconfigure with the most recently used flags,\n"         ++ "    but use the compiler at PATH.\n\n"-    , commandUsage        = usageAlternatives "reconfigure" [ "[FLAGS]" ]+    , commandUsage        = usageAlternatives "v1-reconfigure" [ "[FLAGS]" ]     , commandDefaultFlags = mempty     } @@ -650,12 +745,26 @@  buildCommand :: CommandUI (BuildFlags, BuildExFlags) buildCommand = parent {+    commandName = "build",+    commandDescription  = Just $ \_ -> wrapText $+      "Components encompass executables, tests, and benchmarks.\n"+        ++ "\n"+        ++ "Affected by configuration options, see `v1-configure`.\n",     commandDefaultFlags = (commandDefaultFlags parent, mempty),+    commandUsage        = usageAlternatives "v1-build" $+      [ "[FLAGS]", "COMPONENTS [FLAGS]" ],     commandOptions      =       \showOrParseArgs -> liftOptions fst setFst                           (commandOptions parent showOrParseArgs)                           ++                           liftOptions snd setSnd (buildExOptions showOrParseArgs)+    , commandNotes        = Just $ \pname ->+      "Examples:\n"+        ++ "  " ++ pname ++ " v1-build           "+        ++ "    All the components in the package\n"+        ++ "  " ++ pname ++ " v1-build foo       "+        ++ "    A component (i.e. lib, exe, test suite)\n\n"+        ++ Cabal.programFlagsDescription defaultProgramDb   }   where     setFst a (_,b) = (a,b)@@ -676,12 +785,40 @@  replCommand :: CommandUI (ReplFlags, BuildExFlags) replCommand = parent {+    commandName = "repl",+    commandDescription  = Just $ \pname -> wrapText $+         "If the current directory contains no package, ignores COMPONENT "+      ++ "parameters and opens an interactive interpreter session; if a "+      ++ "sandbox is present, its package database will be used.\n"+      ++ "\n"+      ++ "Otherwise, (re)configures with the given or default flags, and "+      ++ "loads the interpreter with the relevant modules. For executables, "+      ++ "tests and benchmarks, loads the main module (and its "+      ++ "dependencies); for libraries all exposed/other modules.\n"+      ++ "\n"+      ++ "The default component is the library itself, or the executable "+      ++ "if that is the only component.\n"+      ++ "\n"+      ++ "Support for loading specific modules is planned but not "+      ++ "implemented yet. For certain scenarios, `" ++ pname+      ++ " v1-exec -- ghci :l Foo` may be used instead. Note that `v1-exec` will "+      ++ "not (re)configure and you will have to specify the location of "+      ++ "other modules, if required.\n",+    commandUsage =  \pname -> "Usage: " ++ pname ++ " v1-repl [COMPONENT] [FLAGS]\n",     commandDefaultFlags = (commandDefaultFlags parent, mempty),     commandOptions      =       \showOrParseArgs -> liftOptions fst setFst                           (commandOptions parent showOrParseArgs)                           ++-                          liftOptions snd setSnd (buildExOptions showOrParseArgs)+                          liftOptions snd setSnd (buildExOptions showOrParseArgs),+    commandNotes        = Just $ \pname ->+      "Examples:\n"+    ++ "  " ++ pname ++ " v1-repl           "+    ++ "    The first component in the package\n"+    ++ "  " ++ pname ++ " v1-repl foo       "+    ++ "    A named component (i.e. lib, exe, test suite)\n"+    ++ "  " ++ pname ++ " v1-repl --ghc-options=\"-lstdc++\""+    ++ "  Specifying flags for interpreter\n"   }   where     setFst a (_,b) = (a,b)@@ -695,6 +832,19 @@  testCommand :: CommandUI (TestFlags, BuildFlags, BuildExFlags) testCommand = parent {+  commandName = "test",+  commandDescription  = Just $ \pname -> wrapText $+         "If necessary (re)configures with `--enable-tests` flag and builds"+      ++ " the test suite.\n"+      ++ "\n"+      ++ "Remember that the tests' dependencies must be installed if there"+      ++ " are additional ones; e.g. with `" ++ pname+      ++ " v1-install --only-dependencies --enable-tests`.\n"+      ++ "\n"+      ++ "By defining UserHooks in a custom Setup.hs, the package can"+      ++ " define actions to be executed before and after running tests.\n",+  commandUsage = usageAlternatives "v1-test"+      [ "[FLAGS]", "TESTCOMPONENTS [FLAGS]" ],   commandDefaultFlags = (commandDefaultFlags parent,                          Cabal.defaultBuildFlags, mempty),   commandOptions      =@@ -720,6 +870,20 @@  benchmarkCommand :: CommandUI (BenchmarkFlags, BuildFlags, BuildExFlags) benchmarkCommand = parent {+  commandName = "bench",+  commandUsage = usageAlternatives "v1-bench"+      [ "[FLAGS]", "BENCHCOMPONENTS [FLAGS]" ],+  commandDescription  = Just $ \pname -> wrapText $+         "If necessary (re)configures with `--enable-benchmarks` flag and"+      ++ " builds the benchmarks.\n"+      ++ "\n"+      ++ "Remember that the benchmarks' dependencies must be installed if"+      ++ " there are additional ones; e.g. with `" ++ pname+      ++ " v1-install --only-dependencies --enable-benchmarks`.\n"+      ++ "\n"+      ++ "By defining UserHooks in a custom Setup.hs, the package can"+      ++ " define actions to be executed before and after running"+      ++ " benchmarks.\n",   commandDefaultFlags = (commandDefaultFlags parent,                          Cabal.defaultBuildFlags, mempty),   commandOptions      =@@ -967,6 +1131,7 @@   outdatedVerbosity     :: Flag Verbosity,   outdatedFreezeFile    :: Flag Bool,   outdatedNewFreezeFile :: Flag Bool,+  outdatedProjectFile   :: Flag FilePath,   outdatedSimpleOutput  :: Flag Bool,   outdatedExitCode      :: Flag Bool,   outdatedQuiet         :: Flag Bool,@@ -979,6 +1144,7 @@   outdatedVerbosity     = toFlag normal,   outdatedFreezeFile    = mempty,   outdatedNewFreezeFile = mempty,+  outdatedProjectFile   = mempty,   outdatedSimpleOutput  = mempty,   outdatedExitCode      = mempty,   outdatedQuiet         = mempty,@@ -1000,16 +1166,21 @@     optionVerbosity outdatedVerbosity       (\v flags -> flags { outdatedVerbosity = v }) -    ,option [] ["freeze-file"]+    ,option [] ["freeze-file", "v1-freeze-file"]      "Act on the freeze file"      outdatedFreezeFile (\v flags -> flags { outdatedFreezeFile = v })      trueArg -    ,option [] ["new-freeze-file"]-     "Act on the new-style freeze file"+    ,option [] ["new-freeze-file", "v2-freeze-file"]+     "Act on the new-style freeze file (default: cabal.project.freeze)"      outdatedNewFreezeFile (\v flags -> flags { outdatedNewFreezeFile = v })      trueArg +    ,option [] ["project-file"]+     "Act on the new-style freeze file named PROJECTFILE.freeze rather than the default cabal.project.freeze"+     outdatedProjectFile (\v flags -> flags { outdatedProjectFile = v })+     (reqArgFlag "PROJECTFILE")+     ,option [] ["simple-output"]      "Only print names of outdated dependencies, one per line"      outdatedSimpleOutput (\v flags -> flags { outdatedSimpleOutput = v })@@ -1080,7 +1251,7 @@       relevantConfigValuesText ["remote-repo"                                ,"remote-repo-cache"                                ,"local-repo"],-    commandUsage        = usageFlags "update",+    commandUsage        = usageFlags "v1-update",     commandDefaultFlags = defaultUpdateFlags,     commandOptions      = \_ -> [         optionVerbosity updateVerbosity (\v flags -> flags { updateVerbosity = v }),@@ -1112,16 +1283,11 @@     commandOptions      = commandOptions installCommand   } -{--cleanCommand  :: CommandUI ()-cleanCommand = makeCommand name shortDesc longDesc emptyFlags options-  where-    name       = "clean"-    shortDesc  = "Removes downloaded files"-    longDesc   = Nothing-    emptyFlags = ()-    options _  = []--}+cleanCommand :: CommandUI CleanFlags+cleanCommand = Cabal.cleanCommand+  { commandUsage = \pname ->+    "Usage: " ++ pname ++ " v1-clean [FLAGS]\n"+  }  checkCommand  :: CommandUI (Flag Verbosity) checkCommand = CommandUI {@@ -1134,9 +1300,9 @@       ++ "If no errors and warnings are reported, Hackage will accept this "       ++ "package.\n",     commandNotes        = Nothing,-    commandUsage        = \pname -> "Usage: " ++ pname ++ " check\n",+    commandUsage        = usageFlags "check",     commandDefaultFlags = toFlag normal,-    commandOptions      = \_ -> []+    commandOptions      = \_ -> [optionVerbosity id const]   }  formatCommand  :: CommandUI (Flag Verbosity)@@ -1182,15 +1348,15 @@       ++ "specified, but the package contains just one executable, that one "       ++ "is built and executed.\n"       ++ "\n"-      ++ "Use `" ++ pname ++ " test --show-details=streaming` to run a "+      ++ "Use `" ++ pname ++ " v1-test --show-details=streaming` to run a "       ++ "test-suite and get its full output.\n",     commandNotes        = Just $ \pname ->           "Examples:\n"-       ++ "  " ++ pname ++ " run\n"+       ++ "  " ++ pname ++ " v1-run\n"        ++ "    Run the only executable in the current package;\n"-       ++ "  " ++ pname ++ " run foo -- --fooflag\n"+       ++ "  " ++ pname ++ " v1-run foo -- --fooflag\n"        ++ "    Works similar to `./foo --fooflag`.\n",-    commandUsage        = usageAlternatives "run"+    commandUsage        = usageAlternatives "v1-run"         ["[FLAGS] [EXECUTABLE] [-- EXECUTABLE_FLAGS]"],     commandDefaultFlags = mempty,     commandOptions      =@@ -1568,7 +1734,7 @@ installCommand = CommandUI {   commandName         = "install",   commandSynopsis     = "Install packages.",-  commandUsage        = usageAlternatives "install" [ "[FLAGS]"+  commandUsage        = usageAlternatives "v1-install" [ "[FLAGS]"                                                     , "[FLAGS] PACKAGES"                                                     ],   commandDescription  = Just $ \_ -> wrapText $@@ -1581,12 +1747,12 @@      ++ " dependencies) (there must be exactly one .cabal file in the current"      ++ " directory).\n"      ++ "\n"-     ++ "When using a sandbox, the flags for `install` only affect the"+     ++ "When using a sandbox, the flags for `v1-install` only affect the"      ++ " current command and have no effect on future commands. (To achieve"-     ++ " that, `configure` must be used.)\n"-     ++ " In contrast, without a sandbox, the flags to `install` are saved and"-     ++ " affect future commands such as `build` and `repl`. See the help for"-     ++ " `configure` for a list of commands being affected.\n"+     ++ " that, `v1-configure` must be used.)\n"+     ++ " In contrast, without a sandbox, the flags to `v1-install` are saved and"+     ++ " affect future commands such as `v1-build` and `v1-repl`. See the help for"+     ++ " `v1-configure` for a list of commands being affected.\n"      ++ "\n"      ++ "Installed executables will by default (and without a sandbox)"      ++ " be put into `~/.cabal/bin/`."@@ -1605,15 +1771,15 @@              Nothing   -> ""         )      ++ "Examples:\n"-     ++ "  " ++ pname ++ " install                 "+     ++ "  " ++ pname ++ " v1-install                 "      ++ "    Package in the current directory\n"-     ++ "  " ++ pname ++ " install foo             "+     ++ "  " ++ pname ++ " v1-install foo             "      ++ "    Package from the hackage server\n"-     ++ "  " ++ pname ++ " install foo-1.0         "+     ++ "  " ++ pname ++ " v1-install foo-1.0         "      ++ "    Specific version of a package\n"-     ++ "  " ++ pname ++ " install 'foo < 2'       "+     ++ "  " ++ pname ++ " v1-install 'foo < 2'       "      ++ "    Constrained package version\n"-     ++ "  " ++ pname ++ " install haddock --bindir=$HOME/hask-bin/ --datadir=$HOME/hask-data/\n"+     ++ "  " ++ pname ++ " v1-install haddock --bindir=$HOME/hask-bin/ --datadir=$HOME/hask-data/\n"      ++ "  " ++ (map (const ' ') pname)                       ++ "                         "      ++ "    Change installation destination\n",@@ -1642,6 +1808,36 @@     get3 (_,_,c,_) = c; set3 c (a,b,_,d) = (a,b,c,d)     get4 (_,_,_,d) = d; set4 d (a,b,c,_) = (a,b,c,d) +haddockCommand :: CommandUI HaddockFlags+haddockCommand = Cabal.haddockCommand+  { commandUsage = usageAlternatives "v1-haddock" $+      [ "[FLAGS]", "COMPONENTS [FLAGS]" ]+  }++filterHaddockArgs :: [String] -> Version -> [String]+filterHaddockArgs args cabalLibVersion+  | cabalLibVersion >= mkVersion [2,3,0] = args_latest+  | cabalLibVersion < mkVersion [2,3,0] = args_2_3_0+  | otherwise = args_latest+  where+    args_latest = args++    -- Cabal < 2.3 doesn't know about per-component haddock+    args_2_3_0 = []++filterHaddockFlags :: HaddockFlags -> Version -> HaddockFlags+filterHaddockFlags flags cabalLibVersion+  | cabalLibVersion >= mkVersion [2,3,0] = flags_latest+  | cabalLibVersion < mkVersion [2,3,0] = flags_2_3_0+  | otherwise = flags_latest+  where+    flags_latest = flags++    flags_2_3_0 = flags_latest {+      -- Cabal < 2.3 doesn't know about per-component haddock+      haddockArgs = []+      }+ haddockOptions :: ShowOrParseArgs -> [OptionField HaddockFlags] haddockOptions showOrParseArgs   = [ opt { optionName = "haddock-" ++ name,@@ -1651,7 +1847,7 @@     , let name = optionName opt     , name `elem` ["hoogle", "html", "html-location"                   ,"executables", "tests", "benchmarks", "all", "internal", "css"-                  ,"hyperlink-source", "hscolour-css"+                  ,"hyperlink-source", "quickjump", "hscolour-css"                   ,"contents-location", "for-hackage"]     ]   where@@ -1956,7 +2152,7 @@         IT.overwrite (\v flags -> flags { IT.overwrite = v })         trueArg -      , option [] ["package-dir"]+      , option [] ["package-dir", "packagedir"]         "Root directory of the package (default = current directory)."         IT.packageDir (\v flags -> flags { IT.packageDir = v })         (reqArgFlag "DIRECTORY")@@ -2075,7 +2271,7 @@                                       ((Just . (:[])) `fmap` parse))                           (maybe [] (fmap display))) -      , option [] ["source-dir"]+      , option [] ["source-dir", "sourcedir"]         "Directory containing package source."         IT.sourceDirs (\v flags -> flags { IT.sourceDirs = v })         (reqArg' "DIR" (Just . (:[]))@@ -2112,6 +2308,8 @@  sdistCommand :: CommandUI (SDistFlags, SDistExFlags) sdistCommand = Cabal.sdistCommand {+    commandUsage        = \pname ->+        "Usage: " ++ pname ++ " v1-sdist [FLAGS]\n",     commandDefaultFlags = (commandDefaultFlags Cabal.sdistCommand, defaultSDistExFlags),     commandOptions      = \showOrParseArgs ->          liftOptions fst setFst (commandOptions Cabal.sdistCommand showOrParseArgs)@@ -2139,6 +2337,30 @@ instance Semigroup SDistExFlags where   (<>) = gmappend +--++doctestCommand :: CommandUI DoctestFlags+doctestCommand = Cabal.doctestCommand+  { commandUsage = \pname ->  "Usage: " ++ pname ++ " v1-doctest [FLAGS]\n" }++copyCommand :: CommandUI CopyFlags+copyCommand = Cabal.copyCommand+ { commandNotes = Just $ \pname ->+    "Examples:\n"+     ++ "  " ++ pname ++ " v1-copy           "+     ++ "    All the components in the package\n"+     ++ "  " ++ pname ++ " v1-copy foo       "+     ++ "    A component (i.e. lib, exe, test suite)"+  , commandUsage = usageAlternatives "v1-copy" $+    [ "[FLAGS]"+    , "COMPONENTS [FLAGS]"+    ]+ }++registerCommand :: CommandUI RegisterFlags+registerCommand = Cabal.registerCommand+ { commandUsage = \pname ->  "Usage: " ++ pname ++ " v1-register [FLAGS]\n" }+ -- ------------------------------------------------------------ -- * Win32SelfUpgrade flags -- ------------------------------------------------------------@@ -2244,11 +2466,11 @@       ++ " packages are installed in the same database (i.e. the user's"       ++ " database in the home directory)."     , paragraph $ "A sandbox in the current directory (created by"-      ++ " `sandbox init`) will be used instead of the user's database for"-      ++ " commands such as `install` and `build`. Note that (a directly"+      ++ " `v1-sandbox init`) will be used instead of the user's database for"+      ++ " commands such as `v1-install` and `v1-build`. Note that (a directly"       ++ " invoked) GHC will not automatically be aware of sandboxes;"       ++ " only if called via appropriate " ++ pname-      ++ " commands, e.g. `repl`, `build`, `exec`."+      ++ " commands, e.g. `v1-repl`, `v1-build`, `v1-exec`."     , paragraph $ "Currently, " ++ pname ++ " will not search for a sandbox"       ++ " in folders above the current one, so cabal will not see the sandbox"       ++ " if you are in a subfolder of a sandbox."@@ -2274,16 +2496,16 @@     , indentParagraph $ "Remove an add-source dependency; however, this will"       ++ " not delete the package(s) that have been installed in the sandbox"       ++ " from this dependency. You can either unregister the package(s) via"-      ++ " `" ++ pname ++ " sandbox hc-pkg unregister` or re-create the"-      ++ " sandbox (`sandbox delete; sandbox init`)."+      ++ " `" ++ pname ++ " v1-sandbox hc-pkg unregister` or re-create the"+      ++ " sandbox (`v1-sandbox delete; v1-sandbox init`)."     , headLine "list-sources:"     , indentParagraph $ "List the directories of local packages made"-      ++ " available via `" ++ pname ++ " add-source`."+      ++ " available via `" ++ pname ++ " v1-sandbox add-source`."     , headLine "hc-pkg:"     , indentParagraph $ "Similar to `ghc-pkg`, but for the sandbox package"       ++ " database. Can be used to list specific/all packages that are"       ++ " installed in the sandbox. For subcommands, see the help for"-      ++ " ghc-pkg. Affected by the compiler version specified by `configure`."+      ++ " ghc-pkg. Affected by the compiler version specified by `v1-configure`."     ],   commandNotes        = Just $ \pname ->        relevantConfigValuesText ["require-sandbox"@@ -2291,18 +2513,18 @@     ++ "\n"     ++ "Examples:\n"     ++ "  Set up a sandbox with one local dependency, located at ../foo:\n"-    ++ "    " ++ pname ++ " sandbox init\n"-    ++ "    " ++ pname ++ " sandbox add-source ../foo\n"-    ++ "    " ++ pname ++ " install --only-dependencies\n"+    ++ "    " ++ pname ++ " v1-sandbox init\n"+    ++ "    " ++ pname ++ " v1-sandbox add-source ../foo\n"+    ++ "    " ++ pname ++ " v1-install --only-dependencies\n"     ++ "  Reset the sandbox:\n"-    ++ "    " ++ pname ++ " sandbox delete\n"-    ++ "    " ++ pname ++ " sandbox init\n"-    ++ "    " ++ pname ++ " install --only-dependencies\n"+    ++ "    " ++ pname ++ " v1-sandbox delete\n"+    ++ "    " ++ pname ++ " v1-sandbox init\n"+    ++ "    " ++ pname ++ " v1-install --only-dependencies\n"     ++ "  List the packages in the sandbox:\n"-    ++ "    " ++ pname ++ " sandbox hc-pkg list\n"+    ++ "    " ++ pname ++ " v1-sandbox hc-pkg list\n"     ++ "  Unregister the `broken` package from the sandbox:\n"-    ++ "    " ++ pname ++ " sandbox hc-pkg -- --force unregister broken\n",-  commandUsage        = usageAlternatives "sandbox"+    ++ "    " ++ pname ++ " v1-sandbox hc-pkg -- --force unregister broken\n",+  commandUsage        = usageAlternatives "v1-sandbox"     [ "init          [FLAGS]"     , "delete        [FLAGS]"     , "add-source    [FLAGS] PATHS"@@ -2358,7 +2580,7 @@        -- TODO: this is too GHC-focused for my liking..        "A directly invoked GHC will not automatically be aware of any"     ++ " sandboxes: the GHC_PACKAGE_PATH environment variable controls what"-    ++ " GHC uses. `" ++ pname ++ " exec` can be used to modify this variable:"+    ++ " GHC uses. `" ++ pname ++ " v1-exec` can be used to modify this variable:"     ++ " COMMAND will be executed in a modified environment and thereby uses"     ++ " the sandbox package database.\n"     ++ "\n"@@ -2366,26 +2588,26 @@     ++ "\n"     ++ "Note that other " ++ pname ++ " commands change the environment"     ++ " variable appropriately already, so there is no need to wrap those"-    ++ " in `" ++ pname ++ " exec`. But with `" ++ pname ++ " exec`, the user"+    ++ " in `" ++ pname ++ " v1-exec`. But with `" ++ pname ++ " v1-exec`, the user"     ++ " has more control and can, for example, execute custom scripts which"     ++ " indirectly execute GHC.\n"     ++ "\n"-    ++ "Note that `" ++ pname ++ " repl` is different from `" ++ pname-    ++ " exec -- ghci` as the latter will not forward any additional flags"+    ++ "Note that `" ++ pname ++ " v1-repl` is different from `" ++ pname+    ++ " v1-exec -- ghci` as the latter will not forward any additional flags"     ++ " being defined in the local package to ghci.\n"     ++ "\n"     ++ "See `" ++ pname ++ " sandbox`.\n",   commandNotes        = Just $ \pname ->        "Examples:\n"-    ++ "  " ++ pname ++ " exec -- ghci -Wall\n"+    ++ "  " ++ pname ++ " v1-exec -- ghci -Wall\n"     ++ "    Start a repl session with sandbox packages and all warnings;\n"-    ++ "  " ++ pname ++ " exec gitit -- -f gitit.cnf\n"+    ++ "  " ++ pname ++ " v1-exec gitit -- -f gitit.cnf\n"     ++ "    Give gitit access to the sandbox packages, and pass it a flag;\n"-    ++ "  " ++ pname ++ " exec runghc Foo.hs\n"+    ++ "  " ++ pname ++ " v1-exec runghc Foo.hs\n"     ++ "    Execute runghc on Foo.hs with runghc configured to use the\n"     ++ "    sandbox package database (if a sandbox is being used).\n",   commandUsage        = \pname ->-       "Usage: " ++ pname ++ " exec [FLAGS] [--] COMMAND [--] [ARGS]\n",+       "Usage: " ++ pname ++ " v1-exec [FLAGS] [--] COMMAND [--] [ARGS]\n",    commandDefaultFlags = defaultExecFlags,   commandOptions      = \showOrParseArgs ->
Distribution/Client/SetupWrapper.hs view
@@ -33,7 +33,8 @@          , withinRange ) import qualified Distribution.Backpack as Backpack import Distribution.Package-         ( newSimpleUnitId, unsafeMkDefUnitId, ComponentId, PackageId, mkPackageName+         ( newSimpleUnitId, unsafeMkDefUnitId, ComponentId+         , PackageId, mkPackageName          , PackageIdentifier(..), packageVersion, packageName ) import Distribution.Types.Dependency import Distribution.PackageDescription@@ -57,7 +58,8 @@          , getProgramSearchPath, getDbProgramOutput, runDbProgram, ghcProgram          , ghcjsProgram ) import Distribution.Simple.Program.Find-         ( programSearchPathAsPATHVar, ProgramSearchPathEntry(ProgramSearchPathDir) )+         ( programSearchPathAsPATHVar+         , ProgramSearchPathEntry(ProgramSearchPathDir) ) import Distribution.Simple.Program.Run          ( getEffectiveEnvironment ) import qualified Distribution.Simple.Program.Strip as Strip@@ -73,7 +75,7 @@ import qualified Distribution.InstalledPackageInfo as IPI import Distribution.Client.Types import Distribution.Client.Config-         ( defaultCabalDir )+         ( getCabalDir ) import Distribution.Client.IndexUtils          ( getInstalledPackages ) import Distribution.Client.JobControl@@ -81,7 +83,8 @@ import Distribution.Simple.Setup          ( Flag(..) ) import Distribution.Simple.Utils-         ( die', debug, info, infoNoWrap, cabalVersion, tryFindPackageDesc, comparing+         ( die', debug, info, infoNoWrap+         , cabalVersion, tryFindPackageDesc, comparing          , createDirectoryIfMissingVerbose, installExecutableFile          , copyFileVerbose, rewriteFileEx ) import Distribution.Client.Utils@@ -389,7 +392,7 @@ runSetupCommand :: Verbosity -> Setup                 -> CommandUI flags  -- ^ command definition                 -> flags  -- ^ command flags-                -> [String]  -- ^ extra command-line arguments+                -> [String] -- ^ extra command-line arguments                 -> IO () runSetupCommand verbosity setup cmd flags extraArgs = do   let args = commandName cmd : commandShowOptions cmd flags ++ extraArgs@@ -403,11 +406,13 @@              -> CommandUI flags              -> (Version -> flags)                 -- ^ produce command flags given the Cabal library version-             -> [String]+             -> (Version -> [String])              -> IO () setupWrapper verbosity options mpkg cmd flags extraArgs = do   setup <- getSetup verbosity options mpkg-  runSetupCommand verbosity setup cmd (flags $ setupVersion setup) extraArgs+  runSetupCommand verbosity setup+                  cmd (flags $ setupVersion setup)+                      (extraArgs $ setupVersion setup)  -- ------------------------------------------------------------ -- * Internal SetupMethod@@ -537,7 +542,7 @@                   doInvoke      moveOutOfTheWay tmpDir path' = do-      let newPath = tmpDir </> "setup" <.> exeExtension+      let newPath = tmpDir </> "setup" <.> exeExtension buildPlatform       Win32.moveFile path' newPath       return newPath @@ -589,7 +594,7 @@   setupDir         = workingDir options </> useDistPref options </> "setup"   setupVersionFile = setupDir   </> "setup" <.> "version"   setupHs          = setupDir   </> "setup" <.> "hs"-  setupProgFile    = setupDir   </> "setup" <.> exeExtension+  setupProgFile    = setupDir   </> "setup" <.> exeExtension buildPlatform   platform         = fromMaybe buildPlatform (usePlatform options)    useCachedSetupExecutable = (bt == Simple || bt == Configure || bt == Make)@@ -634,8 +639,8 @@             case savedVer of               Just version | version `withinRange` useCabalVersion options                 -> do updateSetupScript version bt-                      -- Does the previously compiled setup executable still exist-                      -- and is it up-to date?+                      -- Does the previously compiled setup executable+                      -- still exist and is it up-to date?                       useExisting <- canUseExistingSetup version                       if useExisting                         then return (version, Nothing, options)@@ -664,7 +669,8 @@                              ,SetupScriptOptions)       installedVersion = do         (comp,    progdb,  options')  <- configureCompiler options-        (version, mipkgid, options'') <- installedCabalVersion options' comp progdb+        (version, mipkgid, options'') <- installedCabalVersion options'+                                         comp progdb         updateSetupScript version bt         writeSetupVersionFile version         return (version, mipkgid, options'')@@ -713,7 +719,8 @@     return (packageVersion pkg, Nothing, options')   installedCabalVersion options' compiler progdb = do     index <- maybeGetInstalledPackages options' compiler progdb-    let cabalDep   = Dependency (mkPackageName "Cabal") (useCabalVersion options')+    let cabalDep   = Dependency (mkPackageName "Cabal")+                                (useCabalVersion options')         options''  = options' { usePackageIndex = Just index }     case PackageIndex.lookupDependency index cabalDep of       []   -> die' verbosity $ "The package '" ++ display (packageName pkg)@@ -775,14 +782,14 @@   cachedSetupDirAndProg :: SetupScriptOptions -> Version                         -> IO (FilePath, FilePath)   cachedSetupDirAndProg options' cabalLibVersion = do-    cabalDir <- defaultCabalDir+    cabalDir <- getCabalDir     let setupCacheDir       = cabalDir </> "setup-exe-cache"         cachedSetupProgFile = setupCacheDir                               </> ("setup-" ++ buildTypeString ++ "-"                                    ++ cabalVersionString ++ "-"                                    ++ platformString ++ "-"                                    ++ compilerVersionString)-                              <.> exeExtension+                              <.> exeExtension buildPlatform     return (setupCacheDir, cachedSetupProgFile)       where         buildTypeString       = show bt@@ -823,7 +830,7 @@               cachedSetupProgFile     return cachedSetupProgFile       where-        criticalSection'      = maybe id criticalSection $ setupCacheLock options'+        criticalSection' = maybe id criticalSection $ setupCacheLock options'    -- | If the Setup.hs is out of date wrt the executable then recompile it.   -- Currently this is GHC/GHCJS only. It should really be generalised.@@ -860,16 +867,19 @@           selectedDeps | useDependenciesExclusive options'                                    = useDependencies options'                        | otherwise = useDependencies options' ++-                                     if any (isCabalPkgId . snd) (useDependencies options')+                                     if any (isCabalPkgId . snd)+                                        (useDependencies options')                                      then []                                      else cabalDep           addRenaming (ipid, _) =             -- Assert 'DefUnitId' invariant-            (Backpack.DefiniteUnitId (unsafeMkDefUnitId (newSimpleUnitId ipid)), defaultRenaming)+            (Backpack.DefiniteUnitId (unsafeMkDefUnitId (newSimpleUnitId ipid))+            ,defaultRenaming)           cppMacrosFile = setupDir </> "setup_macros.h"           ghcOptions = mempty {               -- Respect -v0, but don't crank up verbosity on GHC if-              -- Cabal verbosity is requested. For that, use --ghc-option=-v instead!+              -- Cabal verbosity is requested. For that, use+              -- --ghc-option=-v instead!               ghcOptVerbosity       = Flag (min verbosity normal)             , ghcOptMode            = Flag GhcModeMake             , ghcOptInputFiles      = toNubListR [setupHs]@@ -886,7 +896,7 @@             , ghcOptPackages        = toNubListR $ map addRenaming selectedDeps             , ghcOptCppIncludes     = toNubListR [ cppMacrosFile                                                  | useVersionMacros options' ]-            , ghcOptExtra           = toNubListR extraOpts+            , ghcOptExtra           = extraOpts             }       let ghcCmdLine = renderGhcOptions compiler platform ghcOptions       when (useVersionMacros options') $@@ -895,7 +905,8 @@       case useLoggingHandle options of         Nothing          -> runDbProgram verbosity program progdb ghcCmdLine -        -- If build logging is enabled, redirect compiler output to the log file.+        -- If build logging is enabled, redirect compiler output to+        -- the log file.         (Just logHandle) -> do output <- getDbProgramOutput verbosity program                                          progdb ghcCmdLine                                hPutStr logHandle output
Distribution/Client/SrcDist.hs view
@@ -69,7 +69,7 @@     -- Run 'setup sdist --output-directory=tmpDir' (or     -- '--list-source'/'--output-directory=someOtherDir') in case we were passed     -- those options.-    setupWrapper verbosity setupOpts (Just pkg) sdistCommand (const flags') []+    setupWrapper verbosity setupOpts (Just pkg) sdistCommand (const flags') (const [])      -- Unless we were given --list-sources or --output-directory ourselves,     -- create an archive.@@ -176,7 +176,7 @@        doListSources :: IO [FilePath]       doListSources = do-        setupWrapper verbosity setupOpts (Just pkg) sdistCommand (const flags) []+        setupWrapper verbosity setupOpts (Just pkg) sdistCommand (const flags) (const [])         fmap lines . readFile $ file        onFailedListSources :: IOException -> IO ()
Distribution/Client/TargetSelector.hs view
@@ -27,7 +27,7 @@     TargetSelectorProblem(..),     reportTargetSelectorProblems,     showTargetSelector,-    TargetString,+    TargetString(..),     showTargetString,     parseTargetString,     -- ** non-IO@@ -84,7 +84,8 @@ import qualified Data.Map.Strict as Map import qualified Data.Set as Set import Control.Arrow ((&&&))-import Control.Monad+import Control.Monad +  hiding ( mfilter ) import qualified Distribution.Compat.ReadP as Parse import Distribution.Compat.ReadP          ( (+++), (<++) )@@ -201,20 +202,27 @@ -- the available packages (and their locations). -- readTargetSelectors :: [PackageSpecifier (SourcePackage (PackageLocation a))]+                    -> Maybe ComponentKindFilter+                    -- ^ This parameter is used when there are ambiguous selectors.+                    --   If it is 'Just', then we attempt to resolve ambiguitiy+                    --   by applying it, since otherwise there is no way to allow+                    --   contextually valid yet syntactically ambiguous selectors.+                    --   (#4676, #5461)                     -> [String]                     -> IO (Either [TargetSelectorProblem] [TargetSelector]) readTargetSelectors = readTargetSelectorsWith defaultDirActions  readTargetSelectorsWith :: (Applicative m, Monad m) => DirActions m                         -> [PackageSpecifier (SourcePackage (PackageLocation a))]+                        -> Maybe ComponentKindFilter                         -> [String]                         -> m (Either [TargetSelectorProblem] [TargetSelector])-readTargetSelectorsWith dirActions@DirActions{..} pkgs targetStrs =+readTargetSelectorsWith dirActions@DirActions{..} pkgs mfilter targetStrs =     case parseTargetStrings targetStrs of       ([], usertargets) -> do         usertargets' <- mapM (getTargetStringFileStatus dirActions) usertargets         knowntargets <- getKnownTargets dirActions pkgs-        case resolveTargetSelectors knowntargets usertargets' of+        case resolveTargetSelectors knowntargets usertargets' mfilter of           ([], btargets) -> return (Right btargets)           (problems, _)  -> return (Left problems)       (strs, _)          -> return (Left (map TargetSelectorUnrecognised strs))@@ -435,29 +443,31 @@ -- resolveTargetSelectors :: KnownTargets                        -> [TargetStringFileStatus]+                       -> Maybe ComponentKindFilter                        -> ([TargetSelectorProblem],                            [TargetSelector]) -- default local dir target if there's no given target:-resolveTargetSelectors (KnownTargets{knownPackagesAll = []}) [] =+resolveTargetSelectors (KnownTargets{knownPackagesAll = []}) [] _ =     ([TargetSelectorNoTargetsInProject], []) -resolveTargetSelectors (KnownTargets{knownPackagesPrimary = []}) [] =+resolveTargetSelectors (KnownTargets{knownPackagesPrimary = []}) [] _ =     ([TargetSelectorNoTargetsInCwd], []) -resolveTargetSelectors (KnownTargets{knownPackagesPrimary}) [] =+resolveTargetSelectors (KnownTargets{knownPackagesPrimary}) [] _ =     ([], [TargetPackage TargetImplicitCwd pkgids Nothing])   where     pkgids = [ pinfoId | KnownPackage{pinfoId} <- knownPackagesPrimary ] -resolveTargetSelectors knowntargets targetStrs =+resolveTargetSelectors knowntargets targetStrs mfilter =     partitionEithers-  . map (resolveTargetSelector knowntargets)+  . map (resolveTargetSelector knowntargets mfilter)   $ targetStrs  resolveTargetSelector :: KnownTargets+                      -> Maybe ComponentKindFilter                       -> TargetStringFileStatus                       -> Either TargetSelectorProblem TargetSelector-resolveTargetSelector knowntargets@KnownTargets{..} targetStrStatus =+resolveTargetSelector knowntargets@KnownTargets{..} mfilter targetStrStatus =     case findMatch (matcher targetStrStatus) of        Unambiguous _@@ -472,6 +482,10 @@         | projectIsEmpty       -> Left TargetSelectorNoTargetsInProject         | otherwise            -> Left (classifyMatchErrors errs) +      Ambiguous _          targets+        | Just kfilter <- mfilter+        , [target] <- applyKindFilter kfilter targets -> Right target+       Ambiguous exactMatch targets ->         case disambiguateTargetSelectors                matcher targetStrStatus exactMatch@@ -531,6 +545,21 @@                      = innerErr (Just (kind,thing)) m         innerErr c m = (c,m) +    applyKindFilter :: ComponentKindFilter -> [TargetSelector] -> [TargetSelector]+    applyKindFilter kfilter = filter go+      where+        go (TargetPackage      _ _ (Just filter')) = kfilter == filter'+        go (TargetPackageNamed _   (Just filter')) = kfilter == filter'+        go (TargetAllPackages      (Just filter')) = kfilter == filter'+        go (TargetComponent _ cname _)+          | CLibName      <- cname                 = kfilter == LibKind+          | CSubLibName _ <- cname                 = kfilter == LibKind+          | CFLibName   _ <- cname                 = kfilter == FLibKind+          | CExeName    _ <- cname                 = kfilter == ExeKind+          | CTestName   _ <- cname                 = kfilter == TestKind+          | CBenchName  _ <- cname                 = kfilter == BenchKind+        go _                                       = True+ -- | The various ways that trying to resolve a 'TargetString' to a -- 'TargetSelector' can fail. --@@ -611,8 +640,9 @@             Left  ( originalMatch                   , [ (forgetFileStatus rendering, matches)                     | rendering <- matchRenderings-                    , let (Match m _ matches) | m /= Inexact =+                    , let Match m _ matches =                             memoisedMatches Map.! rendering+                    , m /= Inexact                     ] )        | (originalMatch, matchRenderings) <- matchResultsRenderings ]
Distribution/Client/Targets.hs view
@@ -455,6 +455,14 @@         error "TODO: readPackageTarget RepoTarballPackage"         -- For repo tarballs this info should be obtained from the index. +      RemoteSourceRepoPackage _srcRepo _ ->+        error "TODO: readPackageTarget RemoteSourceRepoPackage"+        -- This can't happen, because it would have errored out already+        -- in fetchPackage, via fetchPackageTarget before it gets to this+        -- function.+        --+        -- When that is corrected, this will also need to be fixed.+     readTarballPackageTarget location tarballFile tarballOriginalLoc = do       (filename, content) <- extractTarballPackageCabalFile                                tarballFile tarballOriginalLoc
Distribution/Client/Types.hs view
@@ -46,6 +46,8 @@          ( PackageName, mkPackageName ) import Distribution.Types.ComponentName          ( ComponentName(..) )+import Distribution.Types.SourceRepo+         ( SourceRepo )  import Distribution.Solver.Types.PackageIndex          ( PackageIndex )@@ -234,7 +236,7 @@      -- | A fully specified source package.      --    | SpecificSourcePackage pkg-  deriving (Eq, Show, Generic)+  deriving (Eq, Show, Functor, Generic)  instance Binary pkg => Binary (PackageSpecifier pkg) @@ -282,9 +284,8 @@     -- locally cached copy. ie a package available from hackage   | RepoTarballPackage Repo PackageId local ---TODO:---  * add support for darcs and other SCM style remote repos with a local cache---  | ScmPackage+    -- | A package available from a version control system source repository+  | RemoteSourceRepoPackage SourceRepo local   deriving (Show, Functor, Eq, Ord, Generic, Typeable)  instance Binary local => Binary (PackageLocation local)
Distribution/Client/Upload.hs view
@@ -172,7 +172,7 @@       repos       = repoContextRepos repoCtxt       remoteRepos = mapMaybe maybeRepoRemote repos   forM_ remoteRepos $ \remoteRepo ->-      do dotCabal <- defaultCabalDir+      do dotCabal <- getCabalDir          let srcDir = dotCabal </> "reports" </> remoteRepoName remoteRepo          -- We don't want to bomb out just because we haven't built any packages          -- from this repo yet.
Distribution/Client/Utils.hs view
@@ -17,7 +17,9 @@                                  , moreRecentFile, existsAndIsMoreRecentThan                                  , tryFindAddSourcePackageDesc                                  , tryFindPackageDesc-                                 , relaxEncodingErrors)+                                 , relaxEncodingErrors+                                 , ProgressPhase (..)+                                 , progressMessage)        where  import Prelude ()@@ -28,7 +30,7 @@ import Distribution.Compat.Time ( getModTime ) import Distribution.Simple.Setup       ( Flag(..) ) import Distribution.Verbosity-import Distribution.Simple.Utils       ( die', findPackageDesc )+import Distribution.Simple.Utils       ( die', findPackageDesc, noticeNoWrap ) import qualified Data.ByteString.Lazy as BS import Data.Bits          ( (.|.), shiftL, shiftR )@@ -45,18 +47,14 @@          , removeFile, setCurrentDirectory ) import System.IO          ( Handle, hClose, openTempFile-#if MIN_VERSION_base(4,4,0)          , hGetEncoding, hSetEncoding-#endif          ) import System.IO.Unsafe ( unsafePerformIO ) -#if MIN_VERSION_base(4,4,0) import GHC.IO.Encoding          ( recover, TextEncoding(TextEncoding) ) import GHC.IO.Encoding.Failure          ( recoverEncode, CodingFailureMode(TransliterateCodingFailure) )-#endif  #if defined(mingw32_HOST_OS) || MIN_VERSION_directory(1,2,3) import qualified System.Directory as Dir@@ -311,14 +309,12 @@ -- set. It's a no-op for versions of `base` less than 4.4. relaxEncodingErrors :: Handle -> IO () relaxEncodingErrors handle = do-#if MIN_VERSION_base(4,4,0)   maybeEncoding <- hGetEncoding handle   case maybeEncoding of     Just (TextEncoding name decoder encoder) | not ("UTF" `isPrefixOf` name) ->       let relax x = x { recover = recoverEncode TransliterateCodingFailure }       in hSetEncoding handle (TextEncoding name decoder (fmap relax encoder))     _ ->-#endif       return ()  -- |Like 'tryFindPackageDesc', but with error specific to add-source deps.@@ -336,3 +332,27 @@     case errOrCabalFile of         Right file -> return file         Left _ -> die' verbosity err++-- | Phase of building a dependency. Represents current status of package+-- dependency processing. See #4040 for details.+data ProgressPhase+    = ProgressDownloading+    | ProgressDownloaded+    | ProgressStarting+    | ProgressBuilding+    | ProgressHaddock+    | ProgressInstalling+    | ProgressCompleted++progressMessage :: Verbosity -> ProgressPhase -> String -> IO ()+progressMessage verbosity phase subject = do+    noticeNoWrap verbosity $ phaseStr ++ subject ++ "\n"+  where+    phaseStr = case phase of+        ProgressDownloading -> "Downloading  "+        ProgressDownloaded  -> "Downloaded   "+        ProgressStarting    -> "Starting     "+        ProgressBuilding    -> "Building     "+        ProgressHaddock     -> "Haddock      "+        ProgressInstalling  -> "Installing   "+        ProgressCompleted   -> "Completed    "
+ Distribution/Client/VCS.hs view
@@ -0,0 +1,518 @@+{-# LANGUAGE NamedFieldPuns, RecordWildCards #-}+module Distribution.Client.VCS (+    -- * VCS driver type+    VCS,+    vcsRepoType,+    vcsProgram,+    -- ** Type re-exports+    SourceRepo,+    RepoType,+    RepoKind,+    Program,+    ConfiguredProgram,++    -- * Selecting amongst source repos+    selectPackageSourceRepo,++    -- * Validating 'SourceRepo's and configuring VCS drivers+    validateSourceRepo,+    validateSourceRepos,+    SourceRepoProblem(..),+    configureVCS,+    configureVCSs,++    -- * Running the VCS driver+    cloneSourceRepo,+    syncSourceRepos,++    -- * The individual VCS drivers+    knownVCSs,+    vcsBzr,+    vcsDarcs,+    vcsGit,+    vcsHg,+    vcsSvn,+  ) where++import Prelude ()+import Distribution.Client.Compat.Prelude++import Distribution.Types.SourceRepo+         ( SourceRepo(..), RepoType(..), RepoKind(..) )+import Distribution.Client.RebuildMonad+         ( Rebuild, monitorFiles, MonitorFilePath, monitorDirectoryExistence )+import Distribution.Verbosity as Verbosity+         ( Verbosity, normal )+import Distribution.Simple.Program+         ( Program(programFindVersion)+         , ConfiguredProgram(programVersion)+         , simpleProgram, findProgramVersion+         , ProgramInvocation(..), programInvocation, runProgramInvocation+         , emptyProgramDb, requireProgram )+import Distribution.Version+         ( mkVersion )++import Control.Monad+         ( mapM_ )+import Control.Monad.Trans+         ( liftIO )+import qualified Data.Char as Char+import qualified Data.Map  as Map+import Data.Ord+         ( comparing )+import Data.Either+         ( partitionEithers )+import System.FilePath+         ( takeDirectory )+import System.Directory+         ( doesDirectoryExist )+++-- | A driver for a version control system, e.g. git, darcs etc.+--+data VCS program = VCS {+       -- | The type of repository this driver is for.+       vcsRepoType  :: RepoType,++       -- | The vcs program itself.+       -- This is used at type 'Program' and 'ConfiguredProgram'.+       vcsProgram   :: program,++       -- | The program invocation(s) to get\/clone a repository into a fresh+       -- local directory.+       vcsCloneRepo :: Verbosity+                    -> ConfiguredProgram+                    -> SourceRepo+                    -> FilePath   -- Source URI+                    -> FilePath   -- Destination directory+                    -> [ProgramInvocation],++       -- | The program invocation(s) to synchronise a whole set of /related/+       -- repositories with corresponding local directories. Also returns the+       -- files that the command depends on, for change monitoring.+       vcsSyncRepos :: Verbosity+                    -> ConfiguredProgram+                    -> [(SourceRepo, FilePath)]+                    -> IO [MonitorFilePath]+     }+++-- ------------------------------------------------------------+-- * Selecting repos and drivers+-- ------------------------------------------------------------++-- | Pick the 'SourceRepo' to use to get the package sources from.+--+-- Note that this does /not/ depend on what 'VCS' drivers we are able to+-- successfully configure. It is based only on the 'SourceRepo's declared+-- in the package, and optionally on a preferred 'RepoKind'.+--+selectPackageSourceRepo :: Maybe RepoKind+                        -> [SourceRepo]+                        -> Maybe SourceRepo+selectPackageSourceRepo preferredRepoKind =+    listToMaybe+    -- Sort repositories by kind, from This to Head to Unknown. Repositories+    -- with equivalent kinds are selected based on the order they appear in+    -- the Cabal description file.+  . sortBy (comparing thisFirst)+    -- If the user has specified the repo kind, filter out the repositories+    -- they're not interested in.+  . filter (\repo -> maybe True (repoKind repo ==) preferredRepoKind)+  where+    thisFirst :: SourceRepo -> Int+    thisFirst r = case repoKind r of+        RepoThis -> 0+        RepoHead -> case repoTag r of+            -- If the type is 'head' but the author specified a tag, they+            -- probably meant to create a 'this' repository but screwed up.+            Just _  -> 0+            Nothing -> 1+        RepoKindUnknown _ -> 2++data SourceRepoProblem = SourceRepoRepoTypeUnspecified+                       | SourceRepoRepoTypeUnsupported RepoType+                       | SourceRepoLocationUnspecified+  deriving Show++-- | Validates that the 'SourceRepo' specifies a location URI and a repository+-- type that is supported by a VCS driver.+--+-- | It also returns the 'VCS' driver we should use to work with it.+--+validateSourceRepo :: SourceRepo+                   -> Either SourceRepoProblem+                             (SourceRepo, String, RepoType, VCS Program)+validateSourceRepo = \repo -> do+    rtype <- repoType repo               ?! SourceRepoRepoTypeUnspecified+    vcs   <- Map.lookup rtype knownVCSs  ?! SourceRepoRepoTypeUnsupported rtype+    uri   <- repoLocation repo           ?! SourceRepoLocationUnspecified+    return (repo, uri, rtype, vcs)+  where+    a ?! e = maybe (Left e) Right a+++-- | As 'validateSourceRepo' but for a bunch of 'SourceRepo's, and return+-- things in a convenient form to pass to 'configureVCSs', or to report+-- problems.+--+validateSourceRepos :: [SourceRepo]+                    -> Either [(SourceRepo, SourceRepoProblem)]+                              [(SourceRepo, String, RepoType, VCS Program)]+validateSourceRepos rs =+    case partitionEithers (map validateSourceRepo' rs) of+      (problems@(_:_), _) -> Left problems+      ([], vcss)          -> Right vcss+  where+    validateSourceRepo' r = either (Left . (,) r) Right+                                   (validateSourceRepo r)+++configureVCS :: Verbosity+             -> VCS Program+             -> IO (VCS ConfiguredProgram)+configureVCS verbosity vcs@VCS{vcsProgram = prog} =+    asVcsConfigured <$> requireProgram verbosity prog emptyProgramDb+  where+    asVcsConfigured (prog', _) = vcs { vcsProgram = prog' }++configureVCSs :: Verbosity+              -> Map RepoType (VCS Program)+              -> IO (Map RepoType (VCS ConfiguredProgram))+configureVCSs verbosity = traverse (configureVCS verbosity)+++-- ------------------------------------------------------------+-- * Running the driver+-- ------------------------------------------------------------++-- | Clone a single source repo into a fresh directory, using a configured VCS.+--+-- This is for making a new copy, not synchronising an existing copy. It will+-- fail if the destination directory already exists.+--+-- Make sure to validate the 'SourceRepo' using 'validateSourceRepo' first.+--+cloneSourceRepo :: Verbosity+                -> VCS ConfiguredProgram+                -> SourceRepo -- ^ Must have 'repoLocation' filled.+                -> FilePath   -- ^ Destination directory+                -> IO ()+cloneSourceRepo _ _ repo@SourceRepo{ repoLocation = Nothing } _ =+    error $ "cloneSourceRepo: precondition violation, missing repoLocation: \""+         ++ show repo ++ "\". Validate using validateSourceRepo first."++cloneSourceRepo verbosity vcs+                repo@SourceRepo{ repoLocation = Just srcuri } destdir =+    mapM_ (runProgramInvocation verbosity) invocations+  where+    invocations = vcsCloneRepo vcs verbosity+                               (vcsProgram vcs) repo+                               srcuri destdir+++-- | Syncronise a set of 'SourceRepo's referring to the same repository with+-- corresponding local directories. The local directories may or may not+-- already exist.+--+-- The 'SourceRepo' values used in a single invocation of 'syncSourceRepos',+-- or used across a series of invocations with any local directory must refer+-- to the /same/ repository. That means it must be the same location but they+-- can differ in the branch, or tag or subdir.+--+-- The reason to allow multiple related 'SourceRepo's is to allow for the+-- network or storage to be shared between different checkouts of the repo.+-- For example if a single repo contains multiple packages in different subdirs+-- and in some project it may make sense to use a different state of the repo+-- for one subdir compared to another.+--+syncSourceRepos :: Verbosity+                -> VCS ConfiguredProgram+                -> [(SourceRepo, FilePath)]+                -> Rebuild ()+syncSourceRepos verbosity vcs repos = do+    files <- liftIO $ vcsSyncRepos vcs verbosity (vcsProgram vcs) repos+    monitorFiles files+++-- ------------------------------------------------------------+-- * The various VCS drivers+-- ------------------------------------------------------------++-- | The set of all supported VCS drivers, organised by 'RepoType'.+--+knownVCSs :: Map RepoType (VCS Program)+knownVCSs = Map.fromList [ (vcsRepoType vcs, vcs) | vcs <- vcss ]+  where+    vcss = [ vcsBzr, vcsDarcs, vcsGit, vcsHg, vcsSvn ]+++-- | VCS driver for Bazaar.+--+vcsBzr :: VCS Program+vcsBzr =+    VCS {+      vcsRepoType = Bazaar,+      vcsProgram  = bzrProgram,+      vcsCloneRepo,+      vcsSyncRepos+    }+  where+    vcsCloneRepo :: Verbosity+                 -> ConfiguredProgram+                 -> SourceRepo+                 -> FilePath+                 -> FilePath+                 -> [ProgramInvocation]+    vcsCloneRepo verbosity prog repo srcuri destdir =+        [ programInvocation prog+            ([branchCmd, srcuri, destdir] ++ tagArgs ++ verboseArg) ]+      where+        -- The @get@ command was deprecated in version 2.4 in favour of+        -- the alias @branch@+        branchCmd | programVersion prog >= Just (mkVersion [2,4])+                              = "branch"+                  | otherwise = "get"++        tagArgs = case repoTag repo of+          Nothing  -> []+          Just tag -> ["-r", "tag:" ++ tag]+        verboseArg = [ "--quiet" | verbosity < Verbosity.normal ]++    vcsSyncRepos :: Verbosity -> ConfiguredProgram+                 -> [(SourceRepo, FilePath)] -> IO [MonitorFilePath]+    vcsSyncRepos _v _p _rs = fail "sync repo not yet supported for bzr"++bzrProgram :: Program+bzrProgram = (simpleProgram "bzr") {+    programFindVersion = findProgramVersion "--version" $ \str ->+      case words str of+        -- "Bazaar (bzr) 2.6.0\n  ... lots of extra stuff"+        (_:_:ver:_) -> ver+        _ -> ""+  }+++-- | VCS driver for Darcs.+--+vcsDarcs :: VCS Program+vcsDarcs =+    VCS {+      vcsRepoType = Darcs,+      vcsProgram  = darcsProgram,+      vcsCloneRepo,+      vcsSyncRepos+    }+  where+    vcsCloneRepo :: Verbosity+                 -> ConfiguredProgram+                 -> SourceRepo+                 -> FilePath+                 -> FilePath+                 -> [ProgramInvocation]+    vcsCloneRepo verbosity prog repo srcuri destdir =+        [ programInvocation prog cloneArgs ]+      where+        cloneArgs  = [cloneCmd, srcuri, destdir] ++ tagArgs ++ verboseArg+        -- At some point the @clone@ command was introduced as an alias for+        -- @get@, and @clone@ seems to be the recommended one now.+        cloneCmd   | programVersion prog >= Just (mkVersion [2,8])+                               = "clone"+                   | otherwise = "get"+        tagArgs    = case repoTag repo of+          Nothing  -> []+          Just tag -> ["-t", tag]+        verboseArg = [ "--quiet" | verbosity < Verbosity.normal ]++    vcsSyncRepos :: Verbosity -> ConfiguredProgram+                 -> [(SourceRepo, FilePath)] -> IO [MonitorFilePath]+    vcsSyncRepos _v _p _rs = fail "sync repo not yet supported for darcs"++darcsProgram :: Program+darcsProgram = (simpleProgram "darcs") {+    programFindVersion = findProgramVersion "--version" $ \str ->+      case words str of+        -- "2.8.5 (release)"+        (ver:_) -> ver+        _ -> ""+  }+++-- | VCS driver for Git.+--+vcsGit :: VCS Program+vcsGit =+    VCS {+      vcsRepoType = Git,+      vcsProgram  = gitProgram,+      vcsCloneRepo,+      vcsSyncRepos+    }+  where+    vcsCloneRepo :: Verbosity+                 -> ConfiguredProgram+                 -> SourceRepo+                 -> FilePath+                 -> FilePath+                 -> [ProgramInvocation]+    vcsCloneRepo verbosity prog repo srcuri destdir =+        [ programInvocation prog cloneArgs ]+        -- And if there's a tag, we have to do that in a second step:+     ++ [ (programInvocation prog (checkoutArgs tag)) {+            progInvokeCwd = Just destdir+          }+        | tag <- maybeToList (repoTag repo) ]+      where+        cloneArgs  = ["clone", srcuri, destdir]+                     ++ branchArgs ++ verboseArg+        branchArgs = case repoBranch repo of+          Just b  -> ["--branch", b]+          Nothing -> []+        checkoutArgs tag = "checkout" : verboseArg ++ [tag, "--"]+        verboseArg = [ "--quiet" | verbosity < Verbosity.normal ]++    vcsSyncRepos :: Verbosity+                 -> ConfiguredProgram+                 -> [(SourceRepo, FilePath)]+                 -> IO [MonitorFilePath]+    vcsSyncRepos _ _ [] = return []+    vcsSyncRepos verbosity gitProg+                 ((primaryRepo, primaryLocalDir) : secondaryRepos) = do++      vcsSyncRepo verbosity gitProg primaryRepo primaryLocalDir Nothing+      sequence_+        [ vcsSyncRepo verbosity gitProg repo localDir (Just primaryLocalDir)+        | (repo, localDir) <- secondaryRepos ]+      return [ monitorDirectoryExistence dir +             | dir <- (primaryLocalDir : map snd secondaryRepos) ]++    vcsSyncRepo verbosity gitProg SourceRepo{..} localDir peer = do+        exists <- doesDirectoryExist localDir+        if exists+          then git localDir                 ["fetch"]+          else git (takeDirectory localDir) cloneArgs+        git localDir checkoutArgs+      where+        git :: FilePath -> [String] -> IO ()+        git cwd args = runProgramInvocation verbosity $+                         (programInvocation gitProg args) {+                           progInvokeCwd = Just cwd+                         }++        cloneArgs      = ["clone", "--no-checkout", loc, localDir]+                      ++ case peer of+                           Nothing           -> []+                           Just peerLocalDir -> ["--reference", peerLocalDir]+                      ++ verboseArg+                         where Just loc = repoLocation+        checkoutArgs   = "checkout" : verboseArg ++ ["--detach", "--force"+                         , checkoutTarget, "--" ]+        checkoutTarget = fromMaybe "HEAD" (repoBranch `mplus` repoTag)+        verboseArg     = [ "--quiet" | verbosity < Verbosity.normal ]++gitProgram :: Program+gitProgram = (simpleProgram "git") {+    programFindVersion = findProgramVersion "--version" $ \str ->+      case words str of+        -- "git version 2.5.5"+        (_:_:ver:_) | all isTypical ver -> ver++        -- or annoyingly "git version 2.17.1.windows.2" yes, really+        (_:_:ver:_) -> intercalate "."+                     . takeWhile (all isNum)+                     . split+                     $ ver+        _ -> ""+  }+  where+    isNum     c = c >= '0' && c <= '9'+    isTypical c = isNum c || c == '.'+    split    cs = case break (=='.') cs of+                    (chunk,[])     -> chunk : []+                    (chunk,_:rest) -> chunk : split rest++-- | VCS driver for Mercurial.+--+vcsHg :: VCS Program+vcsHg =+    VCS {+      vcsRepoType = Mercurial,+      vcsProgram  = hgProgram,+      vcsCloneRepo,+      vcsSyncRepos+    }+  where+    vcsCloneRepo :: Verbosity+                 -> ConfiguredProgram+                 -> SourceRepo+                 -> FilePath+                 -> FilePath+                 -> [ProgramInvocation]+    vcsCloneRepo verbosity prog repo srcuri destdir =+        [ programInvocation prog cloneArgs ]+      where+        cloneArgs  = ["clone", srcuri, destdir]+                     ++ branchArgs ++ tagArgs ++ verboseArg+        branchArgs = case repoBranch repo of+          Just b  -> ["--branch", b]+          Nothing -> []+        tagArgs = case repoTag repo of+          Just t  -> ["--rev", t]+          Nothing -> []+        verboseArg = [ "--quiet" | verbosity < Verbosity.normal ]++    vcsSyncRepos :: Verbosity+                 -> ConfiguredProgram+                 -> [(SourceRepo, FilePath)]+                 -> IO [MonitorFilePath]+    vcsSyncRepos _v _p _rs = fail "sync repo not yet supported for hg"++hgProgram :: Program+hgProgram = (simpleProgram "hg") {+    programFindVersion = findProgramVersion "--version" $ \str ->+      case words str of+        -- Mercurial Distributed SCM (version 3.5.2)\n ... long message+        (_:_:_:_:ver:_) -> takeWhile (\c -> Char.isDigit c || c == '.') ver+        _ -> ""+  }+++-- | VCS driver for Subversion.+--+vcsSvn :: VCS Program+vcsSvn =+    VCS {+      vcsRepoType = SVN,+      vcsProgram  = svnProgram,+      vcsCloneRepo,+      vcsSyncRepos+    }+  where+    vcsCloneRepo :: Verbosity+                 -> ConfiguredProgram+                 -> SourceRepo+                 -> FilePath+                 -> FilePath+                 -> [ProgramInvocation]+    vcsCloneRepo verbosity prog _repo srcuri destdir =+        [ programInvocation prog checkoutArgs ]+      where+        checkoutArgs = ["checkout", srcuri, destdir] ++ verboseArg+        verboseArg   = [ "--quiet" | verbosity < Verbosity.normal ]+        --TODO: branch or tag?++    vcsSyncRepos :: Verbosity+                 -> ConfiguredProgram+                 -> [(SourceRepo, FilePath)]+                 -> IO [MonitorFilePath]+    vcsSyncRepos _v _p _rs = fail "sync repo not yet supported for svn"++svnProgram :: Program+svnProgram = (simpleProgram "svn") {+    programFindVersion = findProgramVersion "--version" $ \str ->+      case words str of+        -- svn, version 1.9.4 (r1740329)\n ... long message+        (_:_:ver:_) -> ver+        _ -> ""+  }+
Distribution/Solver/Modular.hs view
@@ -10,7 +10,7 @@ -- plan.  import Prelude ()-import Distribution.Client.Compat.Prelude+import Distribution.Solver.Compat.Prelude  import qualified Data.Map as M import Data.Set (Set)@@ -48,6 +48,7 @@          ( Platform(..) ) import Distribution.Simple.Utils          ( ordNubBy )+import Distribution.Verbosity   -- | Ties the two worlds together: classic cabal-install vs. the modular@@ -58,7 +59,7 @@   solve' sc cinfo idx pkgConfigDB pprefs gcs pns     where       -- Indices have to be converted into solver-specific uniform index.-      idx    = convPIs os arch cinfo (shadowPkgs sc) (strongFlags sc) (solveExecutables sc) iidx sidx+      idx    = convPIs os arch cinfo gcs (shadowPkgs sc) (strongFlags sc) (solveExecutables sc) iidx sidx       -- Constraints have to be converted into a finite map indexed by PN.       gcs    = M.fromListWith (++) (map pair pcs)         where@@ -115,35 +116,36 @@        -> Set PN        -> Progress String String (Assignment, RevDepMap) solve' sc cinfo idx pkgConfigDB pprefs gcs pns =-    foldProgress Step createErrorMsg Done (runSolver sc)+    foldProgress Step (uncurry createErrorMsg) Done (runSolver printFullLog sc)   where-    runSolver :: SolverConfig-              -> Progress String SolverFailure (Assignment, RevDepMap)-    runSolver sc' =-        logToProgress (solverVerbosity sc') (maxBackjumps sc') $ -- convert log format into progress format+    runSolver :: Bool -> SolverConfig+              -> Progress String (SolverFailure, String) (Assignment, RevDepMap)+    runSolver keepLog sc' =+        logToProgress keepLog (solverVerbosity sc') (maxBackjumps sc') $         solve sc' cinfo idx pkgConfigDB pprefs gcs pns -    createErrorMsg :: SolverFailure+    createErrorMsg :: SolverFailure -> String                    -> Progress String String (Assignment, RevDepMap)-    createErrorMsg (NoSolution cs        msg) =-        Fail $ rerunSolverForErrorMsg cs msg-    createErrorMsg (BackjumpLimitReached msg) =+    createErrorMsg (ExhaustiveSearch cs _) msg =+        Fail $ rerunSolverForErrorMsg cs ++ msg+    createErrorMsg BackjumpLimitReached    msg =         Step ("Backjump limit reached. Rerunning dependency solver to generate "               ++ "a final conflict set for the search tree containing the "               ++ "first backjump.") $-        foldProgress Step f Done $-        runSolver sc { pruneAfterFirstSuccess = PruneAfterFirstSuccess True }+        foldProgress Step (f . fst) Done $+        runSolver printFullLog+                  sc { pruneAfterFirstSuccess = PruneAfterFirstSuccess True }       where         f :: SolverFailure -> Progress String String (Assignment, RevDepMap)-        f (NoSolution cs        _) = Fail $ rerunSolverForErrorMsg cs msg-        f (BackjumpLimitReached _) =+        f (ExhaustiveSearch cs _) = Fail $ rerunSolverForErrorMsg cs ++ msg+        f BackjumpLimitReached    =             -- This case is possible when the number of goals involved in             -- conflicts is greater than the backjump limit.             Fail $ msg ++ "Failed to generate a summarized dependency solver "                        ++ "log due to low backjump limit." -    rerunSolverForErrorMsg :: ConflictSet -> String -> String-    rerunSolverForErrorMsg cs finalMsg =+    rerunSolverForErrorMsg :: ConflictSet -> String+    rerunSolverForErrorMsg cs =       let sc' = sc {                     goalOrder = Just goalOrder'                   , maxBackjumps = Just 0@@ -153,8 +155,9 @@           -- original goal order.           goalOrder' = preferGoalsFromConflictSet cs <> fromMaybe mempty (goalOrder sc) -      in unlines ("Could not resolve dependencies:" : messages (runSolver sc'))-          ++ finalMsg+      in unlines ("Could not resolve dependencies:" : messages (runSolver True sc'))++    printFullLog = solverVerbosity sc >= verbose      messages :: Progress step fail done -> [step]     messages = foldProgress (:) (const []) (const [])
Distribution/Solver/Modular/Builder.hs view
@@ -72,7 +72,7 @@       -- the later addition will have better dependency information.     go g o ((Stanza sn@(SN qpn _) t)           : ngs) =         go g (StanzaGoal sn t (flagGR qpn) : o) ngs-    go g o ((Simple (LDep dr (Dep _ qpn _)) c) : ngs)+    go g o ((Simple (LDep dr (Dep (PkgComponent qpn _) _)) c) : ngs)       | qpn == qpn'       =             -- We currently only add a self-dependency to the graph if it is             -- between a package and its setup script. The edge creates a cycle
Distribution/Solver/Modular/ConflictSet.hs view
@@ -51,7 +51,7 @@ -- kept abstract. data ConflictSet = CS {     -- | The set of variables involved on the conflict-    conflictSetToSet :: Set (Var QPN)+    conflictSetToSet :: !(Set (Var QPN))  #ifdef DEBUG_CONFLICT_SETS     -- | The origin of the conflict set
Distribution/Solver/Modular/Dependency.hs view
@@ -16,6 +16,8 @@   , FlaggedDep(..)   , LDep(..)   , Dep(..)+  , PkgComponent(..)+  , ExposedComponent(..)   , DependencyReason(..)   , showDependencyReason   , flattenFlaggedDeps@@ -37,7 +39,7 @@ import Prelude () import qualified Data.Map as M import qualified Data.Set as S-import Distribution.Client.Compat.Prelude hiding (pi)+import Distribution.Solver.Compat.Prelude hiding (pi)  import Language.Haskell.Extension (Extension(..), Language(..)) @@ -112,12 +114,22 @@ -- | A dependency (constraint) associates a package name with a constrained -- instance. It can also represent other types of dependencies, such as -- dependencies on language extensions.-data Dep qpn = Dep (Maybe UnqualComponentName) qpn CI  -- ^ dependency on a package (possibly for executable)-             | Ext  Extension                          -- ^ dependency on a language extension-             | Lang Language                           -- ^ dependency on a language version-             | Pkg  PkgconfigName VR                   -- ^ dependency on a pkg-config package+data Dep qpn = Dep (PkgComponent qpn) CI  -- ^ dependency on a package component+             | Ext Extension              -- ^ dependency on a language extension+             | Lang Language              -- ^ dependency on a language version+             | Pkg PkgconfigName VR       -- ^ dependency on a pkg-config package   deriving Functor +-- | An exposed component within a package. This type is used to represent+-- build-depends and build-tool-depends dependencies.+data PkgComponent qpn = PkgComponent qpn ExposedComponent+  deriving (Eq, Ord, Functor, Show)++-- | A component that can be depended upon by another package, i.e., a library+-- or an executable.+data ExposedComponent = ExposedLib | ExposedExe UnqualComponentName+  deriving (Eq, Ord, Show)+ -- | The reason that a dependency is active. It identifies the package and any -- flag and stanza choices that introduced the dependency. It contains -- everything needed for creating ConflictSets or describing conflicts in solver@@ -169,7 +181,7 @@     -- Suppose package B has a setup dependency on package A.     -- This will be recorded as something like     ---    -- > LDep (DependencyReason "B") (Dep Nothing "A" (Constrained AnyVersion))+    -- > LDep (DependencyReason "B") (Dep (PkgComponent "A" ExposedLib) (Constrained AnyVersion))     --     -- Observe that when we qualify this dependency, we need to turn that     -- @"A"@ into @"B-setup.A"@, but we should not apply that same qualifier@@ -181,11 +193,12 @@     goD (Ext  ext)    _    = Ext  ext     goD (Lang lang)   _    = Lang lang     goD (Pkg pkn vr)  _    = Pkg pkn vr-    goD (Dep mExe dep ci) comp-      | isJust mExe = Dep mExe (Q (PackagePath ns (QualExe   pn dep)) dep) ci-      | qBase  dep  = Dep mExe (Q (PackagePath ns (QualBase  pn    )) dep) ci-      | qSetup comp = Dep mExe (Q (PackagePath ns (QualSetup pn    )) dep) ci-      | otherwise   = Dep mExe (Q (PackagePath ns inheritedQ        ) dep) ci+    goD (Dep dep@(PkgComponent qpn (ExposedExe _)) ci) _ =+        Dep (Q (PackagePath ns (QualExe pn qpn)) <$> dep) ci+    goD (Dep dep@(PkgComponent qpn ExposedLib) ci) comp+      | qBase qpn   = Dep (Q (PackagePath ns (QualBase  pn)) <$> dep) ci+      | qSetup comp = Dep (Q (PackagePath ns (QualSetup pn)) <$> dep) ci+      | otherwise   = Dep (Q (PackagePath ns inheritedQ    ) <$> dep) ci      -- If P has a setup dependency on Q, and Q has a regular dependency on R, then     -- we say that the 'Setup' qualifier is inherited: P has an (indirect) setup
Distribution/Solver/Modular/Explore.hs view
@@ -5,9 +5,11 @@     , backjumpAndExplore     ) where +import qualified Distribution.Solver.Types.Progress as P+ import Data.Foldable as F import Data.List as L (foldl')-import Data.Map as M+import Data.Map.Strict as M  import Distribution.Solver.Modular.Assignment import Distribution.Solver.Modular.Dependency@@ -43,34 +45,61 @@ -- with the (virtual) option not to choose anything for the current -- variable. See also the comments for 'avoidSet'. ---backjump :: EnableBackjumping -> Var QPN-         -> ConflictSet -> W.WeightedPSQ w k (ConflictMap -> ConflictSetLog a)-         -> ConflictMap -> ConflictSetLog a-backjump (EnableBackjumping enableBj) var lastCS xs =+backjump :: Maybe Int -> EnableBackjumping -> Var QPN+         -> ConflictSet -> W.WeightedPSQ w k (ExploreState -> ConflictSetLog a)+         -> ExploreState -> ConflictSetLog a+backjump mbj (EnableBackjumping enableBj) var lastCS xs =     F.foldr combine avoidGoal xs CS.empty   where-    combine :: forall a . (ConflictMap -> ConflictSetLog a)-            -> (ConflictSet -> ConflictMap -> ConflictSetLog a)-            ->  ConflictSet -> ConflictMap -> ConflictSetLog a-    combine x f csAcc cm = retry (x cm) next+    combine :: forall a . (ExploreState -> ConflictSetLog a)+            -> (ConflictSet -> ExploreState -> ConflictSetLog a)+            ->  ConflictSet -> ExploreState -> ConflictSetLog a+    combine x f csAcc es = retry (x es) next       where-        next :: (ConflictSet, ConflictMap) -> ConflictSetLog a-        next (cs, cm')-          | enableBj && not (var `CS.member` cs) = logBackjump cs cm'-          | otherwise                            = f (csAcc `CS.union` cs) cm'+        next :: IntermediateFailure -> ConflictSetLog a+        next BackjumpLimit = fromProgress (P.Fail BackjumpLimit)+        next (NoSolution !cs es')+          | enableBj && not (var `CS.member` cs) = skipLoggingBackjump cs es'+          | otherwise                            = f (csAcc `CS.union` cs) es'      -- This function represents the option to not choose a value for this goal.-    avoidGoal :: ConflictSet -> ConflictMap -> ConflictSetLog a-    avoidGoal cs !cm = logBackjump (cs `CS.union` lastCS) (updateCM lastCS cm)-                                -- 'lastCS' instead of 'cs' here ---^-                                -- since we do not want to double-count the-                                -- additionally accumulated conflicts.+    avoidGoal :: ConflictSet -> ExploreState -> ConflictSetLog a+    avoidGoal cs !es =+        logBackjump (cs `CS.union` lastCS) $ -    logBackjump :: ConflictSet -> ConflictMap -> ConflictSetLog a-    logBackjump cs cm = failWith (Failure cs Backjump) (cs, cm)+        -- Use 'lastCS' below instead of 'cs' since we do not want to+        -- double-count the additionally accumulated conflicts.+        es { esConflictMap = updateCM lastCS (esConflictMap es) } -type ConflictSetLog = RetryLog Message (ConflictSet, ConflictMap)+    logBackjump :: ConflictSet -> ExploreState -> ConflictSetLog a+    logBackjump cs es =+        failWith (Failure cs Backjump) $+            if reachedBjLimit (esBackjumps es)+            then BackjumpLimit+            else NoSolution cs es { esBackjumps = esBackjumps es + 1 }+      where+        reachedBjLimit = case mbj of+                           Nothing    -> const False+                           Just limit -> (== limit) +    -- The solver does not count or log backjumps at levels where the conflict+    -- set does not contain the current variable. Otherwise, there would be many+    -- consecutive log messages about backjumping with the same conflict set.+    skipLoggingBackjump :: ConflictSet -> ExploreState -> ConflictSetLog a+    skipLoggingBackjump cs es = fromProgress $ P.Fail (NoSolution cs es)++-- | The state that is read and written while exploring the search tree.+data ExploreState = ES {+    esConflictMap :: !ConflictMap+  , esBackjumps   :: !Int+  }++data IntermediateFailure =+    NoSolution ConflictSet ExploreState+  | BackjumpLimit++type ConflictSetLog = RetryLog Message IntermediateFailure+ getBestGoal :: ConflictMap -> P.PSQ (Goal QPN) a -> (Goal QPN, a) getBestGoal cm =   P.maximumBy@@ -86,10 +115,7 @@  updateCM :: ConflictSet -> ConflictMap -> ConflictMap updateCM cs cm =-  L.foldl' (\ cmc k -> M.alter inc k cmc) cm (CS.toList cs)-  where-    inc Nothing  = Just 1-    inc (Just n) = Just $! n + 1+  L.foldl' (\ cmc k -> M.insertWith (+) k 1 cmc) cm (CS.toList cs)  -- | Record complete assignments on 'Done' nodes. assign :: Tree d c -> Tree Assignment c@@ -109,39 +135,46 @@  -- | A tree traversal that simultaneously propagates conflict sets up -- the tree from the leaves and creates a log.-exploreLog :: EnableBackjumping -> CountConflicts -> Tree Assignment QGoalReason+exploreLog :: Maybe Int -> EnableBackjumping -> CountConflicts+           -> Tree Assignment QGoalReason            -> ConflictSetLog (Assignment, RevDepMap)-exploreLog enableBj (CountConflicts countConflicts) t = cata go t M.empty+exploreLog mbj enableBj (CountConflicts countConflicts) t = cata go t initES   where     getBestGoal' :: P.PSQ (Goal QPN) a -> ConflictMap -> (Goal QPN, a)     getBestGoal'       | countConflicts = \ ts cm -> getBestGoal cm ts       | otherwise      = \ ts _  -> getFirstGoal ts -    go :: TreeF Assignment QGoalReason (ConflictMap -> ConflictSetLog (Assignment, RevDepMap))-                                    -> (ConflictMap -> ConflictSetLog (Assignment, RevDepMap))-    go (FailF c fr)                            = \ !cm -> failWith (Failure c fr)-                                                                 (c, updateCM c cm)+    go :: TreeF Assignment QGoalReason (ExploreState -> ConflictSetLog (Assignment, RevDepMap))+                                    -> (ExploreState -> ConflictSetLog (Assignment, RevDepMap))+    go (FailF c fr)                            = \ !es ->+        let es' = es { esConflictMap = updateCM c (esConflictMap es) }+        in failWith (Failure c fr) (NoSolution c es')     go (DoneF rdm a)                           = \ _   -> succeedWith Success (a, rdm)     go (PChoiceF qpn _ gr       ts)            =-      backjump enableBj (P qpn) (avoidSet (P qpn) gr) $ -- try children in order,-        W.mapWithKey                                -- when descending ...-          (\ k r cm -> tryWith (TryP qpn k) (r cm))+      backjump mbj enableBj (P qpn) (avoidSet (P qpn) gr) $ -- try children in order,+        W.mapWithKey                                        -- when descending ...+          (\ k r es -> tryWith (TryP qpn k) (r es))           ts     go (FChoiceF qfn _ gr _ _ _ ts)            =-      backjump enableBj (F qfn) (avoidSet (F qfn) gr) $ -- try children in order,-        W.mapWithKey                                -- when descending ...-          (\ k r cm -> tryWith (TryF qfn k) (r cm))+      backjump mbj enableBj (F qfn) (avoidSet (F qfn) gr) $ -- try children in order,+        W.mapWithKey                                        -- when descending ...+          (\ k r es -> tryWith (TryF qfn k) (r es))           ts     go (SChoiceF qsn _ gr _     ts)            =-      backjump enableBj (S qsn) (avoidSet (S qsn) gr) $ -- try children in order,-        W.mapWithKey                                -- when descending ...-          (\ k r cm -> tryWith (TryS qsn k) (r cm))+      backjump mbj enableBj (S qsn) (avoidSet (S qsn) gr) $ -- try children in order,+        W.mapWithKey                                        -- when descending ...+          (\ k r es -> tryWith (TryS qsn k) (r es))           ts-    go (GoalChoiceF _           ts)            = \ cm ->-      let (k, v) = getBestGoal' ts cm-      in continueWith (Next k) (v cm)+    go (GoalChoiceF _           ts)            = \ es ->+      let (k, v) = getBestGoal' ts (esConflictMap es)+      in continueWith (Next k) (v es) +    initES = ES {+        esConflictMap = M.empty+      , esBackjumps = 0+      }+ -- | Build a conflict set corresponding to the (virtual) option not to -- choose a solution for a goal at all. --@@ -171,8 +204,17 @@   CS.union (CS.singleton var) (goalReasonToCS gr)  -- | Interface.-backjumpAndExplore :: EnableBackjumping+--+-- Takes as an argument a limit on allowed backjumps. If the limit is 'Nothing',+-- then infinitely many backjumps are allowed. If the limit is 'Just 0',+-- backtracking is completely disabled.+backjumpAndExplore :: Maybe Int+                   -> EnableBackjumping                    -> CountConflicts-                   -> Tree d QGoalReason -> Log Message (Assignment, RevDepMap)-backjumpAndExplore enableBj countConflicts =-    toProgress . exploreLog enableBj countConflicts . assign+                   -> Tree d QGoalReason+                   -> RetryLog Message SolverFailure (Assignment, RevDepMap)+backjumpAndExplore mbj enableBj countConflicts =+    mapFailure convertFailure . exploreLog mbj enableBj countConflicts . assign+  where+    convertFailure (NoSolution cs es) = ExhaustiveSearch cs (esConflictMap es)+    convertFailure BackjumpLimit      = BackjumpLimitReached
Distribution/Solver/Modular/Index.hs view
@@ -1,6 +1,7 @@ module Distribution.Solver.Modular.Index     ( Index     , PInfo(..)+    , IsBuildable(..)     , defaultQualifyOptions     , mkIndex     ) where@@ -13,7 +14,6 @@ import Distribution.Solver.Modular.Flag import Distribution.Solver.Modular.Package import Distribution.Solver.Modular.Tree-import Distribution.Types.UnqualComponentName  -- | An index contains information about package instances. This is a nested -- dictionary. Package names are mapped to instances, which in turn is mapped@@ -21,13 +21,18 @@ type Index = Map PN (Map I PInfo)  -- | Info associated with a package instance.--- Currently, dependencies, executable names, flags and failure reasons.+-- Currently, dependencies, component names, flags and failure reasons.+-- The component map records whether any components are unbuildable in the+-- current environment (compiler, os, arch, and global flag constraints). -- Packages that have a failure reason recorded for them are disabled -- globally, for reasons external to the solver. We currently use this -- for shadowing which essentially is a GHC limitation, and for -- installed packages that are broken.-data PInfo = PInfo (FlaggedDeps PN) [UnqualComponentName] FlagInfo (Maybe FailReason)+data PInfo = PInfo (FlaggedDeps PN) (Map ExposedComponent IsBuildable) FlagInfo (Maybe FailReason) +-- | Whether a component is made unbuildable by a "buildable: False" field.+newtype IsBuildable = IsBuildable Bool+ mkIndex :: [(PN, I, PInfo)] -> Index mkIndex xs = M.map M.fromList (groupMap (L.map (\ (pn, i, pi) -> (pn, (i, pi))) xs)) @@ -40,9 +45,9 @@                               | -- Find all versions of base ..                                 Just is <- [M.lookup base idx]                                 -- .. which are installed ..-                              , (I _ver (Inst _), PInfo deps _exes _flagNfo _fr) <- M.toList is+                              , (I _ver (Inst _), PInfo deps _comps _flagNfo _fr) <- M.toList is                                 -- .. and flatten all their dependencies ..-                              , (LDep _ (Dep _is_exe dep _ci), _comp) <- flattenFlaggedDeps deps+                              , (LDep _ (Dep (PkgComponent dep _) _ci), _comp) <- flattenFlaggedDeps deps                               ]     , qoSetupIndependent = True     }
Distribution/Solver/Modular/IndexConversion.hs view
@@ -3,8 +3,8 @@     ) where  import Data.List as L-import Distribution.Compat.Map.Strict (Map)-import qualified Distribution.Compat.Map.Strict as M+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M import Data.Maybe import Data.Monoid as Mon import Data.Set as S@@ -30,7 +30,9 @@ import           Distribution.Solver.Types.ComponentDeps                    ( Component(..), componentNameToComponent ) import           Distribution.Solver.Types.Flag+import           Distribution.Solver.Types.LabeledPackageConstraint import           Distribution.Solver.Types.OptionalStanza+import           Distribution.Solver.Types.PackageConstraint import qualified Distribution.Solver.Types.PackageIndex as CI import           Distribution.Solver.Types.Settings import           Distribution.Solver.Types.SourcePackage@@ -53,10 +55,13 @@ -- resolving these situations. However, the right thing to do is to -- fix the problem there, so for now, shadowing is only activated if -- explicitly requested.-convPIs :: OS -> Arch -> CompilerInfo -> ShadowPkgs -> StrongFlags -> SolveExecutables ->-           SI.InstalledPackageIndex -> CI.PackageIndex (SourcePackage loc) -> Index-convPIs os arch comp sip strfl solveExes iidx sidx =-  mkIndex (convIPI' sip iidx ++ convSPI' os arch comp strfl solveExes sidx)+convPIs :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint]+        -> ShadowPkgs -> StrongFlags -> SolveExecutables+        -> SI.InstalledPackageIndex -> CI.PackageIndex (SourcePackage loc)+        -> Index+convPIs os arch comp constraints sip strfl solveExes iidx sidx =+  mkIndex $+  convIPI' sip iidx ++ convSPI' os arch comp constraints strfl solveExes sidx  -- | Convert a Cabal installed package index to the simpler, -- more uniform index format of the solver.@@ -72,7 +77,8 @@   where      -- shadowing is recorded in the package info-    shadow (pn, i, PInfo fdeps exes fds _) | sip = (pn, i, PInfo fdeps exes fds (Just Shadowed))+    shadow (pn, i, PInfo fdeps comps fds _)+      | sip = (pn, i, PInfo fdeps comps fds (Just Shadowed))     shadow x                                     = x  -- | Extract/recover the the package ID from an installed package info, and convert it to a solver's I.@@ -86,8 +92,10 @@ convIP :: SI.InstalledPackageIndex -> InstalledPackageInfo -> (PN, I, PInfo) convIP idx ipi =   case mapM (convIPId (DependencyReason pn M.empty S.empty) comp idx) (IPI.depends ipi) of-        Nothing  -> (pn, i, PInfo [] [] M.empty (Just Broken))-        Just fds -> (pn, i, PInfo fds [] M.empty Nothing)+        Nothing  -> (pn, i, PInfo [] M.empty M.empty (Just Broken))+        Just fds -> ( pn+                    , i+                    , PInfo fds (M.singleton ExposedLib (IsBuildable True)) M.empty Nothing)  where   (pn, i) = convId ipi   -- 'sourceLibName' is unreliable, but for now we only really use this for@@ -133,30 +141,35 @@   case SI.lookupUnitId idx ipid of     Nothing  -> Nothing     Just ipi -> let (pn, i) = convId ipi-                in  Just (D.Simple (LDep dr (Dep Nothing pn (Fixed i))) comp)+                in  Just (D.Simple (LDep dr (Dep (PkgComponent pn ExposedLib) (Fixed i))) comp)                 -- NB: something we pick up from the                 -- InstalledPackageIndex is NEVER an executable  -- | Convert a cabal-install source package index to the simpler, -- more uniform index format of the solver.-convSPI' :: OS -> Arch -> CompilerInfo -> StrongFlags -> SolveExecutables ->-            CI.PackageIndex (SourcePackage loc) -> [(PN, I, PInfo)]-convSPI' os arch cinfo strfl solveExes = L.map (convSP os arch cinfo strfl solveExes) . CI.allPackages+convSPI' :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint]+         -> StrongFlags -> SolveExecutables+         -> CI.PackageIndex (SourcePackage loc) -> [(PN, I, PInfo)]+convSPI' os arch cinfo constraints strfl solveExes =+    L.map (convSP os arch cinfo constraints strfl solveExes) . CI.allPackages  -- | Convert a single source package into the solver-specific format.-convSP :: OS -> Arch -> CompilerInfo -> StrongFlags -> SolveExecutables -> SourcePackage loc -> (PN, I, PInfo)-convSP os arch cinfo strfl solveExes (SourcePackage (PackageIdentifier pn pv) gpd _ _pl) =+convSP :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint]+       -> StrongFlags -> SolveExecutables -> SourcePackage loc -> (PN, I, PInfo)+convSP os arch cinfo constraints strfl solveExes (SourcePackage (PackageIdentifier pn pv) gpd _ _pl) =   let i = I pv InRepo-  in  (pn, i, convGPD os arch cinfo strfl solveExes pn gpd)+      pkgConstraints = fromMaybe [] $ M.lookup pn constraints+  in  (pn, i, convGPD os arch cinfo pkgConstraints strfl solveExes pn gpd)  -- We do not use 'flattenPackageDescription' or 'finalizePD' -- from 'Distribution.PackageDescription.Configuration' here, because we -- want to keep the condition tree, but simplify much of the test.  -- | Convert a generic package description to a solver-specific 'PInfo'.-convGPD :: OS -> Arch -> CompilerInfo -> StrongFlags -> SolveExecutables ->-           PN -> GenericPackageDescription -> PInfo-convGPD os arch cinfo strfl solveExes pn+convGPD :: OS -> Arch -> CompilerInfo -> [LabeledPackageConstraint]+        -> StrongFlags -> SolveExecutables -> PN -> GenericPackageDescription+        -> PInfo+convGPD os arch cinfo constraints strfl solveExes pn         (GenericPackageDescription pkg flags mlib sub_libs flibs exes tests benchs) =   let     fds  = flagInfo strfl flags@@ -222,9 +235,82 @@     -- forced to, emit a meaningful solver error message).     fr | reqSpecVer > maxSpecVer = Just (UnsupportedSpecVer reqSpecVer)        | otherwise               = Nothing-  in-    PInfo flagged_deps (L.map fst exes) fds fr +    components :: Map ExposedComponent IsBuildable+    components = M.fromList $ libComps ++ exeComps+      where+        libComps = [ (ExposedLib, IsBuildable $ isBuildable libBuildInfo lib)+                   | lib <- maybeToList mlib ]+        exeComps = [ (ExposedExe name, IsBuildable $ isBuildable buildInfo exe)+                   | (name, exe) <- exes ]+        isBuildable = isBuildableComponent os arch cinfo constraints++  in PInfo flagged_deps components fds fr++-- | Returns true if the component is buildable in the given environment.+-- This function can give false-positives. For example, it only considers flags+-- that are set by unqualified flag constraints, and it doesn't check whether+-- the intra-package dependencies of a component are buildable. It is also+-- possible for the solver to later assign a value to an automatic flag that+-- makes the component unbuildable.+isBuildableComponent :: OS+                     -> Arch+                     -> CompilerInfo+                     -> [LabeledPackageConstraint]+                     -> (a -> BuildInfo)+                     -> CondTree ConfVar [Dependency] a+                     -> Bool+isBuildableComponent os arch cinfo constraints getInfo tree =+    case simplifyCondition $ extractCondition (buildable . getInfo) tree of+      Lit False -> False+      _         -> True+  where+    flagAssignment :: [(FlagName, Bool)]+    flagAssignment =+        mconcat [ unFlagAssignment fa+                | PackageConstraint (ScopeAnyQualifier _) (PackagePropertyFlags fa)+                    <- L.map unlabelPackageConstraint constraints]++    -- Simplify the condition, using the current environment. Most of this+    -- function was copied from convBranch and+    -- Distribution.Types.Condition.simplifyCondition.+    simplifyCondition :: Condition ConfVar -> Condition ConfVar+    simplifyCondition (Var (OS os')) = Lit (os == os')+    simplifyCondition (Var (Arch arch')) = Lit (arch == arch')+    simplifyCondition (Var (Impl cf cvr))+        | matchImpl (compilerInfoId cinfo) ||+              -- fixme: Nothing should be treated as unknown, rather than empty+              --        list. This code should eventually be changed to either+              --        support partial resolution of compiler flags or to+              --        complain about incompletely configured compilers.+          any matchImpl (fromMaybe [] $ compilerInfoCompat cinfo) = Lit True+        | otherwise = Lit False+      where+        matchImpl (CompilerId cf' cv) = cf == cf' && checkVR cvr cv+    simplifyCondition (Var (Flag f))+        | Just b <- L.lookup f flagAssignment = Lit b+    simplifyCondition (Var v) = Var v+    simplifyCondition (Lit b) = Lit b+    simplifyCondition (CNot c) =+        case simplifyCondition c of+          Lit True -> Lit False+          Lit False -> Lit True+          c' -> CNot c'+    simplifyCondition (COr c d) =+        case (simplifyCondition c, simplifyCondition d) of+          (Lit False, d') -> d'+          (Lit True, _)   -> Lit True+          (c', Lit False) -> c'+          (_, Lit True)   -> Lit True+          (c', d')        -> COr c' d'+    simplifyCondition (CAnd c d) =+        case (simplifyCondition c, simplifyCondition d) of+          (Lit False, _) -> Lit False+          (Lit True, d') -> d'+          (_, Lit False) -> Lit False+          (c', Lit True) -> c'+          (c', d')       -> CAnd c' d'+ -- | Create a flagged dependency tree from a list @fds@ of flagged -- dependencies, using @f@ to form the tree node (@f@ will be -- something like @Stanza sn@).@@ -289,7 +375,7 @@     bi = getInfo info  data SimpleFlaggedDepKey qpn =-    SimpleFlaggedDepKey (Maybe UnqualComponentName) qpn Component+    SimpleFlaggedDepKey (PkgComponent qpn) Component   deriving (Eq, Ord)  data SimpleFlaggedDepValue qpn = SimpleFlaggedDepValue (DependencyReason qpn) VR@@ -320,9 +406,9 @@           => (Map (SimpleFlaggedDepKey qpn) (SimpleFlaggedDepValue qpn), FlaggedDeps qpn)           -> FlaggedDep qpn           -> (Map (SimpleFlaggedDepKey qpn) (SimpleFlaggedDepValue qpn), FlaggedDeps qpn)-        f (merged', unmerged') (D.Simple (LDep dr (Dep mExe qpn (Constrained vr))) comp) =+        f (merged', unmerged') (D.Simple (LDep dr (Dep dep (Constrained vr))) comp) =             ( M.insertWith mergeValues-                           (SimpleFlaggedDepKey mExe qpn comp)+                           (SimpleFlaggedDepKey dep comp)                            (SimpleFlaggedDepValue dr vr)                            merged'             , unmerged')@@ -337,8 +423,8 @@     toFlaggedDep :: SimpleFlaggedDepKey qpn                  -> SimpleFlaggedDepValue qpn                  -> FlaggedDep qpn-    toFlaggedDep (SimpleFlaggedDepKey mExe qpn comp) (SimpleFlaggedDepValue dr vr) =-        D.Simple (LDep dr (Dep mExe qpn (Constrained vr))) comp+    toFlaggedDep (SimpleFlaggedDepKey dep comp) (SimpleFlaggedDepValue dr vr) =+        D.Simple (LDep dr (Dep dep (Constrained vr))) comp  -- | Branch interpreter.  Mutually recursive with 'convCondTree'. --@@ -463,11 +549,10 @@         -- Union the DependencyReasons, because the extracted dependency can be         -- avoided by removing the dependency from either side of the         -- conditional.-        [ D.Simple (LDep (unionDRs vs1 vs2) (Dep mExe1 pn1 (Constrained $ vr1 .||. vr2))) comp-        | D.Simple (LDep vs1                (Dep mExe1 pn1 (Constrained vr1))) _ <- ps-        , D.Simple (LDep vs2                (Dep mExe2 pn2 (Constrained vr2))) _ <- ps'-        , pn1 == pn2-        , mExe1 == mExe2+        [ D.Simple (LDep (unionDRs vs1 vs2) (Dep dep1 (Constrained $ vr1 .||. vr2))) comp+        | D.Simple (LDep vs1                (Dep dep1 (Constrained vr1))) _ <- ps+        , D.Simple (LDep vs2                (Dep dep2 (Constrained vr2))) _ <- ps'+        , dep1 == dep2         ]  -- | Merge DependencyReasons by unioning their variables.@@ -477,11 +562,11 @@  -- | Convert a Cabal dependency on a library to a solver-specific dependency. convLibDep :: DependencyReason PN -> Dependency -> LDep PN-convLibDep dr (Dependency pn vr) = LDep dr $ Dep Nothing pn (Constrained vr)+convLibDep dr (Dependency pn vr) = LDep dr $ Dep (PkgComponent pn ExposedLib) (Constrained vr)  -- | Convert a Cabal dependency on an executable (build-tools) to a solver-specific dependency. convExeDep :: DependencyReason PN -> ExeDependency -> LDep PN-convExeDep dr (ExeDependency pn exe vr) = LDep dr $ Dep (Just exe) pn (Constrained vr)+convExeDep dr (ExeDependency pn exe vr) = LDep dr $ Dep (PkgComponent pn (ExposedExe exe)) (Constrained vr)  -- | Convert setup dependencies convSetupBuildInfo :: PN -> SetupBuildInfo -> FlaggedDeps PN
Distribution/Solver/Modular/Linking.hs view
@@ -245,7 +245,7 @@      go1 :: FlaggedDep QPN -> FlaggedDep QPN -> UpdateState ()     go1 dep rdep = case (dep, rdep) of-      (Simple (LDep dr1 (Dep _ qpn _)) _, ~(Simple (LDep dr2 (Dep _ qpn' _)) _)) -> do+      (Simple (LDep dr1 (Dep (PkgComponent qpn _) _)) _, ~(Simple (LDep dr2 (Dep (PkgComponent qpn' _) _)) _)) -> do         vs <- get         let lg   = M.findWithDefault (lgSingleton qpn  Nothing) qpn  $ vsLinks vs             lg'  = M.findWithDefault (lgSingleton qpn' Nothing) qpn' $ vsLinks vs
Distribution/Solver/Modular/Log.hs view
@@ -1,6 +1,5 @@ module Distribution.Solver.Modular.Log-    ( Log-    , logToProgress+    ( logToProgress     , SolverFailure(..)     ) where @@ -11,63 +10,47 @@  import Distribution.Solver.Modular.Dependency import Distribution.Solver.Modular.Message-import Distribution.Solver.Modular.Tree (FailReason(..)) import qualified Distribution.Solver.Modular.ConflictSet as CS+import Distribution.Solver.Modular.RetryLog import Distribution.Verbosity --- | The 'Log' datatype.------ Represents the progress of a computation lazily.------ Parameterized over the type of actual messages and the final result.-type Log m a = Progress m (ConflictSet, ConflictMap) a--data Exhaustiveness = Exhaustive | BackjumpLimit---- | Information about a dependency solver failure. It includes an error message--- and a final conflict set, if available.+-- | Information about a dependency solver failure. data SolverFailure =-    NoSolution ConflictSet String-  | BackjumpLimitReached String+    ExhaustiveSearch ConflictSet ConflictMap+  | BackjumpLimitReached --- | Postprocesses a log file. Takes as an argument a limit on allowed backjumps.--- If the limit is 'Nothing', then infinitely many backjumps are allowed. If the--- limit is 'Just 0', backtracking is completely disabled.-logToProgress :: Verbosity -> Maybe Int -> Log Message a -> Progress String SolverFailure a-logToProgress verbosity mbj l =-    let ms = proc mbj l-        mapFailure f = foldProgress Step (Fail . f) Done-    in mapFailure finalError (showMessages ms) -- run with backjump limit applied+-- | Postprocesses a log file. When the dependency solver fails to find a+-- solution, the log ends with a SolverFailure and a message describing the+-- failure. This function discards all log messages and avoids calling+-- 'showMessages' if the log isn't needed (specified by 'keepLog'), for+-- efficiency.+logToProgress :: Bool+              -> Verbosity+              -> Maybe Int+              -> RetryLog Message SolverFailure a+              -> Progress String (SolverFailure, String) a+logToProgress keepLog verbosity mbj lg =+    if keepLog+    then showMessages progress+    else foldProgress (const id) Fail Done progress   where-    -- Proc takes the allowed number of backjumps and a 'Progress' and explores the-    -- messages until the maximum number of backjumps has been reached. It filters out-    -- and ignores repeated backjumps. If proc reaches the backjump limit, it truncates-    -- the 'Progress' and ends it with the last conflict set. Otherwise, it leaves the-    -- original result.-    proc :: Maybe Int -> Log Message b -> Progress Message (Exhaustiveness, ConflictSet, ConflictMap) b-    proc _        (Done x)                          = Done x-    proc _        (Fail (cs, cm))                   = Fail (Exhaustive, cs, cm)-    proc mbj'     (Step x@(Failure cs Backjump) xs@(Step Leave (Step (Failure cs' Backjump) _)))-      | cs == cs'                                   = Step x (proc mbj'           xs) -- repeated backjumps count as one-    proc (Just 0) (Step   (Failure cs Backjump)  _) = Fail (BackjumpLimit, cs, mempty) -- No final conflict map available-    proc (Just n) (Step x@(Failure _  Backjump) xs) = Step x (proc (Just (n - 1)) xs)-    proc mbj'     (Step x                       xs) = Step x (proc mbj'           xs)+    progress =+        -- Convert the RetryLog to a Progress (with toProgress) as late as+        -- possible, to take advantage of efficient updates at failures.+        toProgress $+        mapFailure (\failure -> (failure, finalErrorMsg failure)) lg -    finalError :: (Exhaustiveness, ConflictSet, ConflictMap) -> SolverFailure-    finalError (exh, cs, cm) =-        case exh of-            Exhaustive ->-                NoSolution cs $-                "After searching the rest of the dependency tree exhaustively, "-                ++ "these were the goals I've had most trouble fulfilling: "-                ++ showCS cm cs-              where-                showCS = if verbosity > normal-                         then CS.showCSWithFrequency-                         else CS.showCSSortedByFrequency-            BackjumpLimit ->-                BackjumpLimitReached $-                "Backjump limit reached (" ++ currlimit mbj ++-                "change with --max-backjumps or try to run with --reorder-goals).\n"-              where currlimit (Just n) = "currently " ++ show n ++ ", "-                    currlimit Nothing  = ""+    finalErrorMsg :: SolverFailure -> String+    finalErrorMsg (ExhaustiveSearch cs cm) =+        "After searching the rest of the dependency tree exhaustively, "+        ++ "these were the goals I've had most trouble fulfilling: "+        ++ showCS cm cs+      where+        showCS = if verbosity > normal+                 then CS.showCSWithFrequency+                 else CS.showCSSortedByFrequency+    finalErrorMsg BackjumpLimitReached =+        "Backjump limit reached (" ++ currlimit mbj +++        "change with --max-backjumps or try to run with --reorder-goals).\n"+      where currlimit (Just n) = "currently " ++ show n ++ ", "+            currlimit Nothing  = ""
Distribution/Solver/Modular/Message.hs view
@@ -53,16 +53,10 @@         (atLevel l $ "rejecting: " ++ showQSNBool qsn b ++ showFR c fr) (go l ms)     go !l (Step (Next (Goal (P _  ) gr)) (Step (TryP qpn' i) ms@(Step Enter (Step (Next _) _)))) =         (atLevel l $ "trying: " ++ showQPNPOpt qpn' i ++ showGR gr) (go l ms)-    go !l (Step (Next (Goal (P qpn) gr)) ms@(Fail _)) =-        (atLevel l $ "unknown package: " ++ showQPN qpn ++ showGR gr) $ go l ms-        -- the previous case potentially arises in the error output, because we remove the backjump itself-        -- if we cut the log after the first error     go !l (Step (Next (Goal (P qpn) gr)) ms@(Step (Failure _c Backjump) _)) =         (atLevel l $ "unknown package: " ++ showQPN qpn ++ showGR gr) $ go l ms     go !l (Step (Next (Goal (P qpn) gr)) (Step (Failure c fr) ms)) =         (atLevel l $ showPackageGoal qpn gr) $ (atLevel l $ showFailure c fr) (go l ms)-    go !l (Step (Failure c Backjump) ms@(Step Leave (Step (Failure c' Backjump) _)))-        | c == c' = go l ms     -- standard display     go !l (Step Enter                    ms) = go (l+1) ms     go !l (Step Leave                    ms) = go (l-1) ms@@ -115,8 +109,10 @@ showFR _ (MissingPkgconfigPackage pn vr)  = " (conflict: pkg-config package " ++ display pn ++ display vr ++ ", not found in the pkg-config database)" showFR _ (NewPackageDoesNotMatchExistingConstraint d) = " (conflict: " ++ showConflictingDep d ++ ")" showFR _ (ConflictingConstraints d1 d2)   = " (conflict: " ++ L.intercalate ", " (L.map showConflictingDep [d1, d2]) ++ ")"-showFR _ (NewPackageIsMissingRequiredExe exe dr) = " (does not contain executable " ++ unUnqualComponentName exe ++ ", which is required by " ++ showDependencyReason dr ++ ")"-showFR _ (PackageRequiresMissingExe qpn exe) = " (requires executable " ++ unUnqualComponentName exe ++ " from " ++ showQPN qpn ++ ", but the executable does not exist)"+showFR _ (NewPackageIsMissingRequiredComponent comp dr) = " (does not contain " ++ showExposedComponent comp ++ ", which is required by " ++ showDependencyReason dr ++ ")"+showFR _ (NewPackageHasUnbuildableRequiredComponent comp dr) = " (" ++ showExposedComponent comp ++ " is not buildable in the current environment, but it is required by " ++ showDependencyReason dr ++ ")"+showFR _ (PackageRequiresMissingComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component does not exist)"+showFR _ (PackageRequiresUnbuildableComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component is not buildable in the current environment)" showFR _ CannotInstall                    = " (only already installed instances can be used)" showFR _ CannotReinstall                  = " (avoiding to reinstall a package with same version but new dependencies)" showFR _ Shadowed                         = " (shadowed by another installed package with same version)"@@ -138,17 +134,21 @@ showFR _ (MalformedStanzaChoice qsn)      = " (INTERNAL ERROR: MALFORMED STANZA CHOICE: " ++ showQSN qsn ++ ")" showFR _ EmptyGoalChoice                  = " (INTERNAL ERROR: EMPTY GOAL CHOICE)" +showExposedComponent :: ExposedComponent -> String+showExposedComponent ExposedLib = "library"+showExposedComponent (ExposedExe name) = "executable '" ++ unUnqualComponentName name ++ "'"+ constraintSource :: ConstraintSource -> String constraintSource src = "constraint from " ++ showConstraintSource src  showConflictingDep :: ConflictingDep -> String-showConflictingDep (ConflictingDep dr mExe qpn ci) =+showConflictingDep (ConflictingDep dr (PkgComponent qpn comp) ci) =   let DependencyReason qpn' _ _ = dr-      exeStr = case mExe of-                 Just exe -> " (exe " ++ unUnqualComponentName exe ++ ")"-                 Nothing  -> ""+      componentStr = case comp of+                       ExposedExe exe -> " (exe " ++ unUnqualComponentName exe ++ ")"+                       ExposedLib     -> ""   in case ci of        Fixed i        -> (if qpn /= qpn' then showDependencyReason dr ++ " => " else "") ++-                         showQPN qpn ++ exeStr ++ "==" ++ showI i+                         showQPN qpn ++ componentStr ++ "==" ++ showI i        Constrained vr -> showDependencyReason dr ++ " => " ++ showQPN qpn ++-                         exeStr ++ showVR vr+                         componentStr ++ showVR vr
Distribution/Solver/Modular/Solver.hs view
@@ -36,6 +36,7 @@ import Distribution.Solver.Modular.Validate import Distribution.Solver.Modular.Linking import Distribution.Solver.Modular.PSQ (PSQ)+import Distribution.Solver.Modular.RetryLog import Distribution.Solver.Modular.Tree import qualified Distribution.Solver.Modular.PSQ as PSQ @@ -89,7 +90,7 @@       -> (PN -> PackagePreferences)           -- ^ preferences       -> Map PN [LabeledPackageConstraint]    -- ^ global constraints       -> Set PN                               -- ^ global goals-      -> Log Message (Assignment, RevDepMap)+      -> RetryLog Message SolverFailure (Assignment, RevDepMap) solve sc cinfo idx pkgConfigDB userPrefs userConstraints userGoals =   explorePhase     $   detectCycles     $@@ -99,7 +100,9 @@   prunePhase       $   buildPhase   where-    explorePhase     = backjumpAndExplore (enableBackjumping sc) (countConflicts sc)+    explorePhase     = backjumpAndExplore (maxBackjumps sc)+                                          (enableBackjumping sc)+                                          (countConflicts sc)     detectCycles     = traceTree "cycles.json" id . detectCyclesPhase     heuristicsPhase  =       let heuristicsTree = traceTree "heuristics.json" id
Distribution/Solver/Modular/Tree.hs view
@@ -31,7 +31,6 @@ import Distribution.Solver.Types.ConstraintSource import Distribution.Solver.Types.Flag import Distribution.Solver.Types.PackagePath-import Distribution.Types.UnqualComponentName import Language.Haskell.Extension (Extension, Language)  type Weight = Double@@ -101,8 +100,10 @@                 | MissingPkgconfigPackage PkgconfigName VR                 | NewPackageDoesNotMatchExistingConstraint ConflictingDep                 | ConflictingConstraints ConflictingDep ConflictingDep-                | NewPackageIsMissingRequiredExe UnqualComponentName (DependencyReason QPN)-                | PackageRequiresMissingExe QPN UnqualComponentName+                | NewPackageIsMissingRequiredComponent ExposedComponent (DependencyReason QPN)+                | NewPackageHasUnbuildableRequiredComponent ExposedComponent (DependencyReason QPN)+                | PackageRequiresMissingComponent QPN ExposedComponent+                | PackageRequiresUnbuildableComponent QPN ExposedComponent                 | CannotInstall                 | CannotReinstall                 | Shadowed@@ -123,7 +124,7 @@   deriving (Eq, Show)  -- | Information about a dependency involved in a conflict, for error messages.-data ConflictingDep = ConflictingDep (DependencyReason QPN) (Maybe UnqualComponentName) QPN CI+data ConflictingDep = ConflictingDep (DependencyReason QPN) (PkgComponent QPN) CI   deriving (Eq, Show)  -- | Functor for the tree type. 'a' is the type of nodes' children. 'd' and 'c'
Distribution/Solver/Modular/Validate.hs view
@@ -22,7 +22,7 @@  import Language.Haskell.Extension (Extension, Language) -import Distribution.Compat.Map.Strict as M+import Data.Map.Strict as M import Distribution.Compiler (CompilerInfo(..))  import Distribution.Solver.Modular.Assignment@@ -37,7 +37,6 @@  import Distribution.Solver.Types.PackagePath import Distribution.Solver.Types.PkgConfigDb (PkgConfigDb, pkgConfigPkgIsPresent)-import Distribution.Types.UnqualComponentName  #ifdef DEBUG_CONFLICT_SETS import GHC.Stack (CallStack)@@ -95,28 +94,28 @@  -- | The state needed during validation. data ValidateState = VS {-  supportedExt  :: Extension -> Bool,-  supportedLang :: Language  -> Bool,-  presentPkgs   :: PkgconfigName -> VR  -> Bool,-  index :: Index,+  supportedExt        :: Extension -> Bool,+  supportedLang       :: Language  -> Bool,+  presentPkgs         :: PkgconfigName -> VR  -> Bool,+  index               :: Index,    -- Saved, scoped, dependencies. Every time 'validate' makes a package choice,   -- it qualifies the package's dependencies and saves them in this map. Then   -- the qualified dependencies are available for subsequent flag and stanza   -- choices for the same package.-  saved :: Map QPN (FlaggedDeps QPN),+  saved               :: Map QPN (FlaggedDeps QPN), -  pa    :: PreAssignment,+  pa                  :: PreAssignment, -  -- Map from package name to the executables that are provided by the chosen-  -- instance of that package.-  availableExes  :: Map QPN [UnqualComponentName],+  -- Map from package name to the components that are provided by the chosen+  -- instance of that package, and whether those components are buildable.+  availableComponents :: Map QPN (Map ExposedComponent IsBuildable), -  -- Map from package name to the executables that are required from that+  -- Map from package name to the components that are required from that   -- package.-  requiredExes   :: Map QPN ExeDeps,+  requiredComponents  :: Map QPN ComponentDependencyReasons, -  qualifyOptions :: QualifyOptions+  qualifyOptions      :: QualifyOptions }  newtype Validate a = Validate (Reader ValidateState a)@@ -133,12 +132,12 @@ -- are associated with MergedPkgDeps. type PPreAssignment = Map QPN MergedPkgDep --- | A dependency on a package, including its DependencyReason.-data PkgDep = PkgDep (DependencyReason QPN) (Maybe UnqualComponentName) QPN CI+-- | A dependency on a component, including its DependencyReason.+data PkgDep = PkgDep (DependencyReason QPN) (PkgComponent QPN) CI --- | Map from executable name to one of the reasons that the executable is+-- | Map from component name to one of the reasons that the component is -- required.-type ExeDeps = Map UnqualComponentName (DependencyReason QPN)+type ComponentDependencyReasons = Map ExposedComponent (DependencyReason QPN)  -- | MergedPkgDep records constraints about the instances that can still be -- chosen, and in the extreme case fixes a concrete instance. Otherwise, it is a@@ -146,15 +145,15 @@ -- them. It also records whether a package is a build-tool dependency, for each -- reason that it was introduced. ----- It is important to store the executable name with the version constraint, for+-- It is important to store the component name with the version constraint, for -- error messages, because whether something is a build-tool dependency affects -- its qualifier, which affects which constraint is applied. data MergedPkgDep =-    MergedDepFixed (Maybe UnqualComponentName) (DependencyReason QPN) I+    MergedDepFixed ExposedComponent (DependencyReason QPN) I   | MergedDepConstrained [VROrigin]  -- | Version ranges paired with origins.-type VROrigin = (VR, Maybe UnqualComponentName, DependencyReason QPN)+type VROrigin = (VR, ExposedComponent, DependencyReason QPN)  -- | The information needed to create a 'Fail' node. type Conflict = (ConflictSet, FailReason)@@ -204,11 +203,11 @@       pkgPresent     <- asks presentPkgs -- obtain the present pkg-config pkgs       idx            <- asks index -- obtain the index       svd            <- asks saved -- obtain saved dependencies-      aExes          <- asks availableExes-      rExes          <- asks requiredExes+      aComps         <- asks availableComponents+      rComps         <- asks requiredComponents       qo             <- asks qualifyOptions       -- obtain dependencies and index-dictated exclusions introduced by the choice-      let (PInfo deps exes _ mfr) = idx ! pn ! i+      let (PInfo deps comps _ mfr) = idx ! pn ! i       -- qualify the deps in the current scope       let qdeps = qualifyDeps qo qpn deps       -- the new active constraints are given by the instance we have chosen,@@ -223,21 +222,21 @@         Just fr -> -- The index marks this as an invalid choice. We can stop.                    return (Fail (varToConflictSet (P qpn)) fr)         Nothing ->-          let newDeps :: Either Conflict (PPreAssignment, Map QPN ExeDeps)+          let newDeps :: Either Conflict (PPreAssignment, Map QPN ComponentDependencyReasons)               newDeps = do                 nppa <- mnppa-                rExes' <- extendRequiredExes aExes rExes newactives-                checkExesInNewPackage rExes qpn exes-                return (nppa, rExes')+                rComps' <- extendRequiredComponents aComps rComps newactives+                checkComponentsInNewPackage (M.findWithDefault M.empty qpn rComps) qpn comps+                return (nppa, rComps')           in case newDeps of-               Left (c, fr)         -> -- We have an inconsistency. We can stop.-                                       return (Fail c fr)-               Right (nppa, rExes') -> -- We have an updated partial assignment for the recursive validation.-                                       local (\ s -> s { pa = PA nppa pfa psa-                                                       , saved = nsvd-                                                       , availableExes = M.insert qpn exes aExes-                                                       , requiredExes = rExes'-                                                       }) r+               Left (c, fr)          -> -- We have an inconsistency. We can stop.+                                        return (Fail c fr)+               Right (nppa, rComps') -> -- We have an updated partial assignment for the recursive validation.+                                        local (\ s -> s { pa = PA nppa pfa psa+                                                        , saved = nsvd+                                                        , availableComponents = M.insert qpn comps aComps+                                                        , requiredComponents = rComps'+                                                        }) r      -- What to do for flag nodes ...     goF :: QFN -> Bool -> Validate (Tree d c) -> Validate (Tree d c)@@ -247,8 +246,8 @@       langSupported  <- asks supportedLang -- obtain the supported languages       pkgPresent     <- asks presentPkgs   -- obtain the present pkg-config pkgs       svd            <- asks saved         -- obtain saved dependencies-      aExes          <- asks availableExes-      rExes          <- asks requiredExes+      aComps         <- asks availableComponents+      rComps         <- asks requiredComponents       -- Note that there should be saved dependencies for the package in question,       -- because while building, we do not choose flags before we see the packages       -- that define them.@@ -261,13 +260,13 @@       -- We now try to get the new active dependencies we might learn about because       -- we have chosen a new flag.       let newactives = extractNewDeps (F qfn) b npfa psa qdeps-          mNewRequiredExes = extendRequiredExes aExes rExes newactives+          mNewRequiredComps = extendRequiredComponents aComps rComps newactives       -- As in the package case, we try to extend the partial assignment.       let mnppa = extend extSupported langSupported pkgPresent newactives ppa-      case liftM2 (,) mnppa mNewRequiredExes of+      case liftM2 (,) mnppa mNewRequiredComps of         Left (c, fr)         -> return (Fail c fr) -- inconsistency found-        Right (nppa, rExes') ->-            local (\ s -> s { pa = PA nppa npfa psa, requiredExes = rExes' }) r+        Right (nppa, rComps') ->+            local (\ s -> s { pa = PA nppa npfa psa, requiredComponents = rComps' }) r      -- What to do for stanza nodes (similar to flag nodes) ...     goS :: QSN -> Bool -> Validate (Tree d c) -> Validate (Tree d c)@@ -277,8 +276,8 @@       langSupported  <- asks supportedLang -- obtain the supported languages       pkgPresent     <- asks presentPkgs -- obtain the present pkg-config pkgs       svd            <- asks saved         -- obtain saved dependencies-      aExes          <- asks availableExes-      rExes          <- asks requiredExes+      aComps         <- asks availableComponents+      rComps         <- asks requiredComponents       -- Note that there should be saved dependencies for the package in question,       -- because while building, we do not choose flags before we see the packages       -- that define them.@@ -291,26 +290,40 @@       -- We now try to get the new active dependencies we might learn about because       -- we have chosen a new flag.       let newactives = extractNewDeps (S qsn) b pfa npsa qdeps-          mNewRequiredExes = extendRequiredExes aExes rExes newactives+          mNewRequiredComps = extendRequiredComponents aComps rComps newactives       -- As in the package case, we try to extend the partial assignment.       let mnppa = extend extSupported langSupported pkgPresent newactives ppa-      case liftM2 (,) mnppa mNewRequiredExes of+      case liftM2 (,) mnppa mNewRequiredComps of         Left (c, fr)         -> return (Fail c fr) -- inconsistency found-        Right (nppa, rExes') ->-            local (\ s -> s { pa = PA nppa pfa npsa, requiredExes = rExes' }) r+        Right (nppa, rComps') ->+            local (\ s -> s { pa = PA nppa pfa npsa, requiredComponents = rComps' }) r --- | Check that a newly chosen package instance contains all executables that--- are required from that package so far.-checkExesInNewPackage :: Map QPN ExeDeps-                      -> QPN-                      -> [UnqualComponentName]-                      -> Either Conflict ()-checkExesInNewPackage required qpn providedExes =-    case M.toList $ deleteKeys providedExes (M.findWithDefault M.empty qpn required) of-      (missingExe, dr) : _ -> let cs = CS.insert (P qpn) $ dependencyReasonToCS dr-                              in Left (cs, NewPackageIsMissingRequiredExe missingExe dr)-      []                   -> Right ()+-- | Check that a newly chosen package instance contains all components that+-- are required from that package so far. The components must also be buildable.+checkComponentsInNewPackage :: ComponentDependencyReasons+                            -> QPN+                            -> Map ExposedComponent IsBuildable+                            -> Either Conflict ()+checkComponentsInNewPackage required qpn providedComps =+    case M.toList $ deleteKeys (M.keys providedComps) required of+      (missingComp, dr) : _ ->+          Left $ mkConflict missingComp dr NewPackageIsMissingRequiredComponent+      []                    ->+          case M.toList $ deleteKeys buildableProvidedComps required of+            (unbuildableComp, dr) : _ ->+                Left $ mkConflict unbuildableComp dr NewPackageHasUnbuildableRequiredComponent+            []                        -> Right ()   where+    mkConflict :: ExposedComponent+               -> DependencyReason QPN+               -> (ExposedComponent -> DependencyReason QPN -> FailReason)+               -> Conflict+    mkConflict comp dr mkFailure =+        (CS.insert (P qpn) (dependencyReasonToCS dr), mkFailure comp dr)++    buildableProvidedComps :: [ExposedComponent]+    buildableProvidedComps = [comp | (comp, IsBuildable True) <- M.toList providedComps]+     deleteKeys :: Ord k => [k] -> Map k v -> Map k v     deleteKeys ks m = L.foldr M.delete m ks @@ -386,18 +399,23 @@     extendSingle a (LDep dr (Pkg pn vr))  =       if pkgPresent pn vr then Right a                           else Left (dependencyReasonToCS dr, MissingPkgconfigPackage pn vr)-    extendSingle a (LDep dr (Dep mExe qpn ci)) =+    extendSingle a (LDep dr (Dep dep@(PkgComponent qpn _) ci)) =       let mergedDep = M.findWithDefault (MergedDepConstrained []) qpn a-      in  case (\ x -> M.insert qpn x a) <$> merge mergedDep (PkgDep dr mExe qpn ci) of+      in  case (\ x -> M.insert qpn x a) <$> merge mergedDep (PkgDep dr dep ci) of             Left (c, (d, d')) -> Left (c, ConflictingConstraints d d')             Right x           -> Right x  -- | Extend a package preassignment with a package choice. For example, when -- the solver chooses foo-2.0, it tries to add the constraint foo==2.0.+--+-- TODO: The new constraint is implemented as a dependency from foo to foo's+-- library. That isn't correct, because foo might only be needed as a build+-- tool dependency. The implemention may need to change when we support+-- component-based dependency solving. extendWithPackageChoice :: PI QPN -> PPreAssignment -> Either Conflict PPreAssignment extendWithPackageChoice (PI qpn i) ppa =   let mergedDep = M.findWithDefault (MergedDepConstrained []) qpn ppa-      newChoice = PkgDep (DependencyReason qpn M.empty S.empty) Nothing qpn (Fixed i)+      newChoice = PkgDep (DependencyReason qpn M.empty S.empty) (PkgComponent qpn ExposedLib) (Fixed i)   in  case (\ x -> M.insert qpn x ppa) <$> merge mergedDep newChoice of         Left (c, (d, _d')) -> -- Don't include the package choice in the                               -- FailReason, because it is redundant.@@ -426,76 +444,93 @@   (?loc :: CallStack) => #endif   MergedPkgDep -> PkgDep -> Either (ConflictSet, (ConflictingDep, ConflictingDep)) MergedPkgDep-merge (MergedDepFixed mExe1 vs1 i1) (PkgDep vs2 mExe2 p ci@(Fixed i2))-  | i1 == i2  = Right $ MergedDepFixed mExe1 vs1 i1+merge (MergedDepFixed comp1 vs1 i1) (PkgDep vs2 (PkgComponent p comp2) ci@(Fixed i2))+  | i1 == i2  = Right $ MergedDepFixed comp1 vs1 i1   | otherwise =       Left ( (CS.union `on` dependencyReasonToCS) vs1 vs2-           , ( ConflictingDep vs1 mExe1 p (Fixed i1)-             , ConflictingDep vs2 mExe2 p ci ) )+           , ( ConflictingDep vs1 (PkgComponent p comp1) (Fixed i1)+             , ConflictingDep vs2 (PkgComponent p comp2) ci ) ) -merge (MergedDepFixed mExe1 vs1 i@(I v _)) (PkgDep vs2 mExe2 p ci@(Constrained vr))-  | checkVR vr v = Right $ MergedDepFixed mExe1 vs1 i+merge (MergedDepFixed comp1 vs1 i@(I v _)) (PkgDep vs2 (PkgComponent p comp2) ci@(Constrained vr))+  | checkVR vr v = Right $ MergedDepFixed comp1 vs1 i   | otherwise    =       Left ( (CS.union `on` dependencyReasonToCS) vs1 vs2-           , ( ConflictingDep vs1 mExe1 p (Fixed i)-             , ConflictingDep vs2 mExe2 p ci ) )+           , ( ConflictingDep vs1 (PkgComponent p comp1) (Fixed i)+             , ConflictingDep vs2 (PkgComponent p comp2) ci ) ) -merge (MergedDepConstrained vrOrigins) (PkgDep vs2 mExe2 p ci@(Fixed i@(I v _))) =+merge (MergedDepConstrained vrOrigins) (PkgDep vs2 (PkgComponent p comp2) ci@(Fixed i@(I v _))) =     go vrOrigins -- I tried "reverse vrOrigins" here, but it seems to slow things down ...   where     go :: [VROrigin] -> Either (ConflictSet, (ConflictingDep, ConflictingDep)) MergedPkgDep-    go [] = Right (MergedDepFixed mExe2 vs2 i)-    go ((vr, mExe1, vs1) : vros)+    go [] = Right (MergedDepFixed comp2 vs2 i)+    go ((vr, comp1, vs1) : vros)        | checkVR vr v = go vros        | otherwise    =            Left ( (CS.union `on` dependencyReasonToCS) vs1 vs2-                , ( ConflictingDep vs1 mExe1 p (Constrained vr)-                  , ConflictingDep vs2 mExe2 p ci ) )+                , ( ConflictingDep vs1 (PkgComponent p comp1) (Constrained vr)+                  , ConflictingDep vs2 (PkgComponent p comp2) ci ) ) -merge (MergedDepConstrained vrOrigins) (PkgDep vs2 mExe2 _ (Constrained vr)) =+merge (MergedDepConstrained vrOrigins) (PkgDep vs2 (PkgComponent _ comp2) (Constrained vr)) =     Right (MergedDepConstrained $      -- TODO: This line appends the new version range, to preserve the order used     -- before a refactoring. Consider prepending the version range, if there is     -- no negative performance impact.-    vrOrigins ++ [(vr, mExe2, vs2)])+    vrOrigins ++ [(vr, comp2, vs2)])  -- | Takes a list of new dependencies and uses it to try to update the map of--- known executable dependencies. It returns a failure when a new dependency--- requires an executable that is missing from one of the previously chosen+-- known component dependencies. It returns a failure when a new dependency+-- requires a component that is missing or unbuildable in a previously chosen -- packages.-extendRequiredExes :: Map QPN [UnqualComponentName]-                   -> Map QPN ExeDeps-                   -> [LDep QPN]-                   -> Either Conflict (Map QPN ExeDeps)-extendRequiredExes available = foldM extendSingle+extendRequiredComponents :: Map QPN (Map ExposedComponent IsBuildable)+                         -> Map QPN ComponentDependencyReasons+                         -> [LDep QPN]+                         -> Either Conflict (Map QPN ComponentDependencyReasons)+extendRequiredComponents available = foldM extendSingle   where-    extendSingle :: Map QPN ExeDeps -> LDep QPN -> Either Conflict (Map QPN ExeDeps)-    extendSingle required (LDep dr (Dep (Just exe) qpn _)) =-      let exeDeps = M.findWithDefault M.empty qpn required-      in -- Only check for the existence of the exe if its package has already-         -- been chosen.+    extendSingle :: Map QPN ComponentDependencyReasons+                 -> LDep QPN+                 -> Either Conflict (Map QPN ComponentDependencyReasons)+    extendSingle required (LDep dr (Dep (PkgComponent qpn comp) _)) =+      let compDeps = M.findWithDefault M.empty qpn required+      in -- Only check for the existence of the component if its package has+         -- already been chosen.          case M.lookup qpn available of-           Just exes-             | L.notElem exe exes -> let cs = CS.insert (P qpn) (dependencyReasonToCS dr)-                                     in Left (cs, PackageRequiresMissingExe qpn exe)-           _                      -> Right $ M.insertWith M.union qpn (M.insert exe dr exeDeps) required-    extendSingle required _                                = Right required+           Just comps+             | M.notMember comp comps                ->+                 Left $ mkConflict qpn comp dr PackageRequiresMissingComponent+             | L.notElem comp (buildableComps comps) ->+                 Left $ mkConflict qpn comp dr PackageRequiresUnbuildableComponent+           _                                         ->+                 Right $ M.insertWith M.union qpn (M.insert comp dr compDeps) required+    extendSingle required _                                         = Right required +    mkConflict :: QPN+               -> ExposedComponent+               -> DependencyReason QPN+               -> (QPN -> ExposedComponent -> FailReason)+               -> Conflict+    mkConflict qpn comp dr mkFailure =+      (CS.insert (P qpn) (dependencyReasonToCS dr), mkFailure qpn comp)++    buildableComps :: Map comp IsBuildable -> [comp]+    buildableComps comps = [comp | (comp, IsBuildable True) <- M.toList comps]++ -- | Interface. validateTree :: CompilerInfo -> Index -> PkgConfigDb -> Tree d c -> Tree d c validateTree cinfo idx pkgConfigDb t = runValidate (validate t) VS {-    supportedExt   = maybe (const True) -- if compiler has no list of extensions, we assume everything is supported-                           (\ es -> let s = S.fromList es in \ x -> S.member x s)-                           (compilerInfoExtensions cinfo)-  , supportedLang  = maybe (const True)-                           (flip L.elem) -- use list lookup because language list is small and no Ord instance-                           (compilerInfoLanguages  cinfo)-  , presentPkgs    = pkgConfigPkgIsPresent pkgConfigDb-  , index          = idx-  , saved          = M.empty-  , pa             = PA M.empty M.empty M.empty-  , availableExes  = M.empty-  , requiredExes   = M.empty-  , qualifyOptions = defaultQualifyOptions idx+    supportedExt        = maybe (const True) -- if compiler has no list of extensions, we assume everything is supported+                                (\ es -> let s = S.fromList es in \ x -> S.member x s)+                                (compilerInfoExtensions cinfo)+  , supportedLang       = maybe (const True)+                                (flip L.elem) -- use list lookup because language list is small and no Ord instance+                                (compilerInfoLanguages  cinfo)+  , presentPkgs         = pkgConfigPkgIsPresent pkgConfigDb+  , index               = idx+  , saved               = M.empty+  , pa                  = PA M.empty M.empty M.empty+  , availableComponents = M.empty+  , requiredComponents  = M.empty+  , qualifyOptions      = defaultQualifyOptions idx   }
bootstrap.sh view
@@ -213,26 +213,26 @@                        # >= 3.1 && < 3.2 DEEPSEQ_VER="1.4.3.0"; DEEPSEQ_VER_REGEXP="1\.[1-9]\."                        # >= 1.1 && < 2-BINARY_VER="0.8.3.0";  BINARY_VER_REGEXP="[0]\.[78]\."+BINARY_VER="0.8.5.1";  BINARY_VER_REGEXP="[0]\.[78]\."                        # >= 0.7 && < 0.9 TEXT_VER="1.2.3.0";    TEXT_VER_REGEXP="[1]\.[2]\."                        # >= 1.2 && < 1.3 NETWORK_URI_VER="2.6.1.0"; NETWORK_URI_VER_REGEXP="2\.6\.(0\.[2-9]|[1-9])"                        # >= 2.6.0.2 && < 2.7-NETWORK_VER="2.6.3.4"; NETWORK_VER_REGEXP="2\.[0-6]\."+NETWORK_VER="2.7.0.0"; NETWORK_VER_REGEXP="2\.[0-7]\."                        # >= 2.0 && < 2.7-CABAL_VER="2.2.0.1";   CABAL_VER_REGEXP="2\.2\.[0-9]"-                       # >= 2.2 && < 2.3+CABAL_VER="2.4.0.1";   CABAL_VER_REGEXP="2\.4\.[0-9]"+                       # >= 2.4 && < 2.5 TRANS_VER="0.5.5.0";   TRANS_VER_REGEXP="0\.[45]\."                        # >= 0.2.* && < 0.6 MTL_VER="2.2.2";       MTL_VER_REGEXP="[2]\."                        #  >= 2.0 && < 3-HTTP_VER="4000.3.11";  HTTP_VER_REGEXP="4000\.(2\.([5-9]|1[0-9]|2[0-9])|3\.?)"+HTTP_VER="4000.3.12";  HTTP_VER_REGEXP="4000\.(2\.([5-9]|1[0-9]|2[0-9])|3\.?)"                        # >= 4000.2.5 < 4000.4 ZLIB_VER="0.6.2";      ZLIB_VER_REGEXP="(0\.5\.([3-9]|1[0-9])|0\.6)"                        # >= 0.5.3 && <= 0.7-TIME_VER="1.8.0.3"     TIME_VER_REGEXP="1\.[1-8]\.?"-                       # >= 1.1 && < 1.9+TIME_VER="1.9.1"       TIME_VER_REGEXP="1\.[1-9]\.?"+                       # >= 1.1 && < 1.10 RANDOM_VER="1.1"       RANDOM_VER_REGEXP="1\.[01]\.?"                        # >= 1 && < 1.2 STM_VER="2.4.5.0";     STM_VER_REGEXP="2\."@@ -249,7 +249,7 @@                        # 0.11.* RESOLV_VER="0.1.1.1";  RESOLV_VER_REGEXP="0\.1\.[1-9]"                        # >= 0.1.1 && < 0.2-MINTTY_VER="0.1.1";    MINTTY_VER_REGEXP="0\.1\.?"+MINTTY_VER="0.1.2";    MINTTY_VER_REGEXP="0\.1\.?"                        # 0.1.* ECHO_VER="0.1.3";      ECHO_VER_REGEXP="0\.1\.[3-9]"                        # >= 0.1.3 && < 0.2@@ -261,6 +261,10 @@                        # >= 0.5.2 && < 0.6 TAR_VER="0.5.1.0";     TAR_VER_REGEXP="0\.5\.([1-9]|1[0-9]|0\.[3-9]|0\.1[0-9])\.?"                        # >= 0.5.0.3  && < 0.6+DIGEST_VER="0.0.1.2"; DIGEST_REGEXP="0\.0\.(1\.[2-9]|[2-9]\.?)"+                       # >= 0.0.1.2 && < 0.1+ZIP_ARCHIVE_VER="0.3.3"; ZIP_ARCHIVE_REGEXP="0\.3\.[3-9]"+                       # >= 0.3.3 && < 0.4  HACKAGE_URL="https://hackage.haskell.org/package" @@ -452,6 +456,8 @@ info_pkg "edit-distance" ${EDIT_DISTANCE_VER} ${EDIT_DISTANCE_VER_REGEXP} info_pkg "ed25519"           ${ED25519_VER}          ${ED25519_VER_REGEXP} info_pkg "tar"               ${TAR_VER}              ${TAR_VER_REGEXP}+info_pkg "digest"            ${DIGEST_VER}           ${DIGEST_REGEXP}+info_pkg "zip-archive"       ${ZIP_ARCHIVE_VER}      ${ZIP_ARCHIVE_REGEXP} info_pkg "hackage-security"  ${HACKAGE_SECURITY_VER} \     ${HACKAGE_SECURITY_VER_REGEXP} @@ -488,6 +494,8 @@ do_pkg "edit-distance" ${EDIT_DISTANCE_VER} ${EDIT_DISTANCE_VER_REGEXP} do_pkg   "ed25519"           ${ED25519_VER}          ${ED25519_VER_REGEXP} do_pkg   "tar"               ${TAR_VER}              ${TAR_VER_REGEXP}+do_pkg   "digest"            ${DIGEST_VER}           ${DIGEST_REGEXP}+do_pkg   "zip-archive"       ${ZIP_ARCHIVE_VER}      ${ZIP_ARCHIVE_REGEXP} do_pkg   "hackage-security"  ${HACKAGE_SECURITY_VER} \     ${HACKAGE_SECURITY_VER_REGEXP} 
cabal-install.cabal view
@@ -1,13 +1,15 @@+Cabal-Version:      >= 1.10+-- NOTE: This file is autogenerated from 'cabal-install.cabal.pp'.+-- DO NOT EDIT MANUALLY.+-- To update this file, edit 'cabal-install.cabal.pp' and run+-- 'make cabal-install-prod' in the project's root folder. Name:               cabal-install-Version:            2.2.0.0+Version:            2.4.0.0 Synopsis:           The command-line interface for Cabal and Hackage. Description:     The \'cabal\' command-line program simplifies the process of managing     Haskell software by automating the fetching, configuration, compilation     and installation of Haskell libraries and programs.-    .-    This package only provides an executable and cannot be used as a-    library (ignore the module listing below.) homepage:           http://www.haskell.org/cabal/ bug-reports:        https://github.com/haskell/cabal/issues License:            BSD3@@ -17,7 +19,6 @@ Copyright:          2003-2018, Cabal Development Team Category:           Distribution Build-type:         Custom-Cabal-Version:      >= 1.10 Extra-Source-Files:   README.md bash-completion/cabal bootstrap.sh changelog   tests/README.md@@ -30,6 +31,9 @@   tests/IntegrationTests2/build/keep-going/p/p.cabal   tests/IntegrationTests2/build/keep-going/q/Q.hs   tests/IntegrationTests2/build/keep-going/q/q.cabal+  tests/IntegrationTests2/build/local-tarball/cabal.project+  tests/IntegrationTests2/build/local-tarball/q/Q.hs+  tests/IntegrationTests2/build/local-tarball/q/q.cabal   tests/IntegrationTests2/build/setup-custom1/A.hs   tests/IntegrationTests2/build/setup-custom1/Setup.hs   tests/IntegrationTests2/build/setup-custom1/a.cabal@@ -89,6 +93,10 @@   tests/IntegrationTests2/targets/variety/p.cabal   -- END gen-extra-source-files +  -- Additional manual extra-source-files:+  tests/IntegrationTests2/build/local-tarball/p-0.1.tar.gz++ source-repository head   type:     git   location: https://github.com/haskell/cabal/@@ -114,32 +122,30 @@   default:      False   manual:       True -flag lib-  description:  Build cabal-install as a library. Please only use this if you are a cabal-install developer.-  Default:      False-  manual:       True---- Build everything (including the test binaries) as a single static binary--- instead of 5 discrete binaries.--- This is useful for CI where we build our binaries on one machine, and then--- ship them to another machine for testing.  Since the test binaries are--- statically linked (making deployment easier), if we build five executables,--- that means we need to ship ALL 5 binaries (with 5 versions of all the--- statically linked libraries) to the test machines. This reduces that to one--- binary and one set of linked libraries.-flag monolithic-  description:  Build cabal-install also with all of its test and support code.  Used by our continuous integration.-  default:      False-  manual:       True+custom-setup+   setup-depends:+       Cabal     >= 2.2,+       base,+       process   >= 1.1.0.1  && < 1.7,+       filepath  >= 1.3      && < 1.5 -library+executable cabal+    main-is:        Main.hs+    hs-source-dirs: main+    default-language: Haskell2010     ghc-options:    -Wall -fwarn-tabs     if impl(ghc >= 8.0)         ghc-options: -Wcompat                      -Wnoncanonical-monad-instances                      -Wnoncanonical-monadfail-instances -    exposed-modules:+    ghc-options: -rtsopts -threaded++    -- On AIX, some legacy BSD operations such as flock(2) are provided by libbsd.a+    if os(aix)+        extra-libraries: bsd+    hs-source-dirs: .+    other-modules:         Distribution.Client.BuildReports.Anonymous         Distribution.Client.BuildReports.Storage         Distribution.Client.BuildReports.Types@@ -147,6 +153,7 @@         Distribution.Client.Check         Distribution.Client.CmdBench         Distribution.Client.CmdBuild+        Distribution.Client.CmdClean         Distribution.Client.CmdConfigure         Distribution.Client.CmdUpdate         Distribution.Client.CmdErrorMessages@@ -157,6 +164,8 @@         Distribution.Client.CmdRepl         Distribution.Client.CmdRun         Distribution.Client.CmdTest+        Distribution.Client.CmdLegacy+        Distribution.Client.CmdSdist         Distribution.Client.Compat.Directory         Distribution.Client.Compat.ExecutablePath         Distribution.Client.Compat.FileLock@@ -234,6 +243,7 @@         Distribution.Client.Utils         Distribution.Client.Utils.Assertion         Distribution.Client.Utils.Json+        Distribution.Client.VCS         Distribution.Client.Win32SelfUpgrade         Distribution.Client.World         Distribution.Solver.Compat.Prelude@@ -286,17 +296,15 @@         Distribution.Solver.Types.Variable         Paths_cabal_install -    -- NOTE: when updating build-depends, don't forget to update version regexps-    -- in bootstrap.sh.     build-depends:         async      >= 2.0      && < 3,         array      >= 0.4      && < 0.6,-        base       >= 4.5      && < 5,+        base       >= 4.6      && < 5,         base16-bytestring >= 0.1.1 && < 0.2,         binary     >= 0.7      && < 0.9,         bytestring >= 0.10.2   && < 1,-        Cabal      >= 2.2      && < 2.3,-        containers >= 0.4      && < 0.6,+        Cabal      == 2.4.*,+        containers >= 0.5      && < 0.7,         cryptohash-sha256 >= 0.11 && < 0.12,         deepseq    >= 1.3      && < 1.5,         directory  >= 1.2.2.0  && < 1.4,@@ -307,15 +315,18 @@         HTTP       >= 4000.1.5 && < 4000.4,         mtl        >= 2.0      && < 3,         network-uri >= 2.6.0.2 && < 2.7,-        network    >= 2.6      && < 2.7,+        network    >= 2.6      && < 2.8,         pretty     >= 1.1      && < 1.2,         process    >= 1.1.0.2  && < 1.7,         random     >= 1        && < 1.2,         stm        >= 2.0      && < 3,         tar        >= 0.5.0.3  && < 0.6,-        time       >= 1.4      && < 1.9,+        time       >= 1.4      && < 1.10,         zlib       >= 0.5.3    && < 0.7,-        hackage-security >= 0.5.2.2 && < 0.6+        hackage-security >= 0.5.2.2 && < 0.6,+        text       >= 1.2.3    && < 1.3,+        zip-archive >= 0.3.2.5 && < 0.4,+        parsec     >= 3.1.13.0 && < 3.2      if flag(native-dns)       if os(windows)@@ -326,7 +337,7 @@     if os(windows)       build-depends: Win32 >= 2 && < 3     else-      build-depends: unix >= 2.5 && < 2.8+      build-depends: unix >= 2.5 && < 2.9      if flag(debug-expensive-assertions)       cpp-options: -DDEBUG_EXPENSIVE_ASSERTIONS@@ -338,446 +349,3 @@     if flag(debug-tracetree)       cpp-options: -DDEBUG_TRACETREE       build-depends: tracetree >= 0.1 && < 0.2--    if !flag(lib)-      buildable: False--    default-language: Haskell2010--executable cabal-    main-is:        Main.hs-    hs-source-dirs: main--    ghc-options:    -Wall -fwarn-tabs -rtsopts-    if impl(ghc >= 8.0)-        ghc-options: -Wcompat-                     -Wnoncanonical-monad-instances-                     -Wnoncanonical-monadfail-instances--    other-modules: Paths_cabal_install--    if flag(lib)-        build-depends:-            cabal-install,-            Cabal      >= 2.2      && < 2.3,-            base,-            directory,-            filepath-    else-        hs-source-dirs: .-        build-depends:-            async      >= 2.0      && < 3,-            array      >= 0.4      && < 0.6,-            base       >= 4.5      && < 5,-            base16-bytestring >= 0.1.1 && < 0.2,-            binary     >= 0.7      && < 0.9,-            bytestring >= 0.10.2   && < 1,-            Cabal      >= 2.2      && < 2.3,-            containers >= 0.4      && < 0.6,-            cryptohash-sha256 >= 0.11 && < 0.12,-            deepseq    >= 1.3      && < 1.5,-            directory  >= 1.2.2.0  && < 1.4,-            echo       >= 0.1.3    && < 0.2,-            edit-distance >= 0.2.2 && < 0.3,-            filepath   >= 1.3      && < 1.5,-            hashable   >= 1.0      && < 2,-            HTTP       >= 4000.1.5 && < 4000.4,-            mtl        >= 2.0      && < 3,-            network    >= 2.6      && < 2.7,-            network-uri >= 2.6     && < 2.7,-            pretty     >= 1.1      && < 1.2,-            process    >= 1.2      && < 1.7,-            random     >= 1        && < 1.2,-            stm        >= 2.0      && < 3,-            tar        >= 0.5.0.3  && < 0.6,-            time       >= 1.4      && < 1.9,-            zlib       >= 0.5.3    && < 0.7,-            hackage-security >= 0.5.2.2 && < 0.6--        other-modules:-            Distribution.Client.BuildReports.Anonymous-            Distribution.Client.BuildReports.Storage-            Distribution.Client.BuildReports.Types-            Distribution.Client.BuildReports.Upload-            Distribution.Client.Check-            Distribution.Client.CmdBench-            Distribution.Client.CmdBuild-            Distribution.Client.CmdConfigure-            Distribution.Client.CmdUpdate-            Distribution.Client.CmdErrorMessages-            Distribution.Client.CmdExec-            Distribution.Client.CmdFreeze-            Distribution.Client.CmdHaddock-            Distribution.Client.CmdInstall-            Distribution.Client.CmdRepl-            Distribution.Client.CmdRun-            Distribution.Client.CmdTest-            Distribution.Client.Compat.Directory-            Distribution.Client.Compat.ExecutablePath-            Distribution.Client.Compat.FileLock-            Distribution.Client.Compat.FilePerms-            Distribution.Client.Compat.Prelude-            Distribution.Client.Compat.Process-            Distribution.Client.Compat.Semaphore-            Distribution.Client.Config-            Distribution.Client.Configure-            Distribution.Client.Dependency-            Distribution.Client.Dependency.Types-            Distribution.Client.DistDirLayout-            Distribution.Client.Exec-            Distribution.Client.Fetch-            Distribution.Client.FetchUtils-            Distribution.Client.FileMonitor-            Distribution.Client.Freeze-            Distribution.Client.GZipUtils-            Distribution.Client.GenBounds-            Distribution.Client.Get-            Distribution.Client.Glob-            Distribution.Client.GlobalFlags-            Distribution.Client.Haddock-            Distribution.Client.HttpUtils-            Distribution.Client.IndexUtils-            Distribution.Client.IndexUtils.Timestamp-            Distribution.Client.Init-            Distribution.Client.Init.Heuristics-            Distribution.Client.Init.Licenses-            Distribution.Client.Init.Types-            Distribution.Client.Install-            Distribution.Client.InstallPlan-            Distribution.Client.InstallSymlink-            Distribution.Client.JobControl-            Distribution.Client.List-            Distribution.Client.Manpage-            Distribution.Client.Nix-            Distribution.Client.Outdated-            Distribution.Client.PackageHash-            Distribution.Client.PackageUtils-            Distribution.Client.ParseUtils-            Distribution.Client.ProjectBuilding-            Distribution.Client.ProjectBuilding.Types-            Distribution.Client.ProjectConfig-            Distribution.Client.ProjectConfig.Legacy-            Distribution.Client.ProjectConfig.Types-            Distribution.Client.ProjectOrchestration-            Distribution.Client.ProjectPlanOutput-            Distribution.Client.ProjectPlanning-            Distribution.Client.ProjectPlanning.Types-            Distribution.Client.RebuildMonad-            Distribution.Client.Reconfigure-            Distribution.Client.Run-            Distribution.Client.Sandbox-            Distribution.Client.Sandbox.Index-            Distribution.Client.Sandbox.PackageEnvironment-            Distribution.Client.Sandbox.Timestamp-            Distribution.Client.Sandbox.Types-            Distribution.Client.SavedFlags-            Distribution.Client.Security.DNS-            Distribution.Client.Security.HTTP-            Distribution.Client.Setup-            Distribution.Client.SetupWrapper-            Distribution.Client.SolverInstallPlan-            Distribution.Client.SourceFiles-            Distribution.Client.SourceRepoParse-            Distribution.Client.SrcDist-            Distribution.Client.Store-            Distribution.Client.Tar-            Distribution.Client.TargetSelector-            Distribution.Client.Targets-            Distribution.Client.Types-            Distribution.Client.Update-            Distribution.Client.Upload-            Distribution.Client.Utils-            Distribution.Client.Utils.Assertion-            Distribution.Client.Utils.Json-            Distribution.Client.Win32SelfUpgrade-            Distribution.Client.World-            Distribution.Solver.Compat.Prelude-            Distribution.Solver.Modular-            Distribution.Solver.Modular.Assignment-            Distribution.Solver.Modular.Builder-            Distribution.Solver.Modular.Configured-            Distribution.Solver.Modular.ConfiguredConversion-            Distribution.Solver.Modular.ConflictSet-            Distribution.Solver.Modular.Cycles-            Distribution.Solver.Modular.Dependency-            Distribution.Solver.Modular.Explore-            Distribution.Solver.Modular.Flag-            Distribution.Solver.Modular.Index-            Distribution.Solver.Modular.IndexConversion-            Distribution.Solver.Modular.LabeledGraph-            Distribution.Solver.Modular.Linking-            Distribution.Solver.Modular.Log-            Distribution.Solver.Modular.Message-            Distribution.Solver.Modular.PSQ-            Distribution.Solver.Modular.Package-            Distribution.Solver.Modular.Preference-            Distribution.Solver.Modular.RetryLog-            Distribution.Solver.Modular.Solver-            Distribution.Solver.Modular.Tree-            Distribution.Solver.Modular.Validate-            Distribution.Solver.Modular.Var-            Distribution.Solver.Modular.Version-            Distribution.Solver.Modular.WeightedPSQ-            Distribution.Solver.Types.ComponentDeps-            Distribution.Solver.Types.ConstraintSource-            Distribution.Solver.Types.DependencyResolver-            Distribution.Solver.Types.Flag-            Distribution.Solver.Types.InstSolverPackage-            Distribution.Solver.Types.InstalledPreference-            Distribution.Solver.Types.LabeledPackageConstraint-            Distribution.Solver.Types.OptionalStanza-            Distribution.Solver.Types.PackageConstraint-            Distribution.Solver.Types.PackageFixedDeps-            Distribution.Solver.Types.PackageIndex-            Distribution.Solver.Types.PackagePath-            Distribution.Solver.Types.PackagePreferences-            Distribution.Solver.Types.PkgConfigDb-            Distribution.Solver.Types.Progress-            Distribution.Solver.Types.ResolverPackage-            Distribution.Solver.Types.Settings-            Distribution.Solver.Types.SolverId-            Distribution.Solver.Types.SolverPackage-            Distribution.Solver.Types.SourcePackage-            Distribution.Solver.Types.Variable--        if flag(native-dns)-          if os(windows)-            build-depends: windns      >= 0.1.0 && < 0.2-          else-            build-depends: resolv      >= 0.1.1 && < 0.2--        if os(windows)-          build-depends: Win32 >= 2 && < 3-        else-          build-depends: unix >= 2.5 && < 2.8--        if flag(debug-expensive-assertions)-          cpp-options: -DDEBUG_EXPENSIVE_ASSERTIONS--        if flag(debug-conflict-sets)-          cpp-options: -DDEBUG_CONFLICT_SETS-          build-depends: base >= 4.8--        if flag(debug-tracetree)-          cpp-options: -DDEBUG_TRACETREE-          build-depends: tracetree >= 0.1 && < 0.2--    if flag(monolithic)-      hs-source-dirs: tests-      other-modules:-        UnitTests-        MemoryUsageTests-        SolverQuickCheck-        IntegrationTests2--        UnitTests.Distribution.Client.ArbitraryInstances-        UnitTests.Distribution.Client.FileMonitor-        UnitTests.Distribution.Client.GZipUtils-        UnitTests.Distribution.Client.Glob-        UnitTests.Distribution.Client.IndexUtils.Timestamp-        UnitTests.Distribution.Client.InstallPlan-        UnitTests.Distribution.Client.JobControl-        UnitTests.Distribution.Client.ProjectConfig-        UnitTests.Distribution.Client.Sandbox-        UnitTests.Distribution.Client.Sandbox.Timestamp-        UnitTests.Distribution.Client.Store-        UnitTests.Distribution.Client.Tar-        UnitTests.Distribution.Client.Targets-        UnitTests.Distribution.Client.UserConfig-        UnitTests.Distribution.Solver.Modular.Builder-        UnitTests.Distribution.Solver.Modular.DSL-        UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils-        UnitTests.Distribution.Solver.Modular.MemoryUsage-        UnitTests.Distribution.Solver.Modular.QuickCheck-        UnitTests.Distribution.Solver.Modular.QuickCheck.Utils-        UnitTests.Distribution.Solver.Modular.RetryLog-        UnitTests.Distribution.Solver.Modular.Solver-        UnitTests.Distribution.Solver.Modular.WeightedPSQ-        UnitTests.Options--      cpp-options: -DMONOLITHIC-      build-depends:-        Cabal      >= 2.2 && < 2.3,-        QuickCheck >= 2.8.2,-        array,-        async,-        bytestring,-        containers,-        deepseq,-        directory,-        edit-distance,-        filepath,-        hashable,-        mtl,-        network,-        network-uri,-        pretty-show >= 1.6.15,-        random,-        tagged,-        tar,-        tasty >= 1.0 && < 1.1,-        tasty-hunit >= 0.10,-        tasty-quickcheck,-        time,-        zlib--    ghc-options: -threaded--    -- On AIX, some legacy BSD operations such as flock(2) are provided by libbsd.a-    if os(aix)-      extra-libraries: bsd--    default-language: Haskell2010---- Small, fast running tests.-Test-Suite unit-tests-  type: exitcode-stdio-1.0-  main-is: UnitTests.hs-  hs-source-dirs: tests-  ghc-options: -Wall -fwarn-tabs -main-is UnitTests-  other-modules:-    UnitTests.Distribution.Client.ArbitraryInstances-    UnitTests.Distribution.Client.Targets-    UnitTests.Distribution.Client.FileMonitor-    UnitTests.Distribution.Client.Glob-    UnitTests.Distribution.Client.GZipUtils-    UnitTests.Distribution.Client.Sandbox-    UnitTests.Distribution.Client.Sandbox.Timestamp-    UnitTests.Distribution.Client.Store-    UnitTests.Distribution.Client.Tar-    UnitTests.Distribution.Client.UserConfig-    UnitTests.Distribution.Client.ProjectConfig-    UnitTests.Distribution.Client.JobControl-    UnitTests.Distribution.Client.IndexUtils.Timestamp-    UnitTests.Distribution.Client.InstallPlan-    UnitTests.Distribution.Solver.Modular.Builder-    UnitTests.Distribution.Solver.Modular.RetryLog-    UnitTests.Distribution.Solver.Modular.Solver-    UnitTests.Distribution.Solver.Modular.DSL-    UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils-    UnitTests.Distribution.Solver.Modular.WeightedPSQ-    UnitTests.Options-  build-depends:-        array,-        base,-        async,-        bytestring,-        cabal-install,-        Cabal,-        containers,-        deepseq,-        mtl,-        random,-        directory,-        filepath,-        tar,-        time,-        zlib,-        network-uri,-        network,-        tasty >= 1.0 && < 1.1,-        tasty-hunit >= 0.10,-        tasty-quickcheck,-        tagged,-        QuickCheck >= 2.8.2--  ghc-options: -threaded--  if !flag(lib)-    buildable: False--  default-language: Haskell2010---- Tests to run with a limited stack and heap size-Test-Suite memory-usage-tests-  type: exitcode-stdio-1.0-  main-is: MemoryUsageTests.hs-  hs-source-dirs: tests-  ghc-options: -Wall -fwarn-tabs "-with-rtsopts=-M4M -K1K" -main-is MemoryUsageTests-  other-modules:-    UnitTests.Distribution.Solver.Modular.DSL-    UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils-    UnitTests.Distribution.Solver.Modular.MemoryUsage-    UnitTests.Options-  build-depends:-        base,-        async,-        Cabal,-        cabal-install,-        containers,-        deepseq,-        tagged,-        tasty >= 1.0 && < 1.1,-        tasty-hunit >= 0.10--  ghc-options: -threaded--  if !flag(lib)-    buildable: False--  default-language: Haskell2010---- Slow solver tests-Test-Suite solver-quickcheck-  type: exitcode-stdio-1.0-  main-is: SolverQuickCheck.hs-  hs-source-dirs: tests-  ghc-options: -Wall -fwarn-tabs -main-is SolverQuickCheck-  other-modules:-    UnitTests.Distribution.Solver.Modular.DSL-    UnitTests.Distribution.Solver.Modular.QuickCheck-    UnitTests.Distribution.Solver.Modular.QuickCheck.Utils-  build-depends:-        base,-        async,-        Cabal,-        cabal-install,-        containers,-        deepseq >= 1.2,-        hashable,-        random,-        tagged,-        tasty >= 1.0 && <1.1,-        tasty-quickcheck,-        QuickCheck >= 2.8.2,-        pretty-show >= 1.6.15--  ghc-options: -threaded--  if !flag(lib)-    buildable: False--  default-language: Haskell2010---- Integration tests that use the cabal-install code directly--- but still build whole projects-test-suite integration-tests2-  type: exitcode-stdio-1.0-  main-is: IntegrationTests2.hs-  hs-source-dirs: tests-  ghc-options: -Wall -fwarn-tabs -main-is IntegrationTests2-  other-modules:-  build-depends:-        base,-        Cabal,-        cabal-install,-        containers,-        deepseq,-        directory,-        edit-distance,-        filepath,-        tasty >= 1.0 && < 1.1,-        tasty-hunit >= 0.10,-        tagged--  if !flag(lib)-    buildable: False--  ghc-options: -threaded-  default-language: Haskell2010--custom-setup-  setup-depends: Cabal >= 2.2,-                 base,-                 process   >= 1.1.0.1  && < 1.7,-                 filepath  >= 1.3      && < 1.5
changelog view
@@ -1,7 +1,58 @@ -*-change-log-*- +2.4.0.0 Mikhail Glushenkov <mikhail.glushenkov@gmail.com> September 2018+        * Bugfix: "cabal new-build --ghc-option '--bogus' --ghc-option '-O1'"+	  no longer ignores all arguments except the last one (#5512).+	* Add the following option aliases for '-dir'-suffixed options:+	  'storedir', 'logsdir', 'packagedir', 'sourcedir', 'outputdir' (#5484).+	* 'new-run' now allows the user to run scripts that use a special block+	  to define their requirements (as in the executable stanza) in place+	  of a target. This also allows the use of 'cabal' as an interpreter+	  in a shebang line.+	* Add aliases for the "new-" commands that won't change when they+	  lose their prefix or are eventually replaced by a third UI+	  paradigm in the future. (#5429)+	* 'outdated' now accepts '--project-file FILE', which will look for bounds+	  from the new-style freeze file named FILE.freeze. This is only+	  available when `--new-freeze-file` has been passed.+	* 'new-repl' now accepts a '--build-depends' flag which accepts the+	  same syntax as is used in .cabal files to add additional dependencies+	  to the environment when developing in the REPL. It is now usable outside+	  of projects. (#5425, #5454)+	* 'new-build' now treats Haddock errors non-fatally. In addition,+	  it attempts to avoid trying to generate Haddocks when there is+	  nothing to generate them from. (#5232, #5459)+	* 'new-run', 'new-test', and 'new-bench' now will attempt to resolve+	  ambiguous selectors by filtering out selectors that would be invalid.+	  (#4679, #5461)+	* 'new-install' now supports installing libraries and local+	  components. (#5399)+	* Drop support for GHC 7.4, since it is out of our support window+	  (and has been for over a year!).+	* 'new-update' now works outside of projects. (#5096)+	* Extend `plan.json` with `pkg-src` provenance information. (#5487)+	* Add 'new-sdist' command (#5389). Creates stable archives based on+	  cabal projects in '.zip' and '.tar.gz' formats.+	* Add '--repl-options' flag to 'cabal repl' and 'cabal new-repl'+	  commands. Passes its arguments to the invoked repl, bypassing the+	  new-build's cached configurations. This assures they don't trigger+	  useless rebuilds and are always applied within the repl. (#4247, #5287)+	* Add 'v1-' prefixes for the commands that will be replaced in the+	  new-build universe, in preparation for it becoming the default.+	  (#5358)+	* 'outdated' accepts '--v1-freeze-file' and '--v2-freeze-file'+	  in the same spirit.+	* Completed the 'new-clean' command (#5357). The functionality is+	  equivalent to old-style clean, but for nix-style builds.+	* Ensure that each package selected for a build-depends dependency+	  contains a library (#5304).+	* Support packages from local tarballs in the cabal.project file.+	* Default changelog generated by 'cabal init' is now named+	  'CHANGELOG.md' (#5441).+	* Align output of 'new-build' command phases (#4040).+ 2.2.0.0 Mikhail Glushenkov <mikhail.glushenkov@gmail.com> March 2018-        * '--with-PROG' and '--PROG-options' are applied to all packages+	* '--with-PROG' and '--PROG-options' are applied to all packages 	and not local packages only (#5019). 	* Completed the 'new-update' command (#4809), which respects nix-style 	cabal.project(.local) files and allows to update from@@ -66,9 +117,8 @@ 	* Paths_ autogen modules now compile when `RebindableSyntax` or 	`OverloadedStrings` is used in `default-extensions`. 	[stack#3789](https://github.com/commercialhaskell/stack/issues/3789)-	* getDataDir` and other `Paths_autogen` functions now work-	correctly when compiling a custom `Setup.hs` script using-	`new-build` (#5164).+    * getDataDir` and other `Paths_autogen` functions now work correctly+    when compiling a custom `Setup.hs` script using `new-build` (#5164).  2.0.0.1 Mikhail Glushenkov <mikhail.glushenkov@gmail.com> December 2017 	* Support for GHC's numeric -g debug levels (#4673).
main/Main.hs view
@@ -47,16 +47,21 @@          , UserConfigFlags(..), userConfigCommand          , reportCommand          , manpageCommand+         , haddockCommand+         , cleanCommand+         , doctestCommand+         , copyCommand+         , registerCommand          ) import Distribution.Simple.Setup          ( HaddockTarget(..)-         , DoctestFlags(..), doctestCommand-         , HaddockFlags(..), haddockCommand, defaultHaddockFlags+         , DoctestFlags(..)+         , HaddockFlags(..), defaultHaddockFlags          , HscolourFlags(..), hscolourCommand          , ReplFlags(..)-         , CopyFlags(..), copyCommand-         , RegisterFlags(..), registerCommand-         , CleanFlags(..), cleanCommand+         , CopyFlags(..)+         , RegisterFlags(..)+         , CleanFlags(..)          , TestFlags(..), BenchmarkFlags(..)          , Flag(..), fromFlag, fromFlagOrDefault, flagToMaybe, toFlag          , configAbsolutePaths@@ -87,6 +92,9 @@ import qualified Distribution.Client.CmdTest      as CmdTest import qualified Distribution.Client.CmdBench     as CmdBench import qualified Distribution.Client.CmdExec      as CmdExec+import qualified Distribution.Client.CmdClean     as CmdClean+import qualified Distribution.Client.CmdSdist     as CmdSdist+import           Distribution.Client.CmdLegacy  import Distribution.Client.Install            (install) import Distribution.Client.Configure          (configure, writeConfigFlags)@@ -232,24 +240,32 @@   getArgs >>= mainWorker  mainWorker :: [String] -> IO ()-mainWorker args = topHandler $-  case commandsRun (globalCommand commands) commands args of-    CommandHelp   help                 -> printGlobalHelp help-    CommandList   opts                 -> printOptionsList opts-    CommandErrors errs                 -> printErrors errs-    CommandReadyToGo (globalFlags, commandParse)  ->-      case commandParse of-        _ | fromFlagOrDefault False (globalVersion globalFlags)-            -> printVersion-          | fromFlagOrDefault False (globalNumericVersion globalFlags)-            -> printNumericVersion-        CommandHelp     help           -> printCommandHelp help-        CommandList     opts           -> printOptionsList opts-        CommandErrors   errs           -> printErrors errs-        CommandReadyToGo action        -> do-          globalFlags' <- updateSandboxConfigFileFlag globalFlags-          action globalFlags'+mainWorker args = do+  validScript <- +    if null args+      then return False+      else doesFileExist (last args) +  topHandler $+    case commandsRun (globalCommand commands) commands args of+      CommandHelp   help                 -> printGlobalHelp help+      CommandList   opts                 -> printOptionsList opts+      CommandErrors errs                 -> printErrors errs+      CommandReadyToGo (globalFlags, commandParse)  ->+        case commandParse of+          _ | fromFlagOrDefault False (globalVersion globalFlags)+              -> printVersion+            | fromFlagOrDefault False (globalNumericVersion globalFlags)+              -> printNumericVersion+          CommandHelp     help           -> printCommandHelp help+          CommandList     opts           -> printOptionsList opts+          CommandErrors   errs           +            | validScript                -> CmdRun.handleShebang (last args)+            | otherwise                  -> printErrors errs+          CommandReadyToGo action        -> do+            globalFlags' <- updateSandboxConfigFileFlag globalFlags+            action globalFlags'+   where     printCommandHelp help = do       pname <- getProgName@@ -275,37 +291,19 @@      commands = map commandFromSpec commandSpecs     commandSpecs =-      [ regularCmd installCommand installAction-      , regularCmd updateCommand updateAction-      , regularCmd listCommand listAction+      [ regularCmd listCommand listAction       , regularCmd infoCommand infoAction       , regularCmd fetchCommand fetchAction-      , regularCmd freezeCommand freezeAction       , regularCmd getCommand getAction       , hiddenCmd  unpackCommand unpackAction       , regularCmd checkCommand checkAction-      , regularCmd sdistCommand sdistAction       , regularCmd uploadCommand uploadAction       , regularCmd reportCommand reportAction-      , regularCmd runCommand runAction       , regularCmd initCommand initAction-      , regularCmd configureExCommand configureAction-      , regularCmd reconfigureCommand reconfigureAction-      , regularCmd buildCommand buildAction-      , regularCmd replCommand replAction-      , regularCmd sandboxCommand sandboxAction-      , regularCmd doctestCommand doctestAction-      , regularCmd haddockCommand haddockAction-      , regularCmd execCommand execAction       , regularCmd userConfigCommand userConfigAction-      , regularCmd cleanCommand cleanAction       , regularCmd genBoundsCommand genBoundsAction       , regularCmd outdatedCommand outdatedAction-      , wrapperCmd copyCommand copyVerbosity copyDistPref       , wrapperCmd hscolourCommand hscolourVerbosity hscolourDistPref-      , wrapperCmd registerCommand regVerbosity regDistPref-      , regularCmd testCommand testAction-      , regularCmd benchmarkCommand benchmarkAction       , hiddenCmd  uninstallCommand uninstallAction       , hiddenCmd  formatCommand formatAction       , hiddenCmd  upgradeCommand upgradeAction@@ -313,21 +311,45 @@       , hiddenCmd  actAsSetupCommand actAsSetupAction       , hiddenCmd  manpageCommand (manpageAction commandSpecs) -      , regularCmd  CmdConfigure.configureCommand CmdConfigure.configureAction-      , regularCmd  CmdUpdate.updateCommand       CmdUpdate.updateAction-      , regularCmd  CmdBuild.buildCommand         CmdBuild.buildAction-      , regularCmd  CmdRepl.replCommand           CmdRepl.replAction-      , regularCmd  CmdFreeze.freezeCommand       CmdFreeze.freezeAction-      , regularCmd  CmdHaddock.haddockCommand     CmdHaddock.haddockAction-      , regularCmd  CmdInstall.installCommand     CmdInstall.installAction-      , regularCmd  CmdRun.runCommand             CmdRun.runAction-      , regularCmd  CmdTest.testCommand           CmdTest.testAction-      , regularCmd  CmdBench.benchCommand         CmdBench.benchAction-      , regularCmd  CmdExec.execCommand           CmdExec.execAction+      ] ++ concat+      [ newCmd  CmdConfigure.configureCommand CmdConfigure.configureAction+      , newCmd  CmdUpdate.updateCommand       CmdUpdate.updateAction+      , newCmd  CmdBuild.buildCommand         CmdBuild.buildAction+      , newCmd  CmdRepl.replCommand           CmdRepl.replAction+      , newCmd  CmdFreeze.freezeCommand       CmdFreeze.freezeAction+      , newCmd  CmdHaddock.haddockCommand     CmdHaddock.haddockAction+      , newCmd  CmdInstall.installCommand     CmdInstall.installAction+      , newCmd  CmdRun.runCommand             CmdRun.runAction+      , newCmd  CmdTest.testCommand           CmdTest.testAction+      , newCmd  CmdBench.benchCommand         CmdBench.benchAction+      , newCmd  CmdExec.execCommand           CmdExec.execAction+      , newCmd  CmdClean.cleanCommand         CmdClean.cleanAction +      , newCmd  CmdSdist.sdistCommand         CmdSdist.sdistAction+      +      , legacyCmd configureExCommand configureAction+      , legacyCmd updateCommand updateAction+      , legacyCmd buildCommand buildAction+      , legacyCmd replCommand replAction+      , legacyCmd freezeCommand freezeAction+      , legacyCmd haddockCommand haddockAction+      , legacyCmd installCommand installAction+      , legacyCmd runCommand runAction+      , legacyCmd testCommand testAction+      , legacyCmd benchmarkCommand benchmarkAction+      , legacyCmd execCommand execAction+      , legacyCmd cleanCommand cleanAction+      , legacyCmd sdistCommand sdistAction+      , legacyCmd doctestCommand doctestAction+      , legacyWrapperCmd copyCommand copyVerbosity copyDistPref+      , legacyWrapperCmd registerCommand regVerbosity regDistPref+      , legacyCmd reconfigureCommand reconfigureAction+      , legacyCmd sandboxCommand sandboxAction       ]  type Action = GlobalFlags -> IO () +-- Duplicated in Distribution.Client.CmdLegacy. Any changes must be+-- reflected there, as well. regularCmd :: CommandUI flags -> (flags -> [String] -> action)            -> CommandSpec action regularCmd ui action =@@ -358,7 +380,7 @@     distPref <- findSavedDistPref config (distPrefFlag flags)     let setupScriptOptions = defaultSetupScriptOptions { useDistPref = distPref }     setupWrapper verbosity setupScriptOptions Nothing-                 command (const flags) extraArgs+                 command (const flags) (const extraArgs)  configureAction :: (ConfigFlags, ConfigExFlags)                 -> [String] -> Action@@ -455,7 +477,7 @@ build :: Verbosity -> SavedConfig -> FilePath -> BuildFlags -> [String] -> IO () build verbosity config distPref buildFlags extraArgs =   setupWrapper verbosity setupOptions Nothing-               (Cabal.buildCommand progDb) mkBuildFlags extraArgs+               (Cabal.buildCommand progDb) mkBuildFlags (const extraArgs)   where     progDb       = defaultProgramDb     setupOptions = defaultSetupScriptOptions { useDistPref = distPref }@@ -521,7 +543,7 @@       nixShell verbosity distPref globalFlags config $ do         maybeWithSandboxDirOnSearchPath useSandbox $           setupWrapper verbosity setupOptions Nothing-          (Cabal.replCommand progDb) (const replFlags') extraArgs+          (Cabal.replCommand progDb) (const replFlags') (const extraArgs)      -- No .cabal file in the current directory: just start the REPL (possibly     -- using the sandbox package DB).@@ -549,7 +571,7 @@       nixShellIfSandboxed verb dist globalFlags config useSandbox $         setupWrapper         verb setupOpts Nothing-        installCommand (const mempty) []+        installCommand (const mempty) (const [])  installAction   (configFlags, configExFlags, installFlags, haddockFlags)@@ -679,7 +701,7 @@      maybeWithSandboxDirOnSearchPath useSandbox $       setupWrapper verbosity setupOptions Nothing-      Cabal.testCommand (const testFlags') extraArgs'+      Cabal.testCommand (const testFlags') (const extraArgs')  data ComponentNames = ComponentNamesUnknown                     | ComponentNames [LBI.ComponentName]@@ -762,7 +784,7 @@      maybeWithSandboxDirOnSearchPath useSandbox $       setupWrapper verbosity setupOptions Nothing-      Cabal.benchmarkCommand (const benchmarkFlags') extraArgs'+      Cabal.benchmarkCommand (const benchmarkFlags') (const extraArgs')  haddockAction :: HaddockFlags -> [String] -> Action haddockAction haddockFlags extraArgs globalFlags = do@@ -780,7 +802,7 @@         setupScriptOptions = defaultSetupScriptOptions                              { useDistPref = distPref }     setupWrapper verbosity setupScriptOptions Nothing-      haddockCommand (const haddockFlags') extraArgs+      haddockCommand (const haddockFlags') (const extraArgs)     when (haddockForHackage haddockFlags == Flag ForHackage) $ do       pkg <- fmap LBI.localPkgDescr (getPersistBuildConfig distPref)       let dest = distPref </> name <.> "tar.gz"@@ -794,7 +816,7 @@   let verbosity = fromFlag (doctestVerbosity doctestFlags)    setupWrapper verbosity defaultSetupScriptOptions Nothing-    doctestCommand (const doctestFlags) extraArgs+    doctestCommand (const doctestFlags) (const extraArgs)  cleanAction :: CleanFlags -> [String] -> Action cleanAction cleanFlags extraArgs globalFlags = do@@ -807,7 +829,7 @@                            }       cleanFlags' = cleanFlags { cleanDistPref = toFlag distPref }   setupWrapper verbosity setupScriptOptions Nothing-               cleanCommand (const cleanFlags') extraArgs+               cleanCommand (const cleanFlags') (const extraArgs)   where     verbosity = fromFlagOrDefault normal (cleanVerbosity cleanFlags) 
− tests/IntegrationTests2.hs
@@ -1,1699 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings #-}---- For the handy instance IsString PackageIdentifier-{-# OPTIONS_GHC -fno-warn-orphans #-}--module IntegrationTests2 where--import Distribution.Client.DistDirLayout-import Distribution.Client.ProjectConfig-import Distribution.Client.Config (defaultCabalDir)-import Distribution.Client.TargetSelector hiding (DirActions(..))-import qualified Distribution.Client.TargetSelector as TS (DirActions(..))-import Distribution.Client.ProjectPlanning-import Distribution.Client.ProjectPlanning.Types-import Distribution.Client.ProjectBuilding-import Distribution.Client.ProjectOrchestration-         ( resolveTargets, TargetProblemCommon(..), distinctTargetComponents )-import Distribution.Client.Types-         ( PackageLocation(..), UnresolvedSourcePackage-         , PackageSpecifier(..) )-import Distribution.Client.Targets-         ( UserConstraint(..), UserConstraintScope(UserAnyQualifier) )-import qualified Distribution.Client.InstallPlan as InstallPlan-import Distribution.Solver.Types.SourcePackage as SP-import Distribution.Solver.Types.ConstraintSource-         ( ConstraintSource(ConstraintSourceUnknown) )-import Distribution.Solver.Types.PackageConstraint-         ( PackageProperty(PackagePropertySource) )--import qualified Distribution.Client.CmdBuild   as CmdBuild-import qualified Distribution.Client.CmdRepl    as CmdRepl-import qualified Distribution.Client.CmdRun     as CmdRun-import qualified Distribution.Client.CmdTest    as CmdTest-import qualified Distribution.Client.CmdBench   as CmdBench-import qualified Distribution.Client.CmdHaddock as CmdHaddock--import Distribution.Package-import Distribution.PackageDescription-import qualified Distribution.Types.GenericPackageDescription as GPG-import Distribution.InstalledPackageInfo (InstalledPackageInfo)-import Distribution.Simple.Setup (toFlag, HaddockFlags(..), defaultHaddockFlags)-import Distribution.Simple.Compiler-import Distribution.System-import Distribution.Version-import Distribution.ModuleName (ModuleName)-import Distribution.Verbosity-import Distribution.Text--import Data.Monoid-import Data.List (sort)-import Data.String (IsString(..))-import qualified Data.Map as Map-import qualified Data.Set as Set-import Control.Monad-import Control.Exception hiding (assert)-import System.FilePath-import System.Directory--import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.Options-import Data.Tagged (Tagged(..))-import Data.Proxy  (Proxy(..))-import Data.Typeable (Typeable)---main :: IO ()-main =-  defaultMainWithIngredients-    (defaultIngredients ++ [includingOptions projectConfigOptionDescriptions])-    (withProjectConfig $ \config ->-      testGroup "Integration tests (internal)"-                (tests config))---tests :: ProjectConfig -> [TestTree]-tests config =-    --TODO: tests for:-    -- * normal success-    -- * dry-run tests with changes-  [ testGroup "Discovery and planning" $-    [ testCase "find root"      testFindProjectRoot-    , testCase "find root fail" testExceptionFindProjectRoot-    , testCase "no package"    (testExceptionInFindingPackage config)-    , testCase "no package2"   (testExceptionInFindingPackage2 config)-    , testCase "proj conf1"    (testExceptionInProjectConfig config)-    ]-  , testGroup "Target selectors" $-    [ testCaseSteps "valid"             testTargetSelectors-    , testCase      "bad syntax"        testTargetSelectorBadSyntax-    , testCaseSteps "ambiguous syntax"  testTargetSelectorAmbiguous-    , testCase      "no current pkg"    testTargetSelectorNoCurrentPackage-    , testCase      "no targets"        testTargetSelectorNoTargets-    , testCase      "project empty"     testTargetSelectorProjectEmpty-    , testCase      "problems (common)"  (testTargetProblemsCommon config)-    , testCaseSteps "problems (build)"   (testTargetProblemsBuild config)-    , testCaseSteps "problems (repl)"    (testTargetProblemsRepl config)-    , testCaseSteps "problems (run)"     (testTargetProblemsRun config)-    , testCaseSteps "problems (test)"    (testTargetProblemsTest config)-    , testCaseSteps "problems (bench)"   (testTargetProblemsBench config)-    , testCaseSteps "problems (haddock)" (testTargetProblemsHaddock config)-    ]-  , testGroup "Exceptions during building (local inplace)" $-    [ testCase "configure"   (testExceptionInConfigureStep config)-    , testCase "build"       (testExceptionInBuildStep config)---    , testCase "register"   testExceptionInRegisterStep-    ]-    --TODO: need to repeat for packages for the store-    --TODO: need to check we can build sub-libs, foreign libs and exes-    -- components for non-local packages / packages in the store.--  , testGroup "Successful builds" $-    [ testCaseSteps "Setup script styles" (testSetupScriptStyles config)-    , testCase      "keep-going"          (testBuildKeepGoing config)-    ]--  , testGroup "Regression tests" $-    [ testCase "issue #3324" (testRegressionIssue3324 config)-    ]-  ]---testFindProjectRoot :: Assertion-testFindProjectRoot = do-    Left (BadProjectRootExplicitFile file) <- findProjectRoot (Just testdir)-                                                              (Just testfile)-    file @?= testfile-  where-    testdir  = basedir </> "exception" </> "no-pkg2"-    testfile = "bklNI8O1OpOUuDu3F4Ij4nv3oAqN"---testExceptionFindProjectRoot :: Assertion-testExceptionFindProjectRoot = do-    Right (ProjectRootExplicit dir _) <- findProjectRoot (Just testdir) Nothing-    cwd <- getCurrentDirectory-    dir @?= cwd </> testdir-  where-    testdir = basedir </> "exception" </> "no-pkg2"---testTargetSelectors :: (String -> IO ()) -> Assertion-testTargetSelectors reportSubCase = do-    (_, _, _, localPackages, _) <- configureProject testdir config-    let readTargetSelectors' = readTargetSelectorsWith (dirActions testdir)-                                                       localPackages--    reportSubCase "cwd"-    do Right ts <- readTargetSelectors' []-       ts @?= [TargetPackage TargetImplicitCwd ["p-0.1"] Nothing]--    reportSubCase "all"-    do Right ts <- readTargetSelectors'-                     ["all", ":all"]-       ts @?= replicate 2 (TargetAllPackages Nothing)--    reportSubCase "filter"-    do Right ts <- readTargetSelectors'-                     [ "libs",  ":cwd:libs"-                     , "flibs", ":cwd:flibs"-                     , "exes",  ":cwd:exes"-                     , "tests", ":cwd:tests"-                     , "benchmarks", ":cwd:benchmarks"]-       zipWithM_ (@?=) ts-         [ TargetPackage TargetImplicitCwd ["p-0.1"] (Just kind)-         | kind <- concatMap (replicate 2) [LibKind .. ]-         ]--    reportSubCase "all:filter"-    do Right ts <- readTargetSelectors'-                     [ "all:libs",  ":all:libs"-                     , "all:flibs", ":all:flibs"-                     , "all:exes",  ":all:exes"-                     , "all:tests", ":all:tests"-                     , "all:benchmarks", ":all:benchmarks"]-       zipWithM_ (@?=) ts-         [ TargetAllPackages (Just kind)-         | kind <- concatMap (replicate 2) [LibKind .. ]-         ]--    reportSubCase "pkg"-    do Right ts <- readTargetSelectors'-                     [       ":pkg:p", ".",  "./",   "p.cabal"-                     , "q",  ":pkg:q", "q/", "./q/", "q/q.cabal"]-       ts @?= replicate 4 (mkTargetPackage "p-0.1")-           ++ replicate 5 (mkTargetPackage "q-0.1")--    reportSubCase "pkg:filter"-    do Right ts <- readTargetSelectors'-                     [ "p:libs",  ".:libs",  ":pkg:p:libs"-                     , "p:flibs", ".:flibs", ":pkg:p:flibs"-                     , "p:exes",  ".:exes",  ":pkg:p:exes"-                     , "p:tests", ".:tests",  ":pkg:p:tests"-                     , "p:benchmarks", ".:benchmarks", ":pkg:p:benchmarks"-                     , "q:libs",  "q/:libs", ":pkg:q:libs"-                     , "q:flibs", "q/:flibs", ":pkg:q:flibs"-                     , "q:exes",  "q/:exes", ":pkg:q:exes"-                     , "q:tests", "q/:tests", ":pkg:q:tests"-                     , "q:benchmarks", "q/:benchmarks", ":pkg:q:benchmarks"]-       zipWithM_ (@?=) ts $-         [ TargetPackage TargetExplicitNamed ["p-0.1"] (Just kind)-         | kind <- concatMap (replicate 3) [LibKind .. ]-         ] ++-         [ TargetPackage TargetExplicitNamed ["q-0.1"] (Just kind)-         | kind <- concatMap (replicate 3) [LibKind .. ]-         ]--    reportSubCase "component"-    do Right ts <- readTargetSelectors'-                     [ "p", "lib:p", "p:lib:p", ":pkg:p:lib:p"-                     ,      "lib:q", "q:lib:q", ":pkg:q:lib:q" ]-       ts @?= replicate 4 (TargetComponent "p-0.1" CLibName WholeComponent)-           ++ replicate 3 (TargetComponent "q-0.1" CLibName WholeComponent)--    reportSubCase "module"-    do Right ts <- readTargetSelectors'-                     [ "P", "lib:p:P", "p:p:P", ":pkg:p:lib:p:module:P"-                     , "QQ", "lib:q:QQ", "q:q:QQ", ":pkg:q:lib:q:module:QQ"-                     , "pexe:PMain" -- p:P or q:QQ would be ambiguous here-                     , "qexe:QMain" -- package p vs component p-                     ]-       ts @?= replicate 4 (TargetComponent "p-0.1" CLibName (ModuleTarget "P"))-           ++ replicate 4 (TargetComponent "q-0.1" CLibName (ModuleTarget "QQ"))-           ++ [ TargetComponent "p-0.1" (CExeName "pexe") (ModuleTarget "PMain")-              , TargetComponent "q-0.1" (CExeName "qexe") (ModuleTarget "QMain")-              ]--    reportSubCase "file"-    do Right ts <- readTargetSelectors'-                     [ "./P.hs", "p:P.lhs", "lib:p:P.hsc", "p:p:P.hsc",-                                 ":pkg:p:lib:p:file:P.y"-                     , "q/QQ.hs", "q:QQ.lhs", "lib:q:QQ.hsc", "q:q:QQ.hsc",-                                  ":pkg:q:lib:q:file:QQ.y"-                     ]-       ts @?= replicate 5 (TargetComponent "p-0.1" CLibName (FileTarget "P"))-           ++ replicate 5 (TargetComponent "q-0.1" CLibName (FileTarget "QQ"))-       -- Note there's a bit of an inconsistency here: for the single-part-       -- syntax the target has to point to a file that exists, whereas for-       -- all the other forms we don't require that.--    cleanProject testdir-  where-    testdir = "targets/simple"-    config  = mempty---testTargetSelectorBadSyntax :: Assertion-testTargetSelectorBadSyntax = do-    (_, _, _, localPackages, _) <- configureProject testdir config-    let targets = [ "foo bar",  " foo"-                  , "foo:", "foo::bar"-                  , "foo: ", "foo: :bar"-                  , "a:b:c:d:e:f", "a:b:c:d:e:f:g:h" ]-    Left errs <- readTargetSelectors localPackages targets-    zipWithM_ (@?=) errs (map TargetSelectorUnrecognised targets)-    cleanProject testdir-  where-    testdir = "targets/empty"-    config  = mempty---testTargetSelectorAmbiguous :: (String -> IO ()) -> Assertion-testTargetSelectorAmbiguous reportSubCase = do--    -- 'all' is ambiguous with packages and cwd components-    reportSubCase "ambiguous: all vs pkg"-    assertAmbiguous "all"-      [mkTargetPackage "all", mkTargetAllPackages]-      [mkpkg "all" []]--    reportSubCase "ambiguous: all vs cwd component"-    assertAmbiguous "all"-      [mkTargetComponent "other" (CExeName "all"), mkTargetAllPackages]-      [mkpkg "other" [mkexe "all"]]--    -- but 'all' is not ambiguous with non-cwd components, modules or files-    reportSubCase "unambiguous: all vs non-cwd comp, mod, file"-    assertUnambiguous "All"-      mkTargetAllPackages-      [ mkpkgAt "foo" [mkexe "All"] "foo"-      , mkpkg   "bar" [ mkexe "bar" `withModules` ["All"]-                      , mkexe "baz" `withCFiles` ["All"] ]-      ]--    -- filters 'libs', 'exes' etc are ambiguous with packages and-    -- local components-    reportSubCase "ambiguous: cwd-pkg filter vs pkg"-    assertAmbiguous "libs"-      [ mkTargetPackage "libs"-      , TargetPackage TargetImplicitCwd ["libs"] (Just LibKind) ]-      [mkpkg "libs" []]--    reportSubCase "ambiguous: filter vs cwd component"-    assertAmbiguous "exes"-      [ mkTargetComponent "other" (CExeName "exes")-      , TargetPackage TargetImplicitCwd ["other"] (Just ExeKind) ]-      [mkpkg "other" [mkexe "exes"]]--    -- but filters are not ambiguous with non-cwd components, modules or files-    reportSubCase "unambiguous: filter vs non-cwd comp, mod, file"-    assertUnambiguous "Libs"-      (TargetPackage TargetImplicitCwd ["bar"] (Just LibKind))-      [ mkpkgAt "foo" [mkexe "Libs"] "foo"-      , mkpkg   "bar" [ mkexe "bar" `withModules` ["Libs"]-                      , mkexe "baz" `withCFiles` ["Libs"] ]-      ]--    -- local components shadow packages and other components-    reportSubCase "unambiguous: cwd comp vs pkg, non-cwd comp"-    assertUnambiguous "foo"-      (mkTargetComponent "other" (CExeName "foo"))-      [ mkpkg   "other"  [mkexe "foo"]-      , mkpkgAt "other2" [mkexe "foo"] "other2" -- shadows non-local foo-      , mkpkg "foo" [] ]                        -- shadows package foo--    -- local components shadow modules and files-    reportSubCase "unambiguous: cwd comp vs module, file"-    assertUnambiguous "Foo"-      (mkTargetComponent "bar" (CExeName "Foo"))-      [ mkpkg "bar" [mkexe "Foo"]-      , mkpkg "other" [ mkexe "other"  `withModules` ["Foo"]-                      , mkexe "other2" `withCFiles`  ["Foo"] ]-      ]--    -- packages shadow non-local components-    reportSubCase "unambiguous: pkg vs non-cwd comp"-    assertUnambiguous "foo"-      (mkTargetPackage "foo")-      [ mkpkg "foo" []-      , mkpkgAt "other" [mkexe "foo"] "other" -- shadows non-local foo-      ]--    -- packages shadow modules and files-    reportSubCase "unambiguous: pkg vs module, file"-    assertUnambiguous "Foo"-      (mkTargetPackage "Foo")-      [ mkpkgAt "Foo" [] "foo"-      , mkpkg "other" [ mkexe "other"  `withModules` ["Foo"]-                      , mkexe "other2" `withCFiles`  ["Foo"] ]-      ]--    -- non-exact case packages and components are ambiguous-    reportSubCase "ambiguous: non-exact-case pkg names"-    assertAmbiguous "Foo"-      [ mkTargetPackage "foo", mkTargetPackage "FOO" ]-      [ mkpkg "foo" [], mkpkg "FOO" [] ]-    reportSubCase "ambiguous: non-exact-case comp names"-    assertAmbiguous "Foo"-      [ mkTargetComponent "bar" (CExeName "foo")-      , mkTargetComponent "bar" (CExeName "FOO") ]-      [ mkpkg "bar" [mkexe "foo", mkexe "FOO"] ]--    -- exact-case Module or File over non-exact case package or component-    reportSubCase "unambiguous: module vs non-exact-case pkg, comp"-    assertUnambiguous "Baz"-      (mkTargetModule "other" (CExeName "other") "Baz")-      [ mkpkg "baz" [mkexe "BAZ"]-      , mkpkg "other" [ mkexe "other"  `withModules` ["Baz"] ]-      ]-    reportSubCase "unambiguous: file vs non-exact-case pkg, comp"-    assertUnambiguous "Baz"-      (mkTargetFile "other" (CExeName "other") "Baz")-      [ mkpkg "baz" [mkexe "BAZ"]-      , mkpkg "other" [ mkexe "other"  `withCFiles` ["Baz"] ]-      ]-  where-    assertAmbiguous :: String-                    -> [TargetSelector]-                    -> [SourcePackage (PackageLocation a)]-                    -> Assertion-    assertAmbiguous str tss pkgs = do-      res <- readTargetSelectorsWith-               fakeDirActions-               (map SpecificSourcePackage pkgs)-               [str]-      case res of-        Left [TargetSelectorAmbiguous _ tss'] ->-          sort (map snd tss') @?= sort tss-        _ -> assertFailure $ "expected Left [TargetSelectorAmbiguous _ _], "-                          ++ "got " ++ show res--    assertUnambiguous :: String-                      -> TargetSelector-                      -> [SourcePackage (PackageLocation a)]-                      -> Assertion-    assertUnambiguous str ts pkgs = do-      res <- readTargetSelectorsWith-               fakeDirActions-               (map SpecificSourcePackage pkgs)-               [str]-      case res of-        Right [ts'] -> ts' @?= ts-        _ -> assertFailure $ "expected Right [Target...], "-                          ++ "got " ++ show res--    fakeDirActions = TS.DirActions {-      TS.doesFileExist       = \_p -> return True,-      TS.doesDirectoryExist  = \_p -> return True,-      TS.canonicalizePath    = \p -> return ("/" </> p), -- FilePath.Unix.</> ?-      TS.getCurrentDirectory = return "/"-    }--    mkpkg :: String -> [Executable] -> SourcePackage (PackageLocation a)-    mkpkg pkgidstr exes = mkpkgAt pkgidstr exes ""--    mkpkgAt :: String -> [Executable] -> FilePath-            -> SourcePackage (PackageLocation a)-    mkpkgAt pkgidstr exes loc =-      SourcePackage {-        packageInfoId = pkgid,-        packageSource = LocalUnpackedPackage loc,-        packageDescrOverride  = Nothing,-        SP.packageDescription = GenericPackageDescription {-          GPG.packageDescription = emptyPackageDescription { package = pkgid },-          genPackageFlags    = [],-          condLibrary        = Nothing,-          condSubLibraries   = [],-          condForeignLibs    = [],-          condExecutables    = [ ( exeName exe, CondNode exe [] [] )-                               | exe <- exes ],-          condTestSuites     = [],-          condBenchmarks     = []-        }-      }-      where-        Just pkgid = simpleParse pkgidstr--    mkexe :: String -> Executable-    mkexe name = mempty { exeName = fromString name }--    withModules :: Executable -> [String] -> Executable-    withModules exe mods =-      exe { buildInfo = (buildInfo exe) { otherModules = map fromString mods } }--    withCFiles :: Executable -> [FilePath] -> Executable-    withCFiles exe files =-      exe { buildInfo = (buildInfo exe) { cSources = files } }---mkTargetPackage :: PackageId -> TargetSelector-mkTargetPackage pkgid =-    TargetPackage TargetExplicitNamed [pkgid] Nothing--mkTargetComponent :: PackageId -> ComponentName -> TargetSelector-mkTargetComponent pkgid cname =-    TargetComponent pkgid cname WholeComponent--mkTargetModule :: PackageId -> ComponentName -> ModuleName -> TargetSelector-mkTargetModule pkgid cname mname =-    TargetComponent pkgid cname (ModuleTarget mname)--mkTargetFile :: PackageId -> ComponentName -> String -> TargetSelector-mkTargetFile pkgid cname fname =-    TargetComponent pkgid cname (FileTarget fname)--mkTargetAllPackages :: TargetSelector-mkTargetAllPackages = TargetAllPackages Nothing--instance IsString PackageIdentifier where-    fromString pkgidstr = pkgid-      where Just pkgid = simpleParse pkgidstr---testTargetSelectorNoCurrentPackage :: Assertion-testTargetSelectorNoCurrentPackage = do-    (_, _, _, localPackages, _) <- configureProject testdir config-    let readTargetSelectors' = readTargetSelectorsWith (dirActions testdir)-                                                       localPackages-        targets = [ "libs",  ":cwd:libs"-                  , "flibs", ":cwd:flibs"-                  , "exes",  ":cwd:exes"-                  , "tests", ":cwd:tests"-                  , "benchmarks", ":cwd:benchmarks"]-    Left errs <- readTargetSelectors' targets-    zipWithM_ (@?=) errs-      [ TargetSelectorNoCurrentPackage ts-      | target <- targets-      , let Just ts = parseTargetString target-      ]-    cleanProject testdir-  where-    testdir = "targets/complex"-    config  = mempty---testTargetSelectorNoTargets :: Assertion-testTargetSelectorNoTargets = do-    (_, _, _, localPackages, _) <- configureProject testdir config-    Left errs <- readTargetSelectors localPackages []-    errs @?= [TargetSelectorNoTargetsInCwd]-    cleanProject testdir-  where-    testdir = "targets/complex"-    config  = mempty---testTargetSelectorProjectEmpty :: Assertion-testTargetSelectorProjectEmpty = do-    (_, _, _, localPackages, _) <- configureProject testdir config-    Left errs <- readTargetSelectors localPackages []-    errs @?= [TargetSelectorNoTargetsInProject]-    cleanProject testdir-  where-    testdir = "targets/empty"-    config  = mempty---testTargetProblemsCommon :: ProjectConfig -> Assertion-testTargetProblemsCommon config0 = do-    (_,elaboratedPlan,_) <- planProject testdir config--    let pkgIdMap :: Map.Map PackageName PackageId-        pkgIdMap = Map.fromList-                     [ (packageName p, packageId p)-                     | p <- InstallPlan.toList elaboratedPlan ]--        cases :: [( TargetSelector -> CmdBuild.TargetProblem-                  , TargetSelector-                  )]-        cases =-          [ -- Cannot resolve packages outside of the project-            ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetProblemNoSuchPackage "foobar"-            , mkTargetPackage "foobar" )--            -- We cannot currently build components like testsuites or-            -- benchmarks from packages that are not local to the project-          , ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetComponentNotProjectLocal-                      (pkgIdMap Map.! "filepath") (CTestName "filepath-tests")-                      WholeComponent-            , mkTargetComponent (pkgIdMap Map.! "filepath")-                                (CTestName "filepath-tests") )--            -- Components can be explicitly @buildable: False@-          , ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetComponentNotBuildable "q-0.1" (CExeName "buildable-false") WholeComponent-            , mkTargetComponent "q-0.1" (CExeName "buildable-false") )--            -- Testsuites and benchmarks can be disabled by the solver if it-            -- cannot satisfy deps-          , ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetOptionalStanzaDisabledBySolver "q-0.1" (CTestName "solver-disabled") WholeComponent-            , mkTargetComponent "q-0.1" (CTestName "solver-disabled") )--            -- Testsuites and benchmarks can be disabled explicitly by the-            -- user via config-          , ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetOptionalStanzaDisabledByUser-                      "q-0.1" (CBenchName "user-disabled") WholeComponent-            , mkTargetComponent "q-0.1" (CBenchName "user-disabled") )--            -- An unknown package. The target selector resolution should only-            -- produce known packages, so this should not happen with the-            -- output from 'readTargetSelectors'.-          , ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetProblemNoSuchPackage "foobar"-            , mkTargetPackage "foobar" )--            -- An unknown component of a known package. The target selector-            -- resolution should only produce known packages, so this should-            -- not happen with the output from 'readTargetSelectors'.-          , ( \_ -> CmdBuild.TargetProblemCommon $-                    TargetProblemNoSuchComponent "q-0.1" (CExeName "no-such")-            , mkTargetComponent "q-0.1" (CExeName "no-such") )-          ]-    assertTargetProblems-      elaboratedPlan-      CmdBuild.selectPackageTargets-      CmdBuild.selectComponentTarget-      CmdBuild.TargetProblemCommon-      cases-  where-    testdir = "targets/complex"-    config  = config0 {-      projectConfigLocalPackages = (projectConfigLocalPackages config0) {-        packageConfigBenchmarks = toFlag False-      }-    , projectConfigShared = (projectConfigShared config0) {-        projectConfigConstraints =-          [( UserConstraint (UserAnyQualifier "filepath") PackagePropertySource-           , ConstraintSourceUnknown )]-      }-    }---testTargetProblemsBuild :: ProjectConfig -> (String -> IO ()) -> Assertion-testTargetProblemsBuild config reportSubCase = do--    reportSubCase "empty-pkg"-    assertProjectTargetProblems-      "targets/empty-pkg" config-      CmdBuild.selectPackageTargets-      CmdBuild.selectComponentTarget-      CmdBuild.TargetProblemCommon-      [ ( CmdBuild.TargetProblemNoTargets, mkTargetPackage "p-0.1" )-      ]--    reportSubCase "all-disabled"-    assertProjectTargetProblems-      "targets/all-disabled"-      config {-        projectConfigLocalPackages = (projectConfigLocalPackages config) {-          packageConfigBenchmarks = toFlag False-        }-      }-      CmdBuild.selectPackageTargets-      CmdBuild.selectComponentTarget-      CmdBuild.TargetProblemCommon-      [ ( flip CmdBuild.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CBenchName "user-disabled")-                                 TargetDisabledByUser True-               , AvailableTarget "p-0.1" (CTestName "solver-disabled")-                                 TargetDisabledBySolver True-               , AvailableTarget "p-0.1" (CExeName "buildable-false")-                                 TargetNotBuildable True-               , AvailableTarget "p-0.1" CLibName-                                 TargetNotBuildable True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "enabled component kinds"-    -- When we explicitly enable all the component kinds then selecting the-    -- whole package selects those component kinds too-    do (_,elaboratedPlan,_) <- planProject "targets/variety" config {-           projectConfigLocalPackages = (projectConfigLocalPackages config) {-             packageConfigTests      = toFlag True,-             packageConfigBenchmarks = toFlag True-           }-         }-       assertProjectDistinctTargets-         elaboratedPlan-         CmdBuild.selectPackageTargets-         CmdBuild.selectComponentTarget-         CmdBuild.TargetProblemCommon-         [ mkTargetPackage "p-0.1" ]-         [ ("p-0.1-inplace",             CLibName)-         , ("p-0.1-inplace-a-benchmark", CBenchName "a-benchmark")-         , ("p-0.1-inplace-a-testsuite", CTestName  "a-testsuite")-         , ("p-0.1-inplace-an-exe",      CExeName   "an-exe")-         , ("p-0.1-inplace-libp",        CFLibName  "libp")-         ]--    reportSubCase "disabled component kinds"-    -- When we explicitly disable all the component kinds then selecting the-    -- whole package only selects the library, foreign lib and exes-    do (_,elaboratedPlan,_) <- planProject "targets/variety" config {-           projectConfigLocalPackages = (projectConfigLocalPackages config) {-             packageConfigTests      = toFlag False,-             packageConfigBenchmarks = toFlag False-           }-         }-       assertProjectDistinctTargets-         elaboratedPlan-         CmdBuild.selectPackageTargets-         CmdBuild.selectComponentTarget-         CmdBuild.TargetProblemCommon-         [ mkTargetPackage "p-0.1" ]-         [ ("p-0.1-inplace",        CLibName)-         , ("p-0.1-inplace-an-exe", CExeName  "an-exe")-         , ("p-0.1-inplace-libp",   CFLibName "libp")-         ]--    reportSubCase "requested component kinds"-    -- When we selecting the package with an explicit filter then we get those-    -- components even though we did not explicitly enable tests/benchmarks-    do (_,elaboratedPlan,_) <- planProject "targets/variety" config-       assertProjectDistinctTargets-         elaboratedPlan-         CmdBuild.selectPackageTargets-         CmdBuild.selectComponentTarget-         CmdBuild.TargetProblemCommon-         [ TargetPackage TargetExplicitNamed ["p-0.1"] (Just TestKind)-         , TargetPackage TargetExplicitNamed ["p-0.1"] (Just BenchKind)-         ]-         [ ("p-0.1-inplace-a-benchmark", CBenchName "a-benchmark")-         , ("p-0.1-inplace-a-testsuite", CTestName  "a-testsuite")-         ]---testTargetProblemsRepl :: ProjectConfig -> (String -> IO ()) -> Assertion-testTargetProblemsRepl config reportSubCase = do--    reportSubCase "multiple-libs"-    assertProjectTargetProblems-      "targets/multiple-libs" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( flip CmdRepl.TargetProblemMatchesMultiple-               [ AvailableTarget "p-0.1" CLibName-                   (TargetBuildable () TargetRequestedByDefault) True-               , AvailableTarget "q-0.1" CLibName-                   (TargetBuildable () TargetRequestedByDefault) True-               ]-        , mkTargetAllPackages )-      ]--    reportSubCase "multiple-exes"-    assertProjectTargetProblems-      "targets/multiple-exes" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( flip CmdRepl.TargetProblemMatchesMultiple-               [ AvailableTarget "p-0.1" (CExeName "p2")-                   (TargetBuildable () TargetRequestedByDefault) True-               , AvailableTarget "p-0.1" (CExeName "p1")-                   (TargetBuildable () TargetRequestedByDefault) True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "multiple-tests"-    assertProjectTargetProblems-      "targets/multiple-tests" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( flip CmdRepl.TargetProblemMatchesMultiple-               [ AvailableTarget "p-0.1" (CTestName "p2")-                   (TargetBuildable () TargetNotRequestedByDefault) True-               , AvailableTarget "p-0.1" (CTestName "p1")-                   (TargetBuildable () TargetNotRequestedByDefault) True-               ]-        , TargetPackage TargetExplicitNamed ["p-0.1"] (Just TestKind) )-      ]--    reportSubCase "multiple targets"-    do (_,elaboratedPlan,_) <- planProject "targets/multiple-exes" config-       assertProjectDistinctTargets-         elaboratedPlan-         CmdRepl.selectPackageTargets-         CmdRepl.selectComponentTarget-         CmdRepl.TargetProblemCommon-         [ mkTargetComponent "p-0.1" (CExeName "p1")-         , mkTargetComponent "p-0.1" (CExeName "p2")-         ]-         [ ("p-0.1-inplace-p1", CExeName "p1")-         , ("p-0.1-inplace-p2", CExeName "p2")-         ]--    reportSubCase "libs-disabled"-    assertProjectTargetProblems-      "targets/libs-disabled" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( flip CmdRepl.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" CLibName TargetNotBuildable True ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "exes-disabled"-    assertProjectTargetProblems-      "targets/exes-disabled" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( flip CmdRepl.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CExeName "p") TargetNotBuildable True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "test-only"-    assertProjectTargetProblems-      "targets/test-only" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( flip CmdRepl.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CTestName "pexe")-                   (TargetBuildable () TargetNotRequestedByDefault) True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "empty-pkg"-    assertProjectTargetProblems-      "targets/empty-pkg" config-      CmdRepl.selectPackageTargets-      CmdRepl.selectComponentTarget-      CmdRepl.TargetProblemCommon-      [ ( CmdRepl.TargetProblemNoTargets, mkTargetPackage "p-0.1" )-      ]--    reportSubCase "requested component kinds"-    do (_,elaboratedPlan,_) <- planProject "targets/variety" config-       -- by default we only get the lib-       assertProjectDistinctTargets-         elaboratedPlan-         CmdRepl.selectPackageTargets-         CmdRepl.selectComponentTarget-         CmdRepl.TargetProblemCommon-         [ TargetPackage TargetExplicitNamed ["p-0.1"] Nothing ]-         [ ("p-0.1-inplace", CLibName) ]-       -- When we select the package with an explicit filter then we get those-       -- components even though we did not explicitly enable tests/benchmarks-       assertProjectDistinctTargets-         elaboratedPlan-         CmdRepl.selectPackageTargets-         CmdRepl.selectComponentTarget-         CmdRepl.TargetProblemCommon-         [ TargetPackage TargetExplicitNamed ["p-0.1"] (Just TestKind) ]-         [ ("p-0.1-inplace-a-testsuite", CTestName  "a-testsuite") ]-       assertProjectDistinctTargets-         elaboratedPlan-         CmdRepl.selectPackageTargets-         CmdRepl.selectComponentTarget-         CmdRepl.TargetProblemCommon-         [ TargetPackage TargetExplicitNamed ["p-0.1"] (Just BenchKind) ]-         [ ("p-0.1-inplace-a-benchmark", CBenchName "a-benchmark") ]---testTargetProblemsRun :: ProjectConfig -> (String -> IO ()) -> Assertion-testTargetProblemsRun config reportSubCase = do--    reportSubCase "multiple-exes"-    assertProjectTargetProblems-      "targets/multiple-exes" config-      CmdRun.selectPackageTargets-      CmdRun.selectComponentTarget-      CmdRun.TargetProblemCommon-      [ ( flip CmdRun.TargetProblemMatchesMultiple-               [ AvailableTarget "p-0.1" (CExeName "p2")-                   (TargetBuildable () TargetRequestedByDefault) True-               , AvailableTarget "p-0.1" (CExeName "p1")-                   (TargetBuildable () TargetRequestedByDefault) True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "multiple targets"-    do (_,elaboratedPlan,_) <- planProject "targets/multiple-exes" config-       assertProjectDistinctTargets-         elaboratedPlan-         CmdRun.selectPackageTargets-         CmdRun.selectComponentTarget-         CmdRun.TargetProblemCommon-         [ mkTargetComponent "p-0.1" (CExeName "p1")-         , mkTargetComponent "p-0.1" (CExeName "p2")-         ]-         [ ("p-0.1-inplace-p1", CExeName "p1")-         , ("p-0.1-inplace-p2", CExeName "p2")-         ]--    reportSubCase "exes-disabled"-    assertProjectTargetProblems-      "targets/exes-disabled" config-      CmdRun.selectPackageTargets-      CmdRun.selectComponentTarget-      CmdRun.TargetProblemCommon-      [ ( flip CmdRun.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CExeName "p") TargetNotBuildable True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "empty-pkg"-    assertProjectTargetProblems-      "targets/empty-pkg" config-      CmdRun.selectPackageTargets-      CmdRun.selectComponentTarget-      CmdRun.TargetProblemCommon-      [ ( CmdRun.TargetProblemNoTargets, mkTargetPackage "p-0.1" )-      ]--    reportSubCase "lib-only"-    assertProjectTargetProblems-      "targets/lib-only" config-      CmdRun.selectPackageTargets-      CmdRun.selectComponentTarget-      CmdRun.TargetProblemCommon-      [ ( CmdRun.TargetProblemNoExes, mkTargetPackage "p-0.1" )-      ]---testTargetProblemsTest :: ProjectConfig -> (String -> IO ()) -> Assertion-testTargetProblemsTest config reportSubCase = do--    reportSubCase "disabled by config"-    assertProjectTargetProblems-      "targets/tests-disabled"-      config {-        projectConfigLocalPackages = (projectConfigLocalPackages config) {-          packageConfigTests = toFlag False-        }-      }-      CmdTest.selectPackageTargets-      CmdTest.selectComponentTarget-      CmdTest.TargetProblemCommon-      [ ( flip CmdTest.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CTestName "user-disabled")-                                 TargetDisabledByUser True-               , AvailableTarget "p-0.1" (CTestName "solver-disabled")-                                 TargetDisabledByUser True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "disabled by solver & buildable false"-    assertProjectTargetProblems-      "targets/tests-disabled"-      config-      CmdTest.selectPackageTargets-      CmdTest.selectComponentTarget-      CmdTest.TargetProblemCommon-      [ ( flip CmdTest.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CTestName "user-disabled")-                                 TargetDisabledBySolver True-               , AvailableTarget "p-0.1" (CTestName "solver-disabled")-                                 TargetDisabledBySolver True-               ]-        , mkTargetPackage "p-0.1" )--      , ( flip CmdTest.TargetProblemNoneEnabled-               [ AvailableTarget "q-0.1" (CTestName "buildable-false")-                                 TargetNotBuildable True-               ]-        , mkTargetPackage "q-0.1" )-      ]--    reportSubCase "empty-pkg"-    assertProjectTargetProblems-      "targets/empty-pkg" config-      CmdTest.selectPackageTargets-      CmdTest.selectComponentTarget-      CmdTest.TargetProblemCommon-      [ ( CmdTest.TargetProblemNoTargets, mkTargetPackage "p-0.1" )-      ]--    reportSubCase "no tests"-    assertProjectTargetProblems-      "targets/simple"-      config-      CmdTest.selectPackageTargets-      CmdTest.selectComponentTarget-      CmdTest.TargetProblemCommon-      [ ( CmdTest.TargetProblemNoTests, mkTargetPackage "p-0.1" )-      , ( CmdTest.TargetProblemNoTests, mkTargetPackage "q-0.1" )-      ]--    reportSubCase "not a test"-    assertProjectTargetProblems-      "targets/variety"-      config-      CmdTest.selectPackageTargets-      CmdTest.selectComponentTarget-      CmdTest.TargetProblemCommon $-      [ ( const (CmdTest.TargetProblemComponentNotTest-                  "p-0.1" CLibName)-        , mkTargetComponent "p-0.1" CLibName )--      , ( const (CmdTest.TargetProblemComponentNotTest-                  "p-0.1" (CExeName "an-exe"))-        , mkTargetComponent "p-0.1" (CExeName "an-exe") )--      , ( const (CmdTest.TargetProblemComponentNotTest-                  "p-0.1" (CFLibName "libp"))-        , mkTargetComponent "p-0.1" (CFLibName "libp") )--      , ( const (CmdTest.TargetProblemComponentNotTest-                  "p-0.1" (CBenchName "a-benchmark"))-        , mkTargetComponent "p-0.1" (CBenchName "a-benchmark") )-      ] ++-      [ ( const (CmdTest.TargetProblemIsSubComponent-                          "p-0.1" cname (ModuleTarget modname))-        , mkTargetModule "p-0.1" cname modname )-      | (cname, modname) <- [ (CTestName  "a-testsuite", "TestModule")-                            , (CBenchName "a-benchmark", "BenchModule")-                            , (CExeName   "an-exe",      "ExeModule")-                            , (CLibName,                 "P")-                            ]-      ] ++-      [ ( const (CmdTest.TargetProblemIsSubComponent-                          "p-0.1" cname (FileTarget fname))-        , mkTargetFile "p-0.1" cname fname)-      | (cname, fname) <- [ (CTestName  "a-testsuite", "Test.hs")-                          , (CBenchName "a-benchmark", "Bench.hs")-                          , (CExeName   "an-exe",      "Main.hs")-                          ]-      ]---testTargetProblemsBench :: ProjectConfig -> (String -> IO ()) -> Assertion-testTargetProblemsBench config reportSubCase = do--    reportSubCase "disabled by config"-    assertProjectTargetProblems-      "targets/benchmarks-disabled"-      config {-        projectConfigLocalPackages = (projectConfigLocalPackages config) {-          packageConfigBenchmarks = toFlag False-        }-      }-      CmdBench.selectPackageTargets-      CmdBench.selectComponentTarget-      CmdBench.TargetProblemCommon-      [ ( flip CmdBench.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CBenchName "user-disabled")-                                 TargetDisabledByUser True-               , AvailableTarget "p-0.1" (CBenchName "solver-disabled")-                                 TargetDisabledByUser True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "disabled by solver & buildable false"-    assertProjectTargetProblems-      "targets/benchmarks-disabled"-      config-      CmdBench.selectPackageTargets-      CmdBench.selectComponentTarget-      CmdBench.TargetProblemCommon-      [ ( flip CmdBench.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CBenchName "user-disabled")-                                 TargetDisabledBySolver True-               , AvailableTarget "p-0.1" (CBenchName "solver-disabled")-                                 TargetDisabledBySolver True-               ]-        , mkTargetPackage "p-0.1" )--      , ( flip CmdBench.TargetProblemNoneEnabled-               [ AvailableTarget "q-0.1" (CBenchName "buildable-false")-                                 TargetNotBuildable True-               ]-        , mkTargetPackage "q-0.1" )-      ]--    reportSubCase "empty-pkg"-    assertProjectTargetProblems-      "targets/empty-pkg" config-      CmdBench.selectPackageTargets-      CmdBench.selectComponentTarget-      CmdBench.TargetProblemCommon-      [ ( CmdBench.TargetProblemNoTargets, mkTargetPackage "p-0.1" )-      ]--    reportSubCase "no benchmarks"-    assertProjectTargetProblems-      "targets/simple"-      config-      CmdBench.selectPackageTargets-      CmdBench.selectComponentTarget-      CmdBench.TargetProblemCommon-      [ ( CmdBench.TargetProblemNoBenchmarks, mkTargetPackage "p-0.1" )-      , ( CmdBench.TargetProblemNoBenchmarks, mkTargetPackage "q-0.1" )-      ]--    reportSubCase "not a benchmark"-    assertProjectTargetProblems-      "targets/variety"-      config-      CmdBench.selectPackageTargets-      CmdBench.selectComponentTarget-      CmdBench.TargetProblemCommon $-      [ ( const (CmdBench.TargetProblemComponentNotBenchmark-                  "p-0.1" CLibName)-        , mkTargetComponent "p-0.1" CLibName )--      , ( const (CmdBench.TargetProblemComponentNotBenchmark-                  "p-0.1" (CExeName "an-exe"))-        , mkTargetComponent "p-0.1" (CExeName "an-exe") )--      , ( const (CmdBench.TargetProblemComponentNotBenchmark-                  "p-0.1" (CFLibName "libp"))-        , mkTargetComponent "p-0.1" (CFLibName "libp") )--      , ( const (CmdBench.TargetProblemComponentNotBenchmark-                  "p-0.1" (CTestName "a-testsuite"))-        , mkTargetComponent "p-0.1" (CTestName "a-testsuite") )-      ] ++-      [ ( const (CmdBench.TargetProblemIsSubComponent-                          "p-0.1" cname (ModuleTarget modname))-        , mkTargetModule "p-0.1" cname modname )-      | (cname, modname) <- [ (CTestName  "a-testsuite", "TestModule")-                            , (CBenchName "a-benchmark", "BenchModule")-                            , (CExeName   "an-exe",      "ExeModule")-                            , (CLibName,                 "P")-                            ]-      ] ++-      [ ( const (CmdBench.TargetProblemIsSubComponent-                          "p-0.1" cname (FileTarget fname))-        , mkTargetFile "p-0.1" cname fname)-      | (cname, fname) <- [ (CTestName  "a-testsuite", "Test.hs")-                          , (CBenchName "a-benchmark", "Bench.hs")-                          , (CExeName   "an-exe",      "Main.hs")-                          ]-      ]---testTargetProblemsHaddock :: ProjectConfig -> (String -> IO ()) -> Assertion-testTargetProblemsHaddock config reportSubCase = do--    reportSubCase "all-disabled"-    assertProjectTargetProblems-      "targets/all-disabled"-      config-      (let haddockFlags = mkHaddockFlags False True True False-        in CmdHaddock.selectPackageTargets haddockFlags)-      CmdHaddock.selectComponentTarget-      CmdHaddock.TargetProblemCommon-      [ ( flip CmdHaddock.TargetProblemNoneEnabled-               [ AvailableTarget "p-0.1" (CBenchName "user-disabled")-                                 TargetDisabledByUser True-               , AvailableTarget "p-0.1" (CTestName "solver-disabled")-                                 TargetDisabledBySolver True-               , AvailableTarget "p-0.1" (CExeName "buildable-false")-                                 TargetNotBuildable True-               , AvailableTarget "p-0.1" CLibName-                                 TargetNotBuildable True-               ]-        , mkTargetPackage "p-0.1" )-      ]--    reportSubCase "empty-pkg"-    assertProjectTargetProblems-      "targets/empty-pkg" config-      (let haddockFlags = mkHaddockFlags False False False False-        in CmdHaddock.selectPackageTargets haddockFlags)-      CmdHaddock.selectComponentTarget-      CmdHaddock.TargetProblemCommon-      [ ( CmdHaddock.TargetProblemNoTargets, mkTargetPackage "p-0.1" )-      ]--    reportSubCase "enabled component kinds"-    -- When we explicitly enable all the component kinds then selecting the-    -- whole package selects those component kinds too-    (_,elaboratedPlan,_) <- planProject "targets/variety" config-    let haddockFlags = mkHaddockFlags True True True True-     in assertProjectDistinctTargets-          elaboratedPlan-          (CmdHaddock.selectPackageTargets haddockFlags)-          CmdHaddock.selectComponentTarget-          CmdHaddock.TargetProblemCommon-          [ mkTargetPackage "p-0.1" ]-          [ ("p-0.1-inplace",             CLibName)-          , ("p-0.1-inplace-a-benchmark", CBenchName "a-benchmark")-          , ("p-0.1-inplace-a-testsuite", CTestName  "a-testsuite")-          , ("p-0.1-inplace-an-exe",      CExeName   "an-exe")-          , ("p-0.1-inplace-libp",        CFLibName  "libp")-          ]--    reportSubCase "disabled component kinds"-    -- When we explicitly disable all the component kinds then selecting the-    -- whole package only selects the library-    let haddockFlags = mkHaddockFlags False False False False-     in assertProjectDistinctTargets-          elaboratedPlan-          (CmdHaddock.selectPackageTargets haddockFlags)-          CmdHaddock.selectComponentTarget-          CmdHaddock.TargetProblemCommon-          [ mkTargetPackage "p-0.1" ]-          [ ("p-0.1-inplace", CLibName) ]--    reportSubCase "requested component kinds"-    -- When we selecting the package with an explicit filter then it does not-    -- matter if the config was to disable all the component kinds-    let haddockFlags = mkHaddockFlags False False False False-     in assertProjectDistinctTargets-          elaboratedPlan-          (CmdHaddock.selectPackageTargets haddockFlags)-          CmdHaddock.selectComponentTarget-          CmdHaddock.TargetProblemCommon-          [ TargetPackage TargetExplicitNamed ["p-0.1"] (Just FLibKind)-          , TargetPackage TargetExplicitNamed ["p-0.1"] (Just ExeKind)-          , TargetPackage TargetExplicitNamed ["p-0.1"] (Just TestKind)-          , TargetPackage TargetExplicitNamed ["p-0.1"] (Just BenchKind)-          ]-          [ ("p-0.1-inplace-a-benchmark", CBenchName "a-benchmark")-          , ("p-0.1-inplace-a-testsuite", CTestName  "a-testsuite")-          , ("p-0.1-inplace-an-exe",      CExeName   "an-exe")-          , ("p-0.1-inplace-libp",        CFLibName  "libp")-          ]-  where-    mkHaddockFlags flib exe test bench =-      defaultHaddockFlags {-        haddockForeignLibs = toFlag flib,-        haddockExecutables = toFlag exe,-        haddockTestSuites  = toFlag test,-        haddockBenchmarks  = toFlag bench-      }--assertProjectDistinctTargets-  :: forall err. (Eq err, Show err) =>-     ElaboratedInstallPlan-  -> (forall k. TargetSelector -> [AvailableTarget k] -> Either err [k])-  -> (forall k. SubComponentTarget ->  AvailableTarget k  -> Either err  k )-  -> (TargetProblemCommon -> err)-  -> [TargetSelector]-  -> [(UnitId, ComponentName)]-  -> Assertion-assertProjectDistinctTargets elaboratedPlan-                             selectPackageTargets-                             selectComponentTarget-                             liftProblem-                             targetSelectors-                             expectedTargets-  | Right targets <- results-  = distinctTargetComponents targets @?= Set.fromList expectedTargets--  | otherwise-  = assertFailure $ "assertProjectDistinctTargets: expected "-                 ++ "(Right targets) but got " ++ show results-  where-    results = resolveTargets-                selectPackageTargets-                selectComponentTarget-                liftProblem-                elaboratedPlan-                targetSelectors---assertProjectTargetProblems-  :: forall err. (Eq err, Show err) =>-     FilePath -> ProjectConfig-  -> (forall k. TargetSelector-             -> [AvailableTarget k]-             -> Either err [k])-  -> (forall k. SubComponentTarget-             -> AvailableTarget k-             -> Either err k )-  -> (TargetProblemCommon -> err)-  -> [(TargetSelector -> err, TargetSelector)]-  -> Assertion-assertProjectTargetProblems testdir config-                            selectPackageTargets-                            selectComponentTarget-                            liftProblem-                            cases = do-    (_,elaboratedPlan,_) <- planProject testdir config-    assertTargetProblems-      elaboratedPlan-      selectPackageTargets-      selectComponentTarget-      liftProblem-      cases---assertTargetProblems-  :: forall err. (Eq err, Show err) =>-     ElaboratedInstallPlan-  -> (forall k. TargetSelector -> [AvailableTarget k] -> Either err [k])-  -> (forall k. SubComponentTarget ->  AvailableTarget k  -> Either err  k )-  -> (TargetProblemCommon -> err)-  -> [(TargetSelector -> err, TargetSelector)]-  -> Assertion-assertTargetProblems elaboratedPlan-                     selectPackageTargets-                     selectComponentTarget-                     liftProblem =-    mapM_ (uncurry assertTargetProblem)-  where-    assertTargetProblem expected targetSelector =-      let res = resolveTargets selectPackageTargets selectComponentTarget-                               liftProblem elaboratedPlan [targetSelector] in-      case res of-        Left [problem] ->-          problem @?= expected targetSelector--        unexpected ->-          assertFailure $ "expected resolveTargets result: (Left [problem]) "-                       ++ "but got: " ++ show unexpected---testExceptionInFindingPackage :: ProjectConfig -> Assertion-testExceptionInFindingPackage config = do-    BadPackageLocations _ locs <- expectException "BadPackageLocations" $-      void $ planProject testdir config-    case locs of-      [BadLocGlobEmptyMatch "./*.cabal"] -> return ()-      _ -> assertFailure "expected BadLocGlobEmptyMatch"-    cleanProject testdir-  where-    testdir = "exception/no-pkg"---testExceptionInFindingPackage2 :: ProjectConfig -> Assertion-testExceptionInFindingPackage2 config = do-    BadPackageLocations _ locs <- expectException "BadPackageLocations" $-      void $ planProject testdir config-    case locs of-      [BadPackageLocationFile (BadLocDirNoCabalFile ".")] -> return ()-      _ -> assertFailure $ "expected BadLocDirNoCabalFile, got " ++ show locs-    cleanProject testdir-  where-    testdir = "exception/no-pkg2"---testExceptionInProjectConfig :: ProjectConfig -> Assertion-testExceptionInProjectConfig config = do-    BadPerPackageCompilerPaths ps <- expectException "BadPerPackageCompilerPaths" $-      void $ planProject testdir config-    case ps of-      [(pn,"ghc")] | "foo" == pn -> return ()-      _ -> assertFailure $ "expected (PackageName \"foo\",\"ghc\"), got "-                        ++ show ps-    cleanProject testdir-  where-    testdir = "exception/bad-config"---testExceptionInConfigureStep :: ProjectConfig -> Assertion-testExceptionInConfigureStep config = do-    (plan, res) <- executePlan =<< planProject testdir config-    (_pkga1, failure) <- expectPackageFailed plan res pkgidA1-    case buildFailureReason failure of-      ConfigureFailed _ -> return ()-      _ -> assertFailure $ "expected ConfigureFailed, got " ++ show failure -    cleanProject testdir-  where-    testdir = "exception/configure"-    pkgidA1 = PackageIdentifier "a" (mkVersion [1])---testExceptionInBuildStep :: ProjectConfig -> Assertion-testExceptionInBuildStep config = do-    (plan, res) <- executePlan =<< planProject testdir config-    (_pkga1, failure) <- expectPackageFailed plan res pkgidA1-    expectBuildFailed failure-  where-    testdir = "exception/build"-    pkgidA1 = PackageIdentifier "a" (mkVersion [1])--testSetupScriptStyles :: ProjectConfig -> (String -> IO ()) -> Assertion-testSetupScriptStyles config reportSubCase = do--  reportSubCase (show SetupCustomExplicitDeps)--  plan0@(_,_,sharedConfig) <- planProject testdir1 config--  let isOSX (Platform _ OSX) = True-      isOSX _ = False-  -- Skip the Custom tests when the shipped Cabal library is buggy-  unless (isOSX (pkgConfigPlatform sharedConfig)-       && compilerVersion (pkgConfigCompiler sharedConfig) < mkVersion [7,10]) $ do--    (plan1, res1) <- executePlan plan0-    (pkg1,  _)    <- expectPackageInstalled plan1 res1 pkgidA-    elabSetupScriptStyle pkg1 @?= SetupCustomExplicitDeps-    hasDefaultSetupDeps pkg1 @?= Just False-    marker1 <- readFile (basedir </> testdir1 </> "marker")-    marker1 @?= "ok"-    removeFile (basedir </> testdir1 </> "marker")--    -- implicit deps implies 'Cabal < 2' which conflicts w/ GHC 8.2 or later-    when (compilerVersion (pkgConfigCompiler sharedConfig) < mkVersion [8,2]) $ do-      reportSubCase (show SetupCustomImplicitDeps)-      (plan2, res2) <- executePlan =<< planProject testdir2 config-      (pkg2,  _)    <- expectPackageInstalled plan2 res2 pkgidA-      elabSetupScriptStyle pkg2 @?= SetupCustomImplicitDeps-      hasDefaultSetupDeps pkg2 @?= Just True-      marker2 <- readFile (basedir </> testdir2 </> "marker")-      marker2 @?= "ok"-      removeFile (basedir </> testdir2 </> "marker")--    reportSubCase (show SetupNonCustomInternalLib)-    (plan3, res3) <- executePlan =<< planProject testdir3 config-    (pkg3,  _)    <- expectPackageInstalled plan3 res3 pkgidA-    elabSetupScriptStyle pkg3 @?= SetupNonCustomInternalLib-{--    --TODO: the SetupNonCustomExternalLib case is hard to test since it-    -- requires a version of Cabal that's later than the one we're testing-    -- e.g. needs a .cabal file that specifies cabal-version: >= 2.0-    -- and a corresponding Cabal package that we can use to try and build a-    -- default Setup.hs.-    reportSubCase (show SetupNonCustomExternalLib)-    (plan4, res4) <- executePlan =<< planProject testdir4 config-    (pkg4,  _)    <- expectPackageInstalled plan4 res4 pkgidA-    pkgSetupScriptStyle pkg4 @?= SetupNonCustomExternalLib--}-  where-    testdir1 = "build/setup-custom1"-    testdir2 = "build/setup-custom2"-    testdir3 = "build/setup-simple"-    pkgidA   = PackageIdentifier "a" (mkVersion [0,1])-    -- The solver fills in default setup deps explicitly, but marks them as such-    hasDefaultSetupDeps = fmap defaultSetupDepends-                        . setupBuildInfo . elabPkgDescription---- | Test the behaviour with and without @--keep-going@----testBuildKeepGoing :: ProjectConfig -> Assertion-testBuildKeepGoing config = do-    -- P is expected to fail, Q does not depend on P but without-    -- parallel build and without keep-going then we don't build Q yet.-    (plan1, res1) <- executePlan =<< planProject testdir (config  <> keepGoing False)-    (_, failure1) <- expectPackageFailed plan1 res1 "p-0.1"-    expectBuildFailed failure1-    _ <- expectPackageConfigured plan1 res1 "q-0.1"--    -- With keep-going then we should go on to sucessfully build Q-    (plan2, res2) <- executePlan-                 =<< planProject testdir (config <> keepGoing True)-    (_, failure2) <- expectPackageFailed plan2 res2 "p-0.1"-    expectBuildFailed failure2-    _ <- expectPackageInstalled plan2 res2 "q-0.1"-    return ()-  where-    testdir = "build/keep-going"-    keepGoing kg =-      mempty {-        projectConfigBuildOnly = mempty {-          projectConfigKeepGoing = toFlag kg-        }-      }---- | See <https://github.com/haskell/cabal/issues/3324>----testRegressionIssue3324 :: ProjectConfig -> Assertion-testRegressionIssue3324 config = do-    -- expected failure first time due to missing dep-    (plan1, res1) <- executePlan =<< planProject testdir config-    (_pkgq, failure) <- expectPackageFailed plan1 res1 "q-0.1"-    expectBuildFailed failure--    -- add the missing dep, now it should work-    let qcabal  = basedir </> testdir </> "q" </> "q.cabal"-    withFileFinallyRestore qcabal $ do-      appendFile qcabal ("  build-depends: p\n")-      (plan2, res2) <- executePlan =<< planProject testdir config-      _ <- expectPackageInstalled plan2 res2 "p-0.1"-      _ <- expectPackageInstalled plan2 res2 "q-0.1"-      return ()-  where-    testdir = "regression/3324"--------------------------------------- Test utils to plan and build-----basedir :: FilePath-basedir = "tests" </> "IntegrationTests2"--dirActions :: FilePath -> TS.DirActions IO-dirActions testdir =-    defaultDirActions {-      TS.doesFileExist       = \p ->-        TS.doesFileExist defaultDirActions (virtcwd </> p),--      TS.doesDirectoryExist  = \p ->-        TS.doesDirectoryExist defaultDirActions (virtcwd </> p),--      TS.canonicalizePath    = \p ->-        TS.canonicalizePath defaultDirActions (virtcwd </> p),--      TS.getCurrentDirectory =-        TS.canonicalizePath defaultDirActions virtcwd-    }-  where-    virtcwd = basedir </> testdir--type ProjDetails = (DistDirLayout,-                    CabalDirLayout,-                    ProjectConfig,-                    [PackageSpecifier UnresolvedSourcePackage],-                    BuildTimeSettings)--configureProject :: FilePath -> ProjectConfig -> IO ProjDetails-configureProject testdir cliConfig = do-    cabalDir <- defaultCabalDir-    let cabalDirLayout = defaultCabalDirLayout cabalDir--    projectRootDir <- canonicalizePath (basedir </> testdir)-    isexplict      <- doesFileExist (projectRootDir </> "cabal.project")-    let projectRoot-          | isexplict = ProjectRootExplicit projectRootDir-                                           (projectRootDir </> "cabal.project")-          | otherwise = ProjectRootImplicit projectRootDir-        distDirLayout = defaultDistDirLayout projectRoot Nothing--    -- Clear state between test runs. The state remains if the previous run-    -- ended in an exception (as we leave the files to help with debugging).-    cleanProject testdir--    (projectConfig, localPackages) <--      rebuildProjectConfig verbosity-                           distDirLayout-                           cliConfig--    let buildSettings = resolveBuildTimeSettings-                          verbosity cabalDirLayout-                          projectConfig--    return (distDirLayout,-            cabalDirLayout,-            projectConfig,-            localPackages,-            buildSettings)--type PlanDetails = (ProjDetails,-                    ElaboratedInstallPlan,-                    ElaboratedSharedConfig)--planProject :: FilePath -> ProjectConfig -> IO PlanDetails-planProject testdir cliConfig = do--    projDetails@-      (distDirLayout,-       cabalDirLayout,-       projectConfig,-       localPackages,-       _buildSettings) <- configureProject testdir cliConfig--    (elaboratedPlan, _, elaboratedShared) <--      rebuildInstallPlan verbosity-                         distDirLayout cabalDirLayout-                         projectConfig-                         localPackages--    return (projDetails,-            elaboratedPlan,-            elaboratedShared)--executePlan :: PlanDetails -> IO (ElaboratedInstallPlan, BuildOutcomes)-executePlan ((distDirLayout, cabalDirLayout, _, _, buildSettings),-             elaboratedPlan,-             elaboratedShared) = do--    let targets :: Map.Map UnitId [ComponentTarget]-        targets =-          Map.fromList-            [ (unitid, [ComponentTarget cname WholeComponent])-            | ts <- Map.elems (availableTargets elaboratedPlan)-            , AvailableTarget {-                availableTargetStatus = TargetBuildable (unitid, cname) _-              } <- ts-            ]-        elaboratedPlan' = pruneInstallPlanToTargets-                            TargetActionBuild targets-                            elaboratedPlan--    pkgsBuildStatus <--      rebuildTargetsDryRun distDirLayout elaboratedShared-                           elaboratedPlan'--    let elaboratedPlan'' = improveInstallPlanWithUpToDatePackages-                             pkgsBuildStatus elaboratedPlan'--    buildOutcomes <--      rebuildTargets verbosity-                     distDirLayout-                     (cabalStoreDirLayout cabalDirLayout)-                     elaboratedPlan''-                     elaboratedShared-                     pkgsBuildStatus-                     -- Avoid trying to use act-as-setup mode:-                     buildSettings { buildSettingNumJobs = 1 }--    return (elaboratedPlan'', buildOutcomes)--cleanProject :: FilePath -> IO ()-cleanProject testdir = do-    alreadyExists <- doesDirectoryExist distDir-    when alreadyExists $ removeDirectoryRecursive distDir-  where-    projectRoot    = ProjectRootImplicit (basedir </> testdir)-    distDirLayout  = defaultDistDirLayout projectRoot Nothing-    distDir        = distDirectory distDirLayout---verbosity :: Verbosity-verbosity = minBound --normal --verbose --maxBound --minBound-------------------------------------------------- Tasty integration to adjust the config-----withProjectConfig :: (ProjectConfig -> TestTree) -> TestTree-withProjectConfig testtree =-    askOption $ \ghcPath ->-      testtree (mkProjectConfig ghcPath)--mkProjectConfig :: GhcPath -> ProjectConfig-mkProjectConfig (GhcPath ghcPath) =-    mempty {-      projectConfigShared = mempty {-        projectConfigHcPath = maybeToFlag ghcPath-      },-     projectConfigBuildOnly = mempty {-       projectConfigNumJobs = toFlag (Just 1)-     }-    }-  where-    maybeToFlag = maybe mempty toFlag---data GhcPath = GhcPath (Maybe FilePath)-  deriving Typeable--instance IsOption GhcPath where-  defaultValue = GhcPath Nothing-  optionName   = Tagged "with-ghc"-  optionHelp   = Tagged "The ghc compiler to use"-  parseValue   = Just . GhcPath . Just--projectConfigOptionDescriptions :: [OptionDescription]-projectConfigOptionDescriptions = [Option (Proxy :: Proxy GhcPath)]--------------------------------------------- HUint style utils for this context-----expectException :: Exception e => String -> IO a -> IO e-expectException expected action = do-    res <- try action-    case res of-      Left  e -> return e-      Right _ -> throwIO $ HUnitFailure Nothing $ "expected an exception " ++ expected--expectPackagePreExisting :: ElaboratedInstallPlan -> BuildOutcomes -> PackageId-                         -> IO InstalledPackageInfo-expectPackagePreExisting plan buildOutcomes pkgid = do-    planpkg <- expectPlanPackage plan pkgid-    case (planpkg, InstallPlan.lookupBuildOutcome planpkg buildOutcomes) of-      (InstallPlan.PreExisting pkg, Nothing)-                       -> return pkg-      (_, buildResult) -> unexpectedBuildResult "PreExisting" planpkg buildResult--expectPackageConfigured :: ElaboratedInstallPlan -> BuildOutcomes -> PackageId-                        -> IO ElaboratedConfiguredPackage-expectPackageConfigured plan buildOutcomes pkgid = do-    planpkg <- expectPlanPackage plan pkgid-    case (planpkg, InstallPlan.lookupBuildOutcome planpkg buildOutcomes) of-      (InstallPlan.Configured pkg, Nothing)-                       -> return pkg-      (_, buildResult) -> unexpectedBuildResult "Configured" planpkg buildResult--expectPackageInstalled :: ElaboratedInstallPlan -> BuildOutcomes -> PackageId-                       -> IO (ElaboratedConfiguredPackage, BuildResult)-expectPackageInstalled plan buildOutcomes pkgid = do-    planpkg <- expectPlanPackage plan pkgid-    case (planpkg, InstallPlan.lookupBuildOutcome planpkg buildOutcomes) of-      (InstallPlan.Configured pkg, Just (Right result))-                       -> return (pkg, result)-      (_, buildResult) -> unexpectedBuildResult "Installed" planpkg buildResult--expectPackageFailed :: ElaboratedInstallPlan -> BuildOutcomes -> PackageId-                    -> IO (ElaboratedConfiguredPackage, BuildFailure)-expectPackageFailed plan buildOutcomes pkgid = do-    planpkg <- expectPlanPackage plan pkgid-    case (planpkg, InstallPlan.lookupBuildOutcome planpkg buildOutcomes) of-      (InstallPlan.Configured pkg, Just (Left failure))-                       -> return (pkg, failure)-      (_, buildResult) -> unexpectedBuildResult "Failed" planpkg buildResult--unexpectedBuildResult :: String -> ElaboratedPlanPackage-                      -> Maybe (Either BuildFailure BuildResult) -> IO a-unexpectedBuildResult expected planpkg buildResult =-    throwIO $ HUnitFailure Nothing $-         "expected to find " ++ display (packageId planpkg) ++ " in the "-      ++ expected ++ " state, but it is actually in the " ++ actual ++ " state."-  where-    actual = case (buildResult, planpkg) of-      (Nothing, InstallPlan.PreExisting{})       -> "PreExisting"-      (Nothing, InstallPlan.Configured{})        -> "Configured"-      (Just (Right _), InstallPlan.Configured{}) -> "Installed"-      (Just (Left  _), InstallPlan.Configured{}) -> "Failed"-      _                                          -> "Impossible!"--expectPlanPackage :: ElaboratedInstallPlan -> PackageId-                  -> IO ElaboratedPlanPackage-expectPlanPackage plan pkgid =-    case [ pkg-         | pkg <- InstallPlan.toList plan-         , packageId pkg == pkgid ] of-      [pkg] -> return pkg-      []    -> throwIO $ HUnitFailure Nothing $-                   "expected to find " ++ display pkgid-                ++ " in the install plan but it's not there"-      _     -> throwIO $ HUnitFailure Nothing $-                   "expected to find only one instance of " ++ display pkgid-                ++ " in the install plan but there's several"--expectBuildFailed :: BuildFailure -> IO ()-expectBuildFailed (BuildFailure _ (BuildFailed _)) = return ()-expectBuildFailed (BuildFailure _ reason) =-    assertFailure $ "expected BuildFailed, got " ++ show reason-------------------------------------------- Other utils------- | Allow altering a file during a test, but then restore it afterwards----withFileFinallyRestore :: FilePath -> IO a -> IO a-withFileFinallyRestore file action = do-    copyFile file backup-    action `finally` renameFile backup file-  where-    backup = file <.> "backup"
+ tests/IntegrationTests2/build/local-tarball/cabal.project view
@@ -0,0 +1,2 @@+packages: p-0.1.tar.gz+          q/
+ tests/IntegrationTests2/build/local-tarball/p-0.1.tar.gz view

binary file changed (absent → 319 bytes)

+ tests/IntegrationTests2/build/local-tarball/q/Q.hs view
@@ -0,0 +1,5 @@+module Q where++import P++q = p ++ " world"
+ tests/IntegrationTests2/build/local-tarball/q/q.cabal view
@@ -0,0 +1,8 @@+name: q+version: 0.1+build-type: Simple+cabal-version: >= 1.2++library+  exposed-modules: Q+  build-depends: base, p
− tests/MemoryUsageTests.hs
@@ -1,15 +0,0 @@-module MemoryUsageTests where--import Test.Tasty--import qualified UnitTests.Distribution.Solver.Modular.MemoryUsage--tests :: TestTree-tests =-  testGroup "Memory Usage"-  [ testGroup "UnitTests.Distribution.Solver.Modular.MemoryUsage"-        UnitTests.Distribution.Solver.Modular.MemoryUsage.tests-  ]--main :: IO ()-main = defaultMain tests
− tests/SolverQuickCheck.hs
@@ -1,16 +0,0 @@-module SolverQuickCheck where--import Test.Tasty--import qualified UnitTests.Distribution.Solver.Modular.QuickCheck---tests :: TestTree-tests =-  testGroup "Solver QuickCheck"-  [ testGroup "UnitTests.Distribution.Solver.Modular.QuickCheck"-        UnitTests.Distribution.Solver.Modular.QuickCheck.tests-  ]--main :: IO ()-main = defaultMain tests
− tests/UnitTests.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}--module UnitTests where--import Test.Tasty--import Distribution.Simple.Utils-import Distribution.Verbosity--import Distribution.Compat.Time--import qualified UnitTests.Distribution.Solver.Modular.Builder-import qualified UnitTests.Distribution.Solver.Modular.WeightedPSQ-import qualified UnitTests.Distribution.Solver.Modular.Solver-import qualified UnitTests.Distribution.Solver.Modular.RetryLog-import qualified UnitTests.Distribution.Client.FileMonitor-import qualified UnitTests.Distribution.Client.Glob-import qualified UnitTests.Distribution.Client.GZipUtils-import qualified UnitTests.Distribution.Client.Sandbox-import qualified UnitTests.Distribution.Client.Sandbox.Timestamp-import qualified UnitTests.Distribution.Client.Store-import qualified UnitTests.Distribution.Client.Tar-import qualified UnitTests.Distribution.Client.Targets-import qualified UnitTests.Distribution.Client.UserConfig-import qualified UnitTests.Distribution.Client.ProjectConfig-import qualified UnitTests.Distribution.Client.JobControl-import qualified UnitTests.Distribution.Client.IndexUtils.Timestamp-import qualified UnitTests.Distribution.Client.InstallPlan--import UnitTests.Options---tests :: Int -> TestTree-tests mtimeChangeCalibrated =-  askOption $ \(OptionMtimeChangeDelay mtimeChangeProvided) ->-  let mtimeChange = if mtimeChangeProvided /= 0-                    then mtimeChangeProvided-                    else mtimeChangeCalibrated-  in-  testGroup "Unit Tests"-  [ testGroup "UnitTests.Distribution.Solver.Modular.Builder"-        UnitTests.Distribution.Solver.Modular.Builder.tests-  , testGroup "UnitTests.Distribution.Solver.Modular.WeightedPSQ"-        UnitTests.Distribution.Solver.Modular.WeightedPSQ.tests-  , testGroup "UnitTests.Distribution.Solver.Modular.Solver"-        UnitTests.Distribution.Solver.Modular.Solver.tests-  , testGroup "UnitTests.Distribution.Solver.Modular.RetryLog"-        UnitTests.Distribution.Solver.Modular.RetryLog.tests-  , testGroup "UnitTests.Distribution.Client.FileMonitor" $-        UnitTests.Distribution.Client.FileMonitor.tests mtimeChange-  , testGroup "UnitTests.Distribution.Client.Glob"-        UnitTests.Distribution.Client.Glob.tests-  , testGroup "Distribution.Client.GZipUtils"-       UnitTests.Distribution.Client.GZipUtils.tests-  , testGroup "Distribution.Client.Sandbox"-       UnitTests.Distribution.Client.Sandbox.tests-  , testGroup "Distribution.Client.Sandbox.Timestamp"-       UnitTests.Distribution.Client.Sandbox.Timestamp.tests-  , testGroup "Distribution.Client.Store"-       UnitTests.Distribution.Client.Store.tests-  , testGroup "Distribution.Client.Tar"-       UnitTests.Distribution.Client.Tar.tests-  , testGroup "Distribution.Client.Targets"-       UnitTests.Distribution.Client.Targets.tests-  , testGroup "UnitTests.Distribution.Client.UserConfig"-       UnitTests.Distribution.Client.UserConfig.tests-  , testGroup "UnitTests.Distribution.Client.ProjectConfig"-       UnitTests.Distribution.Client.ProjectConfig.tests-  , testGroup "UnitTests.Distribution.Client.JobControl"-       UnitTests.Distribution.Client.JobControl.tests-  , testGroup "UnitTests.Distribution.Client.IndexUtils.Timestamp"-       UnitTests.Distribution.Client.IndexUtils.Timestamp.tests-  , testGroup "UnitTests.Distribution.Client.InstallPlan"-       UnitTests.Distribution.Client.InstallPlan.tests-  ]--main :: IO ()-main = do-  (mtimeChange, mtimeChange') <- calibrateMtimeChangeDelay-  let toMillis :: Int -> Double-      toMillis x = fromIntegral x / 1000.0-  notice normal $ "File modification time resolution calibration completed, "-    ++ "maximum delay observed: "-    ++ (show . toMillis $ mtimeChange ) ++ " ms. "-    ++ "Will be using delay of " ++ (show . toMillis $ mtimeChange')-    ++ " for test runs."-  defaultMainWithIngredients-         (includingOptions extraOptions : defaultIngredients)-         (tests mtimeChange')-
− tests/UnitTests/Distribution/Client/ArbitraryInstances.hs
@@ -1,180 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module UnitTests.Distribution.Client.ArbitraryInstances (-    adjustSize,-    shortListOf,-    shortListOf1,-    arbitraryFlag,-    ShortToken(..),-    arbitraryShortToken,-    NonMEmpty(..),-    NoShrink(..),-  ) where--import Data.Char-import Data.List-#if !MIN_VERSION_base(4,8,0)-import Data.Monoid-import Control.Applicative-#endif-import Control.Monad--import Distribution.Version-import Distribution.Types.Dependency-import Distribution.Package-import Distribution.System-import Distribution.Verbosity--import Distribution.Simple.Setup-import Distribution.Simple.InstallDirs--import Distribution.Utils.NubList--import Distribution.Client.IndexUtils.Timestamp--import Test.QuickCheck---adjustSize :: (Int -> Int) -> Gen a -> Gen a-adjustSize adjust gen = sized (\n -> resize (adjust n) gen)--shortListOf :: Int -> Gen a -> Gen [a]-shortListOf bound gen =-    sized $ \n -> do-      k <- choose (0, (n `div` 2) `min` bound)-      vectorOf k gen--shortListOf1 :: Int -> Gen a -> Gen [a]-shortListOf1 bound gen =-    sized $ \n -> do-      k <- choose (1, 1 `max` ((n `div` 2) `min` bound))-      vectorOf k gen--newtype ShortToken = ShortToken { getShortToken :: String }-  deriving Show--instance Arbitrary ShortToken where-  arbitrary =-    ShortToken <$>-      (shortListOf1 5 (choose ('#', '~'))-       `suchThat` (not . ("[]" `isPrefixOf`)))-    --TODO: [code cleanup] need to replace parseHaskellString impl to stop-    -- accepting Haskell list syntax [], ['a'] etc, just allow String syntax.-    -- Workaround, don't generate [] as this does not round trip.---  shrink (ShortToken cs) =-    [ ShortToken cs' | cs' <- shrink cs, not (null cs') ]--arbitraryShortToken :: Gen String-arbitraryShortToken = getShortToken <$> arbitrary--instance Arbitrary Version where-  arbitrary = do-    branch <- shortListOf1 4 $-                frequency [(3, return 0)-                          ,(3, return 1)-                          ,(2, return 2)-                          ,(1, return 3)]-    return (mkVersion branch)-    where--  shrink ver = [ mkVersion branch' | branch' <- shrink (versionNumbers ver)-                                   , not (null branch') ]--instance Arbitrary VersionRange where-  arbitrary = canonicaliseVersionRange <$> sized verRangeExp-    where-      verRangeExp n = frequency $-        [ (2, return anyVersion)-        , (1, liftM thisVersion arbitrary)-        , (1, liftM laterVersion arbitrary)-        , (1, liftM orLaterVersion arbitrary)-        , (1, liftM orLaterVersion' arbitrary)-        , (1, liftM earlierVersion arbitrary)-        , (1, liftM orEarlierVersion arbitrary)-        , (1, liftM orEarlierVersion' arbitrary)-        , (1, liftM withinVersion arbitrary)-        , (2, liftM VersionRangeParens arbitrary)-        ] ++ if n == 0 then [] else-        [ (2, liftM2 unionVersionRanges     verRangeExp2 verRangeExp2)-        , (2, liftM2 intersectVersionRanges verRangeExp2 verRangeExp2)-        ]-        where-          verRangeExp2 = verRangeExp (n `div` 2)--      orLaterVersion'   v =-        unionVersionRanges (laterVersion v)   (thisVersion v)-      orEarlierVersion' v =-        unionVersionRanges (earlierVersion v) (thisVersion v)--      canonicaliseVersionRange = fromVersionIntervals . toVersionIntervals--instance Arbitrary PackageName where-    arbitrary = mkPackageName . intercalate "-" <$> shortListOf1 2 nameComponent-      where-        nameComponent = shortListOf1 5 (elements packageChars)-                        `suchThat` (not . all isDigit)-        packageChars  = filter isAlphaNum ['\0'..'\127']--instance Arbitrary Dependency where-    arbitrary = Dependency <$> arbitrary <*> arbitrary--instance Arbitrary OS where-    arbitrary = elements knownOSs--instance Arbitrary Arch where-    arbitrary = elements knownArches--instance Arbitrary Platform where-    arbitrary = Platform <$> arbitrary <*> arbitrary--instance Arbitrary a => Arbitrary (Flag a) where-    arbitrary = arbitraryFlag arbitrary-    shrink NoFlag   = []-    shrink (Flag x) = NoFlag : [ Flag x' | x' <- shrink x ]--arbitraryFlag :: Gen a -> Gen (Flag a)-arbitraryFlag genA =-    sized $ \sz ->-      case sz of-        0 -> pure NoFlag-        _ -> frequency [ (1, pure NoFlag)-                       , (3, Flag <$> genA) ]---instance (Arbitrary a, Ord a) => Arbitrary (NubList a) where-    arbitrary = toNubList <$> arbitrary-    shrink xs = [ toNubList [] | (not . null) (fromNubList xs) ]-    -- try empty, otherwise don't shrink as it can loop--instance Arbitrary Verbosity where-    arbitrary = elements [minBound..maxBound]--instance Arbitrary PathTemplate where-    arbitrary = toPathTemplate <$> arbitraryShortToken-    shrink t  = [ toPathTemplate s | s <- shrink (show t), not (null s) ]---newtype NonMEmpty a = NonMEmpty { getNonMEmpty :: a }-  deriving (Eq, Ord, Show)--instance (Arbitrary a, Monoid a, Eq a) => Arbitrary (NonMEmpty a) where-  arbitrary = NonMEmpty <$> (arbitrary `suchThat` (/= mempty))-  shrink (NonMEmpty x) = [ NonMEmpty x' | x' <- shrink x, x' /= mempty ]--newtype NoShrink a = NoShrink { getNoShrink :: a }-  deriving (Eq, Ord, Show)--instance Arbitrary a => Arbitrary (NoShrink a) where-    arbitrary = NoShrink <$> arbitrary-    shrink _  = []--instance Arbitrary Timestamp where-    arbitrary = (maybe (toEnum 0) id . epochTimeToTimestamp) <$> arbitrary--instance Arbitrary IndexState where-    arbitrary = frequency [ (1, pure IndexStateHead)-                          , (50, IndexStateTime <$> arbitrary)-                          ]
− tests/UnitTests/Distribution/Client/FileMonitor.hs
@@ -1,857 +0,0 @@-module UnitTests.Distribution.Client.FileMonitor (tests) where--import Control.Monad-import Control.Exception-import Control.Concurrent (threadDelay)-import qualified Data.Set as Set-import System.FilePath-import qualified System.Directory as IO-import Prelude hiding (writeFile)-import qualified Prelude as IO (writeFile)--import Distribution.Text (simpleParse)-import Distribution.Compat.Binary-import Distribution.Simple.Utils (withTempDirectory)-import Distribution.Verbosity (silent)--import Distribution.Client.FileMonitor-import Distribution.Compat.Time--import Test.Tasty-import Test.Tasty.HUnit---tests :: Int -> [TestTree]-tests mtimeChange =-  [ testCase "sanity check mtimes"   $ testFileMTimeSanity mtimeChange-  , testCase "sanity check dirs"     $ testDirChangeSanity mtimeChange-  , testCase "no monitor cache"      testNoMonitorCache-  , testCase "corrupt monitor cache" testCorruptMonitorCache-  , testCase "empty monitor"         testEmptyMonitor-  , testCase "missing file"          testMissingFile-  , testCase "change file"           $ testChangedFile mtimeChange-  , testCase "file mtime vs content" $ testChangedFileMtimeVsContent mtimeChange-  , testCase "update during action"  $ testUpdateDuringAction mtimeChange-  , testCase "remove file"           testRemoveFile-  , testCase "non-existent file"     testNonExistentFile-  , testCase "changed file type"     $ testChangedFileType mtimeChange-  , testCase "several monitor kinds" $ testMultipleMonitorKinds mtimeChange--  , testGroup "glob matches"-    [ testCase "no change"           testGlobNoChange-    , testCase "add match"           $ testGlobAddMatch mtimeChange-    , testCase "remove match"        $ testGlobRemoveMatch mtimeChange-    , testCase "change match"        $ testGlobChangeMatch mtimeChange--    , testCase "add match subdir"    $ testGlobAddMatchSubdir mtimeChange-    , testCase "remove match subdir" $ testGlobRemoveMatchSubdir mtimeChange-    , testCase "change match subdir" $ testGlobChangeMatchSubdir mtimeChange--    , testCase "match toplevel dir"  $ testGlobMatchTopDir mtimeChange-    , testCase "add non-match"       $ testGlobAddNonMatch mtimeChange-    , testCase "remove non-match"    $ testGlobRemoveNonMatch mtimeChange--    , testCase "add non-match"       $ testGlobAddNonMatchSubdir mtimeChange-    , testCase "remove non-match"    $ testGlobRemoveNonMatchSubdir mtimeChange--    , testCase "invariant sorted 1"  $ testInvariantMonitorStateGlobFiles-                                         mtimeChange-    , testCase "invariant sorted 2"  $ testInvariantMonitorStateGlobDirs-                                         mtimeChange--    , testCase "match dirs"          $ testGlobMatchDir mtimeChange-    , testCase "match dirs only"     $ testGlobMatchDirOnly mtimeChange-    , testCase "change file type"    $ testGlobChangeFileType mtimeChange-    , testCase "absolute paths"      $ testGlobAbsolutePath mtimeChange-    ]--  , testCase "value unchanged"       testValueUnchanged-  , testCase "value changed"         testValueChanged-  , testCase "value & file changed"  $ testValueAndFileChanged mtimeChange-  , testCase "value updated"         testValueUpdated-  ]---- Check the file system behaves the way we expect it to---- we rely on file mtimes having a reasonable resolution-testFileMTimeSanity :: Int -> Assertion-testFileMTimeSanity mtimeChange =-  withTempDirectory silent "." "file-status-" $ \dir -> do-    replicateM_ 10 $ do-      IO.writeFile (dir </> "a") "content"-      t1 <- getModTime (dir </> "a")-      threadDelay mtimeChange-      IO.writeFile (dir </> "a") "content"-      t2 <- getModTime (dir </> "a")-      assertBool "expected different file mtimes" (t2 > t1)---- We rely on directories changing mtime when entries are added or removed-testDirChangeSanity :: Int -> Assertion-testDirChangeSanity mtimeChange =-  withTempDirectory silent "." "dir-mtime-" $ \dir -> do--    expectMTimeChange dir "file add" $-      IO.writeFile (dir </> "file") "content"--    expectMTimeSame dir "file content change" $-      IO.writeFile (dir </> "file") "new content"--    expectMTimeChange dir "file del" $-      IO.removeFile (dir </> "file")--    expectMTimeChange dir "subdir add" $-      IO.createDirectory (dir </> "dir")--    expectMTimeSame dir "subdir file add" $-      IO.writeFile (dir </> "dir" </> "file") "content"--    expectMTimeChange dir "subdir file move in" $-      IO.renameFile (dir </> "dir" </> "file") (dir </> "file")--    expectMTimeChange dir "subdir file move out" $-      IO.renameFile (dir </> "file") (dir </> "dir" </> "file")--    expectMTimeSame dir "subdir dir add" $-      IO.createDirectory (dir </> "dir" </> "subdir")--    expectMTimeChange dir "subdir dir move in" $-      IO.renameDirectory (dir </> "dir" </> "subdir") (dir </> "subdir")--    expectMTimeChange dir "subdir dir move out" $-      IO.renameDirectory (dir </> "subdir") (dir </> "dir" </> "subdir")--  where-    expectMTimeChange, expectMTimeSame :: FilePath -> String -> IO ()-                                       -> Assertion--    expectMTimeChange dir descr action = do-      t  <- getModTime dir-      threadDelay mtimeChange-      action-      t' <- getModTime dir-      assertBool ("expected dir mtime change on " ++ descr) (t' > t)--    expectMTimeSame dir descr action = do-      t  <- getModTime dir-      threadDelay mtimeChange-      action-      t' <- getModTime dir-      assertBool ("expected same dir mtime on " ++ descr) (t' == t)----- Now for the FileMonitor tests proper...---- first run, where we don't even call updateMonitor-testNoMonitorCache :: Assertion-testNoMonitorCache =-  withFileMonitor $ \root monitor -> do-    reason <- expectMonitorChanged root (monitor :: FileMonitor () ()) ()-    reason @?= MonitorFirstRun---- write garbage into the binary cache file-testCorruptMonitorCache :: Assertion-testCorruptMonitorCache =-  withFileMonitor $ \root monitor -> do-    IO.writeFile (fileMonitorCacheFile monitor) "broken"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitorCorruptCache--    updateMonitor root monitor [] () ()-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= []--    IO.writeFile (fileMonitorCacheFile monitor) "broken"-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitorCorruptCache---- no files to monitor-testEmptyMonitor :: Assertion-testEmptyMonitor =-  withFileMonitor $ \root monitor -> do-    touchFile root "a"-    updateMonitor root monitor [] () ()-    touchFile root "b"-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= []---- monitor a file that is expected to exist-testMissingFile :: Assertion-testMissingFile = do-    test monitorFile       touchFile  "a"-    test monitorFileHashed touchFile  "a"-    test monitorFile       touchFile ("dir" </> "a")-    test monitorFileHashed touchFile ("dir" </> "a")-    test monitorDirectory  touchDir   "a"-    test monitorDirectory  touchDir  ("dir" </> "a")-  where-    test :: (FilePath -> MonitorFilePath)-         -> (RootPath -> FilePath -> IO ())-         -> FilePath-         -> IO ()-    test monitorKind touch file =-      withFileMonitor $ \root monitor -> do-        -- a file that doesn't exist at snapshot time is considered to have-        -- changed-        updateMonitor root monitor [monitorKind file] () ()-        reason <- expectMonitorChanged root monitor ()-        reason @?= MonitoredFileChanged file--        -- a file doesn't exist at snapshot time, but gets added afterwards is-        -- also considered to have changed-        updateMonitor root monitor [monitorKind file] () ()-        touch root file-        reason2 <- expectMonitorChanged root monitor ()-        reason2 @?= MonitoredFileChanged file---testChangedFile :: Int -> Assertion-testChangedFile mtimeChange = do-    test monitorFile       touchFile touchFile         "a"-    test monitorFileHashed touchFile touchFileContent  "a"-    test monitorFile       touchFile touchFile        ("dir" </> "a")-    test monitorFileHashed touchFile touchFileContent ("dir" </> "a")-    test monitorDirectory  touchDir  touchDir          "a"-    test monitorDirectory  touchDir  touchDir         ("dir" </> "a")-  where-    test :: (FilePath -> MonitorFilePath)-         -> (RootPath -> FilePath -> IO ())-         -> (RootPath -> FilePath -> IO ())-         -> FilePath-         -> IO ()-    test monitorKind touch touch' file =-      withFileMonitor $ \root monitor -> do-        touch root file-        updateMonitor root monitor [monitorKind file] () ()-        threadDelay mtimeChange-        touch' root file-        reason <- expectMonitorChanged root monitor ()-        reason @?= MonitoredFileChanged file---testChangedFileMtimeVsContent :: Int -> Assertion-testChangedFileMtimeVsContent mtimeChange =-  withFileMonitor $ \root monitor -> do-    -- if we don't touch the file, it's unchanged-    touchFile root "a"-    updateMonitor root monitor [monitorFile "a"] () ()-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFile "a"]--    -- if we do touch the file, it's changed if we only consider mtime-    updateMonitor root monitor [monitorFile "a"] () ()-    threadDelay mtimeChange-    touchFile root "a"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged "a"--    -- but if we touch the file, it's unchanged if we consider content hash-    updateMonitor root monitor [monitorFileHashed "a"] () ()-    threadDelay mtimeChange-    touchFile root "a"-    (res2, files2) <- expectMonitorUnchanged root monitor ()-    res2   @?= ()-    files2 @?= [monitorFileHashed "a"]--    -- finally if we change the content it's changed-    updateMonitor root monitor [monitorFileHashed "a"] () ()-    threadDelay mtimeChange-    touchFileContent root "a"-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitoredFileChanged "a"---testUpdateDuringAction :: Int -> Assertion-testUpdateDuringAction mtimeChange = do-    test (monitorFile        "a") touchFile "a"-    test (monitorFileHashed  "a") touchFile "a"-    test (monitorDirectory   "a") touchDir  "a"-    test (monitorFileGlobStr "*") touchFile "a"-    test (monitorFileGlobStr "*") { monitorKindDir = DirModTime }-                                  touchDir  "a"-  where-    test :: MonitorFilePath-         -> (RootPath -> FilePath -> IO ())-         -> FilePath-         -> IO ()-    test monitorSpec touch file =-      withFileMonitor $ \root monitor -> do-        touch root file-        updateMonitor root monitor [monitorSpec] () ()--        -- start doing an update action...-        threadDelay mtimeChange -- some time passes-        touch root file         -- a file gets updates during the action-        threadDelay mtimeChange -- some time passes then we finish-        updateMonitor root monitor [monitorSpec] () ()-        -- we don't notice this change since we took the timestamp after the-        -- action finished-        (res, files) <- expectMonitorUnchanged root monitor ()-        res   @?= ()-        files @?= [monitorSpec]--        -- Let's try again, this time taking the timestamp before the action-        timestamp' <- beginUpdateFileMonitor-        threadDelay mtimeChange -- some time passes-        touch root file         -- a file gets updates during the action-        threadDelay mtimeChange -- some time passes then we finish-        updateMonitorWithTimestamp root monitor timestamp' [monitorSpec] () ()-        -- now we do notice the change since we took the snapshot before the-        -- action finished-        reason <- expectMonitorChanged root monitor ()-        reason @?= MonitoredFileChanged file---testRemoveFile :: Assertion-testRemoveFile = do-    test monitorFile       touchFile removeFile  "a"-    test monitorFileHashed touchFile removeFile  "a"-    test monitorFile       touchFile removeFile ("dir" </> "a")-    test monitorFileHashed touchFile removeFile ("dir" </> "a")-    test monitorDirectory  touchDir  removeDir   "a"-    test monitorDirectory  touchDir  removeDir  ("dir" </> "a")-  where-    test :: (FilePath -> MonitorFilePath)-         -> (RootPath -> FilePath -> IO ())-         -> (RootPath -> FilePath -> IO ())-         -> FilePath-         -> IO ()-    test monitorKind touch remove file =-      withFileMonitor $ \root monitor -> do-        touch root file-        updateMonitor root monitor [monitorKind file] () ()-        remove root file-        reason <- expectMonitorChanged root monitor ()-        reason @?= MonitoredFileChanged file----- monitor a file that we expect not to exist-testNonExistentFile :: Assertion-testNonExistentFile =-  withFileMonitor $ \root monitor -> do-    -- a file that doesn't exist at snapshot time or check time is unchanged-    updateMonitor root monitor [monitorNonExistentFile "a"] () ()-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorNonExistentFile "a"]--    -- if the file then exists it has changed-    touchFile root "a"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged "a"--    -- if the file then exists at snapshot and check time it has changed-    updateMonitor root monitor [monitorNonExistentFile "a"] () ()-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitoredFileChanged "a"--    -- but if the file existed at snapshot time and doesn't exist at check time-    -- it is consider unchanged. This is unlike files we expect to exist, but-    -- that's because files that exist can have different content and actions-    -- can depend on that content, whereas if the action expected a file not to-    -- exist and it now does not, it'll give the same result, irrespective of-    -- the fact that the file might have existed in the meantime.-    updateMonitor root monitor [monitorNonExistentFile "a"] () ()-    removeFile root "a"-    (res2, files2) <- expectMonitorUnchanged root monitor ()-    res2   @?= ()-    files2 @?= [monitorNonExistentFile "a"]---testChangedFileType :: Int-> Assertion-testChangedFileType mtimeChange = do-    test (monitorFile            "a") touchFile removeFile createDir-    test (monitorFileHashed      "a") touchFile removeFile createDir--    test (monitorDirectory       "a") createDir removeDir touchFile-    test (monitorFileOrDirectory "a") createDir removeDir touchFile--    test (monitorFileGlobStr     "*") { monitorKindDir = DirModTime }-                                      touchFile removeFile createDir-    test (monitorFileGlobStr     "*") { monitorKindDir = DirModTime }-                                      createDir removeDir touchFile-  where-    test :: MonitorFilePath-         -> (RootPath -> String -> IO ())-         -> (RootPath -> String -> IO ())-         -> (RootPath -> String -> IO ())-         -> IO ()-    test monitorKind touch remove touch' =-      withFileMonitor $ \root monitor -> do-        touch  root "a"-        updateMonitor root monitor [monitorKind] () ()-        threadDelay mtimeChange-        remove root "a"-        touch' root "a"-        reason <- expectMonitorChanged root monitor ()-        reason @?= MonitoredFileChanged "a"---- Monitoring the same file with two different kinds of monitor should work--- both should be kept, and both checked for changes.--- We had a bug where only one monitor kind was kept per file.--- https://github.com/haskell/cabal/pull/3863#issuecomment-248495178-testMultipleMonitorKinds :: Int -> Assertion-testMultipleMonitorKinds mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root "a"-    updateMonitor root monitor [monitorFile "a", monitorFileHashed "a"] () ()-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFile "a", monitorFileHashed "a"]-    threadDelay mtimeChange-    touchFile root "a" -- not changing content, just mtime-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged "a"--    createDir root "dir"-    updateMonitor root monitor [monitorDirectory "dir",-                                monitorDirectoryExistence "dir"] () ()-    (res2, files2) <- expectMonitorUnchanged root monitor ()-    res2   @?= ()-    files2 @?= [monitorDirectory "dir", monitorDirectoryExistence "dir"]-    threadDelay mtimeChange-    touchFile root ("dir" </> "a") -- changing dir mtime, not existence-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitoredFileChanged "dir"------------------------ globs-----testGlobNoChange :: Assertion-testGlobNoChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "good-a")-    touchFile root ("dir" </> "good-b")-    updateMonitor root monitor [monitorFileGlobStr "dir/good-*"] () ()-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/good-*"]--testGlobAddMatch :: Int -> Assertion-testGlobAddMatch mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "good-a")-    updateMonitor root monitor [monitorFileGlobStr "dir/good-*"] () ()-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/good-*"]-    threadDelay mtimeChange-    touchFile root ("dir" </> "good-b")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "good-b")--testGlobRemoveMatch :: Int -> Assertion-testGlobRemoveMatch mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "good-a")-    touchFile root ("dir" </> "good-b")-    updateMonitor root monitor [monitorFileGlobStr "dir/good-*"] () ()-    threadDelay mtimeChange-    removeFile root "dir/good-a"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "good-a")--testGlobChangeMatch :: Int -> Assertion-testGlobChangeMatch mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "good-a")-    touchFile root ("dir" </> "good-b")-    updateMonitor root monitor [monitorFileGlobStr "dir/good-*"] () ()-    threadDelay mtimeChange-    touchFile root ("dir" </> "good-b")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/good-*"]--    touchFileContent root ("dir" </> "good-b")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "good-b")--testGlobAddMatchSubdir :: Int -> Assertion-testGlobAddMatchSubdir mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a" </> "good-a")-    updateMonitor root monitor [monitorFileGlobStr "dir/*/good-*"] () ()-    threadDelay mtimeChange-    touchFile root ("dir" </> "b" </> "good-b")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "b" </> "good-b")--testGlobRemoveMatchSubdir :: Int -> Assertion-testGlobRemoveMatchSubdir mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a" </> "good-a")-    touchFile root ("dir" </> "b" </> "good-b")-    updateMonitor root monitor [monitorFileGlobStr "dir/*/good-*"] () ()-    threadDelay mtimeChange-    removeDir root ("dir" </> "a")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "a" </> "good-a")--testGlobChangeMatchSubdir :: Int -> Assertion-testGlobChangeMatchSubdir mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a" </> "good-a")-    touchFile root ("dir" </> "b" </> "good-b")-    updateMonitor root monitor [monitorFileGlobStr "dir/*/good-*"] () ()-    threadDelay mtimeChange-    touchFile root ("dir" </> "b" </> "good-b")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*/good-*"]--    touchFileContent root "dir/b/good-b"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "b" </> "good-b")---- check nothing goes squiffy with matching in the top dir-testGlobMatchTopDir :: Int -> Assertion-testGlobMatchTopDir mtimeChange =-  withFileMonitor $ \root monitor -> do-    updateMonitor root monitor [monitorFileGlobStr "*"] () ()-    threadDelay mtimeChange-    touchFile root "a"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged "a"--testGlobAddNonMatch :: Int -> Assertion-testGlobAddNonMatch mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "good-a")-    updateMonitor root monitor [monitorFileGlobStr "dir/good-*"] () ()-    threadDelay mtimeChange-    touchFile root ("dir" </> "bad")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/good-*"]--testGlobRemoveNonMatch :: Int -> Assertion-testGlobRemoveNonMatch mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "good-a")-    touchFile root ("dir" </> "bad")-    updateMonitor root monitor [monitorFileGlobStr "dir/good-*"] () ()-    threadDelay mtimeChange-    removeFile root "dir/bad"-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/good-*"]--testGlobAddNonMatchSubdir :: Int -> Assertion-testGlobAddNonMatchSubdir mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a" </> "good-a")-    updateMonitor root monitor [monitorFileGlobStr "dir/*/good-*"] () ()-    threadDelay mtimeChange-    touchFile root ("dir" </> "b" </> "bad")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*/good-*"]--testGlobRemoveNonMatchSubdir :: Int -> Assertion-testGlobRemoveNonMatchSubdir mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a" </> "good-a")-    touchFile root ("dir" </> "b" </> "bad")-    updateMonitor root monitor [monitorFileGlobStr "dir/*/good-*"] () ()-    threadDelay mtimeChange-    removeDir root ("dir" </> "b")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*/good-*"]----- try and tickle a bug that happens if we don't maintain the invariant that--- MonitorStateGlobFiles entries are sorted-testInvariantMonitorStateGlobFiles :: Int -> Assertion-testInvariantMonitorStateGlobFiles mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a")-    touchFile root ("dir" </> "b")-    touchFile root ("dir" </> "c")-    touchFile root ("dir" </> "d")-    updateMonitor root monitor [monitorFileGlobStr "dir/*"] () ()-    threadDelay mtimeChange-    -- so there should be no change (since we're doing content checks)-    -- but if we can get the dir entries to appear in the wrong order-    -- then if the sorted invariant is not maintained then we can fool-    -- the 'probeGlobStatus' into thinking there's changes-    removeFile root ("dir" </> "a")-    removeFile root ("dir" </> "b")-    removeFile root ("dir" </> "c")-    removeFile root ("dir" </> "d")-    touchFile root ("dir" </> "d")-    touchFile root ("dir" </> "c")-    touchFile root ("dir" </> "b")-    touchFile root ("dir" </> "a")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*"]---- same thing for the subdirs case-testInvariantMonitorStateGlobDirs :: Int -> Assertion-testInvariantMonitorStateGlobDirs mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root ("dir" </> "a" </> "file")-    touchFile root ("dir" </> "b" </> "file")-    touchFile root ("dir" </> "c" </> "file")-    touchFile root ("dir" </> "d" </> "file")-    updateMonitor root monitor [monitorFileGlobStr "dir/*/file"] () ()-    threadDelay mtimeChange-    removeDir root ("dir" </> "a")-    removeDir root ("dir" </> "b")-    removeDir root ("dir" </> "c")-    removeDir root ("dir" </> "d")-    touchFile root ("dir" </> "d" </> "file")-    touchFile root ("dir" </> "c" </> "file")-    touchFile root ("dir" </> "b" </> "file")-    touchFile root ("dir" </> "a" </> "file")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*/file"]---- ensure that a glob can match a directory as well as a file-testGlobMatchDir :: Int -> Assertion-testGlobMatchDir mtimeChange =-  withFileMonitor $ \root monitor -> do-    createDir root ("dir" </> "a")-    updateMonitor root monitor [monitorFileGlobStr "dir/*"] () ()-    threadDelay mtimeChange-    -- nothing changed yet-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*"]-    -- expect dir/b to match and be detected as changed-    createDir root ("dir" </> "b")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "b")-    -- now remove dir/a and expect it to be detected as changed-    updateMonitor root monitor [monitorFileGlobStr "dir/*"] () ()-    threadDelay mtimeChange-    removeDir root ("dir" </> "a")-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitoredFileChanged ("dir" </> "a")--testGlobMatchDirOnly :: Int -> Assertion-testGlobMatchDirOnly mtimeChange =-  withFileMonitor $ \root monitor -> do-    updateMonitor root monitor [monitorFileGlobStr "dir/*/"] () ()-    threadDelay mtimeChange-    -- expect file dir/a to not match, so not detected as changed-    touchFile root ("dir" </> "a")-    (res, files) <- expectMonitorUnchanged root monitor ()-    res   @?= ()-    files @?= [monitorFileGlobStr "dir/*/"]-    -- note that checking the file monitor for changes can updates the-    -- cached dir mtimes (when it has to record that there's new matches)-    -- so we need an extra mtime delay-    threadDelay mtimeChange-    -- but expect dir/b to match-    createDir root ("dir" </> "b")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "b")--testGlobChangeFileType :: Int -> Assertion-testGlobChangeFileType mtimeChange =-  withFileMonitor $ \root monitor -> do-    -- change file to dir-    touchFile root ("dir" </> "a")-    updateMonitor root monitor [monitorFileGlobStr "dir/*"] () ()-    threadDelay mtimeChange-    removeFile root ("dir" </> "a")-    createDir  root ("dir" </> "a")-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged ("dir" </> "a")-    -- change dir to file-    updateMonitor root monitor [monitorFileGlobStr "dir/*"] () ()-    threadDelay mtimeChange-    removeDir root ("dir" </> "a")-    touchFile root ("dir" </> "a")-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitoredFileChanged ("dir" </> "a")--testGlobAbsolutePath :: Int -> Assertion-testGlobAbsolutePath mtimeChange =-  withFileMonitor $ \root monitor -> do-    root' <- absoluteRoot root-    -- absolute glob, removing a file-    touchFile root ("dir/good-a")-    touchFile root ("dir/good-b")-    updateMonitor root monitor [monitorFileGlobStr (root' </> "dir/good-*")] () ()-    threadDelay mtimeChange-    removeFile root "dir/good-a"-    reason <- expectMonitorChanged root monitor ()-    reason @?= MonitoredFileChanged (root' </> "dir/good-a")-    -- absolute glob, adding a file-    updateMonitor root monitor [monitorFileGlobStr (root' </> "dir/good-*")] () ()-    threadDelay mtimeChange-    touchFile root ("dir/good-a")-    reason2 <- expectMonitorChanged root monitor ()-    reason2 @?= MonitoredFileChanged (root' </> "dir/good-a")-    -- absolute glob, changing a file-    updateMonitor root monitor [monitorFileGlobStr (root' </> "dir/good-*")] () ()-    threadDelay mtimeChange-    touchFileContent root "dir/good-b"-    reason3 <- expectMonitorChanged root monitor ()-    reason3 @?= MonitoredFileChanged (root' </> "dir/good-b")------------------------ value changes-----testValueUnchanged :: Assertion-testValueUnchanged =-  withFileMonitor $ \root monitor -> do-    touchFile root "a"-    updateMonitor root monitor [monitorFile "a"] (42 :: Int) "ok"-    (res, files) <- expectMonitorUnchanged root monitor 42-    res   @?= "ok"-    files @?= [monitorFile "a"]--testValueChanged :: Assertion-testValueChanged =-  withFileMonitor $ \root monitor -> do-    touchFile root "a"-    updateMonitor root monitor [monitorFile "a"] (42 :: Int) "ok"-    reason <- expectMonitorChanged root monitor 43-    reason @?= MonitoredValueChanged 42--testValueAndFileChanged :: Int -> Assertion-testValueAndFileChanged mtimeChange =-  withFileMonitor $ \root monitor -> do-    touchFile root "a"--    -- we change the value and the file, and the value change is reported-    updateMonitor root monitor [monitorFile "a"] (42 :: Int) "ok"-    threadDelay mtimeChange-    touchFile root "a"-    reason <- expectMonitorChanged root monitor 43-    reason @?= MonitoredValueChanged 42--    -- if fileMonitorCheckIfOnlyValueChanged then if only the value changed-    -- then it's reported as MonitoredValueChanged-    let monitor' :: FileMonitor Int String-        monitor' = monitor { fileMonitorCheckIfOnlyValueChanged = True }-    updateMonitor root monitor' [monitorFile "a"] 42 "ok"-    reason2 <- expectMonitorChanged root monitor' 43-    reason2 @?= MonitoredValueChanged 42--    -- but if a file changed too then we don't report MonitoredValueChanged-    updateMonitor root monitor' [monitorFile "a"] 42 "ok"-    threadDelay mtimeChange-    touchFile root "a"-    reason3 <- expectMonitorChanged root monitor' 43-    reason3 @?= MonitoredFileChanged "a"--testValueUpdated :: Assertion-testValueUpdated =-  withFileMonitor $ \root monitor -> do-    touchFile root "a"--    let monitor' :: FileMonitor (Set.Set Int) String-        monitor' = (monitor :: FileMonitor (Set.Set Int) String) {-                     fileMonitorCheckIfOnlyValueChanged = True,-                     fileMonitorKeyValid = Set.isSubsetOf-                   }--    updateMonitor root monitor' [monitorFile "a"] (Set.fromList [42,43]) "ok"-    (res,_files) <- expectMonitorUnchanged root monitor' (Set.fromList [42])-    res @?= "ok"--    reason <- expectMonitorChanged root monitor' (Set.fromList [42,44])-    reason @?= MonitoredValueChanged (Set.fromList [42,43])------------------- Utils--newtype RootPath = RootPath FilePath--touchFile :: RootPath -> FilePath -> IO ()-touchFile (RootPath root) fname = do-  let path = root </> fname-  IO.createDirectoryIfMissing True (takeDirectory path)-  IO.writeFile path "touched"--touchFileContent :: RootPath -> FilePath -> IO ()-touchFileContent (RootPath root) fname = do-  let path = root </> fname-  IO.createDirectoryIfMissing True (takeDirectory path)-  IO.writeFile path "different"--removeFile :: RootPath -> FilePath -> IO ()-removeFile (RootPath root) fname = IO.removeFile (root </> fname)--touchDir :: RootPath -> FilePath -> IO ()-touchDir root@(RootPath rootdir) dname = do-  IO.createDirectoryIfMissing True (rootdir </> dname)-  touchFile  root (dname </> "touch")-  removeFile root (dname </> "touch")--createDir :: RootPath -> FilePath -> IO ()-createDir (RootPath root) dname = do-  let path = root </> dname-  IO.createDirectoryIfMissing True (takeDirectory path)-  IO.createDirectory path--removeDir :: RootPath -> FilePath -> IO ()-removeDir (RootPath root) dname = IO.removeDirectoryRecursive (root </> dname)--absoluteRoot :: RootPath -> IO FilePath-absoluteRoot (RootPath root) = IO.canonicalizePath root--monitorFileGlobStr :: String -> MonitorFilePath-monitorFileGlobStr globstr-  | Just glob <- simpleParse globstr = monitorFileGlob glob-  | otherwise                        = error $ "Failed to parse " ++ globstr---expectMonitorChanged :: (Binary a, Binary b)-                     => RootPath -> FileMonitor a b -> a-                     -> IO (MonitorChangedReason a)-expectMonitorChanged root monitor key = do-  res <- checkChanged root monitor key-  case res of-    MonitorChanged reason -> return reason-    MonitorUnchanged _ _  -> throwIO $ HUnitFailure Nothing "expected change"--expectMonitorUnchanged :: (Binary a, Binary b)-                        => RootPath -> FileMonitor a b -> a-                        -> IO (b, [MonitorFilePath])-expectMonitorUnchanged root monitor key = do-  res <- checkChanged root monitor key-  case res of-    MonitorChanged _reason   -> throwIO $ HUnitFailure Nothing "expected no change"-    MonitorUnchanged b files -> return (b, files)--checkChanged :: (Binary a, Binary b)-             => RootPath -> FileMonitor a b-             -> a -> IO (MonitorChanged a b)-checkChanged (RootPath root) monitor key =-  checkFileMonitorChanged monitor root key--updateMonitor :: (Binary a, Binary b)-              => RootPath -> FileMonitor a b-              -> [MonitorFilePath] -> a -> b -> IO ()-updateMonitor (RootPath root) monitor files key result =-  updateFileMonitor monitor root Nothing files key result--updateMonitorWithTimestamp :: (Binary a, Binary b)-              => RootPath -> FileMonitor a b -> MonitorTimestamp-              -> [MonitorFilePath] -> a -> b -> IO ()-updateMonitorWithTimestamp (RootPath root) monitor timestamp files key result =-  updateFileMonitor monitor root (Just timestamp) files key result--withFileMonitor :: Eq a => (RootPath -> FileMonitor a b -> IO c) -> IO c-withFileMonitor action = do-  withTempDirectory silent "." "file-status-" $ \root -> do-    let file    = root <.> "monitor"-        monitor = newFileMonitor file-    finally (action (RootPath root) monitor) $ do-      exists <- IO.doesFileExist file-      when exists $ IO.removeFile file
− tests/UnitTests/Distribution/Client/GZipUtils.hs
@@ -1,60 +0,0 @@-module UnitTests.Distribution.Client.GZipUtils (-  tests-  ) where--import Codec.Compression.GZip          as GZip-import Codec.Compression.Zlib          as Zlib-import Control.Exception.Base                  (evaluate)-import Control.Exception                       (try, SomeException)-import Control.Monad                           (void)-import Data.ByteString                as BS    (null)-import Data.ByteString.Lazy           as BSL   (pack, toChunks)-import Data.ByteString.Lazy.Char8     as BSLL  (pack, init, length)-import Data.Monoid                             ((<>))-import Distribution.Client.GZipUtils           (maybeDecompress)-import Data.Word                               (Word8)--import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.QuickCheck--tests :: [TestTree]-tests = [ testCase "maybeDecompress" maybeDecompressUnitTest-        -- "decompress plain" property is non-trivial to state,-        -- maybeDecompress returns input bytestring only if error occurs right at the beginning of the decompression process-        -- generating such input would essentially duplicate maybeDecompress implementation-        , testProperty "decompress zlib"  prop_maybeDecompress_zlib-        , testProperty "decompress gzip"  prop_maybeDecompress_gzip-        ]--maybeDecompressUnitTest :: Assertion-maybeDecompressUnitTest =-        assertBool "decompress plain"            (maybeDecompress original              == original)-     >> assertBool "decompress zlib (with show)" (show (maybeDecompress compressedZlib) == show original)-     >> assertBool "decompress gzip (with show)" (show (maybeDecompress compressedGZip) == show original)-     >> assertBool "decompress zlib"             (maybeDecompress compressedZlib        == original)-     >> assertBool "decompress gzip"             (maybeDecompress compressedGZip        == original)-     >> assertBool "have no empty chunks"        (Prelude.all (not . BS.null) . BSL.toChunks . maybeDecompress $ compressedZlib)-     >> (runBrokenStream >>= assertBool "decompress broken stream" . isLeft)-  where-    original = BSLL.pack "original uncompressed input"-    compressedZlib = Zlib.compress original-    compressedGZip = GZip.compress original--    runBrokenStream :: IO (Either SomeException ())-    runBrokenStream = try . void . evaluate . BSLL.length $ maybeDecompress (BSLL.init compressedZlib <> BSLL.pack "*")--prop_maybeDecompress_zlib :: [Word8] -> Property-prop_maybeDecompress_zlib ws = property $ maybeDecompress compressedZlib === original-  where original = BSL.pack ws-        compressedZlib = Zlib.compress original--prop_maybeDecompress_gzip :: [Word8] -> Property-prop_maybeDecompress_gzip ws = property $ maybeDecompress compressedGZip === original-  where original = BSL.pack ws-        compressedGZip = GZip.compress original---- (Only available from "Data.Either" since 7.8.)-isLeft :: Either a b -> Bool-isLeft (Right _) = False-isLeft (Left _) = True
− tests/UnitTests/Distribution/Client/Glob.hs
@@ -1,203 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module UnitTests.Distribution.Client.Glob (tests) where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative-#endif-import Data.Char-import Data.List-import Distribution.Text (display, parse, simpleParse)-import Distribution.Compat.ReadP--import Distribution.Client.Glob-import UnitTests.Distribution.Client.ArbitraryInstances--import Test.Tasty-import Test.Tasty.QuickCheck-import Test.Tasty.HUnit-import Control.Exception---tests :: [TestTree]-tests =-  [ testProperty "print/parse roundtrip" prop_roundtrip_printparse-  , testCase     "parse examples"        testParseCases-  ]----TODO: [nice to have] tests for trivial globs, tests for matching,--- tests for windows style file paths--prop_roundtrip_printparse :: FilePathGlob -> Bool-prop_roundtrip_printparse pathglob =-  -- can't use simpleParse because it mis-handles trailing spaces-  case [ x | (x, []) <- readP_to_S parse (display pathglob) ] of-    xs@(_:_) -> last xs == pathglob-    _        -> False---- first run, where we don't even call updateMonitor-testParseCases :: Assertion-testParseCases = do--  FilePathGlob (FilePathRoot "/") GlobDirTrailing <- testparse "/"-  FilePathGlob FilePathHomeDir  GlobDirTrailing <- testparse "~/"--  FilePathGlob (FilePathRoot "A:\\") GlobDirTrailing <- testparse "A:/"-  FilePathGlob (FilePathRoot "Z:\\") GlobDirTrailing <- testparse "z:/"-  FilePathGlob (FilePathRoot "C:\\") GlobDirTrailing <- testparse "C:\\"-  FilePathGlob FilePathRelative (GlobFile [Literal "_:"]) <- testparse "_:"--  FilePathGlob FilePathRelative-    (GlobFile [Literal "."]) <- testparse "."--  FilePathGlob FilePathRelative-    (GlobFile [Literal "~"]) <- testparse "~"--  FilePathGlob FilePathRelative-    (GlobDir  [Literal "."] GlobDirTrailing) <- testparse "./"--  FilePathGlob FilePathRelative-    (GlobFile [Literal "foo"]) <- testparse "foo"--  FilePathGlob FilePathRelative-    (GlobDir [Literal "foo"]-      (GlobFile [Literal "bar"])) <- testparse "foo/bar"--  FilePathGlob FilePathRelative-    (GlobDir [Literal "foo"]-      (GlobDir [Literal "bar"] GlobDirTrailing)) <- testparse "foo/bar/"--  FilePathGlob (FilePathRoot "/")-    (GlobDir [Literal "foo"]-      (GlobDir [Literal "bar"] GlobDirTrailing)) <- testparse "/foo/bar/"--  FilePathGlob FilePathRelative-    (GlobFile [WildCard]) <- testparse "*"--  FilePathGlob FilePathRelative-    (GlobFile [WildCard,WildCard]) <- testparse "**" -- not helpful but valid--  FilePathGlob FilePathRelative-    (GlobFile [WildCard, Literal "foo", WildCard]) <- testparse "*foo*"--  FilePathGlob FilePathRelative-    (GlobFile [Literal "foo", WildCard, Literal "bar"]) <- testparse "foo*bar"--  FilePathGlob FilePathRelative-    (GlobFile [Union [[WildCard], [Literal "foo"]]]) <- testparse "{*,foo}"--  parseFail "{"-  parseFail "}"-  parseFail ","-  parseFail "{"-  parseFail "{{}"-  parseFail "{}"-  parseFail "{,}"-  parseFail "{foo,}"-  parseFail "{,foo}"--  return ()--testparse :: String -> IO FilePathGlob-testparse s =-    case simpleParse s of-      Just p  -> return p-      Nothing -> throwIO $ HUnitFailure Nothing ("expected parse of: " ++ s)--parseFail :: String -> Assertion-parseFail s =-    case simpleParse s :: Maybe FilePathGlob of-      Just _  -> throwIO $ HUnitFailure Nothing ("expected no parse of: " ++ s)-      Nothing -> return ()--instance Arbitrary FilePathGlob where-  arbitrary = (FilePathGlob <$> arbitrary <*> arbitrary)-                `suchThat` validFilePathGlob--  shrink (FilePathGlob root pathglob) =-    [ FilePathGlob root' pathglob'-    | (root', pathglob') <- shrink (root, pathglob)-    , validFilePathGlob (FilePathGlob root' pathglob') ]--validFilePathGlob :: FilePathGlob -> Bool-validFilePathGlob (FilePathGlob FilePathRelative pathglob) =-  case pathglob of-    GlobDirTrailing             -> False-    GlobDir [Literal "~"] _     -> False-    GlobDir [Literal (d:":")] _ -      | isLetter d              -> False-    _                           -> True-validFilePathGlob _ = True--instance Arbitrary FilePathRoot where-  arbitrary =-    frequency-      [ (3, pure FilePathRelative)-      , (1, pure (FilePathRoot unixroot))-      , (1, FilePathRoot <$> windrive)-      , (1, pure FilePathHomeDir)-      ]-    where-      unixroot = "/"-      windrive = do d <- choose ('A', 'Z'); return (d : ":\\")--  shrink FilePathRelative     = []-  shrink (FilePathRoot _)     = [FilePathRelative]-  shrink FilePathHomeDir      = [FilePathRelative]---instance Arbitrary FilePathGlobRel where-  arbitrary = sized $ \sz ->-    oneof $ take (max 1 sz)-      [ pure GlobDirTrailing-      , GlobFile  <$> (getGlobPieces <$> arbitrary)-      , GlobDir   <$> (getGlobPieces <$> arbitrary)-                  <*> resize (sz `div` 2) arbitrary-      ]--  shrink GlobDirTrailing = []-  shrink (GlobFile glob) =-      GlobDirTrailing-    : [ GlobFile (getGlobPieces glob') | glob' <- shrink (GlobPieces glob) ]-  shrink (GlobDir glob pathglob) =-      pathglob-    : GlobFile glob-    : [ GlobDir (getGlobPieces glob') pathglob'-      | (glob', pathglob') <- shrink (GlobPieces glob, pathglob) ]--newtype GlobPieces = GlobPieces { getGlobPieces :: [GlobPiece] }-  deriving Eq--instance Arbitrary GlobPieces where-  arbitrary = GlobPieces . mergeLiterals <$> shortListOf1 5 arbitrary--  shrink (GlobPieces glob) =-    [ GlobPieces (mergeLiterals (getNonEmpty glob'))-    | glob' <- shrink (NonEmpty glob) ]--mergeLiterals :: [GlobPiece] -> [GlobPiece]-mergeLiterals (Literal a : Literal b : ps) = mergeLiterals (Literal (a++b) : ps)-mergeLiterals (Union as : ps) = Union (map mergeLiterals as) : mergeLiterals ps-mergeLiterals (p:ps) = p : mergeLiterals ps-mergeLiterals []     = []--instance Arbitrary GlobPiece where-  arbitrary = sized $ \sz ->-    frequency-      [ (3, Literal <$> shortListOf1 10 (elements globLiteralChars))-      , (1, pure WildCard)-      , (1, Union <$> resize (sz `div` 2) (shortListOf1 5 (shortListOf1 5 arbitrary)))-      ]--  shrink (Literal str) = [ Literal str'-                         | str' <- shrink str-                         , not (null str')-                         , all (`elem` globLiteralChars) str' ]-  shrink WildCard       = []-  shrink (Union as)     = [ Union (map getGlobPieces (getNonEmpty as'))-                          | as' <- shrink (NonEmpty (map GlobPieces as)) ]--globLiteralChars :: [Char]-globLiteralChars = ['\0'..'\128'] \\ "*{},/\\"-
− tests/UnitTests/Distribution/Client/IndexUtils/Timestamp.hs
@@ -1,60 +0,0 @@-module UnitTests.Distribution.Client.IndexUtils.Timestamp (tests) where--import Distribution.Text-import Data.Time-import Data.Time.Clock.POSIX--import Distribution.Client.IndexUtils.Timestamp--import Test.Tasty-import Test.Tasty.QuickCheck--tests :: [TestTree]-tests =-    [ testProperty "Timestamp1" prop_timestamp1-    , testProperty "Timestamp2" prop_timestamp2-    , testProperty "Timestamp3" prop_timestamp3-    , testProperty "Timestamp4" prop_timestamp4-    , testProperty "Timestamp5" prop_timestamp5-    ]---- test unixtime format parsing-prop_timestamp1 :: Int -> Bool-prop_timestamp1 t0 = Just t == simpleParse ('@':show t0)-  where-    t = toEnum t0 :: Timestamp---- test display/simpleParse roundtrip-prop_timestamp2 :: Int -> Bool-prop_timestamp2 t0-  | t /= nullTimestamp  = simpleParse (display t) == Just t-  | otherwise           = display t == ""-  where-    t = toEnum t0 :: Timestamp---- test display against reference impl-prop_timestamp3 :: Int -> Bool-prop_timestamp3 t0-  | t /= nullTimestamp  = refDisp t == display t-  | otherwise           = display t == ""-  where-    t = toEnum t0 :: Timestamp--    refDisp = maybe undefined (formatTime undefined "%FT%TZ")-              . timestampToUTCTime---- test utcTimeToTimestamp/timestampToUTCTime roundtrip-prop_timestamp4 :: Int -> Bool-prop_timestamp4 t0-  | t /= nullTimestamp  = (utcTimeToTimestamp =<< timestampToUTCTime t) == Just t-  | otherwise           = timestampToUTCTime t == Nothing-  where-    t = toEnum t0 :: Timestamp--prop_timestamp5 :: Int -> Bool-prop_timestamp5 t0-  | t /= nullTimestamp = timestampToUTCTime t == Just ut-  | otherwise          = timestampToUTCTime t == Nothing-  where-    t = toEnum t0 :: Timestamp-    ut = posixSecondsToUTCTime (fromIntegral t0)
− tests/UnitTests/Distribution/Client/InstallPlan.hs
@@ -1,312 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE NoMonoLocalBinds #-}-{-# LANGUAGE ConstraintKinds #-}-module UnitTests.Distribution.Client.InstallPlan (tests) where--import           Distribution.Package-import           Distribution.Version-import qualified Distribution.Client.InstallPlan as InstallPlan-import           Distribution.Client.InstallPlan (GenericInstallPlan, IsUnit)-import qualified Distribution.Compat.Graph as Graph-import           Distribution.Compat.Graph (IsNode(..))-import           Distribution.Solver.Types.Settings-import           Distribution.Solver.Types.PackageFixedDeps-import qualified Distribution.Solver.Types.ComponentDeps as CD-import           Distribution.Client.Types-import           Distribution.Client.JobControl--import Data.Graph-import Data.Array hiding (index)-import Data.List-import qualified Data.Map as Map-import qualified Data.Set as Set-import Data.Set (Set)-import Data.IORef-import Control.Monad-import Control.Concurrent (threadDelay)-import System.Random-import Test.QuickCheck--import Test.Tasty-import Test.Tasty.QuickCheck---tests :: [TestTree]-tests =-  [ testProperty "reverseTopologicalOrder" prop_reverseTopologicalOrder-  , testProperty "executionOrder"          prop_executionOrder-  , testProperty "execute serial"          prop_execute_serial-  , testProperty "execute parallel"        prop_execute_parallel-  , testProperty "execute/executionOrder"  prop_execute_vs_executionOrder-  ]--prop_reverseTopologicalOrder :: TestInstallPlan -> Bool-prop_reverseTopologicalOrder (TestInstallPlan plan graph toVertex _) =-    isReverseTopologicalOrder-      graph-      (map (toVertex . installedUnitId)-           (InstallPlan.reverseTopologicalOrder plan))---- | @executionOrder@ is in reverse topological order-prop_executionOrder :: TestInstallPlan -> Bool-prop_executionOrder (TestInstallPlan plan graph toVertex _) =-    isReversePartialTopologicalOrder graph (map toVertex pkgids)- && allConfiguredPackages plan == Set.fromList pkgids-  where-    pkgids = map installedUnitId (InstallPlan.executionOrder plan)---- | @execute@ is in reverse topological order-prop_execute_serial :: TestInstallPlan -> Property-prop_execute_serial tplan@(TestInstallPlan plan graph toVertex _) =-    ioProperty $ do-      jobCtl <- newSerialJobControl-      pkgids <- executeTestInstallPlan jobCtl tplan (\_ -> return ())-      return $ isReversePartialTopologicalOrder graph (map toVertex pkgids)-            && allConfiguredPackages plan == Set.fromList pkgids--prop_execute_parallel :: Positive (Small Int) -> TestInstallPlan -> Property-prop_execute_parallel (Positive (Small maxJobLimit))-                      tplan@(TestInstallPlan plan graph toVertex _) =-    ioProperty $ do-      jobCtl <- newParallelJobControl maxJobLimit-      pkgids <- executeTestInstallPlan jobCtl tplan $ \_ -> do-                  delay <- randomRIO (0,1000)-                  threadDelay delay-      return $ isReversePartialTopologicalOrder graph (map toVertex pkgids)-            && allConfiguredPackages plan == Set.fromList pkgids---- | return the packages that are visited by execute, in order.-executeTestInstallPlan :: JobControl IO (UnitId, Either () ())-                       -> TestInstallPlan-                       -> (TestPkg -> IO ())-                       -> IO [UnitId]-executeTestInstallPlan jobCtl (TestInstallPlan plan _ _ _) visit = do-    resultsRef <- newIORef []-    _ <- InstallPlan.execute jobCtl False (const ())-                             plan $ \(ReadyPackage pkg) -> do-           visit pkg-           atomicModifyIORef resultsRef $ \pkgs -> (installedUnitId pkg:pkgs, ())-           return (Right ())-    fmap reverse (readIORef resultsRef)---- | @execute@ visits the packages in the same order as @executionOrder@-prop_execute_vs_executionOrder :: TestInstallPlan -> Property-prop_execute_vs_executionOrder tplan@(TestInstallPlan plan _ _ _) =-    ioProperty $ do-      jobCtl <- newSerialJobControl-      pkgids <- executeTestInstallPlan jobCtl tplan (\_ -> return ())-      let pkgids' = map installedUnitId (InstallPlan.executionOrder plan)-      return (pkgids == pkgids')-------------------------------- Property helper utils------- | A graph topological ordering is a linear ordering of its vertices such--- that for every directed edge uv from vertex u to vertex v, u comes before v--- in the ordering.------ A reverse topological ordering is the swapped: for every directed edge uv--- from vertex u to vertex v, v comes before u in the ordering.----isReverseTopologicalOrder :: Graph -> [Vertex] -> Bool-isReverseTopologicalOrder g vs =-    and [ ixs ! u > ixs ! v-        | let ixs = array (bounds g) (zip vs [0::Int ..])-        , (u,v) <- edges g ]--isReversePartialTopologicalOrder :: Graph -> [Vertex] -> Bool-isReversePartialTopologicalOrder g vs =-    and [ case (ixs ! u, ixs ! v) of-            (Just ixu, Just ixv) -> ixu > ixv-            _                    -> True-        | let ixs = array (bounds g)-                          (zip (range (bounds g)) (repeat Nothing) ++ -                           zip vs (map Just [0::Int ..]))-        , (u,v) <- edges g ]--allConfiguredPackages :: HasUnitId srcpkg-                      => GenericInstallPlan ipkg srcpkg -> Set UnitId-allConfiguredPackages plan =-    Set.fromList-      [ installedUnitId pkg-      | InstallPlan.Configured pkg <- InstallPlan.toList plan ]-------------------------- Test generators-----data TestInstallPlan = TestInstallPlan-                         (GenericInstallPlan TestPkg TestPkg)-                         Graph-                         (UnitId -> Vertex)-                         (Vertex -> UnitId)--instance Show TestInstallPlan where-  show (TestInstallPlan plan _ _ _) = InstallPlan.showInstallPlan plan--data TestPkg = TestPkg PackageId UnitId [UnitId]-  deriving (Eq, Show)--instance IsNode TestPkg where-  type Key TestPkg = UnitId-  nodeKey (TestPkg _ ipkgid _) = ipkgid-  nodeNeighbors (TestPkg _ _ deps) = deps---instance Package TestPkg where-  packageId (TestPkg pkgid _ _) = pkgid--instance HasUnitId TestPkg where-  installedUnitId (TestPkg _ ipkgid _) = ipkgid--instance PackageFixedDeps TestPkg where-  depends (TestPkg _ _ deps) = CD.singleton CD.ComponentLib deps--instance PackageInstalled TestPkg where-  installedDepends (TestPkg _ _ deps) = deps--instance Arbitrary TestInstallPlan where-  arbitrary = arbitraryTestInstallPlan--arbitraryTestInstallPlan :: Gen TestInstallPlan-arbitraryTestInstallPlan = do-    graph <- arbitraryAcyclicGraph-               (choose (2,5))-               (choose (1,5))-               0.3--    plan  <- arbitraryInstallPlan mkTestPkg mkTestPkg 0.5 graph--    let toVertexMap   = Map.fromList [ (mkUnitIdV v, v) | v <- vertices graph ]-        fromVertexMap = Map.fromList [ (v, mkUnitIdV v) | v <- vertices graph ]-        toVertex      = (toVertexMap   Map.!)-        fromVertex    = (fromVertexMap Map.!)--    return (TestInstallPlan plan graph toVertex fromVertex)-  where-    mkTestPkg pkgv depvs =-        return (TestPkg pkgid ipkgid deps)-      where-        pkgid  = mkPkgId pkgv-        ipkgid = mkUnitIdV pkgv-        deps   = map mkUnitIdV depvs-    mkUnitIdV = mkUnitId . show-    mkPkgId v = PackageIdentifier (mkPackageName ("pkg" ++ show v))-                                  (mkVersion [1])----- | Generate a random 'InstallPlan' following the structure of an existing--- 'Graph'.------ It takes generators for installed and source packages and the chance that--- each package is installed (for those packages with no prerequisites).----arbitraryInstallPlan :: (IsUnit ipkg,-                         IsUnit srcpkg)-                     => (Vertex -> [Vertex] -> Gen ipkg)-                     -> (Vertex -> [Vertex] -> Gen srcpkg)-                     -> Float-                     -> Graph-                     -> Gen (InstallPlan.GenericInstallPlan ipkg srcpkg)-arbitraryInstallPlan mkIPkg mkSrcPkg ipkgProportion graph = do--    (ipkgvs, srcpkgvs) <--      fmap ((\(ipkgs, srcpkgs) -> (map fst ipkgs, map fst srcpkgs))-            . partition snd) $-      sequence-        [ do isipkg <- if isRoot then pick ipkgProportion-                                 else return False-             return (v, isipkg)-        | (v,n) <- assocs (outdegree graph)-        , let isRoot = n == 0 ]--    ipkgs   <- sequence-                 [ mkIPkg pkgv depvs-                 | pkgv <- ipkgvs-                 , let depvs  = graph ! pkgv-                 ]-    srcpkgs <- sequence-                 [ mkSrcPkg pkgv depvs-                 | pkgv <- srcpkgvs-                 , let depvs  = graph ! pkgv-                 ]-    let index = Graph.fromDistinctList-                   (map InstallPlan.PreExisting ipkgs-                 ++ map InstallPlan.Configured  srcpkgs)-    return $ InstallPlan.new (IndependentGoals False) index----- | Generate a random directed acyclic graph, based on the algorithm presented--- here <http://stackoverflow.com/questions/12790337/generating-a-random-dag>------ It generates a DAG based on ranks of nodes. Nodes in each rank can only--- have edges to nodes in subsequent ranks.------ The generator is paramterised by a generator for the number of ranks and--- the number of nodes within each rank. It is also paramterised by the--- chance that each node in each rank will have an edge from each node in--- each previous rank. Thus a higher chance will produce a more densely--- connected graph.----arbitraryAcyclicGraph :: Gen Int -> Gen Int -> Float -> Gen Graph-arbitraryAcyclicGraph genNRanks genNPerRank edgeChance = do-    nranks    <- genNRanks-    rankSizes <- replicateM nranks genNPerRank-    let rankStarts = scanl (+) 0 rankSizes-        rankRanges = drop 1 (zip rankStarts (tail rankStarts))-        totalRange = sum rankSizes-    rankEdges <- mapM (uncurry genRank) rankRanges-    return $ buildG (0, totalRange-1) (concat rankEdges)-  where-    genRank :: Vertex -> Vertex -> Gen [Edge]-    genRank rankStart rankEnd =-      filterM (const (pick edgeChance))-        [ (i,j)-        | i <- [0..rankStart-1]-        , j <- [rankStart..rankEnd-1]-        ]--pick :: Float -> Gen Bool-pick chance = do-    p <- choose (0,1)-    return (p < chance)-------------------------------------- Inspecting generated graphs-----{---- Handy util for checking the generated graphs look sensible-writeDotFile :: FilePath -> Graph -> IO ()-writeDotFile file = writeFile file . renderDotGraph--renderDotGraph :: Graph -> String-renderDotGraph graph =-  unlines (-      [header-      ,graphDefaultAtribs-      ,nodeDefaultAtribs-      ,edgeDefaultAtribs]-    ++ map renderNode (vertices graph)-    ++ map renderEdge (edges graph)-    ++ [footer]-  )-  where-    renderNode n = "\t" ++ show n ++ " [label=\"" ++ show n ++  "\"];"--    renderEdge (n, n') = "\t" ++ show n ++ " -> " ++ show n' ++ "[];"---header, footer, graphDefaultAtribs, nodeDefaultAtribs, edgeDefaultAtribs :: String--header = "digraph packages {"-footer = "}"--graphDefaultAtribs = "\tgraph [fontsize=14, fontcolor=black, color=black];"-nodeDefaultAtribs  = "\tnode [label=\"\\N\", width=\"0.75\", shape=ellipse];"-edgeDefaultAtribs  = "\tedge [fontsize=10];"--}
− tests/UnitTests/Distribution/Client/JobControl.hs
@@ -1,193 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}-module UnitTests.Distribution.Client.JobControl (tests) where--import Distribution.Client.JobControl--import Data.List-import Data.Maybe-import Data.IORef-import Control.Monad-import Control.Concurrent (threadDelay)-import Control.Exception  (Exception, try, throwIO)-import Data.Typeable      (Typeable)-import qualified Data.Set as Set--import Test.Tasty-import Test.Tasty.QuickCheck hiding (collect)---tests :: [TestTree]-tests =-  [ testGroup "serial"-      [ testProperty "submit batch"       prop_submit_serial-      , testProperty "submit batch"       prop_remaining_serial-      , testProperty "submit interleaved" prop_interleaved_serial-      , testProperty "concurrent jobs"    prop_concurrent_serial-      , testProperty "cancel"             prop_cancel_serial-      , testProperty "exceptions"         prop_exception_serial-      ]-  , testGroup "parallel"-      [ testProperty "submit batch"       prop_submit_parallel-      , testProperty "submit batch"       prop_remaining_parallel-      , testProperty "submit interleaved" prop_interleaved_parallel-      , testProperty "concurrent jobs"    prop_concurrent_parallel-      , testProperty "cancel"             prop_cancel_parallel-      , testProperty "exceptions"         prop_exception_parallel-      ]-  ]---prop_submit_serial :: [Int] -> Property-prop_submit_serial xs =-  ioProperty $ do-    jobCtl <- newSerialJobControl-    prop_submit jobCtl xs--prop_submit_parallel :: Positive (Small Int) -> [Int] -> Property-prop_submit_parallel (Positive (Small maxJobLimit)) xs =-  ioProperty $ do-    jobCtl <- newParallelJobControl maxJobLimit-    prop_submit jobCtl xs--prop_remaining_serial :: [Int] -> Property-prop_remaining_serial xs =-  ioProperty $ do-    jobCtl <- newSerialJobControl-    prop_remaining jobCtl xs--prop_remaining_parallel :: Positive (Small Int) -> [Int] -> Property-prop_remaining_parallel (Positive (Small maxJobLimit)) xs =-  ioProperty $ do-    jobCtl <- newParallelJobControl maxJobLimit-    prop_remaining jobCtl xs--prop_interleaved_serial :: [Int] -> Property-prop_interleaved_serial xs =-  ioProperty $ do-    jobCtl <- newSerialJobControl-    prop_submit_interleaved jobCtl xs--prop_interleaved_parallel :: Positive (Small Int) -> [Int] -> Property-prop_interleaved_parallel (Positive (Small maxJobLimit)) xs =-  ioProperty $ do-    jobCtl <- newParallelJobControl maxJobLimit-    prop_submit_interleaved jobCtl xs--prop_submit :: JobControl IO Int -> [Int] -> IO Bool-prop_submit jobCtl xs = do-    mapM_ (\x -> spawnJob jobCtl (return x)) xs-    xs' <- mapM (\_ -> collectJob jobCtl) xs-    return (sort xs == sort xs')--prop_remaining :: JobControl IO Int -> [Int] -> IO Bool-prop_remaining jobCtl xs = do-    mapM_ (\x -> spawnJob jobCtl (return x)) xs-    xs' <- collectRemainingJobs jobCtl-    return (sort xs == sort xs')--collectRemainingJobs :: Monad m => JobControl m a -> m [a]-collectRemainingJobs jobCtl = go []-  where-    go xs = do-      remaining <- remainingJobs jobCtl-      if remaining-        then do x <- collectJob jobCtl-                go (x:xs)-        else return xs--prop_submit_interleaved :: JobControl IO (Maybe Int) -> [Int] -> IO Bool-prop_submit_interleaved jobCtl xs = do-    xs' <- sequence-      [ spawn >> collect-      | let spawns   = map (\x -> spawnJob jobCtl (return (Just x))) xs-                    ++ repeat (return ())-            collects = replicate 5 (return Nothing)-                    ++ map (\_ -> collectJob jobCtl) xs-      , (spawn, collect) <- zip spawns collects-      ]-    return (sort xs == sort (catMaybes xs'))--prop_concurrent_serial :: NonNegative (Small Int) -> Property-prop_concurrent_serial (NonNegative (Small ntasks)) =-  ioProperty $ do-    jobCtl   <- newSerialJobControl-    countRef <- newIORef (0 :: Int)-    replicateM_ ntasks (spawnJob jobCtl (task countRef))-    counts   <- replicateM ntasks (collectJob jobCtl)-    return $ length counts == ntasks-          && all (\(n0, n1) -> n0 == 0 && n1 == 1) counts-  where-    task countRef = do-      n0 <- atomicModifyIORef countRef (\n -> (n+1, n))-      threadDelay 100-      n1 <- atomicModifyIORef countRef (\n -> (n-1, n))-      return (n0, n1)--prop_concurrent_parallel :: Positive (Small Int) -> NonNegative Int -> Property-prop_concurrent_parallel (Positive (Small maxJobLimit)) (NonNegative ntasks) =-  ioProperty $ do-    jobCtl   <- newParallelJobControl maxJobLimit-    countRef <- newIORef (0 :: Int)-    replicateM_ ntasks (spawnJob jobCtl (task countRef))-    counts   <- replicateM ntasks (collectJob jobCtl)-    return $ length counts == ntasks-          && all (\(n0, n1) -> n0 >= 0 && n0 <  maxJobLimit-                            && n1 >  0 && n1 <= maxJobLimit) counts-             -- we do hit the concurrency limit (in the right circumstances)-          && if ntasks >= maxJobLimit*2 -- give us enough of a margin-               then any (\(_,n1) -> n1 == maxJobLimit) counts-               else True-  where-    task countRef = do-      n0 <- atomicModifyIORef countRef (\n -> (n+1, n))-      threadDelay 100-      n1 <- atomicModifyIORef countRef (\n -> (n-1, n))-      return (n0, n1)--prop_cancel_serial :: [Int] -> [Int] -> Property-prop_cancel_serial xs ys =-  ioProperty $ do-    jobCtl <- newSerialJobControl-    mapM_ (\x -> spawnJob jobCtl (return x)) (xs++ys)-    xs' <- mapM (\_ -> collectJob jobCtl) xs-    cancelJobs jobCtl-    ys' <- collectRemainingJobs jobCtl-    return (sort xs == sort xs' && null ys')--prop_cancel_parallel :: Positive (Small Int) -> [Int] -> [Int] -> Property-prop_cancel_parallel (Positive (Small maxJobLimit)) xs ys = do-  ioProperty $ do-    jobCtl <- newParallelJobControl maxJobLimit-    mapM_ (\x -> spawnJob jobCtl (threadDelay 100  >> return x)) (xs++ys)-    xs' <- mapM (\_ -> collectJob jobCtl) xs-    cancelJobs jobCtl-    ys' <- collectRemainingJobs jobCtl-    return $ Set.fromList (xs'++ys') `Set.isSubsetOf` Set.fromList (xs++ys)--data TestException = TestException Int-  deriving (Typeable, Show)--instance Exception TestException--prop_exception_serial :: [Either Int Int] -> Property-prop_exception_serial xs =-  ioProperty $ do-    jobCtl <- newSerialJobControl-    prop_exception jobCtl xs--prop_exception_parallel :: Positive (Small Int) -> [Either Int Int] -> Property-prop_exception_parallel (Positive (Small maxJobLimit)) xs =-  ioProperty $ do-    jobCtl <- newParallelJobControl maxJobLimit-    prop_exception jobCtl xs--prop_exception :: JobControl IO Int -> [Either Int Int] -> IO Bool-prop_exception jobCtl xs = do-    mapM_ (\x -> spawnJob jobCtl (either (throwIO . TestException) return x)) xs-    xs' <- replicateM (length xs) $ do-             mx <- try (collectJob jobCtl)-             return $ case mx of-               Left (TestException n) -> Left  n-               Right               n  -> Right n-    return (sort xs == sort xs')-
− tests/UnitTests/Distribution/Client/ProjectConfig.hs
@@ -1,874 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module UnitTests.Distribution.Client.ProjectConfig (tests) where--#if !MIN_VERSION_base(4,8,0)-import Data.Monoid-import Control.Applicative-#endif-import Data.Map (Map)-import qualified Data.Map as Map-import Data.List--import Distribution.Package-import Distribution.PackageDescription hiding (Flag)-import Distribution.Compiler-import Distribution.Version-import Distribution.ParseUtils-import Distribution.Text as Text-import Distribution.Simple.Compiler-import Distribution.Simple.Setup-import Distribution.Simple.InstallDirs-import qualified Distribution.Compat.ReadP as Parse-import Distribution.Simple.Utils-import Distribution.Simple.Program.Types-import Distribution.Simple.Program.Db--import Distribution.Client.Types-import Distribution.Client.Dependency.Types-import Distribution.Client.BuildReports.Types-import Distribution.Client.Targets-import Distribution.Utils.NubList-import Network.URI--import Distribution.Solver.Types.PackageConstraint-import Distribution.Solver.Types.ConstraintSource-import Distribution.Solver.Types.OptionalStanza-import Distribution.Solver.Types.Settings--import Distribution.Client.ProjectConfig-import Distribution.Client.ProjectConfig.Legacy--import UnitTests.Distribution.Client.ArbitraryInstances--import Test.Tasty-import Test.Tasty.QuickCheck--tests :: [TestTree]-tests =-  [ testGroup "ProjectConfig <-> LegacyProjectConfig round trip" $-    [ testProperty "packages"  prop_roundtrip_legacytypes_packages-    , testProperty "buildonly" prop_roundtrip_legacytypes_buildonly-    , testProperty "specific"  prop_roundtrip_legacytypes_specific-    ] ++-    -- a couple tests seem to trigger a RTS fault in ghc-7.6 and older-    -- unclear why as of yet-    concat-    [ [ testProperty "shared"    prop_roundtrip_legacytypes_shared-      , testProperty "local"     prop_roundtrip_legacytypes_local-      , testProperty "all"       prop_roundtrip_legacytypes_all-      ]-    | not usingGhc76orOlder-    ]--  , testGroup "individual parser tests"-    [ testProperty "package location"  prop_parsePackageLocationTokenQ-    , testProperty "RelaxedDep"        prop_roundtrip_printparse_RelaxedDep-    , testProperty "RelaxDeps"         prop_roundtrip_printparse_RelaxDeps-    , testProperty "RelaxDeps'"        prop_roundtrip_printparse_RelaxDeps'-    ]--  , testGroup "ProjectConfig printing/parsing round trip"-    [ testProperty "packages"  prop_roundtrip_printparse_packages-    , testProperty "buildonly" prop_roundtrip_printparse_buildonly-    , testProperty "shared"    prop_roundtrip_printparse_shared-    , testProperty "local"     prop_roundtrip_printparse_local-    , testProperty "specific"  prop_roundtrip_printparse_specific-    , testProperty "all"       prop_roundtrip_printparse_all-    ]-  ]-  where-    usingGhc76orOlder =-      case buildCompilerId of-        CompilerId GHC v -> v < mkVersion [7,7]-        _                -> False------------------------------------------------------ Round trip: conversion to/from legacy types-----roundtrip :: Eq a => (a -> b) -> (b -> a) -> a -> Bool-roundtrip f f_inv x =-    (f_inv . f) x == x--roundtrip_legacytypes :: ProjectConfig -> Bool-roundtrip_legacytypes =-    roundtrip convertToLegacyProjectConfig-              convertLegacyProjectConfig---prop_roundtrip_legacytypes_all :: ProjectConfig -> Bool-prop_roundtrip_legacytypes_all config =-    roundtrip_legacytypes-      config {-        projectConfigProvenance = mempty-      }--prop_roundtrip_legacytypes_packages :: ProjectConfig -> Bool-prop_roundtrip_legacytypes_packages config =-    roundtrip_legacytypes-      config {-        projectConfigBuildOnly       = mempty,-        projectConfigShared          = mempty,-        projectConfigProvenance      = mempty,-        projectConfigLocalPackages   = mempty,-        projectConfigSpecificPackage = mempty-      }--prop_roundtrip_legacytypes_buildonly :: ProjectConfigBuildOnly -> Bool-prop_roundtrip_legacytypes_buildonly config =-    roundtrip_legacytypes-      mempty { projectConfigBuildOnly = config }--prop_roundtrip_legacytypes_shared :: ProjectConfigShared -> Bool-prop_roundtrip_legacytypes_shared config =-    roundtrip_legacytypes-      mempty { projectConfigShared = config }--prop_roundtrip_legacytypes_local :: PackageConfig -> Bool-prop_roundtrip_legacytypes_local config =-    roundtrip_legacytypes-      mempty { projectConfigLocalPackages = config }--prop_roundtrip_legacytypes_specific :: Map PackageName PackageConfig -> Bool-prop_roundtrip_legacytypes_specific config =-    roundtrip_legacytypes-      mempty { projectConfigSpecificPackage = MapMappend config }-------------------------------------------------- Round trip: printing and parsing config-----roundtrip_printparse :: ProjectConfig -> Bool-roundtrip_printparse config =-    case (fmap convertLegacyProjectConfig-        . parseLegacyProjectConfig-        . showLegacyProjectConfig-        . convertToLegacyProjectConfig)-          config of-      ParseOk _ x -> x == config { projectConfigProvenance = mempty }-      _           -> False---prop_roundtrip_printparse_all :: ProjectConfig -> Bool-prop_roundtrip_printparse_all config =-    roundtrip_printparse config {-      projectConfigBuildOnly =-        hackProjectConfigBuildOnly (projectConfigBuildOnly config),--      projectConfigShared =-        hackProjectConfigShared (projectConfigShared config)-    }--prop_roundtrip_printparse_packages :: [PackageLocationString]-                                   -> [PackageLocationString]-                                   -> [SourceRepo]-                                   -> [Dependency]-                                   -> Bool-prop_roundtrip_printparse_packages pkglocstrs1 pkglocstrs2 repos named =-    roundtrip_printparse-      mempty {-        projectPackages         = map getPackageLocationString pkglocstrs1,-        projectPackagesOptional = map getPackageLocationString pkglocstrs2,-        projectPackagesRepo     = repos,-        projectPackagesNamed    = named-      }--prop_roundtrip_printparse_buildonly :: ProjectConfigBuildOnly -> Bool-prop_roundtrip_printparse_buildonly config =-    roundtrip_printparse-      mempty {-        projectConfigBuildOnly = hackProjectConfigBuildOnly config-      }--hackProjectConfigBuildOnly :: ProjectConfigBuildOnly -> ProjectConfigBuildOnly-hackProjectConfigBuildOnly config =-    config {-      -- These two fields are only command line transitory things, not-      -- something to be recorded persistently in a config file-      projectConfigOnlyDeps = mempty,-      projectConfigDryRun   = mempty-    }--prop_roundtrip_printparse_shared :: ProjectConfigShared -> Bool-prop_roundtrip_printparse_shared config =-    roundtrip_printparse-      mempty {-        projectConfigShared = hackProjectConfigShared config-      }--hackProjectConfigShared :: ProjectConfigShared -> ProjectConfigShared-hackProjectConfigShared config =-    config {-      projectConfigProjectFile = mempty, -- not present within project files-      projectConfigConfigFile  = mempty, -- ditto-      projectConfigConstraints =-      --TODO: [required eventually] parse ambiguity in constraint-      -- "pkgname -any" as either any version or disabled flag "any".-        let ambiguous (UserConstraint _ (PackagePropertyFlags flags), _) =-              (not . null) [ () | (name, False) <- unFlagAssignment flags-                                , "any" `isPrefixOf` unFlagName name ]-            ambiguous _ = False-         in filter (not . ambiguous) (projectConfigConstraints config)-    }---prop_roundtrip_printparse_local :: PackageConfig -> Bool-prop_roundtrip_printparse_local config =-    roundtrip_printparse-      mempty {-        projectConfigLocalPackages = config-      }--prop_roundtrip_printparse_specific :: Map PackageName (NonMEmpty PackageConfig)-                                   -> Bool-prop_roundtrip_printparse_specific config =-    roundtrip_printparse-      mempty {-        projectConfigSpecificPackage = MapMappend (fmap getNonMEmpty config)-      }---------------------------------- Individual Parser tests------- | Helper to parse a given string------ Succeeds only if there is a unique complete parse-runReadP :: Parse.ReadP a a -> String -> Maybe a-runReadP parser s = case [ x | (x,"") <- Parse.readP_to_S parser s ] of-                      [x'] -> Just x'-                      _    -> Nothing--prop_parsePackageLocationTokenQ :: PackageLocationString -> Bool-prop_parsePackageLocationTokenQ (PackageLocationString str) =-    runReadP parsePackageLocationTokenQ (renderPackageLocationToken str) == Just str--prop_roundtrip_printparse_RelaxedDep :: RelaxedDep -> Bool-prop_roundtrip_printparse_RelaxedDep rdep =-    runReadP Text.parse (Text.display rdep) == Just rdep--prop_roundtrip_printparse_RelaxDeps :: RelaxDeps -> Bool-prop_roundtrip_printparse_RelaxDeps rdep =-    runReadP Text.parse (Text.display rdep) == Just rdep--prop_roundtrip_printparse_RelaxDeps' :: RelaxDeps -> Bool-prop_roundtrip_printparse_RelaxDeps' rdep =-    runReadP Text.parse (go $ Text.display rdep) == Just rdep-  where-    -- replace 'all' tokens by '*'-    go :: String -> String-    go [] = []-    go "all" = "*"-    go ('a':'l':'l':c:rest) | c `elem` ":," = '*' : go (c:rest)-    go rest = let (x,y) = break (`elem` ":,") rest-                  (x',y') = span (`elem` ":,^") y-              in x++x'++go y'----------------------------- Arbitrary instances-----instance Arbitrary ProjectConfig where-    arbitrary =-      ProjectConfig-        <$> (map getPackageLocationString <$> arbitrary)-        <*> (map getPackageLocationString <$> arbitrary)-        <*> shortListOf 3 arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> (MapMappend . fmap getNonMEmpty . Map.fromList-               <$> shortListOf 3 arbitrary)-        -- package entries with no content are equivalent to-        -- the entry not existing at all, so exclude empty--    shrink ProjectConfig { projectPackages = x0-                         , projectPackagesOptional = x1-                         , projectPackagesRepo = x2-                         , projectPackagesNamed = x3-                         , projectConfigBuildOnly = x4-                         , projectConfigShared = x5-                         , projectConfigProvenance = x6-                         , projectConfigLocalPackages = x7-                         , projectConfigSpecificPackage = x8-                         , projectConfigAllPackages = x9 } =-      [ ProjectConfig { projectPackages = x0'-                      , projectPackagesOptional = x1'-                      , projectPackagesRepo = x2'-                      , projectPackagesNamed = x3'-                      , projectConfigBuildOnly = x4'-                      , projectConfigShared = x5'-                      , projectConfigProvenance = x6'-                      , projectConfigLocalPackages = x7'-                      , projectConfigSpecificPackage = (MapMappend-                                                         (fmap getNonMEmpty x8'))-                      , projectConfigAllPackages = x9' }-      | ((x0', x1', x2', x3'), (x4', x5', x6', x7', x8', x9'))-          <- shrink ((x0, x1, x2, x3),-                      (x4, x5, x6, x7, fmap NonMEmpty (getMapMappend x8), x9))-      ]--newtype PackageLocationString-      = PackageLocationString { getPackageLocationString :: String }-  deriving Show--instance Arbitrary PackageLocationString where-  arbitrary =-    PackageLocationString <$>-    oneof-      [ show . getNonEmpty <$> (arbitrary :: Gen (NonEmptyList String))-      , arbitraryGlobLikeStr-      , show <$> (arbitrary :: Gen URI)-      ]--arbitraryGlobLikeStr :: Gen String-arbitraryGlobLikeStr = outerTerm-  where-    outerTerm  = concat <$> shortListOf1 4-                  (frequency [ (2, token)-                             , (1, braces <$> innerTerm) ])-    innerTerm  = intercalate "," <$> shortListOf1 3-                  (frequency [ (3, token)-                             , (1, braces <$> innerTerm) ])-    token      = shortListOf1 4 (elements (['#'..'~'] \\ "{,}"))-    braces s   = "{" ++ s ++ "}"---instance Arbitrary ProjectConfigBuildOnly where-    arbitrary =-      ProjectConfigBuildOnly-        <$> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> (toNubList <$> shortListOf 2 arbitrary)             --  4-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> (fmap getShortToken <$> arbitrary)                  --  8-        <*> arbitrary-        <*> arbitraryNumJobs-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> (fmap getShortToken <$> arbitrary)-        <*> arbitrary-        <*> (fmap getShortToken <$> arbitrary)-        <*> (fmap getShortToken <$> arbitrary)-        <*> (fmap getShortToken <$> arbitrary)-      where-        arbitraryNumJobs = fmap (fmap getPositive) <$> arbitrary--    shrink ProjectConfigBuildOnly { projectConfigVerbosity = x00-                                  , projectConfigDryRun = x01-                                  , projectConfigOnlyDeps = x02-                                  , projectConfigSummaryFile = x03-                                  , projectConfigLogFile = x04-                                  , projectConfigBuildReports = x05-                                  , projectConfigReportPlanningFailure = x06-                                  , projectConfigSymlinkBinDir = x07-                                  , projectConfigOneShot = x08-                                  , projectConfigNumJobs = x09-                                  , projectConfigKeepGoing = x10-                                  , projectConfigOfflineMode = x11-                                  , projectConfigKeepTempFiles = x12-                                  , projectConfigHttpTransport = x13-                                  , projectConfigIgnoreExpiry = x14-                                  , projectConfigCacheDir = x15-                                  , projectConfigLogsDir = x16-                                  , projectConfigStoreDir = x17 } =-      [ ProjectConfigBuildOnly { projectConfigVerbosity = x00'-                               , projectConfigDryRun = x01'-                               , projectConfigOnlyDeps = x02'-                               , projectConfigSummaryFile = x03'-                               , projectConfigLogFile = x04'-                               , projectConfigBuildReports = x05'-                               , projectConfigReportPlanningFailure = x06'-                               , projectConfigSymlinkBinDir = x07'-                               , projectConfigOneShot = x08'-                               , projectConfigNumJobs = postShrink_NumJobs x09'-                               , projectConfigKeepGoing = x10'-                               , projectConfigOfflineMode = x11'-                               , projectConfigKeepTempFiles = x12'-                               , projectConfigHttpTransport = x13-                               , projectConfigIgnoreExpiry = x14'-                               , projectConfigCacheDir = x15-                               , projectConfigLogsDir = x16-                               , projectConfigStoreDir = x17}-      | ((x00', x01', x02', x03', x04'),-         (x05', x06', x07', x08', x09'),-         (x10', x11', x12',       x14'))-          <- shrink-               ((x00, x01, x02, x03, x04),-                (x05, x06, x07, x08, preShrink_NumJobs x09),-                (x10, x11, x12,      x14))-      ]-      where-        preShrink_NumJobs  = fmap (fmap Positive)-        postShrink_NumJobs = fmap (fmap getPositive)--instance Arbitrary ProjectConfigShared where-    arbitrary =-      ProjectConfigShared-        <$> arbitraryFlag arbitraryShortToken-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitrary-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitrary-        <*> arbitrary-        <*> (toNubList <$> listOf arbitraryShortToken)-        <*> arbitrary-        <*> arbitraryConstraints-        <*> shortListOf 2 arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary-        <*> (toNubList <$> listOf arbitraryShortToken)-      where-        arbitraryConstraints :: Gen [(UserConstraint, ConstraintSource)]-        arbitraryConstraints =-            fmap (\uc -> (uc, projectConfigConstraintSource)) <$> arbitrary--    shrink ProjectConfigShared { projectConfigDistDir = x00-                               , projectConfigProjectFile = x01-                               , projectConfigHcFlavor = x02-                               , projectConfigHcPath = x03-                               , projectConfigHcPkg = x04-                               , projectConfigHaddockIndex = x05-                               , projectConfigRemoteRepos = x06-                               , projectConfigLocalRepos = x07-                               , projectConfigIndexState = x08-                               , projectConfigConstraints = x09-                               , projectConfigPreferences = x10-                               , projectConfigCabalVersion = x11-                               , projectConfigSolver = x12-                               , projectConfigAllowOlder = x13-                               , projectConfigAllowNewer = x14-                               , projectConfigMaxBackjumps = x15-                               , projectConfigReorderGoals = x16-                               , projectConfigCountConflicts = x17-                               , projectConfigStrongFlags = x18-                               , projectConfigAllowBootLibInstalls = x19-                               , projectConfigPerComponent = x20-                               , projectConfigIndependentGoals = x21-                               , projectConfigConfigFile = x22-                               , projectConfigProgPathExtra = x23} =-      [ ProjectConfigShared { projectConfigDistDir = x00'-                            , projectConfigProjectFile = x01'-                            , projectConfigHcFlavor = x02'-                            , projectConfigHcPath = fmap getNonEmpty x03'-                            , projectConfigHcPkg = fmap getNonEmpty x04'-                            , projectConfigHaddockIndex = x05'-                            , projectConfigRemoteRepos = x06'-                            , projectConfigLocalRepos = x07'-                            , projectConfigIndexState = x08'-                            , projectConfigConstraints = postShrink_Constraints x09'-                            , projectConfigPreferences = x10'-                            , projectConfigCabalVersion = x11'-                            , projectConfigSolver = x12'-                            , projectConfigAllowOlder = x13'-                            , projectConfigAllowNewer = x14'-                            , projectConfigMaxBackjumps = x15'-                            , projectConfigReorderGoals = x16'-                            , projectConfigCountConflicts = x17'-                            , projectConfigStrongFlags = x18'-                            , projectConfigAllowBootLibInstalls = x19'-                            , projectConfigPerComponent = x20'-                            , projectConfigIndependentGoals = x21'-                            , projectConfigConfigFile = x22'-                            , projectConfigProgPathExtra = x23'}-      | ((x00', x01', x02', x03', x04'),-         (x05', x06', x07', x08', x09'),-         (x10', x11', x12', x13', x14'),-         (x15', x16', x17', x18', x19'),-          x20', x21', x22', x23')-          <- shrink-               ((x00, x01, x02, fmap NonEmpty x03, fmap NonEmpty x04),-                (x05, x06, x07, x08, preShrink_Constraints x09),-                (x10, x11, x12, x13, x14),-                (x15, x16, x17, x18, x19),-                 x20, x21, x22, x23)-      ]-      where-        preShrink_Constraints  = map fst-        postShrink_Constraints = map (\uc -> (uc, projectConfigConstraintSource))--projectConfigConstraintSource :: ConstraintSource-projectConfigConstraintSource =-    ConstraintSourceProjectConfig "TODO"--instance Arbitrary ProjectConfigProvenance where-    arbitrary = elements [Implicit, Explicit "cabal.project"]--instance Arbitrary FlagAssignment where-    arbitrary = mkFlagAssignment <$> arbitrary--instance Arbitrary PackageConfig where-    arbitrary =-      PackageConfig-        <$> (MapLast . Map.fromList <$> shortListOf 10-              ((,) <$> arbitraryProgramName-                   <*> arbitraryShortToken))-        <*> (MapMappend . Map.fromList <$> shortListOf 10-              ((,) <$> arbitraryProgramName-                   <*> listOf arbitraryShortToken))-        <*> (toNubList <$> listOf arbitraryShortToken)-        <*> arbitrary-        <*> arbitrary <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> shortListOf 5 arbitraryShortToken-        <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> shortListOf 5 arbitraryShortToken-        <*> shortListOf 5 arbitraryShortToken-        <*> shortListOf 5 arbitraryShortToken-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitrary-        <*> arbitrary-        <*> arbitrary <*> arbitrary-        <*> arbitrary-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitrary-        <*> arbitraryFlag arbitraryShortToken-        <*> arbitrary-        <*> arbitrary-      where-        arbitraryProgramName :: Gen String-        arbitraryProgramName =-          elements [ programName prog-                   | (prog, _) <- knownPrograms (defaultProgramDb) ]--    shrink PackageConfig { packageConfigProgramPaths = x00-                         , packageConfigProgramArgs = x01-                         , packageConfigProgramPathExtra = x02-                         , packageConfigFlagAssignment = x03-                         , packageConfigVanillaLib = x04-                         , packageConfigSharedLib = x05-                         , packageConfigStaticLib = x42-                         , packageConfigDynExe = x06-                         , packageConfigProf = x07-                         , packageConfigProfLib = x08-                         , packageConfigProfExe = x09-                         , packageConfigProfDetail = x10-                         , packageConfigProfLibDetail = x11-                         , packageConfigConfigureArgs = x12-                         , packageConfigOptimization = x13-                         , packageConfigProgPrefix = x14-                         , packageConfigProgSuffix = x15-                         , packageConfigExtraLibDirs = x16-                         , packageConfigExtraFrameworkDirs = x17-                         , packageConfigExtraIncludeDirs = x18-                         , packageConfigGHCiLib = x19-                         , packageConfigSplitSections = x20-                         , packageConfigSplitObjs = x20_1-                         , packageConfigStripExes = x21-                         , packageConfigStripLibs = x22-                         , packageConfigTests = x23-                         , packageConfigBenchmarks = x24-                         , packageConfigCoverage = x25-                         , packageConfigRelocatable = x26-                         , packageConfigDebugInfo = x27-                         , packageConfigRunTests = x28-                         , packageConfigDocumentation = x29-                         , packageConfigHaddockHoogle = x30-                         , packageConfigHaddockHtml = x31-                         , packageConfigHaddockHtmlLocation = x32-                         , packageConfigHaddockForeignLibs = x33-                         , packageConfigHaddockExecutables = x33_1-                         , packageConfigHaddockTestSuites = x34-                         , packageConfigHaddockBenchmarks = x35-                         , packageConfigHaddockInternal = x36-                         , packageConfigHaddockCss = x37-                         , packageConfigHaddockLinkedSource = x38-                         , packageConfigHaddockHscolourCss = x39-                         , packageConfigHaddockContents = x40-                         , packageConfigHaddockForHackage = x41 } =-      [ PackageConfig { packageConfigProgramPaths = postShrink_Paths x00'-                      , packageConfigProgramArgs = postShrink_Args x01'-                      , packageConfigProgramPathExtra = x02'-                      , packageConfigFlagAssignment = x03'-                      , packageConfigVanillaLib = x04'-                      , packageConfigSharedLib = x05'-                      , packageConfigStaticLib = x42'-                      , packageConfigDynExe = x06'-                      , packageConfigProf = x07'-                      , packageConfigProfLib = x08'-                      , packageConfigProfExe = x09'-                      , packageConfigProfDetail = x10'-                      , packageConfigProfLibDetail = x11'-                      , packageConfigConfigureArgs = map getNonEmpty x12'-                      , packageConfigOptimization = x13'-                      , packageConfigProgPrefix = x14'-                      , packageConfigProgSuffix = x15'-                      , packageConfigExtraLibDirs = map getNonEmpty x16'-                      , packageConfigExtraFrameworkDirs = map getNonEmpty x17'-                      , packageConfigExtraIncludeDirs = map getNonEmpty x18'-                      , packageConfigGHCiLib = x19'-                      , packageConfigSplitSections = x20'-                      , packageConfigSplitObjs = x20_1'-                      , packageConfigStripExes = x21'-                      , packageConfigStripLibs = x22'-                      , packageConfigTests = x23'-                      , packageConfigBenchmarks = x24'-                      , packageConfigCoverage = x25'-                      , packageConfigRelocatable = x26'-                      , packageConfigDebugInfo = x27'-                      , packageConfigRunTests = x28'-                      , packageConfigDocumentation = x29'-                      , packageConfigHaddockHoogle = x30'-                      , packageConfigHaddockHtml = x31'-                      , packageConfigHaddockHtmlLocation = x32'-                      , packageConfigHaddockForeignLibs = x33'-                      , packageConfigHaddockExecutables = x33_1'-                      , packageConfigHaddockTestSuites = x34'-                      , packageConfigHaddockBenchmarks = x35'-                      , packageConfigHaddockInternal = x36'-                      , packageConfigHaddockCss = fmap getNonEmpty x37'-                      , packageConfigHaddockLinkedSource = x38'-                      , packageConfigHaddockHscolourCss = fmap getNonEmpty x39'-                      , packageConfigHaddockContents = x40'-                      , packageConfigHaddockForHackage = x41' }-      |  (((x00', x01', x02', x03', x04'),-          (x05', x42', x06', x07', x08', x09'),-          (x10', x11', x12', x13', x14'),-          (x15', x16', x17', x18', x19')),-         ((x20', x20_1', x21', x22', x23', x24'),-          (x25', x26', x27', x28', x29'),-          (x30', x31', x32', (x33', x33_1'), x34'),-          (x35', x36', x37', x38', x39'),-          (x40', x41')))-          <- shrink-             (((preShrink_Paths x00, preShrink_Args x01, x02, x03, x04),-                (x05, x42, x06, x07, x08, x09),-                (x10, x11, map NonEmpty x12, x13, x14),-                (x15, map NonEmpty x16,-                  map NonEmpty x17,-                  map NonEmpty x18,-                  x19)),-               ((x20, x20_1, x21, x22, x23, x24),-                 (x25, x26, x27, x28, x29),-                 (x30, x31, x32, (x33, x33_1), x34),-                 (x35, x36, fmap NonEmpty x37, x38, fmap NonEmpty x39),-                 (x40, x41)))-      ]-      where-        preShrink_Paths  = Map.map NonEmpty-                         . Map.mapKeys NoShrink-                         . getMapLast-        postShrink_Paths = MapLast-                         . Map.map getNonEmpty-                         . Map.mapKeys getNoShrink-        preShrink_Args   = Map.map (NonEmpty . map NonEmpty)-                         . Map.mapKeys NoShrink-                         . getMapMappend-        postShrink_Args  = MapMappend-                         . Map.map (map getNonEmpty . getNonEmpty)-                         . Map.mapKeys getNoShrink--instance Arbitrary HaddockTarget where-    arbitrary = elements [ForHackage, ForDevelopment]--instance Arbitrary SourceRepo where-    arbitrary = (SourceRepo RepoThis-                           <$> arbitrary-                           <*> (fmap getShortToken <$> arbitrary)-                           <*> (fmap getShortToken <$> arbitrary)-                           <*> (fmap getShortToken <$> arbitrary)-                           <*> (fmap getShortToken <$> arbitrary)-                           <*> (fmap getShortToken <$> arbitrary))-                `suchThat` (/= emptySourceRepo RepoThis)--    shrink (SourceRepo _ x1 x2 x3 x4 x5 x6) =-      [ repo-      | ((x1', x2', x3'), (x4', x5', x6'))-          <- shrink ((x1,-                      fmap ShortToken x2,-                      fmap ShortToken x3),-                     (fmap ShortToken x4,-                      fmap ShortToken x5,-                      fmap ShortToken x6))-      , let repo = SourceRepo RepoThis x1'-                              (fmap getShortToken x2')-                              (fmap getShortToken x3')-                              (fmap getShortToken x4')-                              (fmap getShortToken x5')-                              (fmap getShortToken x6')-      , repo /= emptySourceRepo RepoThis-      ]--instance Arbitrary RepoType where-    arbitrary = elements knownRepoTypes--instance Arbitrary ReportLevel where-    arbitrary = elements [NoReports .. DetailedReports]--instance Arbitrary CompilerFlavor where-    arbitrary = elements knownCompilerFlavors-      where-        --TODO: [code cleanup] export knownCompilerFlavors from D.Compiler-        -- it's already defined there, just need it exported.-        knownCompilerFlavors =-          [GHC, GHCJS, NHC, YHC, Hugs, HBC, Helium, JHC, LHC, UHC]--instance Arbitrary a => Arbitrary (InstallDirs a) where-    arbitrary =-      InstallDirs-        <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary --  4-        <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary --  8-        <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary -- 12-        <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary -- 16--instance Arbitrary PackageDB where-    arbitrary = oneof [ pure GlobalPackageDB-                      , pure UserPackageDB-                      , SpecificPackageDB . getShortToken <$> arbitrary-                      ]--instance Arbitrary RemoteRepo where-    arbitrary =-      RemoteRepo-        <$> arbitraryShortToken `suchThat` (not . (":" `isPrefixOf`))-        <*> arbitrary  -- URI-        <*> arbitrary-        <*> listOf arbitraryRootKey-        <*> (fmap getNonNegative arbitrary)-        <*> pure False-      where-        arbitraryRootKey =-          shortListOf1 5 (oneof [ choose ('0', '9')-                                , choose ('a', 'f') ])--instance Arbitrary UserConstraintScope where-    arbitrary = oneof [ UserQualified <$> arbitrary <*> arbitrary-                      , UserAnySetupQualifier <$> arbitrary-                      , UserAnyQualifier <$> arbitrary-                      ]--instance Arbitrary UserQualifier where-    arbitrary = oneof [ pure UserQualToplevel-                      , UserQualSetup <$> arbitrary--                      -- -- TODO: Re-enable UserQualExe tests once we decide on a syntax.-                      -- , UserQualExe <$> arbitrary <*> arbitrary-                      ]--instance Arbitrary UserConstraint where-    arbitrary = UserConstraint <$> arbitrary <*> arbitrary--instance Arbitrary PackageProperty where-    arbitrary = oneof [ PackagePropertyVersion <$> arbitrary-                      , pure PackagePropertyInstalled-                      , pure PackagePropertySource-                      , PackagePropertyFlags  . mkFlagAssignment <$> shortListOf1 3 arbitrary-                      , PackagePropertyStanzas . (\x->[x]) <$> arbitrary-                      ]--instance Arbitrary OptionalStanza where-    arbitrary = elements [minBound..maxBound]--instance Arbitrary FlagName where-    arbitrary = mkFlagName <$> flagident-      where-        flagident   = lowercase <$> shortListOf1 5 (elements flagChars)-                      `suchThat` (("-" /=) . take 1)-        flagChars   = "-_" ++ ['a'..'z']--instance Arbitrary PreSolver where-    arbitrary = elements [minBound..maxBound]--instance Arbitrary ReorderGoals where-    arbitrary = ReorderGoals <$> arbitrary--instance Arbitrary CountConflicts where-    arbitrary = CountConflicts <$> arbitrary--instance Arbitrary IndependentGoals where-    arbitrary = IndependentGoals <$> arbitrary--instance Arbitrary StrongFlags where-    arbitrary = StrongFlags <$> arbitrary--instance Arbitrary AllowBootLibInstalls where-    arbitrary = AllowBootLibInstalls <$> arbitrary--instance Arbitrary AllowNewer where-    arbitrary = AllowNewer <$> arbitrary--instance Arbitrary AllowOlder where-    arbitrary = AllowOlder <$> arbitrary--instance Arbitrary RelaxDeps where-    arbitrary = oneof [ pure mempty-                      , RelaxDepsSome <$> shortListOf1 3 arbitrary-                      , pure RelaxDepsAll-                      ]--instance Arbitrary RelaxDepMod where-    arbitrary = elements [RelaxDepModNone, RelaxDepModCaret]--instance Arbitrary RelaxDepScope where-    arbitrary = oneof [ pure RelaxDepScopeAll-                      , RelaxDepScopePackage <$> arbitrary-                      , RelaxDepScopePackageId <$> (PackageIdentifier <$> arbitrary <*> arbitrary)-                      ]--instance Arbitrary RelaxDepSubject where-    arbitrary = oneof [ pure RelaxDepSubjectAll-                      , RelaxDepSubjectPkg <$> arbitrary-                      ]--instance Arbitrary RelaxedDep where-    arbitrary = RelaxedDep <$> arbitrary <*> arbitrary <*> arbitrary--instance Arbitrary ProfDetailLevel where-    arbitrary = elements [ d | (_,_,d) <- knownProfDetailLevels ]--instance Arbitrary OptimisationLevel where-    arbitrary = elements [minBound..maxBound]--instance Arbitrary DebugInfoLevel where-    arbitrary = elements [minBound..maxBound]--instance Arbitrary URI where-    arbitrary =-      URI <$> elements ["file:", "http:", "https:"]-          <*> (Just <$> arbitrary)-          <*> (('/':) <$> arbitraryURIToken)-          <*> (('?':) <$> arbitraryURIToken)-          <*> pure ""--instance Arbitrary URIAuth where-    arbitrary =-      URIAuth <$> pure ""   -- no password as this does not roundtrip-              <*> arbitraryURIToken-              <*> arbitraryURIPort--arbitraryURIToken :: Gen String-arbitraryURIToken =-    shortListOf1 6 (elements (filter isUnreserved ['\0'..'\255']))--arbitraryURIPort :: Gen String-arbitraryURIPort =-    oneof [ pure "", (':':) <$> shortListOf1 4 (choose ('0','9')) ]
− tests/UnitTests/Distribution/Client/Sandbox.hs
@@ -1,28 +0,0 @@-module UnitTests.Distribution.Client.Sandbox (-  tests-  ) where--import Distribution.Client.Sandbox (withSandboxBinDirOnSearchPath)--import Test.Tasty-import Test.Tasty.HUnit--import System.FilePath             (getSearchPath, (</>))--tests :: [TestTree]-tests = [ testCase "sandboxBinDirOnSearchPath" sandboxBinDirOnSearchPathTest-        , testCase "oldSearchPathRestored" oldSearchPathRestoreTest-        ]--sandboxBinDirOnSearchPathTest :: Assertion-sandboxBinDirOnSearchPathTest =-  withSandboxBinDirOnSearchPath "foo" $ do-    r <- getSearchPath-    assertBool "'foo/bin' not on search path" $ ("foo" </> "bin") `elem` r--oldSearchPathRestoreTest :: Assertion-oldSearchPathRestoreTest = do-  r <- getSearchPath-  withSandboxBinDirOnSearchPath "foo" $ return ()-  r' <- getSearchPath-  assertEqual "Old search path wasn't restored" r r'
− tests/UnitTests/Distribution/Client/Sandbox/Timestamp.hs
@@ -1,63 +0,0 @@-module UnitTests.Distribution.Client.Sandbox.Timestamp (tests) where--import System.FilePath--import Distribution.Simple.Utils (withTempDirectory)-import Distribution.Verbosity--import Distribution.Compat.Time-import Distribution.Client.Sandbox.Timestamp--import Test.Tasty-import Test.Tasty.HUnit--tests :: [TestTree]-tests =-  [ testCase "timestamp record version 1 can be read" timestampReadTest_v1-  , testCase "timestamp record version 2 can be read" timestampReadTest_v2-  , testCase "written timestamp record can be read"   timestampReadWriteTest ]--timestampRecord_v1 :: String-timestampRecord_v1 =-  "[(\"i386-linux-ghc-8.0.0.20160204\",[(\"/foo/bar/Baz\",1455350946)])" ++-  ",(\"i386-linux-ghc-7.10.3\",[(\"/foo/bar/Baz\",1455484719)])]\n"--timestampRecord_v2 :: String-timestampRecord_v2 =-  "2\n" ++-  "[(\"i386-linux-ghc-8.0.0.20160204\",[(\"/foo/bar/Baz\",1455350946)])" ++-  ",(\"i386-linux-ghc-7.10.3\",[(\"/foo/bar/Baz\",1455484719)])]"--timestampReadTest_v1 :: Assertion-timestampReadTest_v1 =-  timestampReadTest timestampRecord_v1 $-  map (\(i, ts) ->-        (i, map (\(p, ModTime t) ->-                  (p, posixSecondsToModTime . fromIntegral $ t)) ts))-  timestampRecord--timestampReadTest_v2 :: Assertion-timestampReadTest_v2 = timestampReadTest timestampRecord_v2 timestampRecord--timestampReadTest :: FilePath -> [TimestampFileRecord] -> Assertion-timestampReadTest fileContent expected =-  withTempDirectory silent "." "cabal-timestamp-" $ \dir -> do-    let fileName = dir </> "timestamp-record"-    writeFile fileName fileContent-    tRec <- readTimestampFile normal fileName-    assertEqual "expected timestamp records to be equal"-      expected tRec--timestampRecord :: [TimestampFileRecord]-timestampRecord =-  [("i386-linux-ghc-8.0.0.20160204",[("/foo/bar/Baz",ModTime 1455350946)])-  ,("i386-linux-ghc-7.10.3",[("/foo/bar/Baz",ModTime 1455484719)])]--timestampReadWriteTest :: Assertion-timestampReadWriteTest =-  withTempDirectory silent "." "cabal-timestamp-" $ \dir -> do-    let fileName = dir </> "timestamp-record"-    writeTimestampFile fileName timestampRecord-    tRec <- readTimestampFile normal fileName-    assertEqual "expected timestamp records to be equal"-      timestampRecord tRec
− tests/UnitTests/Distribution/Client/Store.hs
@@ -1,181 +0,0 @@-module UnitTests.Distribution.Client.Store (tests) where----import Control.Monad---import Control.Concurrent (forkIO, threadDelay)---import Control.Concurrent.MVar-import qualified Data.Set as Set-import System.FilePath-import System.Directory---import System.Random--import Distribution.Package (UnitId, mkUnitId)-import Distribution.Compiler (CompilerId(..), CompilerFlavor(..))-import Distribution.Version  (mkVersion)-import Distribution.Verbosity (Verbosity, silent)-import Distribution.Simple.Utils (withTempDirectory)--import Distribution.Client.Store-import Distribution.Client.RebuildMonad--import Test.Tasty-import Test.Tasty.HUnit---tests :: [TestTree]-tests =-  [ testCase "list content empty"  testListEmpty-  , testCase "install serial"      testInstallSerial---, testCase "install parallel"    testInstallParallel-    --TODO: figure out some way to do a parallel test, see issue below-  ]---testListEmpty :: Assertion-testListEmpty =-  withTempDirectory verbosity "." "store-" $ \tmp -> do-    let storeDirLayout = defaultStoreDirLayout (tmp </> "store")--    assertStoreEntryExists storeDirLayout compid unitid False-    assertStoreContent tmp storeDirLayout compid        Set.empty-  where-    compid = CompilerId GHC (mkVersion [1,0])-    unitid = mkUnitId "foo-1.0-xyz"---testInstallSerial :: Assertion-testInstallSerial =-  withTempDirectory verbosity "." "store-" $ \tmp -> do-    let storeDirLayout = defaultStoreDirLayout (tmp </> "store")-        copyFiles file content dir = do-          -- we copy into a prefix inside the tmp dir and return the prefix-          let destprefix = dir </> "prefix"-          createDirectory destprefix-          writeFile (destprefix </> file) content-          return (destprefix,[])--    assertNewStoreEntry tmp storeDirLayout compid unitid1-                        (copyFiles "file1" "content-foo") (return ())-                        UseNewStoreEntry--    assertNewStoreEntry tmp storeDirLayout compid unitid1-                        (copyFiles "file1" "content-foo") (return ())-                        UseExistingStoreEntry--    assertNewStoreEntry tmp storeDirLayout compid unitid2-                        (copyFiles "file2" "content-bar") (return ())-                        UseNewStoreEntry--    let pkgDir :: UnitId -> FilePath-        pkgDir = storePackageDirectory storeDirLayout compid-    assertFileEqual (pkgDir unitid1 </> "file1") "content-foo"-    assertFileEqual (pkgDir unitid2 </> "file2") "content-bar"-  where-    compid  = CompilerId GHC (mkVersion [1,0])-    unitid1 = mkUnitId "foo-1.0-xyz"-    unitid2 = mkUnitId "bar-2.0-xyz"---{---- unfortunately a parallel test like the one below is thwarted by the normal--- process-internal file locking. If that locking were not in place then we--- ought to get the blocking behaviour, but due to the normal Handle locking--- it just fails instead.--testInstallParallel :: Assertion-testInstallParallel =-  withTempDirectory verbosity "." "store-" $ \tmp -> do-    let storeDirLayout = defaultStoreDirLayout (tmp </> "store")--    sync1 <- newEmptyMVar-    sync2 <- newEmptyMVar-    outv  <- newEmptyMVar-    regv  <- newMVar (0 :: Int)--    sequence_-      [ do forkIO $ do-             let copyFiles dir = do-                   delay <- randomRIO (1,100000)-                   writeFile (dir </> "file") (show n)-                   putMVar  sync1 ()-                   readMVar sync2-                   threadDelay delay-                 register = do-                   modifyMVar_ regv (return . (+1))-                   threadDelay 200000-             o <- newStoreEntry verbosity storeDirLayout-                                compid unitid-                                copyFiles register-             putMVar outv (n, o)-      | n <- [0..9 :: Int] ]--    replicateM_ 10 (takeMVar sync1)-    -- all threads are in the copyFiles action concurrently, release them:-    putMVar  sync2 ()--    outcomes <- replicateM 10 (takeMVar outv)-    regcount <- readMVar regv-    let regcount' = length [ () | (_, UseNewStoreEntry) <- outcomes ]--    assertEqual "num registrations" 1 regcount-    assertEqual "num registrations" 1 regcount'--    assertStoreContent tmp storeDirLayout compid (Set.singleton unitid)--    let pkgDir :: UnitId -> FilePath-        pkgDir = storePackageDirectory storeDirLayout compid-    case [ n | (n, UseNewStoreEntry) <- outcomes ] of-      [n] -> assertFileEqual (pkgDir unitid </> "file") (show n)-      _   -> assertFailure "impossible"--  where-    compid  = CompilerId GHC (mkVersion [1,0])-    unitid = mkUnitId "foo-1.0-xyz"--}------------------ Utils--assertNewStoreEntry :: FilePath -> StoreDirLayout-                    -> CompilerId -> UnitId-                    -> (FilePath -> IO (FilePath,[FilePath])) -> IO ()-                    -> NewStoreEntryOutcome-                    -> Assertion-assertNewStoreEntry tmp storeDirLayout compid unitid-                    copyFiles register expectedOutcome = do-    entries <- runRebuild tmp $ getStoreEntries storeDirLayout compid-    outcome <- newStoreEntry verbosity storeDirLayout-                             compid unitid-                             copyFiles register-    assertEqual "newStoreEntry outcome" expectedOutcome outcome-    assertStoreEntryExists storeDirLayout compid unitid True-    let expected = Set.insert unitid entries-    assertStoreContent tmp storeDirLayout compid expected---assertStoreEntryExists :: StoreDirLayout-                       -> CompilerId -> UnitId -> Bool-                       -> Assertion-assertStoreEntryExists storeDirLayout compid unitid expected = do-    actual <- doesStoreEntryExist storeDirLayout compid unitid-    assertEqual "store entry exists" expected actual---assertStoreContent :: FilePath -> StoreDirLayout-                   -> CompilerId -> Set.Set UnitId-                   -> Assertion-assertStoreContent tmp storeDirLayout compid expected = do-    actual <- runRebuild tmp $ getStoreEntries storeDirLayout compid-    assertEqual "store content" actual expected---assertFileEqual :: FilePath -> String -> Assertion-assertFileEqual path expected = do-    exists <- doesFileExist path-    assertBool ("file does not exist:\n" ++ path) exists-    actual <- readFile path-    assertEqual ("file content for:\n" ++ path) expected actual---verbosity :: Verbosity-verbosity = silent-
− tests/UnitTests/Distribution/Client/Tar.hs
@@ -1,75 +0,0 @@-module UnitTests.Distribution.Client.Tar (-  tests-  ) where--import Distribution.Client.Tar ( filterEntries-                               , filterEntriesM-                               )-import Codec.Archive.Tar       ( Entries(..)-                               , foldEntries-                               )-import Codec.Archive.Tar.Entry ( EntryContent(..)-                               , simpleEntry-                               , Entry(..)-                               , toTarPath-                               )--import Test.Tasty-import Test.Tasty.HUnit--import qualified Data.ByteString.Lazy as BS-import qualified Data.ByteString.Lazy.Char8 as BS.Char8-import Control.Monad.Writer.Lazy (runWriterT, tell)--tests :: [TestTree]-tests = [ testCase "filterEntries" filterTest-        , testCase "filterEntriesM" filterMTest-        ]--filterTest :: Assertion-filterTest = do-  let e1 = getFileEntry "file1" "x"-      e2 = getFileEntry "file2" "y"-      p = (\e -> let (NormalFile dta _) = entryContent e-                     str = BS.Char8.unpack dta-                 in str /= "y")-  assertEqual "Unexpected result for filter" "xz" $-    entriesToString $ filterEntries p $ Next e1 $ Next e2 Done-  assertEqual "Unexpected result for filter" "z" $-    entriesToString $ filterEntries p $ Done-  assertEqual "Unexpected result for filter" "xf" $-    entriesToString $ filterEntries p $ Next e1 $ Next e2 $ Fail "f"--filterMTest :: Assertion-filterMTest = do-  let e1 = getFileEntry "file1" "x"-      e2 = getFileEntry "file2" "y"-      p = (\e -> let (NormalFile dta _) = entryContent e-                     str = BS.Char8.unpack dta-                 in tell "t" >> return (str /= "y"))--  (r, w) <- runWriterT $ filterEntriesM p $ Next e1 $ Next e2 Done-  assertEqual "Unexpected result for filterM" "xz" $ entriesToString r-  assertEqual "Unexpected result for filterM w" "tt" w--  (r1, w1) <- runWriterT $ filterEntriesM p $ Done-  assertEqual "Unexpected result for filterM" "z" $ entriesToString r1-  assertEqual "Unexpected result for filterM w" "" w1--  (r2, w2) <- runWriterT $ filterEntriesM p $ Next e1 $ Next e2 $ Fail "f"-  assertEqual "Unexpected result for filterM" "xf" $ entriesToString r2-  assertEqual "Unexpected result for filterM w" "tt" w2--getFileEntry :: FilePath -> [Char] -> Entry-getFileEntry pth dta =-  simpleEntry tp $ NormalFile dta' $ BS.length dta'-  where  tp = case toTarPath False pth of-           Right tp' -> tp'-           Left e -> error e-         dta' = BS.Char8.pack dta--entriesToString :: Entries String -> String-entriesToString =-  foldEntries (\e acc -> let (NormalFile dta _) = entryContent e-                             str = BS.Char8.unpack dta-                          in str ++ acc) "z" id
− tests/UnitTests/Distribution/Client/Targets.hs
@@ -1,107 +0,0 @@-module UnitTests.Distribution.Client.Targets (-  tests-  ) where--import Distribution.Client.Targets     (UserQualifier(..)-                                       ,UserConstraintScope(..)-                                       ,UserConstraint(..), readUserConstraint)-import Distribution.Compat.ReadP       (readP_to_S)-import Distribution.Package            (mkPackageName)-import Distribution.PackageDescription (mkFlagName, mkFlagAssignment)-import Distribution.Version            (anyVersion, thisVersion, mkVersion)-import Distribution.ParseUtils         (parseCommaList)-import Distribution.Text               (parse)--import Distribution.Solver.Types.PackageConstraint (PackageProperty(..))-import Distribution.Solver.Types.OptionalStanza (OptionalStanza(..))--import Test.Tasty-import Test.Tasty.HUnit--import Data.Char                       (isSpace)-import Data.List                       (intercalate)---- Helper function: makes a test group by mapping each element--- of a list to a test case.-makeGroup :: String -> (a -> Assertion) -> [a] -> TestTree-makeGroup name f xs = testGroup name $-                      zipWith testCase (map show [0 :: Integer ..]) (map f xs)--tests :: [TestTree]-tests =-  [ makeGroup "readUserConstraint" (uncurry readUserConstraintTest)-      exampleConstraints--  , makeGroup "parseUserConstraint" (uncurry parseUserConstraintTest)-      exampleConstraints--  , makeGroup "readUserConstraints" (uncurry readUserConstraintsTest)-      [-- First example only.-       (head exampleStrs, take 1 exampleUcs),-       -- All examples separated by commas.-       (intercalate ", " exampleStrs, exampleUcs)]-  ]-  where-    (exampleStrs, exampleUcs) = unzip exampleConstraints--exampleConstraints :: [(String, UserConstraint)]-exampleConstraints =-  [ ("template-haskell installed",-     UserConstraint (UserQualified UserQualToplevel (pn "template-haskell"))-                    PackagePropertyInstalled)--  , ("bytestring -any",-     UserConstraint (UserQualified UserQualToplevel (pn "bytestring"))-                    (PackagePropertyVersion anyVersion))--  , ("any.directory test",-     UserConstraint (UserAnyQualifier (pn "directory"))-                    (PackagePropertyStanzas [TestStanzas]))--  , ("setup.Cabal installed",-     UserConstraint (UserAnySetupQualifier (pn "Cabal"))-                    PackagePropertyInstalled)--  , ("process:setup.bytestring ==5.2",-     UserConstraint (UserQualified (UserQualSetup (pn "process")) (pn "bytestring"))-                    (PackagePropertyVersion (thisVersion (mkVersion [5, 2]))))--  , ("network:setup.containers +foo -bar baz",-     UserConstraint (UserQualified (UserQualSetup (pn "network")) (pn "containers"))-                    (PackagePropertyFlags (mkFlagAssignment-                                          [(fn "foo", True),-                                           (fn "bar", False),-                                           (fn "baz", True)])))--  -- -- TODO: Re-enable UserQualExe tests once we decide on a syntax.-  ---  -- , ("foo:happy:exe.template-haskell test",-  --    UserConstraint (UserQualified (UserQualExe (pn "foo") (pn "happy")) (pn "template-haskell"))-  --                   (PackagePropertyStanzas [TestStanzas]))-  ]-  where-    pn = mkPackageName-    fn = mkFlagName--readUserConstraintTest :: String -> UserConstraint -> Assertion-readUserConstraintTest str uc =-  assertEqual ("Couldn't read constraint: '" ++ str ++ "'") expected actual-  where-    expected = uc-    actual   = let Right r = readUserConstraint str in r--parseUserConstraintTest :: String -> UserConstraint -> Assertion-parseUserConstraintTest str uc =-  assertEqual ("Couldn't parse constraint: '" ++ str ++ "'") expected actual-  where-    expected = [uc]-    actual   = [ x | (x, ys) <- readP_to_S parse str-                   , all isSpace ys]--readUserConstraintsTest :: String -> [UserConstraint] -> Assertion-readUserConstraintsTest str ucs =-  assertEqual ("Couldn't read constraints: '" ++ str ++ "'") expected actual-  where-    expected = [ucs]-    actual   = [ x | (x, ys) <- readP_to_S (parseCommaList parse) str-                   , all isSpace ys]
− tests/UnitTests/Distribution/Client/UserConfig.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE CPP #-}-module UnitTests.Distribution.Client.UserConfig-    ( tests-    ) where--import Control.Exception (bracket)-import Control.Monad (replicateM_)-import Data.List (sort, nub)-#if !MIN_VERSION_base(4,8,0)-import Data.Monoid-#endif-import System.Directory (doesFileExist,-                         getCurrentDirectory, getTemporaryDirectory)-import System.FilePath ((</>))--import Test.Tasty-import Test.Tasty.HUnit--import Distribution.Client.Config-import Distribution.Utils.NubList (fromNubList)-import Distribution.Client.Setup (GlobalFlags (..), InstallFlags (..))-import Distribution.Client.Utils (removeExistingFile)-import Distribution.Simple.Setup (Flag (..), ConfigFlags (..), fromFlag)-import Distribution.Simple.Utils (withTempDirectory)-import Distribution.Verbosity (silent)--tests :: [TestTree]-tests = [ testCase "nullDiffOnCreate" nullDiffOnCreateTest-        , testCase "canDetectDifference" canDetectDifference-        , testCase "canUpdateConfig" canUpdateConfig-        , testCase "doubleUpdateConfig" doubleUpdateConfig-        , testCase "newDefaultConfig" newDefaultConfig-        ]--nullDiffOnCreateTest :: Assertion-nullDiffOnCreateTest = bracketTest $ \configFile -> do-    -- Create a new default config file in our test directory.-    _ <- loadConfig silent (Flag configFile)-    -- Now we read it in and compare it against the default.-    diff <- userConfigDiff silent (globalFlags configFile) []-    assertBool (unlines $ "Following diff should be empty:" : diff) $ null diff---canDetectDifference :: Assertion-canDetectDifference = bracketTest $ \configFile -> do-    -- Create a new default config file in our test directory.-    _ <- loadConfig silent (Flag configFile)-    appendFile configFile "verbose: 0\n"-    diff <- userConfigDiff silent (globalFlags configFile) []-    assertBool (unlines $ "Should detect a difference:" : diff) $-        diff == [ "+ verbose: 0" ]---canUpdateConfig :: Assertion-canUpdateConfig = bracketTest $ \configFile -> do-    -- Write a trivial cabal file.-    writeFile configFile "tests: True\n"-    -- Update the config file.-    userConfigUpdate silent (globalFlags configFile) []-    -- Load it again.-    updated <- loadConfig silent (Flag configFile)-    assertBool ("Field 'tests' should be True") $-        fromFlag (configTests $ savedConfigureFlags updated)---doubleUpdateConfig :: Assertion-doubleUpdateConfig = bracketTest $ \configFile -> do-    -- Create a new default config file in our test directory.-    _ <- loadConfig silent (Flag configFile)-    -- Update it twice.-    replicateM_ 2 $ userConfigUpdate silent (globalFlags configFile) []-    -- Load it again.-    updated <- loadConfig silent (Flag configFile)--    assertBool ("Field 'remote-repo' doesn't contain duplicates") $-        listUnique (map show . fromNubList . globalRemoteRepos $ savedGlobalFlags updated)-    assertBool ("Field 'extra-prog-path' doesn't contain duplicates") $-        listUnique (map show . fromNubList . configProgramPathExtra $ savedConfigureFlags updated)-    assertBool ("Field 'build-summary' doesn't contain duplicates") $-        listUnique (map show . fromNubList . installSummaryFile $ savedInstallFlags updated)---newDefaultConfig :: Assertion-newDefaultConfig = do-    sysTmpDir <- getTemporaryDirectory-    withTempDirectory silent sysTmpDir "cabal-test" $ \tmpDir -> do-        let configFile  = tmpDir </> "tmp.config"-        _ <- createDefaultConfigFile silent [] configFile-        exists <- doesFileExist configFile-        assertBool ("Config file should be written to " ++ configFile) exists---globalFlags :: FilePath -> GlobalFlags-globalFlags configFile = mempty { globalConfigFile = Flag configFile }---listUnique :: Ord a => [a] -> Bool-listUnique xs =-    let sorted = sort xs-    in nub sorted == xs---bracketTest :: (FilePath -> IO ()) -> Assertion-bracketTest =-    bracket testSetup testTearDown-  where-    testSetup :: IO FilePath-    testSetup = fmap (</> "test-user-config") getCurrentDirectory--    testTearDown :: FilePath -> IO ()-    testTearDown configFile =-        mapM_ removeExistingFile [configFile, configFile ++ ".backup"]
− tests/UnitTests/Distribution/Solver/Modular/Builder.hs
@@ -1,20 +0,0 @@-module UnitTests.Distribution.Solver.Modular.Builder (-  tests-  ) where--import Distribution.Solver.Modular.Builder--import Test.Tasty-import Test.Tasty.QuickCheck--tests :: [TestTree]-tests = [ testProperty "splitsAltImplementation" splitsTest-        ]---- | Simpler splits implementation-splits' :: [a] -> [(a, [a])]-splits' [] = []-splits' (x : xs) = (x, xs) : map (\ (y, ys) -> (y, x : ys)) (splits' xs)--splitsTest :: [Int] -> Property-splitsTest xs = splits' xs === splits xs
− tests/UnitTests/Distribution/Solver/Modular/DSL.hs
@@ -1,698 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE ScopedTypeVariables #-}--- | DSL for testing the modular solver-module UnitTests.Distribution.Solver.Modular.DSL (-    ExampleDependency(..)-  , Dependencies(..)-  , ExTest(..)-  , ExExe(..)-  , ExConstraint(..)-  , ExPreference(..)-  , ExampleDb-  , ExampleVersionRange-  , ExamplePkgVersion-  , ExamplePkgName-  , ExampleFlagName-  , ExFlag(..)-  , ExampleAvailable(..)-  , ExampleInstalled(..)-  , ExampleQualifier(..)-  , ExampleVar(..)-  , EnableAllTests(..)-  , exAv-  , exInst-  , exFlagged-  , exResolve-  , extractInstallPlan-  , declareFlags-  , withSetupDeps-  , withTest-  , withTests-  , withExe-  , withExes-  , runProgress-  , mkSimpleVersion-  , mkVersionRange-  ) where--import Prelude ()-import Distribution.Solver.Compat.Prelude---- base-import Data.Either (partitionEithers)-import qualified Data.Map as Map---- Cabal-import qualified Distribution.Compiler                  as C-import qualified Distribution.InstalledPackageInfo      as IPI-import           Distribution.License (License(..))-import qualified Distribution.ModuleName                as Module-import qualified Distribution.Package                   as C-  hiding (HasUnitId(..))-import qualified Distribution.Types.ExeDependency as C-import qualified Distribution.Types.LegacyExeDependency as C-import qualified Distribution.Types.PkgconfigDependency as C-import qualified Distribution.Types.UnqualComponentName as C-import qualified Distribution.Types.CondTree            as C-import qualified Distribution.PackageDescription        as C-import qualified Distribution.PackageDescription.Check  as C-import qualified Distribution.Simple.PackageIndex       as C.PackageIndex-import           Distribution.Simple.Setup (BooleanFlag(..))-import qualified Distribution.System                    as C-import           Distribution.Text (display)-import qualified Distribution.Version                   as C-import Language.Haskell.Extension (Extension(..), Language(..))---- cabal-install-import Distribution.Client.Dependency-import Distribution.Client.Dependency.Types-import Distribution.Client.Types-import qualified Distribution.Client.SolverInstallPlan as CI.SolverInstallPlan--import           Distribution.Solver.Types.ComponentDeps (ComponentDeps)-import qualified Distribution.Solver.Types.ComponentDeps as CD-import           Distribution.Solver.Types.ConstraintSource-import           Distribution.Solver.Types.Flag-import           Distribution.Solver.Types.LabeledPackageConstraint-import           Distribution.Solver.Types.OptionalStanza-import qualified Distribution.Solver.Types.PackageIndex      as CI.PackageIndex-import           Distribution.Solver.Types.PackageConstraint-import qualified Distribution.Solver.Types.PackagePath as P-import qualified Distribution.Solver.Types.PkgConfigDb as PC-import           Distribution.Solver.Types.Settings-import           Distribution.Solver.Types.SolverPackage-import           Distribution.Solver.Types.SourcePackage-import           Distribution.Solver.Types.Variable--{--------------------------------------------------------------------------------  Example package database DSL--  In order to be able to set simple examples up quickly, we define a very-  simple version of the package database here explicitly designed for use in-  tests.--  The design of `ExampleDb` takes the perspective of the solver, not the-  perspective of the package DB. This makes it easier to set up tests for-  various parts of the solver, but makes the mapping somewhat awkward,  because-  it means we first map from "solver perspective" `ExampleDb` to the package-  database format, and then the modular solver internally in `IndexConversion`-  maps this back to the solver specific data structures.--  IMPLEMENTATION NOTES-  ----------------------  TODO: Perhaps these should be made comments of the corresponding data type-  definitions. For now these are just my own conclusions and may be wrong.--  * The difference between `GenericPackageDescription` and `PackageDescription`-    is that `PackageDescription` describes a particular _configuration_ of a-    package (for instance, see documentation for `checkPackage`). A-    `GenericPackageDescription` can be turned into a `PackageDescription` in-    two ways:--      a. `finalizePD` does the proper translation, by taking-         into account the platform, available dependencies, etc. and picks a-         flag assignment (or gives an error if no flag assignment can be found)-      b. `flattenPackageDescription` ignores flag assignment and just joins all-         components together.--    The slightly odd thing is that a `GenericPackageDescription` contains a-    `PackageDescription` as a field; both of the above functions do the same-    thing: they take the embedded `PackageDescription` as a basis for the result-    value, but override `library`, `executables`, `testSuites`, `benchmarks`-    and `buildDepends`.-  * The `condTreeComponents` fields of a `CondTree` is a list of triples-    `(condition, then-branch, else-branch)`, where the `else-branch` is-    optional.--------------------------------------------------------------------------------}--type ExamplePkgName    = String-type ExamplePkgVersion = Int-type ExamplePkgHash    = String  -- for example "installed" packages-type ExampleFlagName   = String-type ExampleTestName   = String-type ExampleExeName    = String-type ExampleVersionRange = C.VersionRange--data Dependencies = NotBuildable | Buildable [ExampleDependency]-  deriving Show--data ExampleDependency =-    -- | Simple dependency on any version-    ExAny ExamplePkgName--    -- | Simple dependency on a fixed version-  | ExFix ExamplePkgName ExamplePkgVersion--    -- | Simple dependency on a range of versions, with an inclusive lower bound-    -- and an exclusive upper bound.-  | ExRange ExamplePkgName ExamplePkgVersion ExamplePkgVersion--    -- | Build-tool-depends dependency-  | ExBuildToolAny ExamplePkgName ExampleExeName--    -- | Build-tool-depends dependency on a fixed version-  | ExBuildToolFix ExamplePkgName ExampleExeName ExamplePkgVersion--    -- | Legacy build-tools dependency-  | ExLegacyBuildToolAny ExamplePkgName--    -- | Legacy build-tools dependency on a fixed version-  | ExLegacyBuildToolFix ExamplePkgName ExamplePkgVersion--    -- | Dependencies indexed by a flag-  | ExFlagged ExampleFlagName Dependencies Dependencies--    -- | Dependency on a language extension-  | ExExt Extension--    -- | Dependency on a language version-  | ExLang Language--    -- | Dependency on a pkg-config package-  | ExPkg (ExamplePkgName, ExamplePkgVersion)-  deriving Show---- | Simplified version of D.Types.GenericPackageDescription.Flag for use in--- example source packages.-data ExFlag = ExFlag {-    exFlagName    :: ExampleFlagName-  , exFlagDefault :: Bool-  , exFlagType    :: FlagType-  } deriving Show--data ExTest = ExTest ExampleTestName [ExampleDependency]--data ExExe = ExExe ExampleExeName [ExampleDependency]--exFlagged :: ExampleFlagName -> [ExampleDependency] -> [ExampleDependency]-          -> ExampleDependency-exFlagged n t e = ExFlagged n (Buildable t) (Buildable e)--data ExConstraint =-    ExVersionConstraint ConstraintScope ExampleVersionRange-  | ExFlagConstraint ConstraintScope ExampleFlagName Bool-  | ExStanzaConstraint ConstraintScope [OptionalStanza]-  deriving Show--data ExPreference =-    ExPkgPref ExamplePkgName ExampleVersionRange-  | ExStanzaPref ExamplePkgName [OptionalStanza]-  deriving Show--data ExampleAvailable = ExAv {-    exAvName    :: ExamplePkgName-  , exAvVersion :: ExamplePkgVersion-  , exAvDeps    :: ComponentDeps [ExampleDependency]--  -- Setting flags here is only necessary to override the default values of-  -- the fields in C.Flag.-  , exAvFlags   :: [ExFlag]-  } deriving Show--data ExampleVar =-    P ExampleQualifier ExamplePkgName-  | F ExampleQualifier ExamplePkgName ExampleFlagName-  | S ExampleQualifier ExamplePkgName OptionalStanza--data ExampleQualifier =-    QualNone-  | QualIndep ExamplePkgName-  | QualSetup ExamplePkgName--    -- The two package names are the build target and the package containing the-    -- setup script.-  | QualIndepSetup ExamplePkgName ExamplePkgName--    -- The two package names are the package depending on the exe and the-    -- package containing the exe.-  | QualExe ExamplePkgName ExamplePkgName---- | Whether to enable tests in all packages in a test case.-newtype EnableAllTests = EnableAllTests Bool-  deriving BooleanFlag---- | Constructs an 'ExampleAvailable' package for the 'ExampleDb',--- given:------      1. The name 'ExamplePkgName' of the available package,---      2. The version 'ExamplePkgVersion' available---      3. The list of dependency constraints 'ExampleDependency'---         that this package has.  'ExampleDependency' provides---         a number of pre-canned dependency types to look at.----exAv :: ExamplePkgName -> ExamplePkgVersion -> [ExampleDependency]-     -> ExampleAvailable-exAv n v ds = ExAv { exAvName = n, exAvVersion = v-                   , exAvDeps = CD.fromLibraryDeps ds, exAvFlags = [] }---- | Override the default settings (e.g., manual vs. automatic) for a subset of--- a package's flags.-declareFlags :: [ExFlag] -> ExampleAvailable -> ExampleAvailable-declareFlags flags ex = ex {-      exAvFlags = flags-    }--withSetupDeps :: ExampleAvailable -> [ExampleDependency] -> ExampleAvailable-withSetupDeps ex setupDeps = ex {-      exAvDeps = exAvDeps ex <> CD.fromSetupDeps setupDeps-    }--withTest :: ExampleAvailable -> ExTest -> ExampleAvailable-withTest ex test = withTests ex [test]--withTests :: ExampleAvailable -> [ExTest] -> ExampleAvailable-withTests ex tests =-  let testCDs = CD.fromList [(CD.ComponentTest $ C.mkUnqualComponentName name, deps)-                            | ExTest name deps <- tests]-  in ex { exAvDeps = exAvDeps ex <> testCDs }--withExe :: ExampleAvailable -> ExExe -> ExampleAvailable-withExe ex exe = withExes ex [exe]--withExes :: ExampleAvailable -> [ExExe] -> ExampleAvailable-withExes ex exes =-  let exeCDs = CD.fromList [(CD.ComponentExe $ C.mkUnqualComponentName name, deps)-                           | ExExe name deps <- exes]-  in ex { exAvDeps = exAvDeps ex <> exeCDs }---- | An installed package in 'ExampleDb'; construct me with 'exInst'.-data ExampleInstalled = ExInst {-    exInstName         :: ExamplePkgName-  , exInstVersion      :: ExamplePkgVersion-  , exInstHash         :: ExamplePkgHash-  , exInstBuildAgainst :: [ExamplePkgHash]-  } deriving Show---- | Constructs an example installed package given:------      1. The name of the package 'ExamplePkgName', i.e., 'String'---      2. The version of the package 'ExamplePkgVersion', i.e., 'Int'---      3. The IPID for the package 'ExamplePkgHash', i.e., 'String'---         (just some unique identifier for the package.)---      4. The 'ExampleInstalled' packages which this package was---         compiled against.)----exInst :: ExamplePkgName -> ExamplePkgVersion -> ExamplePkgHash-       -> [ExampleInstalled] -> ExampleInstalled-exInst pn v hash deps = ExInst pn v hash (map exInstHash deps)---- | An example package database is a list of installed packages--- 'ExampleInstalled' and available packages 'ExampleAvailable'.--- Generally, you want to use 'exInst' and 'exAv' to construct--- these packages.-type ExampleDb = [Either ExampleInstalled ExampleAvailable]--type DependencyTree a = C.CondTree C.ConfVar [C.Dependency] a--type DependencyComponent a = C.CondBranch C.ConfVar [C.Dependency] a--exDbPkgs :: ExampleDb -> [ExamplePkgName]-exDbPkgs = map (either exInstName exAvName)--exAvSrcPkg :: ExampleAvailable -> UnresolvedSourcePackage-exAvSrcPkg ex =-    let pkgId = exAvPkgId ex--        flags :: [C.Flag]-        flags =-          let declaredFlags :: Map ExampleFlagName C.Flag-              declaredFlags =-                  Map.fromListWith-                      (\f1 f2 -> error $ "duplicate flag declarations: " ++ show [f1, f2])-                      [(exFlagName flag, mkFlag flag) | flag <- exAvFlags ex]--              usedFlags :: Map ExampleFlagName C.Flag-              usedFlags = Map.fromList [(fn, mkDefaultFlag fn) | fn <- names]-                where-                  names = concatMap extractFlags $-                          CD.libraryDeps (exAvDeps ex)-                           ++ concatMap snd testSuites-                           ++ concatMap snd executables-          in -- 'declaredFlags' overrides 'usedFlags' to give flags non-default settings:-             Map.elems $ declaredFlags `Map.union` usedFlags--        testSuites = [(name, deps) | (CD.ComponentTest name, deps) <- CD.toList (exAvDeps ex)]-        executables = [(name, deps) | (CD.ComponentExe name, deps) <- CD.toList (exAvDeps ex)]-        setup = case CD.setupDeps (exAvDeps ex) of-                  []   -> Nothing-                  deps -> Just C.SetupBuildInfo {-                            C.setupDepends = mkSetupDeps deps,-                            C.defaultSetupDepends = False-                          }-        package = SourcePackage {-            packageInfoId        = pkgId-          , packageSource        = LocalTarballPackage "<<path>>"-          , packageDescrOverride = Nothing-          , packageDescription   = C.GenericPackageDescription {-                C.packageDescription = C.emptyPackageDescription {-                    C.package        = pkgId-                  , C.setupBuildInfo = setup-                  , C.licenseRaw = Right BSD3-                  , C.buildTypeRaw = if isNothing setup-                                     then Just C.Simple-                                     else Just C.Custom-                  , C.category = "category"-                  , C.maintainer = "maintainer"-                  , C.description = "description"-                  , C.synopsis = "synopsis"-                  , C.licenseFiles = ["LICENSE"]-                  , C.specVersionRaw = Left $ C.mkVersion [1,12]-                  }-              , C.genPackageFlags = flags-              , C.condLibrary =-                  let mkLib bi = mempty { C.libBuildInfo = bi }-                  in Just $ mkCondTree defaultLib mkLib $ mkBuildInfoTree $-                     Buildable (CD.libraryDeps (exAvDeps ex))-              , C.condSubLibraries = []-              , C.condForeignLibs = []-              , C.condExecutables =-                  let mkTree = mkCondTree defaultExe mkExe . mkBuildInfoTree . Buildable-                      mkExe bi = mempty { C.buildInfo = bi }-                  in map (\(t, deps) -> (t, mkTree deps)) executables-              , C.condTestSuites =-                  let mkTree = mkCondTree defaultTest mkTest . mkBuildInfoTree . Buildable-                      mkTest bi = mempty { C.testBuildInfo = bi }-                  in map (\(t, deps) -> (t, mkTree deps)) testSuites-              , C.condBenchmarks  = []-              }-            }-        pkgCheckErrors =-          -- We ignore these warnings because some unit tests test that the-          -- solver allows unknown extensions/languages when the compiler-          -- supports them.-          let ignore = ["Unknown extensions:", "Unknown languages:"]-          in [ err | err <- C.checkPackage (packageDescription package) Nothing-             , not $ any (`isPrefixOf` C.explanation err) ignore ]-    in if null pkgCheckErrors-       then package-       else error $ "invalid GenericPackageDescription for package "-                 ++ display pkgId ++ ": " ++ show pkgCheckErrors-  where-    defaultTopLevelBuildInfo :: C.BuildInfo-    defaultTopLevelBuildInfo = mempty { C.defaultLanguage = Just Haskell98 }--    defaultLib :: C.Library-    defaultLib = mempty { C.exposedModules = [Module.fromString "Module"] }--    defaultExe :: C.Executable-    defaultExe = mempty { C.modulePath = "Main.hs" }--    defaultTest :: C.TestSuite-    defaultTest = mempty {-        C.testInterface = C.TestSuiteExeV10 (C.mkVersion [1,0]) "Test.hs"-      }--    -- Split the set of dependencies into the set of dependencies of the library,-    -- the dependencies of the test suites and extensions.-    splitTopLevel :: [ExampleDependency]-                  -> ( [ExampleDependency]-                     , [Extension]-                     , Maybe Language-                     , [(ExamplePkgName, ExamplePkgVersion)] -- pkg-config-                     , [(ExamplePkgName, ExampleExeName, C.VersionRange)] -- build tools-                     , [(ExamplePkgName, C.VersionRange)] -- legacy build tools-                     )-    splitTopLevel [] =-        ([], [], Nothing, [], [], [])-    splitTopLevel (ExBuildToolAny p e:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (other, exts, lang, pcpkgs, (p, e, C.anyVersion):exes, legacyExes)-    splitTopLevel (ExBuildToolFix p e v:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (other, exts, lang, pcpkgs, (p, e, C.thisVersion (mkSimpleVersion v)):exes, legacyExes)-    splitTopLevel (ExLegacyBuildToolAny p:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (other, exts, lang, pcpkgs, exes, (p, C.anyVersion):legacyExes)-    splitTopLevel (ExLegacyBuildToolFix p v:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (other, exts, lang, pcpkgs, exes, (p, C.thisVersion (mkSimpleVersion v)):legacyExes)-    splitTopLevel (ExExt ext:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (other, ext:exts, lang, pcpkgs, exes, legacyExes)-    splitTopLevel (ExLang lang:deps) =-        case splitTopLevel deps of-            (other, exts, Nothing, pcpkgs, exes, legacyExes) -> (other, exts, Just lang, pcpkgs, exes, legacyExes)-            _ -> error "Only 1 Language dependency is supported"-    splitTopLevel (ExPkg pkg:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (other, exts, lang, pkg:pcpkgs, exes, legacyExes)-    splitTopLevel (dep:deps) =-      let (other, exts, lang, pcpkgs, exes, legacyExes) = splitTopLevel deps-      in (dep:other, exts, lang, pcpkgs, exes, legacyExes)--    -- Extract the total set of flags used-    extractFlags :: ExampleDependency -> [ExampleFlagName]-    extractFlags (ExAny _)            = []-    extractFlags (ExFix _ _)          = []-    extractFlags (ExRange _ _ _)      = []-    extractFlags (ExBuildToolAny _ _)   = []-    extractFlags (ExBuildToolFix _ _ _) = []-    extractFlags (ExLegacyBuildToolAny _)   = []-    extractFlags (ExLegacyBuildToolFix _ _) = []-    extractFlags (ExFlagged f a b)    =-        f : concatMap extractFlags (deps a ++ deps b)-      where-        deps :: Dependencies -> [ExampleDependency]-        deps NotBuildable = []-        deps (Buildable ds) = ds-    extractFlags (ExExt _)      = []-    extractFlags (ExLang _)     = []-    extractFlags (ExPkg _)      = []--    -- Convert a tree of BuildInfos into a tree of a specific component type.-    -- 'defaultTopLevel' contains the default values for the component, and-    -- 'mkComponent' creates a component from a 'BuildInfo'.-    mkCondTree :: forall a. Semigroup a =>-                  a -> (C.BuildInfo -> a)-               -> DependencyTree C.BuildInfo-               -> DependencyTree a-    mkCondTree defaultTopLevel mkComponent (C.CondNode topData topConstraints topComps) =-        C.CondNode {-            C.condTreeData =-                defaultTopLevel <> mkComponent (defaultTopLevelBuildInfo <> topData)-          , C.condTreeConstraints = topConstraints-          , C.condTreeComponents = goComponents topComps-          }-      where-        go :: DependencyTree C.BuildInfo -> DependencyTree a-        go (C.CondNode ctData constraints comps) =-            C.CondNode (mkComponent ctData) constraints (goComponents comps)--        goComponents :: [DependencyComponent C.BuildInfo]-                     -> [DependencyComponent a]-        goComponents comps = [C.CondBranch cond (go t) (go <$> me) | C.CondBranch cond t me <- comps]--    mkBuildInfoTree :: Dependencies -> DependencyTree C.BuildInfo-    mkBuildInfoTree NotBuildable =-      C.CondNode {-             C.condTreeData        = mempty { C.buildable = False }-           , C.condTreeConstraints = []-           , C.condTreeComponents  = []-           }-    mkBuildInfoTree (Buildable deps) =-      let (libraryDeps, exts, mlang, pcpkgs, buildTools, legacyBuildTools) = splitTopLevel deps-          (directDeps, flaggedDeps) = splitDeps libraryDeps-          bi = mempty {-                  C.otherExtensions = exts-                , C.defaultLanguage = mlang-                , C.buildToolDepends = [ C.ExeDependency (C.mkPackageName p) (C.mkUnqualComponentName e) vr-                                       | (p, e, vr) <- buildTools]-                , C.buildTools = [ C.LegacyExeDependency n vr-                                 | (n,vr) <- legacyBuildTools]-                , C.pkgconfigDepends = [ C.PkgconfigDependency n' v'-                                       | (n,v) <- pcpkgs-                                       , let n' = C.mkPkgconfigName n-                                       , let v' = C.thisVersion (mkSimpleVersion v) ]-              }-      in C.CondNode {-             C.condTreeData        = bi -- Necessary for language extensions-           -- TODO: Arguably, build-tools dependencies should also-           -- effect constraints on conditional tree. But no way to-           -- distinguish between them-           , C.condTreeConstraints = map mkDirect directDeps-           , C.condTreeComponents  = map mkFlagged flaggedDeps-           }--    mkDirect :: (ExamplePkgName, C.VersionRange) -> C.Dependency-    mkDirect (dep, vr) = C.Dependency (C.mkPackageName dep) vr--    mkFlagged :: (ExampleFlagName, Dependencies, Dependencies)-              -> DependencyComponent C.BuildInfo-    mkFlagged (f, a, b) =-        C.CondBranch (C.Var (C.Flag (C.mkFlagName f)))-                     (mkBuildInfoTree a)-                     (Just (mkBuildInfoTree b))--    -- Split a set of dependencies into direct dependencies and flagged-    -- dependencies. A direct dependency is a tuple of the name of package and-    -- its version range meant to be converted to a 'C.Dependency' with-    -- 'mkDirect' for example. A flagged dependency is the set of dependencies-    -- guarded by a flag.-    splitDeps :: [ExampleDependency]-              -> ( [(ExamplePkgName, C.VersionRange)]-                 , [(ExampleFlagName, Dependencies, Dependencies)]-                 )-    splitDeps [] =-      ([], [])-    splitDeps (ExAny p:deps) =-      let (directDeps, flaggedDeps) = splitDeps deps-      in ((p, C.anyVersion):directDeps, flaggedDeps)-    splitDeps (ExFix p v:deps) =-      let (directDeps, flaggedDeps) = splitDeps deps-      in ((p, C.thisVersion $ mkSimpleVersion v):directDeps, flaggedDeps)-    splitDeps (ExRange p v1 v2:deps) =-      let (directDeps, flaggedDeps) = splitDeps deps-      in ((p, mkVersionRange v1 v2):directDeps, flaggedDeps)-    splitDeps (ExFlagged f a b:deps) =-      let (directDeps, flaggedDeps) = splitDeps deps-      in (directDeps, (f, a, b):flaggedDeps)-    splitDeps (dep:_) = error $ "Unexpected dependency: " ++ show dep--    -- custom-setup only supports simple dependencies-    mkSetupDeps :: [ExampleDependency] -> [C.Dependency]-    mkSetupDeps deps =-      let (directDeps, []) = splitDeps deps in map mkDirect directDeps--mkSimpleVersion :: ExamplePkgVersion -> C.Version-mkSimpleVersion n = C.mkVersion [n, 0, 0]--mkVersionRange :: ExamplePkgVersion -> ExamplePkgVersion -> C.VersionRange-mkVersionRange v1 v2 =-    C.intersectVersionRanges (C.orLaterVersion $ mkSimpleVersion v1)-                             (C.earlierVersion $ mkSimpleVersion v2)--mkFlag :: ExFlag -> C.Flag-mkFlag flag = C.MkFlag {-    C.flagName        = C.mkFlagName $ exFlagName flag-  , C.flagDescription = ""-  , C.flagDefault     = exFlagDefault flag-  , C.flagManual      =-      case exFlagType flag of-        Manual    -> True-        Automatic -> False-  }--mkDefaultFlag :: ExampleFlagName -> C.Flag-mkDefaultFlag flag = C.MkFlag {-    C.flagName        = C.mkFlagName flag-  , C.flagDescription = ""-  , C.flagDefault     = True-  , C.flagManual      = False-  }--exAvPkgId :: ExampleAvailable -> C.PackageIdentifier-exAvPkgId ex = C.PackageIdentifier {-      pkgName    = C.mkPackageName (exAvName ex)-    , pkgVersion = C.mkVersion [exAvVersion ex, 0, 0]-    }--exInstInfo :: ExampleInstalled -> IPI.InstalledPackageInfo-exInstInfo ex = IPI.emptyInstalledPackageInfo {-      IPI.installedUnitId    = C.mkUnitId (exInstHash ex)-    , IPI.sourcePackageId    = exInstPkgId ex-    , IPI.depends            = map C.mkUnitId (exInstBuildAgainst ex)-    }--exInstPkgId :: ExampleInstalled -> C.PackageIdentifier-exInstPkgId ex = C.PackageIdentifier {-      pkgName    = C.mkPackageName (exInstName ex)-    , pkgVersion = C.mkVersion [exInstVersion ex, 0, 0]-    }--exAvIdx :: [ExampleAvailable] -> CI.PackageIndex.PackageIndex UnresolvedSourcePackage-exAvIdx = CI.PackageIndex.fromList . map exAvSrcPkg--exInstIdx :: [ExampleInstalled] -> C.PackageIndex.InstalledPackageIndex-exInstIdx = C.PackageIndex.fromList . map exInstInfo--exResolve :: ExampleDb-          -- List of extensions supported by the compiler, or Nothing if unknown.-          -> Maybe [Extension]-          -- List of languages supported by the compiler, or Nothing if unknown.-          -> Maybe [Language]-          -> PC.PkgConfigDb-          -> [ExamplePkgName]-          -> Maybe Int-          -> CountConflicts-          -> IndependentGoals-          -> ReorderGoals-          -> AllowBootLibInstalls-          -> EnableBackjumping-          -> SolveExecutables-          -> Maybe (Variable P.QPN -> Variable P.QPN -> Ordering)-          -> [ExConstraint]-          -> [ExPreference]-          -> EnableAllTests-          -> Progress String String CI.SolverInstallPlan.SolverInstallPlan-exResolve db exts langs pkgConfigDb targets mbj countConflicts indepGoals-          reorder allowBootLibInstalls enableBj solveExes goalOrder constraints-          prefs enableAllTests-    = resolveDependencies C.buildPlatform compiler pkgConfigDb Modular params-  where-    defaultCompiler = C.unknownCompilerInfo C.buildCompilerId C.NoAbiTag-    compiler = defaultCompiler { C.compilerInfoExtensions = exts-                               , C.compilerInfoLanguages  = langs-                               }-    (inst, avai) = partitionEithers db-    instIdx      = exInstIdx inst-    avaiIdx      = SourcePackageDb {-                       packageIndex       = exAvIdx avai-                     , packagePreferences = Map.empty-                     }-    enableTests-        | asBool enableAllTests = fmap (\p -> PackageConstraint-                                              (scopeToplevel (C.mkPackageName p))-                                              (PackagePropertyStanzas [TestStanzas]))-                                       (exDbPkgs db)-        | otherwise             = []-    targets'     = fmap (\p -> NamedPackage (C.mkPackageName p) []) targets-    params       =   addConstraints (fmap toConstraint constraints)-                   $ addConstraints (fmap toLpc enableTests)-                   $ addPreferences (fmap toPref prefs)-                   $ setCountConflicts countConflicts-                   $ setIndependentGoals indepGoals-                   $ setReorderGoals reorder-                   $ setMaxBackjumps mbj-                   $ setAllowBootLibInstalls allowBootLibInstalls-                   $ setEnableBackjumping enableBj-                   $ setSolveExecutables solveExes-                   $ setGoalOrder goalOrder-                   $ standardInstallPolicy instIdx avaiIdx targets'-    toLpc     pc = LabeledPackageConstraint pc ConstraintSourceUnknown--    toConstraint (ExVersionConstraint scope v) =-        toLpc $ PackageConstraint scope (PackagePropertyVersion v)-    toConstraint (ExFlagConstraint scope fn b) =-        toLpc $ PackageConstraint scope (PackagePropertyFlags (C.mkFlagAssignment [(C.mkFlagName fn, b)]))-    toConstraint (ExStanzaConstraint scope stanzas) =-        toLpc $ PackageConstraint scope (PackagePropertyStanzas stanzas)--    toPref (ExPkgPref n v)          = PackageVersionPreference (C.mkPackageName n) v-    toPref (ExStanzaPref n stanzas) = PackageStanzasPreference (C.mkPackageName n) stanzas--extractInstallPlan :: CI.SolverInstallPlan.SolverInstallPlan-                   -> [(ExamplePkgName, ExamplePkgVersion)]-extractInstallPlan = catMaybes . map confPkg . CI.SolverInstallPlan.toList-  where-    confPkg :: CI.SolverInstallPlan.SolverPlanPackage -> Maybe (String, Int)-    confPkg (CI.SolverInstallPlan.Configured pkg) = Just $ srcPkg pkg-    confPkg _                               = Nothing--    srcPkg :: SolverPackage UnresolvedPkgLoc -> (String, Int)-    srcPkg cpkg =-      let C.PackageIdentifier pn ver = packageInfoId (solverPkgSource cpkg)-      in (C.unPackageName pn, head (C.versionNumbers ver))--{--------------------------------------------------------------------------------  Auxiliary--------------------------------------------------------------------------------}---- | Run Progress computation-runProgress :: Progress step e a -> ([step], Either e a)-runProgress = go-  where-    go (Step s p) = let (ss, result) = go p in (s:ss, result)-    go (Fail e)   = ([], Left e)-    go (Done a)   = ([], Right a)
− tests/UnitTests/Distribution/Solver/Modular/DSL/TestCaseUtils.hs
@@ -1,254 +0,0 @@-{-# LANGUAGE RecordWildCards #-}--- | Utilities for creating HUnit test cases with the solver DSL.-module UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils (-    SolverTest-  , SolverResult(..)-  , maxBackjumps-  , independentGoals-  , allowBootLibInstalls-  , disableBackjumping-  , disableSolveExecutables-  , goalOrder-  , constraints-  , preferences-  , enableAllTests-  , solverSuccess-  , solverFailure-  , anySolverFailure-  , mkTest-  , mkTestExts-  , mkTestLangs-  , mkTestPCDepends-  , mkTestExtLangPC-  , runTest-  ) where--import Prelude ()-import Distribution.Solver.Compat.Prelude--import Data.List (elemIndex)-import Data.Ord (comparing)---- test-framework-import Test.Tasty as TF-import Test.Tasty.HUnit (testCase, assertEqual, assertBool)---- Cabal-import qualified Distribution.PackageDescription as C-import qualified Distribution.Types.PackageName as C-import Language.Haskell.Extension (Extension(..), Language(..))---- cabal-install-import qualified Distribution.Solver.Types.PackagePath as P-import Distribution.Solver.Types.PkgConfigDb (PkgConfigDb, pkgConfigDbFromList)-import Distribution.Solver.Types.Settings-import Distribution.Solver.Types.Variable-import Distribution.Client.Dependency (foldProgress)-import UnitTests.Distribution.Solver.Modular.DSL-import UnitTests.Options--maxBackjumps :: Maybe Int -> SolverTest -> SolverTest-maxBackjumps mbj test = test { testMaxBackjumps = mbj }---- | Combinator to turn on --independent-goals behavior, i.e. solve--- for the goals as if we were solving for each goal independently.-independentGoals :: SolverTest -> SolverTest-independentGoals test = test { testIndepGoals = IndependentGoals True }--allowBootLibInstalls :: SolverTest -> SolverTest-allowBootLibInstalls test =-    test { testAllowBootLibInstalls = AllowBootLibInstalls True }--disableBackjumping :: SolverTest -> SolverTest-disableBackjumping test =-    test { testEnableBackjumping = EnableBackjumping False }--disableSolveExecutables :: SolverTest -> SolverTest-disableSolveExecutables test =-    test { testSolveExecutables = SolveExecutables False }--goalOrder :: [ExampleVar] -> SolverTest -> SolverTest-goalOrder order test = test { testGoalOrder = Just order }--constraints :: [ExConstraint] -> SolverTest -> SolverTest-constraints cs test = test { testConstraints = cs }--preferences :: [ExPreference] -> SolverTest -> SolverTest-preferences prefs test = test { testSoftConstraints = prefs }--enableAllTests :: SolverTest -> SolverTest-enableAllTests test = test { testEnableAllTests = EnableAllTests True }--{--------------------------------------------------------------------------------  Solver tests--------------------------------------------------------------------------------}--data SolverTest = SolverTest {-    testLabel                :: String-  , testTargets              :: [String]-  , testResult               :: SolverResult-  , testMaxBackjumps         :: Maybe Int-  , testIndepGoals           :: IndependentGoals-  , testAllowBootLibInstalls :: AllowBootLibInstalls-  , testEnableBackjumping    :: EnableBackjumping-  , testSolveExecutables     :: SolveExecutables-  , testGoalOrder            :: Maybe [ExampleVar]-  , testConstraints          :: [ExConstraint]-  , testSoftConstraints      :: [ExPreference]-  , testDb                   :: ExampleDb-  , testSupportedExts        :: Maybe [Extension]-  , testSupportedLangs       :: Maybe [Language]-  , testPkgConfigDb          :: PkgConfigDb-  , testEnableAllTests       :: EnableAllTests-  }---- | Expected result of a solver test.-data SolverResult = SolverResult {-    -- | The solver's log should satisfy this predicate. Note that we also print-    -- the log, so evaluating a large log here can cause a space leak.-    resultLogPredicate            :: [String] -> Bool,--    -- | Fails with an error message satisfying the predicate, or succeeds with-    -- the given plan.-    resultErrorMsgPredicateOrPlan :: Either (String -> Bool) [(String, Int)]-  }--solverSuccess :: [(String, Int)] -> SolverResult-solverSuccess = SolverResult (const True) . Right--solverFailure :: (String -> Bool) -> SolverResult-solverFailure = SolverResult (const True) . Left---- | Can be used for test cases where we just want to verify that--- they fail, but do not care about the error message.-anySolverFailure :: SolverResult-anySolverFailure = solverFailure (const True)---- | Makes a solver test case, consisting of the following components:------      1. An 'ExampleDb', representing the package database (both---         installed and remote) we are doing dependency solving over,---      2. A 'String' name for the test,---      3. A list '[String]' of package names to solve for---      4. The expected result, either 'Nothing' if there is no---         satisfying solution, or a list '[(String, Int)]' of---         packages to install, at which versions.------ See 'UnitTests.Distribution.Solver.Modular.DSL' for how--- to construct an 'ExampleDb', as well as definitions of 'db1' etc.--- in this file.-mkTest :: ExampleDb-       -> String-       -> [String]-       -> SolverResult-       -> SolverTest-mkTest = mkTestExtLangPC Nothing Nothing []--mkTestExts :: [Extension]-           -> ExampleDb-           -> String-           -> [String]-           -> SolverResult-           -> SolverTest-mkTestExts exts = mkTestExtLangPC (Just exts) Nothing []--mkTestLangs :: [Language]-            -> ExampleDb-            -> String-            -> [String]-            -> SolverResult-            -> SolverTest-mkTestLangs langs = mkTestExtLangPC Nothing (Just langs) []--mkTestPCDepends :: [(String, String)]-                -> ExampleDb-                -> String-                -> [String]-                -> SolverResult-                -> SolverTest-mkTestPCDepends pkgConfigDb = mkTestExtLangPC Nothing Nothing pkgConfigDb--mkTestExtLangPC :: Maybe [Extension]-                -> Maybe [Language]-                -> [(String, String)]-                -> ExampleDb-                -> String-                -> [String]-                -> SolverResult-                -> SolverTest-mkTestExtLangPC exts langs pkgConfigDb db label targets result = SolverTest {-    testLabel                = label-  , testTargets              = targets-  , testResult               = result-  , testMaxBackjumps         = Nothing-  , testIndepGoals           = IndependentGoals False-  , testAllowBootLibInstalls = AllowBootLibInstalls False-  , testEnableBackjumping    = EnableBackjumping True-  , testSolveExecutables     = SolveExecutables True-  , testGoalOrder            = Nothing-  , testConstraints          = []-  , testSoftConstraints      = []-  , testDb                   = db-  , testSupportedExts        = exts-  , testSupportedLangs       = langs-  , testPkgConfigDb          = pkgConfigDbFromList pkgConfigDb-  , testEnableAllTests       = EnableAllTests False-  }--runTest :: SolverTest -> TF.TestTree-runTest SolverTest{..} = askOption $ \(OptionShowSolverLog showSolverLog) ->-    testCase testLabel $ do-      let progress = exResolve testDb testSupportedExts-                     testSupportedLangs testPkgConfigDb testTargets-                     testMaxBackjumps (CountConflicts True) testIndepGoals-                     (ReorderGoals False) testAllowBootLibInstalls-                     testEnableBackjumping testSolveExecutables-                     (sortGoals <$> testGoalOrder) testConstraints-                     testSoftConstraints testEnableAllTests-          printMsg msg = when showSolverLog $ putStrLn msg-          msgs = foldProgress (:) (const []) (const []) progress-      assertBool ("Unexpected solver log:\n" ++ unlines msgs) $-                 resultLogPredicate testResult $ concatMap lines msgs-      result <- foldProgress ((>>) . printMsg) (return . Left) (return . Right) progress-      case result of-        Left  err  -> assertBool ("Unexpected error:\n" ++ err)-                                 (checkErrorMsg testResult err)-        Right plan -> assertEqual "" (toMaybe testResult) (Just (extractInstallPlan plan))-  where-    toMaybe :: SolverResult -> Maybe [(String, Int)]-    toMaybe = either (const Nothing) Just . resultErrorMsgPredicateOrPlan--    checkErrorMsg :: SolverResult -> String -> Bool-    checkErrorMsg result msg =-        case resultErrorMsgPredicateOrPlan result of-          Left f  -> f msg-          Right _ -> False--    sortGoals :: [ExampleVar]-              -> Variable P.QPN -> Variable P.QPN -> Ordering-    sortGoals = orderFromList . map toVariable--    -- Sort elements in the list ahead of elements not in the list. Otherwise,-    -- follow the order in the list.-    orderFromList :: Eq a => [a] -> a -> a -> Ordering-    orderFromList xs =-        comparing $ \x -> let i = elemIndex x xs in (isNothing i, i)--    toVariable :: ExampleVar -> Variable P.QPN-    toVariable (P q pn)        = PackageVar (toQPN q pn)-    toVariable (F q pn fn)     = FlagVar    (toQPN q pn) (C.mkFlagName fn)-    toVariable (S q pn stanza) = StanzaVar  (toQPN q pn) stanza--    toQPN :: ExampleQualifier -> ExamplePkgName -> P.QPN-    toQPN q pn = P.Q pp (C.mkPackageName pn)-      where-        pp = case q of-               QualNone           -> P.PackagePath P.DefaultNamespace P.QualToplevel-               QualIndep p        -> P.PackagePath (P.Independent $ C.mkPackageName p)-                                                   P.QualToplevel-               QualSetup s        -> P.PackagePath P.DefaultNamespace-                                                   (P.QualSetup (C.mkPackageName s))-               QualIndepSetup p s -> P.PackagePath (P.Independent $ C.mkPackageName p)-                                                   (P.QualSetup (C.mkPackageName s))-               QualExe p1 p2      -> P.PackagePath P.DefaultNamespace-                                                   (P.QualExe (C.mkPackageName p1) (C.mkPackageName p2))
− tests/UnitTests/Distribution/Solver/Modular/MemoryUsage.hs
@@ -1,191 +0,0 @@--- | Tests for detecting space leaks in the dependency solver.-module UnitTests.Distribution.Solver.Modular.MemoryUsage (tests) where--import Test.Tasty (TestTree)--import UnitTests.Distribution.Solver.Modular.DSL-import UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils--tests :: [TestTree]-tests = [-      runTest $ basicTest "basic space leak test"-    , runTest $ flagsTest "package with many flags"-    , runTest $ issue2899 "issue #2899"-    , runTest $ duplicateDependencies "duplicate dependencies"-    , runTest $ duplicateFlaggedDependencies "duplicate flagged dependencies"-    ]---- | This test solves for n packages that each have two versions. There is no--- solution, because the nth package depends on another package that doesn't fit--- its version constraint. Backjumping is disabled, so the solver must explore a--- search tree of size 2^n. It should fail if memory usage is proportional to--- the size of the tree.-basicTest :: String -> SolverTest-basicTest name =-    disableBackjumping $ mkTest pkgs name ["target"] anySolverFailure-  where-    n :: Int-    n = 18--    pkgs :: ExampleDb-    pkgs = map Right $-           [ exAv "target" 1 [ExAny $ pkgName 1]]-        ++ [ exAv (pkgName i) v [ExRange (pkgName $ i + 1) 2 4]-           | i <- [1..n], v <- [2, 3]]-        ++ [exAv (pkgName $ n + 1) 1 []]--    pkgName :: Int -> ExamplePkgName-    pkgName x = "pkg-" ++ show x---- | This test is similar to 'basicTest', except that it has one package with n--- flags, flag-1 through flag-n. The solver assigns flags in order, so it--- doesn't discover the unknown dependencies under flag-n until it has assigned--- all of the flags. It has to explore the whole search tree.-flagsTest :: String -> SolverTest-flagsTest name =-    disableBackjumping $-    goalOrder orderedFlags $ mkTest pkgs name ["pkg"] anySolverFailure-  where-    n :: Int-    n = 16--    pkgs :: ExampleDb-    pkgs = [Right $ exAv "pkg" 1 $-                [exFlagged (numberedFlag n) [ExAny "unknown1"] [ExAny "unknown2"]]--                -- The remaining flags have no effect:-             ++ [exFlagged (numberedFlag i) [] [] | i <- [1..n - 1]]-           ]--    orderedFlags :: [ExampleVar]-    orderedFlags = [F QualNone "pkg" (numberedFlag i) | i <- [1..n]]---- | Test for a space leak caused by sharing of search trees under packages with--- link choices (issue #2899).------ The goal order is fixed so that the solver chooses setup-dep and then--- target-setup.setup-dep at the top of the search tree. target-setup.setup-dep--- has two choices: link to setup-dep, and don't link to setup-dep. setup-dep--- has a long chain of dependencies (pkg-1 through pkg-n). However, pkg-n--- depends on pkg-n+1, which doesn't exist, so there is no solution. Since each--- dependency has two versions, the solver must try 2^n combinations when--- backjumping is disabled. These combinations create large search trees under--- each of the two choices for target-setup.setup-dep. Although the choice to--- not link is disallowed by the Single Instance Restriction, the solver doesn't--- know that until it has explored (and evaluated) the whole tree under the--- choice to link. If the two trees are shared, memory usage spikes.-issue2899 :: String -> SolverTest-issue2899 name =-    disableBackjumping $-    goalOrder goals $ mkTest pkgs name ["target"] anySolverFailure-  where-    n :: Int-    n = 16--    pkgs :: ExampleDb-    pkgs = map Right $-           [ exAv "target" 1 [ExAny "setup-dep"] `withSetupDeps` [ExAny "setup-dep"]-           , exAv "setup-dep" 1 [ExAny $ pkgName 1]]-        ++ [ exAv (pkgName i) v [ExAny $ pkgName (i + 1)]-           | i <- [1..n], v <- [1, 2]]--    pkgName :: Int -> ExamplePkgName-    pkgName x = "pkg-" ++ show x--    goals :: [ExampleVar]-    goals = [P QualNone "setup-dep", P (QualSetup "target") "setup-dep"]---- | Test for an issue related to lifting dependencies out of conditionals when--- converting a PackageDescription to the solver's internal representation.------ Issue:--- For each conditional and each package B, the solver combined each dependency--- on B in the true branch with each dependency on B in the false branch. It--- added the combined dependencies to the build-depends outside of the--- conditional. Since dependencies could be lifted out of multiple levels of--- conditionals, the number of new dependencies could grow exponentially in the--- number of levels. For example, the following package generated 4 copies of B--- under flag-2=False, 8 copies under flag-1=False, and 16 copies at the top--- level:------ if flag(flag-1)---   build-depends: B, B--- else---   if flag(flag-2)---     build-depends: B, B---   else---     if flag(flag-3)---       build-depends: B, B---     else---       build-depends: B, B------ This issue caused the quickcheck tests to start frequently running out of--- memory after an optimization that pruned unreachable branches (See PR #4929).--- Each problematic test case contained at least one build-depends field with--- duplicate dependencies, which was then duplicated under multiple levels of--- conditionals by the solver's "buildable: False" transformation, when--- "buildable: False" was under multiple flags. Finally, the branch pruning--- feature put all build-depends fields in consecutive levels of the condition--- tree, causing the solver's representation of the package to follow the--- pattern in the example above.------ Now the solver avoids this issue by combining all dependencies on the same--- package before lifting them out of conditionals.------ This test case is an expanded version of the example above, with library and--- build-tool dependencies.-duplicateDependencies :: String -> SolverTest-duplicateDependencies name =-    mkTest pkgs name ["A"] $ solverSuccess [("A", 1), ("B", 1)]-  where-    copies, depth :: Int-    copies = 50-    depth = 50--    pkgs :: ExampleDb-    pkgs = [-        Right $ exAv "A" 1 (dependencyTree 1)-      , Right $ exAv "B" 1 [] `withExe` ExExe "exe" []-      ]--    dependencyTree :: Int -> [ExampleDependency]-    dependencyTree n-        | n > depth = buildDepends-        | otherwise = [exFlagged (numberedFlag n) buildDepends-                                                  (dependencyTree (n + 1))]-      where-        buildDepends = replicate copies (ExFix "B" 1)-                    ++ replicate copies (ExBuildToolFix "B" "exe" 1)---- | This test is similar to duplicateDependencies, except that every dependency--- on B is replaced by a conditional that contains B in both branches. It tests--- that the solver doesn't just combine dependencies within one build-depends or--- build-tool-depends field; it also needs to combine dependencies after they--- are lifted out of conditionals.-duplicateFlaggedDependencies :: String -> SolverTest-duplicateFlaggedDependencies name =-    mkTest pkgs name ["A"] $ solverSuccess [("A", 1), ("B", 1)]-  where-    copies, depth :: Int-    copies = 15-    depth = 15--    pkgs :: ExampleDb-    pkgs = [-        Right $ exAv "A" 1 (dependencyTree 1)-      , Right $ exAv "B" 1 [] `withExe` ExExe "exe" []-      ]--    dependencyTree :: Int -> [ExampleDependency]-    dependencyTree n-        | n > depth = flaggedDeps-        | otherwise = [exFlagged (numberedFlag n) flaggedDeps-                                                  (dependencyTree (n + 1))]-      where-        flaggedDeps = zipWith ($) (replicate copies flaggedDep) [0 :: Int ..]-        flaggedDep m = exFlagged (numberedFlag n ++ "-" ++ show m) buildDepends-                                                                   buildDepends-        buildDepends = [ExFix "B" 1, ExBuildToolFix "B" "exe" 1]--numberedFlag :: Int -> ExampleFlagName-numberedFlag n = "flag-" ++ show n
− tests/UnitTests/Distribution/Solver/Modular/QuickCheck.hs
@@ -1,492 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module UnitTests.Distribution.Solver.Modular.QuickCheck (tests) where--import Prelude ()-import Distribution.Client.Compat.Prelude--import Control.Arrow ((&&&))-import Control.DeepSeq (force)-import Data.Either (lefts)-import Data.Function (on)-import Data.Hashable (Hashable(..))-import Data.List (groupBy, isInfixOf)-import Data.Ord (comparing)--import Text.Show.Pretty (parseValue, valToStr)--import Test.Tasty (TestTree)-import Test.Tasty.QuickCheck--import Distribution.Types.GenericPackageDescription (FlagName)-import Distribution.Utils.ShortText (ShortText)--import Distribution.Client.Setup (defaultMaxBackjumps)--import           Distribution.Types.PackageName-import           Distribution.Types.UnqualComponentName--import qualified Distribution.Solver.Types.ComponentDeps as CD-import           Distribution.Solver.Types.ComponentDeps-                   ( Component(..), ComponentDep, ComponentDeps )-import           Distribution.Solver.Types.OptionalStanza-import           Distribution.Solver.Types.PackageConstraint-import qualified Distribution.Solver.Types.PackagePath as P-import           Distribution.Solver.Types.PkgConfigDb-                   (pkgConfigDbFromList)-import           Distribution.Solver.Types.Settings-import           Distribution.Solver.Types.Variable-import           Distribution.Version--import UnitTests.Distribution.Solver.Modular.DSL-import UnitTests.Distribution.Solver.Modular.QuickCheck.Utils-    ( testPropertyWithSeed )--tests :: [TestTree]-tests = [-      -- This test checks that certain solver parameters do not affect the-      -- existence of a solution. It runs the solver twice, and only sets those-      -- parameters on the second run. The test also applies parameters that-      -- can affect the existence of a solution to both runs.-      testPropertyWithSeed "target and goal order do not affect solvability" $-          \test targetOrder mGoalOrder1 mGoalOrder2 indepGoals ->-            let r1 = solve' mGoalOrder1 test-                r2 = solve' mGoalOrder2 test { testTargets = targets2 }-                solve' goalOrder =-                    solve (EnableBackjumping True) (ReorderGoals False)-                          (CountConflicts True) indepGoals-                          (getBlind <$> goalOrder)-                targets = testTargets test-                targets2 = case targetOrder of-                             SameOrder -> targets-                             ReverseOrder -> reverse targets-            in counterexample (showResults r1 r2) $-               noneReachedBackjumpLimit [r1, r2] ==>-               isRight (resultPlan r1) === isRight (resultPlan r2)--    , testPropertyWithSeed-          "solvable without --independent-goals => solvable with --independent-goals" $-          \test reorderGoals ->-            let r1 = solve' (IndependentGoals False) test-                r2 = solve' (IndependentGoals True)  test-                solve' indep = solve (EnableBackjumping True) reorderGoals-                                     (CountConflicts True) indep Nothing-             in counterexample (showResults r1 r2) $-                noneReachedBackjumpLimit [r1, r2] ==>-                isRight (resultPlan r1) `implies` isRight (resultPlan r2)--    , testPropertyWithSeed "backjumping does not affect solvability" $-          \test reorderGoals indepGoals ->-            let r1 = solve' (EnableBackjumping True)  test-                r2 = solve' (EnableBackjumping False) test-                solve' enableBj = solve enableBj reorderGoals-                                        (CountConflicts True) indepGoals Nothing-             in counterexample (showResults r1 r2) $-                noneReachedBackjumpLimit [r1, r2] ==>-                isRight (resultPlan r1) === isRight (resultPlan r2)--    -- This test uses --no-count-conflicts, because the goal order used with-    -- --count-conflicts depends on the total set of conflicts seen by the-    -- solver. The solver explores more of the tree and encounters more-    -- conflicts when it doesn't backjump. The different goal orders can lead to-    -- different solutions and cause the test to fail.-    -- TODO: Find a faster way to randomly sort goals, and then use a random-    -- goal order in this test.-    , testPropertyWithSeed-          "backjumping does not affect the result (with static goal order)" $-          \test reorderGoals indepGoals ->-            let r1 = solve' (EnableBackjumping True)  test-                r2 = solve' (EnableBackjumping False) test-                solve' enableBj = solve enableBj reorderGoals-                                  (CountConflicts False) indepGoals Nothing-             in counterexample (showResults r1 r2) $-                noneReachedBackjumpLimit [r1, r2] ==>-                resultPlan r1 === resultPlan r2-    ]-  where-    noneReachedBackjumpLimit :: [Result] -> Bool-    noneReachedBackjumpLimit =-        not . any (\r -> resultPlan r == Left BackjumpLimitReached)--    showResults :: Result -> Result -> String-    showResults r1 r2 = showResult 1 r1 ++ showResult 2 r2--    showResult :: Int -> Result -> String-    showResult n result =-        unlines $ ["", "Run " ++ show n ++ ":"]-               ++ resultLog result-               ++ ["result: " ++ show (resultPlan result)]--    implies :: Bool -> Bool -> Bool-    implies x y = not x || y--    isRight :: Either a b -> Bool-    isRight (Right _) = True-    isRight _         = False--newtype VarOrdering = VarOrdering {-      unVarOrdering :: Variable P.QPN -> Variable P.QPN -> Ordering-    }--solve :: EnableBackjumping -> ReorderGoals -> CountConflicts -> IndependentGoals-      -> Maybe VarOrdering-      -> SolverTest -> Result-solve enableBj reorder countConflicts indep goalOrder test =-  let (lg, result) =-        runProgress $ exResolve (unTestDb (testDb test)) Nothing Nothing-                  (pkgConfigDbFromList [])-                  (map unPN (testTargets test))-                  -- The backjump limit prevents individual tests from using-                  -- too much time and memory.-                  (Just defaultMaxBackjumps)-                  countConflicts indep reorder (AllowBootLibInstalls False)-                  enableBj (SolveExecutables True) (unVarOrdering <$> goalOrder)-                  (testConstraints test) (testPreferences test)-                  (EnableAllTests False)--      failure :: String -> Failure-      failure msg-        | "Backjump limit reached" `isInfixOf` msg = BackjumpLimitReached-        | otherwise                                = OtherFailure-  in Result {-       resultLog = lg-     , resultPlan =-         -- Force the result so that we check for internal errors when we check-         -- for success or failure. See D.C.Dependency.validateSolverResult.-         force $ either (Left . failure) (Right . extractInstallPlan) result-     }---- | How to modify the order of the input targets.-data TargetOrder = SameOrder | ReverseOrder-  deriving Show--instance Arbitrary TargetOrder where-  arbitrary = elements [SameOrder, ReverseOrder]--  shrink SameOrder = []-  shrink ReverseOrder = [SameOrder]--data Result = Result {-    resultLog :: [String]-  , resultPlan :: Either Failure [(ExamplePkgName, ExamplePkgVersion)]-  }--data Failure = BackjumpLimitReached | OtherFailure-  deriving (Eq, Generic, Show)--instance NFData Failure---- | Package name.-newtype PN = PN { unPN :: String }-  deriving (Eq, Ord, Show)--instance Arbitrary PN where-  arbitrary = PN <$> elements ("base" : [[pn] | pn <- ['A'..'G']])---- | Package version.-newtype PV = PV { unPV :: Int }-  deriving (Eq, Ord, Show)--instance Arbitrary PV where-  arbitrary = PV <$> elements [1..10]--type TestPackage = Either ExampleInstalled ExampleAvailable--getName :: TestPackage -> PN-getName = PN . either exInstName exAvName--getVersion :: TestPackage -> PV-getVersion = PV . either exInstVersion exAvVersion--data SolverTest = SolverTest {-    testDb :: TestDb-  , testTargets :: [PN]-  , testConstraints :: [ExConstraint]-  , testPreferences :: [ExPreference]-  }---- | Pretty-print the test when quickcheck calls 'show'.-instance Show SolverTest where-  show test =-    let str = "SolverTest {testDb = " ++ show (testDb test)-                     ++ ", testTargets = " ++ show (testTargets test)-                     ++ ", testConstraints = " ++ show (testConstraints test)-                     ++ ", testPreferences = " ++ show (testPreferences test)-                     ++ "}"-    in maybe str valToStr $ parseValue str--instance Arbitrary SolverTest where-  arbitrary = do-    db <- arbitrary-    let pkgVersions = nub $ map (getName &&& getVersion) (unTestDb db)-        pkgs = nub $ map fst pkgVersions-    Positive n <- arbitrary-    targets <- randomSubset n pkgs-    constraints <- case pkgVersions of-                     [] -> return []-                     _  -> boundedListOf 1 $ arbitraryConstraint pkgVersions-    prefs <- case pkgVersions of-               [] -> return []-               _  -> boundedListOf 3 $ arbitraryPreference pkgVersions-    return (SolverTest db targets constraints prefs)--  shrink test =-         [test { testDb = db } | db <- shrink (testDb test)]-      ++ [test { testTargets = targets } | targets <- shrink (testTargets test)]-      ++ [test { testConstraints = cs } | cs <- shrink (testConstraints test)]-      ++ [test { testPreferences = prefs } | prefs <- shrink (testPreferences test)]---- | Collection of source and installed packages.-newtype TestDb = TestDb { unTestDb :: ExampleDb }-  deriving Show--instance Arbitrary TestDb where-  arbitrary = do-      -- Avoid cyclic dependencies by grouping packages by name and only-      -- allowing each package to depend on packages in the groups before it.-      groupedPkgs <- shuffle . groupBy ((==) `on` fst) . nub . sort =<<-                     boundedListOf 10 arbitrary-      db <- foldM nextPkgs (TestDb []) groupedPkgs-      TestDb <$> shuffle (unTestDb db)-    where-      nextPkgs :: TestDb -> [(PN, PV)] -> Gen TestDb-      nextPkgs db pkgs = TestDb . (++ unTestDb db) <$> traverse (nextPkg db) pkgs--      nextPkg :: TestDb -> (PN, PV) -> Gen TestPackage-      nextPkg db (pn, v) = do-        installed <- arbitrary-        if installed-        then Left <$> arbitraryExInst pn v (lefts $ unTestDb db)-        else Right <$> arbitraryExAv pn v db--  shrink (TestDb pkgs) = map TestDb $ shrink pkgs--arbitraryExAv :: PN -> PV -> TestDb -> Gen ExampleAvailable-arbitraryExAv pn v db =-    (\cds -> ExAv (unPN pn) (unPV v) cds []) <$> arbitraryComponentDeps db--arbitraryExInst :: PN -> PV -> [ExampleInstalled] -> Gen ExampleInstalled-arbitraryExInst pn v pkgs = do-  pkgHash <- vectorOf 10 $ elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']-  numDeps <- min 3 <$> arbitrary-  deps <- randomSubset numDeps pkgs-  return $ ExInst (unPN pn) (unPV v) pkgHash (map exInstHash deps)--arbitraryComponentDeps :: TestDb -> Gen (ComponentDeps [ExampleDependency])-arbitraryComponentDeps (TestDb []) = return $ CD.fromList []-arbitraryComponentDeps db =-    -- dedupComponentNames removes components with duplicate names, for example,-    -- 'ComponentExe x' and 'ComponentTest x', and then CD.fromList combines-    -- duplicate unnamed components.-    CD.fromList . dedupComponentNames <$>-    boundedListOf 5 (arbitraryComponentDep db)-  where-    dedupComponentNames =-        nubBy ((\x y -> isJust x && isJust y && x == y) `on` componentName . fst)--    componentName :: Component -> Maybe UnqualComponentName-    componentName ComponentLib        = Nothing-    componentName ComponentSetup      = Nothing-    componentName (ComponentSubLib n) = Just n-    componentName (ComponentFLib   n) = Just n-    componentName (ComponentExe    n) = Just n-    componentName (ComponentTest   n) = Just n-    componentName (ComponentBench  n) = Just n--arbitraryComponentDep :: TestDb -> Gen (ComponentDep [ExampleDependency])-arbitraryComponentDep db = do-  comp <- arbitrary-  deps <- case comp of-            ComponentSetup -> smallListOf (arbitraryExDep db SetupDep)-            _              -> boundedListOf 5 (arbitraryExDep db NonSetupDep)-  return (comp, deps)---- | Location of an 'ExampleDependency'. It determines which values are valid.-data ExDepLocation = SetupDep | NonSetupDep--arbitraryExDep :: TestDb -> ExDepLocation -> Gen ExampleDependency-arbitraryExDep db@(TestDb pkgs) level =-  let flag = ExFlagged <$> arbitraryFlagName-                       <*> arbitraryDeps db-                       <*> arbitraryDeps db-      other =-          -- Package checks require dependencies on "base" to have bounds.-        let notBase = filter ((/= PN "base") . getName) pkgs-        in  [ExAny . unPN <$> elements (map getName notBase) | not (null notBase)]-         ++ [-              -- existing version-              let fixed pkg = ExFix (unPN $ getName pkg) (unPV $ getVersion pkg)-              in fixed <$> elements pkgs--              -- random version of an existing package-            , ExFix . unPN . getName <$> elements pkgs <*> (unPV <$> arbitrary)-            ]-  in oneof $-      case level of-        NonSetupDep -> flag : other-        SetupDep -> other--arbitraryDeps :: TestDb -> Gen Dependencies-arbitraryDeps db = frequency-    [ (1, return NotBuildable)-    , (20, Buildable <$> smallListOf (arbitraryExDep db NonSetupDep))-    ]--arbitraryFlagName :: Gen String-arbitraryFlagName = (:[]) <$> elements ['A'..'E']--arbitraryConstraint :: [(PN, PV)] -> Gen ExConstraint-arbitraryConstraint pkgs = do-  (PN pn, v) <- elements pkgs-  let anyQualifier = ScopeAnyQualifier (mkPackageName pn)-  oneof [-      ExVersionConstraint anyQualifier <$> arbitraryVersionRange v-    , ExStanzaConstraint anyQualifier <$> sublistOf [TestStanzas, BenchStanzas]-    ]--arbitraryPreference :: [(PN, PV)] -> Gen ExPreference-arbitraryPreference pkgs = do-  (PN pn, v) <- elements pkgs-  oneof [-      ExStanzaPref pn <$> sublistOf [TestStanzas, BenchStanzas]-    , ExPkgPref pn <$> arbitraryVersionRange v-    ]--arbitraryVersionRange :: PV -> Gen VersionRange-arbitraryVersionRange (PV v) =-  let version = mkSimpleVersion v-  in elements [-         thisVersion version-       , notThisVersion version-       , earlierVersion version-       , orLaterVersion version-       , noVersion-       ]--instance Arbitrary ReorderGoals where-  arbitrary = ReorderGoals <$> arbitrary--  shrink (ReorderGoals reorder) = [ReorderGoals False | reorder]--instance Arbitrary IndependentGoals where-  arbitrary = IndependentGoals <$> arbitrary--  shrink (IndependentGoals indep) = [IndependentGoals False | indep]--instance Arbitrary UnqualComponentName where-  arbitrary = mkUnqualComponentName <$> (:[]) <$> elements "ABC"--instance Arbitrary Component where-  arbitrary = oneof [ return ComponentLib-                    , ComponentSubLib <$> arbitrary-                    , ComponentExe <$> arbitrary-                    , ComponentFLib <$> arbitrary-                    , ComponentTest <$> arbitrary-                    , ComponentBench <$> arbitrary-                    , return ComponentSetup-                    ]--  shrink ComponentLib = []-  shrink _ = [ComponentLib]--instance Arbitrary ExampleInstalled where-  arbitrary = error "arbitrary not implemented: ExampleInstalled"--  shrink ei = [ ei { exInstBuildAgainst = deps }-              | deps <- shrinkList shrinkNothing (exInstBuildAgainst ei)]--instance Arbitrary ExampleAvailable where-  arbitrary = error "arbitrary not implemented: ExampleAvailable"--  shrink ea = [ea { exAvDeps = deps } | deps <- shrink (exAvDeps ea)]--instance (Arbitrary a, Monoid a) => Arbitrary (ComponentDeps a) where-  arbitrary = error "arbitrary not implemented: ComponentDeps"--  shrink = map CD.fromList . shrink . CD.toList--instance Arbitrary ExampleDependency where-  arbitrary = error "arbitrary not implemented: ExampleDependency"--  shrink (ExAny _) = []-  shrink (ExFix "base" _) = [] -- preserve bounds on base-  shrink (ExFix pn _) = [ExAny pn]-  shrink (ExFlagged flag th el) =-         deps th ++ deps el-      ++ [ExFlagged flag th' el | th' <- shrink th]-      ++ [ExFlagged flag th el' | el' <- shrink el]-    where-      deps NotBuildable = []-      deps (Buildable ds) = ds-  shrink dep = error $ "Dependency not handled: " ++ show dep--instance Arbitrary Dependencies where-  arbitrary = error "arbitrary not implemented: Dependencies"--  shrink NotBuildable = [Buildable []]-  shrink (Buildable deps) = map Buildable (shrink deps)--instance Arbitrary ExConstraint where-  arbitrary = error "arbitrary not implemented: ExConstraint"--  shrink (ExStanzaConstraint scope stanzas) =-      [ExStanzaConstraint scope stanzas' | stanzas' <- shrink stanzas]-  shrink (ExVersionConstraint scope vr) =-      [ExVersionConstraint scope vr' | vr' <- shrink vr]-  shrink _ = []--instance Arbitrary ExPreference where-  arbitrary = error "arbitrary not implemented: ExPreference"--  shrink (ExStanzaPref pn stanzas) =-      [ExStanzaPref pn stanzas' | stanzas' <- shrink stanzas]-  shrink (ExPkgPref pn vr) = [ExPkgPref pn vr' | vr' <- shrink vr]--instance Arbitrary OptionalStanza where-  arbitrary = error "arbitrary not implemented: OptionalStanza"--  shrink BenchStanzas = [TestStanzas]-  shrink TestStanzas  = []--instance Arbitrary VersionRange where-  arbitrary = error "arbitrary not implemented: VersionRange"--  shrink vr = [noVersion | vr /= noVersion]---- Randomly sorts solver variables using 'hash'.--- TODO: Sorting goals with this function is very slow.-instance Arbitrary VarOrdering where-  arbitrary = do-      f <- arbitrary :: Gen (Int -> Int)-      return $ VarOrdering (comparing (f . hash))--instance Hashable pn => Hashable (Variable pn)-instance Hashable a => Hashable (P.Qualified a)-instance Hashable P.PackagePath-instance Hashable P.Qualifier-instance Hashable P.Namespace-instance Hashable OptionalStanza-instance Hashable FlagName-instance Hashable PackageName-instance Hashable ShortText--deriving instance Generic (Variable pn)-deriving instance Generic (P.Qualified a)-deriving instance Generic P.PackagePath-deriving instance Generic P.Namespace-deriving instance Generic P.Qualifier--randomSubset :: Int -> [a] -> Gen [a]-randomSubset n xs = take n <$> shuffle xs--boundedListOf :: Int -> Gen a -> Gen [a]-boundedListOf n gen = take n <$> listOf gen---- | Generates lists with average length less than 1.-smallListOf :: Gen a -> Gen [a]-smallListOf gen =-    frequency [ (fr, vectorOf n gen)-              | (fr, n) <- [(3, 0), (5, 1), (2, 2)]]
− tests/UnitTests/Distribution/Solver/Modular/QuickCheck/Utils.hs
@@ -1,33 +0,0 @@-module UnitTests.Distribution.Solver.Modular.QuickCheck.Utils (-    testPropertyWithSeed-  ) where--import Data.Tagged (Tagged, retag)-import System.Random (getStdRandom, random)--import Test.Tasty (TestTree)-import Test.Tasty.Options (OptionDescription, lookupOption, setOption)-import Test.Tasty.Providers (IsTest (..), singleTest)-import Test.Tasty.QuickCheck-    ( QC (..), QuickCheckReplay (..), Testable, property )--import Distribution.Simple.Utils-import Distribution.Verbosity---- | Create a QuickCheck test that prints the seed before testing the property.--- The seed can be useful for debugging non-terminating test cases. This is--- related to https://github.com/feuerbach/tasty/issues/86.-testPropertyWithSeed :: Testable a => String -> a -> TestTree-testPropertyWithSeed name = singleTest name . QCWithSeed . QC . property--newtype QCWithSeed = QCWithSeed QC--instance IsTest QCWithSeed where-  testOptions = retag (testOptions :: Tagged QC [OptionDescription])--  run options (QCWithSeed test) progress = do-    replay <- case lookupOption options of-                 QuickCheckReplay (Just override) -> return override-                 QuickCheckReplay Nothing         -> getStdRandom random-    notice normal $ "Using --quickcheck-replay=" ++ show replay-    run (setOption (QuickCheckReplay (Just replay)) options) test progress
− tests/UnitTests/Distribution/Solver/Modular/RetryLog.hs
@@ -1,72 +0,0 @@-{-# LANGUAGE StandaloneDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module UnitTests.Distribution.Solver.Modular.RetryLog (-  tests-  ) where--import Distribution.Solver.Modular.Message-import Distribution.Solver.Modular.RetryLog-import Distribution.Solver.Types.Progress--import Test.Tasty (TestTree)-import Test.Tasty.HUnit (testCase, (@?=))-import Test.Tasty.QuickCheck-         ( Arbitrary(..), Blind(..), listOf, oneof, testProperty, (===))--type Log a = Progress a String String--tests :: [TestTree]-tests = [-    testProperty "'toProgress . fromProgress' is identity" $ \p ->-        toProgress (fromProgress p) === (p :: Log Int)--  , testProperty "'mapFailure f' is like 'foldProgress Step (Fail . f) Done'" $-        let mapFailureProgress f = foldProgress Step (Fail . f) Done-        in \(Blind f) p ->-               toProgress (mapFailure f (fromProgress p))-               === mapFailureProgress (f :: String -> Int) (p :: Log Int)--  , testProperty "'retry p f' is like 'foldProgress Step f Done p'" $-      \p (Blind f) ->-        toProgress (retry (fromProgress p) (fromProgress . f))-        === (foldProgress Step f Done (p :: Log Int) :: Log Int)--  , testProperty "failWith" $ \step failure ->-        toProgress (failWith step failure)-        === (Step step (Fail failure) :: Log Int)--  , testProperty "succeedWith" $ \step success ->-        toProgress (succeedWith step success)-        === (Step step (Done success) :: Log Int)--  , testProperty "continueWith" $ \step p ->-        toProgress (continueWith step (fromProgress p))-        === (Step step p :: Log Int)--  , testCase "tryWith with failure" $-        let failure = Fail "Error"-            s = Step Success-        in toProgress (tryWith Success $ fromProgress (s (s failure)))-           @?= (s (Step Enter (s (s (Step Leave failure)))) :: Log Message)--  , testCase "tryWith with success" $-        let done = Done "Done"-            s = Step Success-        in toProgress (tryWith Success $ fromProgress (s (s done)))-           @?= (s (Step Enter (s (s done))) :: Log Message)-  ]--instance (Arbitrary step, Arbitrary fail, Arbitrary done)-    => Arbitrary (Progress step fail done) where-  arbitrary = do-    steps <- listOf arbitrary-    end <- oneof [Fail `fmap` arbitrary, Done `fmap` arbitrary]-    return $ foldr Step end steps--deriving instance (Eq step, Eq fail, Eq done) => Eq (Progress step fail done)--deriving instance (Show step, Show fail, Show done)-    => Show (Progress step fail done)--deriving instance Eq Message-deriving instance Show Message
− tests/UnitTests/Distribution/Solver/Modular/Solver.hs
@@ -1,1578 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--- | This is a set of unit tests for the dependency solver,--- which uses the solver DSL ("UnitTests.Distribution.Solver.Modular.DSL")--- to more conveniently create package databases to run the solver tests on.-module UnitTests.Distribution.Solver.Modular.Solver (tests)-       where---- base-import Data.List (isInfixOf)--import qualified Distribution.Version as V---- test-framework-import Test.Tasty as TF---- Cabal-import Language.Haskell.Extension ( Extension(..)-                                  , KnownExtension(..), Language(..))---- cabal-install-import Distribution.Solver.Types.Flag-import Distribution.Solver.Types.OptionalStanza-import Distribution.Solver.Types.PackageConstraint-import qualified Distribution.Solver.Types.PackagePath as P-import UnitTests.Distribution.Solver.Modular.DSL-import UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils--tests :: [TF.TestTree]-tests = [-      testGroup "Simple dependencies" [-          runTest $         mkTest db1 "alreadyInstalled"   ["A"]      (solverSuccess [])-        , runTest $         mkTest db1 "installLatest"      ["B"]      (solverSuccess [("B", 2)])-        , runTest $         mkTest db1 "simpleDep1"         ["C"]      (solverSuccess [("B", 1), ("C", 1)])-        , runTest $         mkTest db1 "simpleDep2"         ["D"]      (solverSuccess [("B", 2), ("D", 1)])-        , runTest $         mkTest db1 "failTwoVersions"    ["C", "D"] anySolverFailure-        , runTest $ indep $ mkTest db1 "indepTwoVersions"   ["C", "D"] (solverSuccess [("B", 1), ("B", 2), ("C", 1), ("D", 1)])-        , runTest $ indep $ mkTest db1 "aliasWhenPossible1" ["C", "E"] (solverSuccess [("B", 1), ("C", 1), ("E", 1)])-        , runTest $ indep $ mkTest db1 "aliasWhenPossible2" ["D", "E"] (solverSuccess [("B", 2), ("D", 1), ("E", 1)])-        , runTest $ indep $ mkTest db2 "aliasWhenPossible3" ["C", "D"] (solverSuccess [("A", 1), ("A", 2), ("B", 1), ("B", 2), ("C", 1), ("D", 1)])-        , runTest $         mkTest db1 "buildDepAgainstOld" ["F"]      (solverSuccess [("B", 1), ("E", 1), ("F", 1)])-        , runTest $         mkTest db1 "buildDepAgainstNew" ["G"]      (solverSuccess [("B", 2), ("E", 1), ("G", 1)])-        , runTest $ indep $ mkTest db1 "multipleInstances"  ["F", "G"] anySolverFailure-        , runTest $         mkTest db21 "unknownPackage1"   ["A"]      (solverSuccess [("A", 1), ("B", 1)])-        , runTest $         mkTest db22 "unknownPackage2"   ["A"]      (solverFailure (isInfixOf "unknown package: C"))-        , runTest $         mkTest db23 "unknownPackage3"   ["A"]      (solverFailure (isInfixOf "unknown package: B"))-        ]-    , testGroup "Flagged dependencies" [-          runTest $         mkTest db3 "forceFlagOn"  ["C"]      (solverSuccess [("A", 1), ("B", 1), ("C", 1)])-        , runTest $         mkTest db3 "forceFlagOff" ["D"]      (solverSuccess [("A", 2), ("B", 1), ("D", 1)])-        , runTest $ indep $ mkTest db3 "linkFlags1"   ["C", "D"] anySolverFailure-        , runTest $ indep $ mkTest db4 "linkFlags2"   ["C", "D"] anySolverFailure-        , runTest $ indep $ mkTest db18 "linkFlags3"  ["A", "B"] (solverSuccess [("A", 1), ("B", 1), ("C", 1), ("D", 1), ("D", 2), ("F", 1)])-        ]-    , testGroup "Lifting dependencies out of conditionals" [-          runTest $ commonDependencyLogMessage "common dependency log message"-        , runTest $ twoLevelDeepCommonDependencyLogMessage "two level deep common dependency log message"-        , runTest $ testBackjumpingWithCommonDependency "backjumping with common dependency"-        ]-    , testGroup "Manual flags" [-          runTest $ mkTest dbManualFlags "Use default value for manual flag" ["pkg"] $-          solverSuccess [("pkg", 1), ("true-dep", 1)]--        , let checkFullLog =-                  any $ isInfixOf "rejecting: pkg:-flag (manual flag can only be changed explicitly)"-          in runTest $ constraints [ExVersionConstraint (ScopeAnyQualifier "true-dep") V.noVersion] $-             mkTest dbManualFlags "Don't toggle manual flag to avoid conflict" ["pkg"] $-             -- TODO: We should check the summarized log instead of the full log-             -- for the manual flags error message, but it currently only-             -- appears in the full log.-             SolverResult checkFullLog (Left $ const True)--        , let cs = [ExFlagConstraint (ScopeAnyQualifier "pkg") "flag" False]-          in runTest $ constraints cs $-             mkTest dbManualFlags "Toggle manual flag with flag constraint" ["pkg"] $-             solverSuccess [("false-dep", 1), ("pkg", 1)]-        ]-    , testGroup "Qualified manual flag constraints" [-          let name = "Top-level flag constraint does not constrain setup dep's flag"-              cs = [ExFlagConstraint (ScopeQualified P.QualToplevel "B") "flag" False]-          in runTest $ constraints cs $ mkTest dbSetupDepWithManualFlag name ["A"] $-             solverSuccess [ ("A", 1), ("B", 1), ("B", 2)-                           , ("b-1-false-dep", 1), ("b-2-true-dep", 1) ]--        , let name = "Solver can toggle setup dep's flag to match top-level constraint"-              cs = [ ExFlagConstraint (ScopeQualified P.QualToplevel "B") "flag" False-                   , ExVersionConstraint (ScopeAnyQualifier "b-2-true-dep") V.noVersion ]-          in runTest $ constraints cs $ mkTest dbSetupDepWithManualFlag name ["A"] $-             solverSuccess [ ("A", 1), ("B", 1), ("B", 2)-                           , ("b-1-false-dep", 1), ("b-2-false-dep", 1) ]--        , let name = "User can constrain flags separately with qualified constraints"-              cs = [ ExFlagConstraint (ScopeQualified P.QualToplevel    "B") "flag" True-                   , ExFlagConstraint (ScopeQualified (P.QualSetup "A") "B") "flag" False ]-          in runTest $ constraints cs $ mkTest dbSetupDepWithManualFlag name ["A"] $-             solverSuccess [ ("A", 1), ("B", 1), ("B", 2)-                           , ("b-1-true-dep", 1), ("b-2-false-dep", 1) ]--          -- Regression test for #4299-        , let name = "Solver can link deps when only one has constrained manual flag"-              cs = [ExFlagConstraint (ScopeQualified P.QualToplevel "B") "flag" False]-          in runTest $ constraints cs $ mkTest dbLinkedSetupDepWithManualFlag name ["A"] $-             solverSuccess [ ("A", 1), ("B", 1), ("b-1-false-dep", 1) ]--        , let name = "Solver cannot link deps that have conflicting manual flag constraints"-              cs = [ ExFlagConstraint (ScopeQualified P.QualToplevel    "B") "flag" True-                   , ExFlagConstraint (ScopeQualified (P.QualSetup "A") "B") "flag" False ]-              failureReason = "(constraint from unknown source requires opposite flag selection)"-              checkFullLog lns =-                  all (\msg -> any (msg `isInfixOf`) lns)-                  [ "rejecting: B:-flag "         ++ failureReason-                  , "rejecting: A:setup.B:+flag " ++ failureReason ]-          in runTest $ constraints cs $-             mkTest dbLinkedSetupDepWithManualFlag name ["A"] $-             SolverResult checkFullLog (Left $ const True)-        ]-    , testGroup "Stanzas" [-          runTest $         enableAllTests $ mkTest db5 "simpleTest1" ["C"]      (solverSuccess [("A", 2), ("C", 1)])-        , runTest $         enableAllTests $ mkTest db5 "simpleTest2" ["D"]      anySolverFailure-        , runTest $         enableAllTests $ mkTest db5 "simpleTest3" ["E"]      (solverSuccess [("A", 1), ("E", 1)])-        , runTest $         enableAllTests $ mkTest db5 "simpleTest4" ["F"]      anySolverFailure -- TODO-        , runTest $         enableAllTests $ mkTest db5 "simpleTest5" ["G"]      (solverSuccess [("A", 2), ("G", 1)])-        , runTest $         enableAllTests $ mkTest db5 "simpleTest6" ["E", "G"] anySolverFailure-        , runTest $ indep $ enableAllTests $ mkTest db5 "simpleTest7" ["E", "G"] (solverSuccess [("A", 1), ("A", 2), ("E", 1), ("G", 1)])-        , runTest $         enableAllTests $ mkTest db6 "depsWithTests1" ["C"]      (solverSuccess [("A", 1), ("B", 1), ("C", 1)])-        , runTest $ indep $ enableAllTests $ mkTest db6 "depsWithTests2" ["C", "D"] (solverSuccess [("A", 1), ("B", 1), ("C", 1), ("D", 1)])-        , runTest $ testTestSuiteWithFlag "test suite with flag"-        ]-    , testGroup "Setup dependencies" [-          runTest $         mkTest db7  "setupDeps1" ["B"] (solverSuccess [("A", 2), ("B", 1)])-        , runTest $         mkTest db7  "setupDeps2" ["C"] (solverSuccess [("A", 2), ("C", 1)])-        , runTest $         mkTest db7  "setupDeps3" ["D"] (solverSuccess [("A", 1), ("D", 1)])-        , runTest $         mkTest db7  "setupDeps4" ["E"] (solverSuccess [("A", 1), ("A", 2), ("E", 1)])-        , runTest $         mkTest db7  "setupDeps5" ["F"] (solverSuccess [("A", 1), ("A", 2), ("F", 1)])-        , runTest $         mkTest db8  "setupDeps6" ["C", "D"] (solverSuccess [("A", 1), ("B", 1), ("B", 2), ("C", 1), ("D", 1)])-        , runTest $         mkTest db9  "setupDeps7" ["F", "G"] (solverSuccess [("A", 1), ("B", 1), ("B",2 ), ("C", 1), ("D", 1), ("E", 1), ("E", 2), ("F", 1), ("G", 1)])-        , runTest $         mkTest db10 "setupDeps8" ["C"] (solverSuccess [("C", 1)])-        , runTest $ indep $ mkTest dbSetupDeps "setupDeps9" ["A", "B"] (solverSuccess [("A", 1), ("B", 1), ("C", 1), ("D", 1), ("D", 2)])-        ]-    , testGroup "Base shim" [-          runTest $ mkTest db11 "baseShim1" ["A"] (solverSuccess [("A", 1)])-        , runTest $ mkTest db12 "baseShim2" ["A"] (solverSuccess [("A", 1)])-        , runTest $ mkTest db12 "baseShim3" ["B"] (solverSuccess [("B", 1)])-        , runTest $ mkTest db12 "baseShim4" ["C"] (solverSuccess [("A", 1), ("B", 1), ("C", 1)])-        , runTest $ mkTest db12 "baseShim5" ["D"] anySolverFailure-        , runTest $ mkTest db12 "baseShim6" ["E"] (solverSuccess [("E", 1), ("syb", 2)])-        ]-    , testGroup "Base" [-          runTest $ mkTest dbBase "Refuse to install base without --allow-boot-library-installs" ["base"] $-                      solverFailure (isInfixOf "only already installed instances can be used")-        , runTest $ allowBootLibInstalls $ mkTest dbBase "Install base with --allow-boot-library-installs" ["base"] $-                      solverSuccess [("base", 1), ("ghc-prim", 1), ("integer-gmp", 1), ("integer-simple", 1)]-        ]-    , testGroup "Cycles" [-          runTest $ mkTest db14 "simpleCycle1"          ["A"]      anySolverFailure-        , runTest $ mkTest db14 "simpleCycle2"          ["A", "B"] anySolverFailure-        , runTest $ mkTest db14 "cycleWithFlagChoice1"  ["C"]      (solverSuccess [("C", 1), ("E", 1)])-        , runTest $ mkTest db15 "cycleThroughSetupDep1" ["A"]      anySolverFailure-        , runTest $ mkTest db15 "cycleThroughSetupDep2" ["B"]      anySolverFailure-        , runTest $ mkTest db15 "cycleThroughSetupDep3" ["C"]      (solverSuccess [("C", 2), ("D", 1)])-        , runTest $ mkTest db15 "cycleThroughSetupDep4" ["D"]      (solverSuccess [("D", 1)])-        , runTest $ mkTest db15 "cycleThroughSetupDep5" ["E"]      (solverSuccess [("C", 2), ("D", 1), ("E", 1)])-        , runTest $ issue4161 "detect cycle between package and its setup script"-        , runTest $ testCyclicDependencyErrorMessages "cyclic dependency error messages"-        ]-    , testGroup "Extensions" [-          runTest $ mkTestExts [EnableExtension CPP] dbExts1 "unsupported" ["A"] anySolverFailure-        , runTest $ mkTestExts [EnableExtension CPP] dbExts1 "unsupportedIndirect" ["B"] anySolverFailure-        , runTest $ mkTestExts [EnableExtension RankNTypes] dbExts1 "supported" ["A"] (solverSuccess [("A",1)])-        , runTest $ mkTestExts (map EnableExtension [CPP,RankNTypes]) dbExts1 "supportedIndirect" ["C"] (solverSuccess [("A",1),("B",1), ("C",1)])-        , runTest $ mkTestExts [EnableExtension CPP] dbExts1 "disabledExtension" ["D"] anySolverFailure-        , runTest $ mkTestExts (map EnableExtension [CPP,RankNTypes]) dbExts1 "disabledExtension" ["D"] anySolverFailure-        , runTest $ mkTestExts (UnknownExtension "custom" : map EnableExtension [CPP,RankNTypes]) dbExts1 "supportedUnknown" ["E"] (solverSuccess [("A",1),("B",1),("C",1),("E",1)])-        ]-    , testGroup "Languages" [-          runTest $ mkTestLangs [Haskell98] dbLangs1 "unsupported" ["A"] anySolverFailure-        , runTest $ mkTestLangs [Haskell98,Haskell2010] dbLangs1 "supported" ["A"] (solverSuccess [("A",1)])-        , runTest $ mkTestLangs [Haskell98] dbLangs1 "unsupportedIndirect" ["B"] anySolverFailure-        , runTest $ mkTestLangs [Haskell98, Haskell2010, UnknownLanguage "Haskell3000"] dbLangs1 "supportedUnknown" ["C"] (solverSuccess [("A",1),("B",1),("C",1)])-        ]-     , testGroup "Qualified Package Constraints" [-          runTest $ mkTest dbConstraints "install latest versions without constraints" ["A", "B", "C"] $-          solverSuccess [("A", 7), ("B", 8), ("C", 9), ("D", 7), ("D", 8), ("D", 9)]--        , let cs = [ ExVersionConstraint (ScopeAnyQualifier "D") $ mkVersionRange 1 4 ]-          in runTest $ constraints cs $-             mkTest dbConstraints "force older versions with unqualified constraint" ["A", "B", "C"] $-             solverSuccess [("A", 1), ("B", 2), ("C", 3), ("D", 1), ("D", 2), ("D", 3)]--        , let cs = [ ExVersionConstraint (ScopeQualified P.QualToplevel    "D") $ mkVersionRange 1 4-                   , ExVersionConstraint (ScopeQualified (P.QualSetup "B") "D") $ mkVersionRange 4 7-                   ]-          in runTest $ constraints cs $-             mkTest dbConstraints "force multiple versions with qualified constraints" ["A", "B", "C"] $-             solverSuccess [("A", 1), ("B", 5), ("C", 9), ("D", 1), ("D", 5), ("D", 9)]--        , let cs = [ ExVersionConstraint (ScopeAnySetupQualifier "D") $ mkVersionRange 1 4 ]-          in runTest $ constraints cs $-             mkTest dbConstraints "constrain package across setup scripts" ["A", "B", "C"] $-             solverSuccess [("A", 7), ("B", 2), ("C", 3), ("D", 2), ("D", 3), ("D", 7)]-        ]-     , testGroup "Package Preferences" [-          runTest $ preferences [ ExPkgPref "A" $ mkvrThis 1]      $ mkTest db13 "selectPreferredVersionSimple" ["A"] (solverSuccess [("A", 1)])-        , runTest $ preferences [ ExPkgPref "A" $ mkvrOrEarlier 2] $ mkTest db13 "selectPreferredVersionSimple2" ["A"] (solverSuccess [("A", 2)])-        , runTest $ preferences [ ExPkgPref "A" $ mkvrOrEarlier 2-                                , ExPkgPref "A" $ mkvrOrEarlier 1] $ mkTest db13 "selectPreferredVersionMultiple" ["A"] (solverSuccess [("A", 1)])-        , runTest $ preferences [ ExPkgPref "A" $ mkvrOrEarlier 1-                                , ExPkgPref "A" $ mkvrOrEarlier 2] $ mkTest db13 "selectPreferredVersionMultiple2" ["A"] (solverSuccess [("A", 1)])-        , runTest $ preferences [ ExPkgPref "A" $ mkvrThis 1-                                , ExPkgPref "A" $ mkvrThis 2] $ mkTest db13 "selectPreferredVersionMultiple3" ["A"] (solverSuccess [("A", 2)])-        , runTest $ preferences [ ExPkgPref "A" $ mkvrThis 1-                                , ExPkgPref "A" $ mkvrOrEarlier 2] $ mkTest db13 "selectPreferredVersionMultiple4" ["A"] (solverSuccess [("A", 1)])-        ]-     , testGroup "Stanza Preferences" [-          runTest $-          mkTest dbStanzaPreferences1 "disable tests by default" ["pkg"] $-          solverSuccess [("pkg", 1)]--        , runTest $ preferences [ExStanzaPref "pkg" [TestStanzas]] $-          mkTest dbStanzaPreferences1 "enable tests with testing preference" ["pkg"] $-          solverSuccess [("pkg", 1), ("test-dep", 1)]--        , runTest $ preferences [ExStanzaPref "pkg" [TestStanzas]] $-          mkTest dbStanzaPreferences2 "disable testing when it's not possible" ["pkg"] $-          solverSuccess [("pkg", 1)]--        , testStanzaPreference "test stanza preference"-        ]-     , testGroup "Buildable Field" [-          testBuildable "avoid building component with unknown dependency" (ExAny "unknown")-        , testBuildable "avoid building component with unknown extension" (ExExt (UnknownExtension "unknown"))-        , testBuildable "avoid building component with unknown language" (ExLang (UnknownLanguage "unknown"))-        , runTest $ mkTest dbBuildable1 "choose flags that set buildable to false" ["pkg"] (solverSuccess [("flag1-false", 1), ("flag2-true", 1), ("pkg", 1)])-        , runTest $ mkTest dbBuildable2 "choose version that sets buildable to false" ["A"] (solverSuccess [("A", 1), ("B", 2)])-         ]-    , testGroup "Pkg-config dependencies" [-          runTest $ mkTestPCDepends [] dbPC1 "noPkgs" ["A"] anySolverFailure-        , runTest $ mkTestPCDepends [("pkgA", "0")] dbPC1 "tooOld" ["A"] anySolverFailure-        , runTest $ mkTestPCDepends [("pkgA", "1.0.0"), ("pkgB", "1.0.0")] dbPC1 "pruneNotFound" ["C"] (solverSuccess [("A", 1), ("B", 1), ("C", 1)])-        , runTest $ mkTestPCDepends [("pkgA", "1.0.0"), ("pkgB", "2.0.0")] dbPC1 "chooseNewest" ["C"] (solverSuccess [("A", 1), ("B", 2), ("C", 1)])-        ]-    , testGroup "Independent goals" [-          runTest $ indep $ mkTest db16 "indepGoals1" ["A", "B"] (solverSuccess [("A", 1), ("B", 1), ("C", 1), ("D", 1), ("D", 2), ("E", 1)])-        , runTest $ testIndepGoals2 "indepGoals2"-        , runTest $ testIndepGoals3 "indepGoals3"-        , runTest $ testIndepGoals4 "indepGoals4"-        , runTest $ testIndepGoals5 "indepGoals5 - fixed goal order" FixedGoalOrder-        , runTest $ testIndepGoals5 "indepGoals5 - default goal order" DefaultGoalOrder-        , runTest $ testIndepGoals6 "indepGoals6 - fixed goal order" FixedGoalOrder-        , runTest $ testIndepGoals6 "indepGoals6 - default goal order" DefaultGoalOrder-        ]-      -- Tests designed for the backjumping blog post-    , testGroup "Backjumping" [-          runTest $         mkTest dbBJ1a "bj1a" ["A"]      (solverSuccess [("A", 1), ("B",  1)])-        , runTest $         mkTest dbBJ1b "bj1b" ["A"]      (solverSuccess [("A", 1), ("B",  1)])-        , runTest $         mkTest dbBJ1c "bj1c" ["A"]      (solverSuccess [("A", 1), ("B",  1)])-        , runTest $         mkTest dbBJ2  "bj2"  ["A"]      (solverSuccess [("A", 1), ("B",  1), ("C", 1)])-        , runTest $         mkTest dbBJ3  "bj3"  ["A"]      (solverSuccess [("A", 1), ("Ba", 1), ("C", 1)])-        , runTest $         mkTest dbBJ4  "bj4"  ["A"]      (solverSuccess [("A", 1), ("B",  1), ("C", 1)])-        , runTest $         mkTest dbBJ5  "bj5"  ["A"]      (solverSuccess [("A", 1), ("B",  1), ("D", 1)])-        , runTest $         mkTest dbBJ6  "bj6"  ["A"]      (solverSuccess [("A", 1), ("B",  1)])-        , runTest $         mkTest dbBJ7  "bj7"  ["A"]      (solverSuccess [("A", 1), ("B",  1), ("C", 1)])-        , runTest $ indep $ mkTest dbBJ8  "bj8"  ["A", "B"] (solverSuccess [("A", 1), ("B",  1), ("C", 1)])-        ]-    -- build-tool-depends dependencies-    , testGroup "build-tool-depends" [-          runTest $ mkTest dbBuildTools "simple exe dependency" ["A"] (solverSuccess [("A", 1), ("bt-pkg", 2)])--        , runTest $ disableSolveExecutables $-          mkTest dbBuildTools "don't install build tool packages in legacy mode" ["A"] (solverSuccess [("A", 1)])--        , runTest $ mkTest dbBuildTools "flagged exe dependency" ["B"] (solverSuccess [("B", 1), ("bt-pkg", 2)])--        , runTest $ enableAllTests $-          mkTest dbBuildTools "test suite exe dependency" ["C"] (solverSuccess [("C", 1), ("bt-pkg", 2)])--        , runTest $ mkTest dbBuildTools "unknown exe" ["D"] $-          solverFailure (isInfixOf "does not contain executable unknown-exe, which is required by D")--        , runTest $ disableSolveExecutables $-          mkTest dbBuildTools "don't check for build tool executables in legacy mode" ["D"] $ solverSuccess [("D", 1)]--        , runTest $ mkTest dbBuildTools "unknown build tools package error mentions package, not exe" ["E"] $-          solverFailure (isInfixOf "unknown package: E:unknown-pkg:exe.unknown-pkg (dependency of E)")--        , runTest $ mkTest dbBuildTools "unknown flagged exe" ["F"] $-          solverFailure (isInfixOf "does not contain executable unknown-exe, which is required by F +flagF")--        , runTest $ enableAllTests $ mkTest dbBuildTools "unknown test suite exe" ["G"] $-          solverFailure (isInfixOf "does not contain executable unknown-exe, which is required by G *test")--        , runTest $ mkTest dbBuildTools "wrong exe for build tool package version" ["H"] $-          solverFailure $ isInfixOf $-              -- The solver reports the version conflict when a version conflict-              -- and an executable conflict apply to the same package version.-              "[__1] rejecting: H:bt-pkg:exe.bt-pkg-4.0.0 (conflict: H => H:bt-pkg:exe.bt-pkg (exe exe1)==3.0.0)\n"-           ++ "[__1] rejecting: H:bt-pkg:exe.bt-pkg-3.0.0 (does not contain executable exe1, which is required by H)\n"-           ++ "[__1] rejecting: H:bt-pkg:exe.bt-pkg-2.0.0, H:bt-pkg:exe.bt-pkg-1.0.0 (conflict: H => H:bt-pkg:exe.bt-pkg (exe exe1)==3.0.0)"--        , runTest $ chooseExeAfterBuildToolsPackage True "choose exe after choosing its package - success"--        , runTest $ chooseExeAfterBuildToolsPackage False "choose exe after choosing its package - failure"--        , runTest $ rejectInstalledBuildToolPackage "reject installed package for build-tool dependency"--        , runTest $ requireConsistentBuildToolVersions "build tool versions must be consistent within one package"-    ]-    -- build-tools dependencies-    , testGroup "legacy build-tools" [-          runTest $ mkTest dbLegacyBuildTools1 "bt1" ["A"] (solverSuccess [("A", 1), ("alex", 1)])--        , runTest $ disableSolveExecutables $-          mkTest dbLegacyBuildTools1 "bt1 - don't install build tool packages in legacy mode" ["A"] (solverSuccess [("A", 1)])--        , runTest $ mkTest dbLegacyBuildTools2 "bt2" ["A"] $-          solverFailure (isInfixOf "does not contain executable alex, which is required by A")--        , runTest $ disableSolveExecutables $-          mkTest dbLegacyBuildTools2 "bt2 - don't check for build tool executables in legacy mode" ["A"] (solverSuccess [("A", 1)])--        , runTest $ mkTest dbLegacyBuildTools3 "bt3" ["A"] (solverSuccess [("A", 1)])--        , runTest $ mkTest dbLegacyBuildTools4 "bt4" ["C"] (solverSuccess [("A", 1), ("B", 1), ("C", 1), ("alex", 1), ("alex", 2)])--        , runTest $ mkTest dbLegacyBuildTools5 "bt5" ["B"] (solverSuccess [("A", 1), ("A", 2), ("B", 1), ("alex", 1)])--        , runTest $ mkTest dbLegacyBuildTools6 "bt6" ["A"] (solverSuccess [("A", 1), ("alex", 1), ("happy", 1)])-        ]-      -- internal dependencies-    , testGroup "internal dependencies" [-          runTest $ mkTest dbIssue3775 "issue #3775" ["B"] (solverSuccess [("A", 2), ("B", 2), ("warp", 1)])-        ]-      -- Tests for the contents of the solver's log-    , testGroup "Solver log" [-          -- See issue #3203. The solver should only choose a version for A once.-          runTest $-              let db = [Right $ exAv "A" 1 []]--                  p :: [String] -> Bool-                  p lg =    elem "targets: A" lg-                         && length (filter ("trying: A" `isInfixOf`) lg) == 1-              in mkTest db "deduplicate targets" ["A", "A"] $-                 SolverResult p $ Right [("A", 1)]-        , runTest $-              let db = [Right $ exAv "A" 1 [ExAny "B"]]-                  msg = "After searching the rest of the dependency tree exhaustively, "-                     ++ "these were the goals I've had most trouble fulfilling: A, B"-              in mkTest db "exhaustive search failure message" ["A"] $-                 solverFailure (isInfixOf msg)-        , testSummarizedLog "show conflicts from final conflict set after exhaustive search" Nothing $-                "Could not resolve dependencies:\n"-             ++ "[__0] trying: A-1.0.0 (user goal)\n"-             ++ "[__1] unknown package: D (dependency of A)\n"-             ++ "[__1] fail (backjumping, conflict set: A, D)\n"-             ++ "After searching the rest of the dependency tree exhaustively, "-             ++ "these were the goals I've had most trouble fulfilling: A, D"-        , testSummarizedLog "show first conflicts after inexhaustive search" (Just 2) $-                "Could not resolve dependencies:\n"-             ++ "[__0] trying: A-1.0.0 (user goal)\n"-             ++ "[__1] trying: B-3.0.0 (dependency of A)\n"-             ++ "[__2] next goal: C (dependency of B)\n"-             ++ "[__2] rejecting: C-1.0.0 (conflict: B => C==3.0.0)\n"-             ++ "Backjump limit reached (currently 2, change with --max-backjumps "-             ++ "or try to run with --reorder-goals).\n"-        , testSummarizedLog "don't show summarized log when backjump limit is too low" (Just 1) $-                "Backjump limit reached (currently 1, change with --max-backjumps "-             ++ "or try to run with --reorder-goals).\n"-             ++ "Failed to generate a summarized dependency solver log due to low backjump limit."-        ]-    ]-  where-    indep           = independentGoals-    mkvrThis        = V.thisVersion . makeV-    mkvrOrEarlier   = V.orEarlierVersion . makeV-    makeV v         = V.mkVersion [v,0,0]--data GoalOrder = FixedGoalOrder | DefaultGoalOrder--{--------------------------------------------------------------------------------  Specific example database for the tests--------------------------------------------------------------------------------}--db1 :: ExampleDb-db1 =-    let a = exInst "A" 1 "A-1" []-    in [ Left a-       , Right $ exAv "B" 1 [ExAny "A"]-       , Right $ exAv "B" 2 [ExAny "A"]-       , Right $ exAv "C" 1 [ExFix "B" 1]-       , Right $ exAv "D" 1 [ExFix "B" 2]-       , Right $ exAv "E" 1 [ExAny "B"]-       , Right $ exAv "F" 1 [ExFix "B" 1, ExAny "E"]-       , Right $ exAv "G" 1 [ExFix "B" 2, ExAny "E"]-       , Right $ exAv "Z" 1 []-       ]---- In this example, we _can_ install C and D as independent goals, but we have--- to pick two diferent versions for B (arbitrarily)-db2 :: ExampleDb-db2 = [-    Right $ exAv "A" 1 []-  , Right $ exAv "A" 2 []-  , Right $ exAv "B" 1 [ExAny "A"]-  , Right $ exAv "B" 2 [ExAny "A"]-  , Right $ exAv "C" 1 [ExAny "B", ExFix "A" 1]-  , Right $ exAv "D" 1 [ExAny "B", ExFix "A" 2]-  ]--db3 :: ExampleDb-db3 = [-     Right $ exAv "A" 1 []-   , Right $ exAv "A" 2 []-   , Right $ exAv "B" 1 [exFlagged "flagB" [ExFix "A" 1] [ExFix "A" 2]]-   , Right $ exAv "C" 1 [ExFix "A" 1, ExAny "B"]-   , Right $ exAv "D" 1 [ExFix "A" 2, ExAny "B"]-   ]---- | Like db3, but the flag picks a different package rather than a--- different package version------ In db3 we cannot install C and D as independent goals because:------ * The multiple instance restriction says C and D _must_ share B--- * Since C relies on A-1, C needs B to be compiled with flagB on--- * Since D relies on A-2, D needs B to be compiled with flagB off--- * Hence C and D have incompatible requirements on B's flags.------ However, _even_ if we don't check explicitly that we pick the same flag--- assignment for 0.B and 1.B, we will still detect the problem because--- 0.B depends on 0.A-1, 1.B depends on 1.A-2, hence we cannot link 0.A to--- 1.A and therefore we cannot link 0.B to 1.B.------ In db4 the situation however is trickier. We again cannot install--- packages C and D as independent goals because:------ * As above, the multiple instance restriction says that C and D _must_ share B--- * Since C relies on Ax-2, it requires B to be compiled with flagB off--- * Since D relies on Ay-2, it requires B to be compiled with flagB on--- * Hence C and D have incompatible requirements on B's flags.------ But now this requirement is more indirect. If we only check dependencies--- we don't see the problem:------ * We link 0.B to 1.B--- * 0.B relies on Ay-1--- * 1.B relies on Ax-1------ We will insist that 0.Ay will be linked to 1.Ay, and 0.Ax to 1.Ax, but since--- we only ever assign to one of these, these constraints are never broken.-db4 :: ExampleDb-db4 = [-     Right $ exAv "Ax" 1 []-   , Right $ exAv "Ax" 2 []-   , Right $ exAv "Ay" 1 []-   , Right $ exAv "Ay" 2 []-   , Right $ exAv "B"  1 [exFlagged "flagB" [ExFix "Ax" 1] [ExFix "Ay" 1]]-   , Right $ exAv "C"  1 [ExFix "Ax" 2, ExAny "B"]-   , Right $ exAv "D"  1 [ExFix "Ay" 2, ExAny "B"]-   ]---- | Simple database containing one package with a manual flag.-dbManualFlags :: ExampleDb-dbManualFlags = [-    Right $ declareFlags [ExFlag "flag" True Manual] $-        exAv "pkg" 1 [exFlagged "flag" [ExAny "true-dep"] [ExAny "false-dep"]]-  , Right $ exAv "true-dep"  1 []-  , Right $ exAv "false-dep" 1 []-  ]---- | Database containing a setup dependency with a manual flag. A's library and--- setup script depend on two different versions of B. B's manual flag can be--- set to different values in the two places where it is used.-dbSetupDepWithManualFlag :: ExampleDb-dbSetupDepWithManualFlag =-  let bFlags = [ExFlag "flag" True Manual]-  in [-      Right $ exAv "A" 1 [ExFix "B" 1] `withSetupDeps` [ExFix "B" 2]-    , Right $ declareFlags bFlags $-          exAv "B" 1 [exFlagged "flag" [ExAny "b-1-true-dep"]-                                       [ExAny "b-1-false-dep"]]-    , Right $ declareFlags bFlags $-          exAv "B" 2 [exFlagged "flag" [ExAny "b-2-true-dep"]-                                       [ExAny "b-2-false-dep"]]-    , Right $ exAv "b-1-true-dep"  1 []-    , Right $ exAv "b-1-false-dep" 1 []-    , Right $ exAv "b-2-true-dep"  1 []-    , Right $ exAv "b-2-false-dep" 1 []-    ]---- | A database similar to 'dbSetupDepWithManualFlag', except that the library--- and setup script both depend on B-1. B must be linked because of the Single--- Instance Restriction, and its flag can only have one value.-dbLinkedSetupDepWithManualFlag :: ExampleDb-dbLinkedSetupDepWithManualFlag = [-    Right $ exAv "A" 1 [ExFix "B" 1] `withSetupDeps` [ExFix "B" 1]-  , Right $ declareFlags [ExFlag "flag" True Manual] $-        exAv "B" 1 [exFlagged "flag" [ExAny "b-1-true-dep"]-                                     [ExAny "b-1-false-dep"]]-  , Right $ exAv "b-1-true-dep"  1 []-  , Right $ exAv "b-1-false-dep" 1 []-  ]---- | Some tests involving testsuites------ Note that in this test framework test suites are always enabled; if you--- want to test without test suites just set up a test database without--- test suites.------ * C depends on A (through its test suite)--- * D depends on B-2 (through its test suite), but B-2 is unavailable--- * E depends on A-1 directly and on A through its test suite. We prefer---     to use A-1 for the test suite in this case.--- * F depends on A-1 directly and on A-2 through its test suite. In this---     case we currently fail to install F, although strictly speaking---     test suites should be considered independent goals.--- * G is like E, but for version A-2. This means that if we cannot install---     E and G together, unless we regard them as independent goals.-db5 :: ExampleDb-db5 = [-    Right $ exAv "A" 1 []-  , Right $ exAv "A" 2 []-  , Right $ exAv "B" 1 []-  , Right $ exAv "C" 1 [] `withTest` ExTest "testC" [ExAny "A"]-  , Right $ exAv "D" 1 [] `withTest` ExTest "testD" [ExFix "B" 2]-  , Right $ exAv "E" 1 [ExFix "A" 1] `withTest` ExTest "testE" [ExAny "A"]-  , Right $ exAv "F" 1 [ExFix "A" 1] `withTest` ExTest "testF" [ExFix "A" 2]-  , Right $ exAv "G" 1 [ExFix "A" 2] `withTest` ExTest "testG" [ExAny "A"]-  ]---- Now the _dependencies_ have test suites------ * Installing C is a simple example. C wants version 1 of A, but depends on---   B, and B's testsuite depends on an any version of A. In this case we prefer---   to link (if we don't regard test suites as independent goals then of course---   linking here doesn't even come into it).--- * Installing [C, D] means that we prefer to link B -- depending on how we---   set things up, this means that we should also link their test suites.-db6 :: ExampleDb-db6 = [-    Right $ exAv "A" 1 []-  , Right $ exAv "A" 2 []-  , Right $ exAv "B" 1 [] `withTest` ExTest "testA" [ExAny "A"]-  , Right $ exAv "C" 1 [ExFix "A" 1, ExAny "B"]-  , Right $ exAv "D" 1 [ExAny "B"]-  ]---- | This test checks that the solver can backjump to disable a flag, even if--- the problematic dependency is also under a test suite. (issue #4390)------ The goal order forces the solver to choose the flag before enabling testing.--- Previously, the solver couldn't handle this case, because it only tried to--- disable testing, and when that failed, it backjumped past the flag choice.--- The solver should also try to set the flag to false, because that avoids the--- dependency on B.-testTestSuiteWithFlag :: String -> SolverTest-testTestSuiteWithFlag name =-    goalOrder goals $ enableAllTests $ mkTest db name ["A", "B"] $-    solverSuccess [("A", 1), ("B", 1)]-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 []-          `withTest`-            ExTest "test" [exFlagged "flag" [ExFix "B" 2] []]-      , Right $ exAv "B" 1 []-      ]--    goals :: [ExampleVar]-    goals = [-        P QualNone "B"-      , P QualNone "A"-      , F QualNone "A" "flag"-      , S QualNone "A" TestStanzas-      ]---- Packages with setup dependencies------ Install..--- * B: Simple example, just make sure setup deps are taken into account at all--- * C: Both the package and the setup script depend on any version of A.---      In this case we prefer to link--- * D: Variation on C.1 where the package requires a specific (not latest)---      version but the setup dependency is not fixed. Again, we prefer to---      link (picking the older version)--- * E: Variation on C.2 with the setup dependency the more inflexible.---      Currently, in this case we do not see the opportunity to link because---      we consider setup dependencies after normal dependencies; we will---      pick A.2 for E, then realize we cannot link E.setup.A to A.2, and pick---      A.1 instead. This isn't so easy to fix (if we want to fix it at all);---      in particular, considering setup dependencies _before_ other deps is---      not an improvement, because in general we would prefer to link setup---      setups to package deps, rather than the other way around. (For example,---      if we change this ordering then the test for D would start to install---      two versions of A).--- * F: The package and the setup script depend on different versions of A.---      This will only work if setup dependencies are considered independent.-db7 :: ExampleDb-db7 = [-    Right $ exAv "A" 1 []-  , Right $ exAv "A" 2 []-  , Right $ exAv "B" 1 []            `withSetupDeps` [ExAny "A"]-  , Right $ exAv "C" 1 [ExAny "A"  ] `withSetupDeps` [ExAny "A"  ]-  , Right $ exAv "D" 1 [ExFix "A" 1] `withSetupDeps` [ExAny "A"  ]-  , Right $ exAv "E" 1 [ExAny "A"  ] `withSetupDeps` [ExFix "A" 1]-  , Right $ exAv "F" 1 [ExFix "A" 2] `withSetupDeps` [ExFix "A" 1]-  ]---- If we install C and D together (not as independent goals), we need to build--- both B.1 and B.2, both of which depend on A.-db8 :: ExampleDb-db8 = [-    Right $ exAv "A" 1 []-  , Right $ exAv "B" 1 [ExAny "A"]-  , Right $ exAv "B" 2 [ExAny "A"]-  , Right $ exAv "C" 1 [] `withSetupDeps` [ExFix "B" 1]-  , Right $ exAv "D" 1 [] `withSetupDeps` [ExFix "B" 2]-  ]---- Extended version of `db8` so that we have nested setup dependencies-db9 :: ExampleDb-db9 = db8 ++ [-    Right $ exAv "E" 1 [ExAny "C"]-  , Right $ exAv "E" 2 [ExAny "D"]-  , Right $ exAv "F" 1 [] `withSetupDeps` [ExFix "E" 1]-  , Right $ exAv "G" 1 [] `withSetupDeps` [ExFix "E" 2]-  ]---- Multiple already-installed packages with inter-dependencies, and one package--- (C) that depends on package A-1 for its setup script and package A-2 as a--- library dependency.-db10 :: ExampleDb-db10 =-  let rts         = exInst "rts"         1 "rts-inst"         []-      ghc_prim    = exInst "ghc-prim"    1 "ghc-prim-inst"    [rts]-      base        = exInst "base"        1 "base-inst"        [rts, ghc_prim]-      a1          = exInst "A"           1 "A1-inst"          [base]-      a2          = exInst "A"           2 "A2-inst"          [base]-  in [-      Left rts-    , Left ghc_prim-    , Left base-    , Left a1-    , Left a2-    , Right $ exAv "C" 1 [ExFix "A" 2] `withSetupDeps` [ExFix "A" 1]-    ]---- | This database tests that a package's setup dependencies are correctly--- linked when the package is linked. See pull request #3268.------ When A and B are installed as independent goals, their dependencies on C must--- be linked, due to the single instance restriction. Since C depends on D, 0.D--- and 1.D must be linked. C also has a setup dependency on D, so 0.C-setup.D--- and 1.C-setup.D must be linked. However, D's two link groups must remain--- independent. The solver should be able to choose D-1 for C's library and D-2--- for C's setup script.-dbSetupDeps :: ExampleDb-dbSetupDeps = [-    Right $ exAv "A" 1 [ExAny "C"]-  , Right $ exAv "B" 1 [ExAny "C"]-  , Right $ exAv "C" 1 [ExFix "D" 1] `withSetupDeps` [ExFix "D" 2]-  , Right $ exAv "D" 1 []-  , Right $ exAv "D" 2 []-  ]---- | Tests for dealing with base shims-db11 :: ExampleDb-db11 =-  let base3 = exInst "base" 3 "base-3-inst" [base4]-      base4 = exInst "base" 4 "base-4-inst" []-  in [-      Left base3-    , Left base4-    , Right $ exAv "A" 1 [ExFix "base" 3]-    ]---- | Slightly more realistic version of db11 where base-3 depends on syb--- This means that if a package depends on base-3 and on syb, then they MUST--- share the version of syb------ * Package A relies on base-3 (which relies on base-4)--- * Package B relies on base-4--- * Package C relies on both A and B--- * Package D relies on base-3 and on syb-2, which is not possible because---     base-3 has a dependency on syb-1 (non-inheritance of the Base qualifier)--- * Package E relies on base-4 and on syb-2, which is fine.-db12 :: ExampleDb-db12 =-  let base3 = exInst "base" 3 "base-3-inst" [base4, syb1]-      base4 = exInst "base" 4 "base-4-inst" []-      syb1  = exInst "syb" 1 "syb-1-inst" [base4]-  in [-      Left base3-    , Left base4-    , Left syb1-    , Right $ exAv "syb" 2 [ExFix "base" 4]-    , Right $ exAv "A" 1 [ExFix "base" 3, ExAny "syb"]-    , Right $ exAv "B" 1 [ExFix "base" 4, ExAny "syb"]-    , Right $ exAv "C" 1 [ExAny "A", ExAny "B"]-    , Right $ exAv "D" 1 [ExFix "base" 3, ExFix "syb" 2]-    , Right $ exAv "E" 1 [ExFix "base" 4, ExFix "syb" 2]-    ]--dbBase :: ExampleDb-dbBase = [-      Right $ exAv "base" 1-              [ExAny "ghc-prim", ExAny "integer-simple", ExAny "integer-gmp"]-    , Right $ exAv "ghc-prim" 1 []-    , Right $ exAv "integer-simple" 1 []-    , Right $ exAv "integer-gmp" 1 []-    ]--db13 :: ExampleDb-db13 = [-    Right $ exAv "A" 1 []-  , Right $ exAv "A" 2 []-  , Right $ exAv "A" 3 []-  ]---- | A, B, and C have three different dependencies on D that can be set to--- different versions with qualified constraints. Each version of D can only--- be depended upon by one version of A, B, or C, so that the versions of A, B,--- and C in the install plan indicate which version of D was chosen for each--- dependency. The one-to-one correspondence between versions of A, B, and C and--- versions of D also prevents linking, which would complicate the solver's--- behavior.-dbConstraints :: ExampleDb-dbConstraints =-    [Right $ exAv "A" v [ExFix "D" v] | v <- [1, 4, 7]]- ++ [Right $ exAv "B" v [] `withSetupDeps` [ExFix "D" v] | v <- [2, 5, 8]]- ++ [Right $ exAv "C" v [] `withSetupDeps` [ExFix "D" v] | v <- [3, 6, 9]]- ++ [Right $ exAv "D" v [] | v <- [1..9]]--dbStanzaPreferences1 :: ExampleDb-dbStanzaPreferences1 = [-    Right $ exAv "pkg" 1 [] `withTest` ExTest "test" [ExAny "test-dep"]-  , Right $ exAv "test-dep" 1 []-  ]--dbStanzaPreferences2 :: ExampleDb-dbStanzaPreferences2 = [-    Right $ exAv "pkg" 1 [] `withTest` ExTest "test" [ExAny "unknown"]-  ]---- | This is a test case for a bug in stanza preferences (#3930). The solver--- should be able to install 'A' by enabling 'flag' and disabling testing. When--- it tries goals in the specified order and prefers testing, it encounters--- 'unknown-pkg2'. 'unknown-pkg2' is only introduced by testing and 'flag', so--- the conflict set should contain both of those variables. Before the fix, it--- only contained 'flag'. The solver backjumped past the choice to disable--- testing and failed to find the solution.-testStanzaPreference :: String -> TestTree-testStanzaPreference name =-  let pkg = exAv "A" 1    [exFlagged "flag"-                              []-                              [ExAny "unknown-pkg1"]]-             `withTest`-            ExTest "test" [exFlagged "flag"-                              [ExAny "unknown-pkg2"]-                              []]-      goals = [-          P QualNone "A"-        , F QualNone "A" "flag"-        , S QualNone "A" TestStanzas-        ]-  in runTest $ goalOrder goals $-     preferences [ ExStanzaPref "A" [TestStanzas]] $-     mkTest [Right pkg] name ["A"] $-     solverSuccess [("A", 1)]---- | Database with some cycles------ * Simplest non-trivial cycle: A -> B and B -> A--- * There is a cycle C -> D -> C, but it can be broken by picking the---   right flag assignment.-db14 :: ExampleDb-db14 = [-    Right $ exAv "A" 1 [ExAny "B"]-  , Right $ exAv "B" 1 [ExAny "A"]-  , Right $ exAv "C" 1 [exFlagged "flagC" [ExAny "D"] [ExAny "E"]]-  , Right $ exAv "D" 1 [ExAny "C"]-  , Right $ exAv "E" 1 []-  ]---- | Cycles through setup dependencies------ The first cycle is unsolvable: package A has a setup dependency on B,--- B has a regular dependency on A, and we only have a single version available--- for both.------ The second cycle can be broken by picking different versions: package C-2.0--- has a setup dependency on D, and D has a regular dependency on C-*. However,--- version C-1.0 is already available (perhaps it didn't have this setup dep).--- Thus, we should be able to break this cycle even if we are installing package--- E, which explictly depends on C-2.0.-db15 :: ExampleDb-db15 = [-    -- First example (real cycle, no solution)-    Right $ exAv   "A" 1            []            `withSetupDeps` [ExAny "B"]-  , Right $ exAv   "B" 1            [ExAny "A"]-    -- Second example (cycle can be broken by picking versions carefully)-  , Left  $ exInst "C" 1 "C-1-inst" []-  , Right $ exAv   "C" 2            []            `withSetupDeps` [ExAny "D"]-  , Right $ exAv   "D" 1            [ExAny "C"  ]-  , Right $ exAv   "E" 1            [ExFix "C" 2]-  ]---- | Detect a cycle between a package and its setup script.------ This type of cycle can easily occur when new-build adds default setup--- dependencies to packages without custom-setup stanzas. For example, cabal--- adds 'time' as a setup dependency for 'time'. The solver should detect the--- cycle when it attempts to link the setup and non-setup instances of the--- package and then choose a different version for the setup dependency.-issue4161 :: String -> SolverTest-issue4161 name =-    mkTest db name ["target"] $-    SolverResult checkFullLog $ Right [("target", 1), ("time", 1), ("time", 2)]-  where-    db :: ExampleDb-    db = [-        Right $ exAv "target" 1 [ExFix "time" 2]-      , Right $ exAv "time"   2 []               `withSetupDeps` [ExAny "time"]-      , Right $ exAv "time"   1 []-      ]--    checkFullLog :: [String] -> Bool-    checkFullLog = any $ isInfixOf $-        "rejecting: time:setup.time~>time-2.0.0 (cyclic dependencies; "-                ++ "conflict set: time:setup.time)"---- | Packages pkg-A, pkg-B, and pkg-C form a cycle. The solver should backtrack--- as soon as it chooses the last package in the cycle, to avoid searching parts--- of the tree that have no solution. Since there is no way to break the cycle,--- it should fail with an error message describing the cycle.-testCyclicDependencyErrorMessages :: String -> SolverTest-testCyclicDependencyErrorMessages name =-    goalOrder goals $-    mkTest db name ["pkg-A"] $-    SolverResult checkFullLog $ Left checkSummarizedLog-  where-    db :: ExampleDb-    db = [-        Right $ exAv "pkg-A" 1 [ExAny "pkg-B"]-      , Right $ exAv "pkg-B" 1 [ExAny "pkg-C"]-      , Right $ exAv "pkg-C" 1 [ExAny "pkg-A", ExAny "pkg-D"]-      , Right $ exAv "pkg-D" 1 [ExAny "pkg-E"]-      , Right $ exAv "pkg-E" 1 []-      ]--    -- The solver should backtrack as soon as pkg-A, pkg-B, and pkg-C form a-    -- cycle. It shouldn't try pkg-D or pkg-E.-    checkFullLog :: [String] -> Bool-    checkFullLog =-        not . any (\l -> "pkg-D" `isInfixOf` l || "pkg-E" `isInfixOf` l)--    checkSummarizedLog :: String -> Bool-    checkSummarizedLog =-        isInfixOf "rejecting: pkg-C-1.0.0 (cyclic dependencies; conflict set: pkg-A, pkg-B, pkg-C)"--    -- Solve for pkg-D and pkg-E last.-    goals :: [ExampleVar]-    goals = [P QualNone ("pkg-" ++ [c]) | c <- ['A'..'E']]---- | Check that the solver can backtrack after encountering the SIR (issue #2843)------ When A and B are installed as independent goals, the single instance--- restriction prevents B from depending on C.  This database tests that the--- solver can backtrack after encountering the single instance restriction and--- choose the only valid flag assignment (-flagA +flagB):------ > flagA flagB  B depends on--- >  On    _     C-*--- >  Off   On    E-*               <-- only valid flag assignment--- >  Off   Off   D-2.0, C-*------ Since A depends on C-* and D-1.0, and C-1.0 depends on any version of D,--- we must build C-1.0 against D-1.0. Since B depends on D-2.0, we cannot have--- C in the transitive closure of B's dependencies, because that would mean we--- would need two instances of C: one built against D-1.0 and one built against--- D-2.0.-db16 :: ExampleDb-db16 = [-    Right $ exAv "A" 1 [ExAny "C", ExFix "D" 1]-  , Right $ exAv "B" 1 [ ExFix "D" 2-                       , exFlagged "flagA"-                             [ExAny "C"]-                             [exFlagged "flagB"-                                 [ExAny "E"]-                                 [ExAny "C"]]]-  , Right $ exAv "C" 1 [ExAny "D"]-  , Right $ exAv "D" 1 []-  , Right $ exAv "D" 2 []-  , Right $ exAv "E" 1 []-  ]---- | This test checks that when the solver discovers a constraint on a--- package's version after choosing to link that package, it can backtrack to--- try alternative versions for the linked-to package. See pull request #3327.------ When A and B are installed as independent goals, their dependencies on C--- must be linked. Since C depends on D, A and B's dependencies on D must also--- be linked. This test fixes the goal order so that the solver chooses D-2 for--- both 0.D and 1.D before it encounters the test suites' constraints. The--- solver must backtrack to try D-1 for both 0.D and 1.D.-testIndepGoals2 :: String -> SolverTest-testIndepGoals2 name =-    goalOrder goals $ independentGoals $-    enableAllTests $ mkTest db name ["A", "B"] $-    solverSuccess [("A", 1), ("B", 1), ("C", 1), ("D", 1)]-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [ExAny "C"] `withTest` ExTest "test" [ExFix "D" 1]-      , Right $ exAv "B" 1 [ExAny "C"] `withTest` ExTest "test" [ExFix "D" 1]-      , Right $ exAv "C" 1 [ExAny "D"]-      , Right $ exAv "D" 1 []-      , Right $ exAv "D" 2 []-      ]--    goals :: [ExampleVar]-    goals = [-        P (QualIndep "A") "A"-      , P (QualIndep "A") "C"-      , P (QualIndep "A") "D"-      , P (QualIndep "B") "B"-      , P (QualIndep "B") "C"-      , P (QualIndep "B") "D"-      , S (QualIndep "B") "B" TestStanzas-      , S (QualIndep "A") "A" TestStanzas-      ]---- | Issue #2834--- When both A and B are installed as independent goals, their dependencies on--- C must be linked. The only combination of C's flags that is consistent with--- A and B's dependencies on D is -flagA +flagB. This database tests that the--- solver can backtrack to find the right combination of flags (requiring F, but--- not E or G) and apply it to both 0.C and 1.C.------ > flagA flagB  C depends on--- >  On    _     D-1, E-*--- >  Off   On    F-*        <-- Only valid choice--- >  Off   Off   D-2, G-*------ The single instance restriction means we cannot have one instance of C--- built against D-1 and one instance built against D-2; since A depends on--- D-1, and B depends on C-2, it is therefore important that C cannot depend--- on any version of D.-db18 :: ExampleDb-db18 = [-    Right $ exAv "A" 1 [ExAny "C", ExFix "D" 1]-  , Right $ exAv "B" 1 [ExAny "C", ExFix "D" 2]-  , Right $ exAv "C" 1 [exFlagged "flagA"-                           [ExFix "D" 1, ExAny "E"]-                           [exFlagged "flagB"-                               [ExAny "F"]-                               [ExFix "D" 2, ExAny "G"]]]-  , Right $ exAv "D" 1 []-  , Right $ exAv "D" 2 []-  , Right $ exAv "E" 1 []-  , Right $ exAv "F" 1 []-  , Right $ exAv "G" 1 []-  ]---- | When both values for flagA introduce package B, the solver should be able--- to choose B before choosing a value for flagA. It should try to choose a--- version for B that is in the union of the version ranges required by +flagA--- and -flagA.-commonDependencyLogMessage :: String -> SolverTest-commonDependencyLogMessage name =-    mkTest db name ["A"] $ solverFailure $ isInfixOf $-        "[__0] trying: A-1.0.0 (user goal)\n"-     ++ "[__1] next goal: B (dependency of A +/-flagA)\n"-     ++ "[__1] rejecting: B-2.0.0 (conflict: A +/-flagA => B==1.0.0 || ==3.0.0)"-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [exFlagged "flagA"-                               [ExFix "B" 1]-                               [ExFix "B" 3]]-      , Right $ exAv "B" 2 []-      ]---- | Test lifting dependencies out of multiple levels of conditionals.-twoLevelDeepCommonDependencyLogMessage :: String -> SolverTest-twoLevelDeepCommonDependencyLogMessage name =-    mkTest db name ["A"] $ solverFailure $ isInfixOf $-        "unknown package: B (dependency of A +/-flagA +/-flagB)"-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [exFlagged "flagA"-                               [exFlagged "flagB"-                                   [ExAny "B"]-                                   [ExAny "B"]]-                               [exFlagged "flagB"-                                   [ExAny "B"]-                                   [ExAny "B"]]]-      ]---- | Test handling nested conditionals that are controlled by the same flag.--- The solver should treat flagA as introducing 'unknown' with value true, not--- both true and false. That means that when +flagA causes a conflict, the--- solver should try flipping flagA to false to resolve the conflict, rather--- than backjumping past flagA.-testBackjumpingWithCommonDependency :: String -> SolverTest-testBackjumpingWithCommonDependency name =-    mkTest db name ["A"] $ solverSuccess [("A", 1), ("B", 1)]-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [exFlagged "flagA"-                               [exFlagged "flagA"-                                   [ExAny "unknown"]-                                   [ExAny "unknown"]]-                               [ExAny "B"]]-      , Right $ exAv "B" 1 []-      ]---- | Tricky test case with independent goals (issue #2842)------ Suppose we are installing D, E, and F as independent goals:------ * D depends on A-* and C-1, requiring A-1 to be built against C-1--- * E depends on B-* and C-2, requiring B-1 to be built against C-2--- * F depends on A-* and B-*; this means we need A-1 and B-1 both to be built---     against the same version of C, violating the single instance restriction.------ We can visualize this DB as:------ >    C-1   C-2--- >    /|\   /|\--- >   / | \ / | \--- >  /  |  X  |  \--- > |   | / \ |   |--- > |   |/   \|   |--- > |   +     +   |--- > |   |     |   |--- > |   A     B   |--- >  \  |\   /|  /--- >   \ | \ / | /--- >    \|  V  |/--- >     D  F  E-testIndepGoals3 :: String -> SolverTest-testIndepGoals3 name =-    goalOrder goals $ independentGoals $-    mkTest db name ["D", "E", "F"] anySolverFailure-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [ExAny "C"]-      , Right $ exAv "B" 1 [ExAny "C"]-      , Right $ exAv "C" 1 []-      , Right $ exAv "C" 2 []-      , Right $ exAv "D" 1 [ExAny "A", ExFix "C" 1]-      , Right $ exAv "E" 1 [ExAny "B", ExFix "C" 2]-      , Right $ exAv "F" 1 [ExAny "A", ExAny "B"]-      ]--    goals :: [ExampleVar]-    goals = [-        P (QualIndep "D") "D"-      , P (QualIndep "D") "C"-      , P (QualIndep "D") "A"-      , P (QualIndep "E") "E"-      , P (QualIndep "E") "C"-      , P (QualIndep "E") "B"-      , P (QualIndep "F") "F"-      , P (QualIndep "F") "B"-      , P (QualIndep "F") "C"-      , P (QualIndep "F") "A"-      ]---- | This test checks that the solver correctly backjumps when dependencies--- of linked packages are not linked. It is an example where the conflict set--- from enforcing the single instance restriction is not sufficient. See pull--- request #3327.------ When A, B, and C are installed as independent goals with the specified goal--- order, the first choice that the solver makes for E is 0.E-2. Then, when it--- chooses dependencies for B and C, it links both 1.E and 2.E to 0.E. Finally,--- the solver discovers C's test's constraint on E. It must backtrack to try--- 1.E-1 and then link 2.E to 1.E. Backjumping all the way to 0.E does not lead--- to a solution, because 0.E's version is constrained by A and cannot be--- changed.-testIndepGoals4 :: String -> SolverTest-testIndepGoals4 name =-    goalOrder goals $ independentGoals $-    enableAllTests $ mkTest db name ["A", "B", "C"] $-    solverSuccess [("A",1), ("B",1), ("C",1), ("D",1), ("E",1), ("E",2)]-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [ExFix "E" 2]-      , Right $ exAv "B" 1 [ExAny "D"]-      , Right $ exAv "C" 1 [ExAny "D"] `withTest` ExTest "test" [ExFix "E" 1]-      , Right $ exAv "D" 1 [ExAny "E"]-      , Right $ exAv "E" 1 []-      , Right $ exAv "E" 2 []-      ]--    goals :: [ExampleVar]-    goals = [-        P (QualIndep "A") "A"-      , P (QualIndep "A") "E"-      , P (QualIndep "B") "B"-      , P (QualIndep "B") "D"-      , P (QualIndep "B") "E"-      , P (QualIndep "C") "C"-      , P (QualIndep "C") "D"-      , P (QualIndep "C") "E"-      , S (QualIndep "C") "C" TestStanzas-      ]---- | Test the trace messages that we get when a package refers to an unknown pkg------ TODO: Currently we don't actually test the trace messages, and this particular--- test still suceeds. The trace can only be verified by hand.-db21 :: ExampleDb-db21 = [-    Right $ exAv "A" 1 [ExAny "B"]-  , Right $ exAv "A" 2 [ExAny "C"] -- A-2.0 will be tried first, but C unknown-  , Right $ exAv "B" 1 []-  ]---- | A variant of 'db21', which actually fails.-db22 :: ExampleDb-db22 = [-    Right $ exAv "A" 1 [ExAny "B"]-  , Right $ exAv "A" 2 [ExAny "C"]-  ]---- | Another test for the unknown package message.  This database tests that--- filtering out redundant conflict set messages in the solver log doesn't--- interfere with generating a message about a missing package (part of issue--- #3617). The conflict set for the missing package is {A, B}. That conflict set--- is propagated up the tree to the level of A. Since the conflict set is the--- same at both levels, the solver only keeps one of the backjumping messages.-db23 :: ExampleDb-db23 = [-    Right $ exAv "A" 1 [ExAny "B"]-  ]---- | Database for (unsuccessfully) trying to expose a bug in the handling--- of implied linking constraints. The question is whether an implied linking--- constraint should only have the introducing package in its conflict set,--- or also its link target.------ It turns out that as long as the Single Instance Restriction is in place,--- it does not matter, because there will aways be an option that is failing--- due to the SIR, which contains the link target in its conflict set.------ Even if the SIR is not in place, if there is a solution, one will always--- be found, because without the SIR, linking is always optional, but never--- necessary.----testIndepGoals5 :: String -> GoalOrder -> SolverTest-testIndepGoals5 name fixGoalOrder =-    case fixGoalOrder of-      FixedGoalOrder   -> goalOrder goals test-      DefaultGoalOrder -> test-  where-    test :: SolverTest-    test = independentGoals $ mkTest db name ["X", "Y"] $-           solverSuccess-           [("A", 1), ("A", 2), ("B", 1), ("C", 1), ("C", 2), ("X", 1), ("Y", 1)]--    db :: ExampleDb-    db = [-        Right $ exAv "X" 1 [ExFix "C" 2, ExAny "A"]-      , Right $ exAv "Y" 1 [ExFix "C" 1, ExFix "A" 2]-      , Right $ exAv "A" 1 []-      , Right $ exAv "A" 2 [ExAny "B"]-      , Right $ exAv "B" 1 [ExAny "C"]-      , Right $ exAv "C" 1 []-      , Right $ exAv "C" 2 []-      ]--    goals :: [ExampleVar]-    goals = [-        P (QualIndep "X") "X"-      , P (QualIndep "X") "A"-      , P (QualIndep "X") "B"-      , P (QualIndep "X") "C"-      , P (QualIndep "Y") "Y"-      , P (QualIndep "Y") "A"-      , P (QualIndep "Y") "B"-      , P (QualIndep "Y") "C"-      ]---- | A simplified version of 'testIndepGoals5'.-testIndepGoals6 :: String -> GoalOrder -> SolverTest-testIndepGoals6 name fixGoalOrder =-    case fixGoalOrder of-      FixedGoalOrder   -> goalOrder goals test-      DefaultGoalOrder -> test-  where-    test :: SolverTest-    test = independentGoals $ mkTest db name ["X", "Y"] $-           solverSuccess-           [("A", 1), ("A", 2), ("B", 1), ("B", 2), ("X", 1), ("Y", 1)]--    db :: ExampleDb-    db = [-        Right $ exAv "X" 1 [ExFix "B" 2, ExAny "A"]-      , Right $ exAv "Y" 1 [ExFix "B" 1, ExFix "A" 2]-      , Right $ exAv "A" 1 []-      , Right $ exAv "A" 2 [ExAny "B"]-      , Right $ exAv "B" 1 []-      , Right $ exAv "B" 2 []-      ]--    goals :: [ExampleVar]-    goals = [-        P (QualIndep "X") "X"-      , P (QualIndep "X") "A"-      , P (QualIndep "X") "B"-      , P (QualIndep "Y") "Y"-      , P (QualIndep "Y") "A"-      , P (QualIndep "Y") "B"-      ]--dbExts1 :: ExampleDb-dbExts1 = [-    Right $ exAv "A" 1 [ExExt (EnableExtension RankNTypes)]-  , Right $ exAv "B" 1 [ExExt (EnableExtension CPP), ExAny "A"]-  , Right $ exAv "C" 1 [ExAny "B"]-  , Right $ exAv "D" 1 [ExExt (DisableExtension CPP), ExAny "B"]-  , Right $ exAv "E" 1 [ExExt (UnknownExtension "custom"), ExAny "C"]-  ]--dbLangs1 :: ExampleDb-dbLangs1 = [-    Right $ exAv "A" 1 [ExLang Haskell2010]-  , Right $ exAv "B" 1 [ExLang Haskell98, ExAny "A"]-  , Right $ exAv "C" 1 [ExLang (UnknownLanguage "Haskell3000"), ExAny "B"]-  ]---- | cabal must set enable-exe to false in order to avoid the unavailable--- dependency. Flags are true by default. The flag choice causes "pkg" to--- depend on "false-dep".-testBuildable :: String -> ExampleDependency -> TestTree-testBuildable testName unavailableDep =-    runTest $-    mkTestExtLangPC (Just []) (Just [Haskell98]) [] db testName ["pkg"] expected-  where-    expected = solverSuccess [("false-dep", 1), ("pkg", 1)]-    db = [-        Right $ exAv "pkg" 1 [exFlagged "enable-exe"-                                 [ExAny "true-dep"]-                                 [ExAny "false-dep"]]-         `withExe`-            ExExe "exe" [ unavailableDep-                        , ExFlagged "enable-exe" (Buildable []) NotBuildable ]-      , Right $ exAv "true-dep" 1 []-      , Right $ exAv "false-dep" 1 []-      ]---- | cabal must choose -flag1 +flag2 for "pkg", which requires packages--- "flag1-false" and "flag2-true".-dbBuildable1 :: ExampleDb-dbBuildable1 = [-    Right $ exAv "pkg" 1-        [ exFlagged "flag1" [ExAny "flag1-true"] [ExAny "flag1-false"]-        , exFlagged "flag2" [ExAny "flag2-true"] [ExAny "flag2-false"]]-     `withExes`-        [ ExExe "exe1"-            [ ExAny "unknown"-            , ExFlagged "flag1" (Buildable []) NotBuildable-            , ExFlagged "flag2" (Buildable []) NotBuildable]-        , ExExe "exe2"-            [ ExAny "unknown"-            , ExFlagged "flag1"-                  (Buildable [])-                  (Buildable [ExFlagged "flag2" NotBuildable (Buildable [])])]-         ]-  , Right $ exAv "flag1-true" 1 []-  , Right $ exAv "flag1-false" 1 []-  , Right $ exAv "flag2-true" 1 []-  , Right $ exAv "flag2-false" 1 []-  ]---- | cabal must pick B-2 to avoid the unknown dependency.-dbBuildable2 :: ExampleDb-dbBuildable2 = [-    Right $ exAv "A" 1 [ExAny "B"]-  , Right $ exAv "B" 1 [ExAny "unknown"]-  , Right $ exAv "B" 2 []-     `withExe`-        ExExe "exe"-        [ ExAny "unknown"-        , ExFlagged "disable-exe" NotBuildable (Buildable [])-        ]-  , Right $ exAv "B" 3 [ExAny "unknown"]-  ]---- | Package databases for testing @pkg-config@ dependencies.-dbPC1 :: ExampleDb-dbPC1 = [-    Right $ exAv "A" 1 [ExPkg ("pkgA", 1)]-  , Right $ exAv "B" 1 [ExPkg ("pkgB", 1), ExAny "A"]-  , Right $ exAv "B" 2 [ExPkg ("pkgB", 2), ExAny "A"]-  , Right $ exAv "C" 1 [ExAny "B"]-  ]---- | Test for the solver's summarized log. The final conflict set is {A, D},--- though the goal order forces the solver to find the (avoidable) conflict--- between B >= 2 and C first. When the solver reaches the backjump limit, it--- should only show the log to the first conflict. When the backjump limit is--- high enough to allow an exhaustive search, the solver should make use of the--- final conflict set to only show the conflict between A and D in the--- summarized log.-testSummarizedLog :: String -> Maybe Int -> String -> TestTree-testSummarizedLog testName mbj expectedMsg =-    runTest $ maxBackjumps mbj $ goalOrder goals $ mkTest db testName ["A"] $-    solverFailure (== expectedMsg)-  where-    db = [-        Right $ exAv "A" 1 [ExAny "B", ExAny "D"]-      , Right $ exAv "B" 3 [ExFix "C" 3]-      , Right $ exAv "B" 2 [ExFix "C" 2]-      , Right $ exAv "B" 1 [ExAny "C"]-      , Right $ exAv "C" 1 []-      ]--    goals :: [ExampleVar]-    goals = [P QualNone pkg | pkg <- ["A", "B", "C", "D"]]--{--------------------------------------------------------------------------------  Simple databases for the illustrations for the backjumping blog post--------------------------------------------------------------------------------}---- | Motivate conflict sets-dbBJ1a :: ExampleDb-dbBJ1a = [-    Right $ exAv "A" 1 [ExFix "B" 1]-  , Right $ exAv "A" 2 [ExFix "B" 2]-  , Right $ exAv "B" 1 []-  ]---- | Show that we can skip some decisions-dbBJ1b :: ExampleDb-dbBJ1b = [-    Right $ exAv "A" 1 [ExFix "B" 1]-  , Right $ exAv "A" 2 [ExFix "B" 2, ExAny "C"]-  , Right $ exAv "B" 1 []-  , Right $ exAv "C" 1 []-  , Right $ exAv "C" 2 []-  ]---- | Motivate why both A and B need to be in the conflict set-dbBJ1c :: ExampleDb-dbBJ1c = [-    Right $ exAv "A" 1 [ExFix "B" 1]-  , Right $ exAv "B" 1 []-  , Right $ exAv "B" 2 []-  ]---- | Motivate the need for accumulating conflict sets while we walk the tree-dbBJ2 :: ExampleDb-dbBJ2 = [-    Right $ exAv "A"  1 [ExFix "B" 1]-  , Right $ exAv "A"  2 [ExFix "B" 2]-  , Right $ exAv "B"  1 [ExFix "C" 1]-  , Right $ exAv "B"  2 [ExFix "C" 2]-  , Right $ exAv "C"  1 []-  ]---- | Motivate the need for `QGoalReason`-dbBJ3 :: ExampleDb-dbBJ3 = [-    Right $ exAv "A"  1 [ExAny "Ba"]-  , Right $ exAv "A"  2 [ExAny "Bb"]-  , Right $ exAv "Ba" 1 [ExFix "C" 1]-  , Right $ exAv "Bb" 1 [ExFix "C" 2]-  , Right $ exAv "C"  1 []-  ]---- | `QGOalReason` not unique-dbBJ4 :: ExampleDb-dbBJ4 = [-    Right $ exAv "A" 1 [ExAny "B", ExAny "C"]-  , Right $ exAv "B" 1 [ExAny "C"]-  , Right $ exAv "C" 1 []-  ]---- | Flags are represented somewhat strangely in the tree------ This example probably won't be in the blog post itself but as a separate--- bug report (#3409)-dbBJ5 :: ExampleDb-dbBJ5 = [-    Right $ exAv "A" 1 [exFlagged "flagA" [ExFix "B" 1] [ExFix "C" 1]]-  , Right $ exAv "B" 1 [ExFix "D" 1]-  , Right $ exAv "C" 1 [ExFix "D" 2]-  , Right $ exAv "D" 1 []-  ]---- | Conflict sets for cycles-dbBJ6 :: ExampleDb-dbBJ6 = [-    Right $ exAv "A" 1 [ExAny "B"]-  , Right $ exAv "B" 1 []-  , Right $ exAv "B" 2 [ExAny "C"]-  , Right $ exAv "C" 1 [ExAny "A"]-  ]---- | Conflicts not unique-dbBJ7 :: ExampleDb-dbBJ7 = [-    Right $ exAv "A" 1 [ExAny "B", ExFix "C" 1]-  , Right $ exAv "B" 1 [ExFix "C" 1]-  , Right $ exAv "C" 1 []-  , Right $ exAv "C" 2 []-  ]---- | Conflict sets for SIR (C shared subgoal of independent goals A, B)-dbBJ8 :: ExampleDb-dbBJ8 = [-    Right $ exAv "A" 1 [ExAny "C"]-  , Right $ exAv "B" 1 [ExAny "C"]-  , Right $ exAv "C" 1 []-  ]--{--------------------------------------------------------------------------------  Databases for build-tool-depends--------------------------------------------------------------------------------}---- | Multiple packages depending on exes from 'bt-pkg'.-dbBuildTools :: ExampleDb-dbBuildTools = [-    Right $ exAv "A" 1 [ExBuildToolAny "bt-pkg" "exe1"]-  , Right $ exAv "B" 1 [exFlagged "flagB" [ExAny "unknown"]-                                          [ExBuildToolAny "bt-pkg" "exe1"]]-  , Right $ exAv "C" 1 [] `withTest` ExTest "testC" [ExBuildToolAny "bt-pkg" "exe1"]-  , Right $ exAv "D" 1 [ExBuildToolAny "bt-pkg" "unknown-exe"]-  , Right $ exAv "E" 1 [ExBuildToolAny "unknown-pkg" "exe1"]-  , Right $ exAv "F" 1 [exFlagged "flagF" [ExBuildToolAny "bt-pkg" "unknown-exe"]-                                          [ExAny "unknown"]]-  , Right $ exAv "G" 1 [] `withTest` ExTest "testG" [ExBuildToolAny "bt-pkg" "unknown-exe"]-  , Right $ exAv "H" 1 [ExBuildToolFix "bt-pkg" "exe1" 3]--  , Right $ exAv "bt-pkg" 4 []-  , Right $ exAv "bt-pkg" 3 [] `withExe` ExExe "exe2" []-  , Right $ exAv "bt-pkg" 2 [] `withExe` ExExe "exe1" []-  , Right $ exAv "bt-pkg" 1 []-  ]---- The solver should never choose an installed package for a build tool--- dependency.-rejectInstalledBuildToolPackage :: String -> SolverTest-rejectInstalledBuildToolPackage name =-    mkTest db name ["A"] $ solverFailure $ isInfixOf $-    "rejecting: A:B:exe.B-1.0.0/installed-1 "-     ++ "(does not contain executable exe, which is required by A)"-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [ExBuildToolAny "B" "exe"]-      , Left $ exInst "B" 1 "B-1" []-      ]---- | This test forces the solver to choose B as a build-tool dependency before--- it sees the dependency on executable exe2 from B. The solver needs to check--- that the version that it already chose for B contains the necessary--- executable. This order causes a different "missing executable" error message--- than when the solver checks for the executable in the same step that it--- chooses the build-tool package.------ This case may become impossible if we ever add the executable name to the--- build-tool goal qualifier. Then this test would involve two qualified goals--- for B, one for exe1 and another for exe2.-chooseExeAfterBuildToolsPackage :: Bool -> String -> SolverTest-chooseExeAfterBuildToolsPackage shouldSucceed name =-    goalOrder goals $ mkTest db name ["A"] $-      if shouldSucceed-      then solverSuccess [("A", 1), ("B", 1)]-      else solverFailure $ isInfixOf $-           "rejecting: A:+flagA (requires executable exe2 from A:B:exe.B, "-            ++ "but the executable does not exist)"-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [ ExBuildToolAny "B" "exe1"-                           , exFlagged "flagA" [ExBuildToolAny "B" "exe2"]-                                               [ExAny "unknown"]]-      , Right $ exAv "B" 1 []-         `withExes`-           [ExExe exe [] | exe <- if shouldSucceed then ["exe1", "exe2"] else ["exe1"]]-      ]--    goals :: [ExampleVar]-    goals = [-        P QualNone "A"-      , P (QualExe "A" "B") "B"-      , F QualNone "A" "flagA"-      ]---- | Test that when one package depends on two executables from another package,--- both executables must come from the same instance of that package. We could--- lift this restriction in the future by adding the executable name to the goal--- qualifier.-requireConsistentBuildToolVersions :: String -> SolverTest-requireConsistentBuildToolVersions name =-    mkTest db name ["A"] $ solverFailure $ isInfixOf $-        "[__1] rejecting: A:B:exe.B-2.0.0 (conflict: A => A:B:exe.B (exe exe1)==1.0.0)\n"-     ++ "[__1] rejecting: A:B:exe.B-1.0.0 (conflict: A => A:B:exe.B (exe exe2)==2.0.0)"-  where-    db :: ExampleDb-    db = [-        Right $ exAv "A" 1 [ ExBuildToolFix "B" "exe1" 1-                           , ExBuildToolFix "B" "exe2" 2 ]-      , Right $ exAv "B" 2 [] `withExes` exes-      , Right $ exAv "B" 1 [] `withExes` exes-      ]--    exes = [ExExe "exe1" [], ExExe "exe2" []]--{--------------------------------------------------------------------------------  Databases for legacy build-tools--------------------------------------------------------------------------------}-dbLegacyBuildTools1 :: ExampleDb-dbLegacyBuildTools1 = [-    Right $ exAv "alex" 1 [] `withExe` ExExe "alex" [],-    Right $ exAv "A" 1 [ExLegacyBuildToolAny "alex"]-  ]---- Test that a recognized build tool dependency specifies the name of both the--- package and the executable. This db has no solution.-dbLegacyBuildTools2 :: ExampleDb-dbLegacyBuildTools2 = [-    Right $ exAv "alex" 1 [] `withExe` ExExe "other-exe" [],-    Right $ exAv "other-package" 1 [] `withExe` ExExe "alex" [],-    Right $ exAv "A" 1 [ExLegacyBuildToolAny "alex"]-  ]---- Test that build-tools on a random thing doesn't matter (only--- the ones we recognize need to be in db)-dbLegacyBuildTools3 :: ExampleDb-dbLegacyBuildTools3 = [-    Right $ exAv "A" 1 [ExLegacyBuildToolAny "otherdude"]-  ]---- Test that we can solve for different versions of executables-dbLegacyBuildTools4 :: ExampleDb-dbLegacyBuildTools4 = [-    Right $ exAv "alex" 1 [] `withExe` ExExe "alex" [],-    Right $ exAv "alex" 2 [] `withExe` ExExe "alex" [],-    Right $ exAv "A" 1 [ExLegacyBuildToolFix "alex" 1],-    Right $ exAv "B" 1 [ExLegacyBuildToolFix "alex" 2],-    Right $ exAv "C" 1 [ExAny "A", ExAny "B"]-  ]---- Test that exe is not related to library choices-dbLegacyBuildTools5 :: ExampleDb-dbLegacyBuildTools5 = [-    Right $ exAv "alex" 1 [ExFix "A" 1] `withExe` ExExe "alex" [],-    Right $ exAv "A" 1 [],-    Right $ exAv "A" 2 [],-    Right $ exAv "B" 1 [ExLegacyBuildToolFix "alex" 1, ExFix "A" 2]-  ]---- Test that build-tools on build-tools works-dbLegacyBuildTools6 :: ExampleDb-dbLegacyBuildTools6 = [-    Right $ exAv "alex" 1 [] `withExe` ExExe "alex" [],-    Right $ exAv "happy" 1 [ExLegacyBuildToolAny "alex"] `withExe` ExExe "happy" [],-    Right $ exAv "A" 1 [ExLegacyBuildToolAny "happy"]-  ]---- Test that build-depends on library/executable package works.--- Extracted from https://github.com/haskell/cabal/issues/3775-dbIssue3775 :: ExampleDb-dbIssue3775 = [-    Right $ exAv "warp" 1 [],-    -- NB: the warp build-depends refers to the package, not the internal-    -- executable!-    Right $ exAv "A" 2 [ExFix "warp" 1] `withExe` ExExe "warp" [ExAny "A"],-    Right $ exAv "B" 2 [ExAny "A", ExAny "warp"]-  ]
− tests/UnitTests/Distribution/Solver/Modular/WeightedPSQ.hs
@@ -1,54 +0,0 @@-{-# LANGUAGE ParallelListComp #-}-module UnitTests.Distribution.Solver.Modular.WeightedPSQ (-  tests-  ) where--import qualified Distribution.Solver.Modular.WeightedPSQ as W--import Data.List (sort)--import Test.Tasty (TestTree)-import Test.Tasty.HUnit (testCase, (@?=))-import Test.Tasty.QuickCheck (Blind(..), testProperty)--tests :: [TestTree]-tests = [-    testProperty "'toList . fromList' preserves elements" $ \xs ->-        sort (xs :: [(Int, Char, Bool)]) == sort (W.toList (W.fromList xs))--  , testProperty "'toList . fromList' sorts stably" $ \xs ->-        let indexAsValue :: [(Int, (), Int)]-            indexAsValue = [(x, (), i) | x <- xs | i <- [0..]]-        in isSorted $ W.toList $ W.fromList indexAsValue--  , testProperty "'mapWeightsWithKey' sorts by weight" $ \xs (Blind f) ->-        isSorted $ W.weights $-        W.mapWeightsWithKey (f :: Int -> Int -> Int) $-        W.fromList (xs :: [(Int, Int, Int)])--  , testCase "applying 'mapWeightsWithKey' twice sorts twice" $-        let indexAsKey :: [((), Int, ())]-            indexAsKey = [((), i, ()) | i <- [0..10]]-            actual = W.toList $-                     W.mapWeightsWithKey (\_ _ -> ()) $-                     W.mapWeightsWithKey (\i _ -> -i) $ -- should not be ignored-                     W.fromList indexAsKey-        in reverse indexAsKey @?= actual--  , testProperty "'union' sorts by weight" $ \xs ys ->-        isSorted $ W.weights $-        W.union (W.fromList xs) (W.fromList (ys :: [(Int, Int, Int)]))--  , testProperty "'union' preserves elements" $ \xs ys ->-        let union = W.union (W.fromList xs)-                            (W.fromList (ys :: [(Int, Int, Int)]))-        in sort (xs ++ ys) == sort (W.toList union)--  , testCase "'lookup' returns first occurrence" $-        let xs = W.fromList [((), False, 'A'), ((), True, 'C'), ((), True, 'B')]-        in Just 'C' @?= W.lookup True xs-  ]--isSorted :: Ord a => [a] -> Bool-isSorted (x1 : xs@(x2 : _)) = x1 <= x2 && isSorted xs-isSorted _ = True
− tests/UnitTests/Options.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}--module UnitTests.Options ( OptionShowSolverLog(..)-                         , OptionMtimeChangeDelay(..)-                         , extraOptions )-       where--import Data.Proxy-import Data.Typeable--import Test.Tasty.Options--{--------------------------------------------------------------------------------  Test options--------------------------------------------------------------------------------}--extraOptions :: [OptionDescription]-extraOptions =-  [ Option (Proxy :: Proxy OptionShowSolverLog)-  , Option (Proxy :: Proxy OptionMtimeChangeDelay)-  ]--newtype OptionShowSolverLog = OptionShowSolverLog Bool-  deriving Typeable--instance IsOption OptionShowSolverLog where-  defaultValue   = OptionShowSolverLog False-  parseValue     = fmap OptionShowSolverLog . safeRead-  optionName     = return "show-solver-log"-  optionHelp     = return "Show full log from the solver"-  optionCLParser = flagCLParser Nothing (OptionShowSolverLog True)--newtype OptionMtimeChangeDelay = OptionMtimeChangeDelay Int-  deriving Typeable--instance IsOption OptionMtimeChangeDelay where-  defaultValue   = OptionMtimeChangeDelay 0-  parseValue     = fmap OptionMtimeChangeDelay . safeRead-  optionName     = return "mtime-change-delay"-  optionHelp     = return $ "How long to wait before attempting to detect"-                   ++ "file modification, in microseconds"