fix bug that turned files already in git into symlinks

This requires a relatively expensive test at file add time to see if it's
in git already. But it can be optimised to only happen during the startup
scan.
This commit is contained in:
Joey Hess 2012-06-12 14:50:54 -04:00
parent 535d9e4998
commit 7d2c813396
2 changed files with 22 additions and 9 deletions

View file

@ -48,6 +48,7 @@ import qualified Command.Add
import qualified Git.Command import qualified Git.Command
import qualified Git.UpdateIndex import qualified Git.UpdateIndex
import qualified Git.HashObject import qualified Git.HashObject
import qualified Git.LsFiles
import qualified Backend import qualified Backend
import Annex.Content import Annex.Content
import Annex.CatFile import Annex.CatFile
@ -67,7 +68,7 @@ import System.INotify
type ChangeChan = TChan Change type ChangeChan = TChan Change
type Handler = FilePath -> Annex (Maybe Change) type Handler = FilePath -> Bool -> Annex (Maybe Change)
data Change = Change data Change = Change
{ changeTime :: UTCTime { changeTime :: UTCTime
@ -173,9 +174,9 @@ runChangeChan = atomically
- -
- Exceptions are ignored, otherwise a whole watcher thread could be crashed. - Exceptions are ignored, otherwise a whole watcher thread could be crashed.
-} -}
runHandler :: MVar Annex.AnnexState -> ChangeChan -> Handler -> FilePath -> IO () runHandler :: MVar Annex.AnnexState -> ChangeChan -> Handler -> FilePath -> Bool -> IO ()
runHandler st changechan handler file = void $ do runHandler st changechan handler file inscan = void $ do
r <- tryIO (runStateMVar st $ handler file) r <- tryIO (runStateMVar st $ handler file inscan)
case r of case r of
Left e -> print e Left e -> print e
Right Nothing -> noop Right Nothing -> noop
@ -201,7 +202,7 @@ noChange = return Nothing
- or return a Change, leaving that to onAddSymlink. - or return a Change, leaving that to onAddSymlink.
-} -}
onAdd :: Handler onAdd :: Handler
onAdd file = do onAdd file False = do
showStart "add" file showStart "add" file
handle =<< Command.Add.ingest file handle =<< Command.Add.ingest file
noChange noChange
@ -210,13 +211,23 @@ onAdd file = do
handle (Just key) = do handle (Just key) = do
Command.Add.link file key True Command.Add.link file key True
showEndOk showEndOk
{- During initial directory scan, this will be run for any files that
- are already checked into git. We don't want to turn those into symlinks,
- so do a check. This is rather expensive, but only happens during
- startup, and when a directory is moved into the tree. -}
onAdd file True = do
liftIO $ putStrLn $ "expensive check for " ++ file
ifM (null <$> inRepo (Git.LsFiles.notInRepo False [file]))
( noChange
, onAdd file False
)
{- A symlink might be an arbitrary symlink, which is just added. {- A symlink might be an arbitrary symlink, which is just added.
- Or, if it is a git-annex symlink, ensure it points to the content - Or, if it is a git-annex symlink, ensure it points to the content
- before adding it. - before adding it.
-} -}
onAddSymlink :: Handler onAddSymlink :: Handler
onAddSymlink file = go =<< Backend.lookupFile file onAddSymlink file _inscan = go =<< Backend.lookupFile file
where where
go Nothing = addlink =<< liftIO (readSymbolicLink file) go Nothing = addlink =<< liftIO (readSymbolicLink file)
go (Just (key, _)) = do go (Just (key, _)) = do
@ -249,7 +260,7 @@ onAddSymlink file = go =<< Backend.lookupFile file
madeChange file "link" madeChange file "link"
onDel :: Handler onDel :: Handler
onDel file = do onDel file _inscan = do
Annex.Queue.addUpdateIndex =<< Annex.Queue.addUpdateIndex =<<
inRepo (Git.UpdateIndex.unstageFile file) inRepo (Git.UpdateIndex.unstageFile file)
madeChange file "rm" madeChange file "rm"
@ -262,14 +273,14 @@ onDel file = do
- command to get the recursive list of files in the directory, so rm is - command to get the recursive list of files in the directory, so rm is
- just as good. -} - just as good. -}
onDelDir :: Handler onDelDir :: Handler
onDelDir dir = do onDelDir dir _inscan = do
Annex.Queue.addCommand "rm" Annex.Queue.addCommand "rm"
[Params "--quiet -r --cached --ignore-unmatch --"] [dir] [Params "--quiet -r --cached --ignore-unmatch --"] [dir]
madeChange dir "rmdir" madeChange dir "rmdir"
{- Called when there's an error with inotify. -} {- Called when there's an error with inotify. -}
onErr :: Handler onErr :: Handler
onErr msg = do onErr msg _inscan = do
warning msg warning msg
return Nothing return Nothing

View file

@ -64,6 +64,8 @@ watchDir :: INotify -> FilePath -> (FilePath -> Bool) -> WatchHooks -> IO ()
watchDir i dir ignored hooks watchDir i dir ignored hooks
| ignored dir = noop | ignored dir = noop
| otherwise = do | otherwise = do
-- Use a lock to make sure events generated during initial
-- scan come before real inotify events.
lock <- newLock lock <- newLock
let handler event = withLock lock (void $ go event) let handler event = withLock lock (void $ go event)
void (addWatch i watchevents dir handler) void (addWatch i watchevents dir handler)