{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE MultiWayIf #-}
module Darcs.Patch.Prim.V1.Apply () where
import Darcs.Prelude
import Control.Exception ( throw )
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(..), mapFL_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 -> FilePath
ap2fp = FilePath -> AnchoredPath -> FilePath
anchorPath FilePath
""
instance Apply Prim where
type ApplyState Prim = Tree
apply :: 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 [ByteString]
o [ByteString]
n)) = AnchoredPath -> (ByteString -> m ByteString) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (ByteString -> m ByteString) -> m ()
mModifyFilePS AnchoredPath
f ((ByteString -> m ByteString) -> m ())
-> (ByteString -> m ByteString) -> m ()
forall a b. (a -> b) -> a -> b
$ AnchoredPath
-> (Int, [ByteString], [ByteString]) -> ByteString -> m ByteString
forall (m :: * -> *).
Monad m =>
AnchoredPath
-> (Int, [ByteString], [ByteString]) -> ByteString -> m ByteString
applyHunk AnchoredPath
f (Int
l, [ByteString]
o, [ByteString]
n)
apply (FP AnchoredPath
f (TokReplace FilePath
t FilePath
o FilePath
n)) = AnchoredPath -> (ByteString -> m ByteString) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (ByteString -> m ByteString) -> m ()
mModifyFilePS AnchoredPath
f ByteString -> m ByteString
forall (m :: * -> *). Monad m => ByteString -> m ByteString
doreplace
where doreplace :: ByteString -> m ByteString
doreplace ByteString
fc =
case FilePath
-> ByteString -> ByteString -> ByteString -> Maybe ByteString
tryTokReplace FilePath
t (FilePath -> ByteString
BC.pack FilePath
o) (FilePath -> ByteString
BC.pack FilePath
n) ByteString
fc of
Maybe ByteString
Nothing -> IOError -> m ByteString
forall a e. Exception e => e -> a
throw (IOError -> m ByteString) -> IOError -> m ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IOError
userError (FilePath -> IOError) -> FilePath -> IOError
forall a b. (a -> b) -> a -> b
$ FilePath
"replace patch to " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ AnchoredPath -> FilePath
ap2fp AnchoredPath
f
FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" couldn't apply."
Just ByteString
fc' -> ByteString -> m ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
fc'
apply (FP AnchoredPath
f (Binary ByteString
o ByteString
n)) = AnchoredPath -> (ByteString -> m ByteString) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (ByteString -> m ByteString) -> m ()
mModifyFilePS AnchoredPath
f ByteString -> m ByteString
forall (m :: * -> *). Monad m => ByteString -> m ByteString
doapply
where doapply :: ByteString -> m ByteString
doapply ByteString
oldf = if ByteString
o ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
oldf
then ByteString -> m ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
n
else IOError -> m ByteString
forall a e. Exception e => e -> a
throw (IOError -> m ByteString) -> IOError -> m ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IOError
userError
(FilePath -> IOError) -> FilePath -> IOError
forall a b. (a -> b) -> a -> b
$ FilePath
"binary patch to " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ AnchoredPath -> FilePath
ap2fp AnchoredPath
f
FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
" 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 FilePath
p FilePath
f FilePath
t) = FilePath -> FilePath -> FilePath -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
FilePath -> FilePath -> FilePath -> m ()
mChangePref FilePath
p FilePath
f FilePath
t
instance RepairToFL Prim where
applyAndTryToFixFL :: Prim wX wY -> m (Maybe (FilePath, FL Prim wX wY))
applyAndTryToFixFL (FP AnchoredPath
f FilePatchType wX wY
RmFile) =
do ByteString
x <- AnchoredPath -> m ByteString
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> m ByteString
mReadFilePS AnchoredPath
f
AnchoredPath -> m ()
forall (m :: * -> *). ApplyMonadTree m => AnchoredPath -> m ()
mRemoveFile AnchoredPath
f
Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY)))
-> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$ if ByteString -> Bool
B.null ByteString
x
then Maybe (FilePath, FL Prim wX wY)
forall a. Maybe a
Nothing
else (FilePath, FL Prim wX wY) -> Maybe (FilePath, FL Prim wX wY)
forall a. a -> Maybe a
Just (FilePath
"WARNING: Fixing removal of non-empty file "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++AnchoredPath -> FilePath
ap2fp AnchoredPath
f,
AnchoredPath -> FilePatchType wX Any -> Prim wX Any
forall wX wY. AnchoredPath -> FilePatchType wX wY -> Prim wX wY
FP AnchoredPath
f (ByteString -> ByteString -> FilePatchType wX Any
forall wX wY. ByteString -> ByteString -> FilePatchType wX wY
Binary ByteString
x ByteString
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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY)))
-> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(FilePath, FL Prim wX wY) -> Maybe (FilePath, FL Prim wX wY)
forall a. a -> Maybe a
Just (FilePath
"WARNING: Dropping add of existing file "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++AnchoredPath -> FilePath
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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (FilePath, 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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY)))
-> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(FilePath, FL Prim wX wY) -> Maybe (FilePath, FL Prim wX wY)
forall a. a -> Maybe a
Just (FilePath
"WARNING: Dropping add of existing directory "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++AnchoredPath -> FilePath
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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (FilePath, FL Prim wX wY)
forall a. Maybe a
Nothing
applyAndTryToFixFL (FP AnchoredPath
f (Binary ByteString
old ByteString
new)) =
do ByteString
x <- AnchoredPath -> m ByteString
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> m ByteString
mReadFilePS AnchoredPath
f
AnchoredPath -> (ByteString -> m ByteString) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (ByteString -> m ByteString) -> m ()
mModifyFilePS AnchoredPath
f (\ByteString
_ -> ByteString -> m ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
new)
if ByteString
x ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
old
then Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY)))
-> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(FilePath, FL Prim wX wY) -> Maybe (FilePath, FL Prim wX wY)
forall a. a -> Maybe a
Just (FilePath
"WARNING: Fixing binary patch to "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++AnchoredPath -> FilePath
ap2fp AnchoredPath
f,
AnchoredPath -> FilePatchType wX wY -> Prim wX wY
forall wX wY. AnchoredPath -> FilePatchType wX wY -> Prim wX wY
FP AnchoredPath
f (ByteString -> ByteString -> FilePatchType wX wY
forall wX wY. ByteString -> ByteString -> FilePatchType wX wY
Binary ByteString
x ByteString
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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (FilePath, 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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY)))
-> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(FilePath, FL Prim wX wY) -> Maybe (FilePath, FL Prim wX wY)
forall a. a -> Maybe a
Just (FilePath
"WARNING: Dropping move patch with non-existing source "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++AnchoredPath -> FilePath
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 (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY)))
-> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall a b. (a -> b) -> a -> b
$
(FilePath, FL Prim wX wY) -> Maybe (FilePath, FL Prim wX wY)
forall a. a -> Maybe a
Just (FilePath
"WARNING: Dropping move patch with existing target "FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++AnchoredPath -> FilePath
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 (p :: * -> * -> *) (m :: * -> *) wX wY.
(Apply p, ApplyMonad (ApplyState p) m) =>
p wX wY -> m ()
apply Prim wX wY
p m ()
-> m (Maybe (FilePath, FL Prim wX wY))
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (FilePath, FL Prim wX wY)
forall a. Maybe a
Nothing
applyAndTryToFixFL Prim wX wY
p = 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 (FilePath, FL Prim wX wY))
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe (FilePath, FL Prim wX wY)
-> m (Maybe (FilePath, FL Prim wX wY))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (FilePath, FL Prim wX wY)
forall a. Maybe a
Nothing
instance PrimApply Prim where
applyPrimFL :: FL Prim wX wY -> m ()
applyPrimFL FL Prim wX wY
NilFL = () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
applyPrimFL (FP AnchoredPath
f h :: FilePatchType wX wY
h@(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 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 let foo :: FL FilePatchType wX wZ
foo = FilePatchType wX wY
h FilePatchType wX wY
-> FL FilePatchType wY wZ -> FL FilePatchType wX wZ
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: (forall wW wY. Prim wW wY -> FilePatchType wW wY)
-> FL Prim wY wZ -> FL FilePatchType wY wZ
forall (a :: * -> * -> *) (b :: * -> * -> *) wX wZ.
(forall wW wY. a wW wY -> b wW wY) -> FL a wX wZ -> FL b wX wZ
mapFL_FL (\(FP _ h') -> FilePatchType wW wY
h') FL Prim wY wZ
xs
AnchoredPath -> (ByteString -> m ByteString) -> m ()
forall (m :: * -> *).
ApplyMonadTree m =>
AnchoredPath -> (ByteString -> m ByteString) -> m ()
mModifyFilePS AnchoredPath
f ((ByteString -> m ByteString) -> m ())
-> (ByteString -> m ByteString) -> m ()
forall a b. (a -> b) -> a -> b
$ FL FilePatchType wX wZ -> ByteString -> m ByteString
forall (m :: * -> *) wX wY.
Monad m =>
FL FilePatchType wX wY -> ByteString -> m ByteString
hunkmod FL FilePatchType wX wZ
foo
FL Prim wZ 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 :: Monad m => FL FilePatchType wX wY
-> B.ByteString -> m B.ByteString
hunkmod :: FL FilePatchType wX wY -> ByteString -> m ByteString
hunkmod FL FilePatchType wX wY
NilFL ByteString
content = ByteString -> m ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
content
hunkmod (Hunk Int
line [ByteString]
old [ByteString]
new:>:FL FilePatchType wY wY
hs) ByteString
content =
AnchoredPath
-> (Int, [ByteString], [ByteString]) -> ByteString -> m ByteString
forall (m :: * -> *).
Monad m =>
AnchoredPath
-> (Int, [ByteString], [ByteString]) -> ByteString -> m ByteString
applyHunk AnchoredPath
f (Int
line, [ByteString]
old, [ByteString]
new) ByteString
content m ByteString -> (ByteString -> m ByteString) -> m ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FL FilePatchType wY wY -> ByteString -> m ByteString
forall (m :: * -> *) wX wY.
Monad m =>
FL FilePatchType wX wY -> ByteString -> m ByteString
hunkmod FL FilePatchType wY wY
hs
hunkmod FL FilePatchType wX wY
_ ByteString
_ = FilePath -> m ByteString
forall a. HasCallStack => FilePath -> a
error FilePath
"impossible case"
applyPrimFL (Prim wX wY
p:>:FL Prim wY wY
ps) = 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 (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FL Prim wY 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 :: Monad m
=> AnchoredPath
-> (Int, [B.ByteString], [B.ByteString])
-> FileContents
-> m FileContents
applyHunk :: AnchoredPath
-> (Int, [ByteString], [ByteString]) -> ByteString -> m ByteString
applyHunk AnchoredPath
f (Int, [ByteString], [ByteString])
h ByteString
fc =
case (Int, [ByteString], [ByteString])
-> ByteString -> Either FilePath ByteString
applyHunkLines (Int, [ByteString], [ByteString])
h ByteString
fc of
Right ByteString
fc' -> ByteString -> m ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
fc'
Left FilePath
msg ->
IOError -> m ByteString
forall a e. Exception e => e -> a
throw (IOError -> m ByteString) -> IOError -> m ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IOError
userError (FilePath -> IOError) -> FilePath -> IOError
forall a b. (a -> b) -> a -> b
$
FilePath
"### Error applying:\n" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ (Int, [ByteString], [ByteString]) -> FilePath
renderHunk (Int, [ByteString], [ByteString])
h FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
FilePath
"\n### to file " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ AnchoredPath -> FilePath
ap2fp AnchoredPath
f FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
":\n" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ByteString -> FilePath
BC.unpack ByteString
fc FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
FilePath
"### Reason: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
msg
where
renderHunk :: (Int, [ByteString], [ByteString]) -> FilePath
renderHunk (Int
l, [ByteString]
o, [ByteString]
n) = Doc -> FilePath
renderString (FileNameFormat
-> AnchoredPath -> Int -> [ByteString] -> [ByteString] -> Doc
showHunk FileNameFormat
FileNameFormatDisplay AnchoredPath
f Int
l [ByteString]
o [ByteString]
n)
applyHunkLines :: (Int, [B.ByteString], [B.ByteString])
-> FileContents
-> Either String FileContents
applyHunkLines :: (Int, [ByteString], [ByteString])
-> ByteString -> Either FilePath ByteString
applyHunkLines (Int
line, [ByteString]
old, [ByteString]
new) ByteString
content
| Int
line Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 =
case Int -> ByteString -> Maybe (ByteString, ByteString)
breakAfterNthNewline ([ByteString] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ByteString]
old) ByteString
content of
Maybe (ByteString, ByteString)
Nothing
| ByteString
content ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== [ByteString] -> ByteString
unlinesPS [ByteString]
old -> ByteString -> Either FilePath ByteString
forall a b. b -> Either a b
Right (ByteString -> Either FilePath ByteString)
-> ByteString -> Either FilePath ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
unlinesPS [ByteString]
new
| Bool
otherwise -> FilePath -> Either FilePath ByteString
forall a b. a -> Either a b
Left FilePath
"Hunk wants to remove content that isn't there"
Just (ByteString
should_be_old, ByteString
suffix)
| ByteString
should_be_old ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== [ByteString] -> ByteString
BC.unlines [ByteString]
old ->
ByteString -> Either FilePath ByteString
forall a b. b -> Either a b
Right (ByteString -> Either FilePath ByteString)
-> ByteString -> Either FilePath ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
unlinesPS ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString]
new [ByteString] -> [ByteString] -> [ByteString]
forall a. [a] -> [a] -> [a]
++ [ByteString
suffix]
| Bool
otherwise ->
FilePath -> Either FilePath ByteString
forall a b. a -> Either a b
Left FilePath
"Hunk wants to remove content that isn't there"
| Int
line Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 = do
(ByteString
pre, ByteString
start) <- Int -> ByteString -> Either FilePath (ByteString, ByteString)
breakBeforeNthNewline (Int
lineInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2) ByteString
content
let hunkContent :: [ByteString] -> ByteString
hunkContent [ByteString]
ls = [ByteString] -> ByteString
unlinesPS (ByteString
B.emptyByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[ByteString]
ls)
ByteString
post <- ByteString -> ByteString -> Either FilePath ByteString
dropPrefix ([ByteString] -> ByteString
hunkContent [ByteString]
old) ByteString
start
ByteString -> Either FilePath ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Either FilePath ByteString)
-> ByteString -> Either FilePath ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
B.concat [ByteString
pre, [ByteString] -> ByteString
hunkContent [ByteString]
new, ByteString
post]
| Bool
otherwise = FilePath -> Either FilePath ByteString
forall a b. a -> Either a b
Left FilePath
"Hunk has zero or negative line number"
where
dropPrefix :: ByteString -> ByteString -> Either FilePath ByteString
dropPrefix ByteString
x ByteString
y
| ByteString
x ByteString -> ByteString -> Bool
`B.isPrefixOf` ByteString
y = ByteString -> Either FilePath ByteString
forall a b. b -> Either a b
Right (ByteString -> Either FilePath ByteString)
-> ByteString -> Either FilePath ByteString
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
x) ByteString
y
| Bool
otherwise =
FilePath -> Either FilePath ByteString
forall a b. a -> Either a b
Left (FilePath -> Either FilePath ByteString)
-> FilePath -> Either FilePath ByteString
forall a b. (a -> b) -> a -> b
$ FilePath
"Hunk wants to remove content that isn't there"
breakAfterNthNewline :: Int -> B.ByteString -> Maybe (B.ByteString, B.ByteString)
breakAfterNthNewline :: Int -> ByteString -> Maybe (ByteString, ByteString)
breakAfterNthNewline Int
0 ByteString
the_ps = (ByteString, ByteString) -> Maybe (ByteString, ByteString)
forall a. a -> Maybe a
Just (ByteString
B.empty, ByteString
the_ps)
breakAfterNthNewline Int
n ByteString
_ | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = FilePath -> Maybe (ByteString, ByteString)
forall a. HasCallStack => FilePath -> a
error FilePath
"precondition of breakAfterNthNewline"
breakAfterNthNewline Int
n ByteString
the_ps = Int -> [Int] -> Maybe (ByteString, ByteString)
forall t.
(Eq t, Num t) =>
t -> [Int] -> Maybe (ByteString, ByteString)
go Int
n (Char -> ByteString -> [Int]
BC.elemIndices Char
'\n' ByteString
the_ps)
where
go :: t -> [Int] -> Maybe (ByteString, ByteString)
go t
_ [] = Maybe (ByteString, ByteString)
forall a. Maybe a
Nothing
go t
1 (Int
i:[Int]
_) = (ByteString, ByteString) -> Maybe (ByteString, ByteString)
forall a. a -> Maybe a
Just ((ByteString, ByteString) -> Maybe (ByteString, ByteString))
-> (ByteString, ByteString) -> Maybe (ByteString, ByteString)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> (ByteString, ByteString)
B.splitAt (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ByteString
the_ps
go !t
m (Int
_:[Int]
is) = t -> [Int] -> Maybe (ByteString, ByteString)
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 -> ByteString -> Either FilePath (ByteString, ByteString)
breakBeforeNthNewline Int
n ByteString
_ | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = FilePath -> Either FilePath (ByteString, ByteString)
forall a. HasCallStack => FilePath -> a
error FilePath
"precondition of breakBeforeNthNewline"
breakBeforeNthNewline Int
n ByteString
the_ps = Int -> [Int] -> Either FilePath (ByteString, ByteString)
forall t.
(Eq t, Num t) =>
t -> [Int] -> Either FilePath (ByteString, ByteString)
go Int
n (Char -> ByteString -> [Int]
BC.elemIndices Char
'\n' ByteString
the_ps)
where
go :: t -> [Int] -> Either FilePath (ByteString, ByteString)
go t
0 [] = (ByteString, ByteString)
-> Either FilePath (ByteString, ByteString)
forall a b. b -> Either a b
Right (ByteString
the_ps, ByteString
B.empty)
go t
0 (Int
i:[Int]
_) = (ByteString, ByteString)
-> Either FilePath (ByteString, ByteString)
forall a b. b -> Either a b
Right ((ByteString, ByteString)
-> Either FilePath (ByteString, ByteString))
-> (ByteString, ByteString)
-> Either FilePath (ByteString, ByteString)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
i ByteString
the_ps
go !t
m (Int
_:[Int]
is) = t -> [Int] -> Either FilePath (ByteString, ByteString)
go (t
m t -> t -> t
forall a. Num a => a -> a -> a
- t
1) [Int]
is
go t
_ [] = FilePath -> Either FilePath (ByteString, ByteString)
forall a b. a -> Either a b
Left FilePath
"Line number does not exist"