summaryrefslogtreecommitdiff
path: root/Logs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-03-18 18:55:43 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-03-18 18:55:43 -0400
commit2402266d0d9731445af1876327a43795795d1a18 (patch)
tree2f52191002e8ee79275c2f4e6070b057a61f9389 /Logs
parent9adb236103d0b8f1db8110b40cc33b9fe5fda4ae (diff)
Each for each metadata field, there's now an automatically maintained "$field-lastchanged" that gives the timestamp of the last change to that field.
Note that this is a nearly entirely free feature. The data was already stored in the metadata log in an easily accessible way, and already was parsed to a time when parsing the log. The generation of the metadata fields may even be done lazily, although probably not entirely (the map has to be evaulated to when queried).
Diffstat (limited to 'Logs')
-rw-r--r--Logs/MetaData.hs42
1 files changed, 34 insertions, 8 deletions
diff --git a/Logs/MetaData.hs b/Logs/MetaData.hs
index 6702c3733..724f309ff 100644
--- a/Logs/MetaData.hs
+++ b/Logs/MetaData.hs
@@ -36,26 +36,50 @@ module Logs.MetaData (
import Common.Annex
import Types.MetaData
+import Annex.MetaData.StandardFields
import qualified Annex.Branch
import Logs
import Logs.SingleValue
import qualified Data.Set as S
+import qualified Data.Map as M
import Data.Time.Clock.POSIX
+import Data.Time.Format
+import System.Locale
instance SingleValueSerializable MetaData where
serialize = Types.MetaData.serialize
deserialize = Types.MetaData.deserialize
-getMetaData :: Key -> Annex (Log MetaData)
-getMetaData = readLog . metaDataLogFile
+getMetaDataLog :: Key -> Annex (Log MetaData)
+getMetaDataLog = readLog . metaDataLogFile
{- Go through the log from oldest to newest, and combine it all
- - into a single MetaData representing the current state. -}
+ - into a single MetaData representing the current state.
+ -
+ - Automatically generates a lastchanged metadata for each field that's
+ - currently set, based on timestamps in the log.
+ -}
getCurrentMetaData :: Key -> Annex MetaData
-getCurrentMetaData = currentMetaData . collect <$$> getMetaData
+getCurrentMetaData k = do
+ ls <- S.toAscList <$> getMetaDataLog k
+ let loggedmeta = currentMetaData $ combineMetaData $ map value ls
+ return $ currentMetaData $ unionMetaData loggedmeta
+ (lastchanged ls loggedmeta)
where
- collect = foldl' unionMetaData emptyMetaData . map value . S.toAscList
+ lastchanged ls (MetaData wanted) =
+ let m = foldl' (flip M.union) M.empty (map genlastchanged ls)
+ in MetaData $ M.mapKeys lastChangedField $
+ -- Only include fields that are currently set.
+ m `M.intersection` wanted
+ -- Makes each field have the timestamp as its value.
+ genlastchanged l =
+ let MetaData m = value l
+ ts = S.singleton $ toMetaValue $
+ formatTime defaultTimeLocale "%s" $
+ posixSecondsToUTCTime $
+ changed l
+ in M.map (const ts) m
{- Adds in some metadata, which can override existing values, or unset
- them, but otherwise leaves any existing metadata as-is. -}
@@ -67,10 +91,12 @@ addMetaData k metadata = addMetaData' k metadata =<< liftIO getPOSIXTime
- will tend to be generated across the different log files, and so
- git will be able to pack the data more efficiently. -}
addMetaData' :: Key -> MetaData -> POSIXTime -> Annex ()
-addMetaData' k metadata now = Annex.Branch.change (metaDataLogFile k) $
+addMetaData' k (MetaData m) now = Annex.Branch.change (metaDataLogFile k) $
showLog . simplifyLog
- . S.insert (LogEntry now metadata)
+ . S.insert (LogEntry now metadata)
. parseLog
+ where
+ metadata = MetaData $ M.filterWithKey (\f _ -> not (isLastChangedField f)) m
{- Simplify a log, removing historical values that are no longer
- needed.
@@ -148,7 +174,7 @@ copyMetaData :: Key -> Key -> Annex ()
copyMetaData oldkey newkey
| oldkey == newkey = noop
| otherwise = do
- l <- getMetaData oldkey
+ l <- getMetaDataLog oldkey
unless (S.null l) $
Annex.Branch.change (metaDataLogFile newkey) $
const $ showLog l