git-annex/Logs/Group.hs

100 lines
2.9 KiB
Haskell
Raw Normal View History

{- git-annex group log
-
- Copyright 2012, 2019 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
module Logs.Group (
groupLog,
2012-10-01 19:17:21 +00:00
groupChange,
groupSet,
lookupGroups,
groupMap,
groupMapLoad,
getStandardGroup,
inUnwantedGroup
) where
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Attoparsec.ByteString as A
import qualified Data.Attoparsec.ByteString.Char8 as A8
import Data.ByteString.Builder
import Annex.Common
import Logs
import qualified Annex.Branch
import qualified Annex
import Logs.UUIDBased
import Types.Group
import Types.StandardGroups
{- Returns the groups of a given repo UUID. -}
lookupGroups :: UUID -> Annex (S.Set Group)
2012-10-02 17:45:30 +00:00
lookupGroups u = (fromMaybe S.empty . M.lookup u) . groupsByUUID <$> groupMap
2012-10-01 19:17:21 +00:00
{- Applies a set modifier to change the groups for a uuid in the groupLog. -}
groupChange :: UUID -> (S.Set Group -> S.Set Group) -> Annex ()
groupChange uuid@(UUID _) modifier = do
curr <- lookupGroups uuid
c <- liftIO currentVectorClock
Annex.Branch.change groupLog $
buildLogOld buildGroup . changeLog c uuid (modifier curr) . parseLogOld parseGroup
-- The changed group invalidates the preferred content cache.
Annex.changeState $ \s -> s
{ Annex.groupmap = Nothing
, Annex.preferredcontentmap = Nothing
}
groupChange NoUUID _ = error "unknown UUID; cannot modify"
buildGroup :: S.Set Group -> Builder
buildGroup = go . S.toList
where
go [] = mempty
go (g:gs) = bld g <> mconcat [ charUtf8 ' ' <> bld g' | g' <- gs ]
bld (Group g) = byteString g
parseGroup :: A.Parser (S.Set Group)
parseGroup = S.fromList <$> go []
where
go l = (A.endOfInput *> pure l)
<|> ((getgroup <* A8.char ' ') >>= go . (:l))
<|> ((:l) <$> getgroup)
-- allow extra writespace before or after a group name
<|> (A8.char ' ' >>= const (go l))
getgroup = Group <$> A8.takeWhile1 (/= ' ')
groupSet :: UUID -> S.Set Group -> Annex ()
groupSet u g = groupChange u (const g)
{- The map is cached for speed. -}
groupMap :: Annex GroupMap
groupMap = maybe groupMapLoad return =<< Annex.getState Annex.groupmap
{- Loads the map, updating the cache. -}
groupMapLoad :: Annex GroupMap
groupMapLoad = do
m <- makeGroupMap . simpleMap . parseLogOld parseGroup
<$> Annex.Branch.get groupLog
Annex.changeState $ \s -> s { Annex.groupmap = Just m }
return m
2012-10-02 17:45:30 +00:00
makeGroupMap :: M.Map UUID (S.Set Group) -> GroupMap
makeGroupMap byuuid = GroupMap byuuid bygroup
2012-11-11 04:51:07 +00:00
where
bygroup = M.fromListWith S.union $
2013-04-03 07:52:41 +00:00
concatMap explode $ M.toList byuuid
2012-11-11 04:51:07 +00:00
explode (u, s) = map (\g -> (g, S.singleton u)) (S.toList s)
{- If a repository is in exactly one standard group, returns it. -}
2012-10-10 20:23:41 +00:00
getStandardGroup :: S.Set Group -> Maybe StandardGroup
2013-04-03 07:52:41 +00:00
getStandardGroup s = case mapMaybe toStandardGroup $ S.toList s of
2012-10-10 20:23:41 +00:00
[g] -> Just g
_ -> Nothing
inUnwantedGroup :: UUID -> Annex Bool
inUnwantedGroup u = elem UnwantedGroup
. mapMaybe toStandardGroup . S.toList <$> lookupGroups u