diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 4dbc94def32..5a30dfed233 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -49,7 +49,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] - ghc: ["9.6.3", "9.4.7", "9.2.8", "9.0.2", "8.10.7", "8.8.4", "8.6.5", "8.4.4"] + ghc: ["9.8.1", "9.6.3", "9.4.8", "9.2.8", "9.0.2", "8.10.7", "8.8.4", "8.6.5", "8.4.4"] exclude: # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356 - os: "windows-latest" @@ -83,7 +83,7 @@ jobs: id: setup-haskell with: ghc-version: ${{ matrix.ghc }} - cabal-version: '3.10.1.0' + cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133 - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546) run: | @@ -117,11 +117,6 @@ jobs: fi echo "FLAGS=$FLAGS" >> $GITHUB_ENV - - name: Allow newer dependencies when built with latest GHC - if: ${{ matrix.ghc }} == '9.6.3' - run: | - echo "allow-newer: rere:base, rere:transformers" >> cabal.project.validate - - name: Validate print-config run: sh validate.sh $FLAGS -s print-config diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs index caf3e16d038..efe8151b705 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs @@ -25,7 +25,12 @@ tests = testGroup "Distribution.Utils.Structured" , testCase "SPDX.License" $ md5Check (Proxy :: Proxy License) 0xd3d4a09f517f9f75bc3d16370d5a853a -- The difference is in encoding of newtypes -#if MIN_VERSION_base(4,7,0) +#if MIN_VERSION_base(4,19,0) + , testCase "GenericPackageDescription" $ + md5Check (Proxy :: Proxy GenericPackageDescription) 0xf5fdb32b43aca790192f44d9ecaa9689 + , testCase "LocalBuildInfo" $ + md5Check (Proxy :: Proxy LocalBuildInfo) 0x205fbe2649bc5e488bce50c07a71cadb +#elif MIN_VERSION_base(4,7,0) , testCase "GenericPackageDescription" $ md5Check (Proxy :: Proxy GenericPackageDescription) 0xb287a6f04e34ef990cdd15bc6cb01c76 , testCase "LocalBuildInfo" $ diff --git a/Cabal/src/Distribution/Simple/GHC.hs b/Cabal/src/Distribution/Simple/GHC.hs index 92378380325..65aa733684f 100644 --- a/Cabal/src/Distribution/Simple/GHC.hs +++ b/Cabal/src/Distribution/Simple/GHC.hs @@ -161,14 +161,14 @@ configure verbosity hcPath hcPkgPath conf0 = do (userMaybeSpecifyPath "ghc" hcPath conf0) let implInfo = ghcVersionImplInfo ghcVersion - -- Cabal currently supports ghc >= 7.0.1 && < 9.8 + -- Cabal currently supports ghc >= 7.0.1 && < 9.10 -- ... and the following odd development version - unless (ghcVersion < mkVersion [9, 8]) $ + unless (ghcVersion < mkVersion [9, 10]) $ warn verbosity $ "Unknown/unsupported 'ghc' version detected " ++ "(Cabal " ++ prettyShow cabalVersion - ++ " supports 'ghc' version < 9.8): " + ++ " supports 'ghc' version < 9.10): " ++ programPath ghcProg ++ " is version " ++ prettyShow ghcVersion diff --git a/cabal-dev-scripts/cabal-dev-scripts.cabal b/cabal-dev-scripts/cabal-dev-scripts.cabal index 24e160eaa92..345d052d62e 100644 --- a/cabal-dev-scripts/cabal-dev-scripts.cabal +++ b/cabal-dev-scripts/cabal-dev-scripts.cabal @@ -18,7 +18,7 @@ executable gen-spdx ghc-options: -Wall build-depends: , aeson ^>=1.4.1.0 || ^>=1.5.2.0 || ^>=2.1.1.0 - , base >=4.10 && <4.19 + , base >=4.10 && <4.20 , bytestring , containers , Diff ^>=0.4 @@ -35,7 +35,7 @@ executable gen-spdx-exc ghc-options: -Wall build-depends: , aeson ^>=1.4.1.0 || ^>=1.5.2.0 || ^>=2.1.1.0 - , base >=4.10 && <4.19 + , base >=4.10 && <4.20 , bytestring , containers , Diff ^>=0.4 diff --git a/cabal-install/src/Distribution/Client/Dependency.hs b/cabal-install/src/Distribution/Client/Dependency.hs index 544ad59a341..37e0cbdf1ee 100644 --- a/cabal-install/src/Distribution/Client/Dependency.hs +++ b/cabal-install/src/Distribution/Client/Dependency.hs @@ -67,7 +67,6 @@ module Distribution.Client.Dependency ) where import Distribution.Client.Compat.Prelude -import qualified Prelude as Unsafe (head) import Distribution.Client.Dependency.Types ( PackagesPreferenceDefault (..) @@ -950,8 +949,11 @@ planPackagesProblems platform cinfo pkgs = , let packageProblems = configuredPackageProblems platform cinfo pkg , not (null packageProblems) ] - ++ [ DuplicatePackageSolverId (Graph.nodeKey (Unsafe.head dups)) dups + ++ [ DuplicatePackageSolverId (Graph.nodeKey aDup) dups | dups <- duplicatesBy (comparing Graph.nodeKey) pkgs + , aDup <- case dups of + [] -> [] + (ad : _) -> [ad] ] data PackageProblem diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs index 8c37cad96f2..7eee9f82f7a 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs @@ -40,7 +40,7 @@ import Distribution.Client.Init.Types import Distribution.Client.Compat.Prelude hiding (getLine, head, last, putStr, putStrLn) import Prelude () -import Data.List (head, last) +import Data.List (last) import qualified Data.List.NonEmpty as NEL import Distribution.CabalSpecVersion (CabalSpecVersion (..)) @@ -340,12 +340,18 @@ packageTypeHeuristics flags = getPackageType flags $ guessPackageType flags -- to a default value. mainFileHeuristics :: Interactive m => InitFlags -> m HsFilePath mainFileHeuristics flags = do - appDir <- head <$> appDirsHeuristics flags + appDirs <- appDirsHeuristics flags + let appDir = case appDirs of + [] -> error "impossible: appDirsHeuristics returned empty list of dirs" + (appDir' : _) -> appDir' getMainFile flags . guessMainFile $ appDir testMainHeuristics :: Interactive m => InitFlags -> m HsFilePath testMainHeuristics flags = do - testDir <- head <$> testDirsHeuristics flags + testDirs' <- testDirsHeuristics flags + let testDir = case testDirs' of + [] -> error "impossible: testDirsHeuristics returned empty list of dirs" + (testDir' : _) -> testDir' guessMainFile testDir initializeTestSuiteHeuristics :: Interactive m => InitFlags -> m Bool diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index 0fe0129d2c3..138f9684553 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -54,9 +54,9 @@ guessMainFile pkgDir = do then do files <- filter isMain <$> listFilesRecursive pkgDir return $ - if null files - then defaultMainIs - else toHsFilePath $ L.head files + case files of + [] -> defaultMainIs + (f : _) -> toHsFilePath f else return defaultMainIs -- | Juggling characters around to guess the desired cabal version based on diff --git a/cabal-install/src/Distribution/Client/InstallPlan.hs b/cabal-install/src/Distribution/Client/InstallPlan.hs index 1a8042d6bad..46212baaccc 100644 --- a/cabal-install/src/Distribution/Client/InstallPlan.hs +++ b/cabal-install/src/Distribution/Client/InstallPlan.hs @@ -72,9 +72,9 @@ module Distribution.Client.InstallPlan , reverseDependencyClosure ) where -import Distribution.Client.Compat.Prelude hiding (lookup, tail, toList) +import Distribution.Client.Compat.Prelude hiding (lookup, toList) import Distribution.Compat.Stack (WithCallStack) -import Prelude (tail) +import Prelude () import Distribution.Client.Types hiding (BuildOutcomes) import qualified Distribution.PackageDescription as PD @@ -757,13 +757,13 @@ failed -> ([srcpkg], Processing) failed plan (Processing processingSet completedSet failedSet) pkgid = assert (pkgid `Set.member` processingSet) $ - assert (all (`Set.notMember` processingSet) (tail newlyFailedIds)) $ - assert (all (`Set.notMember` completedSet) (tail newlyFailedIds)) $ + assert (all (`Set.notMember` processingSet) (drop 1 newlyFailedIds)) $ + assert (all (`Set.notMember` completedSet) (drop 1 newlyFailedIds)) $ -- but note that some newlyFailed may already be in the failed set -- since one package can depend on two packages that both fail and -- so would be in the rev-dep closure for both. assert (processingInvariant plan processing') $ - ( map asConfiguredPackage (tail newlyFailed) + ( map asConfiguredPackage (drop 1 newlyFailed) , processing' ) where diff --git a/cabal-install/src/Distribution/Client/Upload.hs b/cabal-install/src/Distribution/Client/Upload.hs index c7abe8b91e4..6e96fa0eafd 100644 --- a/cabal-install/src/Distribution/Client/Upload.hs +++ b/cabal-install/src/Distribution/Client/Upload.hs @@ -1,7 +1,7 @@ module Distribution.Client.Upload (upload, uploadDoc, report) where import Distribution.Client.Compat.Prelude -import qualified Prelude as Unsafe (head, read, tail) +import qualified Prelude as Unsafe (read) import Distribution.Client.HttpUtils ( HttpTransport (..) @@ -155,11 +155,13 @@ uploadDoc verbosity repoCtxt mToken mUsername mPassword isCandidate path = do break (== '-') (reverse (takeFileName path)) - pkgid = reverse $ Unsafe.tail reversePkgid + pkgid = reverse $ drop 1 reversePkgid when ( reverse reverseSuffix /= "docs.tar.gz" - || null reversePkgid - || Unsafe.head reversePkgid /= '-' + || ( case reversePkgid of + [] -> True + (c : _) -> c /= '-' + ) ) $ dieWithException verbosity ExpectedMatchingFileName diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs index bf6e25c5b87..55ea3747b9f 100644 --- a/cabal-install/tests/IntegrationTests2.hs +++ b/cabal-install/tests/IntegrationTests2.hs @@ -80,7 +80,6 @@ import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.Options import Data.Tagged (Tagged(..)) -import qualified Data.List as L import qualified Data.ByteString as BS import Distribution.Client.GlobalFlags (GlobalFlags, globalNix) @@ -2180,9 +2179,10 @@ testConfigOptionComments = do where -- | Find lines containing a target string. findLineWith :: Bool -> String -> String -> String - findLineWith isComment target text - | not . null $ findLinesWith isComment target text = removeCommentValue . L.head $ findLinesWith isComment target text - | otherwise = text + findLineWith isComment target text = + case findLinesWith isComment target text of + [] -> text + (l : _) -> removeCommentValue l findLinesWith :: Bool -> String -> String -> [String] findLinesWith isComment target | isComment = filter (isInfixOf (" " ++ target ++ ":")) . lines diff --git a/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs b/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs index 39f508040c3..0663360df42 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE CPP #-} + module UnitTests.Distribution.Client.FileMonitor (tests) where import Distribution.Parsec (simpleParsec) @@ -31,8 +33,8 @@ tests mtimeChange = [ testGroup "Structured hashes" [ testCase "MonitorStateFile" $ structureHash (Proxy :: Proxy MonitorStateFile) @?= Fingerprint 0xe4108804c34962f6 0x06e94f8fc9e48e13 - , testCase "MonitorStateGlob" $ structureHash (Proxy :: Proxy MonitorStateGlob) @?= Fingerprint 0xfd8f6be0e8258fe7 0xdb5fac737139bca6 - , testCase "MonitorStateFileSet" $ structureHash (Proxy :: Proxy MonitorStateFileSet) @?= Fingerprint 0xb745f4ea498389a5 0x70db6adb5078aa27 + , testCase "MonitorStateGlob" $ structureHash (Proxy :: Proxy MonitorStateGlob) @?= Fingerprint fingerprintStateGlob1 fingerprintStateGlob2 + , testCase "MonitorStateFileSet" $ structureHash (Proxy :: Proxy MonitorStateFileSet) @?= Fingerprint fingerprintStateFileSet1 fingerprintStateFileSet2 ] , testCase "sanity check mtimes" $ testFileMTimeSanity mtimeChange , testCase "sanity check dirs" $ testDirChangeSanity mtimeChange @@ -85,6 +87,18 @@ tests mtimeChange = knownBrokenInWindows msg = case buildOS of Windows -> expectFailBecause msg _ -> id + fingerprintStateGlob1, fingerprintStateGlob2, fingerprintStateFileSet1, fingerprintStateFileSet2 :: Word64 +#if MIN_VERSION_base(4,19,0) + fingerprintStateGlob1 = 0xae70229aabb1ba1f + fingerprintStateGlob2 = 0xb53ed324c96f0d0d + fingerprintStateFileSet1 = 0x8e509e16f973e036 + fingerprintStateFileSet2 = 0xa23f21d8dc8a2dee +#else + fingerprintStateGlob1 = 0xfd8f6be0e8258fe7 + fingerprintStateGlob2 = 0xdb5fac737139bca6 + fingerprintStateFileSet1 = 0xb745f4ea498389a5 + fingerprintStateFileSet2 = 0x70db6adb5078aa27 +#endif -- Check the file system behaves the way we expect it to diff --git a/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs b/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs index b708ea80302..39c719f2e1f 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs @@ -5,7 +5,6 @@ module UnitTests.Distribution.Client.InstallPlan (tests) where import Distribution.Client.Compat.Prelude -import qualified Prelude as Unsafe (tail) import Distribution.Client.InstallPlan (GenericInstallPlan, IsUnit) import qualified Distribution.Client.InstallPlan as InstallPlan @@ -285,7 +284,7 @@ arbitraryAcyclicGraph genNRanks genNPerRank edgeChance = do nranks <- genNRanks rankSizes <- replicateM nranks genNPerRank let rankStarts = scanl (+) 0 rankSizes - rankRanges = drop 1 (zip rankStarts (Unsafe.tail rankStarts)) + rankRanges = drop 1 (zip rankStarts (drop 1 rankStarts)) totalRange = sum rankSizes rankEdges <- traverse (uncurry genRank) rankRanges return $ buildG (0, totalRange - 1) (concat rankEdges) diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs b/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs index 060dbdffe4f..ac6d96cc159 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs @@ -43,7 +43,10 @@ tests = "readUserConstraints" (uncurry readUserConstraintsTest) [ -- First example only. - (head exampleStrs, take 1 exampleUcs) + + ( case exampleStrs of (e : _) -> e; _ -> error "empty examples" + , take 1 exampleUcs + ) , -- All examples separated by commas. (intercalate ", " exampleStrs, exampleUcs) ] diff --git a/cabal-testsuite/src/Test/Cabal/Prelude.hs b/cabal-testsuite/src/Test/Cabal/Prelude.hs index e89481f13d3..2c54deaa2a2 100644 --- a/cabal-testsuite/src/Test/Cabal/Prelude.hs +++ b/cabal-testsuite/src/Test/Cabal/Prelude.hs @@ -1163,7 +1163,7 @@ findDependencyInStore :: FilePath -- ^store dir -> String -- ^package name prefix -> IO FilePath -- ^package dir findDependencyInStore storeDir pkgName = do - storeDirForGhcVersion <- head <$> listDirectory storeDir + (storeDirForGhcVersion : _) <- listDirectory storeDir packageDirs <- listDirectory (storeDir storeDirForGhcVersion) -- Ideally, we should call 'hashedInstalledPackageId' from 'Distribution.Client.PackageHash'. -- But 'PackageHashInputs', especially 'PackageHashConfigInputs', is too hard to construct. diff --git a/cabal.project b/cabal.project index d0b2fbabc1f..d506fe9b117 100644 --- a/cabal.project +++ b/cabal.project @@ -1,3 +1,5 @@ +import: cabal.project.latest-ghc + packages: Cabal/ packages: cabal-testsuite/ packages: Cabal-syntax/ diff --git a/cabal.project.latest-ghc b/cabal.project.latest-ghc new file mode 100644 index 00000000000..5132415b48c --- /dev/null +++ b/cabal.project.latest-ghc @@ -0,0 +1,12 @@ +-- Usually, the latest GHC requires a few allow-newer's +-- for some time after the release. This project file is meant to host these. +-- The file is supposed to be included in the main project files used for +-- Cabal development: +-- - cabal.project (day-to-day development), +-- - cabal.project.validate (Cabal CI), +-- Commented out below are the usual suspects. Feel free to add more. + +-- NOTE: don't forget to update the compiler version in the conditional +-- when upgrading to a newer GHC +if impl(ghc >= 9.8.1) + -- allow-newer: windns:* diff --git a/cabal.project.validate b/cabal.project.validate index 66e823f62b1..d3583c31b0e 100644 --- a/cabal.project.validate +++ b/cabal.project.validate @@ -1,3 +1,5 @@ +import: cabal.project.latest-ghc + packages: Cabal-syntax/ packages: Cabal/ packages: cabal-testsuite/