diff options
author | Joey Hess <joey@kitenet.net> | 2011-07-05 20:16:57 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2011-07-05 20:16:57 -0400 |
commit | 6040d8aed17de582f5d5c179040e29c599315e31 (patch) | |
tree | bb524b386d740353e35a99c235a5d9b6af1f4ddb /RemoteLog.hs | |
parent | 9f1577f74684d8d627e75d3021eb1ff50ef7492f (diff) |
factor out RemoteLog
Diffstat (limited to 'RemoteLog.hs')
-rw-r--r-- | RemoteLog.hs | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/RemoteLog.hs b/RemoteLog.hs new file mode 100644 index 000000000..c2065db9d --- /dev/null +++ b/RemoteLog.hs @@ -0,0 +1,97 @@ +{- git-annex remote log + - + - Copyright 2011 Joey Hess <joey@kitenet.net> + - + - Licensed under the GNU GPL version 3 or higher. + -} + +module RemoteLog ( + remoteLog, + readRemoteLog, + configSet, + keyValToConfig, + configToKeyVal, + + prop_idempotent_configEscape +) where + +import Data.List +import qualified Data.Map as M +import Data.Maybe +import Data.Char + +import qualified Branch +import Types +import Types.Remote +import UUID + +{- Filename of remote.log. -} +remoteLog :: FilePath +remoteLog = "remote.log" + +{- Adds or updates a remote's config in the log. -} +configSet :: UUID -> RemoteConfig -> Annex () +configSet u c = do + m <- readRemoteLog + Branch.change remoteLog $ unlines $ sort $ + map toline $ M.toList $ M.insert u c m + where + toline (u', c') = u' ++ " " ++ (unwords $ configToKeyVal c') + +{- Map of remotes by uuid containing key/value config maps. -} +readRemoteLog :: Annex (M.Map UUID RemoteConfig) +readRemoteLog = return . remoteLogParse =<< Branch.get remoteLog + +remoteLogParse :: String -> M.Map UUID RemoteConfig +remoteLogParse s = + M.fromList $ catMaybes $ map parseline $ filter (not . null) $ lines s + where + parseline l + | length w > 2 = Just (u, c) + | otherwise = Nothing + where + w = words l + u = w !! 0 + c = keyValToConfig $ tail w + +{- Given Strings like "key=value", generates a RemoteConfig. -} +keyValToConfig :: [String] -> RemoteConfig +keyValToConfig ws = M.fromList $ map (/=/) ws + where + (/=/) s = (k, v) + where + k = takeWhile (/= '=') s + v = configUnEscape $ drop (1 + length k) s + +configToKeyVal :: M.Map String String -> [String] +configToKeyVal m = map toword $ sort $ M.toList m + where + toword (k, v) = k ++ "=" ++ configEscape v + +configEscape :: String -> String +configEscape = (>>= escape) + where + escape c + | isSpace c || c `elem` "&" = "&" ++ show (ord c) ++ ";" + | otherwise = [c] + +configUnEscape :: String -> String +configUnEscape = unescape + where + unescape [] = [] + unescape (c:rest) + | c == '&' = entity rest + | otherwise = c : unescape rest + entity s = if ok + then chr (read num) : unescape rest + else '&' : unescape s + where + num = takeWhile isNumber s + r = drop (length num) s + rest = drop 1 r + ok = not (null num) && + not (null r) && r !! 0 == ';' + +{- for quickcheck -} +prop_idempotent_configEscape :: String -> Bool +prop_idempotent_configEscape s = s == (configUnEscape $ configEscape s) |