diff --git a/.github/workflows/build-haskell.yml b/.github/workflows/build-haskell.yml index b730a89..e3b6003 100644 --- a/.github/workflows/build-haskell.yml +++ b/.github/workflows/build-haskell.yml @@ -18,8 +18,6 @@ jobs: name: ${{ matrix.os }}-ghc-${{ matrix.ghc }} runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.allow-failure }} - env: - cabal-build-dir: b strategy: matrix: allow-failure: @@ -27,78 +25,86 @@ jobs: os: - ubuntu-latest cabal: - - latest + # Cabal 3.12 does not work due to 'entropy' dependency. + - '3.10' ghc: - - 8.0.2 - - 8.2.2 - - 8.4.4 - - 8.6.5 - - 8.8.4 - - 8.10.7 - - 9.2.8 - - 9.4.7 - - 9.6.5 - - 9.8.2 - - 9.10.1 + - '8.0' + - '8.2' + - '8.4' + - '8.6' + - '8.8' + - '8.10' + - '9.2' + - '9.4' + - '9.6' + - '9.8' + - '9.10' + include: + - allow-failure: true + os: ubuntu-latest + cabal: '3.12' + ghc: '9.12' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Environment uses: haskell-actions/setup@v2 - id: setup-haskell-cabal + id: setup with: ghc-version: ${{ matrix.ghc }} cabal-version: ${{ matrix.cabal }} - name: Configure - run: > - cabal configure - --builddir=${{ env.cabal-build-dir }} - --enable-tests - --enable-benchmarks - --enable-documentation - --test-show-details=direct - --write-ghc-environment-files=always - - - name: Freeze - run: > - cabal freeze - --builddir=${{ env.cabal-build-dir }} + run: | + cabal configure \ + --enable-tests \ + --enable-benchmarks \ + --enable-documentation \ + --test-show-details=direct \ + --write-ghc-environment-files=always + cabal build all --dry-run + # The last step generates dist-newstyle/cache/plan.json for the cache key. - - name: Cache - uses: actions/cache@v3 + # For a description of how the Caching works, see + # https://github.com/haskell-actions/setup?tab=readme-ov-file#model-cabal-workflow-with-caching + - name: Dependencies (Restore from cache) + uses: actions/cache/restore@v4 + id: cache env: - hash: ${{ hashFiles('cabal.project.freeze') }} + key: ${{ matrix.os }}-ghc-${{ matrix.ghc }} + hash: ${{ hashFiles('**/plan.json') }} with: - key: ${{ matrix.os }}-ghc-${{ matrix.ghc }}-${{ env.hash }} - restore-keys: | - ${{ matrix.os }}-ghc-${{ matrix.ghc }}- - path: | - ${{ steps.setup-haskell-cabal.outputs.cabal-store }} - ${{ env.cabal-build-dir }} + key: ${{ env.key }}-${{ env.hash }} + restore-keys: ${{ env.key }}- + path: ${{ steps.setup.outputs.cabal-store }} - - name: Dependencies - run: > - cabal build all - --builddir=${{ env.cabal-build-dir }} - --only-dependencies + - name: Dependencies (Install) + if: steps.cache.outputs.cache-hit != 'true' + run: cabal build all --only-dependencies + + # Cache dependencies already here, + # so that we do not have to rebuild them should the subsequent steps fail. + - name: Dependencies (Save cache) + uses: actions/cache/save@v4 + # If we had an exact cache hit, + # trying to save the cache would error because of key clash. + if: steps.cache.outputs.cache-hit != 'true' + with: + key: ${{ steps.cache.outputs.cache-primary-key }} + path: ${{ steps.setup.outputs.cabal-store }} - name: Build run: > cabal build all - --builddir=${{ env.cabal-build-dir }} --enable-tests --enable-benchmarks - --ghc-options=-Wall - name: Test run: > cabal test all - --builddir=${{ env.cabal-build-dir }} - name: Benchmark run: > cabal bench all - --builddir=${{ env.cabal-build-dir }} || true diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c100d..e1228ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Changelog for the `threepenny-gui` package +**0.9.4.2** – Maintenance and snapshot release + +* Bump dependencies for compatibility with GHC-9.12. + **0.9.4.1** – Maintenance and snapshot release * Bump dependencies for compatibility with GHC-9.8. diff --git a/cabal.project b/cabal.project index 06633c0..adf6cef 100644 --- a/cabal.project +++ b/cabal.project @@ -5,3 +5,14 @@ flags: +buildExamples package snap-server flags: +openssl + +if (impl(ghc == 9.12.1)) + constraints: + , hashable >= 1.5 + , template-haskell >= 2.23 + + allow-newer: + , *:time + , *:ghc-prim + , *:template-haskell + , *:base diff --git a/flake.nix b/flake.nix index c24fe4f..63cd8c0 100644 --- a/flake.nix +++ b/flake.nix @@ -20,7 +20,7 @@ # If we are building a haskell project (e.g. the current directory) # we'd use this to get the haskell packages from the current project. project = pkgs.haskell-nix.project' { - compiler-nix-name = "ghc964"; + compiler-nix-name = "ghc966"; src = ./.; projectFileName = "cabal.project"; diff --git a/src/Foreign/JavaScript/Types.hs b/src/Foreign/JavaScript/Types.hs index bdbb39b..3339884 100644 --- a/src/Foreign/JavaScript/Types.hs +++ b/src/Foreign/JavaScript/Types.hs @@ -1,20 +1,50 @@ {-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-} module Foreign.JavaScript.Types where +import Control.Concurrent.STM + ( STM + , TMVar + , TQueue + , TVar + ) +import Control.DeepSeq + ( NFData (..) + , force + ) +import Data.Aeson + ( toJSON + , (.=) + , (.:) + ) +import Data.ByteString.Char8 + ( ByteString + ) +import Data.Map + ( Map + ) +import Data.String + ( fromString + ) +import Data.Text + ( Text + ) +import Data.Typeable + ( Typeable + ) +import Snap.Core + ( Cookie(..) + ) +import System.IO + ( stderr + ) + +import qualified Control.Concurrent.STM as STM import qualified Control.Exception as E -import Control.Concurrent.STM as STM -import Control.Concurrent.MVar -import Control.DeepSeq -import Data.Aeson as JSON -import Data.ByteString.Char8 (ByteString) -import qualified Data.ByteString.Char8 as BS (hPutStrLn) -import Data.Map as Map -import Data.String -import Data.Text -import Data.Typeable -import Snap.Core (Cookie(..)) -import System.IO (stderr) +import qualified Data.Aeson as JSON +import qualified Data.ByteString.Char8 as BS (hPutStrLn) +import qualified Data.Map as Map +import Control.Concurrent.MVar import Foreign.RemotePtr {----------------------------------------------------------------------------- @@ -196,8 +226,8 @@ data ClientMsg | Quit deriving (Eq, Show) -instance FromJSON ClientMsg where - parseJSON (Object msg) = do +instance JSON.FromJSON ClientMsg where + parseJSON (JSON.Object msg) = do tag <- msg .: "tag" case (tag :: Text) of "Event" -> Event <$> (msg .: "name") <*> (msg .: "arguments") @@ -209,8 +239,10 @@ readClient :: Comm -> STM ClientMsg readClient c = do msg <- readComm c case JSON.fromJSON msg of - Error s -> error $ "Foreign.JavaScript: Error parsing client message " ++ show s - Success x -> return x + JSON.Error s -> + error $ "Foreign.JavaScript: Error parsing client message " ++ show s + JSON.Success x + -> pure x -- | Messages sent by the Haskell server. data ServerMsg @@ -226,11 +258,15 @@ instance NFData ServerMsg where rnf (Debug x) = rnf x rnf (Timestamp ) = () -instance ToJSON ServerMsg where - toJSON (Debug x) = object [ "tag" .= t "Debug" , "contents" .= toJSON x] - toJSON (Timestamp ) = object [ "tag" .= t "Timestamp" ] - toJSON (RunEval x) = object [ "tag" .= t "RunEval" , "contents" .= toJSON x] - toJSON (CallEval x) = object [ "tag" .= t "CallEval", "contents" .= toJSON x] +instance JSON.ToJSON ServerMsg where + toJSON (Debug x) = + JSON.object [ "tag" .= t "Debug", "contents" .= toJSON x] + toJSON Timestamp = + JSON.object [ "tag" .= t "Timestamp" ] + toJSON (RunEval x) = + JSON.object [ "tag" .= t "RunEval", "contents" .= toJSON x] + toJSON (CallEval x) = + JSON.object [ "tag" .= t "CallEval", "contents" .= toJSON x] t :: String -> Text t s = fromString s @@ -335,8 +371,8 @@ data Window = Window newPartialWindow :: IO Window newPartialWindow = do ptr <- newRemotePtr "" () =<< newVendor - b1 <- newTMVarIO id - b2 <- newTVarIO NoBuffering + b1 <- STM.newTMVarIO id + b2 <- STM.newTVarIO NoBuffering let nop = const $ return () Window undefined [] nop undefined b1 b2 (return ()) nop nop ptr <$> newVendor <*> newVendor diff --git a/threepenny-gui.cabal b/threepenny-gui.cabal index d082713..94c1971 100644 --- a/threepenny-gui.cabal +++ b/threepenny-gui.cabal @@ -1,7 +1,7 @@ -Name: threepenny-gui -Version: 0.9.4.1 -Synopsis: GUI framework that uses the web browser as a display. -Description: +name: threepenny-gui +version: 0.9.4.2 +synopsis: GUI framework that uses the web browser as a display. +description: Threepenny-GUI is a GUI framework that uses the web browser as a display. . It's very easy to install because everyone has a web browser installed. @@ -19,41 +19,45 @@ Description: . @cabal install threepenny-gui -fbuildExamples@ -License: BSD3 -License-file: LICENSE -Author: Heinrich Apfelmus -Maintainer: Heinrich Apfelmus -Homepage: http://wiki.haskell.org/Threepenny-gui +license: BSD3 +license-file: LICENSE +author: Heinrich Apfelmus +maintainer: Heinrich Apfelmus +homepage: http://wiki.haskell.org/Threepenny-gui bug-reports: https://github.com/HeinrichApfelmus/threepenny-gui/issues -Category: Web, GUI -Build-type: Simple -Cabal-version: >=1.10 -Tested-With: GHC == 8.0.2 - ,GHC == 8.2.2 - ,GHC == 8.4.4 - ,GHC == 8.6.5 - ,GHC == 8.8.4 - ,GHC == 8.10.7 - ,GHC == 9.2.8 - ,GHC == 9.4.7 - ,GHC == 9.6.5 - ,GHC == 9.8.2 - ,GHC == 9.10.1 - -Extra-Source-Files: CHANGELOG.md - ,README.md - ,samples/README.md - ,js/*.html - ,js/*.css - ,js/*.js - ,js/lib/*.js - -Data-dir: . -Data-files: samples/static/css/*.css - ,samples/static/css/*.png - ,samples/static/*.html - ,samples/static/*.png - ,samples/static/*.wav +category: Web, GUI +build-type: Simple +cabal-version: >=1.10 +tested-with: + GHC == 8.0.2 + , GHC == 8.2.2 + , GHC == 8.4.4 + , GHC == 8.6.5 + , GHC == 8.8.4 + , GHC == 8.10.7 + , GHC == 9.2.8 + , GHC == 9.4.7 + , GHC == 9.6.6 + , GHC == 9.8.4 + , GHC == 9.10.1 + , GHC == 9.12.1 + +extra-source-Files: + CHANGELOG.md + , README.md + , samples/README.md + , js/*.html + , js/*.css + , js/*.js + , js/lib/*.js + +data-dir: . +data-files: + samples/static/css/*.css + , samples/static/css/*.png + , samples/static/*.html + , samples/static/*.png + , samples/static/*.wav flag buildExamples @@ -70,72 +74,72 @@ flag rebug default: False manual: True -Source-repository head +source-repository head type: git location: git://github.com/HeinrichApfelmus/threepenny-gui.git - -Library +library hs-source-dirs: src exposed-modules: - Foreign.JavaScript - ,Foreign.RemotePtr - ,Graphics.UI.Threepenny - ,Graphics.UI.Threepenny.Attributes - ,Graphics.UI.Threepenny.Canvas - ,Graphics.UI.Threepenny.Core - ,Graphics.UI.Threepenny.DragNDrop - ,Graphics.UI.Threepenny.Elements - ,Graphics.UI.Threepenny.Events - ,Graphics.UI.Threepenny.JQuery - ,Graphics.UI.Threepenny.SVG - ,Graphics.UI.Threepenny.SVG.Attributes - ,Graphics.UI.Threepenny.SVG.Elements - ,Graphics.UI.Threepenny.Timer - ,Graphics.UI.Threepenny.Widgets - ,Reactive.Threepenny + Foreign.JavaScript + Foreign.RemotePtr + Graphics.UI.Threepenny + Graphics.UI.Threepenny.Attributes + Graphics.UI.Threepenny.Canvas + Graphics.UI.Threepenny.Core + Graphics.UI.Threepenny.DragNDrop + Graphics.UI.Threepenny.Elements + Graphics.UI.Threepenny.Events + Graphics.UI.Threepenny.JQuery + Graphics.UI.Threepenny.SVG + Graphics.UI.Threepenny.SVG.Attributes + Graphics.UI.Threepenny.SVG.Elements + Graphics.UI.Threepenny.Timer + Graphics.UI.Threepenny.Widgets + Reactive.Threepenny other-modules: - Foreign.JavaScript.CallBuffer - ,Foreign.JavaScript.EventLoop - ,Foreign.JavaScript.Include - ,Foreign.JavaScript.Marshal - ,Foreign.JavaScript.Resources - ,Foreign.JavaScript.Server - ,Foreign.JavaScript.Types - ,Graphics.UI.Threepenny.Internal - ,Reactive.Threepenny.Memo - ,Reactive.Threepenny.Monads - ,Reactive.Threepenny.PulseLatch - ,Reactive.Threepenny.Types - ,Paths_threepenny_gui + Foreign.JavaScript.CallBuffer + Foreign.JavaScript.EventLoop + Foreign.JavaScript.Include + Foreign.JavaScript.Marshal + Foreign.JavaScript.Resources + Foreign.JavaScript.Server + Foreign.JavaScript.Types + Graphics.UI.Threepenny.Internal + Reactive.Threepenny.Memo + Reactive.Threepenny.Monads + Reactive.Threepenny.PulseLatch + Reactive.Threepenny.Types + Paths_threepenny_gui other-extensions: CPP cpp-options: -DCABAL if flag(rebug) cpp-options: -DREBUG ghc-options: -O2 - build-depends: base >= 4.8 && < 4.21 - ,aeson (>= 0.7 && < 0.10) || == 0.11.* || (>= 1.0 && < 2.3) - ,async >= 2.0 && < 2.3 - ,bytestring >= 0.9.2 && < 0.13 - ,containers >= 0.4.2 && < 0.8 - ,data-default >= 0.5.0 && < 0.8 - ,deepseq >= 1.3.0 && < 1.6 - ,exceptions >= 0.6 && < 0.11 - ,filepath >= 1.3.0 && < 1.6.0 - ,file-embed >= 0.0.10 && < 0.1 - ,hashable >= 1.2.0 && < 1.5 - ,safe == 0.3.* - ,snap-server >= 0.9.0 && < 1.2 - ,snap-core >= 0.9.0 && < 1.1 - ,stm >= 2.2 && < 2.6 - ,template-haskell >= 2.7.0 && < 2.23 - ,text >= 0.11 && < 2.2 - ,transformers >= 0.3.0 && < 0.7 - ,unordered-containers == 0.2.* - ,websockets (>= 0.8 && < 0.12.5) || (> 0.12.5.0 && < 0.14) - ,websockets-snap >= 0.8 && < 0.11 - ,vault == 0.3.* - ,vector >= 0.10 && < 0.14 + build-depends: + base >= 4.8 && < 4.22 + , aeson (>= 0.7 && < 0.10) || == 0.11.* || (>= 1.0 && < 2.3) + , async >= 2.0 && < 2.3 + , bytestring >= 0.9.2 && < 0.13 + , containers >= 0.4.2 && < 0.8 + , data-default >= 0.5.0 && < 0.8 + , deepseq >= 1.3.0 && < 1.6 + , exceptions >= 0.6 && < 0.11 + , filepath >= 1.3.0 && < 1.6.0 + , file-embed >= 0.0.10 && < 0.1 + , hashable >= 1.2.0 && < 1.6 + , safe == 0.3.* + , snap-server >= 0.9.0 && < 1.2 + , snap-core >= 0.9.0 && < 1.1 + , stm >= 2.2 && < 2.6 + , template-haskell >= 2.7.0 && < 2.24 + , text >= 0.11 && < 2.2 + , transformers >= 0.3.0 && < 0.7 + , unordered-containers == 0.2.* + , websockets (>= 0.8 && < 0.12.5) || (> 0.12.5.0 && < 0.14) + , websockets-snap >= 0.8 && < 0.11 + , vault >= 0.3 && < 0.4 + , vector >= 0.10 && < 0.14 if impl(ghc >= 8.0) ghc-options: -Wcompat -Wnoncanonical-monad-instances default-language: Haskell2010