{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE MultiWayIf #-}
module Darcs.Patch.Prim.V1.Apply () where
import Darcs.Prelude
import Control.Monad.Catch ( MonadThrow(throwM) )
import Darcs.Patch.Apply ( Apply(..) )
import Darcs.Patch.Repair ( RepairToFL(..) )
import Darcs.Patch.Prim.Class ( PrimApply(..) )
import Darcs.Patch.Prim.V1.Core
( Prim(..),
DirPatchType(..), FilePatchType(..) )
import Darcs.Patch.Prim.V1.Show ( showHunk )
import Darcs.Util.Path ( AnchoredPath, anchorPath )
import Darcs.Patch.Format ( FileNameFormat(FileNameFormatDisplay) )
import Darcs.Patch.TokenReplace ( tryTokReplace )
import Darcs.Patch.ApplyMonad ( ApplyMonadTree(..) )
import Darcs.Util.Tree( Tree )
import Darcs.Patch.Witnesses.Ordered ( FL(..), spanFL, (:>)(..) )
import Darcs.Patch.Witnesses.Unsafe ( unsafeCoercePStart )
import Darcs.Util.ByteString ( unlinesPS )
import Darcs.Util.Printer( renderString )
import qualified Data.ByteString as B
( ByteString
, drop
, empty
, null
, concat
, isPrefixOf
, length
, splitAt
)
import qualified Data.ByteString.Char8 as BC (pack, unpack, unlines, elemIndices)
type FileContents = B.ByteString
ap2fp :: AnchoredPath -> FilePath
ap2fp :: AnchoredPath -> String
ap2fp = String -> AnchoredPath -> String
anchorPath String
""
instance Apply Prim where
type ApplyState Prim = Tree
apply :: forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
apply (FP AnchoredPath
f FilePatchType wX wY
RmFile) = AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mRemoveFile AnchoredPath
f
apply (FP AnchoredPath
f FilePatchType wX wY
AddFile) = AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mCreateFile AnchoredPath
f
apply (FP AnchoredPath
f (Hunk Int
l [FileContents]
o [FileContents]
n)) = AnchoredPath -> (FileContents -> m FileContents) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (FileContents -> m FileContents) -> m ()
mModifyFilePS AnchoredPath
f ((FileContents -> m FileContents) -> m ())
-> (FileContents -> m FileContents) -> m ()
forall a b. (a -> b) -> a -> b
$ AnchoredPath
-> (Int, [FileContents], [FileContents])
-> FileContents
-> m FileContents
forall (m :: * -> *).
MonadThrow m =>
AnchoredPath
-> (Int, [FileContents], [FileContents])
-> FileContents
-> m FileContents
applyHunk AnchoredPath
f (Int
l, [FileContents]
o, [FileContents]
n)
apply (FP AnchoredPath
f (TokReplace String
t String
o String
n)) = AnchoredPath -> (FileContents -> m FileContents) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (FileContents -> m FileContents) -> m ()
mModifyFilePS AnchoredPath
f FileContents -> m FileContents
forall {m :: * -> *}.
MonadThrow m =>
FileContents -> m FileContents
doreplace
where doreplace :: FileContents -> m FileContents
doreplace FileContents
fc =
case String
-> FileContents
-> FileContents
-> FileContents
-> Maybe FileContents
tryTokReplace String
t (String -> FileContents
BC.pack String
o) (String -> FileContents
BC.pack String
n) FileContents
fc of
Maybe FileContents
Nothing -> IOError -> m FileContents
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOError -> m FileContents) -> IOError -> m FileContents
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError (String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$ String
"replace patch to " String -> String -> String
forall a. [a] -> [a] -> [a]
++ AnchoredPath -> String
ap2fp AnchoredPath
f
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" couldn't apply."
Just FileContents
fc' -> FileContents -> m FileContents
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return FileContents
fc'
apply (FP AnchoredPath
f (Binary FileContents
o FileContents
n)) = AnchoredPath -> (FileContents -> m FileContents) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (FileContents -> m FileContents) -> m ()
mModifyFilePS AnchoredPath
f FileContents -> m FileContents
forall {m :: * -> *}.
MonadThrow m =>
FileContents -> m FileContents
doapply
where doapply :: FileContents -> m FileContents
doapply FileContents
oldf = if FileContents
o FileContents -> FileContents -> Bool
forall a. Eq a => a -> a -> Bool
== FileContents
oldf
then FileContents -> m FileContents
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return FileContents
n
else IOError -> m FileContents
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOError -> m FileContents) -> IOError -> m FileContents
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError
(String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$ String
"binary patch to " String -> String -> String
forall a. [a] -> [a] -> [a]
++ AnchoredPath -> String
ap2fp AnchoredPath
f
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" couldn't apply."
apply (DP AnchoredPath
d DirPatchType wX wY
AddDir) = AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mCreateDirectory AnchoredPath
d
apply (DP AnchoredPath
d DirPatchType wX wY
RmDir) = AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mRemoveDirectory AnchoredPath
d
apply (Move AnchoredPath
f AnchoredPath
f') = AnchoredPath -> AnchoredPath -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> AnchoredPath -> m ()
mRename AnchoredPath
f AnchoredPath
f'
apply (ChangePref String
p String
f String
t) = String -> String -> String -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
String -> String -> String -> m ()
mChangePref String
p String
f String
t
instance RepairToFL Prim where
applyAndTryToFixFL :: forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m (Maybe (String, FL Prim wX wY))
applyAndTryToFixFL (FP AnchoredPath
f FilePatchType wX wY
RmFile) =
do FileContents
x <- AnchoredPath -> m FileContents
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> m FileContents
mReadFilePS AnchoredPath
f
AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mRemoveFile AnchoredPath
f
Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY)))
-> Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$ if FileContents -> Bool
B.null FileContents
x
then Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
else (String, FL Prim wX wY) -> Maybe (String, FL Prim wX wY)
forall a. a -> Maybe a
Just (String
"WARNING: Fixing removal of non-empty file "String -> String -> String
forall a. [a] -> [a] -> [a]
++AnchoredPath -> String
ap2fp AnchoredPath
f,
AnchoredPath -> FilePatchType wX Any -> Prim wX Any
forall wX wY. AnchoredPath -> FilePatchType wX wY -> Prim wX wY
FP AnchoredPath
f (FileContents -> FileContents -> FilePatchType wX Any
forall wX wY. FileContents -> FileContents -> FilePatchType wX wY
Binary FileContents
x FileContents
B.empty) Prim wX Any -> FL Prim Any wY -> FL Prim wX wY
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: AnchoredPath -> FilePatchType Any wY -> Prim Any wY
forall wX wY. AnchoredPath -> FilePatchType wX wY -> Prim wX wY
FP AnchoredPath
f FilePatchType Any wY
forall wX wY. FilePatchType wX wY
RmFile Prim Any wY -> FL Prim wY wY -> FL Prim Any wY
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL Prim wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL )
applyAndTryToFixFL (FP AnchoredPath
f FilePatchType wX wY
AddFile) =
do Bool
exists <- AnchoredPath -> m Bool
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m Bool
mDoesFileExist AnchoredPath
f
if Bool
exists
then Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY)))
-> Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(String, FL Prim wX wY) -> Maybe (String, FL Prim wX wY)
forall a. a -> Maybe a
Just (String
"WARNING: Dropping add of existing file "String -> String -> String
forall a. [a] -> [a] -> [a]
++AnchoredPath -> String
ap2fp AnchoredPath
f,
FL Prim wY wY -> FL Prim wX wY
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart FL Prim wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
)
else do AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mCreateFile AnchoredPath
f
Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
applyAndTryToFixFL (DP AnchoredPath
f DirPatchType wX wY
AddDir) =
do Bool
exists <- AnchoredPath -> m Bool
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m Bool
mDoesDirectoryExist AnchoredPath
f
if Bool
exists
then Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY)))
-> Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(String, FL Prim wX wY) -> Maybe (String, FL Prim wX wY)
forall a. a -> Maybe a
Just (String
"WARNING: Dropping add of existing directory "String -> String -> String
forall a. [a] -> [a] -> [a]
++AnchoredPath -> String
ap2fp AnchoredPath
f,
FL Prim wY wY -> FL Prim wX wY
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart FL Prim wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
)
else do AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mCreateDirectory AnchoredPath
f
Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
applyAndTryToFixFL (FP AnchoredPath
f (Binary FileContents
old FileContents
new)) =
do FileContents
x <- AnchoredPath -> m FileContents
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> m FileContents
mReadFilePS AnchoredPath
f
AnchoredPath -> (FileContents -> m FileContents) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (FileContents -> m FileContents) -> m ()
mModifyFilePS AnchoredPath
f (\FileContents
_ -> FileContents -> m FileContents
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return FileContents
new)
if FileContents
x FileContents -> FileContents -> Bool
forall a. Eq a => a -> a -> Bool
/= FileContents
old
then Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY)))
-> Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(String, FL Prim wX wY) -> Maybe (String, FL Prim wX wY)
forall a. a -> Maybe a
Just (String
"WARNING: Fixing binary patch to "String -> String -> String
forall a. [a] -> [a] -> [a]
++AnchoredPath -> String
ap2fp AnchoredPath
f,
AnchoredPath -> FilePatchType wX wY -> Prim wX wY
forall wX wY. AnchoredPath -> FilePatchType wX wY -> Prim wX wY
FP AnchoredPath
f (FileContents -> FileContents -> FilePatchType wX wY
forall wX wY. FileContents -> FileContents -> FilePatchType wX wY
Binary FileContents
x FileContents
new) Prim wX wY -> FL Prim wY wY -> FL Prim wX wY
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL Prim wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
)
else Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
applyAndTryToFixFL p :: Prim wX wY
p@(Move AnchoredPath
old AnchoredPath
new) =
do Bool
old_is_file <- AnchoredPath -> m Bool
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m Bool
mDoesFileExist AnchoredPath
old
Bool
old_is_dir <- AnchoredPath -> m Bool
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m Bool
mDoesDirectoryExist AnchoredPath
old
Bool
new_is_file <- AnchoredPath -> m Bool
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m Bool
mDoesFileExist AnchoredPath
new
Bool
new_is_dir <- AnchoredPath -> m Bool
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m Bool
mDoesDirectoryExist AnchoredPath
new
if | Bool -> Bool
not (Bool
old_is_file Bool -> Bool -> Bool
|| Bool
old_is_dir) ->
Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY)))
-> Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(String, FL Prim wX wY) -> Maybe (String, FL Prim wX wY)
forall a. a -> Maybe a
Just (String
"WARNING: Dropping move patch with non-existing source "String -> String -> String
forall a. [a] -> [a] -> [a]
++AnchoredPath -> String
ap2fp AnchoredPath
old,
FL Prim wY wY -> FL Prim wX wY
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart FL Prim wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
)
| Bool
new_is_file Bool -> Bool -> Bool
|| Bool
new_is_dir ->
Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY)))
-> Maybe (String, FL Prim wX wY)
-> m (Maybe (String, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(String, FL Prim wX wY) -> Maybe (String, FL Prim wX wY)
forall a. a -> Maybe a
Just (String
"WARNING: Dropping move patch with existing target "String -> String -> String
forall a. [a] -> [a] -> [a]
++AnchoredPath -> String
ap2fp AnchoredPath
old,
FL Prim wY wY -> FL Prim wX wY
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart FL Prim wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
)
| Bool
otherwise -> Prim wX wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
forall (p :: * -> * -> *) (m :: * -> *) wX wY.
(Apply p, ApplyMonad (ApplyState p) m) =>
p wX wY -> m ()
apply Prim wX wY
p m ()
-> m (Maybe (String, FL Prim wX wY))
-> m (Maybe (String, FL Prim wX wY))
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
applyAndTryToFixFL Prim wX wY
p = Prim wX wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
forall (p :: * -> * -> *) (m :: * -> *) wX wY.
(Apply p, ApplyMonad (ApplyState p) m) =>
p wX wY -> m ()
apply Prim wX wY
p m ()
-> m (Maybe (String, FL Prim wX wY))
-> m (Maybe (String, FL Prim wX wY))
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe (String, FL Prim wX wY) -> m (Maybe (String, FL Prim wX wY))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (String, FL Prim wX wY)
forall a. Maybe a
Nothing
instance PrimApply Prim where
applyPrimFL :: forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
FL Prim wX wY -> m ()
applyPrimFL FL Prim wX wY
NilFL = () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
applyPrimFL (h :: Prim wX wY
h@(FP AnchoredPath
f (Hunk{})):>:FL Prim wY wY
the_ps)
= case (forall wW wY. Prim wW wY -> Bool)
-> FL Prim wY wY -> (:>) (FL Prim) (FL Prim) wY wY
forall (a :: * -> * -> *) wX wZ.
(forall wW wY. a wW wY -> Bool)
-> FL a wX wZ -> (:>) (FL a) (FL a) wX wZ
spanFL Prim wW wY -> Bool
forall wW wY. Prim wW wY -> Bool
f_hunk FL Prim wY wY
the_ps of
(FL Prim wY wZ
xs :> FL Prim wZ wY
ps') ->
do AnchoredPath -> (FileContents -> m FileContents) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (FileContents -> m FileContents) -> m ()
mModifyFilePS AnchoredPath
f ((FileContents -> m FileContents) -> m ())
-> (FileContents -> m FileContents) -> m ()
forall a b. (a -> b) -> a -> b
$ FL Prim wX wZ -> FileContents -> m FileContents
forall (m :: * -> *) wX wY.
MonadThrow m =>
FL Prim wX wY -> FileContents -> m FileContents
hunkmod (Prim wX wY
h Prim wX wY -> FL Prim wY wZ -> FL Prim wX wZ
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL Prim wY wZ
xs)
FL Prim wZ wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
FL Prim wX wY -> m ()
forall (prim :: * -> * -> *) (m :: * -> *) wX wY.
(PrimApply prim, ApplyMonad (ApplyState prim) m) =>
FL prim wX wY -> m ()
applyPrimFL FL Prim wZ wY
ps'
where f_hunk :: Prim wX wY -> Bool
f_hunk (FP AnchoredPath
f' (Hunk{})) = AnchoredPath
f AnchoredPath -> AnchoredPath -> Bool
forall a. Eq a => a -> a -> Bool
== AnchoredPath
f'
f_hunk Prim wX wY
_ = Bool
False
hunkmod :: MonadThrow m => FL Prim wX wY
-> B.ByteString -> m B.ByteString
hunkmod :: forall (m :: * -> *) wX wY.
MonadThrow m =>
FL Prim wX wY -> FileContents -> m FileContents
hunkmod FL Prim wX wY
NilFL FileContents
content = FileContents -> m FileContents
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return FileContents
content
hunkmod (FP AnchoredPath
_ (Hunk Int
line [FileContents]
old [FileContents]
new):>:FL Prim wY wY
hs) FileContents
content =
AnchoredPath
-> (Int, [FileContents], [FileContents])
-> FileContents
-> m FileContents
forall (m :: * -> *).
MonadThrow m =>
AnchoredPath
-> (Int, [FileContents], [FileContents])
-> FileContents
-> m FileContents
applyHunk AnchoredPath
f (Int
line, [FileContents]
old, [FileContents]
new) FileContents
content m FileContents
-> (FileContents -> m FileContents) -> m FileContents
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FL Prim wY wY -> FileContents -> m FileContents
forall (m :: * -> *) wX wY.
MonadThrow m =>
FL Prim wX wY -> FileContents -> m FileContents
hunkmod FL Prim wY wY
hs
hunkmod FL Prim wX wY
_ FileContents
_ = String -> m FileContents
forall a. HasCallStack => String -> a
error String
"impossible case"
applyPrimFL (Prim wX wY
p:>:FL Prim wY wY
ps) = Prim wX wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
Prim wX wY -> m ()
forall (p :: * -> * -> *) (m :: * -> *) wX wY.
(Apply p, ApplyMonad (ApplyState p) m) =>
p wX wY -> m ()
apply Prim wX wY
p m () -> m () -> m ()
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FL Prim wY wY -> m ()
forall (m :: * -> *) wX wY.
ApplyMonad (ApplyState Prim) m =>
FL Prim wX wY -> m ()
forall (prim :: * -> * -> *) (m :: * -> *) wX wY.
(PrimApply prim, ApplyMonad (ApplyState prim) m) =>
FL prim wX wY -> m ()
applyPrimFL FL Prim wY wY
ps
applyHunk :: MonadThrow m
=> AnchoredPath
-> (Int, [B.ByteString], [B.ByteString])
-> FileContents
-> m FileContents
applyHunk :: forall (m :: * -> *).
MonadThrow m =>
AnchoredPath
-> (Int, [FileContents], [FileContents])
-> FileContents
-> m FileContents
applyHunk AnchoredPath
f (Int, [FileContents], [FileContents])
h FileContents
fc =
case (Int, [FileContents], [FileContents])
-> FileContents -> Either String FileContents
applyHunkLines (Int, [FileContents], [FileContents])
h FileContents
fc of
Right FileContents
fc' -> FileContents -> m FileContents
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return FileContents
fc'
Left String
msg ->
IOError -> m FileContents
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM (IOError -> m FileContents) -> IOError -> m FileContents
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError (String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$
String
"### Error applying:\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int, [FileContents], [FileContents]) -> String
renderHunk (Int, [FileContents], [FileContents])
h String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"\n### to file " String -> String -> String
forall a. [a] -> [a] -> [a]
++ AnchoredPath -> String
ap2fp AnchoredPath
f String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ FileContents -> String
BC.unpack FileContents
fc String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"### Reason: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
msg
where
renderHunk :: (Int, [FileContents], [FileContents]) -> String
renderHunk (Int
l, [FileContents]
o, [FileContents]
n) = Doc -> String
renderString (FileNameFormat
-> AnchoredPath -> Int -> [FileContents] -> [FileContents] -> Doc
showHunk FileNameFormat
FileNameFormatDisplay AnchoredPath
f Int
l [FileContents]
o [FileContents]
n)
applyHunkLines :: (Int, [B.ByteString], [B.ByteString])
-> FileContents
-> Either String FileContents
applyHunkLines :: (Int, [FileContents], [FileContents])
-> FileContents -> Either String FileContents
applyHunkLines (Int
line, [FileContents]
old, [FileContents]
new) FileContents
content
| Int
line Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 =
case Int -> FileContents -> Maybe (FileContents, FileContents)
breakAfterNthNewline ([FileContents] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FileContents]
old) FileContents
content of
Maybe (FileContents, FileContents)
Nothing
| FileContents
content FileContents -> FileContents -> Bool
forall a. Eq a => a -> a -> Bool
== [FileContents] -> FileContents
unlinesPS [FileContents]
old -> FileContents -> Either String FileContents
forall a b. b -> Either a b
Right (FileContents -> Either String FileContents)
-> FileContents -> Either String FileContents
forall a b. (a -> b) -> a -> b
$ [FileContents] -> FileContents
unlinesPS [FileContents]
new
| Bool
otherwise -> String -> Either String FileContents
forall a b. a -> Either a b
Left String
"Hunk wants to remove content that isn't there"
Just (FileContents
should_be_old, FileContents
suffix)
| FileContents
should_be_old FileContents -> FileContents -> Bool
forall a. Eq a => a -> a -> Bool
== [FileContents] -> FileContents
BC.unlines [FileContents]
old ->
FileContents -> Either String FileContents
forall a b. b -> Either a b
Right (FileContents -> Either String FileContents)
-> FileContents -> Either String FileContents
forall a b. (a -> b) -> a -> b
$ [FileContents] -> FileContents
unlinesPS ([FileContents] -> FileContents) -> [FileContents] -> FileContents
forall a b. (a -> b) -> a -> b
$ [FileContents]
new [FileContents] -> [FileContents] -> [FileContents]
forall a. [a] -> [a] -> [a]
++ [FileContents
suffix]
| Bool
otherwise ->
String -> Either String FileContents
forall a b. a -> Either a b
Left String
"Hunk wants to remove content that isn't there"
| Int
line Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 = do
(FileContents
pre, FileContents
start) <- Int -> FileContents -> Either String (FileContents, FileContents)
breakBeforeNthNewline (Int
lineInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2) FileContents
content
let hunkContent :: [FileContents] -> FileContents
hunkContent [FileContents]
ls = [FileContents] -> FileContents
unlinesPS (FileContents
B.emptyFileContents -> [FileContents] -> [FileContents]
forall a. a -> [a] -> [a]
:[FileContents]
ls)
FileContents
post <- FileContents -> FileContents -> Either String FileContents
dropPrefix ([FileContents] -> FileContents
hunkContent [FileContents]
old) FileContents
start
FileContents -> Either String FileContents
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (FileContents -> Either String FileContents)
-> FileContents -> Either String FileContents
forall a b. (a -> b) -> a -> b
$ [FileContents] -> FileContents
B.concat [FileContents
pre, [FileContents] -> FileContents
hunkContent [FileContents]
new, FileContents
post]
| Bool
otherwise = String -> Either String FileContents
forall a b. a -> Either a b
Left String
"Hunk has zero or negative line number"
where
dropPrefix :: FileContents -> FileContents -> Either String FileContents
dropPrefix FileContents
x FileContents
y
| FileContents
x FileContents -> FileContents -> Bool
`B.isPrefixOf` FileContents
y = FileContents -> Either String FileContents
forall a b. b -> Either a b
Right (FileContents -> Either String FileContents)
-> FileContents -> Either String FileContents
forall a b. (a -> b) -> a -> b
$ Int -> FileContents -> FileContents
B.drop (FileContents -> Int
B.length FileContents
x) FileContents
y
| Bool
otherwise =
String -> Either String FileContents
forall a b. a -> Either a b
Left (String -> Either String FileContents)
-> String -> Either String FileContents
forall a b. (a -> b) -> a -> b
$ String
"Hunk wants to remove content that isn't there"
breakAfterNthNewline :: Int -> B.ByteString -> Maybe (B.ByteString, B.ByteString)
breakAfterNthNewline :: Int -> FileContents -> Maybe (FileContents, FileContents)
breakAfterNthNewline Int
0 FileContents
the_ps = (FileContents, FileContents) -> Maybe (FileContents, FileContents)
forall a. a -> Maybe a
Just (FileContents
B.empty, FileContents
the_ps)
breakAfterNthNewline Int
n FileContents
_ | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> Maybe (FileContents, FileContents)
forall a. HasCallStack => String -> a
error String
"precondition of breakAfterNthNewline"
breakAfterNthNewline Int
n FileContents
the_ps = Int -> [Int] -> Maybe (FileContents, FileContents)
forall {t}.
(Eq t, Num t) =>
t -> [Int] -> Maybe (FileContents, FileContents)
go Int
n (Char -> FileContents -> [Int]
BC.elemIndices Char
'\n' FileContents
the_ps)
where
go :: t -> [Int] -> Maybe (FileContents, FileContents)
go t
_ [] = Maybe (FileContents, FileContents)
forall a. Maybe a
Nothing
go t
1 (Int
i:[Int]
_) = (FileContents, FileContents) -> Maybe (FileContents, FileContents)
forall a. a -> Maybe a
Just ((FileContents, FileContents)
-> Maybe (FileContents, FileContents))
-> (FileContents, FileContents)
-> Maybe (FileContents, FileContents)
forall a b. (a -> b) -> a -> b
$ Int -> FileContents -> (FileContents, FileContents)
B.splitAt (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) FileContents
the_ps
go !t
m (Int
_:[Int]
is) = t -> [Int] -> Maybe (FileContents, FileContents)
go (t
m t -> t -> t
forall a. Num a => a -> a -> a
- t
1) [Int]
is
breakBeforeNthNewline :: Int -> B.ByteString -> Either String (B.ByteString, B.ByteString)
breakBeforeNthNewline :: Int -> FileContents -> Either String (FileContents, FileContents)
breakBeforeNthNewline Int
n FileContents
_ | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> Either String (FileContents, FileContents)
forall a. HasCallStack => String -> a
error String
"precondition of breakBeforeNthNewline"
breakBeforeNthNewline Int
n FileContents
the_ps = Int -> [Int] -> Either String (FileContents, FileContents)
forall {t}.
(Eq t, Num t) =>
t -> [Int] -> Either String (FileContents, FileContents)
go Int
n (Char -> FileContents -> [Int]
BC.elemIndices Char
'\n' FileContents
the_ps)
where
go :: t -> [Int] -> Either String (FileContents, FileContents)
go t
0 [] = (FileContents, FileContents)
-> Either String (FileContents, FileContents)
forall a b. b -> Either a b
Right (FileContents
the_ps, FileContents
B.empty)
go t
0 (Int
i:[Int]
_) = (FileContents, FileContents)
-> Either String (FileContents, FileContents)
forall a b. b -> Either a b
Right ((FileContents, FileContents)
-> Either String (FileContents, FileContents))
-> (FileContents, FileContents)
-> Either String (FileContents, FileContents)
forall a b. (a -> b) -> a -> b
$ Int -> FileContents -> (FileContents, FileContents)
B.splitAt Int
i FileContents
the_ps
go !t
m (Int
_:[Int]
is) = t -> [Int] -> Either String (FileContents, FileContents)
go (t
m t -> t -> t
forall a. Num a => a -> a -> a
- t
1) [Int]
is
go t
_ [] = String -> Either String (FileContents, FileContents)
forall a b. a -> Either a b
Left String
"Line number does not exist"