git-annex/Utility.hs

123 lines
3.3 KiB
Haskell
Raw Normal View History

{- general purpose utility functions
2010-10-27 20:53:54 +00:00
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
2010-10-27 20:53:54 +00:00
-
- Licensed under the GNU GPL version 3 or higher.
2010-10-10 04:18:10 +00:00
-}
2010-10-11 21:52:46 +00:00
module Utility (
hGetContentsStrict,
2010-12-03 04:33:41 +00:00
readFileStrict,
unsetFileMode,
readMaybe,
2011-06-30 04:42:09 +00:00
viaTmp,
withTempFile,
2011-02-01 00:14:08 +00:00
dirContains,
2011-04-02 19:50:51 +00:00
dirContents,
2011-04-09 16:34:49 +00:00
myHomeDir,
catchBool,
inPath,
firstM,
anyM
2010-10-11 21:52:46 +00:00
) where
2010-10-10 04:18:10 +00:00
import IO (bracket)
2010-10-10 04:18:10 +00:00
import System.IO
import System.Posix.Process hiding (executeFile)
2010-11-08 21:44:08 +00:00
import System.Posix.Files
import System.Posix.Types
2011-04-09 16:34:49 +00:00
import System.Posix.User
import System.FilePath
2010-10-15 20:09:30 +00:00
import System.Directory
2010-11-08 21:44:08 +00:00
import Foreign (complement)
import Utility.Path
import Data.Maybe
import Control.Monad (liftM)
2010-10-10 06:22:35 +00:00
{- A version of hgetContents that is not lazy. Ensures file is
- all read before it gets closed. -}
2010-10-31 20:00:32 +00:00
hGetContentsStrict :: Handle -> IO String
2010-10-10 06:22:35 +00:00
hGetContentsStrict h = hGetContents h >>= \s -> length s `seq` return s
2010-12-03 04:33:41 +00:00
{- A version of readFile that is not lazy. -}
readFileStrict :: FilePath -> IO String
readFileStrict f = readFile f >>= \s -> length s `seq` return s
2010-11-08 21:44:08 +00:00
{- Removes a FileMode from a file.
- For example, call with otherWriteMode to chmod o-w -}
unsetFileMode :: FilePath -> FileMode -> IO ()
unsetFileMode f m = do
s <- getFileStatus f
2010-11-22 21:51:55 +00:00
setFileMode f $ fileMode s `intersectFileModes` complement m
{- Attempts to read a value from a String. -}
readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
((x,_):_) -> Just x
_ -> Nothing
2011-06-30 04:42:09 +00:00
{- Runs an action like writeFile, writing to a tmp file first and
- then moving it into place. -}
viaTmp :: (FilePath -> String -> IO ()) -> FilePath -> String -> IO ()
viaTmp a file content = do
pid <- getProcessID
let tmpfile = file ++ ".tmp" ++ show pid
createDirectoryIfMissing True (parentDir file)
2011-06-30 04:42:09 +00:00
a tmpfile content
renameFile tmpfile file
2011-04-02 19:50:51 +00:00
{- Runs an action with a temp file, then removes the file. -}
withTempFile :: String -> (FilePath -> Handle -> IO a) -> IO a
2011-08-21 17:17:12 +00:00
withTempFile template a = bracket create remove use
where
create = do
tmpdir <- catch getTemporaryDirectory (const $ return ".")
openTempFile tmpdir template
remove (name, handle) = do
hClose handle
catchBool (removeFile name >> return True)
2011-08-21 17:17:12 +00:00
use (name, handle) = a name handle
2011-04-02 19:50:51 +00:00
{- Lists the contents of a directory.
- Unlike getDirectoryContents, paths are not relative to the directory. -}
dirContents :: FilePath -> IO [FilePath]
dirContents d = do
c <- getDirectoryContents d
return $ map (d </>) $ filter notcruft c
where
notcruft "." = False
notcruft ".." = False
notcruft _ = True
2011-04-09 16:34:49 +00:00
{- Current user's home directory. -}
myHomeDir :: IO FilePath
myHomeDir = do
uid <- getEffectiveUserID
u <- getUserEntryForID uid
return $ homeDirectory u
2011-04-17 04:57:29 +00:00
{- Catches IO errors and returns a Bool -}
catchBool :: IO Bool -> IO Bool
catchBool = flip catch (const $ return False)
{- Return the first value from a list, if any, satisfying the given
- predicate -}
firstM :: (Monad m) => (a -> m Bool) -> [a] -> m (Maybe a)
firstM _ [] = return Nothing
firstM p (x:xs) = do
q <- p x
if q
then return (Just x)
else firstM p xs
{- Returns true if any value in the list satisfies the preducate,
- stopping once one is found. -}
anyM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
anyM p = liftM isJust . firstM p
{- Checks if a command is available in PATH. -}
inPath :: String -> IO Bool
inPath command = getSearchPath >>= anyM indir
where
indir d = doesFileExist $ d </> command