packages feed

Extra 1.33 → 1.42

raw patch · 14 files changed

+194/−112 lines, 14 filesdep +bzlibdep +zlibdep ~QuickCheckdep ~Unixutilsdep ~basesetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: bzlib, zlib

Dependency ranges changed: QuickCheck, Unixutils, base

API changes (from Hackage documentation)

- Extra.Misc: processOutput :: String -> IO (Either Int String)
- Extra.Misc: processOutput2 :: String -> IO (String, ExitCode)
+ Extra.CIO: blue :: [Char] -> [Char]
+ Extra.CIO: green :: [Char] -> [Char]
+ Extra.CIO: hColor :: Handle -> [Char] -> [Char]
+ Extra.CIO: magenta :: [Char] -> [Char]
+ Extra.CIO: red :: [Char] -> [Char]
+ Extra.IOThread: IOThread :: (Chan (a, MVar (Either SomeException b))) -> IOThread a b
+ Extra.IOThread: ioRequest :: (IOThread a b) -> a -> IO b
+ Extra.IOThread: newtype IOThread a b
+ Extra.IOThread: startIOThread :: (a -> IO b) -> IO (ThreadId, IOThread a b)
+ Extra.URIQuery: copy :: String -> URI -> URI -> URI
+ Extra.URIQuery: del :: String -> URI -> URI
+ Extra.URIQuery: modify :: String -> (Maybe String -> Maybe String) -> URI -> URI
+ Extra.URIQuery: put :: String -> String -> URI -> URI
- Extra.CIO: bol :: (CIO m) => m ()
+ Extra.CIO: bol :: CIO m => m ()
- Extra.CIO: class (MonadIO m) => CIO m
+ Extra.CIO: class MonadIO m => CIO m
- Extra.CIO: eBOL :: (CIO m) => m ()
+ Extra.CIO: eBOL :: CIO m => m ()
- Extra.CIO: ePutChar :: (CIO m) => Char -> m ()
+ Extra.CIO: ePutChar :: CIO m => Char -> m ()
- Extra.CIO: ePutStr :: (CIO m) => String -> m ()
+ Extra.CIO: ePutStr :: CIO m => String -> m ()
- Extra.CIO: ePutStrBl :: (CIO m) => String -> m ()
+ Extra.CIO: ePutStrBl :: CIO m => String -> m ()
- Extra.CIO: ePutStrLn :: (CIO m) => String -> m ()
+ Extra.CIO: ePutStrLn :: CIO m => String -> m ()
- Extra.CIO: ev :: (CIO m) => Int -> m Int
+ Extra.CIO: ev :: CIO m => Int -> m Int
- Extra.CIO: hBOL :: (CIO m) => Handle -> m ()
+ Extra.CIO: hBOL :: CIO m => Handle -> m ()
- Extra.CIO: hPutChar :: (CIO m) => Handle -> Char -> m ()
+ Extra.CIO: hPutChar :: CIO m => Handle -> Char -> m ()
- Extra.CIO: hPutStr :: (CIO m) => Handle -> String -> m ()
+ Extra.CIO: hPutStr :: CIO m => Handle -> String -> m ()
- Extra.CIO: hPutStrBl :: (CIO m) => Handle -> String -> m ()
+ Extra.CIO: hPutStrBl :: CIO m => Handle -> String -> m ()
- Extra.CIO: hPutStrLn :: (CIO m) => Handle -> String -> m ()
+ Extra.CIO: hPutStrLn :: CIO m => Handle -> String -> m ()
- Extra.CIO: putChar :: (CIO m) => Char -> m ()
+ Extra.CIO: putChar :: CIO m => Char -> m ()
- Extra.CIO: putStr :: (CIO m) => String -> m ()
+ Extra.CIO: putStr :: CIO m => String -> m ()
- Extra.CIO: putStrBl :: (CIO m) => String -> m ()
+ Extra.CIO: putStrBl :: CIO m => String -> m ()
- Extra.CIO: putStrLn :: (CIO m) => String -> m ()
+ Extra.CIO: putStrLn :: CIO m => String -> m ()
- Extra.CIO: setStyle :: (CIO m) => (TStyle -> TStyle) -> m a -> m a
+ Extra.CIO: setStyle :: CIO m => (TStyle -> TStyle) -> m a -> m a
- Extra.CIO: tryCIO :: (CIO m) => m a -> m (Either Exception a)
+ Extra.CIO: tryCIO :: CIO m => m a -> m (Either SomeException a)
- Extra.CIO: vBOL :: (CIO m) => Int -> m ()
+ Extra.CIO: vBOL :: CIO m => Int -> m ()
- Extra.CIO: vEBOL :: (CIO m) => Int -> m ()
+ Extra.CIO: vEBOL :: CIO m => Int -> m ()
- Extra.CIO: vEPutChar :: (CIO m) => Int -> Char -> m ()
+ Extra.CIO: vEPutChar :: CIO m => Int -> Char -> m ()
- Extra.CIO: vEPutStr :: (CIO m) => Int -> String -> m ()
+ Extra.CIO: vEPutStr :: CIO m => Int -> String -> m ()
- Extra.CIO: vEPutStrBl :: (CIO m) => Int -> String -> m ()
+ Extra.CIO: vEPutStrBl :: CIO m => Int -> String -> m ()
- Extra.CIO: vEPutStrLn :: (CIO m) => Int -> String -> m ()
+ Extra.CIO: vEPutStrLn :: CIO m => Int -> String -> m ()
- Extra.CIO: vHBOL :: (CIO m) => Handle -> Int -> m ()
+ Extra.CIO: vHBOL :: CIO m => Handle -> Int -> m ()
- Extra.CIO: vHPutChar :: (CIO m) => Handle -> Int -> Char -> m ()
+ Extra.CIO: vHPutChar :: CIO m => Handle -> Int -> Char -> m ()
- Extra.CIO: vHPutStrBl :: (CIO m) => Handle -> Int -> String -> m ()
+ Extra.CIO: vHPutStrBl :: CIO m => Handle -> Int -> String -> m ()
- Extra.CIO: vHPutStrLn :: (CIO m) => Handle -> Int -> String -> m ()
+ Extra.CIO: vHPutStrLn :: CIO m => Handle -> Int -> String -> m ()
- Extra.CIO: vPutChar :: (CIO m) => Int -> Char -> m ()
+ Extra.CIO: vPutChar :: CIO m => Int -> Char -> m ()
- Extra.CIO: vPutStr :: (CIO m) => Int -> String -> m ()
+ Extra.CIO: vPutStr :: CIO m => Int -> String -> m ()
- Extra.CIO: vPutStrBl :: (CIO m) => Int -> String -> m ()
+ Extra.CIO: vPutStrBl :: CIO m => Int -> String -> m ()
- Extra.CIO: vPutStrLn :: (CIO m) => Int -> String -> m ()
+ Extra.CIO: vPutStrLn :: CIO m => Int -> String -> m ()
- Extra.CIO: withStyle :: (CIO m) => TStyle -> m a -> m a
+ Extra.CIO: withStyle :: CIO m => TStyle -> m a -> m a
- Extra.List: changePrefix :: (Eq a) => [a] -> [a] -> [a] -> Maybe [a]
+ Extra.List: changePrefix :: Eq a => [a] -> [a] -> [a] -> Maybe [a]
- Extra.List: dropPrefix :: (Eq a) => [a] -> [a] -> Maybe [a]
+ Extra.List: dropPrefix :: Eq a => [a] -> [a] -> Maybe [a]
- Extra.List: isSublistOf :: (Eq a) => [a] -> [a] -> Maybe Int
+ Extra.List: isSublistOf :: Eq a => [a] -> [a] -> Maybe Int
- Extra.List: listIntersection :: (Eq a) => [[a]] -> [a]
+ Extra.List: listIntersection :: Eq a => [[a]] -> [a]
- Extra.List: partitionM :: (Monad m) => (a -> m Bool) -> [a] -> m ([a], [a])
+ Extra.List: partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
- Extra.List: wordsBy :: (Eq a) => (a -> Bool) -> [a] -> [[a]]
+ Extra.List: wordsBy :: Eq a => (a -> Bool) -> [a] -> [[a]]
- Extra.Lock: awaitLock :: (MonadIO m) => Int -> Int -> FilePath -> m a -> m (Either Exception a)
+ Extra.Lock: awaitLock :: (MonadIO m, Ord a, Num a) => a -> Int -> FilePath -> m b -> m (Either ErrorCall b)
- Extra.Lock: withLock :: (MonadIO m) => FilePath -> m a -> m (Either Exception a)
+ Extra.Lock: withLock :: MonadIO m => FilePath -> m a -> m (Either IOException a)
- Extra.Misc: listDiff :: (Ord a) => [a] -> [a] -> [a]
+ Extra.Misc: listDiff :: Ord a => [a] -> [a] -> [a]
- Extra.Misc: listMap :: (Ord k) => [(k, a)] -> Map k [a]
+ Extra.Misc: listMap :: Ord k => [(k, a)] -> Map k [a]
- Extra.Misc: read' :: (Read a) => String -> a
+ Extra.Misc: read' :: Read a => String -> a
- Extra.Misc: splitOutput :: [Output] -> (ByteString, ByteString, Maybe ExitCode)
+ Extra.Misc: splitOutput :: [Output] -> (ByteString, ByteString, ExitCode)
- Extra.TIO: tryTIO :: TIO a -> TIO (Either Exception a)
+ Extra.TIO: tryTIO :: Exception a1 => TIO a -> RWST TStyle () TState IO (Either a1 a)
- Extra.Time: formatDebianDate :: (FormatTime t) => t -> [Char]
+ Extra.Time: formatDebianDate :: FormatTime t => t -> [Char]
- Test.QUnit: testQuickCheck :: (Testable a) => Config -> a -> Test
+ Test.QUnit: testQuickCheck :: Testable a => Args -> a -> Test

