uni-posixutil (empty) → 2.2.0.0
raw patch · 8 files changed
+847/−0 lines, 8 filesdep +basedep +directorydep +processsetup-changed
Dependencies added: base, directory, process, uni-events, uni-util, unix
Files
- LICENSE +123/−0
- Posixutil/BlockSigPIPE.hs +20/−0
- Posixutil/ChildProcess.hs +370/−0
- Posixutil/CopyFile.hs +186/−0
- Posixutil/ProcessClasses.hs +46/−0
- Posixutil/SafeSystem.hs +64/−0
- Setup.hs +2/−0
- uni-posixutil.cabal +36/−0
+ LICENSE view
@@ -0,0 +1,123 @@+License Agreement++Preamble++The aim of this licence agreement is to enable the free use of the+software that is described in the sequel by anyone. In order to+guarantee this, it is necessary to set up rules for the use of the+software that hold for any user.++Provider of this licence is the University of Bremen, represented by+its principal (called "licence provider" in the sequel). The provider+of the licence has developed the "Uniform Workbench" (just+called "software" in the sequel). The software includes a+graphical tool for accessing documents stored in a versioned repository,+but also contains libraries and some other tools.++Following the ideas of open source software, the licence provider+gives access to the software without fee for anyone (called "licence+taker" in the sequel) under the following conditions which are similar+to the Lesser Gnu Public License (LGPL). Each licence taker obligates+himself to follow the terms of use below.++++1 Principle++Each licence taker appreciating these terms of use receives a simple+right, not resctricted in time and space and without any fee, to use+the software, in particular, to copy, distribute and process+it. Exclusively the following terms of use do hold. The licence+provider explicitly contradicts any conflicting terms of business. By+making use of the rights described below, in particular by copying or+distributing it, a licence treaty between the licence provider and the+licence takes is concluded.++++2 Copying++The licence taker has the right to make and distribute unmodified+copies of the software on any media. Prerequisite for this is that the+licence provider and this licence agreement is clearly recognizable,+and that the sources are distributed together with the software.++++3 Modification and Distribution++The licence taker has the right to modify copies of the software (or+parts thereof) and to distribute these modifications under the terms+of 2 above and the following conditions:++1. The modified software has to carry a clear mark that points to the+original licence provider, the modification that has been made, and+the date of the modification.++2. The licence taker has to ensure that the software as a whole or+parts of it are accessible to third parties under the terms of this+licence agreement without fee.++3. If during the modification a copyright of the licence taker+emerges, then this copyright must be put under the terms of this+licence if the modified software is distributed.+++4 Other duties++1. Reference to the validity of this licence agreement must not be+modified or deleted by the licence taker.++2. The use of the software by third parties must not be conditioned by+the fulfilment of duties that are not mentioned in this licence+agreement.++3. The use of the software must not be prevented or complicated by+means fo technical protection, in particular copy protection means.++++5 Liability, Update++1. Liability of the licence provider is restriced to fraudulent+withheld factual or legal errors. The licence provider does not give+any warranty, and neither ensures any properties of the+software. Furthermore, he is liable only for those damages that are+caused by willful or grossly negligent violation of duty.++2. The licence provider has the right to update these terms of use at+any time.+++++6 Forum for users++The licence provider does provide neither support nor+consultation. Without acknowledgement of any legal duty, the licence+provider will care about the installation of a user forum for+discussions about the software and its further development.+++7 Legal domicile++It is agreed that the law of the Federal Republic of Germany is valid+for this licence agreement. For any lawsuits or legal actions emerging+from this licence agreement, it is agreed that exclusively German+courts are competent. Legal domicile is Bremen.+++8 Termination through Offence++Any violation of a duty of this agreement automatically terminates the+rights of use of the offender.++++9 Salvatorian Clause++If any rule of this agreement should be or become inoperative,+validity of the other rules is not affected. The parties will care+about replacing the invalid rule by some valid rule that comes close+to the purpose of this agreement.+
+ Posixutil/BlockSigPIPE.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE CPP #-}+-- | Module that should also compile on Windows for blocking sigPIPE on+-- Unix, something you need to do to avoid the entire system crashing when+-- a pipe is closed.+module Posixutil.BlockSigPIPE(+ blockSigPIPE, -- :: IO ()+ ) where++import Util.Computation++#ifndef WINDOWS+import System.Posix.Signals+#endif++blockSigPIPE :: IO ()+blockSigPIPE = do+#ifndef WINDOWS+ installHandler sigPIPE Ignore Nothing+#endif+ done
+ Posixutil/ChildProcess.hs view
@@ -0,0 +1,370 @@+-- |+-- Description: Calling other programs.+--+-- Calling other programs.+--+-- This module now serves basically as an interface to GHC's new+-- System.Process module.+module Posixutil.ChildProcess (+ ChildProcess,+ PosixProcess, -- holds information about a process to be created++ ChildProcessStatus(ChildExited,ChildTerminated),++ -- linemode, arguments, &c encode configuration options for+ -- a process to be created. Various functions for creating new+ -- processes take a [Config PosixProcess] as an argument.+ -- In particular newChildProcess does.+ linemode, -- :: Bool -> Config PosixProcess+ -- for meaning of linemode see readMsg.+ arguments, -- :: [String] -> Config PosixProcess+ appendArguments,-- :: [String] -> Config PosixProcess+ environment, -- :: [(String,String)] -> Config PosixProcess+ standarderrors, -- :: Bool -> Config PosixProcess+ -- if standarderrors is true, we send stderr to the childprocesses+ -- out channel (of which there is only one). Otherwise we+ -- display them, with the name of the responsible process,+ -- on our stderr.+ challengeResponse, -- :: (String,String) -> Config PosixProcess+ -- Set a "challenge" and "response". Each is given as a String.+ -- The challenge (first String) will have newline appended if in line-mode.+ -- However the response will always be expected exactly as is.+ toolName, -- :: String -> Config PosixProcess+ -- The name of the tool, used in error messages and in the debug file.++ newChildProcess, -- :: FilePath -> [Config PosixProcess] -> IO ChildProcess+++ sendMsg, -- :: ChildProcess -> String -> IO ()+ -- sendMsg sends a String to the ChildProcess, adding a new line+ -- for line mode.++ sendMsgRaw, -- :: ChildProcess -> CStringLen -> IO ()+ -- sendMsgRaw writes a CStringLen+ -- to the child process. It does not append a newline.++ readMsg, -- :: ChildProcess -> IO String++ waitForChildProcess, -- :: ChildProcess -> IO ChildProcessStatus+ -- waits until the ChildProcess exits or is terminated+ )+where++import System.IO+import System.IO.Error as IO++import Foreign.C.String+import System.Exit+import System.Process+import Control.Concurrent+import qualified Control.Exception as Exception++import Util.Computation+import Util.CompileFlags+import Util.Object+import Util.IOExtras+import Util.Debug+import Util.FileNames++import Events.Destructible++import Posixutil.BlockSigPIPE+import Posixutil.ProcessClasses++-- --------------------------------------------------------------------------+-- Tool Parameters+-- --------------------------------------------------------------------------++-- | Describes configuration options for the process.+data PosixProcess =+ PosixProcess {+ args :: [String],+ ppenv :: Maybe [(String, String)],+ lmode :: Bool, -- line mode+ includestderr :: Bool, -- include stderr+ cresponse :: Maybe (String,String),+ toolname :: Maybe String+ }++-- | Initial configuration options.+defaultPosixProcess :: PosixProcess+defaultPosixProcess =+ PosixProcess {+ args = [],+ ppenv = Nothing,+ lmode = True,+ includestderr = True,+ cresponse = Nothing,+ toolname = Nothing+ }+++-- | If 'True', 'readMsg' returns lines, otherwise it returs the first input+-- that's available+linemode :: Bool -> Config PosixProcess+linemode lm' parms = return parms{lmode = lm'}++-- | Set command arguments+arguments :: [String] -> Config PosixProcess+arguments args' parms = return parms{args = args'}++-- | Append command arguments+appendArguments :: [String] -> Config PosixProcess+appendArguments args' parms = return parms{args = (args parms) ++ args'}++-- | Set the process' environment.+environment :: [(String,String)] -> Config PosixProcess+environment env' parms = return parms{ppenv = Just env'}++-- if 'True', we send stderr to the childprocesses+-- out channel (of which there is only one). Otherwise we+-- display them, with the name of the responsible process,+-- on our stderr.+standarderrors :: Bool -> Config PosixProcess+standarderrors err' parms = return parms{includestderr = err'}++-- | Set a "challenge" and "response". This is used as a test+-- when the tool starts up, to make sure that everything is+-- working properly.+---+-- The challenge (first String) will have newline appended if in line-mode.+-- However the response will always be expected exactly as is.+challengeResponse :: (String,String) -> Config PosixProcess+challengeResponse cr parms = return parms {cresponse = Just cr}++-- | The name of the tool, used in error messages and in the debug file.+toolName :: String -> Config PosixProcess+toolName n parms = return parms {toolname = Just n}+++-- -------------------------------------------------------------------------+-- Data Declaration+-- -------------------------------------------------------------------------++-- | A running process+data ChildProcess = ChildProcess {+ processHandle :: ProcessHandle,+ -- | GHC's handle to the process.++ processIn :: Handle,+ processOutput :: Chan String,++ childObjectID :: ObjectID,+ lineMode :: Bool,+ -- | if True readMsg returns lines, otherwise+ -- it returns the first input that's available.+ toolTitle :: String+ -- Title of the tool, derived from the file name or+ -- supplied by the toolName function,+ -- used in the debugging file.+ }++-- | Status if a process+data ChildProcessStatus = ChildExited ExitCode+ | ChildTerminated+ deriving (Eq, Ord, Show)++-- -------------------------------------------------------------------------+-- Initialising+-- -------------------------------------------------------------------------++-- | Starting a new 'ChildProcess'+newChildProcess :: FilePath -> [Config PosixProcess] -> IO ChildProcess+newChildProcess filePath configurations =+ do+ parms <- configure defaultPosixProcess configurations++ debug("newChildProcess:")+ debug(filePath:(args parms))++ blockSigPIPE++ -- run the process.+ (processIn,processOut,processErr,processHandle) <- runInteractiveProcess+ filePath (args parms) Nothing (ppenv parms)++ childObjectID <- newObject++ processOutput <- newChan++ let+ toolTitle :: String+ toolTitle =+ case (toolname parms,splitName filePath) of+ (Just toolTitle,_) -> toolTitle+ (Nothing,(dir,toolTitle)) -> toolTitle++ lineMode :: Bool+ lineMode = lmode parms++ getFn :: Handle -> IO String+ getFn = if lineMode then hGetLine else getAvail++ -- Worker thread which reads input from the tool and sends it to+ -- processOutput+ monitorHandle :: Handle -> IO ()+ monitorHandle handle =+ foreverUntil (+ do+ nextOrEOF <- catchEOF (getFn handle)+ case nextOrEOF of+ Nothing -> return True+ Just line ->+ do+ debugRead childProcess (line ++ "\n")+ writeChan processOutput line+ return False+ )++ -- Worker thread which reads input from the tool (in fact, stderr)+ -- and reports it.+ reportErrors :: IO ()+ reportErrors =+ foreverUntil (+ do+ nextOrEOF <- catchEOF (getFn processErr)+ case nextOrEOF of+ Nothing -> return True+ Just line ->+ do+ hPutStrLn stderr ("Error from " ++ toolTitle+ ++ ": " ++ line)+ hFlush stderr+ return False+ )++ getAvail :: Handle -> IO String+ getAvail handle =+ do+ c0 <- hGetChar handle -- force a wait if necessary+ getAvail0 [c0] handle++ getAvail0 :: String -> Handle -> IO String+ getAvail0 acc handle =+ do+ ready <- hReady handle+ if ready+ then+ do+ c <- hGetChar handle+ getAvail0 (c : acc) handle+ else+ return (reverse acc)++ childProcess = ChildProcess {+ processHandle = processHandle,+ processIn = processIn,+ processOutput = processOutput,+ childObjectID = childObjectID,+ lineMode = lineMode,+ toolTitle = toolTitle+ }++ -- Do challenge-response+ case cresponse parms of+ Nothing -> done+ Just (challenge,response) ->+ do+ sendMsg childProcess challenge+ responseLineOrError+ <- IO.try (mapM (const (hGetChar processOut))+ [1..length response])+ case responseLineOrError of+ Left excep -> error (+ "Starting " ++ toolTitle ++ " got IO error "+ ++ show excep)+ Right line -> if line == response+ then+ done+ else+ do+ remainder <- getAvail0 [] processOut+ error (+ "Starting " ++ toolTitle+ ++ " got unexpected response "+ ++ line ++ remainder+ )++ forkIO (monitorHandle processOut)+ if includestderr parms+ then+ forkIO (monitorHandle processErr)+ else+ forkIO (reportErrors)++ return childProcess++-- -------------------------------------------------------------------------+-- Communicating with the process+-- -------------------------------------------------------------------------++-- | Sends a String to the ChildProcess, adding a new line+-- for line mode.+sendMsg :: ChildProcess -> String -> IO ()+sendMsg childProcess line =+ do+ debugWrite childProcess line+ let+ lineToWrite =+ if lineMode childProcess then line ++ recordSep else line+ hPutStr (processIn childProcess) lineToWrite+ hFlush (processIn childProcess)++++-- | Writes a CStringLen+-- to the child process. It does not append a newline.+sendMsgRaw :: ChildProcess -> CStringLen -> IO ()+sendMsgRaw childProcess (cStrLn@(ptr,len)) =+ do+ if isDebug+ then+ do+ str <- peekCStringLen cStrLn+ debugWrite childProcess str+ else+ done+ hPutBuf (processIn childProcess) ptr len+ hFlush (processIn childProcess)++-- | Reads a string from the ChildProcess+readMsg :: ChildProcess -> IO String+readMsg childProcess = readChan (processOutput childProcess)++-- -------------------------------------------------------------------------+-- Waiting for a process+-- -------------------------------------------------------------------------++-- | Waits for the ChildProcess to exit or be terminated+waitForChildProcess :: ChildProcess -> IO ChildProcessStatus+waitForChildProcess p =+ Exception.catch (waitForChild p) (\_ -> return ChildTerminated)+ where+ waitForChild p = do+ exitCode <- waitForProcess (processHandle p)+ return (ChildExited exitCode)++-- -------------------------------------------------------------------------+-- Writing debugging information to a file+-- -------------------------------------------------------------------------++debugWrite :: ChildProcess -> String -> IO ()+debugWrite childProcess str =+ debugString (toolTitle childProcess++">"++str++"\n")++debugRead :: ChildProcess -> String -> IO ()+debugRead childProcess str =+ debugString (toolTitle childProcess++"<"++str++"\n")++-- -------------------------------------------------------------------------+-- Instances+-- -------------------------------------------------------------------------++instance Object ChildProcess where+ objectID = childObjectID++instance Destroyable ChildProcess where+ destroy childProcess = terminateProcess (processHandle childProcess)++instance Tool ChildProcess where+ getToolStatus childProcess = getProcessExitCode (processHandle childProcess)
+ Posixutil/CopyFile.hs view
@@ -0,0 +1,186 @@+-- | This contains functions for copying to and from files+module Posixutil.CopyFile(+ copyFile,+ copyFileWE,+ copyStringToFile,+ copyStringToFileCheck,+ copyFileToString,+ copyFileToStringCheck,+ copyICStringLenToFile,+ copyFileToICStringLenCheck,++ copyCStringLenToFile,+ copyFileToCStringLen,+ copyFileToICStringLen,+ ) where++import System.IO as IO+import System.IO.Error as IO+import qualified System.IO.Error as IOErr++import Foreign.C+import Control.Exception+import qualified System.Directory as Dir++import Util.Computation+import Util.ICStringLen+import Util.DeepSeq++-- amahnke: Supplemented C-Code by System.Directory.CopyFile:+--+-- foreign import ccall unsafe "copy_file.h copy_file" copyFilePrim+-- :: CString -> CString -> IO Int++copyFile :: String -> String -> IO ()+copyFile source destination =+ do+ unitWE <- copyFileWE source destination+ coerceWithErrorIO unitWE++copyFileWE :: String -> String -> IO (WithError ())+copyFileWE source destination =+ if source == destination+ then+ return (hasValue ())+ else+ IOErr.catch (do+ Dir.copyFile source destination+ return(hasValue()))+ (\ioErr ->+ let+ codeStr = if IOErr.isAlreadyExistsError ioErr+ then ("Can't write to " ++ destination ++ ". File already exists!")+ else if IOErr.isDoesNotExistError ioErr+ then ("Can't read from " ++ source ++ ". File doesn't exists!")+ else if IOErr.isPermissionError ioErr+ then ("Can't write to " ++ destination ++ ". Insufficient permissions!")+ else if IOErr.isFullError ioErr+ then ("Can't write to " ++ destination ++ ". Disk full!")+ else ("Something went wrong within copyFile.")+ in+ return(hasError codeStr)+ )+ {--+ code <-+ withCString source (\ sourcePrim ->+ withCString destination (\ destinationPrim ->+ copyFilePrim sourcePrim destinationPrim+ )+ )+ if (code<0)+ then+ let+ codeStr = case code of+ -- see includes/copy_file.h+ -1 -> "Can't read from "++source+ -2 -> "Can't write to "++destination+ -3 -> "Not enough memory to allocate buffer"+ _ -> "Unknown error!!"+ in+ return(hasError codeStr)+ else+ return(hasValue ())+--}++-- | Reads in a file to a String. NB - differs from readFile in that this+-- is done instantly, so we don\'t have to worry about semi-closed handles+-- hanging around.+copyFileToString :: FilePath -> IO String+copyFileToString filePath =+ do+ s <- IO.readFile filePath++-- (cString,len) <- copyFileToCStringLen filePath+-- string <- peekCStringLen (cString,len)+-- free cString+ s `deepSeq` (return s)++-- | Read in a file, catching certain errors+copyFileToStringCheck :: FilePath -> IO (WithError String)+copyFileToStringCheck filePath =+ exceptionToError+ (\ exception ->+ case ioErrors exception of+ Nothing -> Nothing+ Just ioError ->+ if IO.isDoesNotExistError ioError+ then+ Just "File does not exist"+ else if IO.isAlreadyInUseError ioError+ then+ Just "File is already in use"+ else if IO.isPermissionError ioError+ then+ Just "No read access to file"+ else+ Nothing+ )+ (copyFileToString filePath)++copyFileToCStringLen :: FilePath -> IO CStringLen+copyFileToCStringLen file =+ do+ str <- readFile file+ newCStringLen $!! str++copyFileToICStringLenCheck :: FilePath -> IO (WithError ICStringLen)+copyFileToICStringLenCheck filePath =+ exceptionToError+ (\ exception ->+ case ioErrors exception of+ Nothing -> Nothing+ Just ioError -> Just (show ioError)+ )+ (copyFileToICStringLen filePath)++copyFileToICStringLen :: FilePath -> IO ICStringLen+copyFileToICStringLen filePath =+ do+ -- shamelessly pirated from GHC's slurpFile function.+ handle <- IO.openFile filePath IO.ReadMode+ len <- IO.hFileSize handle+ if len > fromIntegral (maxBound::Int)+ then+ error "CopyFile.copyFileToICStringLen: file too big"+ else+ do+ let+ len_i = fromIntegral len+ mkICStringLen len_i+ (\ cString ->+ do+ lenRead <- hGetBuf handle cString len_i+ when (lenRead < len_i)+ (error"EOF within CopyFile.copyFileToICStringLen")+ )++copyICStringLenToFile :: ICStringLen -> FilePath -> IO ()+copyICStringLenToFile icsl filePath =+ withICStringLen icsl (\ i cstr ->+ copyCStringLenToFile (cstr,i) filePath+ )++-- | Write to a file, catching certain errors.+-- (At the moment this is not very helpful, returning messages like+-- \"system error\").+copyStringToFileCheck :: String -> FilePath -> IO (WithError ())+copyStringToFileCheck str filePath =+ exceptionToError+ (\ exception ->+ case ioErrors exception of+ Nothing -> Nothing+ Just ioError -> Just (show ioError)+ )+ (copyStringToFile str filePath)++copyStringToFile :: String -> FilePath -> IO ()+copyStringToFile str filePath =+ withCStringLen str+ (\ cStringLen -> copyCStringLenToFile cStringLen filePath)++copyCStringLenToFile :: CStringLen -> FilePath -> IO ()+copyCStringLenToFile (ptr,len) filePath =+ do+ handle <- IO.openFile filePath IO.WriteMode+ hPutBuf handle ptr len+ IO.hFlush handle
+ Posixutil/ProcessClasses.hs view
@@ -0,0 +1,46 @@+-- | ProcessClasses describes some classes which tools encapsulating+-- processes may instance.+module Posixutil.ProcessClasses(+ ToolStatus, -- encodes status of process+ Tool(..), -- can get tool status+ SingleInstanceTool(..), -- this tool has at most one instance+ CommandTool(..), -- can send commands.+ ) where++import System.Exit++-- --------------------------------------------------------------------------+-- Can get status+-- --------------------------------------------------------------------------++type ToolStatus = Maybe ExitCode++class Tool t where+ getToolStatus :: t -> IO ToolStatus++-- --------------------------------------------------------------------------+-- Tool has at most one instance, which this gets.+-- --------------------------------------------------------------------------++class SingleInstanceTool t where+ getToolInstance :: IO t++-- --------------------------------------------------------------------------+-- Command tools, IE tools where you can send a message and (maybe)+-- get a response.+-- --------------------------------------------------------------------------++class Tool t => CommandTool t where+ -- Tools have two sorts of output. One is what comes out of their+ -- stdout channel (and if the appropriate mode in ChildProcess is set+ -- their stderr channel as well).+ -- execOneWayCmd is used when that's all there is.+ -- execCmd is used when there's also a string from somewhere else as well.+ evalCmd :: String -> t -> IO String+ execCmd :: String -> t -> IO ()+ execOneWayCmd :: String -> t -> IO ()+ execCmd cmd t =+ do+ _ <- evalCmd cmd t+ return ()+ -- only overrridden by Expect, in which all commands are one-way.
+ Posixutil/SafeSystem.hs view
@@ -0,0 +1,64 @@+-- | SafeSystem.safeSystem executes a command (supplied as a String) and+-- returns its exit code. It differs from System.system in that it does+-- NOT stop the world while doing this, so that other threads can run.+-- How it works: we use ChildProcess to run the runCommand C program,+-- and feed it the command over stdin. Ugly, but is there a better way?+module Posixutil.SafeSystem(+ safeSystemGeneral,+ safeSystem,+ ) where++import System.Exit++import Util.WBFiles+import Util.FileNames+import Util.Computation++import Posixutil.ChildProcess++safeSystem :: String -> IO ExitCode+safeSystem command =+ let+ -- We ignore blank output lines.+ outputSink "" = done+ outputSink str = putStrLn ("SafeSystem output: "++str)+ in+ safeSystemGeneral command outputSink++-- | Run \"command\", displaying any output using the supplied+-- outputSink function. (This output had better not include+-- \"EXITCODE [number]\".)+--+-- outputSink is fed output line by line, and without the newlines.+safeSystemGeneral :: String -> (String -> IO ()) -> IO ExitCode+safeSystemGeneral command outputSink =+ do+ -- Get location of runCommand+ top <- getTOP+ let+ fullName = (trimDir top) `combineNames`+ ("posixutil" `combineNames` "runCommand")+ childProcess <- newChildProcess fullName [+ linemode True,+ standarderrors True+ ]+ sendMsg childProcess (command++"\n")+ let+ readOutput =+ do+ let+ -- we ignore blank input lines.+ notExit str =+ do+ outputSink str+ readOutput+ nextLine <- readMsg childProcess+ case nextLine of+ 'E':'X':'I':'T':'C':'O':'D':'E':' ':numberStr ->+ case readsPrec 0 numberStr of+ [(0,"")] -> return ExitSuccess+ [(n,"")] -> return (ExitFailure n)+ _ -> notExit nextLine+ _ -> notExit nextLine+ readOutput+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ uni-posixutil.cabal view
@@ -0,0 +1,36 @@+name: uni-posixutil+version: 2.2.0.0+build-type: Simple+license: LGPL+license-file: LICENSE+author: uniform@informatik.uni-bremen.de+maintainer: Christian.Maeder@dfki.de+homepage: http://www.informatik.uni-bremen.de/uniform/wb/+category: Uniform+synopsis: Posix utilities for the uniform workbench+description: posix utilities+cabal-version: >= 1.4+tested-with: GHC==6.8.3, GHC==6.10.4, GHC==6.12.3++library+ exposed-modules:+ Posixutil.CopyFile,+ Posixutil.SafeSystem,+ Posixutil.ProcessClasses,+ Posixutil.ChildProcess,+ Posixutil.BlockSigPIPE++ build-depends:+ base >=3 && < 4,+ directory,+ process,+ uni-util,+ uni-events++ if os(windows)+ cpp-options: -DWINDOWS+ else+ build-Depends: unix++ if impl(ghc > 6.10)+ ghc-options: -fwarn-unused-imports -fno-warn-warnings-deprecations