Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to network 3.0 with backward compatibility for network <= 2.8 #98

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions Database/MongoDB/Connection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import Control.Applicative ((<$>))
#endif

import Control.Monad (forM_)
import Network (HostName, PortID(..), connectTo)
import System.IO.Unsafe (unsafePerformIO)
import System.Timeout (timeout)
import Text.ParserCombinators.Parsec (parse, many1, letter, digit, char, eof,
Expand All @@ -48,6 +47,7 @@ import Data.Text (Text)
import qualified Data.Bson as B
import qualified Data.Text as T

import Database.MongoDB.Internal.Network (HostName, PortID(..), connectTo)
import Database.MongoDB.Internal.Protocol (Pipe, newPipe, close, isClosed)
import Database.MongoDB.Internal.Util (untilSuccess, liftIOE,
updateAssocs, shuffle, mergesortM)
Expand Down Expand Up @@ -79,11 +79,7 @@ showHostPort :: Host -> String
-- TODO: Distinguish Service and UnixSocket port
showHostPort (Host hostname port) = hostname ++ ":" ++ portname where
portname = case port of
Service s -> s
PortNumber p -> show p
#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
UnixSocket s -> s
#endif

readHostPortM :: (Monad m) => String -> m Host
-- ^ Read string \"hostname:port\" as @Host hosthame (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Fail if string does not match either syntax.
Expand Down
32 changes: 32 additions & 0 deletions Database/MongoDB/Internal/Network.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-- | Compatibility layer for network package, including newtype 'PortID'
{-# LANGUAGE CPP, PackageImports #-}

module Database.MongoDB.Internal.Network (PortID(..), N.HostName, connectTo) where

import Control.Exception (bracketOnError)
import Network.BSD as BSD
import System.IO (Handle, IOMode(ReadWriteMode))

#if !MIN_VERSION_network(2, 8, 0)
import qualified Network as N
#else
import qualified Network.Socket as N
#endif

newtype PortID = PortNumber N.PortNumber deriving (Show, Eq, Ord)

-- Taken from network 2.8's connectTo
-- https://github.com/haskell/network/blob/e73f0b96c9da924fe83f3c73488f7e69f712755f/Network.hs#L120-L129
connectTo :: N.HostName -- Hostname
-> PortID -- Port Identifier
-> IO Handle -- Connected Socket
connectTo hostname (PortNumber port) = do
proto <- BSD.getProtocolNumber "tcp"
bracketOnError
(N.socket N.AF_INET N.Stream proto)
(N.close) -- only done if there's an error
(\sock -> do
he <- BSD.getHostByName hostname
N.connect sock (N.SockAddrInet port (hostAddress he))
N.socketToHandle sock ReadWriteMode
)
11 changes: 1 addition & 10 deletions Database/MongoDB/Internal/Util.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
-- | Miscellaneous general functions and Show, Eq, and Ord instances for PortID
-- | Miscellaneous general functions

{-# LANGUAGE FlexibleInstances, UndecidableInstances, StandaloneDeriving #-}
{-# LANGUAGE CPP #-}
-- PortID instances
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Database.MongoDB.Internal.Util where

Expand All @@ -14,7 +12,6 @@ import Control.Exception (handle, throwIO, Exception)
import Control.Monad (liftM, liftM2)
import Data.Bits (Bits, (.|.))
import Data.Word (Word8)
import Network (PortID(..))
import Numeric (showHex)
import System.Random (newStdGen)
import System.Random.Shuffle (shuffle')
Expand All @@ -28,12 +25,6 @@ import Data.Text (Text)

import qualified Data.Text as T

#if !MIN_VERSION_network(2, 4, 1)
deriving instance Show PortID
deriving instance Eq PortID
#endif
deriving instance Ord PortID

-- | A monadic sort implementation derived from the non-monadic one in ghc's Prelude
mergesortM :: Monad m => (a -> a -> m Ordering) -> [a] -> m [a]
mergesortM cmp = mergesortM' cmp . map wrap
Expand Down
2 changes: 1 addition & 1 deletion Database/MongoDB/Transport/Tls.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import Database.MongoDB.Internal.Protocol (newPipeWith)
import Database.MongoDB.Transport (Transport(Transport))
import qualified Database.MongoDB.Transport as T
import System.IO.Error (mkIOError, eofErrorType)
import Network (connectTo, HostName, PortID)
import Database.MongoDB.Internal.Network (connectTo, HostName, PortID)
import qualified Network.TLS as TLS
import qualified Network.TLS.Extra.Cipher as TLS
import Database.MongoDB.Query (access, slaveOk, retrieveServerData)
Expand Down
16 changes: 15 additions & 1 deletion mongoDB.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ Build-type: Simple
Stability: alpha
Extra-Source-Files: CHANGELOG.md

-- Imitated from https://github.com/mongodb-haskell/bson/pull/18
Flag _old-network
description: Control whether to use <http://hackage.haskell.org/package/network-bsd network-bsd>
default: False
manual: False

Library
GHC-options: -Wall
default-language: Haskell2010
Expand Down Expand Up @@ -54,14 +60,22 @@ Library
, base64-bytestring >= 1.0.0.1
, nonce >= 1.0.5

if flag(_old-network)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@scott-fleischman Can you clarify for me who and how is supposed to set this flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are set using the cabal configuration flags as described here.

There are a couple choices involved here that I basically deferred to the choices made in the bson PR.

  1. The name of the flag. _old-network is pretty cryptic. I just copied it. If flags can contain numbers it might be better to name it something like use-network2 or something like that.
  2. Default value. Again I made it False by default but maybe until network-3.* gets into stackage, maybe the default should be true? Then when stackage includes network 3 by default in the newest stackage lts then mongoDB could ship a breaking change which changes the flag to true, so it defaults to using network3.

I don't believe the .cabal files themselves allow logic like conditional statements based on a library dependency version. In our case we would need to include a new library (network-bsd) if network is >=3.0, so that might not be possible without configure flags.

In the end, I am happy to consider alternatives to the approach taken in this PR with regards to cabal configuration. But as far as I can tell that is going to involve some user choice of which network to use.

You can see how I set them in the stack files, for example:
https://github.com/plow-technologies/mongodb/blob/f84cc035179198ed63a5e247aa7c95f61ce7a295/stack-ghc80.yaml#L2-L4

The flag is omitted here, so it defaults to using the network 3.0+ and network-bsd dependencies.
https://github.com/plow-technologies/mongodb/blob/network-deprecations/stack-ghc86-network3.yaml

Copy link
Contributor Author

@scott-fleischman scott-fleischman Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe manual: False might be useful here though and would work out-of-the-box in both cases (network 2 or network 3). https://www.haskell.org/cabal/users-guide/developing-packages.html#pkg-field-flag-manual

By default, Cabal will first try to satisfy dependencies with the default flag value and then, if that is not possible, with the negated value. However, if the flag is manual, then the default value (which can be overridden by commandline flags) will be used.

Copy link
Contributor Author

@scott-fleischman scott-fleischman Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem to work for stack if I remove the explicit flag set. I get errors in the stack configure step.

cabal (cabal-install version 2.4.0.0) itself seems ok with it though. I was able to build using ghc 8.2.2 and it picked the old network configurations even though the _old-network flag defaults to False.

Copy link
Contributor Author

@scott-fleischman scott-fleischman Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So all in all, it seems to me the current approach seems pretty good given the various options I am aware of.

Stack users will have to set the flag explicitly for network <=2.8.
Cabal users should work fine as-is. (I'm not sure how to test against the newer network because I'm not sure how to get cabal to know about the bson PR, which it would need to for network3.)

So with defaulting the flag to false, stack users of network 2.8 will have to explicitly set it to true (or explicitly include network 3). When the stackage lts includes network 3, then can remove the explicit flag from their configuration.

Cabal users should work fine in both cases. When network 3 is available for their configuration (needs bson available that works with network 3), since the _old-network flag default to True, it will try the network 3 config first, so it will use that. Else it default to the old network configuration and builds fine. I tested with ghc 8.2.2 and ghc 8.6.5 with cabal 2.4.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a reference to the conditional options in a cabal file: https://www.haskell.org/cabal/users-guide/developing-packages.html#conditions

-- "Network.BSD" is only available in network < 2.9
build-depends: network < 2.9
else
-- "Network.BSD" has been moved into its own package `network-bsd`
build-depends: network-bsd >= 2.7 && < 2.9

Exposed-modules: Database.MongoDB
Database.MongoDB.Admin
Database.MongoDB.Connection
Database.MongoDB.GridFS
Database.MongoDB.Query
Database.MongoDB.Transport
Database.MongoDB.Transport.Tls
Other-modules: Database.MongoDB.Internal.Protocol
Other-modules: Database.MongoDB.Internal.Network
Database.MongoDB.Internal.Protocol
Database.MongoDB.Internal.Util

Source-repository head
Expand Down
4 changes: 4 additions & 0 deletions stack-ghc80.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: lts-9.21
flags:
mongoDB:
_old-network: true
4 changes: 4 additions & 0 deletions stack-ghc82.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: lts-11.22
flags:
mongoDB:
_old-network: true
4 changes: 4 additions & 0 deletions stack-ghc84.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: lts-12.26
flags:
mongoDB:
_old-network: true
6 changes: 6 additions & 0 deletions stack-ghc86-network3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resolver: lts-13.23
extra-deps:
- git: [email protected]:hvr/bson.git # https://github.com/mongodb-haskell/bson/pull/18
commit: 2fc8d04120c0758201762b8e22254aeb6d574f41
- network-bsd-2.8.1.0
- network-3.1.0.0
4 changes: 4 additions & 0 deletions stack-ghc86.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: lts-13.23
flags:
mongoDB:
_old-network: true