1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
{- git-annex assistant change tracking
-
- Copyright 2012-2015 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU GPL version 3 or higher.
-}
{-# LANGUAGE BangPatterns #-}
module Assistant.Types.Changes where
import Types.KeySource
import Types.Key
import Utility.TList
import Annex.Ingest
import Control.Concurrent.STM
import Data.Time.Clock
import qualified Data.Set as S
{- An un-ordered pool of Changes that have been noticed and should be
- staged and committed. Changes will typically be in order, but ordering
- may be lost. In any case, order should not matter, as any given Change
- may later be reverted by a later Change (ie, a file is added and then
- deleted). Code that processes the changes needs to deal with such
- scenarios.
-}
type ChangePool = TList Change
newChangePool :: IO ChangePool
newChangePool = atomically newTList
data Change
= Change
{ changeTime :: UTCTime
, _changeFile :: FilePath
, changeInfo :: ChangeInfo
}
| PendingAddChange
{ changeTime ::UTCTime
, _changeFile :: FilePath
}
| InProcessAddChange
{ changeTime ::UTCTime
, lockedDown :: LockedDown
}
deriving (Show)
data ChangeInfo = AddKeyChange Key | AddFileChange | LinkChange (Maybe Key) | RmChange
deriving (Show, Eq, Ord)
changeInfoKey :: ChangeInfo -> Maybe Key
changeInfoKey (AddKeyChange k) = Just k
changeInfoKey (LinkChange (Just k)) = Just k
changeInfoKey _ = Nothing
changeFile :: Change -> FilePath
changeFile (Change _ f _) = f
changeFile (PendingAddChange _ f) = f
changeFile (InProcessAddChange _ ld) = keyFilename $ keySource ld
isPendingAddChange :: Change -> Bool
isPendingAddChange (PendingAddChange {}) = True
isPendingAddChange _ = False
isInProcessAddChange :: Change -> Bool
isInProcessAddChange (InProcessAddChange {}) = True
isInProcessAddChange _ = False
retryChange :: Change -> Change
retryChange c@(InProcessAddChange time _) =
PendingAddChange time $ changeFile c
retryChange c = c
finishedChange :: Change -> Key -> Change
finishedChange c@(InProcessAddChange {}) k = Change
{ changeTime = changeTime c
, _changeFile = changeFile c
, changeInfo = AddKeyChange k
}
finishedChange c _ = c
{- Combine PendingAddChanges that are for the same file.
- Multiple such often get noticed when eg, a file is opened and then
- closed in quick succession. -}
simplifyChanges :: [Change] -> [Change]
simplifyChanges [c] = [c]
simplifyChanges cl = go cl S.empty []
where
go [] _ l = reverse l
go (c:cs) seen l
| isPendingAddChange c =
if S.member f seen
then go cs seen l
else
let !seen' = S.insert f seen
in go cs seen' (c:l)
| otherwise = go cs seen (c:l)
where
f = changeFile c
|