git-annex/Utility.hs

88 lines
2.4 KiB
Haskell
Raw Normal View History

2010-10-10 04:18:10 +00:00
{- git-annex utility functions
-}
2010-10-11 21:52:46 +00:00
module Utility (
withFileLocked,
hGetContentsStrict,
2010-10-15 20:09:30 +00:00
parentDir,
relPathCwdToDir,
relPathDirToDir,
2010-10-11 21:52:46 +00:00
) where
2010-10-10 04:18:10 +00:00
import System.IO
import System.Posix.IO
import Data.String.Utils
2010-10-15 20:09:30 +00:00
import System.Path
import System.Directory
2010-10-10 04:18:10 +00:00
{- Let's just say that Haskell makes reading/writing a file with
- file locking excessively difficult. -}
2010-10-10 15:08:40 +00:00
withFileLocked file mode action = do
-- TODO: find a way to use bracket here
2010-10-10 04:18:10 +00:00
handle <- openFile file mode
lockfd <- handleToFd handle -- closes handle
waitToSetLock lockfd (lockType mode, AbsoluteSeek, 0, 0)
handle' <- fdToHandle lockfd
2010-10-10 15:08:40 +00:00
ret <- action handle'
hClose handle'
return ret
2010-10-10 04:18:10 +00:00
where
lockType ReadMode = ReadLock
lockType _ = WriteLock
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. -}
hGetContentsStrict h = hGetContents h >>= \s -> length s `seq` return s
2010-10-10 04:18:10 +00:00
{- Returns the parent directory of a path. Parent of / is "" -}
parentDir :: String -> String
parentDir dir =
if length dirs > 0
then absolute ++ (join "/" $ take ((length dirs) - 1) dirs)
2010-10-10 04:18:10 +00:00
else ""
where
dirs = filter (\x -> length x > 0) $ split "/" dir
absolute = if ((dir !! 0) == '/') then "/" else ""
2010-10-15 20:09:30 +00:00
{- Constructs a relative path from the CWD to a directory.
-
- For example, assuming CWD is /tmp/foo/bar:
- relPathCwdToDir "/tmp/foo" == "../"
- relPathCwdToDir "/tmp/foo/bar" == ""
- relPathCwdToDir "/tmp/foo/bar" == ""
-}
relPathCwdToDir :: FilePath -> IO FilePath
relPathCwdToDir dir = do
cwd <- getCurrentDirectory
let absdir = abs cwd dir
return $ relPathDirToDir cwd absdir
where
-- absolute, normalized form of the directory
abs cwd dir =
case (absNormPath cwd dir) of
Just d -> d
Nothing -> error $ "unable to normalize " ++ dir
{- Constructs a relative path from one directory to another.
-
- Both directories must be absolute, and normalized (eg with absNormpath).
-
- The path will end with "/", unless it is empty.
- -}
2010-10-15 20:09:30 +00:00
relPathDirToDir :: FilePath -> FilePath -> FilePath
relPathDirToDir from to =
if (0 < length path)
then if (endswith "/" path)
then path
else path ++ "/"
2010-10-15 20:09:30 +00:00
else ""
where
pfrom = split "/" from
pto = split "/" to
2010-10-15 20:09:30 +00:00
common = map fst $ filter same $ zip pfrom pto
same (c,d) = c == d
uncommon = drop numcommon pto
dotdots = take ((length pfrom) - numcommon) $ repeat ".."
numcommon = length $ common
path = join "/" $ dotdots ++ uncommon