2018-01-02 21:17:10 +00:00
|
|
|
{- git-annex log files
|
|
|
|
-
|
|
|
|
- Copyright 2018 Joey Hess <id@joeyh.name>
|
|
|
|
-
|
2018-10-25 18:43:13 +00:00
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
2018-01-02 21:17:10 +00:00
|
|
|
-}
|
|
|
|
|
2019-05-20 20:37:04 +00:00
|
|
|
module Logs.File (writeLogFile, withLogHandle, appendLogFile, streamLogFile) where
|
2018-01-02 21:17:10 +00:00
|
|
|
|
|
|
|
import Annex.Common
|
|
|
|
import Annex.Perms
|
2018-10-25 18:43:13 +00:00
|
|
|
import Annex.LockFile
|
2019-05-20 20:37:04 +00:00
|
|
|
import Annex.ReplaceFile
|
2018-10-25 18:43:13 +00:00
|
|
|
import qualified Git
|
2018-01-02 21:17:10 +00:00
|
|
|
import Utility.Tmp
|
|
|
|
|
2018-01-04 18:46:58 +00:00
|
|
|
-- | Writes content to a file, replacing the file atomically, and
|
|
|
|
-- making the new file have whatever permissions the git repository is
|
|
|
|
-- configured to use. Creates the parent directory when necessary.
|
2018-01-02 21:17:10 +00:00
|
|
|
writeLogFile :: FilePath -> String -> Annex ()
|
2018-10-25 18:43:13 +00:00
|
|
|
writeLogFile f c = createDirWhenNeeded f $ viaTmp writelog f c
|
2018-01-02 21:17:10 +00:00
|
|
|
where
|
|
|
|
writelog f' c' = do
|
|
|
|
liftIO $ writeFile f' c'
|
|
|
|
setAnnexFilePerm f'
|
2018-10-25 18:43:13 +00:00
|
|
|
|
2019-05-20 20:37:04 +00:00
|
|
|
-- | Runs the action with a handle connected to a temp file.
|
|
|
|
-- The temp file replaces the log file once the action succeeds.
|
|
|
|
withLogHandle :: FilePath -> (Handle -> Annex a) -> Annex a
|
|
|
|
withLogHandle f a = do
|
|
|
|
createAnnexDirectory (parentDir f)
|
2020-03-06 15:31:01 +00:00
|
|
|
replaceGitAnnexDirFile f $ \tmp ->
|
2019-05-20 20:37:04 +00:00
|
|
|
bracket (setup tmp) cleanup a
|
|
|
|
where
|
|
|
|
setup tmp = do
|
|
|
|
setAnnexFilePerm tmp
|
|
|
|
liftIO $ openFile tmp WriteMode
|
|
|
|
cleanup h = liftIO $ hClose h
|
|
|
|
|
2018-10-25 18:43:13 +00:00
|
|
|
-- | Appends a line to a log file, first locking it to prevent
|
|
|
|
-- concurrent writers.
|
|
|
|
appendLogFile :: FilePath -> (Git.Repo -> FilePath) -> String -> Annex ()
|
|
|
|
appendLogFile f lck c = createDirWhenNeeded f $ withExclusiveLock lck $ do
|
|
|
|
liftIO $ withFile f AppendMode $ \h -> hPutStrLn h c
|
|
|
|
setAnnexFilePerm f
|
|
|
|
|
|
|
|
-- | Streams lines from a log file, and then empties the file at the end.
|
|
|
|
--
|
|
|
|
-- If the action is interrupted or throws an exception, the log file is
|
|
|
|
-- left unchanged.
|
|
|
|
--
|
|
|
|
-- Does nothing if the log file does not exist.
|
|
|
|
--
|
|
|
|
-- Locking is used to prevent writes to to the log file while this
|
|
|
|
-- is running.
|
|
|
|
streamLogFile :: FilePath -> (Git.Repo -> FilePath) -> (String -> Annex ()) -> Annex ()
|
|
|
|
streamLogFile f lck a = withExclusiveLock lck $ bracketOnError setup cleanup go
|
|
|
|
where
|
|
|
|
setup = liftIO $ tryWhenExists $ openFile f ReadMode
|
|
|
|
cleanup Nothing = noop
|
|
|
|
cleanup (Just h) = liftIO $ hClose h
|
|
|
|
go Nothing = noop
|
|
|
|
go (Just h) = do
|
|
|
|
mapM_ a =<< liftIO (lines <$> hGetContents h)
|
|
|
|
liftIO $ hClose h
|
|
|
|
liftIO $ writeFile f ""
|
|
|
|
setAnnexFilePerm f
|
|
|
|
|
|
|
|
createDirWhenNeeded :: FilePath -> Annex () -> Annex ()
|
|
|
|
createDirWhenNeeded f a = a `catchNonAsync` \_e -> do
|
|
|
|
-- Most of the time, the directory will exist, so this is only
|
|
|
|
-- done if writing the file fails.
|
|
|
|
createAnnexDirectory (parentDir f)
|
|
|
|
a
|