{-# LANGUAGE MultiParamTypeClasses #-}
module Darcs.Patch.Index.Monad
( withPatchMods
, applyToFileMods
, makePatchID
) where
import Darcs.Prelude
import Darcs.Patch.Index.Types ( PatchMod(..), PatchId(..) )
import Darcs.Patch.Info ( makePatchname, PatchInfo )
import Darcs.Patch.Apply ( Apply(..) )
import Darcs.Patch.ApplyMonad ( ApplyMonad(..), ApplyMonadTree(..) )
import Control.Monad.State
import Control.Arrow
import Darcs.Util.Path ( AnchoredPath, anchorPath, movedirfilename, isPrefix )
import qualified Data.Set as S
import Data.Set ( Set )
import Darcs.Util.Tree (Tree)
newtype FileModMonad a = FMM (State (Set AnchoredPath, [PatchMod AnchoredPath]) a)
deriving ( Functor
, Applicative
, Monad
, MonadState (Set AnchoredPath, [PatchMod AnchoredPath])
)
withPatchMods :: FileModMonad a
-> Set AnchoredPath
-> (Set AnchoredPath, [PatchMod AnchoredPath])
withPatchMods (FMM m) fps = second reverse $ execState m (fps,[])
instance ApplyMonad Tree FileModMonad where
type ApplyMonadBase FileModMonad = FileModMonad
nestedApply _ _ = error "nestedApply FileModMonad"
liftApply _ _ = error "liftApply FileModMonad"
getApplyState = error "getApplyState FileModMonad"
instance ApplyMonadTree FileModMonad where
mDoesDirectoryExist d = do
fps <- gets fst
return $ S.member d fps
mDoesFileExist f = do
fps <- gets fst
return $ S.member f fps
mReadFilePS _ = error "mReadFilePS FileModMonad"
mCreateFile = createFile
mCreateDirectory = createDir
mRemoveFile = remove
mRemoveDirectory = remove
mRename a b = do
fns <- gets fst
if S.notMember a fns then
addMod (PInvalid a)
else
do
addMod (PRename a b)
modifyFps (S.delete a)
addFile b
forM_ (S.toList fns) $ \fn ->
when (a `isPrefix` fn && a /= fn) $ do
modifyFps (S.delete fn)
let newfn = movedirfilename a b fn
addFile newfn
addMod (PRename fn newfn)
mModifyFilePS f _ = addMod (PTouch f)
addMod :: PatchMod AnchoredPath -> FileModMonad ()
addMod pm = modify $ second (pm :)
addFile :: AnchoredPath -> FileModMonad ()
addFile f = modifyFps (S.insert f)
createFile :: AnchoredPath -> FileModMonad ()
createFile fn = do
errorIfPresent fn True
addMod (PCreateFile fn)
addFile fn
createDir :: AnchoredPath -> FileModMonad ()
createDir fn = do
errorIfPresent fn False
addMod (PCreateDir fn)
addFile fn
errorIfPresent :: AnchoredPath -> Bool -> FileModMonad ()
errorIfPresent fn isFile = do
fs <- gets fst
when (S.member fn fs) $
error $ unwords [ "error: patch index entry for"
, if isFile then "file" else "directory"
, anchorPath "" fn
, "created >1 times. Run `darcs repair` and try again."
]
remove :: AnchoredPath -> FileModMonad ()
remove f = addMod (PRemove f) >> modifyFps (S.delete f)
modifyFps :: (Set AnchoredPath -> Set AnchoredPath) -> FileModMonad ()
modifyFps f = modify $ first f
makePatchID :: PatchInfo -> PatchId
makePatchID = PID . makePatchname
applyToFileMods :: (Apply p, ApplyState p ~ Tree)
=> p wX wY
-> Set AnchoredPath
-> (Set AnchoredPath, [PatchMod AnchoredPath])
applyToFileMods patch = withPatchMods (apply patch)