darcs-2.18.5: src/Darcs/Repository/Unrevert.hs
module Darcs.Repository.Unrevert
( finalizeTentativeUnrevert
, revertTentativeUnrevert
, writeUnrevert
, readUnrevert
, removeFromUnrevertContext
) where
import Darcs.Prelude
import Darcs.Patch ( PrimOf, RepoPatch, commuteRL )
import Darcs.Patch.Apply ( ApplyState )
import Darcs.Patch.Bundle ( interpretBundle, makeBundle, parseBundle )
import Darcs.Patch.Depends ( patchSetMerge, removeFromPatchSet )
import Darcs.Patch.Info ( patchinfo )
import Darcs.Patch.Named ( infopatch )
import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, hopefully )
import Darcs.Patch.Set ( Origin, PatchSet, SealedPatchSet )
import Darcs.Patch.Witnesses.Ordered
( (:/\:)(..)
, (:>)(..)
, FL(..)
, lengthFL
, reverseFL
)
import Darcs.Patch.Witnesses.Sealed ( Sealed(Sealed) )
import Darcs.Repository.Paths ( tentativeUnrevertPath, unrevertPath )
import Darcs.Util.Exception ( catchDoesNotExistError, ifDoesNotExistError )
import Darcs.Util.Global ( debugMessage )
import Darcs.Util.IsoDate ( getIsoDateTime )
import Darcs.Util.Lock ( readBinFile, removeFileMayNotExist, writeDocBinFile )
import Darcs.Util.Prompt ( promptYorn )
import Darcs.Util.Tree ( Tree )
import System.Directory ( copyFile, renameFile )
import System.Exit ( exitSuccess )
finalizeTentativeUnrevert :: IO ()
finalizeTentativeUnrevert =
renameFile tentativeUnrevertPath unrevertPath `catchDoesNotExistError`
removeFileMayNotExist unrevertPath
revertTentativeUnrevert :: IO ()
revertTentativeUnrevert =
copyFile unrevertPath tentativeUnrevertPath `catchDoesNotExistError`
removeFileMayNotExist tentativeUnrevertPath
writeUnrevert :: (RepoPatch p, ApplyState p ~ Tree)
=> PatchSet p Origin wR
-> FL (PrimOf p) wR wX
-> IO ()
writeUnrevert _ NilFL = removeFileMayNotExist tentativeUnrevertPath
writeUnrevert recorded ps = do
date <- getIsoDateTime
info <- patchinfo date "unrevert" "anon" []
let np = infopatch info ps
bundle <- makeBundle Nothing recorded (np :>: NilFL)
writeDocBinFile tentativeUnrevertPath bundle
readUnrevert :: RepoPatch p
=> PatchSet p Origin wR
-> IO (SealedPatchSet p Origin)
readUnrevert us = do
pf <- readBinFile tentativeUnrevertPath
`catchDoesNotExistError` fail "There's nothing to unrevert!"
case parseBundle pf of
Right (Sealed bundle) -> do
case interpretBundle us bundle of
Left msg -> fail msg
Right ps -> return (Sealed ps)
Left err -> fail $ "Couldn't parse unrevert patch:\n" ++ err
removeFromUnrevertContext :: forall p wR wX. (RepoPatch p, ApplyState p ~ Tree)
=> PatchSet p Origin wR
-> FL (PatchInfoAnd p) wX wR
-> IO ()
removeFromUnrevertContext _ NilFL = return () -- nothing to do
removeFromUnrevertContext ref ps =
ifDoesNotExistError () $ do
debugMessage "Reading the unrevert bundle..."
Sealed bundle <- unrevert_patch_bundle
debugMessage "Adjusting the context of the unrevert changes..."
debugMessage $
"Removing " ++ show (lengthFL ps) ++ " patches in removeFromUnrevertContext"
Sealed bundle_ps <- bundle_to_patchset bundle
case patchSetMerge ref bundle_ps of
(unrevert :>: NilFL) :/\: _ -> do
case commuteRL (reverseFL ps :> unrevert) of
Nothing -> unrevert_impossible
Just (unrevert' :> _) ->
case removeFromPatchSet ps ref of
Nothing -> unrevert_impossible
Just common -> do
debugMessage "Have now found the new context..."
bundle' <- makeBundle Nothing common (hopefully unrevert' :>: NilFL)
writeDocBinFile tentativeUnrevertPath bundle'
_ -> return () -- TODO I guess this should be an error call
debugMessage "Done adjusting the context of the unrevert changes"
where
unrevert_impossible = do
confirmed <-
promptYorn "This operation will make unrevert impossible!\nProceed?"
if confirmed
then removeFileMayNotExist tentativeUnrevertPath
else putStrLn "Cancelled." >> exitSuccess
unrevert_patch_bundle = do
pf <- readBinFile tentativeUnrevertPath
case parseBundle pf of
Right foo -> return foo
Left err -> fail $ "Couldn't parse unrevert patch:\n" ++ err
bundle_to_patchset bundle =
either fail (return . Sealed) $ interpretBundle ref bundle