ide-backend-common 0.10.1.1 → 0.10.1.2
raw patch · 10 files changed
+470/−59 lines, 10 filesdep +Win32dep +base64-bytestringdep +networkdep ~aesondep ~async
Dependencies added: Win32, base64-bytestring, network, process, time, unix-compat
Dependency ranges changed: aeson, async
Files
- ChangeLog.md +3/−0
- IdeSession/RPC/Server.hs +13/−20
- IdeSession/RPC/Sockets.hs +77/−0
- IdeSession/RPC/Stream.hs +19/−9
- IdeSession/Types/Public.hs +15/−4
- IdeSession/Util.hs +42/−20
- IdeSession/Util/PortableFiles.hs +71/−0
- IdeSession/Util/PortableIO.hs +129/−0
- IdeSession/Util/PortableProcess.hs +81/−0
- ide-backend-common.cabal +20/−6
+ ChangeLog.md view
@@ -0,0 +1,3 @@+## 0.10.1++* Fix build failure with pretty-show 1.6.9 due to orphan instances
IdeSession/RPC/Server.hs view
@@ -13,8 +13,6 @@ , hSetBuffering , BufferMode(BlockBuffering) )-import System.Posix.Types (Fd)-import System.Posix.IO (closeFd, fdToHandle) import Control.Monad (void) import qualified Control.Exception as Ex import Control.Concurrent (threadDelay)@@ -23,9 +21,12 @@ import Control.Concurrent.Async (Async, async) import Data.Binary (encode, decode) +import Network+ import IdeSession.Util.BlockingOps (readChan, wait, waitAny) import IdeSession.RPC.API import IdeSession.RPC.Stream+import IdeSession.RPC.Sockets -------------------------------------------------------------------------------- -- Server-side API --@@ -43,32 +44,24 @@ -> [String] -- ^ Command line args -> IO () rpcServer handler args = do- let readFd :: String -> Fd- readFd fd = fromIntegral (read fd :: Int)-- let errorLog : fds = args- [requestR, requestW, responseR, responseW] = map readFd fds+ let errorLog : ports = args+ [request, response] = map stringToPort ports - closeFd requestW- closeFd responseR- requestR' <- fdToHandle requestR- responseW' <- fdToHandle responseW+ request' <- connectToPort request+ response' <- connectToPort response - rpcServer' requestR' responseW' errorLog handler+ rpcServer' request' response' errorLog handler -- | Start a concurrent conversation.-concurrentConversation :: FilePath -- ^ stdin named pipe- -> FilePath -- ^ stdout named pipe+concurrentConversation :: Socket -- ^ input, stdin named pipe on unix+ -> Socket -- ^ output, stdout named pipe on unix -> FilePath -- ^ log file for exceptions -> (FilePath -> RpcConversation -> IO ()) -> IO ()-concurrentConversation requestR responseW errorLog server = do- hin <- openPipeForReading requestR timeout- hout <- openPipeForWriting responseW timeout+concurrentConversation request response errorLog server = do+ hin <- acceptHandle request+ hout <- acceptHandle response rpcServer' hin hout errorLog server- where- timeout :: Int- timeout = maxBound -- | Start the RPC server rpcServer' :: Handle -- ^ Input
+ IdeSession/RPC/Sockets.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE CPP, StandaloneDeriving, DeriveGeneric, DeriveDataTypeable #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- This module provies an interface for using sockets in RPC communication.+module IdeSession.RPC.Sockets (+ portToString+ , makeSocket+ , connectToPort+ , stringToPort+ , acceptHandle+ , ReadChannel(..)+ , WriteChannel(..)+) where++import System.IO (Handle)++import GHC.Generics (Generic)+import Data.Typeable (Typeable)+import Data.Binary+import Network+import Data.ByteString.Lazy.Char8+import qualified Data.ByteString.Base64.Lazy as Base64+import Network.Socket hiding (close, sClose, accept, socketPort)++#ifdef VERSION_unix+-- import Control.Exception+-- import Control.Concurrent.MVar+import System.IO.Temp (createTempDirectory)+import System.FilePath ((</>))+import System.Directory (getTemporaryDirectory)+#endif++newtype ReadChannel = ReadChannel PortID deriving (Generic, Typeable)+newtype WriteChannel = WriteChannel PortID deriving (Generic, Typeable)++instance Binary ReadChannel+instance Binary WriteChannel++-- Creating a socket with auto generated port (or file in case Unix domain+-- sockets are used)+makeSocket :: IO Socket++#ifdef VERSION_unix+makeSocket = do+ tmpDir <- getTemporaryDirectory+ rpcDir <- createTempDirectory tmpDir "ide-backend-rpc."+ let rpcFile = rpcDir </> "rpc"+ s <- listenOn $ UnixSocket rpcFile+ p <- socketPort s+ return s+++#else+{- On non-Unix we use a plain socket -}+makeSocket = listenOn $ PortNumber aNY_PORT+#endif++connectToPort :: PortID -> IO Handle+connectToPort = connectTo "localhost"++acceptHandle :: Socket -> IO Handle+acceptHandle s = do+ (h, _, _) <- accept s+ return h++portToString :: PortID -> String+portToString = unpack . Base64.encode . encode++stringToPort :: String -> PortID+stringToPort = decode . Base64.decodeLenient . pack+++{- Orphans -}+deriving instance Generic PortID+deriving instance Generic PortNumber+instance Binary PortID+instance Binary PortNumber
IdeSession/RPC/Stream.hs view
@@ -7,7 +7,7 @@ ) where import Prelude hiding (take)-import System.IO (Handle)+import System.IO (Handle, hIsEOF) import qualified Control.Exception as Ex import qualified Data.ByteString.Lazy.Internal as BSL import qualified Data.ByteString as BSS@@ -31,20 +31,30 @@ go atEnd decoder = case decoder of Binary.Fail _ _ err -> do writeIORef st decoder- Ex.throwIO $ userError $+ throwUserError $ if atEnd- then "IdeSession.RPC.Stream ended, causing " ++ err+ then "IdeSession.RPC.Stream ended, causing: " ++ err else "IdeSession.RPC.Stream decode failure: " ++ err Binary.Partial k -> do- mchunk <- Ex.try $ BSS.hGetSome h BSL.defaultChunkSize- case mchunk of- Left ex -> do writeIORef st decoder- Ex.throwIO (ex :: Ex.SomeException)- Right chunk | BSS.null chunk -> go True . k $ Nothing- | otherwise -> go False . k $ Just chunk+ eof <- hIsEOF h+ -- For some reason doing this check helps avoiding race conditions in+ -- in various scenarios when the server is force terminated.+ -- E.g., the tests in SessionRestart.hs+ if eof then throwUserError "IdeSession.RPC.Stream input handle closed unexpectedly"+ else do+ mchunk <- Ex.try $ BSS.hGetSome h BSL.defaultChunkSize+ case mchunk of+ Left (ex :: Ex.SomeException) -> do+ writeIORef st decoder+ -- wrapping with a user error so that it's easier to catch later on+ throwUserError $ "IdeSession.RPC.Stream ended unexpectedly, causing: " ++ show ex+ Right chunk | BSS.null chunk -> go True . k $ Nothing+ | otherwise -> go False . k $ Just chunk Binary.Done unused _numConsumed a -> do writeIORef st $ contDecoder unused return a contDecoder :: BSS.ByteString -> Binary.Decoder a contDecoder = Binary.pushChunk (Binary.runGetIncremental Binary.get)++ throwUserError = Ex.throwIO . userError
IdeSession/Types/Public.hs view
@@ -255,12 +255,23 @@ -- | This type represents the status of the compilation from an IDE update. data UpdateStatus =- UpdateStatusFailed Text- | UpdateStatusRequiredRestart- | UpdateStatusCrashRestart Text- | UpdateStatusServerDied Text+ -- | Indicates that the server is restarting because it needs to to fulfil the+ -- update.+ UpdateStatusRequiredRestart+ -- | Indicates that this update has caused the server to start again, since it+ -- died last update.+ | UpdateStatusErrorRestart Text+ -- | Gives compilation progress updates. | UpdateStatusProgress Progress++ -- | The update completed successfully. | UpdateStatusDone+ -- | The update failed, yielding an error. No more status updates should come+ -- after this.+ | UpdateStatusFailed Text+ -- The server tried to restart, but failed to restart. No more status updates+ -- should come after this.+ | UpdateStatusFailedToRestart deriving (Typeable, Generic, Eq, Show) {------------------------------------------------------------------------------
IdeSession/Util.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, DeriveFunctor, DeriveGeneric, StandaloneDeriving, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, DeriveFunctor, DeriveGeneric, DeriveDataTypeable, StandaloneDeriving, GeneralizedNewtypeDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module IdeSession.Util ( -- * Misc util@@ -21,8 +21,11 @@ , swizzleStderr , redirectStderr , captureOutput- ) where+ , UnsupportedOnNonUnix(..)+ , ReqRunRpc(..)+) where +import Control.Exception import Control.Applicative ((<$>)) import Control.Monad (void, forM_, mplus) import Crypto.Classes (blockLength, initialCtx, updateCtx, finalize)@@ -37,20 +40,25 @@ import Data.Text (Text) import Data.Typeable (typeOf) import Foreign.C.Types (CFile)-import Foreign.Ptr (Ptr, castPtr, nullPtr)+import Foreign.Ptr (Ptr, castPtr, ) import GHC.Generics (Generic) import GHC.IO (unsafeUnmask) import System.Directory (createDirectoryIfMissing, removeFile, renameFile)-import System.Environment (getEnvironment)+import System.Environment (getEnvironment, setEnv, unsetEnv) import System.FilePath (splitFileName, (<.>), (</>)) import System.FilePath (splitSearchPath, searchPathSeparator) import System.IO import System.IO.Error (isDoesNotExistError)+import Data.Typeable (Typeable)+import Network++import Foreign.Ptr (nullPtr) import System.IO.Temp (withSystemTempFile)-import System.Posix (Fd)-import System.Posix.Env (setEnv, unsetEnv)-import System.Posix.IO-import System.Posix.Types (CPid(..))+import IdeSession.Util.PortableIO+import IdeSession.RPC.Sockets+import IdeSession.Util.PortableProcess++import System.PosixCompat.Types (CPid(..)) import Text.Show.Pretty import qualified Control.Exception as Ex import qualified Data.Attoparsec.Text as Att@@ -62,7 +70,6 @@ import qualified Data.ByteString.Lazy as BSL import qualified Data.Text as Text import qualified Data.Text.Foreign as Text-import qualified System.Posix.Files as Files import IdeSession.Strict.Container import qualified IdeSession.Strict.Map as StrictMap@@ -170,12 +177,14 @@ forM_ curEnv $ \(var, _val) -> unsetEnv var -- Restore initial environment- forM_ initEnv $ \(var, val) -> setEnv var val True+ forM_ initEnv $ \(var, val) -> setEnv var val+ -- previously used the Posix setEnv, which had an explicit flag for overwrites (set to True)+ -- not sure about the behavior of the portable version -- Apply overrides forM_ overrides $ \(var, mVal) -> case mVal of- Just val -> setEnv var val True+ Just val -> setEnv var val -- see comment about setEnv above Nothing -> unsetEnv var relInclToOpts :: FilePath -> [FilePath] -> [String]@@ -258,18 +267,17 @@ {------------------------------------------------------------------------------- Manipulations with stdout and stderr. -------------------------------------------------------------------------------}--swizzleStdout :: Fd -> IO a -> IO a+swizzleStdout :: FileDescriptor -> IO a -> IO a swizzleStdout = swizzleHandle (stdout, stdOutput) -swizzleStderr :: Fd -> IO a -> IO a+swizzleStderr :: FileDescriptor -> IO a -> IO a swizzleStderr = swizzleHandle (stderr, stdError) -swizzleHandle :: (Handle, Fd) -> Fd -> IO a -> IO a+swizzleHandle :: (Handle, FileDescriptor) -> FileDescriptor -> IO a -> IO a swizzleHandle (targetHandle, targetFd) fd act = Ex.bracket swizzle unswizzle (\_ -> act) where- swizzle :: IO Fd+ swizzle :: IO FileDescriptor swizzle = do -- Flush existing handles hFlush targetHandle@@ -281,7 +289,7 @@ return backup - unswizzle :: Fd -> IO ()+ unswizzle :: FileDescriptor -> IO () unswizzle backup = do -- Flush handles again hFlush targetHandle@@ -293,12 +301,10 @@ redirectStderr :: FilePath -> IO a -> IO a redirectStderr fp act = do- Ex.bracket (openFd fp WriteOnly (Just mode) defaultFileFlags)+ Ex.bracket (openWritableFile fp) closeFd $ \errorLogFd -> swizzleStderr errorLogFd $ act- where- mode = Files.unionFileModes Files.ownerReadMode Files.ownerWriteMode captureOutput :: IO a -> IO (String, a) captureOutput act = do@@ -308,6 +314,22 @@ closeFd fd suppressed <- readFile fp return (suppressed, a)++{-------------------------------------------------------------------------------+ Non-Unix compatibility+-------------------------------------------------------------------------------}++-- A data type for RPC communication when trying to run a @ReqRun@ value on the server+-- Encoding the possibility that the action is not supported+data ReqRunRpc = ReqRunConversation Pid WriteChannel ReadChannel FilePath+ | ReqRunUnsupported String+ deriving (Generic, Typeable)++instance Binary ReqRunRpc++newtype UnsupportedOnNonUnix = UnsupportedOnNonUnix String+ deriving (Typeable, Show)+instance Exception UnsupportedOnNonUnix {------------------------------------------------------------------------------- Orphans
+ IdeSession/Util/PortableFiles.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE CPP #-}+module IdeSession.Util.PortableFiles (+ setFileTimes+ , getFileStatus+ , modificationTime+ , toExecutable+ , moduleNameToExeName+) where+++import System.PosixCompat.Types+import System.PosixCompat.Files hiding (setFileTimes)++#ifdef VERSION_unix+import qualified System.Posix.Files as Posix+#else+import Foreign+import Data.Time.Clock.POSIX+import System.FilePath.Posix+import qualified System.Win32 as Win32+import Control.Exception (bracket)+#endif++setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()++-- Converts a module name to and executable file name+moduleNameToExeName :: String -> String++-- Converts a name of an a executable to the corresponding file name+toExecutable :: String -> String++#ifdef VERSION_unix++setFileTimes = Posix.setFileTimes++moduleNameToExeName = id++toExecutable = id++#else++-- Unlike `utime`, which doesn't work for directories on Windows, this works for both for files and directories+-- Mostly copied from @System.Directory@ 1.2.3.0+setFileTimes path atime mtime =+ bracket (openFileHandle path' Win32.gENERIC_WRITE)+ Win32.closeHandle $ \ handle ->+ with (posixToWindowsTime atime) $ \ atime' ->+ with (posixToWindowsTime mtime) $ \ mtime' ->+ Win32.failIf_ not "setFileTimes" $+ Win32.c_SetFileTime handle nullPtr atime' mtime'+ where+ path' = normalise path -- handle empty paths+ windowsPosixEpochDifference :: Num a => a+ windowsPosixEpochDifference = 116444736000000000+ posixToWindowsTime :: EpochTime -> Win32.FILETIME+ posixToWindowsTime t = Win32.FILETIME $+ truncate ((realToFrac t :: POSIXTime) * 10000000 + windowsPosixEpochDifference)+ openFileHandle :: String -> Win32.AccessMode -> IO Win32.HANDLE+ openFileHandle p mode = Win32.createFile p mode share Nothing+ Win32.oPEN_EXISTING flags Nothing+ where share = Win32.fILE_SHARE_DELETE+ .|. Win32.fILE_SHARE_READ+ .|. Win32.fILE_SHARE_WRITE+ flags = Win32.fILE_ATTRIBUTE_NORMAL+ .|. Win32.fILE_FLAG_BACKUP_SEMANTICS -- required for directories+++moduleNameToExeName = toExecutable++toExecutable e = e ++ ".exe"+#endif
+ IdeSession/Util/PortableIO.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE CPP, RecordWildCards #-}+module IdeSession.Util.PortableIO where++import System.IO (Handle, IOMode(..))++#ifdef VERSION_unix+import System.Posix.Types (Fd)+import qualified System.Posix.IO as Posix+import System.Posix.Files+#else+import Foreign.C.Error (throwErrnoIfMinus1_, throwErrnoIfMinus1)+import Foreign.C.Types (CInt(..), CUInt(..))+import Foreign.Ptr (Ptr)+import Foreign.Marshal.Array (allocaArray)+import Foreign.Storable (peek, peekElemOff)+import GHC.IO.FD (mkFD)+import GHC.IO.Device (IODeviceType(Stream))+import GHC.IO.Handle.FD (mkHandleFromFD)+import System.IO (openFile)++{- For the reimplementation of handleToFd from System.Posix.IO -}+import System.IO.Error+import GHC.IO.Handle.Internals+import GHC.IO.Handle.Types hiding (Handle)+import qualified GHC.IO.FD as FD+import GHC.IO.Exception+import Data.Typeable (cast)+#endif++#ifdef VERSION_unix+type FileDescriptor = Fd+#else+type FileDescriptor = CInt+#endif++createPipe :: IO (FileDescriptor, FileDescriptor)+fdToHandle :: FileDescriptor -> IOMode -> IO Handle+handleToFd :: Handle -> IO FileDescriptor+closeFd :: FileDescriptor -> IO ()++dup :: FileDescriptor -> IO FileDescriptor+dupTo :: FileDescriptor -> FileDescriptor -> IO FileDescriptor++-- Opens, and possibly creates, the given file for writing+openWritableFile :: FilePath -> IO FileDescriptor++stdInput, stdOutput, stdError :: FileDescriptor++#ifdef VERSION_unix++createPipe = Posix.createPipe+fdToHandle fd _ = Posix.fdToHandle fd+handleToFd = Posix.handleToFd+closeFd = Posix.closeFd++dup = Posix.dup+dupTo = Posix.dupTo++openWritableFile fp = Posix.openFd fp Posix.WriteOnly (Just mode) Posix.defaultFileFlags+ where+ mode = unionFileModes ownerReadMode ownerWriteMode++stdInput = Posix.stdInput+stdOutput = Posix.stdOutput+stdError = Posix.stdError++#else++createPipe = allocaArray 2 $ \pfds -> do+ throwErrnoIfMinus1_ "_pipe" $ c__pipe pfds 2 ({- _O_BINARY -} 32768)+ readfd <- peek pfds+ writefd <- peekElemOff pfds 1+ return (readfd, writefd)++fdToHandle fd mode = do+ (fd', deviceType) <- mkFD fd mode (Just (Stream, 0, 0)) False False+ mkHandleFromFD fd' deviceType "" mode False Nothing++closeFd = throwErrnoIfMinus1_ "_close" . c__close++dup = throwErrnoIfMinus1 "_dup" . c__dup++dupTo fd1 fd2 = throwErrnoIfMinus1 "_dup2" $ c__dup2 fd1 fd2++-- Previously this was a ccall to '_open' in 'io.h'+-- TODO could this implementation work for the Unix version?+openWritableFile fp = openFile fp WriteMode >>= handleToFd++stdInput = 0+stdOutput = 1+stdError = 2++{- Copied from System.Posix.IO -}+handleToFd h@(FileHandle _ m) =+ withHandle' "handleToFd" h m $ handleToFd' h+handleToFd h@(DuplexHandle _ r w) = do+ _ <- withHandle' "handleToFd" h r $ handleToFd' h+ withHandle' "handleToFd" h w $ handleToFd' h+ -- for a DuplexHandle, make sure we mark both sides as closed,+ -- otherwise a finalizer will come along later and close the other+ -- side. (#3914)++handleToFd' :: Handle -> Handle__ -> IO (Handle__, FileDescriptor)+handleToFd' h h_@Handle__{haType=_,..} =+ case cast haDevice of+ Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation+ "handleToFd" (Just h) Nothing)+ "handle is not a file descriptor")+ Just fd -> do+ -- converting a Handle into an Fd effectively means+ -- letting go of the Handle; it is put into a closed+ -- state as a result.+ flushWriteBuffer h_+ FD.release fd+ return (Handle__{haType=ClosedHandle,..}, FD.fdFD fd)++foreign import ccall "io.h _pipe" c__pipe ::+ Ptr CInt -> CUInt -> CInt -> IO CInt++foreign import ccall "io.h _close" c__close ::+ CInt -> IO CInt++foreign import ccall "io.h _dup" c__dup ::+ CInt -> IO CInt++foreign import ccall "io.h _dup2" c__dup2 ::+ CInt -> CInt -> IO CInt++#endif
+ IdeSession/Util/PortableProcess.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE CPP #-}+module IdeSession.Util.PortableProcess where++import System.Process (ProcessHandle)++#ifdef VERSION_unix+import System.Posix.Signals+import System.Posix.Types+import System.Process.Internals (withProcessHandle, ProcessHandle__(..))+#else+import System.Process+import System.Process.Internals hiding (ProcessHandle)+import System.Win32 hiding (ProcessHandle)+#endif++#ifdef VERSION_unix+type Pid = ProcessID+#else+type Pid = ProcessId+#endif++-- Attempts to kill the process, on Unix using sigKILL+sigKillProcess :: Pid -> IO ()++-- Attempts to terminate the process, on Unix using sigTERM+sigTermProcess :: Pid -> IO ()++-- Raises a sigKILL+raiseSigKill :: IO ()++-- The exit code for sigKILL+sigKillExitCode :: Int++-- If available sends a sigKill to the given process handle+killProcessHandle :: ProcessHandle -> IO ()+++#ifdef VERSION_unix+sigKillProcess = signalProcess sigKILL+sigTermProcess = signalProcess sigTERM+raiseSigKill = raiseSignal sigKILL+sigKillExitCode = -9++killProcessHandle ph = withProcessHandle ph $ \p_ ->+ case p_ of+ ClosedHandle _ ->+ leaveHandleAsIs p_+ OpenHandle pID -> do+ signalProcess sigKILL pID+ leaveHandleAsIs p_+ where+ leaveHandleAsIs _p =+#if MIN_VERSION_process(1,2,0)+ return ()+#else+ return (_p, ())+#endif++#else+-- On Windows, we just terminate, no special support for sigKILL+sigKillProcess = sigTermProcess+sigTermProcess pid = do+ ptr <- openProcess pROCESS_TERMINATE False pid+ ph <- mkProcessHandle ptr+ terminateProcess ph++sigKillExitCode = 1++-- On Windows, no special support for sigKill+killProcessHandle = terminateProcess++foreign import ccall unsafe "winbase.h GetCurrentProcessId"+ c_GetCurrentProcessId :: IO DWORD++getCurrentPid :: IO Pid+getCurrentPid = c_GetCurrentProcessId++raiseSigKill = do+ pid <- getCurrentPid+ sigKillProcess pid+#endif
ide-backend-common.cabal view
@@ -1,5 +1,5 @@ name: ide-backend-common-version: 0.10.1.1+version: 0.10.1.2 synopsis: Shared library used be ide-backend and ide-backend-server description: Should not be used by end users license: MIT@@ -10,19 +10,23 @@ category: Development build-type: Simple cabal-version: >=1.10-extra-source-files: README.md+extra-source-files: README.md ChangeLog.md library exposed-modules: IdeSession.Util IdeSession.Util.BlockingOps IdeSession.Util.Logger IdeSession.Util.PrettyVal+ IdeSession.Util.PortableProcess+ IdeSession.Util.PortableIO+ IdeSession.Util.PortableFiles IdeSession.GHC.API IdeSession.GHC.Requests IdeSession.GHC.Responses IdeSession.RPC.API IdeSession.RPC.Server IdeSession.RPC.Stream+ IdeSession.RPC.Sockets IdeSession.Strict.Container IdeSession.Strict.IntMap IdeSession.Strict.List@@ -45,9 +49,8 @@ containers >= 0.4.2 && < 1, bytestring >= 0.9.2 && < 1, mtl >= 2.1 && < 2.3,- async >= 2.0 && < 2.1,- aeson >= 0.6.2 && < 0.10,- unix >= 2.5 && < 2.8,+ async >= 2.0 && < 2.2,+ aeson >= 0.6.2 && < 0.11, temporary >= 1.1.2.4 && < 1.3, bytestring-trie >= 0.2 && < 0.3, text >= 0.11 && < 1.3,@@ -61,8 +64,13 @@ attoparsec >= 0.10 && < 0.14, template-haskell, pretty-show >= 1.3 && < 1.7,- monad-logger+ monad-logger,+ unix-compat >= 0.4.1.1 && < 0.4.2,+ network,+ process,+ base64-bytestring + -- GHC.Generics lived in `ghc-prim` for GHC 7.2 & GHC 7.4 if impl(ghc < 7.6) build-depends: ghc-prim == 0.2.*@@ -89,3 +97,9 @@ TypeSynonymInstances ghc-options: -Wall -fno-warn-unused-do-bind++ if os(windows)+ build-depends: Win32,+ time+ else+ build-depends: unix >= 2.5 && < 2.8