broke up Utility

This commit is contained in:
Joey Hess 2011-10-16 00:31:25 -04:00
parent 91366c896d
commit 23f2a12816
16 changed files with 126 additions and 112 deletions

View file

@ -16,6 +16,7 @@ import Common.Annex
import Command import Command
import Annex.Content import Annex.Content
import Utility.FileMode import Utility.FileMode
import Utility.TempFile
import Logs.Location import Logs.Location
import qualified Annex import qualified Annex
import qualified Git import qualified Git

View file

@ -15,7 +15,7 @@ module Common (
module System.Posix.IO, module System.Posix.IO,
module System.Posix.Process, module System.Posix.Process,
module System.Exit, module System.Exit,
module Utility, module Utility.Misc,
module Utility.Conditional, module Utility.Conditional,
module Utility.SafeCommand, module Utility.SafeCommand,
module Utility.Path, module Utility.Path,
@ -40,7 +40,7 @@ import System.Posix.IO
import System.Posix.Process hiding (executeFile) import System.Posix.Process hiding (executeFile)
import System.Exit import System.Exit
import Utility import Utility.Misc
import Utility.Conditional import Utility.Conditional
import Utility.SafeCommand import Utility.SafeCommand
import Utility.Path import Utility.Path

View file

@ -12,6 +12,7 @@ module Init (
) where ) where
import Common.Annex import Common.Annex
import Utility.TempFile
import qualified Git import qualified Git
import qualified Annex.Branch import qualified Annex.Branch
import Annex.Version import Annex.Version

View file

@ -20,6 +20,7 @@ import qualified Annex
import Annex.UUID import Annex.UUID
import qualified Annex.Content import qualified Annex.Content
import qualified Utility.Url as Url import qualified Utility.Url as Url
import Utility.TempFile
import Config import Config
import Init import Init

View file

@ -13,7 +13,6 @@ import qualified Data.Map as M
import Common.Annex import Common.Annex
import Types.Remote import Types.Remote
import qualified Git import qualified Git
import Logs.UUID
import Config import Config
import Annex.Content import Annex.Content
import Remote.Helper.Special import Remote.Helper.Special

View file

@ -21,7 +21,6 @@ import Common.Annex
import Types.Remote import Types.Remote
import Types.Key import Types.Key
import qualified Git import qualified Git
import Logs.UUID
import Config import Config
import Remote.Helper.Special import Remote.Helper.Special
import Remote.Helper.Encryptable import Remote.Helper.Encryptable

View file

