112 lines
3.3 KiB
Haskell
112 lines
3.3 KiB
Haskell
{- git-annex unused log file
|
|
-
|
|
- This file is stored locally in .git/annex/, not in the git-annex branch.
|
|
-
|
|
- The format: "int key timestamp"
|
|
-
|
|
- The int is a short, stable identifier that the user can use to
|
|
- refer to this key. (Equivalent to a filename.)
|
|
-
|
|
- The timestamp indicates when the key was first determined to be unused.
|
|
- Older versions of the log omit the timestamp.
|
|
-
|
|
- Copyright 2010-2014 Joey Hess <id@joeyh.name>
|
|
-
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
module Logs.Unused (
|
|
UnusedMap,
|
|
updateUnusedLog,
|
|
readUnusedLog,
|
|
readUnusedMap,
|
|
dateUnusedLog,
|
|
unusedKeys,
|
|
unusedKeys',
|
|
setUnusedKeys,
|
|
) where
|
|
|
|
import qualified Data.Map as M
|
|
import qualified Data.Set as S
|
|
import Data.Time.Clock.POSIX
|
|
import Data.Time
|
|
|
|
import Annex.Common
|
|
import qualified Annex
|
|
import Utility.TimeStamp
|
|
import Logs.File
|
|
|
|
-- everything that is stored in the unused log
|
|
type UnusedLog = M.Map Key (Int, Maybe POSIXTime)
|
|
|
|
-- used to look up unused keys specified by the user
|
|
type UnusedMap = M.Map Int Key
|
|
|
|
log2map :: UnusedLog -> UnusedMap
|
|
log2map = M.fromList . map (\(k, (i, _t)) -> (i, k)) . M.toList
|
|
|
|
map2log :: POSIXTime -> UnusedMap -> UnusedLog
|
|
map2log t = M.fromList . map (\(i, k) -> (k, (i, Just t))) . M.toList
|
|
|
|
{- Only keeps keys that are in the new log, but uses any timestamps
|
|
- those keys had in the old log. -}
|
|
preserveTimestamps :: UnusedLog -> UnusedLog -> UnusedLog
|
|
preserveTimestamps oldl newl = M.intersection (M.unionWith oldts oldl newl) newl
|
|
where
|
|
oldts _old@(_, ts) _new@(int, _) = (int, ts)
|
|
|
|
updateUnusedLog :: RawFilePath -> UnusedMap -> Annex ()
|
|
updateUnusedLog prefix m = do
|
|
oldl <- readUnusedLog prefix
|
|
newl <- preserveTimestamps oldl . flip map2log m <$> liftIO getPOSIXTime
|
|
writeUnusedLog prefix newl
|
|
|
|
writeUnusedLog :: RawFilePath -> UnusedLog -> Annex ()
|
|
writeUnusedLog prefix l = do
|
|
logfile <- fromRepo $ gitAnnexUnusedLog prefix
|
|
writeLogFile logfile $ unlines $ map format $ M.toList l
|
|
where
|
|
format (k, (i, Just t)) = show i ++ " " ++ serializeKey k ++ " " ++ show t
|
|
format (k, (i, Nothing)) = show i ++ " " ++ serializeKey k
|
|
|
|
readUnusedLog :: RawFilePath -> Annex UnusedLog
|
|
readUnusedLog prefix = do
|
|
f <- fromRawFilePath <$> fromRepo (gitAnnexUnusedLog prefix)
|
|
ifM (liftIO $ doesFileExist f)
|
|
( M.fromList . mapMaybe parse . lines
|
|
<$> liftIO (readFileStrict f)
|
|
, return M.empty
|
|
)
|
|
where
|
|
parse line = case (readish sint, deserializeKey skey, parsePOSIXTime ts) of
|
|
(Just int, Just key, mtimestamp) -> Just (key, (int, mtimestamp))
|
|
_ -> Nothing
|
|
where
|
|
(sint, rest) = separate (== ' ') line
|
|
(rts, rskey) = separate (== ' ') (reverse rest)
|
|
skey = reverse rskey
|
|
ts = reverse rts
|
|
|
|
readUnusedMap :: RawFilePath -> Annex UnusedMap
|
|
readUnusedMap = log2map <$$> readUnusedLog
|
|
|
|
dateUnusedLog :: RawFilePath -> Annex (Maybe UTCTime)
|
|
dateUnusedLog prefix = do
|
|
f <- fromRepo $ gitAnnexUnusedLog prefix
|
|
liftIO $ catchMaybeIO $ getModificationTime $ fromRawFilePath f
|
|
|
|
{- Set of unused keys. This is cached for speed. -}
|
|
unusedKeys :: Annex (S.Set Key)
|
|
unusedKeys = maybe (setUnusedKeys =<< unusedKeys') return
|
|
=<< Annex.getState Annex.unusedkeys
|
|
|
|
unusedKeys' :: Annex [Key]
|
|
unusedKeys' = M.keys <$> readUnusedLog ""
|
|
|
|
setUnusedKeys :: [Key] -> Annex (S.Set Key)
|
|
setUnusedKeys ks = do
|
|
let v = S.fromList ks
|
|
Annex.changeState $ \s -> s { Annex.unusedkeys = Just v }
|
|
return v
|