From 56e0d695638035b9e3b15e193cffb3541b70feb7 Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Tue, 2 Apr 2024 14:07:28 +0300 Subject: [PATCH] Depend on os-string-2.* Support filepath-1.5 Provide instances for OsString/WindowsString/PosixString from both packages, if both have them. --- .github/workflows/haskell-ci.yml | 44 ++++++++++++++++++++------------ CHANGES.md | 5 ++++ cabal.haskell-ci | 10 +++++++- hashable.cabal | 27 +++++++++++++++----- src/Data/Hashable/Class.hs | 34 ++++++++++++++++++++++-- tests/Properties.hs | 30 +++++++++++++++++++++- 6 files changed, 123 insertions(+), 27 deletions(-) diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index 5ff33e3..231a352 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -8,9 +8,9 @@ # # For more information, see https://github.com/haskell-CI/haskell-ci # -# version: 0.17.20231010 +# version: 0.19.20240317 # -# REGENDATA ("0.17.20231010",["github","cabal.project"]) +# REGENDATA ("0.19.20240317",["github","cabal.project"]) # name: Haskell-CI on: @@ -32,19 +32,19 @@ jobs: strategy: matrix: include: - - compiler: ghc-9.8.1 + - compiler: ghc-9.8.2 compilerKind: ghc - compilerVersion: 9.8.1 + compilerVersion: 9.8.2 setup-method: ghcup allow-failure: false - - compiler: ghc-9.6.3 + - compiler: ghc-9.6.4 compilerKind: ghc - compilerVersion: 9.6.3 + compilerVersion: 9.6.4 setup-method: ghcup allow-failure: false - - compiler: ghc-9.4.7 + - compiler: ghc-9.4.8 compilerKind: ghc - compilerVersion: 9.4.7 + compilerVersion: 9.4.8 setup-method: ghcup allow-failure: false - compiler: ghc-9.2.8 @@ -100,18 +100,20 @@ jobs: apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5 if [ "${{ matrix.setup-method }}" = ghcup ]; then mkdir -p "$HOME/.ghcup/bin" - curl -sL https://downloads.haskell.org/ghcup/0.1.19.5/x86_64-linux-ghcup-0.1.19.5 > "$HOME/.ghcup/bin/ghcup" + curl -sL https://downloads.haskell.org/ghcup/0.1.20.0/x86_64-linux-ghcup-0.1.20.0 > "$HOME/.ghcup/bin/ghcup" chmod a+x "$HOME/.ghcup/bin/ghcup" + "$HOME/.ghcup/bin/ghcup" config add-release-channel https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml; "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false) - "$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false) + "$HOME/.ghcup/bin/ghcup" install cabal 3.10.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false) else apt-add-repository -y 'ppa:hvr/ghc' apt-get update apt-get install -y "$HCNAME" mkdir -p "$HOME/.ghcup/bin" - curl -sL https://downloads.haskell.org/ghcup/0.1.19.5/x86_64-linux-ghcup-0.1.19.5 > "$HOME/.ghcup/bin/ghcup" + curl -sL https://downloads.haskell.org/ghcup/0.1.20.0/x86_64-linux-ghcup-0.1.20.0 > "$HOME/.ghcup/bin/ghcup" chmod a+x "$HOME/.ghcup/bin/ghcup" - "$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false) + "$HOME/.ghcup/bin/ghcup" config add-release-channel https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.8.yaml; + "$HOME/.ghcup/bin/ghcup" install cabal 3.10.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false) fi env: HCKIND: ${{ matrix.compilerKind }} @@ -131,13 +133,13 @@ jobs: echo "HC=$HC" >> "$GITHUB_ENV" echo "HCPKG=$HCPKG" >> "$GITHUB_ENV" echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV" - echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV" + echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.2.0 -vnormal+nowrap" >> "$GITHUB_ENV" else HC=$HCDIR/bin/$HCKIND echo "HC=$HC" >> "$GITHUB_ENV" echo "HCPKG=$HCDIR/bin/$HCKIND-pkg" >> "$GITHUB_ENV" echo "HADDOCK=$HCDIR/bin/haddock" >> "$GITHUB_ENV" - echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV" + echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.2.0 -vnormal+nowrap" >> "$GITHUB_ENV" fi HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))') @@ -264,12 +266,20 @@ jobs: - name: prepare for constraint sets run: | rm -f cabal.project.local + - name: constraint set filepath-1.5 + run: | + if [ $((HCNUMVER >= 90200)) -ne 0 ] ; then $CABAL v2-build $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.5.2.0' all --dry-run ; fi + if [ $((HCNUMVER >= 90200)) -ne 0 ] ; then cabal-plan topo | sort ; fi + if [ $((HCNUMVER >= 90200)) -ne 0 ] ; then $CABAL v2-build $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.5.2.0' --dependencies-only -j2 all ; fi + if [ $((HCNUMVER >= 90200)) -ne 0 ] ; then $CABAL v2-build $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.5.2.0' all ; fi + if [ $((HCNUMVER >= 90200)) -ne 0 ] ; then $CABAL v2-test $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.5.2.0' all ; fi - name: constraint set filepath-1.4.100.0 run: | - $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='filepath >=1.4.100.0' all --dry-run + $CABAL v2-build $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.4.100.0' all --dry-run cabal-plan topo | sort - $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='filepath >=1.4.100.0' --dependencies-only -j2 all - $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='filepath >=1.4.100.0' all + $CABAL v2-build $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.4.100.0' --dependencies-only -j2 all + $CABAL v2-build $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.4.100.0' all + $CABAL v2-test $ARG_COMPILER --enable-tests --disable-benchmarks --constraint='filepath ^>=1.4.100.0' all - name: constraint set random-initial-seed run: | $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='hashable +random-initial-seed' all --dry-run diff --git a/CHANGES.md b/CHANGES.md index 6647c54..410f1be 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ See also https://pvp.haskell.org/faq +## Version 1.4.4.0 + + * Depend on `os-string-2` for GHC-9.2+ + * Support `filepath-1.5` + ## Version 1.4.3.0 * Export `defaultHashWithSalt` and `defaultHash`. diff --git a/cabal.haskell-ci b/cabal.haskell-ci index 7015856..41cc5e1 100644 --- a/cabal.haskell-ci +++ b/cabal.haskell-ci @@ -7,4 +7,12 @@ constraint-set random-initial-seed constraints: hashable +random-initial-seed constraint-set filepath-1.4.100.0 - constraints: filepath >=1.4.100.0 + constraints: filepath ^>=1.4.100.0 + tests: True + run-tests: True + +constraint-set filepath-1.5 + ghc: >=9.2 + constraints: filepath ^>=1.5.2.0 + tests: True + run-tests: True diff --git a/hashable.cabal b/hashable.cabal index 10aa4cd..dbed582 100644 --- a/hashable.cabal +++ b/hashable.cabal @@ -1,7 +1,6 @@ cabal-version: 1.12 name: hashable -version: 1.4.3.0 -x-revision: 1 +version: 1.4.4.0 synopsis: A class for types that can be converted to a hash value description: This package defines a class, 'Hashable', for types that @@ -38,9 +37,9 @@ tested-with: || ==9.0.1 || ==9.0.2 || ==9.2.8 - || ==9.4.7 - || ==9.6.3 - || ==9.8.1 + || ==9.4.8 + || ==9.6.4 + || ==9.8.2 extra-source-files: CHANGES.md @@ -84,10 +83,22 @@ library , bytestring >=0.10.8.2 && <0.13 , containers >=0.5.10.2 && <0.7 , deepseq >=1.4.3.0 && <1.6 - , filepath >=1.4.1.2 && <1.5 , ghc-prim , text >=1.2.3.0 && <1.3 || >=2.0 && <2.2 + if impl(ghc >=9.2) + -- depend on os-string on newer GHCs only. + -- os-string has tight lower bound on bytestring, which prevents + -- using bundled version on older GHCs. + build-depends: os-string >=2.0.2 + + -- we also ensure that we can get filepath-1.5 only with GHC-9.2 + -- therefore there is else-branch with stricter upper bound. + build-depends: filepath >=1.4.1.2 && <1.6 + + else + build-depends: filepath >=1.4.1.2 && <1.5 + if !impl(ghc >=9.2) build-depends: base-orphans >=0.8.6 && <0.10 @@ -152,6 +163,7 @@ test-suite hashable-tests build-depends: base , bytestring + , filepath , ghc-prim , hashable , HUnit @@ -162,6 +174,9 @@ test-suite hashable-tests , test-framework-quickcheck2 >=0.2.9 , text >=0.11.0.5 + if impl(ghc >=9.2) + build-depends: os-string + if !os(windows) build-depends: unix cpp-options: -DHAVE_MMAP diff --git a/src/Data/Hashable/Class.hs b/src/Data/Hashable/Class.hs index 4f60d03..fcf9f59 100644 --- a/src/Data/Hashable/Class.hs +++ b/src/Data/Hashable/Class.hs @@ -4,6 +4,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE PackageImports #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE Trustworthy #-} @@ -167,7 +168,25 @@ import Data.Tuple (Solo (..)) import GHC.Tuple (Solo (..)) #endif -#if MIN_VERSION_filepath(1,4,100) +-- filepath >=1.4.100 && <1.5 has System.OsString.Internal.Types module +#if MIN_VERSION_filepath(1,4,100) && !(MIN_VERSION_filepath(1,5,0)) +#define HAS_OS_STRING_filepath 1 +#else +#define HAS_OS_STRING_filepath 0 +#endif + +-- if we depend on os_string module, then it has System.OsString.Internal.Types +-- module as well +#ifdef MIN_VERSION_os_string +#define HAS_OS_STRING_os_string 1 +#else +#define HAS_OS_STRING_os_string 0 +#endif + +#if HAS_OS_STRING_filepath && HAS_OS_STRING_os_string +import "os-string" System.OsString.Internal.Types (OsString (..), PosixString (..), WindowsString (..)) +import qualified "filepath" System.OsString.Internal.Types as FP (OsString (..), PosixString (..), WindowsString (..)) +#elif HAS_OS_STRING_filepath || HAS_OS_STRING_os_string import System.OsString.Internal.Types (OsString (..), PosixString (..), WindowsString (..)) #endif @@ -666,7 +685,7 @@ instance Hashable BSI.ShortByteString where hashWithSalt salt sbs@(BSI.SBS ba) = hashByteArrayWithSalt ba 0 (BSI.length sbs) (hashWithSalt salt (BSI.length sbs)) -#if MIN_VERSION_filepath(1,4,100) +#if HAS_OS_STRING_filepath || HAS_OS_STRING_os_string -- | @since 1.4.2.0 instance Hashable PosixString where hashWithSalt salt (PosixString s) = hashWithSalt salt s @@ -680,6 +699,17 @@ instance Hashable OsString where hashWithSalt salt (OsString s) = hashWithSalt salt s #endif +#if HAS_OS_STRING_filepath && HAS_OS_STRING_os_string +instance Hashable FP.PosixString where + hashWithSalt salt (FP.PosixString s) = hashWithSalt salt s + +instance Hashable FP.WindowsString where + hashWithSalt salt (FP.WindowsString s) = hashWithSalt salt s + +instance Hashable FP.OsString where + hashWithSalt salt (FP.OsString s) = hashWithSalt salt s +#endif + #if MIN_VERSION_text(2,0,0) instance Hashable T.Text where diff --git a/tests/Properties.hs b/tests/Properties.hs index 5ec898f..31271bd 100644 --- a/tests/Properties.hs +++ b/tests/Properties.hs @@ -1,6 +1,6 @@ {-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving, MagicHash, Rank2Types, UnboxedTuples #-} -{-# LANGUAGE DeriveGeneric, ScopedTypeVariables #-} +{-# LANGUAGE DeriveGeneric, ScopedTypeVariables, PackageImports #-} -- | QuickCheck tests for the 'Data.Hashable' module. We test -- functions by comparing the C and Haskell implementations. @@ -30,6 +30,14 @@ import GHC.Generics import qualified Data.ByteString.Short as BS +#if MIN_VERSION_filepath(1,4,100) && !(MIN_VERSION_filepath(1,5,0)) +import qualified "filepath" System.OsString.Internal.Types as FP +#endif + +#ifdef MIN_VERSION_os_string +import qualified "os-string" System.OsString.Internal.Types as OS +#endif + ------------------------------------------------------------------------ -- * Properties @@ -252,3 +260,23 @@ properties = fromStrict :: B.ByteString -> BL.ByteString fromStrict = BL.fromStrict + +------------------------------------------------------------------------ +-- test that instances exist + +instanceExists :: Hashable a => a -> () +instanceExists _ = () + +#if MIN_VERSION_filepath(1,4,100) && !(MIN_VERSION_filepath(1,5,0)) +_fp1, _fp2, _fp3 :: () +_fp1 = instanceExists (undefined :: FP.OsString) +_fp2 = instanceExists (undefined :: FP.WindowsString) +_fp3 = instanceExists (undefined :: FP.PosixString) +#endif + +#ifdef MIN_VERSION_os_string +_os1, _os2, _os3 :: () +_os1 = instanceExists (undefined :: OS.OsString) +_os2 = instanceExists (undefined :: OS.WindowsString) +_os3 = instanceExists (undefined :: OS.PosixString) +#endif