module Darcs.Patch.Rebase.Change
( RebaseChange(..)
, toRebaseChanges
, extractRebaseChange
, reifyRebaseChange
, partitionUnconflicted
, rcToPia
, WithDroppedDeps(..)
, WDDNamed
, commuterIdWDD
, simplifyPush, simplifyPushes
, addNamedToRebase
) where
import Darcs.Prelude
import Darcs.Patch.Commute ( commuteFL, commuteRL )
import Darcs.Patch.CommuteFn
( CommuteFn
, MergeFn
, commuterFLId, commuterIdFL
)
import Darcs.Patch.Debug ( PatchDebug(..) )
import Darcs.Patch.Effect ( Effect(..) )
import Darcs.Patch.FileHunk ( IsHunk(..) )
import Darcs.Patch.Format ( PatchListFormat(..) )
import Darcs.Patch.Ident ( Ident(..), PatchId )
import Darcs.Patch.Info ( PatchInfo, patchinfo, displayPatchInfo )
import Darcs.Patch.Invert ( Invert, invert, invertFL )
import Darcs.Patch.Merge ( selfMerger )
import Darcs.Patch.Named
( Named(..)
, HasDeps(..)
, infopatch
, mergerIdNamed
, patchcontents
, ShowDepsFormat(..)
, showDependencies
)
import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, PatchInfoAndG, n2pia )
import Darcs.Patch.Apply ( Apply(..) )
import Darcs.Patch.Commute ( Commute(..) )
import Darcs.Patch.Inspect ( PatchInspect(..) )
import Darcs.Patch.Read ( ReadPatch(..) )
import Darcs.Patch.Show ( ShowPatch(..), displayPatch )
import Darcs.Patch.Summary
( ConflictState(..)
, IsConflictedPrim(..)
, Summary(..)
, plainSummary
, plainSummaryFL
)
import Darcs.Patch.FromPrim ( PrimPatchBase(..), FromPrim(..) )
import Darcs.Patch.Permutations ( genCommuteWhatWeCanFL )
import Darcs.Patch.Prim.Class ( PrimPatch )
import Darcs.Patch.Rebase.Fixup
( RebaseFixup(..)
, commuteFixupNamed, commuteNamedFixup
, flToNamesPrims
, pushFixupFixup
)
import Darcs.Patch.Rebase.Name ( RebaseName(..) )
import Darcs.Patch.Rebase.PushFixup
( PushFixupFn, dropFixups
, pushFixupFLMB_FLFLMB
, pushFixupIdMB_FLFLMB
, pushFixupIdMB_FLIdFLFL
)
import Darcs.Patch.RepoPatch ( RepoPatch )
import Darcs.Patch.RepoType ( RepoType(..), RebaseType(..) )
import Darcs.Patch.Show ( ShowPatchBasic(..), ShowPatchFor(..), ShowContextPatch(..) )
import Darcs.Patch.Unwind ( Unwound(..), fullUnwind )
import Darcs.Patch.Witnesses.Maybe ( Maybe2(..) )
import Darcs.Patch.Witnesses.Ordered
import Darcs.Patch.Witnesses.Sealed
import Darcs.Patch.Witnesses.Show ( Show1, Show2 )
import Darcs.Patch.Witnesses.Unsafe ( unsafeCoerceP )
import qualified Darcs.Util.Diff as D ( DiffAlgorithm )
import Darcs.Util.IsoDate ( getIsoDateTime )
import Darcs.Util.Parser ( lexString )
import Darcs.Util.Printer ( Doc, ($$), ($+$), (<+>), blueText, redText, empty, vcat )
import qualified Data.ByteString.Char8 as BC ( pack )
import Data.List ( (\\) )
import Data.List.Ordered ( nubSort )
import Data.Maybe ( fromMaybe )
data RebaseChange prim wX wY where
RC :: FL (RebaseFixup prim) wX wY -> Named prim wY wZ -> RebaseChange prim wX wZ
instance Show2 prim => Show1 (RebaseChange prim wX)
instance Show2 prim => Show2 (RebaseChange prim)
deriving instance Show2 prim => Show (RebaseChange prim wX wY)
rcToPia :: RebaseChange prim wX wY -> Sealed2 (PatchInfoAnd ('RepoType 'NoRebase) prim)
rcToPia (RC _ toEdit) = Sealed2 (n2pia toEdit)
instance PrimPatch prim => PrimPatchBase (RebaseChange prim) where
type PrimOf (RebaseChange prim) = prim
instance PatchDebug prim => PatchDebug (RebaseChange prim)
instance HasDeps (RebaseChange prim) where
getdeps (RC _ toedit) = getdeps toedit
type instance PatchId (RebaseChange prim) = PatchInfo
instance Ident (RebaseChange prim) where
ident (RC _ toedit) = ident toedit
instance Apply prim => Apply (RebaseChange prim) where
type ApplyState (RebaseChange prim) = ApplyState prim
apply (RC fixups toedit) = apply fixups >> apply toedit
unapply (RC fixups toedit) = unapply toedit >> unapply fixups
instance Commute prim => Summary (RebaseChange prim) where
conflictedEffect (RC fixups toedit) =
case flToNamesPrims fixups of
_names :> prims ->
case genCommuteWhatWeCanFL (commuterFLId commute) (prims :> patchcontents toedit) of
unconflicted :> _ :> conflicted ->
mapFL (IsC Okay) unconflicted ++ mapFL (IsC Conflicted) conflicted
instance (ShowPatchBasic prim, Invert prim, PatchListFormat prim)
=> ShowPatchBasic (RebaseChange prim) where
showPatch ForStorage (RC fixups toedit) =
blueText "rebase-change"
<+> blueText "(" $$ showPatch ForStorage fixups $$ blueText ")"
$$ showPatch ForStorage toedit
showPatch ForDisplay p@(RC _ (NamedP n _ _)) =
displayPatchInfo n $$ rebaseChangeContent p
rebaseChangeContent :: (ShowPatchBasic prim, Invert prim)
=> RebaseChange prim wX wY -> Doc
rebaseChangeContent (RC fixups contents) =
vcat (mapFL (showPatch ForDisplay) (patchcontents contents)) $+$
if nullFL fixups
then empty
else redText "conflicts:" $+$ vcat (mapRL showFixup (invertFL fixups))
where
showFixup (PrimFixup p) = displayPatch p
showFixup (NameFixup n) = displayPatch n
instance PrimPatch prim => ShowPatch (RebaseChange prim) where
description (RC _ (NamedP n _ _)) = displayPatchInfo n
summary p@(RC _ (NamedP _ ds _)) =
showDependencies ShowDepsSummary ds $$ plainSummary p
summaryFL ps =
showDependencies ShowDepsSummary (getdepsFL ps) $$ plainSummaryFL ps
where
getdepsFL = nubSort . concat . mapFL getdeps
content = rebaseChangeContent
instance (ShowPatchBasic prim, Invert prim, PatchListFormat prim)
=> ShowContextPatch (RebaseChange prim) where
showContextPatch f p = return $ showPatch f p
instance (ReadPatch prim, PatchListFormat prim) => ReadPatch (RebaseChange prim) where
readPatch' = do
lexString (BC.pack "rebase-change")
lexString (BC.pack "(")
Sealed fixups <- readPatch'
lexString (BC.pack ")")
Sealed contents <- readPatch'
return $ Sealed $ RC fixups contents
toRebaseChanges
:: FL (RebaseChange prim) wX wY
-> FL (PatchInfoAndG ('RepoType 'IsRebase) (RebaseChange prim)) wX wY
toRebaseChanges = mapFL_FL n2pia
instance Commute prim => Commute (RebaseChange prim) where
commute (RC fixups1 edit1 :> RC fixups2 edit2) = do
fixups2' :> edit1' <- commuterIdFL commuteNamedFixup (edit1 :> fixups2)
edit2' :> edit1'' <- commute (edit1' :> edit2)
fixupsS :> (fixups2'' :> edit2'') :> fixups1' <-
return $ pushThrough (fixups1 :> (fixups2' :> edit2'))
return (RC (fixupsS +>+ fixups2'') edit2'' :> RC fixups1' edit1'')
instance PatchInspect prim => PatchInspect (RebaseChange prim) where
listTouchedFiles (RC fixup toedit) = nubSort (listTouchedFiles fixup ++ listTouchedFiles toedit)
hunkMatches f (RC fixup toedit) = hunkMatches f fixup || hunkMatches f toedit
partitionUnconflicted
:: Commute prim
=> FL (RebaseChange prim) wX wY
-> (FL (RebaseChange prim) :> RL (RebaseChange prim)) wX wY
partitionUnconflicted = partitionUnconflictedAcc NilRL
partitionUnconflictedAcc
:: Commute prim
=> RL (RebaseChange prim) wX wY -> FL (RebaseChange prim) wY wZ
-> (FL (RebaseChange prim) :> RL (RebaseChange prim)) wX wZ
partitionUnconflictedAcc right NilFL = NilFL :> right
partitionUnconflictedAcc right (p :>: ps) =
case commuteRL (right :> p) of
Just (p'@(RC NilFL _) :> right')
-> case partitionUnconflictedAcc right' ps of
left' :> right'' -> (p' :>: left') :> right''
_ -> partitionUnconflictedAcc (right :<: p) ps
data WithDroppedDeps p wX wY =
WithDroppedDeps {
wddPatch :: p wX wY,
wddDependedOn :: [PatchInfo]
}
noDroppedDeps :: p wX wY -> WithDroppedDeps p wX wY
noDroppedDeps p = WithDroppedDeps p []
instance PrimPatchBase p => PrimPatchBase (WithDroppedDeps p) where
type PrimOf (WithDroppedDeps p) = PrimOf p
instance Effect p => Effect (WithDroppedDeps p) where
effect = effect . wddPatch
simplifyPush
:: PrimPatch prim
=> D.DiffAlgorithm
-> RebaseFixup prim wX wY
-> FL (RebaseChange prim) wY wZ
-> Sealed (FL (RebaseChange prim) wX)
simplifyPush da fixup items = dropFixups $ pushFixupChanges da (fixup :> items)
simplifyPushes
:: PrimPatch prim
=> D.DiffAlgorithm
-> FL (RebaseFixup prim) wX wY
-> FL (RebaseChange prim) wY wZ
-> Sealed (FL (RebaseChange prim) wX)
simplifyPushes _ NilFL ps = Sealed ps
simplifyPushes da (f :>: fs) ps = unseal (simplifyPush da f) (simplifyPushes da fs ps)
pushFixupChange
:: PrimPatch prim
=> D.DiffAlgorithm
-> PushFixupFn
(RebaseFixup prim) (RebaseChange prim)
(RebaseChange prim) (Maybe2 (RebaseFixup prim))
pushFixupChange da (f1 :> RC fs2 e)
= case pushFixupFLMB_FLFLMB (pushFixupFixup da) (f1 :> fs2) of
fs2' :> Nothing2 -> RC fs2' e :> Nothing2
fs2' :> Just2 f1' ->
case commuteFixupNamed (f1' :> e) of
Nothing -> RC (fs2' +>+ f1' :>: NilFL) e :> Nothing2
Just (e' :> f1'') -> RC fs2' e' :> Just2 f1''
pushFixupChanges
:: PrimPatch prim
=> D.DiffAlgorithm
-> PushFixupFn
(RebaseFixup prim) (FL (RebaseChange prim))
(FL (RebaseChange prim)) (Maybe2 (RebaseFixup prim))
pushFixupChanges da = pushFixupIdMB_FLFLMB (pushFixupChange da)
pushFixupsChange
:: PrimPatch prim
=> D.DiffAlgorithm
-> PushFixupFn
(FL (RebaseFixup prim)) (RebaseChange prim)
(RebaseChange prim) (FL (RebaseFixup prim))
pushFixupsChange da = pushFixupIdMB_FLIdFLFL (pushFixupChange da)
pushThrough
:: Commute prim
=> (FL (RebaseFixup prim) :> (FL (RebaseFixup prim) :> Named prim)) wX wY
-> (FL (RebaseFixup prim) :> (FL (RebaseFixup prim) :> Named prim) :> FL (RebaseFixup prim)) wX wY
pushThrough (NilFL :> v) = NilFL :> v :> NilFL
pushThrough ((p :>: ps) :> v) =
case pushThrough (ps :> v) of
psS :> v'@(qs:>te) :> ps' ->
fromMaybe ((p :>: psS) :> v' :> ps') $ do
psS' :> p' <- commuteFL (p :> psS)
qs' :> p'' <- commuteFL (p' :> qs)
te' :> p''' <- commuteFixupNamed (p'' :> te)
return (psS' :> (qs' :> te') :> (p''' :>: ps'))
type WDDNamed p = WithDroppedDeps (Named p)
mergerIdWDD :: MergeFn p1 p2 -> MergeFn p1 (WithDroppedDeps p2)
mergerIdWDD merger (p1 :\/: WithDroppedDeps p2 deps) =
case merger (p1 :\/: p2) of
p2' :/\: p1' -> WithDroppedDeps p2' deps :/\: p1'
commuterIdWDD :: CommuteFn p q -> CommuteFn p (WithDroppedDeps q)
commuterIdWDD commuter (p :> WithDroppedDeps q deps)
= do
q' :> p' <- commuter (p :> q)
return (WithDroppedDeps q' deps :> p')
forceCommuteName :: (RebaseName :> WDDNamed p) wX wY -> (WDDNamed p :> RebaseName) wX wY
forceCommuteName (AddName an :> WithDroppedDeps (NamedP pn deps body) ddeps)
| an == pn = error "impossible case"
| otherwise =
WithDroppedDeps
(NamedP pn (deps \\ [an]) (unsafeCoerceP body))
(if an `elem` deps then an : ddeps else ddeps)
:>
AddName an
forceCommuteName (DelName dn :> p@(WithDroppedDeps (NamedP pn deps _body) _ddeps))
| dn == pn = error "impossible case"
| dn `elem` deps = error "impossible case"
| otherwise = unsafeCoerceP p :> DelName dn
forceCommuteName (Rename old new :> WithDroppedDeps (NamedP pn deps body) ddeps)
| old == pn = error "impossible case"
| new == pn = error "impossible case"
| old `elem` deps = error "impossible case"
| otherwise =
let newdeps = map (\dep -> if new == dep then old else dep) deps
in WithDroppedDeps (NamedP pn newdeps (unsafeCoerceP body)) ddeps :> Rename old new
forceCommutePrim :: RepoPatch p
=> (PrimOf p :> WDDNamed p) wX wY
-> (WDDNamed p :> FL (PrimOf p)) wX wY
forceCommutePrim (p :> wq) =
let rp = fromAnonymousPrim p
irp = fromAnonymousPrim (invert p)
in case mergerIdWDD (mergerIdNamed selfMerger) (irp :\/: wq) of
wq' :/\: irp' -> prefixWith (rp :>: irp :>: NilFL) wq' :> invert (effect irp')
where
prefixWith xs (WithDroppedDeps (NamedP i ds ps) dds) =
WithDroppedDeps (NamedP i ds (xs +>+ ps)) dds
forceCommutes :: RepoPatch p
=> (FL (RebaseFixup (PrimOf p)) :> WDDNamed p) wX wY
-> (WDDNamed p :> FL (RebaseFixup (PrimOf p))) wX wY
forceCommutes (NilFL :> q) = q :> NilFL
forceCommutes ((NameFixup n :>: ps) :> q) =
case forceCommutes (ps :> q) of
q' :> ps' ->
case forceCommuteName (n :> q') of
q'' :> n' -> q'' :> (NameFixup n' :>: ps')
forceCommutes ((PrimFixup p :>: ps) :> q) =
case forceCommutes (ps :> q) of
q' :> ps' ->
case forceCommutePrim (p :> q') of
qs'' :> p' -> qs'' :> (mapFL_FL PrimFixup p' +>+ ps')
fromPrimNamed :: FromPrim p => Named (PrimOf p) wX wY -> Named p wX wY
fromPrimNamed (NamedP n deps ps) = NamedP n deps (fromPrims n ps)
extractRebaseChange
:: forall p wX wY
. RepoPatch p
=> D.DiffAlgorithm
-> FL (RebaseChange (PrimOf p)) wX wY
-> (FL (WDDNamed p) :> FL (RebaseFixup (PrimOf p))) wX wY
extractRebaseChange da rcs = go (NilFL :> rcs)
where
go
:: forall wA wB
. (FL (RebaseFixup (PrimOf p)) :> FL (RebaseChange (PrimOf p))) wA wB
-> (FL (WDDNamed p) :> FL (RebaseFixup (PrimOf p))) wA wB
go (fixupsIn :> NilFL) = NilFL :> fixupsIn
go (fixupsIn :> rc :>: rest) =
case pushFixupsChange da (fixupsIn :> rc) of
RC fixups toedit :> fixupsOut2 ->
case forceCommutes (fixups :> WithDroppedDeps (fromPrimNamed toedit) []) of
toedit' :> fixupsOut1 ->
case go (fixupsOut1 +>+ fixupsOut2 :> rest) of
toedits' :> fixupsOut -> toedit' :>: toedits' :> fixupsOut
reifyRebaseChange
:: FromPrim p
=> String
-> FL (RebaseChange (PrimOf p)) wX wY
-> IO ((FL (WDDNamed p) :> FL (RebaseFixup (PrimOf p))) wX wY)
reifyRebaseChange author rs = do
res <- concatFL <$> mapFL_FL_M reifyOne rs
return (res :> NilFL)
where
reifyOne :: FromPrim p => RebaseChange (PrimOf p) wA wB -> IO (FL (WDDNamed p) wA wB)
reifyOne (RC fixups toedit) =
case flToNamesPrims fixups of
names :> NilFL ->
return $
mapFL_FL (noDroppedDeps . mkDummy) names +>+
noDroppedDeps (fromPrimNamed toedit) :>:
NilFL
names :> prims -> do
n <- mkReified author prims
return $
mapFL_FL (noDroppedDeps . mkDummy) names +>+ noDroppedDeps n :>:
noDroppedDeps (fromPrimNamed toedit) :>:
NilFL
mkReified :: FromPrim p => String -> FL (PrimOf p) wX wY -> IO (Named p wX wY)
mkReified author ps = do
let name = "Reified fixup patch"
let desc = []
date <- getIsoDateTime
info <- patchinfo date name author desc
return $ infopatch info ps
mkDummy :: FromPrim p => RebaseName wX wY -> Named p wX wY
mkDummy (AddName pi) = infopatch pi (unsafeCoerceP NilFL)
mkDummy (DelName _) = error "internal error: can't make a dummy patch from a delete"
mkDummy (Rename _ _) = error "internal error: can't make a dummy patch from a rename"
instance IsHunk (RebaseChange prim) where
isHunk _ = Nothing
instance PatchListFormat (RebaseChange prim)
addNamedToRebase
:: RepoPatch p
=> D.DiffAlgorithm
-> Named p wX wY
-> FL (RebaseChange (PrimOf p)) wY wZ
-> Sealed (FL (RebaseChange (PrimOf p)) wX)
addNamedToRebase da named@(NamedP n deps _) =
case fullUnwind named of
Unwound before underlying after ->
unseal (simplifyPushes da (mapFL_FL PrimFixup before)) .
mapSeal ((RC NilFL (NamedP n deps underlying) :>:)) .
simplifyPushes da (mapFL_FL PrimFixup (reverseRL after))