@ -13,6 +13,7 @@ import qualified Git
import Config import Config
import Logs.Web import Logs.Web
import qualified Utility.Url as Url import qualified Utility.Url as Url
import Utility.Monad
remote :: RemoteType Annex remote :: RemoteType Annex
remote = RemoteType { remote = RemoteType {

View file

@ -21,6 +21,7 @@ import qualified Git.LsFiles as LsFiles
import Backend import Backend
import Annex.Version import Annex.Version
import Utility.FileMode import Utility.FileMode
import Utility.TempFile
import qualified Upgrade.V2 import qualified Upgrade.V2
-- v2 adds hashing of filenames of content and location log files. -- v2 adds hashing of filenames of content and location log files.

View file

@ -12,6 +12,7 @@ import qualified Git
import qualified Annex.Branch import qualified Annex.Branch
import Logs.Location import Logs.Location
import Annex.Content import Annex.Content
import Utility.TempFile
olddir :: Git.Repo -> FilePath olddir :: Git.Repo -> FilePath
olddir g olddir g

View file

@ -1,106 +0,0 @@
{- general purpose utility functions
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Utility (
hGetContentsStrict,
readFileStrict,
readMaybe,
viaTmp,
withTempFile,
dirContents,
myHomeDir,
catchBool,
inPath,
firstM,
anyM
) where
import Control.Applicative
import IO (bracket)
import System.IO
import System.Posix.Process hiding (executeFile)
import System.Posix.User
import System.FilePath
import System.Directory
import Utility.Path
import Data.Maybe
import Control.Monad (liftM)
{- A version of hgetContents that is not lazy. Ensures file is
- all read before it gets closed. -}
hGetContentsStrict :: Handle -> IO String
hGetContentsStrict h = hGetContents h >>= \s -> length s `seq` return s
{- A version of readFile that is not lazy. -}
readFileStrict :: FilePath -> IO String
readFileStrict f = readFile f >>= \s -> length s `seq` return s
{- Attempts to read a value from a String. -}
readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
((x,_):_) -> Just x
_ -> Nothing
{- 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)
a tmpfile content
renameFile tmpfile file
{- Runs an action with a temp file, then removes the file. -}
withTempFile :: String -> (FilePath -> Handle -> IO a) -> IO a
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)
use (name, handle) = a name handle
{- Lists the contents of a directory.
- Unlike getDirectoryContents, paths are not relative to the directory. -}
dirContents :: FilePath -> IO [FilePath]
dirContents d = map (d </>) . filter notcruft <$> getDirectoryContents d
where
notcruft "." = False
notcruft ".." = False
notcruft _ = True
{- Current user's home directory. -}
myHomeDir :: IO FilePath
myHomeDir = homeDirectory <$> (getUserEntryForID =<< getEffectiveUserID)
{- 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

29
Utility/Misc.hs Normal file
View file

@ -0,0 +1,29 @@
{- misc utility functions
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Utility.Misc where
import System.IO
{- A version of hgetContents that is not lazy. Ensures file is
- all read before it gets closed. -}
hGetContentsStrict :: Handle -> IO String
hGetContentsStrict h = hGetContents h >>= \s -> length s `seq` return s
{- A version of readFile that is not lazy. -}
readFileStrict :: FilePath -> IO String
readFileStrict f = readFile f >>= \s -> length s `seq` return s
{- Attempts to read a value from a String. -}
readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
((x,_):_) -> Just x
_ -> Nothing
{- Catches IO errors and returns a Bool -}
catchBool :: IO Bool -> IO Bool
catchBool = flip catch (const $ return False)

26
Utility/Monad.hs Normal file
View file

@ -0,0 +1,26 @@
{- monadic stuff
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Utility.Monad where
import Data.Maybe
import Control.Monad (liftM)
{- 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

View file

@ -14,6 +14,9 @@ import System.Directory
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import Control.Applicative import Control.Applicative
import System.Posix.User
import Utility.Monad
{- Returns the parent directory of a path. Parent of / is "" -} {- Returns the parent directory of a path. Parent of / is "" -}
parentDir :: FilePath -> FilePath parentDir :: FilePath -> FilePath
@ -112,3 +115,22 @@ preserveOrder (l:ls) new = found ++ preserveOrder ls rest
-} -}
runPreserveOrder :: ([FilePath] -> IO [FilePath]) -> [FilePath] -> IO [FilePath] runPreserveOrder :: ([FilePath] -> IO [FilePath]) -> [FilePath] -> IO [FilePath]
runPreserveOrder a files = preserveOrder files <$> a files runPreserveOrder a files = preserveOrder files <$> a files
{- Lists the contents of a directory.
- Unlike getDirectoryContents, paths are not relative to the directory. -}
dirContents :: FilePath -> IO [FilePath]
dirContents d = map (d </>) . filter notcruft <$> getDirectoryContents d
where
notcruft "." = False
notcruft ".." = False
notcruft _ = True
{- Current user's home directory. -}
myHomeDir :: IO FilePath
myHomeDir = homeDirectory <$> (getUserEntryForID =<< getEffectiveUserID)
{- Checks if a command is available in PATH. -}
inPath :: String -> IO Bool
inPath command = getSearchPath >>= anyM indir
where
indir d = doesFileExist $ d </> command

View file

@ -1,4 +1,4 @@
{- git-annex file copying with rsync {- file copying with rsync
- -
- Copyright 2010 Joey Hess <joey@kitenet.net> - Copyright 2010 Joey Hess <joey@kitenet.net>
- -

39
Utility/TempFile.hs Normal file
View file

@ -0,0 +1,39 @@
{- temp file functions
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Utility.TempFile where
import IO (bracket)
import System.IO
import System.Posix.Process hiding (executeFile)
import System.Directory
import Utility.Misc
import Utility.Path
{- Runs an action like writeFile, writing to a temp file first and
- then moving it into place. The temp file is stored in the same
- directory as the final file to avoid cross-device renames. -}
viaTmp :: (FilePath -> String -> IO ()) -> FilePath -> String -> IO ()
viaTmp a file content = do
pid <- getProcessID
let tmpfile = file ++ ".tmp" ++ show pid
createDirectoryIfMissing True (parentDir file)
a tmpfile content
renameFile tmpfile file
{- Runs an action with a temp file, then removes the file. -}
withTempFile :: String -> (FilePath -> Handle -> IO a) -> IO a
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)
use (name, handle) = a name handle

View file

@ -17,7 +17,7 @@ import Network.HTTP
import Network.URI import Network.URI
import Utility.SafeCommand import Utility.SafeCommand
import Utility import Utility.Path
type URLString = String type URLString = String