summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-03-15 13:44:31 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-03-15 13:45:25 -0400
commitfba52e2651cb8b2f26cdb4f38396cd9f55cf0985 (patch)
tree102cce17acd6125e85e102e05b1b0b15305f4e6d
parentec579eba79d0d72e66e57e6f5c28077a5c7e201f (diff)
factored out a generic MapLog from uuid-based logs
UUIDBased is just a MapLog with a UUID for the field.
-rw-r--r--Logs.hs12
-rw-r--r--Logs/MapLog.hs81
-rw-r--r--Logs/UUIDBased.hs75
-rw-r--r--Test.hs6
-rw-r--r--doc/internals.mdwn9
5 files changed, 117 insertions, 66 deletions
diff --git a/Logs.hs b/Logs.hs
index 21908a9cf..2a2fc430e 100644
--- a/Logs.hs
+++ b/Logs.hs
@@ -24,7 +24,7 @@ getLogVariety :: FilePath -> Maybe LogVariety
getLogVariety f
| f `elem` topLevelUUIDBasedLogs = Just UUIDBasedLog
| isRemoteStateLog f = Just NewUUIDBasedLog
- | isMetaDataLog f || f == numcopiesLog = Just OtherLog
+ | isMetaDataLog f || f `elem` otherLogs = Just OtherLog
| otherwise = PresenceLog <$> firstJust (presenceLogs f)
{- All the uuid-based logs stored in the top of the git-annex branch. -}
@@ -45,6 +45,13 @@ presenceLogs f =
, locationLogFileKey f
]
+{- Logs that are neither UUID based nor presence logs. -}
+otherLogs :: [FilePath]
+otherLogs =
+ [ numcopiesLog
+ , groupPreferredContentLog
+ ]
+
uuidLog :: FilePath
uuidLog = "uuid.log"
@@ -63,6 +70,9 @@ groupLog = "group.log"
preferredContentLog :: FilePath
preferredContentLog = "preferred-content.log"
+groupPreferredContentLog :: FilePath
+groupPreferredContentLog = "group-preferred-content.log"
+
scheduleLog :: FilePath
scheduleLog = "schedule.log"
diff --git a/Logs/MapLog.hs b/Logs/MapLog.hs
new file mode 100644
index 000000000..1725ef953
--- /dev/null
+++ b/Logs/MapLog.hs
@@ -0,0 +1,81 @@
+{- git-annex Map log
+ -
+ - This is used to store a Map, in a way that can be union merged.
+ -
+ - A line of the log will look like: "timestamp field value"
+ -
+ - Copyright 2014 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Logs.MapLog where
+
+import qualified Data.Map as M
+import Data.Time.Clock.POSIX
+import Data.Time
+import System.Locale
+
+import Common
+
+data TimeStamp = Unknown | Date POSIXTime
+ deriving (Eq, Ord, Show)
+
+data LogEntry v = LogEntry
+ { changed :: TimeStamp
+ , value :: v
+ } deriving (Eq, Show)
+
+type MapLog f v = M.Map f (LogEntry v)
+
+showMapLog :: (f -> String) -> (v -> String) -> MapLog f v -> String
+showMapLog fieldshower valueshower = unlines . map showpair . M.toList
+ where
+ showpair (f, LogEntry (Date p) v) =
+ unwords [show p, fieldshower f, valueshower v]
+ showpair (f, LogEntry Unknown v) =
+ unwords ["0", fieldshower f, valueshower v]
+
+parseMapLog :: Ord f => (String -> Maybe f) -> (String -> Maybe v) -> String -> MapLog f v
+parseMapLog fieldparser valueparser = M.fromListWith best . mapMaybe parse . lines
+ where
+ parse line = do
+ let (ts, rest) = splitword line
+ (sf, sv) = splitword rest
+ date <- Date . utcTimeToPOSIXSeconds <$> parseTime defaultTimeLocale "%s%Qs" ts
+ f <- fieldparser sf
+ v <- valueparser sv
+ Just (f, LogEntry date v)
+ splitword = separate (== ' ')
+
+changeMapLog :: Ord f => POSIXTime -> f -> v -> MapLog f v -> MapLog f v
+changeMapLog t f v = M.insert f $ LogEntry (Date t) v
+
+{- Only add an LogEntry if it's newer (or at least as new as) than any
+ - existing LogEntry for a field. -}
+addMapLog :: Ord f => f -> LogEntry v -> MapLog f v -> MapLog f v
+addMapLog = M.insertWith' best
+
+{- Converts a MapLog into a simple Map without the timestamp information.
+ - This is a one-way trip, but useful for code that never needs to change
+ - the log. -}
+simpleMap :: MapLog f v -> M.Map f v
+simpleMap = M.map value
+
+best :: LogEntry v -> LogEntry v -> LogEntry v
+best new old
+ | changed old > changed new = old
+ | otherwise = new
+
+-- Unknown is oldest.
+prop_TimeStamp_sane :: Bool
+prop_TimeStamp_sane = Unknown < Date 1
+
+prop_addMapLog_sane :: Bool
+prop_addMapLog_sane = newWins && newestWins
+ where
+ newWins = addMapLog ("foo") (LogEntry (Date 1) "new") l == l2
+ newestWins = addMapLog ("foo") (LogEntry (Date 1) "newest") l2 /= l2
+
+ l = M.fromList [("foo", LogEntry (Date 0) "old")]
+ l2 = M.fromList [("foo", LogEntry (Date 1) "new")]
diff --git a/Logs/UUIDBased.hs b/Logs/UUIDBased.hs
index 430c92d55..b403b6253 100644
--- a/Logs/UUIDBased.hs
+++ b/Logs/UUIDBased.hs
@@ -26,9 +26,6 @@ module Logs.UUIDBased (
changeLog,
addLog,
simpleMap,
-
- prop_TimeStamp_sane,
- prop_addLog_sane,
) where
import qualified Data.Map as M
@@ -38,21 +35,11 @@ import System.Locale
import Common
import Types.UUID
+import Logs.MapLog
-data TimeStamp = Unknown | Date POSIXTime
- deriving (Eq, Ord, Show)
-
-data LogEntry a = LogEntry
- { changed :: TimeStamp
- , value :: a
- } deriving (Eq, Show)
-
-type Log a = M.Map UUID (LogEntry a)
+type Log v = MapLog UUID v
-tskey :: String
-tskey = "timestamp="
-
-showLog :: (a -> String) -> Log a -> String
+showLog :: (v -> String) -> Log v -> String
showLog shower = unlines . map showpair . M.toList
where
showpair (k, LogEntry (Date p) v) =
@@ -60,14 +47,6 @@ showLog shower = unlines . map showpair . M.toList
showpair (k, LogEntry Unknown v) =
unwords [fromUUID k, shower v]
-showLogNew :: (a -> String) -> Log a -> String
-showLogNew shower = unlines . map showpair . M.toList
- where
- showpair (k, LogEntry (Date p) v) =
- unwords [show p, fromUUID k, shower v]
- showpair (k, LogEntry Unknown v) =
- unwords ["0", fromUUID k, shower v]
-
parseLog :: (String -> Maybe a) -> String -> Log a
parseLog = parseLogWithUUID . const
@@ -98,45 +77,17 @@ parseLogWithUUID parser = M.fromListWith best . mapMaybe parse . lines
Nothing -> Unknown
Just d -> Date $ utcTimeToPOSIXSeconds d
-parseLogNew :: (String -> Maybe a) -> String -> Log a
-parseLogNew parser = M.fromListWith best . mapMaybe parse . lines
- where
- parse line = do
- let (ts, rest) = splitword line
- (u, v) = splitword rest
- date <- Date . utcTimeToPOSIXSeconds <$> parseTime defaultTimeLocale "%s%Qs" ts
- val <- parser v
- Just (toUUID u, LogEntry date val)
- splitword = separate (== ' ')
-
-changeLog :: POSIXTime -> UUID -> a -> Log a -> Log a
-changeLog t u v = M.insert u $ LogEntry (Date t) v
-
-{- Only add an LogEntry if it's newer (or at least as new as) than any
- - existing LogEntry for a UUID. -}
-addLog :: UUID -> LogEntry a -> Log a -> Log a
-addLog = M.insertWith' best
+showLogNew :: (v -> String) -> Log v -> String
+showLogNew = showMapLog fromUUID
-{- Converts a Log into a simple Map without the timestamp information.
- - This is a one-way trip, but useful for code that never needs to change
- - the log. -}
-simpleMap :: Log a -> M.Map UUID a
-simpleMap = M.map value
+parseLogNew :: (String -> Maybe v) -> String -> Log v
+parseLogNew = parseMapLog (Just . toUUID)
-best :: LogEntry a -> LogEntry a -> LogEntry a
-best new old
- | changed old > changed new = old
- | otherwise = new
+changeLog :: POSIXTime -> UUID -> v -> Log v -> Log v
+changeLog = changeMapLog
--- Unknown is oldest.
-prop_TimeStamp_sane :: Bool
-prop_TimeStamp_sane = Unknown < Date 1
+addLog :: UUID -> LogEntry v -> Log v -> Log v
+addLog = addMapLog
-prop_addLog_sane :: Bool
-prop_addLog_sane = newWins && newestWins
- where
- newWins = addLog (UUID "foo") (LogEntry (Date 1) "new") l == l2
- newestWins = addLog (UUID "foo") (LogEntry (Date 1) "newest") l2 /= l2
-
- l = M.fromList [(UUID "foo", LogEntry (Date 0) "old")]
- l2 = M.fromList [(UUID "foo", LogEntry (Date 1) "new")]
+tskey :: String
+tskey = "timestamp="
diff --git a/Test.hs b/Test.hs
index 0f52abf6c..1c448b357 100644
--- a/Test.hs
+++ b/Test.hs
@@ -43,7 +43,7 @@ import qualified Types.Backend
import qualified Types.TrustLevel
import qualified Types
import qualified Logs
-import qualified Logs.UUIDBased
+import qualified Logs.MapLog
import qualified Logs.Trust
import qualified Logs.Remote
import qualified Logs.Unused
@@ -140,8 +140,8 @@ properties = localOption (QuickCheckTests 1000) $ testGroup "QuickCheck"
, testProperty "prop_cost_sane" Config.Cost.prop_cost_sane
, testProperty "prop_matcher_sane" Utility.Matcher.prop_matcher_sane
, testProperty "prop_HmacSha1WithCipher_sane" Crypto.prop_HmacSha1WithCipher_sane
- , testProperty "prop_TimeStamp_sane" Logs.UUIDBased.prop_TimeStamp_sane
- , testProperty "prop_addLog_sane" Logs.UUIDBased.prop_addLog_sane
+ , testProperty "prop_TimeStamp_sane" Logs.MapLog.prop_TimeStamp_sane
+ , testProperty "prop_addMapLog_sane" Logs.MapLog.prop_addMapLog_sane
, testProperty "prop_verifiable_sane" Utility.Verifiable.prop_verifiable_sane
, testProperty "prop_segment_regressionTest" Utility.Misc.prop_segment_regressionTest
, testProperty "prop_read_write_transferinfo" Logs.Transfer.prop_read_write_transferinfo
diff --git a/doc/internals.mdwn b/doc/internals.mdwn
index 4e003d9bc..0c5124d0b 100644
--- a/doc/internals.mdwn
+++ b/doc/internals.mdwn
@@ -150,6 +150,15 @@ Files matching the expression are preferred to be retained in the
repository, while files not matching it are preferred to be stored
somewhere else.
+## `group-preferred-content.log`
+
+Contains standard preferred content settings for groups. (Overriding or
+supplimenting the ones built into git-annex.)
+
+The file format is one line per group, staring with a timestamp, then a
+space, then the group name followed by a space and then the preferred
+content expression.
+
## `aaa/bbb/*.log`
These log files record [[location_tracking]] information