diff --git a/.travis.yml b/.travis.yml index 7525c2d..b04b221 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,15 +57,18 @@ matrix: #- env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7 # compiler: ": #GHC 7.10.3" # addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=8.0.2 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 8.0.2" - addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + # - env: BUILD=cabal GHCVER=8.0.2 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7 + # compiler: ": #GHC 8.0.2" + # addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - env: BUILD=cabal GHCVER=8.2.2 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7 compiler: ": #GHC 8.2.2" addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=8.4.1 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 8.4.1" - addons: {apt: {packages: [cabal-install-2.0,ghc-8.4.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + - env: BUILD=cabal GHCVER=8.4.4 CABALVER=2.2 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 8.4.4" + addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + - env: BUILD=cabal GHCVER=8.6.3 CABALVER=2.4 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 8.6.3" + addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} # Build with the newest GHC and cabal-install. This is an accepted failure, # see below. @@ -99,9 +102,17 @@ matrix: # compiler: ": #stack 8.0.2" # addons: {apt: {packages: [libgmp-dev]}} - - env: BUILD=stack ARGS="--resolver lts-11" - compiler: ": #stack 8.2.2" - addons: {apt: {packages: [libgmp-dev]}} + # - env: BUILD=stack ARGS="--resolver lts-11" + # compiler: ": #stack 8.2.2" + # addons: {apt: {packages: [libgmp-dev]}} + + # - env: BUILD=stack ARGS="--resolver lts-12" + # compiler: ": #stack 8.4.4" + # addons: {apt: {packages: [libgmp-dev]}} + + # - env: BUILD=stack ARGS="--resolver lts-13" + # compiler: ": #stack 8.6.3" + # addons: {apt: {packages: [libgmp-dev]}} # Nightly builds are allowed to fail - env: BUILD=stack ARGS="--resolver nightly" @@ -134,9 +145,17 @@ matrix: # compiler: ": #stack 8.0.2 osx" # os: osx - - env: BUILD=stack ARGS="--resolver lts-11" - compiler: ": #stack 8.2.2 osx" - os: osx + # - env: BUILD=stack ARGS="--resolver lts-11" + # compiler: ": #stack 8.2.2 osx" + # os: osx + + # - env: BUILD=stack ARGS="--resolver lts-12" + # compiler: ": #stack 8.4.4 osx" + # os: osx + + # - env: BUILD=stack ARGS="--resolver lts-13" + # compiler: ": #stack 8.6.3 osx" + # os: osx - env: BUILD=stack ARGS="--resolver nightly" compiler: ": #stack nightly osx" @@ -180,9 +199,14 @@ install: case "$BUILD" in stack) # Add in extra-deps for older snapshots, as necessary - stack --no-terminal --install-ghc $ARGS test --bench --dry-run || ( \ - stack --no-terminal $ARGS build cabal-install && \ - stack --no-terminal $ARGS solver --update-config) + # + # This is disabled by default, as relying on the solver like this can + # make builds unreliable. Instead, if you have this situation, it's + # recommended that you maintain multiple stack-lts-X.yaml files. + + #stack --no-terminal --install-ghc $ARGS test --bench --dry-run || ( \ + # stack --no-terminal $ARGS build cabal-install && \ + # stack --no-terminal $ARGS solver --update-config) # Build the dependencies stack --no-terminal --install-ghc $ARGS test --bench --only-dependencies @@ -206,7 +230,7 @@ script: set -ex case "$BUILD" in stack) - stack --no-terminal $ARGS test --bench --no-run-benchmarks --haddock --no-haddock-deps --flag servant-checked-exceptions:buildexample + stack --no-terminal $ARGS test --bench --no-run-benchmarks --haddock --no-haddock-deps --flag servant-checked-exceptions:buildexample --flag servant-checked-exceptions-core:buildexample ;; cabal) cabal install --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES diff --git a/servant-checked-exceptions-core/CHANGELOG.md b/servant-checked-exceptions-core/CHANGELOG.md index fd1490a..6703f29 100644 --- a/servant-checked-exceptions-core/CHANGELOG.md +++ b/servant-checked-exceptions-core/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.1.0.0 + +* Add support for servant-0.16 and remove support for all previous version of + servant. [#31](https://github.com/cdepillabout/servant-checked-exceptions/pull/31) + Thanks [Schell Carl Scivally](https://github.com/schell)! + ## 2.0.0.0 * Initial release of `servant-checked-exceptions-core` package, with diff --git a/servant-checked-exceptions-core/servant-checked-exceptions-core.cabal b/servant-checked-exceptions-core/servant-checked-exceptions-core.cabal index 76e258e..8962134 100644 --- a/servant-checked-exceptions-core/servant-checked-exceptions-core.cabal +++ b/servant-checked-exceptions-core/servant-checked-exceptions-core.cabal @@ -1,5 +1,5 @@ name: servant-checked-exceptions-core -version: 2.0.0.0 +version: 2.1.0.0 synopsis: Checked exceptions for Servant APIs. description: Please see . homepage: https://github.com/cdepillabout/servant-checked-exceptions @@ -8,7 +8,7 @@ license-file: LICENSE author: Dennis Gosnell maintainer: cdep.illabout@gmail.com copyright: 2017-2018 Dennis Gosnell -category: Text +category: Web build-type: Simple extra-source-files: CHANGELOG.md , README.md @@ -34,7 +34,6 @@ library build-depends: base >= 4.9 && < 5 , aeson , bytestring - , deepseq , http-media , http-types , profunctors @@ -48,7 +47,7 @@ library other-extensions: QuasiQuotes , TemplateHaskell -executable servant-checked-exceptions-example-docs +executable servant-checked-exceptions-core-example-docs main-is: Docs.hs other-modules: Api hs-source-dirs: example @@ -68,7 +67,7 @@ executable servant-checked-exceptions-example-docs else buildable: False -test-suite servant-checked-exceptions-doctest +test-suite servant-checked-exceptions-core-doctest if impl(ghcjs) buildable: False type: exitcode-stdio-1.0 diff --git a/servant-checked-exceptions/CHANGELOG.md b/servant-checked-exceptions/CHANGELOG.md index aa4889b..c0f5264 100644 --- a/servant-checked-exceptions/CHANGELOG.md +++ b/servant-checked-exceptions/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.1.0.0 + +* Add support for servant-0.16 and remove support for all previous version of + servant. [#31](https://github.com/cdepillabout/servant-checked-exceptions/pull/31) + Thanks [Schell Carl Scivally](https://github.com/schell)! + ## 2.0.0.0 * Split into two package `servant-checked-exceptions-core` and @@ -6,7 +12,7 @@ the latter reexports the former and adds instances for `HasServer` and `HasClient`. The rationale is described further in [issue 25](https://github.com/cdepillabout/servant-checked-exceptions/issues/25) - + Most users should only depend on `servant-checked-exceptions`. But users who need access to core types without incurring a dependency on `servant-server` and `servant-client` can depend on diff --git a/servant-checked-exceptions/example/Docs.hs b/servant-checked-exceptions/example/Docs.hs deleted file mode 100644 index 68f5a63..0000000 --- a/servant-checked-exceptions/example/Docs.hs +++ /dev/null @@ -1,63 +0,0 @@ -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE EmptyCase #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE InstanceSigs #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} - -module Main where - -import Data.Proxy (Proxy(Proxy)) -import Data.Text (Text) -import Servant.API (Capture) -import Servant.Docs - (DocCapture(DocCapture), ToCapture(toCapture), ToSample(toSamples), - docs, markdown) - -import Servant.Checked.Exceptions () - -import Api - (Api, BadSearchTermErr(BadSearchTermErr), - IncorrectCapitalization(IncorrectCapitalization), SearchQuery, - SearchResponse) - --- This module prints out documentation for 'Api'. --- --- Notice how we only need 'ToSample' instances for the two errors we are --- throwing with 'Throws': 'BadSearchTermErr' and 'IncorrectCapitialization'. --- We don't have to directly worry about writing instances for 'Envelope'. - -instance ToSample SearchResponse where - toSamples :: Proxy SearchResponse -> [(Text, SearchResponse)] - toSamples Proxy = [("This is a successful response.", "good")] - -instance ToCapture (Capture "query" SearchQuery) where - toCapture :: Proxy (Capture "query" SearchQuery) -> DocCapture - toCapture Proxy = - DocCapture "query" "a search string like \"hello\" or \"bye\"" - -instance ToSample BadSearchTermErr where - toSamples :: Proxy BadSearchTermErr -> [(Text, BadSearchTermErr)] - toSamples Proxy = - [("a completely incorrect search term was used", BadSearchTermErr)] - -instance ToSample IncorrectCapitalization where - toSamples :: Proxy IncorrectCapitalization -> [(Text, IncorrectCapitalization)] - toSamples Proxy = - [ ( "the search term \"Hello\" has not been capitalized correctly" - , IncorrectCapitalization) - ] - --- | Print the documentation rendered as markdown to stdout. -main :: IO () -main = putStrLn . markdown $ docs (Proxy :: Proxy Api) diff --git a/servant-checked-exceptions/servant-checked-exceptions.cabal b/servant-checked-exceptions/servant-checked-exceptions.cabal index 1f155e0..f018398 100644 --- a/servant-checked-exceptions/servant-checked-exceptions.cabal +++ b/servant-checked-exceptions/servant-checked-exceptions.cabal @@ -1,5 +1,5 @@ name: servant-checked-exceptions -version: 2.0.0.0 +version: 2.1.0.0 synopsis: Checked exceptions for Servant APIs. description: Please see . homepage: https://github.com/cdepillabout/servant-checked-exceptions @@ -8,7 +8,7 @@ license-file: LICENSE author: Dennis Gosnell maintainer: cdep.illabout@gmail.com copyright: 2017-2018 Dennis Gosnell -category: Text +category: Web build-type: Simple extra-source-files: CHANGELOG.md , README.md @@ -27,20 +27,13 @@ library , Servant.Checked.Exceptions.Internal.Servant.Client , Servant.Checked.Exceptions.Internal.Servant.Server build-depends: base >= 4.9 && < 5 - , aeson , bytestring - , deepseq - , http-media , http-types - , profunctors - , tagged - , servant >= 0.12 + , servant >= 0.16 , servant-checked-exceptions-core - , servant-client >= 0.12 - , servant-client-core >= 0.12 - , servant-docs >= 0.10 - , servant-server >= 0.12 - , text + , servant-client >= 0.16 + , servant-client-core >= 0.16 + , servant-server >= 0.16 , wai , world-peace default-language: Haskell2010 @@ -70,26 +63,6 @@ executable servant-checked-exceptions-example-client else buildable: False -executable servant-checked-exceptions-example-docs - main-is: Docs.hs - other-modules: Api - hs-source-dirs: example - build-depends: base - , aeson - , http-api-data - , http-types - , servant - , servant-checked-exceptions - , servant-docs - , text - default-language: Haskell2010 - ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N - - if flag(buildexample) - buildable: True - else - buildable: False - executable servant-checked-exceptions-example-server main-is: Server.hs other-modules: Api @@ -98,7 +71,6 @@ executable servant-checked-exceptions-example-server , aeson , http-api-data , http-types - , natural-transformation , servant , servant-checked-exceptions , servant-server @@ -119,11 +91,10 @@ test-suite servant-checked-exceptions-test other-modules: hs-source-dirs: test build-depends: base - , bytestring , hspec-wai , http-types , tasty - , tasty-hspec + , tasty-hspec >= 0.2 , tasty-hunit , servant , servant-checked-exceptions diff --git a/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Client.hs b/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Client.hs index 31cb4c2..89df6c5 100644 --- a/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Client.hs +++ b/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Client.hs @@ -6,6 +6,7 @@ {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} @@ -46,7 +47,16 @@ instance (RunClient m, HasClient m (Throwing '[e] :> api)) => HasClient m (Throw -> Proxy (Throws e :> api) -> Request -> Client m (Throwing '[e] :> api) - clientWithRoute p Proxy = clientWithRoute p (Proxy :: Proxy (Throwing '[e] :> api)) + clientWithRoute p Proxy = clientWithRoute p (Proxy @(Throwing '[e] :> api)) + + hoistClientMonad + :: Proxy m + -> Proxy (Throws e :> api) + -> (forall x. mon x -> mon' x) + -> Client mon (Throws e :> api) + -> Client mon' (Throwing '[e] :> api) + hoistClientMonad pm _ = hoistClientMonad pm (Proxy @(Throwing '[e] :> api)) + -- | When @'Throwing' es@ comes before a 'Verb', change it into the same 'Verb' -- but returning an @'Envelope' es@. @@ -64,6 +74,17 @@ instance (HasClient m (Verb method status ctypes (Envelope es a))) => clientWithRoute p Proxy = clientWithRoute p (Proxy :: Proxy (Verb method status ctypes (Envelope es a))) + hoistClientMonad + :: Proxy m + -> Proxy (Throwing es :> Verb method status ctypes a) + -> (forall x. mon x -> mon' x) + -> Client mon (Throwing es :> Verb method status ctypes a) + -> Client mon' (Verb method status ctypes (Envelope es a)) + hoistClientMonad pm _ = + hoistClientMonad pm (Proxy @(Verb method status ctypes (Envelope es a))) + + + -- | When 'NoThrow' comes before a 'Verb', change it into the same 'Verb' -- but returning an @'Envelope' \'[]@. instance (RunClient m, HasClient m (Verb method status ctypes (Envelope '[] a))) => @@ -80,6 +101,16 @@ instance (RunClient m, HasClient m (Verb method status ctypes (Envelope '[] a))) clientWithRoute p Proxy = clientWithRoute p (Proxy :: Proxy (Verb method status ctypes (Envelope '[] a))) + hoistClientMonad + :: Proxy m + -> Proxy (NoThrow :> Verb method status ctypes a) + -> (forall x. mon x -> mon' x) + -> Client mon (NoThrow :> Verb method status ctypes a) + -> Client mon' (Verb method status ctypes (Envelope '[] a)) + hoistClientMonad pm _ = + hoistClientMonad pm (Proxy @(Verb method status ctypes (Envelope '[] a))) + + -- | When @'Throwing' es@ comes before ':<|>', push @'Throwing' es@ into each -- branch of the API. instance (RunClient m, HasClient m ((Throwing es :> api1) :<|> (Throwing es :> api2))) => @@ -96,6 +127,16 @@ instance (RunClient m, HasClient m ((Throwing es :> api1) :<|> (Throwing es :> a clientWithRoute p _ = clientWithRoute p (Proxy :: Proxy ((Throwing es :> api1) :<|> (Throwing es :> api2))) + hoistClientMonad + :: Proxy m + -> Proxy (Throwing es :> (api1 :<|> api2)) + -> (forall x. mon x -> mon' x) + -> Client mon (Throwing es :> (api1 :<|> api2)) + -> Client mon' ((Throwing es :> api1) :<|> (Throwing es :> api2)) + hoistClientMonad pm _ = + hoistClientMonad pm (Proxy @(Throwing es :> (api1 :<|> api2))) + + -- | When 'NoThrow' comes before ':<|>', push 'NoThrow' into each branch of the -- API. instance (RunClient m, HasClient m ((NoThrow :> api1) :<|> (NoThrow :> api2))) => @@ -112,6 +153,16 @@ instance (RunClient m, HasClient m ((NoThrow :> api1) :<|> (NoThrow :> api2))) = clientWithRoute p _ = clientWithRoute p (Proxy :: Proxy ((NoThrow :> api1) :<|> (NoThrow :> api2))) + hoistClientMonad + :: Proxy m + -> Proxy (NoThrow :> (api1 :<|> api2)) + -> (forall x. mon x -> mon' x) + -> Client mon (NoThrow :> (api1 :<|> api2)) + -> Client mon' ((NoThrow :> api1) :<|> (NoThrow :> api2)) + hoistClientMonad pm _ = + hoistClientMonad pm (Proxy @(NoThrow :> (api1 :<|> api2))) + + -- | When a @'Throws' e@ comes immediately after a @'Throwing' es@, 'Snoc' the -- @e@ onto the @es@. Otherwise, if @'Throws' e@ comes before any other -- combinator, push it down so it is closer to the 'Verb'. @@ -129,6 +180,16 @@ instance (RunClient m, HasClient m (ThrowingNonterminal (Throwing es :> api :> a clientWithRoute p _ = clientWithRoute p (Proxy :: Proxy (ThrowingNonterminal (Throwing es :> api :> apis))) + hoistClientMonad + :: Proxy m + -> Proxy (Throwing es :> api :> apis) + -> (forall x. mon x -> mon' x) + -> Client mon (Throwing es :> api :> apis) + -> Client mon' (ThrowingNonterminal (Throwing es :> api :> apis)) + hoistClientMonad pm _ = + hoistClientMonad pm (Proxy @(ThrowingNonterminal (Throwing es :> api :> apis))) + + -- | When 'NoThrow' comes before any other combinator, push it down so it is -- closer to the 'Verb'. instance (RunClient m, HasClient m (api :> NoThrow :> apis)) => @@ -144,3 +205,12 @@ instance (RunClient m, HasClient m (api :> NoThrow :> apis)) => -> Client m (api :> NoThrow :> apis) clientWithRoute p _ = clientWithRoute p (Proxy :: Proxy (api :> NoThrow :> apis)) + + hoistClientMonad + :: Proxy m + -> Proxy (NoThrow :> api :> apis) + -> (forall x. mon x -> mon' x) + -> Client mon (NoThrow :> api :> apis) + -> Client mon' (api :> NoThrow :> apis) + hoistClientMonad pm _ = + hoistClientMonad pm (Proxy @(api :> NoThrow :> apis)) diff --git a/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Server.hs b/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Server.hs index f66f891..d7cbadb 100644 --- a/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Server.hs +++ b/servant-checked-exceptions/src/Servant/Checked/Exceptions/Internal/Servant/Server.hs @@ -45,13 +45,12 @@ import Servant.API.ContentTypes ) import Servant.Server.Internal (ct_wildcard) import Servant.Server.Internal.Router (Router, Router', leafRouter) -import Servant.Server.Internal.RoutingApplication +import Servant.Server.Internal.RouteResult (RouteResult(FailFatal, Route)) +import Servant.Server.Internal.DelayedIO (DelayedIO, delayedFail) +import Servant.Server.Internal.Delayed ( Delayed - , DelayedIO - , RouteResult(FailFatal, Route) , addAcceptCheck , addMethodCheck - , delayedFail , runAction ) import Servant @@ -90,8 +89,8 @@ instance (HasServer (Throwing '[e] :> api) context) => type ServerT (Throws e :> api) m = ServerT (Throwing '[e] :> api) m - hoistServerWithContext _ pc nt s = - hoistServerWithContext (Proxy :: Proxy (Throwing '[e] :> api)) pc nt s + hoistServerWithContext _ = + hoistServerWithContext (Proxy :: Proxy (Throwing '[e] :> api)) route :: Proxy (Throws e :> api) @@ -230,7 +229,7 @@ instance type ServerT (VerbWithErr method successStatus ctypes es a) m = m (Envelope es a) - hoistServerWithContext _ _ nt s = nt s + hoistServerWithContext _ _ nt = nt route :: Proxy (VerbWithErr method successStatus ctypes es a) @@ -317,4 +316,4 @@ processMethodRouter handleA status method headers request = case handleA of Just (contentT, body) -> Route $ responseLBS status hdrs bdy where bdy = if allowedMethodHead method request then "" else body - hdrs = (hContentType, LBS.toStrict contentT) : (fromMaybe [] headers) + hdrs = (hContentType, LBS.toStrict contentT) : fromMaybe [] headers diff --git a/stack.yaml b/stack.yaml index c0f9005..ea838c8 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,7 +1,7 @@ # For more information, see: http://docs.haskellstack.org/en/stable/yaml_configuration.html # Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2) -resolver: lts-11.4 +resolver: nightly-2019-04-05 # Local packages, usually specified by relative directory name packages: @@ -9,9 +9,7 @@ packages: - 'servant-checked-exceptions-core' # Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3) -extra-deps: -# This should be available in nightly sometime after 2018/3/12. -- world-peace-0.1.0.0 +extra-deps: [] # Override default flag values for local packages and extra-deps flags: {}