From f3a372c99abc324ed4c41ef7b7b4f0f7f01a81b3 Mon Sep 17 00:00:00 2001 From: Gabriel Gonzalez Date: Fri, 5 Oct 2018 20:51:18 -0700 Subject: [PATCH] Build against GHC 7.10.3 (#621) ... as requested by @jneira so that Dhall will continue to work as a dependency of Eta, which is built using GHC 7.10.3 This adds CI support for testing the build against GHC 7.10.3 and also fixes issues building against that GHC version that were caught in the process --- benchmark/parser/Main.hs | 19 ++++ default.nix | 234 ++++++++++++++++++++++++++------------- dhall.cabal | 13 ++- nix/basement.nix | 12 ++ nix/foundation.nix | 12 ++ nix/lens-family-core.nix | 9 ++ nix/wcwidth.patch | 29 +++++ release.nix | 19 +++- shell.nix | 2 +- src/Dhall/Import.hs | 22 +++- tests/Regression.hs | 13 +-- 11 files changed, 291 insertions(+), 93 deletions(-) create mode 100644 nix/basement.nix create mode 100644 nix/foundation.nix create mode 100644 nix/lens-family-core.nix create mode 100644 nix/wcwidth.patch diff --git a/benchmark/parser/Main.hs b/benchmark/parser/Main.hs index ce7c805..99d5665 100644 --- a/benchmark/parser/Main.hs +++ b/benchmark/parser/Main.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Main where @@ -5,6 +6,7 @@ module Main where import Control.Monad (forM) import Criterion.Main (defaultMain, bgroup, bench, whnf, nfIO) import Data.Map (Map, foldrWithKey, singleton, unions) +import Data.Monoid ((<>)) import System.Directory @@ -16,6 +18,23 @@ import qualified Data.Text.IO as TIO import qualified Dhall.Binary import qualified Dhall.Parser as Dhall +#if MIN_VERSION_directory(1,2,3) +#else +import Control.Exception (bracket) + +withCurrentDirectory :: FilePath -- ^ Directory to execute in + -> IO a -- ^ Action to be executed + -> IO a +withCurrentDirectory dir action = + bracket getCurrentDirectory setCurrentDirectory $ \ _ -> do + setCurrentDirectory dir + action + +listDirectory :: FilePath -> IO [FilePath] +listDirectory path = filter f <$> getDirectoryContents path + where f filename = filename /= "." && filename /= ".." +#endif + type PreludeFiles = Map FilePath T.Text loadPreludeFiles :: IO PreludeFiles diff --git a/default.nix b/default.nix index 6d12ef4..c3661f8 100644 --- a/default.nix +++ b/default.nix @@ -1,3 +1,5 @@ +{ compiler ? "ghc843" }: + let fetchNixpkgs = import ./nix/fetchNixpkgs.nix; @@ -20,56 +22,71 @@ let in pkgsNew.callPackage (import ./nix/dhall-sdist.nix src) { }; - haskellPackages = pkgsOld.haskellPackages.override (old: { - overrides = - let - extension = - haskellPackagesNew: haskellPackagesOld: { - dhall = - pkgsNew.haskell.lib.overrideCabal - (pkgsNew.haskell.lib.doCoverage - (pkgsNew.haskell.lib.failOnAllWarnings - (haskellPackagesNew.callCabal2nix - "dhall" - pkgsNew.dhall-sdist - { } + haskell = pkgsOld.haskell // { + packages = pkgsOld.haskell.packages // { + "${compiler}" = pkgsOld.haskell.packages."${compiler}".override (old: { + overrides = + let + failOnAllWarnings = drv: + # GHC 7.10.3 incorrectly detects non-exhaustive pattern + # matches + if compiler == "ghc7103" + then drv + else pkgsNew.haskell.lib.failOnAllWarnings drv; + + extension = + haskellPackagesNew: haskellPackagesOld: { + dhall = + pkgsNew.haskell.lib.overrideCabal + (pkgsNew.haskell.lib.doCoverage + (failOnAllWarnings + (haskellPackagesNew.callCabal2nix + "dhall" + pkgsNew.dhall-sdist + { } + ) + ) ) - ) - ) - (old: { - postInstall = (old.postInstall or "") + '' - ${pkgsNew.coreutils}/bin/mkdir --parents $out/nix-support - ${pkgsNew.coreutils}/bin/ln --symbolic $out/share/hpc/vanilla/html/dhall-* "$out/share/hpc/vanilla/html/dhall" - ${pkgsNew.coreutils}/bin/echo "report coverage $out/share/hpc/vanilla/html/dhall/hpc_index.html" >> $out/nix-support/hydra-build-products - ''; - } - ); + (old: { + postInstall = (old.postInstall or "") + '' + ${pkgsNew.coreutils}/bin/mkdir --parents $out/nix-support + ${pkgsNew.coreutils}/bin/ln --symbolic $out/share/hpc/vanilla/html/dhall-* "$out/share/hpc/vanilla/html/dhall" + ${pkgsNew.coreutils}/bin/echo "report coverage $out/share/hpc/vanilla/html/dhall/hpc_index.html" >> $out/nix-support/hydra-build-products + ''; + } + ); - prettyprinter = - pkgsNew.haskell.lib.dontCheck haskellPackagesOld.prettyprinter; + # https://github.com/well-typed/cborg/issues/172 + serialise = + pkgsNew.haskell.lib.dontCheck + haskellPackagesOld.serialise; - serialise = - pkgsNew.haskell.lib.dontCheck haskellPackagesOld.serialise; - }; + prettyprinter = + pkgsNew.haskell.lib.dontCheck + haskellPackagesOld.prettyprinter; + }; - in - pkgsNew.lib.fold - pkgsNew.lib.composeExtensions - (old.overrides or (_: _: {})) - [ (pkgsNew.haskell.lib.packagesFromDirectory { directory = ./nix; }) + in + pkgsNew.lib.fold + pkgsNew.lib.composeExtensions + (old.overrides or (_: _: {})) + [ (pkgsNew.haskell.lib.packagesFromDirectory { directory = ./nix; }) - extension - ]; - } - ); + extension + ]; + } + ); + }; + }; }; - overlayDynamic = pkgsNew: pkgsOld: { + overlayCabal2nix = pkgsNew: pkgsOld: { haskellPackages = pkgsOld.haskellPackages.override (old: { overrides = let extension = haskellPackagesNew: haskellPackagesOld: { + # `cabal2nix` requires a newer version of `hpack` hpack = haskellPackagesOld.hpack_0_29_6; }; @@ -82,6 +99,79 @@ let ); }; + overlayGHC7103 = pkgsNew: pkgsOld: { + haskell = pkgsOld.haskell // { + packages = pkgsOld.haskell.packages // { + "${compiler}" = pkgsOld.haskell.packages."${compiler}".override (old: { + overrides = + let + extension = + haskellPackagesNew: haskellPackagesOld: { + # Most of these fixes are due to certain dependencies being + # hidden behind a conditional compiler version directive, so + # they aren't included by default in the default Hackage + # package set (which was generated for `ghc-8.4.3`) + base-compat-batteries = + pkgsNew.haskell.lib.addBuildDepends + haskellPackagesOld.base-compat-batteries + [ haskellPackagesNew.bifunctors + haskellPackagesNew.fail + ]; + + cborg = + pkgsNew.haskell.lib.addBuildDepends + haskellPackagesOld.cborg + [ haskellPackagesNew.fail + haskellPackagesNew.semigroups + ]; + + dhall = + pkgsNew.haskell.lib.addBuildDepends + haskellPackagesOld.dhall + [ haskellPackagesNew.doctest + haskellPackagesNew.mockery + ]; + + megaparsec = + pkgsNew.haskell.lib.addBuildDepend + haskellPackagesOld.megaparsec + haskellPackagesNew.fail; + + generic-deriving = + pkgsNew.haskell.lib.dontCheck + haskellPackagesOld.generic-deriving; + + prettyprinter = + pkgsNew.haskell.lib.addBuildDepend + haskellPackagesOld.prettyprinter + haskellPackagesNew.semigroups; + + transformers-compat = + pkgsNew.haskell.lib.addBuildDepend + haskellPackagesOld.transformers-compat + haskellPackagesNew.generic-deriving; + + # For some reason, `Cabal-1.22.5` does not respect the + # `buildable: False` directive for the executable section + # even when configured with `-f -cli`. Fixing this requires + # patching out the executable section of `wcwidth` in order + # to avoid pulling in some extra dependencies which cause a + # a dependency cycle. + wcwidth = + pkgsNew.haskell.lib.appendPatch + haskellPackagesOld.wcwidth ./nix/wcwidth.patch; + }; + + in + pkgsNew.lib.composeExtensions + (old.overrides or (_: _: {})) + extension; + } + ); + }; + }; + }; + nixpkgs = fetchNixpkgs { rev = "1d4de0d552ae9aa66a5b8dee5fb0650a4372d148"; @@ -92,7 +182,9 @@ let pkgs = import nixpkgs { config = {}; - overlays = [ overlayShared overlayDynamic ]; + overlays = + [ overlayShared overlayCabal2nix ] + ++ (if compiler == "ghc7103" then [ overlayGHC7103 ] else []); }; overlayStaticLinux = pkgsNew: pkgsOld: { @@ -115,12 +207,12 @@ let useFixedCabal = drv: pkgsNew.haskell.lib.overrideCabal drv (old: { setupHaskellDepends = (old.setupHaskellDepends or []) ++ [ - pkgsNew.haskellPackages.Cabal_patched + pkgsNew.haskell.packages."${compiler}".Cabal_patched ]; libraryHaskellDepends = (old.libraryHaskellDepends or []) ++ [ - pkgsNew.haskellPackages.Cabal_patched + pkgsNew.haskell.packages."${compiler}".Cabal_patched ]; } ); @@ -140,28 +232,30 @@ let "--extra-lib-dirs=${pkgsNew.ncurses.override { enableStatic = true; }}/lib" ]; }; + + packages = pkgsOld.haskell.packages // { + "${compiler}" = pkgsOld.haskell.packages."${compiler}".override (old: { + overrides = + let + extension = + haskellPackagesNew: haskellPackagesOld: { + Cabal_patched = + haskellPackagesNew.callCabal2nix + "Cabal" + pkgsNew.Cabal_patched_Cabal_subdir + { }; + + dhall = pkgsNew.haskell.lib.statify haskellPackagesOld.dhall; + }; + + in + pkgsNew.lib.composeExtensions + (old.overrides or (_: _: {})) + extension; + } + ); + }; }; - - haskellPackages = pkgsOld.haskellPackages.override (old: { - overrides = - let - extension = - haskellPackagesNew: haskellPackagesOld: { - Cabal_patched = - pkgsNew.haskellPackages.callCabal2nix - "Cabal" - pkgsNew.Cabal_patched_Cabal_subdir - { }; - - dhall = pkgsNew.haskell.lib.statify haskellPackagesOld.dhall; - }; - - in - pkgsNew.lib.composeExtensions - (old.overrides or (_: _: {})) - extension; - } - ); }; nixpkgsStaticLinux = fetchNixpkgs { @@ -190,7 +284,7 @@ in tarball = pkgsStaticLinux.releaseTools.binaryTarball rec { - src = pkgsStaticLinux.pkgsMusl.haskellPackages.dhall; + src = pkgsStaticLinux.pkgsMusl.haskell.packages."${compiler}".dhall; installPhase = '' releaseName=${src.name} @@ -198,17 +292,9 @@ in ''; }; - inherit (pkgs.haskellPackages) dhall; + inherit (pkgs.haskell.packages."${compiler}") dhall; - all = pkgs.releaseTools.aggregate - { name = "dhall"; + inherit (pkgs.releaseTools) aggregate; - constituents = [ - dhall - tarball - pwd - ]; - }; - - shell = (pkgs.haskell.lib.doBenchmark pkgs.haskellPackages.dhall).env; + shell = (pkgs.haskell.lib.doBenchmark pkgs.haskell.packages."${compiler}".dhall).env; } diff --git a/dhall.cabal b/dhall.cabal index b28761e..fc2df5b 100644 --- a/dhall.cabal +++ b/dhall.cabal @@ -179,11 +179,11 @@ Library contravariant < 1.6 , cryptonite >= 0.23 && < 1.0 , Diff >= 0.2 && < 0.4 , - directory >= 1.2.7.1 && < 1.4 , + directory >= 1.2.2.0 && < 1.4 , exceptions >= 0.8.3 && < 0.11, filepath >= 1.4 && < 1.5 , hashable < 1.3 , - haskeline >= 0.7.3.0 && < 0.8 , + haskeline >= 0.7.2.1 && < 0.8 , insert-ordered-containers >= 0.2.1.0 && < 0.3 , lens-family-core >= 1.0.0 && < 1.3 , megaparsec >= 7.0.0 && < 7.1 , @@ -291,11 +291,16 @@ Test-Suite doctest GHC-Options: -Wall Build-Depends: base , - directory >= 1.2.2.0 && < 1.4 , + directory , filepath < 1.5 , mockery < 0.4 , doctest >= 0.7.0 && < 0.17 Default-Language: Haskell2010 + -- `doctest` doesn't work with `MIN_VERSION` macros before GHC 8 + -- + -- See: https://ghc.haskell.org/trac/ghc/ticket/10970 + if impl(ghc < 8.0) + Buildable: False Benchmark dhall-parser Type: exitcode-stdio-1.0 @@ -307,7 +312,7 @@ Benchmark dhall-parser containers >= 0.5.0.0 && < 0.7, criterion >= 1.1 && < 1.6, dhall , - directory >= 1.2.7.1 && < 1.4, + directory , serialise , text >= 0.11.1.0 && < 1.3 Default-Language: Haskell2010 diff --git a/nix/basement.nix b/nix/basement.nix new file mode 100644 index 0000000..cc4c794 --- /dev/null +++ b/nix/basement.nix @@ -0,0 +1,12 @@ +{ mkDerivation, base, ghc-prim, stdenv }: +mkDerivation { + pname = "basement"; + version = "0.0.6"; + sha256 = "9ca23b940006d8c6a7bc9c07c4ef1bf5ddb47ce82d384c5f341996e22cb95ff7"; + revision = "1"; + editedCabalFile = "0jlj6jy1fsh5xc3z1finjxsq838n3v7qz4zv344l37s1w9z8pwlf"; + libraryHaskellDepends = [ base ghc-prim ]; + homepage = "https://github.com/haskell-foundation/foundation"; + description = "Foundation scrap box of array & string"; + license = stdenv.lib.licenses.bsd3; +} diff --git a/nix/foundation.nix b/nix/foundation.nix new file mode 100644 index 0000000..441daa5 --- /dev/null +++ b/nix/foundation.nix @@ -0,0 +1,12 @@ +{ mkDerivation, base, basement, gauge, ghc-prim, stdenv }: +mkDerivation { + pname = "foundation"; + version = "0.0.19"; + sha256 = "b83bd852f1bc2f7a39fe02ce673580483cb3264ce10dd8768ee4dcf49a2b6f14"; + libraryHaskellDepends = [ base basement ghc-prim ]; + testHaskellDepends = [ base basement ]; + benchmarkHaskellDepends = [ base basement gauge ]; + homepage = "https://github.com/haskell-foundation/foundation"; + description = "Alternative prelude with batteries and no dependencies"; + license = stdenv.lib.licenses.bsd3; +} diff --git a/nix/lens-family-core.nix b/nix/lens-family-core.nix new file mode 100644 index 0000000..77dc88c --- /dev/null +++ b/nix/lens-family-core.nix @@ -0,0 +1,9 @@ +{ mkDerivation, base, containers, stdenv, transformers }: +mkDerivation { + pname = "lens-family-core"; + version = "1.2.1"; + sha256 = "95e3b9876a6cdcc6865bfad22e04af41430c7a9a6bc96e9a25a2a35a841d19a4"; + libraryHaskellDepends = [ base containers transformers ]; + description = "Haskell 98 Lens Families"; + license = stdenv.lib.licenses.bsd3; +} diff --git a/nix/wcwidth.patch b/nix/wcwidth.patch new file mode 100644 index 0000000..ddeed44 --- /dev/null +++ b/nix/wcwidth.patch @@ -0,0 +1,29 @@ +diff -Naur wcwidth-0.0.2.before/wcwidth.cabal wcwidth-0.0.2.after/wcwidth.cabal +--- wcwidth-0.0.2.before/wcwidth.cabal 2011-04-03 21:19:59.000000000 -0700 ++++ wcwidth-0.0.2.after/wcwidth.cabal 2018-10-04 11:34:55.000000000 -0700 +@@ -35,25 +35,3 @@ + extensions : StandaloneDeriving + ForeignFunctionInterface + OverloadedStrings +- +- +-executable wcwidth-tools +- main-is : WCWidthTableaux.hs +- if flag(cli) +- buildable : True +- else +- buildable : False +- if flag(split-base) +- build-depends : base >= 4 && < 5 +- else +- build-depends : base < 4 +- build-depends : containers +- , bytestring +- , setlocale >= 0.0.3 +- , utf8-string >= 0.3 +- , attoparsec >= 0.8.5 +- extensions : StandaloneDeriving +- ForeignFunctionInterface +- OverloadedStrings +- +- diff --git a/release.nix b/release.nix index 5eb4d5d..df0e319 100644 --- a/release.nix +++ b/release.nix @@ -1,10 +1,21 @@ let - default = (import ./default.nix); + default_7_10_3 = import ./default.nix { compiler = "ghc7103"; }; + + default_8_4_3 = import ./default.nix { compiler = "ghc843"; }; in - { dhall = default.all; + { dhall = default_8_4_3.aggregate + { name = "dhall"; - inherit (default) tarball; + constituents = [ + default_7_10_3.dhall + default_8_4_3.dhall + default_8_4_3.tarball + default_8_4_3.pwd + ]; + }; - coverage = default.dhall; + "coverage" = default_8_4_3.dhall; + + inherit (default_8_4_3) tarball; } diff --git a/shell.nix b/shell.nix index af299aa..82fb296 100644 --- a/shell.nix +++ b/shell.nix @@ -1 +1 @@ -(import ./default.nix).shell +(import ./default.nix {}).shell diff --git a/src/Dhall/Import.hs b/src/Dhall/Import.hs index 8227276..8419a0a 100644 --- a/src/Dhall/Import.hs +++ b/src/Dhall/Import.hs @@ -129,7 +129,6 @@ module Dhall.Import ( import Control.Applicative (Alternative(..)) import Codec.CBOR.Term (Term) -import Control.Applicative (empty) import Control.Exception (Exception, SomeException, throwIO, toException) import Control.Monad (guard) import Control.Monad.Catch (throwM, MonadCatch(catch), catches, Handler(..)) @@ -470,7 +469,7 @@ exprFromImport here@(Import {..}) = do result <- Maybe.runMaybeT $ do Just expectedHash <- return hash cacheFile <- getCacheFile expectedHash - True <- liftIO (Directory.doesPathExist cacheFile) + True <- liftIO (Directory.doesFileExist cacheFile) bytesStrict <- liftIO (Data.ByteString.readFile cacheFile) @@ -564,7 +563,7 @@ getCacheFile hash = do liftIO (Directory.setPermissions directory private) - cacheDirectory <- liftIO $ Directory.getXdgDirectory Directory.XdgCache "" + cacheDirectory <- getCacheDirectory assertDirectory cacheDirectory @@ -576,6 +575,23 @@ getCacheFile hash = do return cacheFile +getCacheDirectory :: MonadIO io => io FilePath +#if MIN_VERSION_directory(1,2,3) +getCacheDirectory = liftIO (Directory.getXdgDirectory Directory.XdgCache "") +#else +getCacheDirectory = liftIO $ do + maybeXDGCacheHome <- System.Environment.lookupEnv "XDG_CACHE_HOME" + + case maybeXDGCacheHome of + Nothing -> do + homeDirectory <- Directory.getHomeDirectory + + return (homeDirectory ".cache") + + Just xdgCacheHome -> do + return xdgCacheHome +#endif + exprFromUncachedImport :: Import -> StateT (Status IO) IO (Expr Src Import) exprFromUncachedImport (Import {..}) = do let ImportHashed {..} = importHashed diff --git a/tests/Regression.hs b/tests/Regression.hs index f250e57..b8198a1 100644 --- a/tests/Regression.hs +++ b/tests/Regression.hs @@ -1,7 +1,6 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TypeApplications #-} module Regression where @@ -52,7 +51,7 @@ data Foo = Foo Integer Bool | Bar Bool Bool Bool | Baz Integer Integer unnamedFields :: TestTree unnamedFields = Test.Tasty.HUnit.testCase "Unnamed Fields" (do - let ty = Dhall.auto @Foo + let ty = Dhall.auto :: Dhall.Type Foo Test.Tasty.HUnit.assertEqual "Good type" (Dhall.expected ty) (Dhall.Core.Union ( Data.HashMap.Strict.InsOrd.fromList [ ("Bar",Dhall.Core.Record (Data.HashMap.Strict.InsOrd.fromList [ @@ -62,14 +61,14 @@ unnamedFields = Test.Tasty.HUnit.testCase "Unnamed Fields" (do ,("Foo",Dhall.Core.Record (Data.HashMap.Strict.InsOrd.fromList [ ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool)]))])) - let inj = Dhall.inject @Foo + let inj = Dhall.inject :: Dhall.InputType Foo Test.Tasty.HUnit.assertEqual "Good Inject" (Dhall.declared inj) (Dhall.expected ty) - let tu_ty = Dhall.auto @(Integer, Bool) + let tu_ty = Dhall.auto :: Dhall.Type (Integer, Bool) Test.Tasty.HUnit.assertEqual "Auto Tuple" (Dhall.expected tu_ty) (Dhall.Core.Record ( Data.HashMap.Strict.InsOrd.fromList [ ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool) ])) - let tu_in = Dhall.inject @(Integer, Bool) + let tu_in = Dhall.inject :: Dhall.InputType (Integer, Bool) Test.Tasty.HUnit.assertEqual "Inj. Tuple" (Dhall.declared tu_in) (Dhall.expected tu_ty) return () )