git-annex/LocationLog.hs

104 lines
3.1 KiB
Haskell
Raw Normal View History

2010-10-09 23:22:40 +00:00
{- git-annex location log
-
- git-annex keeps track of on which repository it last saw a file's content.
- This can be useful when using it for archiving with offline storage.
- When you indicate you --want a file, git-annex will tell you which
- repositories have the file's content.
-
- Location tracking information is stored in `.git-annex/$filename.log`.
- Repositories record their name and the date when they --get or --drop
- a file's content. (Git is configured to use a union merge for this file,
- so the lines may be in arbitrary order, but it will never conflict.)
-
2010-10-10 02:29:16 +00:00
- A line of the log will look like: "date N reponame filename"
- Where N=1 when the repo has the file, and 0 otherwise.
2010-10-09 23:22:40 +00:00
-
-}
module LocationLog where
import Data.DateTime
import System.IO
import System.Posix.IO
2010-10-10 02:14:13 +00:00
import GitRepo
2010-10-09 23:22:40 +00:00
2010-10-10 02:29:16 +00:00
data LogStatus = FilePresent | FileMissing | Undefined
deriving (Eq)
instance Show LogStatus where
show FilePresent = "1"
show FileMissing = "0"
show Undefined = "undefined"
instance Read LogStatus where
readsPrec _ "1" = [(FilePresent, "")]
readsPrec _ "0" = [(FileMissing, "")]
readsPrec _ _ = [(Undefined, "")]
2010-10-09 23:22:40 +00:00
data LogLine = LogLine {
date :: DateTime,
2010-10-10 02:29:16 +00:00
status :: LogStatus,
2010-10-09 23:22:40 +00:00
repo :: String,
file :: String
} deriving (Eq)
instance Show LogLine where
2010-10-10 02:29:16 +00:00
show (LogLine date status repo file) = unwords
[(show (toSeconds date)), (show status), repo, file]
2010-10-09 23:22:40 +00:00
instance Read LogLine where
2010-10-10 02:29:16 +00:00
-- This parser is robust in that even unparsable log lines are
-- read without an exception being thrown.
-- Such lines have a status of Undefined.
2010-10-09 23:22:40 +00:00
readsPrec _ string = if (length w >= 3)
2010-10-10 02:29:16 +00:00
then [((LogLine date status repo file), "")]
else [((LogLine (fromSeconds 0) Undefined "" ""), "")]
2010-10-09 23:22:40 +00:00
where
2010-10-10 02:29:16 +00:00
date = fromSeconds $ read $ w !! 0
status = read $ w !! 1
repo = w !! 2
2010-10-09 23:22:40 +00:00
file = unwords $ rest w
w = words string
2010-10-10 02:29:16 +00:00
rest (_:_:_:l) = l
2010-10-09 23:22:40 +00:00
{- Reads a log file -}
readLog :: String -> IO [LogLine]
readLog file = do
h <- openLocked file ReadMode
s <- hGetContents h
-- hClose handle' -- TODO disabled due to lazy IO issue
-- filter out any unparsable lines
2010-10-10 02:29:16 +00:00
return $ filter (\l -> (status l) /= Undefined ) $ map read $ lines s
2010-10-09 23:22:40 +00:00
{- Adds a LogLine to a log file -}
writeLog :: String -> LogLine -> IO ()
writeLog file line = do
h <- openLocked file AppendMode
hPutStrLn h $ show line
hClose h
{- Let's just say that Haskell makes reading/writing a file with
- file locking excessively difficult. -}
openLocked file mode = do
handle <- openFile file mode
lockfd <- handleToFd handle -- closes handle
waitToSetLock lockfd (lockType mode, AbsoluteSeek, 0, 0)
handle' <- fdToHandle lockfd
return handle'
where
lockType ReadMode = ReadLock
lockType _ = WriteLock
{- Generates a new log line with the current date. -}
2010-10-10 02:29:16 +00:00
logNow :: LogStatus -> String -> String -> IO LogLine
logNow status repo file = do
2010-10-09 23:22:40 +00:00
now <- getCurrentTime
2010-10-10 02:29:16 +00:00
return $ LogLine now status repo file
2010-10-10 02:14:13 +00:00
{- Returns the filename of the log file for a given annexed file. -}
logFile :: String -> IO String
logFile annexedFile = do
repo <- repoTop
return $ repo ++ "/.git-annex/" ++
(gitRelative repo annexedFile) ++ ".log"