Merge branch 'master' into ghc7.4
Conflicts: Utility/Misc.hs
This commit is contained in:
commit
44b115e0b1
16 changed files with 78 additions and 100 deletions
|
@ -25,7 +25,6 @@ module Annex.Content (
|
||||||
preseedTmp,
|
preseedTmp,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import System.IO.Error (try)
|
|
||||||
import Control.Exception (bracket_)
|
import Control.Exception (bracket_)
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
|
|
||||||
|
@ -79,7 +78,7 @@ lockContent key a = do
|
||||||
where
|
where
|
||||||
lock Nothing = return Nothing
|
lock Nothing = return Nothing
|
||||||
lock (Just l) = do
|
lock (Just l) = do
|
||||||
v <- try $ setLock l (WriteLock, AbsoluteSeek, 0, 0)
|
v <- tryIO $ setLock l (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
case v of
|
case v of
|
||||||
Left _ -> error "content is locked"
|
Left _ -> error "content is locked"
|
||||||
Right _ -> return $ Just l
|
Right _ -> return $ Just l
|
||||||
|
|
|
@ -91,4 +91,4 @@ lockJournal a = do
|
||||||
{- Runs an action, catching failure and running something to fix it up, and
|
{- Runs an action, catching failure and running something to fix it up, and
|
||||||
- retrying if necessary. -}
|
- retrying if necessary. -}
|
||||||
doRedo :: IO a -> IO b -> IO a
|
doRedo :: IO a -> IO b -> IO a
|
||||||
doRedo a b = catch a $ const $ b >> a
|
doRedo a b = catchIO a $ const $ b >> a
|
||||||
|
|
|
@ -11,7 +11,6 @@ module Annex.Ssh (
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import System.IO.Error (try)
|
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import Annex.LockPool
|
import Annex.LockPool
|
||||||
|
@ -72,7 +71,8 @@ sshCleanup = do
|
||||||
let lockfile = socket2lock socketfile
|
let lockfile = socket2lock socketfile
|
||||||
unlockFile lockfile
|
unlockFile lockfile
|
||||||
fd <- liftIO $ openFd lockfile ReadWrite (Just stdFileMode) defaultFileFlags
|
fd <- liftIO $ openFd lockfile ReadWrite (Just stdFileMode) defaultFileFlags
|
||||||
v <- liftIO $ try $ setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
v <- liftIO $ tryIO $
|
||||||
|
setLock fd (WriteLock, AbsoluteSeek, 0, 0)
|
||||||
case v of
|
case v of
|
||||||
Left _ -> return ()
|
Left _ -> return ()
|
||||||
Right _ -> stopssh socketfile
|
Right _ -> stopssh socketfile
|
||||||
|
|
|
@ -16,7 +16,6 @@ module Backend (
|
||||||
maybeLookupBackendName
|
maybeLookupBackendName
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import System.IO.Error (try)
|
|
||||||
import System.Posix.Files
|
import System.Posix.Files
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
|
@ -77,7 +76,7 @@ genKey' (b:bs) file = do
|
||||||
- by examining what the file symlinks to. -}
|
- by examining what the file symlinks to. -}
|
||||||
lookupFile :: FilePath -> Annex (Maybe (Key, Backend))
|
lookupFile :: FilePath -> Annex (Maybe (Key, Backend))
|
||||||
lookupFile file = do
|
lookupFile file = do
|
||||||
tl <- liftIO $ try getsymlink
|
tl <- liftIO $ tryIO getsymlink
|
||||||
case tl of
|
case tl of
|
||||||
Left _ -> return Nothing
|
Left _ -> return Nothing
|
||||||
Right l -> makekey l
|
Right l -> makekey l
|
||||||
|
|
|
@ -11,7 +11,6 @@ module CmdLine (
|
||||||
shutdown
|
shutdown
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified System.IO.Error as IO
|
|
||||||
import qualified Control.Exception as E
|
import qualified Control.Exception as E
|
||||||
import Control.Exception (throw)
|
import Control.Exception (throw)
|
||||||
import System.Console.GetOpt
|
import System.Console.GetOpt
|
||||||
|
@ -74,7 +73,7 @@ tryRun' errnum _ cmd []
|
||||||
| otherwise = return ()
|
| otherwise = return ()
|
||||||
tryRun' errnum state cmd (a:as) = run >>= handle
|
tryRun' errnum state cmd (a:as) = run >>= handle
|
||||||
where
|
where
|
||||||
run = IO.try $ Annex.run state $ do
|
run = tryIO $ Annex.run state $ do
|
||||||
Annex.Queue.flushWhenFull
|
Annex.Queue.flushWhenFull
|
||||||
a
|
a
|
||||||
handle (Left err) = showerr err >> cont False state
|
handle (Left err) = showerr err >> cont False state
|
||||||
|
|
|
@ -81,7 +81,7 @@ performRemote key file backend numcopies remote = do
|
||||||
t <- fromRepo gitAnnexTmpDir
|
t <- fromRepo gitAnnexTmpDir
|
||||||
let tmp = t </> "fsck" ++ show pid ++ "." ++ keyFile key
|
let tmp = t </> "fsck" ++ show pid ++ "." ++ keyFile key
|
||||||
liftIO $ createDirectoryIfMissing True t
|
liftIO $ createDirectoryIfMissing True t
|
||||||
let cleanup = liftIO $ catch (removeFile tmp) (const $ return ())
|
let cleanup = liftIO $ catchIO (removeFile tmp) (const $ return ())
|
||||||
cleanup
|
cleanup
|
||||||
cleanup `after` a tmp
|
cleanup `after` a tmp
|
||||||
getfile tmp = do
|
getfile tmp = do
|
||||||
|
|
|
@ -21,6 +21,7 @@ import System.Posix.Process as X hiding (executeFile)
|
||||||
import System.Exit as X
|
import System.Exit as X
|
||||||
|
|
||||||
import Utility.Misc as X
|
import Utility.Misc as X
|
||||||
|
import Utility.Exception as X
|
||||||
import Utility.SafeCommand as X
|
import Utility.SafeCommand as X
|
||||||
import Utility.Path as X
|
import Utility.Path as X
|
||||||
import Utility.Directory as X
|
import Utility.Directory as X
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
module Remote.Bup (remote) where
|
module Remote.Bup (remote) where
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy.Char8 as L
|
import qualified Data.ByteString.Lazy.Char8 as L
|
||||||
import System.IO.Error
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import System.Process
|
import System.Process
|
||||||
|
|
||||||
|
@ -200,7 +199,7 @@ getBupUUID :: Git.Repo -> UUID -> Annex (UUID, Git.Repo)
|
||||||
getBupUUID r u
|
getBupUUID r u
|
||||||
| Git.repoIsUrl r = return (u, r)
|
| Git.repoIsUrl r = return (u, r)
|
||||||
| otherwise = liftIO $ do
|
| otherwise = liftIO $ do
|
||||||
ret <- try $ Git.Config.read r
|
ret <- tryIO $ Git.Config.read r
|
||||||
case ret of
|
case ret of
|
||||||
Right r' -> return (toUUID $ Git.Config.get "annex.uuid" "" r', r')
|
Right r' -> return (toUUID $ Git.Config.get "annex.uuid" "" r', r')
|
||||||
Left _ -> return (NoUUID, r)
|
Left _ -> return (NoUUID, r)
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
module Upgrade.V0 where
|
module Upgrade.V0 where
|
||||||
|
|
||||||
import System.IO.Error (try)
|
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import Annex.Content
|
import Annex.Content
|
||||||
import qualified Upgrade.V1
|
import qualified Upgrade.V1
|
||||||
|
@ -47,7 +45,7 @@ getKeysPresent0 dir = do
|
||||||
return $ map fileKey0 files
|
return $ map fileKey0 files
|
||||||
where
|
where
|
||||||
present d = do
|
present d = do
|
||||||
result <- try $
|
result <- tryIO $
|
||||||
getFileStatus $ dir ++ "/" ++ takeFileName d
|
getFileStatus $ dir ++ "/" ++ takeFileName d
|
||||||
case result of
|
case result of
|
||||||
Right s -> return $ isRegularFile s
|
Right s -> return $ isRegularFile s
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
module Upgrade.V1 where
|
module Upgrade.V1 where
|
||||||
|
|
||||||
import System.IO.Error (try)
|
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
|
||||||
|
@ -183,7 +182,7 @@ readLog1 file = catchDefaultIO (parseLog <$> readFileStrict file) []
|
||||||
|
|
||||||
lookupFile1 :: FilePath -> Annex (Maybe (Key, Backend))
|
lookupFile1 :: FilePath -> Annex (Maybe (Key, Backend))
|
||||||
lookupFile1 file = do
|
lookupFile1 file = do
|
||||||
tl <- liftIO $ try getsymlink
|
tl <- liftIO $ tryIO getsymlink
|
||||||
case tl of
|
case tl of
|
||||||
Left _ -> return Nothing
|
Left _ -> return Nothing
|
||||||
Right l -> makekey l
|
Right l -> makekey l
|
||||||
|
@ -216,7 +215,7 @@ getKeyFilesPresent1' dir = do
|
||||||
liftIO $ filterM present files
|
liftIO $ filterM present files
|
||||||
where
|
where
|
||||||
present f = do
|
present f = do
|
||||||
result <- try $ getFileStatus f
|
result <- tryIO $ getFileStatus f
|
||||||
case result of
|
case result of
|
||||||
Right s -> return $ isRegularFile s
|
Right s -> return $ isRegularFile s
|
||||||
Left _ -> return False
|
Left _ -> return False
|
||||||
|
|
|
@ -16,11 +16,12 @@ import Control.Monad.IfElse
|
||||||
|
|
||||||
import Utility.SafeCommand
|
import Utility.SafeCommand
|
||||||
import Utility.TempFile
|
import Utility.TempFile
|
||||||
|
import Utility.Exception
|
||||||
|
|
||||||
{- Moves one filename to another.
|
{- Moves one filename to another.
|
||||||
- First tries a rename, but falls back to moving across devices if needed. -}
|
- First tries a rename, but falls back to moving across devices if needed. -}
|
||||||
moveFile :: FilePath -> FilePath -> IO ()
|
moveFile :: FilePath -> FilePath -> IO ()
|
||||||
moveFile src dest = try (rename src dest) >>= onrename
|
moveFile src dest = tryIO (rename src dest) >>= onrename
|
||||||
where
|
where
|
||||||
onrename (Right _) = return ()
|
onrename (Right _) = return ()
|
||||||
onrename (Left e)
|
onrename (Left e)
|
||||||
|
@ -40,11 +41,10 @@ moveFile src dest = try (rename src dest) >>= onrename
|
||||||
Param src, Param tmp]
|
Param src, Param tmp]
|
||||||
unless ok $ do
|
unless ok $ do
|
||||||
-- delete any partial
|
-- delete any partial
|
||||||
_ <- try $
|
_ <- tryIO $ removeFile tmp
|
||||||
removeFile tmp
|
|
||||||
rethrow
|
rethrow
|
||||||
isdir f = do
|
isdir f = do
|
||||||
r <- try (getFileStatus f)
|
r <- tryIO $ getFileStatus f
|
||||||
case r of
|
case r of
|
||||||
(Left _) -> return False
|
(Left _) -> return False
|
||||||
(Right s) -> return $ isDirectory s
|
(Right s) -> return $ isDirectory s
|
||||||
|
|
39
Utility/Exception.hs
Normal file
39
Utility/Exception.hs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{- Simple IO exception handling
|
||||||
|
-
|
||||||
|
- Copyright 2011-2012 Joey Hess <joey@kitenet.net>
|
||||||
|
-
|
||||||
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Utility.Exception where
|
||||||
|
|
||||||
|
import Prelude hiding (catch)
|
||||||
|
import Control.Exception
|
||||||
|
import Control.Applicative
|
||||||
|
|
||||||
|
{- Catches IO errors and returns a Bool -}
|
||||||
|
catchBoolIO :: IO Bool -> IO Bool
|
||||||
|
catchBoolIO a = catchDefaultIO a False
|
||||||
|
|
||||||
|
{- Catches IO errors and returns a Maybe -}
|
||||||
|
catchMaybeIO :: IO a -> IO (Maybe a)
|
||||||
|
catchMaybeIO a = catchDefaultIO (Just <$> a) Nothing
|
||||||
|
|
||||||
|
{- Catches IO errors and returns a default value. -}
|
||||||
|
catchDefaultIO :: IO a -> a -> IO a
|
||||||
|
catchDefaultIO a def = catchIO a (const $ return def)
|
||||||
|
|
||||||
|
{- Catches IO errors and returns the error message. -}
|
||||||
|
catchMsgIO :: IO a -> IO (Either String a)
|
||||||
|
catchMsgIO a = dispatch <$> tryIO a
|
||||||
|
where
|
||||||
|
dispatch (Left e) = Left $ show e
|
||||||
|
dispatch (Right v) = Right v
|
||||||
|
|
||||||
|
{- catch specialized for IO errors only -}
|
||||||
|
catchIO :: IO a -> (IOException -> IO a) -> IO a
|
||||||
|
catchIO = catch
|
||||||
|
|
||||||
|
{- try specialized for IO errors only -}
|
||||||
|
tryIO :: IO a -> IO (Either IOException a)
|
||||||
|
tryIO = try
|
|
@ -8,9 +8,7 @@
|
||||||
module Utility.Misc where
|
module Utility.Misc where
|
||||||
|
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.IO.Error (try)
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Applicative
|
|
||||||
import GHC.IO.Encoding
|
import GHC.IO.Encoding
|
||||||
|
|
||||||
{- Sets a Handle to use the filesystem encoding. This causes data
|
{- Sets a Handle to use the filesystem encoding. This causes data
|
||||||
|
@ -45,22 +43,3 @@ separate c l = unbreak $ break c l
|
||||||
{- Breaks out the first line. -}
|
{- Breaks out the first line. -}
|
||||||
firstLine :: String-> String
|
firstLine :: String-> String
|
||||||
firstLine = takeWhile (/= '\n')
|
firstLine = takeWhile (/= '\n')
|
||||||
|
|
||||||
{- Catches IO errors and returns a Bool -}
|
|
||||||
catchBoolIO :: IO Bool -> IO Bool
|
|
||||||
catchBoolIO a = catchDefaultIO a False
|
|
||||||
|
|
||||||
{- Catches IO errors and returns a Maybe -}
|
|
||||||
catchMaybeIO :: IO a -> IO (Maybe a)
|
|
||||||
catchMaybeIO a = catchDefaultIO (Just <$> a) Nothing
|
|
||||||
|
|
||||||
{- Catches IO errors and returns a default value. -}
|
|
||||||
catchDefaultIO :: IO a -> a -> IO a
|
|
||||||
catchDefaultIO a def = catch a (const $ return def)
|
|
||||||
|
|
||||||
{- Catches IO errors and returns the error message. -}
|
|
||||||
catchMsgIO :: IO a -> IO (Either String a)
|
|
||||||
catchMsgIO a = dispatch <$> try a
|
|
||||||
where
|
|
||||||
dispatch (Left e) = Left $ show e
|
|
||||||
dispatch (Right v) = Right v
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import System.IO
|
||||||
import System.Posix.Process hiding (executeFile)
|
import System.Posix.Process hiding (executeFile)
|
||||||
import System.Directory
|
import System.Directory
|
||||||
|
|
||||||
import Utility.Misc
|
import Utility.Exception
|
||||||
import Utility.Path
|
import Utility.Path
|
||||||
|
|
||||||
{- Runs an action like writeFile, writing to a temp file first and
|
{- Runs an action like writeFile, writing to a temp file first and
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
This bug is reopened to track some new UTF-8 filename issues caused by GHC
|
This bug is reopened to track some new UTF-8 filename issues caused by GHC
|
||||||
7.4. Older versions of GHC, like the 7.0.4 in debian unstable, are not
|
7.4. In this version of GHC, git-annex's hack to support filenames in any
|
||||||
affected. See the comments for details about the new bug. --[[Joey]]
|
encoding no longer works. Even unicode filenames fail to work when
|
||||||
|
git-annex is built with 7.4. --[[Joey]]
|
||||||
|
|
||||||
|
I now have a `ghc7.4` branch in git that seems to solve this,
|
||||||
|
for all filename encodings, and all system encodings. It will
|
||||||
|
only build with the new GHC. If you have this problem, give it a try!
|
||||||
|
--[[Joey]]
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -74,39 +80,3 @@ It looks like the common latin1-to-UTF8 encoding. Functionality other than otupu
|
||||||
> > On second thought, I switched to this. Any decoding of a filename
|
> > On second thought, I switched to this. Any decoding of a filename
|
||||||
> > is going to make someone unhappy; the previous approach broke
|
> > is going to make someone unhappy; the previous approach broke
|
||||||
> > non-utf8 filenames.
|
> > non-utf8 filenames.
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Simpler test case:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
import Codec.Binary.UTF8.String
|
|
||||||
import System.Environment
|
|
||||||
|
|
||||||
main = do
|
|
||||||
args <- getArgs
|
|
||||||
let file = decodeString $ head args
|
|
||||||
putStrLn $ "file is: " ++ file
|
|
||||||
putStr =<< readFile file
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
If I pass this a filename like 'ü', it will fail, and notice
|
|
||||||
the bad encoding of the filename in the error message:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
$ echo hi > ü; runghc foo.hs ü
|
|
||||||
file is: ü
|
|
||||||
foo.hs: <20>: openFile: does not exist (No such file or directory)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
On the other hand, if I remove the decodeString, it prints the filename
|
|
||||||
wrong, while accessing it right:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
$ runghc foo.hs ü
|
|
||||||
file is: üa
|
|
||||||
hi
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
The only way that seems to consistently work is to delay decoding the
|
|
||||||
filename to places where it's output. But then it's easy to miss some.
|
|
||||||
|
|
|
@ -1,25 +1,16 @@
|
||||||
short answer: no
|
Can it be built on Windows?
|
||||||
|
|
||||||
Long answer, quoting from a mail to someone else:
|
short answer: not yet
|
||||||
|
|
||||||
Well, I can tell you that it assumes a POSIX system, both in available
|
First, you need to get some unix utilities for windows. Git of course.
|
||||||
utilities and system calls, So you'd need to use cygwin or something
|
Also rsync, and a `cp` command that understands at least `cp -p`, and
|
||||||
like that. (Perhaps you already are for git, I think git also assumes a
|
`uuid`, and `xargs` and `sha1sum`. Note that some of these could be
|
||||||
POSIX system.) So you need a Haskell that can target that. What this
|
replaced with haskell libraries to some degree.
|
||||||
page refers to as "GHC-Cygwin":
|
|
||||||
<http://www.haskell.org/ghc/docs/6.6/html/building/platforms.html>
|
|
||||||
I don't know where to get one. Did find this:
|
|
||||||
<http://copilotco.com/mail-archives/haskell-cafe.2007/msg00824.html>
|
|
||||||
|
|
||||||
(There are probably also still some places where it assumes / as a path
|
There are probably still some places where it assumes / as a path
|
||||||
separator, although I fixed some. Probably almost all are fixed now.)
|
separator, although I fixed probably almost all by now.
|
||||||
|
|
||||||
FWIW, git-annex works fine on OS X and other fine proprietary unixen. ;P
|
Then windows versions of these functions could be found,
|
||||||
--[[Joey]]
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Alternatively, windows versions of these functions could be found,
|
|
||||||
which are all the ones that need POSIX, I think. A fair amount of this,
|
which are all the ones that need POSIX, I think. A fair amount of this,
|
||||||
the stuff to do with signals and users, could be empty stubs in windows.
|
the stuff to do with signals and users, could be empty stubs in windows.
|
||||||
The file manipulation, particularly symlinks, would probably be the main
|
The file manipulation, particularly symlinks, would probably be the main
|
||||||
|
@ -63,3 +54,8 @@ sigCHLD
|
||||||
sigINT
|
sigINT
|
||||||
unionFileModes
|
unionFileModes
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
A good starting point is
|
||||||
|
<http://hackage.haskell.org/package/unix-compat-0.3.0.1>. However, note
|
||||||
|
that its implementations of stuff like `createSymbolicLink` are stubs.
|
||||||
|
--[[Joey]]
|
||||||
|
|
Loading…
Reference in a new issue