From c2cbecb52a20675f89a4b902b3051351dc7d0d03 Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Sun, 27 Mar 2022 21:18:23 +0200 Subject: [PATCH 1/5] Minimal migration to Cabal-3.6.3.0 This patch makes the minimal changes to compile with Cabal-3.6.3.0. Cabal-3.6 intends a semantics of the caret operator ^>= that is more subtle than expanding it into its version interval. We do not pick up this intention in this patch, but fall back to Distribution.Types.VersionInterval.Legacy See https://github.com/haskell/cabal/issues/7916 for a in-depth discussion. --- hackage-server.cabal | 2 +- src/Distribution/Server/Packages/Render.hs | 14 ++++++++++++-- src/Distribution/Server/Util/ParseSpecVer.hs | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hackage-server.cabal b/hackage-server.cabal index 8da1867b6..baf87c34e 100644 --- a/hackage-server.cabal +++ b/hackage-server.cabal @@ -113,7 +113,7 @@ common defaults -- other dependencies shared by most components build-depends: , aeson ^>= 2.0.3.0 - , Cabal ^>= 3.4.1.0 + , Cabal ^>= 3.6.3.0 , fail ^>= 4.9.0 -- we use Control.Monad.Except, introduced in mtl-2.2.1 , network >= 3 && < 3.2 diff --git a/src/Distribution/Server/Packages/Render.hs b/src/Distribution/Server/Packages/Render.hs index b4964da7e..34241afda 100644 --- a/src/Distribution/Server/Packages/Render.hs +++ b/src/Distribution/Server/Packages/Render.hs @@ -31,7 +31,15 @@ import Distribution.PackageDescription.Configuration import Distribution.Package import Distribution.Text import Distribution.Pretty (prettyShow) -import Distribution.Version +import Distribution.Version (noVersion) +import Distribution.Types.VersionInterval.Legacy + -- Andreas Abel, 2022-03-27: + -- Note that this "Legacy" module is both new and deprecated in Cabal-3.6. + -- However, the non-deprecated module "Distribution.Types.VersionInterval" + -- does not define the functions anymore we rely on here, namely + -- @{union,intersect}VersionIntervals@. + -- I criticized this unfortunate development at length at: + -- https://github.com/haskell/cabal/issues/7916 import Distribution.ModuleName as ModuleName import Distribution.Types.ModuleReexport @@ -41,7 +49,9 @@ import Distribution.Server.Packages.Types import Distribution.Server.Packages.ModuleForest import qualified Distribution.Server.Users.Users as Users import Distribution.Server.Users.Types +import Distribution.Utils.Path (getSymbolicPath) import Distribution.Utils.ShortText (fromShortText) + import qualified Data.TarIndex as TarIndex import Data.TarIndex (TarIndex, TarEntryOffset) @@ -95,7 +105,7 @@ doPackageRender users info = PackageRender , rendSublibraryDeps = (unUnqualComponentName *** depTree libBuildInfo) `map` condSubLibraries genDesc , rendLicenseName = prettyShow (license desc) -- maybe make this a bit more human-readable - , rendLicenseFiles = licenseFiles desc + , rendLicenseFiles = map getSymbolicPath $ licenseFiles desc , rendMaintainer = case fromShortText $ maintainer desc of "None" -> Nothing "none" -> Nothing diff --git a/src/Distribution/Server/Util/ParseSpecVer.hs b/src/Distribution/Server/Util/ParseSpecVer.hs index ba622810f..bf6ca9f4e 100644 --- a/src/Distribution/Server/Util/ParseSpecVer.hs +++ b/src/Distribution/Server/Util/ParseSpecVer.hs @@ -239,8 +239,8 @@ decodeVerFallback v0 = simpleParse v <|> parseSpecVR parseSpecVR = do vr <- simpleParse v case asVersionIntervals vr of - [] -> Just $ mkVersion [0] - ((LowerBound version _, _):_) -> Just $ version + VersionInterval (LowerBound version _) _ : _ -> Just version + [] -> Just $ mkVersion [0] v = BC8.unpack v0 From 709533313810cb6c4503acd412e9adca981c1161 Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Mon, 28 Mar 2022 11:36:40 +0200 Subject: [PATCH 2/5] Build with GHC 9.2 --- .github/workflows/ci.yml | 2 ++ hackage-server.cabal | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 105ce8db8..a6a0d2285 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,8 @@ jobs: fail-fast: false matrix: versions: + - ghc: '9.2.2' + cabal: '3.6' - ghc: '9.0.2' cabal: '3.6' - ghc: '8.10.7' diff --git a/hackage-server.cabal b/hackage-server.cabal index baf87c34e..0b72ac5db 100644 --- a/hackage-server.cabal +++ b/hackage-server.cabal @@ -27,7 +27,7 @@ copyright: 2008-2015 Duncan Coutts, license: BSD-3-Clause license-file: LICENSE -tested-with: GHC == { 8.10.7, 8.8.4 } +tested-with: GHC == { 9.2.2, 9.0.2, 8.10.7, 8.8.4 } data-dir: datafiles data-files: @@ -95,9 +95,9 @@ common defaults -- see `cabal.project.local-ghc-${VERSION}` files build-depends: , array >= 0.5 && < 0.6 - , base >= 4.13 && < 4.16 + , base >= 4.13 && < 4.17 , binary >= 0.8 && < 0.9 - , bytestring >= 0.10 && < 0.11 + , bytestring >= 0.10 && < 0.12 , containers ^>= 0.6.0 , deepseq >= 1.4 && < 1.5 , directory >= 1.3 && < 1.4 @@ -105,8 +105,8 @@ common defaults , mtl ^>= 2.2.1 , pretty >= 1.1 && < 1.2 , process >= 1.6 && < 1.7 - , text ^>= 1.2.2 - , time >= 1.9 && < 1.12 + , text ^>= 1.2.5.0 + , time >= 1.9 && < 1.13 , transformers >= 0.5 && < 0.6 , unix >= 2.7 && < 2.8 , scientific @@ -356,7 +356,7 @@ library lib-server -- NB: see also build-depends in `common defaults`! build-depends: , HStringTemplate ^>= 0.8 - , HTTP ^>= 4000.3.6 + , HTTP ^>= 4000.3.16 , QuickCheck ^>= 2.14 , acid-state ^>= 0.16 , async ^>= 2.2.1 @@ -364,7 +364,7 @@ library lib-server , attoparsec ^>= 0.14.4 , base16-bytestring ^>= 1.0 -- requires bumping http-io-streams - , base64-bytestring ^>= 1.1 + , base64-bytestring ^>= 1.2.1.0 --NOTE: blaze-builder-0.4 is now a compat package that uses bytestring-0.10 builder , blaze-builder ^>= 0.4 , blaze-html ^>= 0.9 @@ -511,7 +511,7 @@ test-suite HighLevelTest -- component-specific dependencies , xml ^>= 1.3.14 , io-streams ^>= 1.5.0.1 - , http-io-streams ^>= 0.1.0.0 + , http-io-streams ^>= 0.1.6.1 test-suite CreateUserTest import: test-defaults From ac439ee5bf9860da8a4ca13a06d8577aa8273bf5 Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Mon, 28 Mar 2022 19:35:12 +0200 Subject: [PATCH 3/5] PackageTestMain: comments, cosmetical changes --- tests/PackageTestMain.hs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/tests/PackageTestMain.hs b/tests/PackageTestMain.hs index aa3bc120b..072c56c02 100644 --- a/tests/PackageTestMain.hs +++ b/tests/PackageTestMain.hs @@ -1,3 +1,5 @@ +-- | Test that Hackage accepts or refuses certain packages. + module Main ( main ) where @@ -22,7 +24,11 @@ main = defaultMain allTests allTests :: TestTree allTests = testGroup "PackageTests" [ testGroup "Tar file permissions" tarPermissions - , testGroup "Cabal package integrity tests" cabalPackageCheckTests] + , testGroup "Cabal package integrity tests" cabalPackageCheckTests + ] + +--------------------------------------------------------------------------- +-- * File permission tests tarPermissions :: [TestTree] tarPermissions = @@ -34,7 +40,8 @@ tarPermissions = (testPermissions "tests/permissions-tarballs/bad-file-perms.tar.gz" badFileMangler) , testCase "Bad Dir Permissions" - (testPermissions "tests/permissions-tarballs/bad-dir-perms.tar.gz" badDirMangler)] + (testPermissions "tests/permissions-tarballs/bad-dir-perms.tar.gz" badDirMangler) + ] goodMangler :: (Tar.Entry -> Maybe CombinedTarErrs) goodMangler = const Nothing @@ -51,6 +58,9 @@ badDirMangler entry = Tar.Directory -> Just $ PermissionsError (Tar.entryPath entry) 0o700 _ -> Nothing +--------------------------------------------------------------------------- +-- * Package integry tests + cabalPackageCheckTests :: [TestTree] cabalPackageCheckTests = [ testCase "Missing ./configure script" missingConfigureScriptTest @@ -58,30 +68,41 @@ cabalPackageCheckTests = , testCase "Bad spec-version" badSpecVer ] +--------------------------------------------------------------------------- +-- ** Tests that must fail + +-- | If @build-type: Configure@, then there must be a @./configure@ script. + missingConfigureScriptTest :: Assertion missingConfigureScriptTest = do tar <- tarGzFile "missing-configure-0.1.0.0" now <- getCurrentTime case unpackPackage now "missing-configure-0.1.0.0.tar.gz" tar of - Right _ -> HUnit.assertFailure "expected error" + Right _ -> HUnit.assertFailure "error: unexpected success" Left err -> HUnit.assertBool ("Error found, but not about missing ./configure: " ++ err) ("The 'build-type' is 'Configure'" `isInfixOf` err) +-- | The @cabal-version@ must be valid. + badSpecVer :: Assertion badSpecVer = do tar <- tarGzFile "bad-specver-package-0" now <- getCurrentTime case unpackPackage now "bad-specver-package-0.tar.gz" tar of - Right _ -> HUnit.assertFailure "expected error" + Right _ -> HUnit.assertFailure "error: unexpected success" Left err -> HUnit.assertBool ("Error found, but not about invalid spec version: " ++ err) ("cabal spec version" `isInfixOf` err) +--------------------------------------------------------------------------- +-- ** Tests that must succeed + -- | Some tar files in hackage are missing directory entries. -- Ensure that they can be verified even without the directory entries. + missingDirsInTarFileTest :: Assertion missingDirsInTarFileTest = do tar <- fmap keepOnlyFiles (tarGzFile "correct-package-0.1.0.0") @@ -89,7 +110,10 @@ missingDirsInTarFileTest = case unpackPackage now "correct-package-0.1.0.0.tar.gz" tar of Right _ -> return () Left err -> - HUnit.assertFailure ("Excpected success but got: " ++ show err) + HUnit.assertFailure ("Expected success but got: " ++ show err) + +--------------------------------------------------------------------------- +-- * Auxiliary functions tarGzFile :: String -> IO ByteString tarGzFile name = do From 4675d01fe32159d702061b04c2f3a15f7a6986db Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Mon, 28 Mar 2022 20:11:58 +0200 Subject: [PATCH 4/5] PackageTestMain: factor out successTest --- tests/PackageTestMain.hs | 44 ++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/tests/PackageTestMain.hs b/tests/PackageTestMain.hs index 072c56c02..b0666e8b5 100644 --- a/tests/PackageTestMain.hs +++ b/tests/PackageTestMain.hs @@ -16,7 +16,7 @@ import Distribution.Server.Packages.Unpack import Distribution.Server.Packages.UnpackTest import Test.Tasty (defaultMain, TestTree, testGroup) -import Test.Tasty.HUnit (testCase, Assertion) +import Test.Tasty.HUnit (testCase, Assertion, HasCallStack) main :: IO () main = defaultMain allTests @@ -105,15 +105,43 @@ badSpecVer = missingDirsInTarFileTest :: Assertion missingDirsInTarFileTest = - do tar <- fmap keepOnlyFiles (tarGzFile "correct-package-0.1.0.0") - now <- getCurrentTime - case unpackPackage now "correct-package-0.1.0.0.tar.gz" tar of - Right _ -> return () - Left err -> - HUnit.assertFailure ("Expected success but got: " ++ show err) + successTestTGZ pkg =<< do keepOnlyFiles <$> tarGzFile pkg + where + pkg = "correct-package-0.1.0.0" + +--------------------------------------------------------------------------- +-- * Auxiliary functions to construct tests + +-- | A generic successful test, given a directory with the package contents. +-- +-- Note: the 'HasCallStack' constraint ensures that the assertion failure +-- is thrown at the invocation site of this function. +-- +successTest + :: HasCallStack + => String -- ^ The directory which is also the package name. + -> Assertion +successTest pkg = successTestTGZ pkg =<< tarGzFile pkg + +-- | A successful test, given the package name and its @.tgz@ stream. +-- +-- Note: the 'HasCallStack' constraint ensures that the assertion failure +-- is thrown at the invocation site of this function. +-- +successTestTGZ + :: HasCallStack + => String -- ^ The package name which is also the stem of the @.tgz@ file. + -> ByteString -- ^ The content of the @.tgz@ archive. + -> Assertion +successTestTGZ pkg tar = do + now <- getCurrentTime + case unpackPackage now (pkg ++ ".tar.gz") tar of + Right _ -> return () + Left err -> + HUnit.assertFailure $ "Expected success, but got: " ++ show err --------------------------------------------------------------------------- --- * Auxiliary functions +-- * Tar utilities tarGzFile :: String -> IO ByteString tarGzFile name = do From fa633f520b6f5616654729c60a9d76846f9d8767 Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Mon, 28 Mar 2022 20:29:56 +0200 Subject: [PATCH 5/5] Fix #1030: test case When building with Cabal-3.6.*, Hackage server will accept the latest GHC LANGUAGE extensions (new in GHC 9.2). --- tests/PackageTestMain.hs | 10 ++++++- .../LANGUAGE-GHC-9.2/LANGUAGE-GHC.cabal | 20 +++++++++++++ tests/unpack-checks/LANGUAGE-GHC-9.2/LICENSE | 30 +++++++++++++++++++ tests/unpack-checks/LANGUAGE-GHC-9.2/Main.hs | 4 +++ tests/unpack-checks/LANGUAGE-GHC-9.2/Setup.hs | 2 ++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/unpack-checks/LANGUAGE-GHC-9.2/LANGUAGE-GHC.cabal create mode 100644 tests/unpack-checks/LANGUAGE-GHC-9.2/LICENSE create mode 100644 tests/unpack-checks/LANGUAGE-GHC-9.2/Main.hs create mode 100644 tests/unpack-checks/LANGUAGE-GHC-9.2/Setup.hs diff --git a/tests/PackageTestMain.hs b/tests/PackageTestMain.hs index b0666e8b5..c8ac19080 100644 --- a/tests/PackageTestMain.hs +++ b/tests/PackageTestMain.hs @@ -63,9 +63,12 @@ badDirMangler entry = cabalPackageCheckTests :: [TestTree] cabalPackageCheckTests = + -- Failing tests [ testCase "Missing ./configure script" missingConfigureScriptTest - , testCase "Missing directories in tar file" missingDirsInTarFileTest , testCase "Bad spec-version" badSpecVer + -- Successful tests + , testCase "Missing directories in tar file" missingDirsInTarFileTest + , testCase "Accept GHC 9.2 LANGUAGE extensions" acceptGHC902LanguageExtensions ] --------------------------------------------------------------------------- @@ -109,6 +112,11 @@ missingDirsInTarFileTest = where pkg = "correct-package-0.1.0.0" +-- | Hackage should accept GHC 9.2 language extensions (issue #1030). + +acceptGHC902LanguageExtensions :: Assertion +acceptGHC902LanguageExtensions = successTest "LANGUAGE-GHC-9.2" + --------------------------------------------------------------------------- -- * Auxiliary functions to construct tests diff --git a/tests/unpack-checks/LANGUAGE-GHC-9.2/LANGUAGE-GHC.cabal b/tests/unpack-checks/LANGUAGE-GHC-9.2/LANGUAGE-GHC.cabal new file mode 100644 index 000000000..ffd904c9f --- /dev/null +++ b/tests/unpack-checks/LANGUAGE-GHC-9.2/LANGUAGE-GHC.cabal @@ -0,0 +1,20 @@ +name: LANGUAGE-GHC +version: 9.2 +synopsis: Test for LANGUAGE extensions (issue #1030) +description: Test whether Hackage accepts the latest LANGUAGE extensions +license: BSD3 +license-file: LICENSE +author: Hackage Server Team +maintainer: no@email.com +category: Test case +build-type: Simple +cabal-version: >=1.10 + +executable foo + main-is: Main.hs + build-depends: base >=4.16 && <4.17 + default-language: GHC2021 + default-extensions: + -- These LANGUAGE extensions are new in GHC 9.2: + NoFieldSelectors + OverloadedRecordDot diff --git a/tests/unpack-checks/LANGUAGE-GHC-9.2/LICENSE b/tests/unpack-checks/LANGUAGE-GHC-9.2/LICENSE new file mode 100644 index 000000000..63dc91251 --- /dev/null +++ b/tests/unpack-checks/LANGUAGE-GHC-9.2/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2016, Hackage Server Team + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Hackage Server Team nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/unpack-checks/LANGUAGE-GHC-9.2/Main.hs b/tests/unpack-checks/LANGUAGE-GHC-9.2/Main.hs new file mode 100644 index 000000000..65ae4a05d --- /dev/null +++ b/tests/unpack-checks/LANGUAGE-GHC-9.2/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Hello, Haskell!" diff --git a/tests/unpack-checks/LANGUAGE-GHC-9.2/Setup.hs b/tests/unpack-checks/LANGUAGE-GHC-9.2/Setup.hs new file mode 100644 index 000000000..9a994af67 --- /dev/null +++ b/tests/unpack-checks/LANGUAGE-GHC-9.2/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain