2011-12-12 22:03:28 +00:00
|
|
|
{- management of the git-annex journal and cache
|
|
|
|
-
|
|
|
|
- The journal is used to queue up changes before they are committed to the
|
|
|
|
- git-annex branch. Amoung other things, it ensures that if git-annex is
|
|
|
|
- interrupted, its recorded data is not lost.
|
|
|
|
-
|
|
|
|
- Copyright 2011 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
|
|
|
module Annex.Journal where
|
|
|
|
|
|
|
|
import System.IO.Binary
|
|
|
|
|
|
|
|
import Common.Annex
|
|
|
|
import Annex.Exception
|
|
|
|
import qualified Git
|
2012-04-21 20:59:49 +00:00
|
|
|
import Annex.Perms
|
2011-12-12 22:03:28 +00:00
|
|
|
|
|
|
|
{- Records content for a file in the branch to the journal.
|
|
|
|
-
|
|
|
|
- Using the journal, rather than immediatly staging content to the index
|
|
|
|
- avoids git needing to rewrite the index after every change. -}
|
|
|
|
setJournalFile :: FilePath -> String -> Annex ()
|
|
|
|
setJournalFile file content = do
|
2012-04-21 20:59:49 +00:00
|
|
|
createAnnexDirectory =<< fromRepo gitAnnexJournalDir
|
|
|
|
createAnnexDirectory =<< fromRepo gitAnnexTmpDir
|
|
|
|
-- journal file is written atomically
|
|
|
|
jfile <- fromRepo $ journalFile file
|
|
|
|
tmp <- fromRepo gitAnnexTmpDir
|
|
|
|
let tmpfile = tmp </> takeFileName jfile
|
|
|
|
liftIO $ do
|
|
|
|
writeBinaryFile tmpfile content
|
|
|
|
moveFile tmpfile jfile
|
2011-12-12 22:03:28 +00:00
|
|
|
|
|
|
|
{- Gets any journalled content for a file in the branch. -}
|
|
|
|
getJournalFile :: FilePath -> Annex (Maybe String)
|
|
|
|
getJournalFile file = inRepo $ \g -> catchMaybeIO $
|
2012-04-21 20:59:49 +00:00
|
|
|
readFileStrict $ journalFile file g
|
2011-12-12 22:03:28 +00:00
|
|
|
|
|
|
|
{- List of files that have updated content in the journal. -}
|
|
|
|
getJournalledFiles :: Annex [FilePath]
|
|
|
|
getJournalledFiles = map fileJournal <$> getJournalFiles
|
|
|
|
|
|
|
|
{- List of existing journal files. -}
|
|
|
|
getJournalFiles :: Annex [FilePath]
|
|
|
|
getJournalFiles = do
|
|
|
|
g <- gitRepo
|
|
|
|
fs <- liftIO $
|
|
|
|
catchDefaultIO (getDirectoryContents $ gitAnnexJournalDir g) []
|
|
|
|
return $ filter (`notElem` [".", ".."]) fs
|
|
|
|
|
|
|
|
{- Checks if there are changes in the journal. -}
|
|
|
|
journalDirty :: Annex Bool
|
|
|
|
journalDirty = not . null <$> getJournalFiles
|
|
|
|
|
|
|
|
{- Produces a filename to use in the journal for a file on the branch.
|
|
|
|
-
|
|
|
|
- The journal typically won't have a lot of files in it, so the hashing
|
|
|
|
- used in the branch is not necessary, and all the files are put directly
|
|
|
|
- in the journal directory.
|
|
|
|
-}
|
2012-04-21 20:59:49 +00:00
|
|
|
journalFile :: FilePath -> Git.Repo -> FilePath
|
|
|
|
journalFile file repo = gitAnnexJournalDir repo </> concatMap mangle file
|
2011-12-12 22:03:28 +00:00
|
|
|
where
|
|
|
|
mangle '/' = "_"
|
|
|
|
mangle '_' = "__"
|
|
|
|
mangle c = [c]
|
|
|
|
|
|
|
|
{- Converts a journal file (relative to the journal dir) back to the
|
|
|
|
- filename on the branch. -}
|
|
|
|
fileJournal :: FilePath -> FilePath
|
|
|
|
fileJournal = replace "//" "_" . replace "_" "/"
|
|
|
|
|
|
|
|
{- Runs an action that modifies the journal, using locking to avoid
|
|
|
|
- contention with other git-annex processes. -}
|
|
|
|
lockJournal :: Annex a -> Annex a
|
|
|
|
lockJournal a = do
|
|
|
|
file <- fromRepo gitAnnexJournalLock
|
2012-04-21 20:59:49 +00:00
|
|
|
createAnnexDirectory $ takeDirectory file
|
|
|
|
mode <- annexFileMode
|
|
|
|
bracketIO (lock file mode) unlock a
|
2011-12-12 22:03:28 +00:00
|
|
|
where
|
2012-04-21 20:59:49 +00:00
|
|
|
lock file mode = do
|
|
|
|
l <- noUmask mode $ createFile file mode
|
2011-12-12 22:03:28 +00:00
|
|
|
waitToSetLock l (WriteLock, AbsoluteSeek, 0, 0)
|
|
|
|
return l
|
|
|
|
unlock = closeFd
|