Files

Extra.cabal view
@@ -1,13 +1,13 @@ Name:           Extra-Version:        1.33+Version:        1.42 License:        BSD3 License-File:	COPYING Author:         David Fox Category:       Unclassified Description:    A hodge-podge of functions and modules that do not have a better home Maintainer:     David Fox <david@seereason.com>-Homepage:       http://src.seereason.com/ghc6102/haskell-extra/-Build-Depends:  base >= 3 && < 4, unix, regex-compat, time >= 1.1, Unixutils >= 1.10 , mtl, network, pretty, directory, bytestring, process, containers, old-time, old-locale, QuickCheck < 2, HUnit, random, filepath+Homepage:       http://src.seereason.com/haskell-extra+Build-Depends:  base < 5, unix, regex-compat, time >= 1.1, Unixutils >= 1.32 , mtl, network, pretty, directory, bytestring, process, containers, old-time, old-locale, QuickCheck >= 2 && < 3, HUnit, random, filepath, zlib, bzlib Synopsis:       A grab bag of modules. ghc-options:	-O2 -W C-Sources:	     cbits/gwinsz.c@@ -16,7 +16,8 @@ Exposed-modules: 	Extra.Bool, Extra.Either, Extra.Exit, Extra.Files, 	Extra.GPGSign,Extra.List, Extra.HughesPJ, Extra.Lock, Extra.Misc, Extra.Net, Extra.SSH,-	Extra.Time, Extra.Terminal, Extra.CIO, Extra.TIO, Extra.IO, Extra.URI, Test.QUnit, Test.QuickCheck.Properties+	Extra.Time, Extra.Terminal, Extra.CIO, Extra.TIO, Extra.IO, Extra.URI, Extra.URIQuery,+        Test.QUnit, Test.QuickCheck.Properties, Extra.IOThread Build-Type: Simple  -- For more complex build options see:
Extra/CIO.hs view
@@ -5,6 +5,12 @@ -- There is an instance for the regular IO monad which doesn't use any -- of these features, to allow functions which do not use the TIO -- monad call functions in the Debian library.+--+-- NOTE: a copy of this library is in the Extra library as+-- well. Please update both locations.+-- +-- This code is provided for backwards compatibility, I don't+-- endorse its use in new projects. module Extra.CIO      ( -- * The CIO class       CIO(..)@@ -56,6 +62,12 @@     , vHBOL     , vBOL     , vEBOL++    , hColor+    , blue+    , green+    , red+    , magenta     ) where  import Prelude hiding (putStr, putChar, putStrLn)@@ -80,7 +92,7 @@     -- |Modify the current output style.     setStyle :: (TStyle -> TStyle) -> m a -> m a     -- |Implementation of try for this monad-    tryCIO :: m a -> m (Either Exception a)+    tryCIO :: m a -> m (Either SomeException a)  -- |A record used to hold the output style information for a task. -- This The prefixes that will appear at the beginning of each line,
Extra/Files.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ScopedTypeVariables #-} -- |Some extra operations on files.  The functions here generally -- return (Right ()) on success, Left [messages] on failure, and throw -- an exception when a failure leaves things in an inconsistant state.@@ -21,19 +22,18 @@     , replaceFile     ) where +import qualified Codec.Compression.GZip as GZip+import qualified Codec.Compression.BZip as BZip import		 Control.Exception hiding (catch) import		 Control.Monad-import qualified Data.ByteString.Lazy.Char8 as B+import qualified Data.ByteString.Lazy as B import		 Data.List import		 Data.Maybe import		 Extra.Misc import		 System.Unix.Directory-import		 System.Unix.Process import		 System.Directory-import		 System.IO import		 System.IO.Error hiding (try, catch) import		 System.Posix.Files-import		 System.Posix.Unistd  -- | Return the list of subdirectories, omitting . and .. and ignoring -- symbolic links.@@ -107,7 +107,7 @@        case deleted of          Right () ->              try (rename old new) >>=-             return . either (\ e -> Left ["Couldn't rename " ++ old ++ " -> " ++ new ++ ": " ++ show e]) (\ _ -> Right ())+             return . either (\ (e :: SomeException) -> Left ["Couldn't rename " ++ old ++ " -> " ++ new ++ ": " ++ show e]) (\ _ -> Right ())          x -> return x  -- |Change a file's name if it exists.@@ -128,26 +128,26 @@              do status <- getSymbolicLinkStatus path 		-- To do: should we remove the directory contents?                 let rm = if isDirectory status then removeDirectory else removeLink-                try (rm path) >>= return . either (\ e -> Left ["Couldn't remove " ++ path ++ ": " ++ show e]) (const . Right $ ())+                try (rm path) >>= return . either (\ (e :: SomeException) -> Left ["Couldn't remove " ++ path ++ ": " ++ show e]) (const . Right $ ())  -- |Create or update gzipped and bzip2-ed versions of a file. zipFile :: FilePath -> IO (Either [String] ()) zipFile path =-    do let commands = ["gzip < '" ++ path ++ "' > '" ++ path ++ ".gz'",-                       "bzip2 < '" ++ path ++ "' > '" ++ path ++ ".bz2'"]-       forceRemoveLink (path ++ ".gz")-       forceRemoveLink (path ++ ".bz2")-       results <- mapM (\ cmd -> lazyCommand cmd B.empty) commands-       case filter (/= ExitSuccess) (concat (map exitCodeOnly results)) of-         [] -> return $ Right ()-         _ -> return (Left ["Failure writing and zipping " ++ path ++ ": " ++-                            concat (map writeMessage (zip commands results))])+    try (do forceRemoveLink gz+            forceRemoveLink bz2+            B.readFile path >>= B.writeFile gz . {- t1 . -} GZip.compress+            B.readFile path >>= B.writeFile bz2 . {- t2 . -} BZip.compress) >>=+    return . either (\ (e :: SomeException) -> Left ["Failure writing and zipping " ++ path, show e]) Right     where-      writeMessage (command, output) =-          case exitCodeOnly output of-            (ExitFailure n : _) ->-                command ++ " -> " ++ show n ++ ":\n  " ++ B.unpack (stderrOnly output)-            _ -> ""+      gz = path ++ ".gz"+      bz2 = path ++ ".bz2"+      --t1 s = trace ("Size of " ++ gz ++ " text: " ++ show (L.length s)) s+      --t2 s = trace ("Size of " ++ bz2 ++ " text: " ++ show (L.length s)) s+      --writeMessage (command, output) =+      --    case exitCodeOnly output of+      --      (ExitFailure n : _) ->+      --          command ++ " -> " ++ show n ++ ":\n  " ++ L.unpack (stderrOnly output)+      --      _ -> ""  -- |like removeLink, but does not fail if link did not exist forceRemoveLink :: FilePath -> IO ()@@ -159,9 +159,10 @@     backupFile path >>=     either (\ e -> return (Left ["Failure renaming " ++ path ++ " -> " ++ path ++ "~: " ++ show e]))            (\ _ -> try (B.writeFile path text) >>=-                   either (\ e -> restoreBackup path >>=-                                  either (\ e -> error ("Failed to restore backup: " ++ path ++ "~ -> " ++ path ++ ": " ++ show e))-                                         (\ _ -> return (Left ["Failure writing " ++ path ++ ": " ++ show e])))+                   either (\ (e :: SomeException) ->+                               restoreBackup path >>=+                               either (\ e -> error ("Failed to restore backup: " ++ path ++ "~ -> " ++ path ++ ": " ++ show e))+                                      (\ _ -> return (Left ["Failure writing " ++ path ++ ": " ++ show e])))                           (\ _ -> zipFile path))  -- | Write out three versions of a file, regular, gzipped, and bzip2ed.@@ -172,7 +173,7 @@     deleteMaybe path >>=     either (\ e -> return (Left ["Failure removing " ++ path ++ ": " ++ show e]))            (\ _ -> try (B.writeFile path text) >>=-                   either (\ e -> return (Left ["Failure writing " ++ path ++ ": " ++ show e]))+                   either (\ (e :: SomeException) -> return (Left ["Failure writing " ++ path ++ ": " ++ show e]))                           (\ _ -> zipFile path))  -- Turn a file into a backup file if it exists.@@ -203,7 +204,7 @@ maybeWriteFile path text =     try (readFile path) >>= maybeWrite     where-      maybeWrite (Left (IOException e)) | isDoesNotExistError e = writeFile path text+      maybeWrite (Left (e :: IOException)) | isDoesNotExistError e = writeFile path text       maybeWrite (Left e) = error ("maybeWriteFile: " ++ show e)       maybeWrite (Right old) | old == text = return ()       maybeWrite (Right _old) = @@ -215,7 +216,7 @@ createSymbolicLinkIfMissing :: String -> FilePath -> IO () createSymbolicLinkIfMissing text path =     try (getSymbolicLinkStatus path) >>=-    either (\ _ -> createSymbolicLink text path) (\ _ -> return ())+    either (\ (_ :: SomeException) -> createSymbolicLink text path) (\ _ -> return ())  prepareSymbolicLink :: FilePath -> FilePath -> IO () prepareSymbolicLink name path =@@ -245,6 +246,8 @@  -- Try something n times, returning the first Right or the last Left -- if it never succeeds.  Sleep between tries.-tries :: Int -> Int -> (IO a) -> IO (Either Exception a)+--tries :: Int -> Int -> (IO a) -> IO (Either Exception a)+{- tries _ 1 f = try f >>= either (return . Left) (return . Right)-tries usec count f = try f >>= either (const (usleep usec >> tries usec (count - 1) f)) (return . Right)+tries usec count f = try f >>= either (\ (_ :: SomeException) -> usleep usec >> tries usec (count - 1) f) (return . Right)+-}
+ Extra/IOThread.hs view
@@ -0,0 +1,41 @@+-- |this module provides a simple mechanism for adding IO operations+-- to a queue and running them in a single thread. This is useful if+-- the IO operations have side-effects which could collide if run from+-- multiple threads. For example, creating an image thumbnail and+-- storing it on disk, running latex, etc.+module Extra.IOThread where++import Control.Concurrent (ThreadId, forkIO)+import Control.Concurrent.Chan (Chan,newChan, readChan, writeChan)+import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, readMVar)+import Control.Exception+import Control.Monad (forever)++newtype IOThread a b = IOThread (Chan (a, MVar (Either SomeException b)))++-- |start the IO thread.+startIOThread :: (a -> IO b) -- ^ the IO function that does all the work+              -> IO (ThreadId, IOThread a b) -- ^ a ThreadId which can be used to kill the IOThread, and a handle that can be used to issue requests to the thread.+startIOThread f =+    do c <- newChan+       tid <- forkIO $ ioThread f c+       return (tid, IOThread c)+    where+      ioThread f c =+          forever $ do (a, mvar) <- readChan c+                       b <- try $ f a+                       putMVar mvar b++-- |issue a request to the IO thread and get back the result+-- if the thread function throws an exception 'ioRequest' will rethrow the exception.+ioRequest :: (IOThread a b) -- ^ handle to the IOThread+          -> a -- ^ argument to the function in the IOThread+          -> IO b -- ^ value returned by the function in the IOThread+ioRequest (IOThread chan) a =+    do resp <- newEmptyMVar +       writeChan chan (a, resp)+       e <- readMVar resp+       case e of+         (Right r) ->  return r+         (Left err) -> throwIO err+            
Extra/List.hs view
@@ -87,3 +87,8 @@ isSublistOf sub lst =     maybe Nothing (\ s -> Just (length s - length sub))               (find (isSuffixOf sub) (inits lst))++{-+lookups :: (Eq a) => a -> [(a, b)] -> [b]+lookups a = map snd . filter ((a ==) . fst)+-}
Extra/Lock.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ScopedTypeVariables #-} module Extra.Lock     ( withLock     , awaitLock@@ -12,14 +13,14 @@ import System.Posix.IO import System.Posix.Unistd -withLock :: (MonadIO m) => FilePath -> m a -> m (Either Exception a)+--withLock :: (MonadIO m) => FilePath -> m a -> m (Either Exception a) withLock path task =     liftIO checkLock >>= liftIO . takeLock >>= doTask task >>= liftIO . dropLock     where       -- Return True if file is locked by a running process, false otherwise-      checkLock :: IO (Either Exception ())+      --checkLock :: IO (Either Exception ())       checkLock = try (readFile path) >>= either (return . checkReadError) (processRunning . lines)-      checkReadError (IOException e) | isDoesNotExistError e = (Right ())+      checkReadError (e :: IOException) | isDoesNotExistError e = (Right ())       checkReadError e = Left e       processRunning (pid : _) =           do exists <- doesDirectoryExist ("/proc/" ++ pid)@@ -27,11 +28,11 @@                True -> return (Left (lockedBy pid))                False -> breakLock       processRunning [] = breakLock-      lockedBy pid = IOException (mkIOError alreadyInUseErrorType ("Locked by " ++ pid) Nothing (Just path))+      lockedBy pid = mkIOError alreadyInUseErrorType ("Locked by " ++ pid) Nothing (Just path)       breakLock = do try (removeFile path) >>= return . either checkBreakError (const (Right ()))-      checkBreakError (IOException e) | isDoesNotExistError e = (Right ())+      checkBreakError (e :: IOException) | isDoesNotExistError e = (Right ())       checkBreakError e = Left e-      takeLock :: Either Exception () -> IO (Either Exception ())+      --takeLock :: Either Exception () -> IO (Either Exception ())       takeLock (Right ()) =           -- Try to create the lock file in exclusive mode, if this           -- succeeds then we have a lock.  Then write the process ID@@ -46,12 +47,12 @@       dropLock (Right a) = try (removeFile path) >>= return . checkDrop a       dropLock (Left e) = return (Left e)       checkDrop a (Right ()) = Right a-      checkDrop a (Left (IOException e)) | isDoesNotExistError e = Right a+      checkDrop a (Left (e :: IOException)) | isDoesNotExistError e = Right a       checkDrop _ (Left e) = Left e  -- |Like withLock, but instead of giving up immediately, try n times -- with a wait between each.-awaitLock :: (MonadIO m) => Int -> Int -> FilePath -> m a -> m (Either Exception a)+--awaitLock :: (MonadIO m) => Int -> Int -> FilePath -> m a -> m (Either Exception a) awaitLock tries usecs path task =     attempt 0     where 
Extra/Misc.hs view
@@ -23,8 +23,8 @@     , sameMd5sum     , tarDir     -- * Processes-    , Extra.Misc.processOutput-    , processOutput2+    -- , Extra.Misc.processOutput+    -- , processOutput2     , splitOutput     -- ByteString     , cd@@ -33,7 +33,6 @@     ) where  import		 Control.Exception-import		 Control.Monad import qualified Data.ByteString.Lazy.Char8 as B import		 Data.List import qualified Data.Map as Map@@ -43,8 +42,6 @@ import		 System.FilePath import		 System.Unix.Process import		 System.Directory-import		 System.Exit-import		 System.IO import		 System.Posix.Files import		 System.Posix.User (getEffectiveUserID) import		 Text.Regex@@ -130,12 +127,11 @@     do output <- lazyCommand cmd B.empty        let result =                case exitCodeOnly output of-                 [ExitFailure n] -> Left ("Error " ++ show n ++ " running '" ++ cmd ++ "'")-                 [ExitSuccess] ->+                 ExitFailure n -> Left ("Error " ++ show n ++ " running '" ++ cmd ++ "'")+                 ExitSuccess ->                      case listToMaybe . words . B.unpack . stdoutOnly $ output of                        Nothing -> Left $ "Error in output of '" ++ cmd ++ "'"                        Just checksum -> Right checksum-                 _ -> Left "Internal error 12"        return result     where       cmd = "md5sum " ++ path@@ -156,32 +152,32 @@       bsum <- md5sum b       return (asum == bsum) +{- -- | Backwards compatibility functions. processOutput :: String -> IO (Either Int String) processOutput command =     do       output <- lazyCommand command B.empty       case exitCodeOnly output of-        [ExitSuccess] -> return . Right . B.unpack . stdoutOnly $ output-        [ExitFailure n] -> return . Left $ n+        ExitSuccess -> return . Right . B.unpack . stdoutOnly $ output+        ExitFailure n -> return . Left $ n         _ -> error "My.processOutput: Internal error 13"  processOutput2 :: String -> IO (String, ExitCode) processOutput2 command =     do       output <- lazyCommand command B.empty-      case exitCodeOnly output of-        [code] -> return ((B.unpack . stdoutOnly $ output), code)-        _ -> error "My.processOutput2: Internal error 14"+      return ((B.unpack . stdoutOnly $ output), exitCodeOnly output)+-} -splitOutput :: [Output] -> (B.ByteString, B.ByteString, Maybe ExitCode)-splitOutput output = (stdoutOnly output, stderrOnly output, listToMaybe (exitCodeOnly output))+splitOutput :: [Output] -> (B.ByteString, B.ByteString, ExitCode)+splitOutput output = (stdoutOnly output, stderrOnly output, exitCodeOnly output)  -- |A version of read with a more helpful error message. read' s =     case reads s of       [] -> error $ "read - no parse: " ++ show s-      ((x, s) : _) -> x+      ((x, _s) : _) -> x  {- type DryRunFn = IO () -> (Bool, String) -> IO ()@@ -272,8 +268,10 @@ -- | Given a tarball, return the name of the top directory. tarDir :: FilePath -> IO (Maybe String) tarDir path =-    Extra.Misc.processOutput cmd >>=-      return . either (const Nothing) (dir . lines)+    lazyCommand cmd B.empty >>= \ output ->+    case exitCodeOnly output of+      ExitSuccess -> return . dir . lines . B.unpack . stdoutOnly $ output+      _ -> return Nothing     where       cmd = "tar tfz '" ++ path ++ "'"       dir [] = Nothing
Extra/Net.hs view
@@ -8,6 +8,9 @@  -- | Parse the text returned when a directory is listed by a web -- server.  This is currently only known to work with Apache.+-- NOTE: there is a second copy of this function in+-- debian:Debian.URI. Please update both locations if you make+-- changes. webServerDirectoryContents :: L.ByteString -> [String] webServerDirectoryContents text =     catMaybes . map (second . matchRegex re) . lines . L.unpack $ text
Extra/SSH.hs view
@@ -4,15 +4,12 @@     , sshCopy     ) where -import Control.Monad(unless) import System.Cmd import System.Directory import System.Posix.User-import System.Posix.Files import System.Environment import System.Exit import System.IO-import Network.URI import qualified Data.ByteString.Lazy.Char8 as B import System.Unix.Process @@ -40,9 +37,9 @@              do hPutStrLn stderr $ "generatePublicKey " ++ " -> " ++ keypath                 result <- lazyCommand cmd B.empty                 case exitCodeOnly result of-                  (ExitFailure n : _) ->+                  ExitFailure n ->                       return . Left $ "Failure: " ++ show cmd ++ " -> " ++ show n ++-                                 "\n\noutput: " ++ B.unpack (outputOnly result)+                                      "\n\noutput: " ++ B.unpack (outputOnly result)                   _ -> return . Right $ keypath  -- |See if we already have access to the destination (user\@host).@@ -72,8 +69,8 @@        let cmd = sshOpenCmd dest port keypath        result <- lazyCommand cmd B.empty        case exitCodeOnly result of-         (ExitFailure n : _) -> return . Left $ "Failure: " ++ show cmd ++ " -> " ++ show n ++-	                                "\n\noutput: " ++ B.unpack (outputOnly result)+         ExitFailure n -> return . Left $ "Failure: " ++ show cmd ++ " -> " ++ show n +++	                                  "\n\noutput: " ++ B.unpack (outputOnly result)          _ -> return . Right $ ()     where       sshOpenCmd dest port keypath =@@ -87,6 +84,7 @@            "chmod 600 .ssh/authorized_keys2")  -- This used to be main.+{- test =     getDest >>=     either (return . Left) (uncurry sshExport) >>=@@ -106,6 +104,7 @@                                ((n, _) : _) -> Right (user ++ host, Just n)                          _ -> Left $ "Invalid destination: " ++ dest           checkArgs args = return . Left $ "Usage: sshexport user@host"+-}  -- |Copy the ssh configuration from $HOME to the \/root directory of a -- changeroot.
Extra/TIO.hs view
@@ -1,4 +1,11 @@ {-# LANGUAGE TypeSynonymInstances #-}+-- |A value of type TIO represents the state of the terminal I/O+-- system.  The 'bol' flag keeps track of whether we are at the+-- beginning of line on the console.  This is computed in terms of+-- what we have sent to the console, but it should be remembered that+-- the order that stdout and stderr are sent to the console may not be+-- the same as the order in which they show up there.  However, in+-- practice this seems to work as one would hope. module Extra.TIO     ( module Extra.CIO     -- * The TIO monad@@ -12,17 +19,8 @@ import Prelude hiding (putStr, putChar, putStrLn) import Control.Exception import Control.Monad.RWS-import Control.Monad.Reader-import Control.Monad.Trans import qualified System.IO as IO --- | This represents the state of the IO system.  The 'bol' flag keeps--- track of whether we are at the beginning of line on the console.--- This is computed in terms of what we have sent to the console, but--- it should be remembered that the order that stdout and stderr are--- sent to the console may not be the same as the order in which they--- show up there.  However, in practice this seems to work as one--- would hope. data TState     = TState { cursor :: Position		-- ^ Is the console at beginning of line?              } deriving Show@@ -41,7 +39,7 @@ runTIO style action = (runRWST action) style initState >>= \ (a, _, _) -> return a  -- |Catch exceptions in a TIO action.-tryTIO :: TIO a -> TIO (Either Exception a)+--tryTIO :: TIO a -> TIO (Either Exception a) tryTIO task =     do state <- get        liftTIO (try' state) task@@ -87,7 +85,7 @@     -- | A "virtual" newline, this puts us into the EOL state.  From     -- this state, a newline will be inserted before the next output,     -- unless that output itself begins with a newline.-    hBOL h =+    hBOL _h =         do state <- get            put (state {cursor = if cursor state == BOL then BOL else EOL})     -- |Return the "effective verbosity", or perhaps the effective
Extra/Terminal.hs view
@@ -3,7 +3,6 @@ -- Copyright Jeremy Shaw 2007 module Extra.Terminal where -import Control.Monad import System.Posix.Env import Foreign.C.Types 
+ Extra/URIQuery.hs view
@@ -0,0 +1,39 @@+module Extra.URIQuery+    ( modify+    , del+    , put+    , copy+    ) where++import Data.List (partition)+import Data.Maybe (listToMaybe)+import Extra.URI++-- |Modify an individual URI query attributes.+modify :: String -> (Maybe String -> Maybe String) -> URI -> URI+modify a vf uri =+    let (vs, other) = partition ((== a) . fst) (parseURIQuery uri) in+    setURIQuery (case vf (listToMaybe (map snd vs)) of+                   Just v' -> (a, v') : other+                   Nothing -> other) uri++-- |Replace a query attribute with Nothing.+del :: String -> URI -> URI+del a uri = modify a (const Nothing) uri++-- |Replace a query attribute with something.+put :: String -> String -> URI -> URI +put a v uri = modify a (const (Just v)) uri++-- |Copy an attribute from one query to another+copy :: String -> URI -> URI -> URI+copy a src dst = modify a (const (lookup a (parseURIQuery src))) dst++-- Apply f to all of the URI's pairs+{-+modifyAll :: (String -> Maybe String -> Maybe String) -> URI -> URI+modifyAll f uri =+    foldr (\ (a, _) uri -> modify a (f a) uri) uri pairs+    where+      pairs = parseURIQuery uri+-}
Setup.hs view
@@ -2,4 +2,4 @@  import Distribution.Simple -main = defaultMainWithHooks defaultUserHooks+main = defaultMainWithHooks simpleUserHooks
Test/QUnit.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeSynonymInstances #-} ----------------------------------------------------------------------------- -- | -- Module      :  Test.QUnit@@ -33,9 +34,8 @@ ----------------------------------------------------------------------------- module Test.QUnit (testQuickCheck) where -import System.Random-import Test.HUnit as HU-import Test.QuickCheck as QC+import qualified Test.HUnit as HU+import qualified Test.QuickCheck as QC  -- |an instance of Test.HUnit.Testable for Test.QuickCheck.Property --@@ -45,39 +45,22 @@ -- -- Because it results in undeciable instances. For example, there is -- an instance of 'Bool' for QC.Testable and HU.Testable already.-instance HU.Testable Property where-    test qc = testQuickCheck defaultConfig qc+instance HU.Testable QC.Property where+    test qc = testQuickCheck QC.stdArgs qc  -- |turns the quickcheck test into an hunit test -- -- Use this if you want to provide a custom 'Config' instead of -- 'defaultConfig'. testQuickCheck :: (QC.Testable a) => -           Config -- ^ quickcheck config-        -> a      -- ^ quickcheck property-        -> Test-testQuickCheck config property =-    TestCase $ do rnd <- newStdGen-                  tests config (evaluate property) rnd 0 0 []---- |modified version of the tests function from Test.QuickCheck-tests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO () -tests config gen rnd0 ntest nfail stamps-  | ntest == configMaxTest config = return () -  | nfail == configMaxFail config = assertFailure $ "Arguments exhausted after " ++ show ntest ++ " tests."-  | otherwise               =-      do putStr (configEvery config ntest (arguments result))-         case ok result of-           Nothing    ->-             tests config gen rnd1 ntest (nfail+1) stamps-           Just True  ->-             tests config gen rnd1 (ntest+1) nfail (stamp result:stamps)-           Just False ->-             assertFailure $  ( "Falsifiable, after "-                   ++ show ntest-                   ++ " tests:\n"-                   ++ unlines (arguments result)-                    )-     where-      result      = generate (configSize config ntest) rnd2 gen-      (rnd1,rnd2) = split rnd0+           QC.Args  -- ^ quickcheck config+        -> a        -- ^ quickcheck property+        -> HU.Test+testQuickCheck args prop =+    HU.TestCase $+    do result <- QC.quickCheckWithResult args prop+       case result of+         (QC.Success _ _ _) -> return ()+         (QC.GaveUp ntest _ _) -> HU.assertFailure $ "Arguments exhausted after" ++ show ntest ++ (if ntest == 1 then " test." else " tests.")+         (QC.Failure _ _ _ _usedSize reason _ _) -> HU.assertFailure reason+         (QC.NoExpectedFailure _ _ _) -> HU.assertFailure $ "No Expected Failure"