ipatch-0.1.1: src/IPatch/Apply.hs
{-
- Copyright (C) 2010 Joachim Breitner
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-}
{-# LANGUAGE Rank2Types, ScopedTypeVariables #-}
module IPatch.Apply where
import Control.Monad ( when )
import System.Exit ( exitWith, ExitCode(ExitSuccess) )
import Data.Functor
import Darcs.Commands ( DarcsCommand(..) )
import Darcs.Arguments ( DarcsFlag(..), fixFilePathOrStd, listFiles )
import Darcs.Repository
( amNotInRepository, applyToWorking, withRepoLock, RepoJob(..), Repository )
import Darcs.RepoPath ( FilePathLike(..) )
import Darcs.Patch ( Effect(effect) )
import Workaround ( getCurrentDirectory )
import Darcs.Global ( debugMessage )
import Darcs.Utils ( promptYorn )
import Darcs.SelectChanges
( WhichChanges(First),
runSelection,
selectChanges,
selectionContextPrim )
import Darcs.Patch.Split ( primSplitter )
import Darcs.Witnesses.Ordered ( (:>)(..), nullFL, FL )
import Darcs.Witnesses.Sealed ( Sealed(Sealed), Sealed2(..), unsafeUnseal, unseal)
import IPatch.Common
( diffToPrims,
initializeBaseState,
withTempRepository,
stdindefault,
clonePathsWithDeletion )
import IPatch.DiffFile ( filesTouchedByDiff, readDiffFile )
applyHelp :: String
applyHelp =
"The `ipatch apply file.patch' command works similar to a `patch file.patch' command.\n" ++
"It will, however, prompt the user about each part of the patch, whether it should\n" ++
"be applied or not. Using the integrated hunk editor, the user has full control over\n" ++
"the chosen changes.\n"++
"\n"++
"No files are touched until the end, when the user is asked for a final confirmation.\n"
applyDescription :: String
applyDescription = "Apply a diff file interactively."
apply :: DarcsCommand
apply = DarcsCommand {commandProgramName = "ipatch",
commandName = "apply",
commandHelp = applyHelp,
commandDescription = applyDescription,
commandExtraArgs = 1,
commandExtraArgHelp = ["<PATCHFILE>"],
commandCommand = applyCmd,
commandPrereq = amNotInRepository,
commandGetArgPossibilities = listFiles,
commandArgdefaults = const stdindefault,
commandAdvancedOptions = [],
commandBasicOptions = []}
applyCmd :: [DarcsFlag] -> [String] -> IO ()
applyCmd _ [""] = fail "Empty filename argument given to apply!"
applyCmd opts [unfixed_patchesfile] = do
maindir <- getCurrentDirectory
patchesfile <- fixFilePathOrStd opts unfixed_patchesfile
diffPS <- readDiffFile patchesfile
files <- filesTouchedByDiff diffPS
if null files
then putStrLn "Patch seems to be empty"
else withTempRepository "work" $ \rdir -> withRepoLock [LookForAdds] $ RepoJob $ \(repo :: Repository p r u t) -> do
(_, repo) <- initializeBaseState rdir maindir files repo
Sealed patch_ps <- diffToPrims diffPS repo
-- Ask the user which parts of the patch to apply
let context = selectionContextPrim "apply" [] (Just primSplitter) Nothing Nothing
let selector = selectChanges First patch_ps
(wanted_ps :> _) <- runSelection selector context
when (nullFL patch_ps) $ do
putStrLn "You selected nothing, so I'm exiting!"
exitWith ExitSuccess
debugMessage $ "Applying selected patches"
applyToWorking repo opts wanted_ps `catch` \e ->
fail ("Error applying patch to working dir:\n" ++ show e)
yorn <- promptYorn "Really apply the selected changes?"
when yorn $ do
clonePathsWithDeletion (toFilePath rdir) maindir files
{-
debugMessage $ "Printing selected parts"
withTempDir "ipatch-repo-old" $ \opath -> do
withTempDir "ipatch-repo-new" $ \npath -> do
setCurrentDirectory (toFilePath rdir)
debugMessage $ "Write out patched state"
withRepoLock (testByDefault []) $ \repo -> do
n <- slurp_recorded repo
withCurrentDirectory npath $ writeSlurpy n "."
withRepoLock (testByDefault []) $ \repo -> do
debugMessage $ "Return to unpatched state"
withGutsOf repo $ do
-- How to wrap wanted_patch in FL wanted_patch?
(_ :> top_patch) <- splitAtFL 1 . patchSetToPatches <$> read_repo repo
tentativelyRemovePatches repo [] top_patch
tentativelyAddToPending repo [] $ invert $ effect top_patch
finalizeRepositoryChanges repo
applyToWorking repo [] (invert wanted_ps) `catch`
\e -> fail ("Couldn't undo patch in working dir.\n" ++ show e)
debugMessage $ "Write out unpatched state"
withRepoLock (testByDefault []) $ \repo -> do
o <- slurp_recorded repo
withCurrentDirectory opath $ writeSlurpy o "."
output <- execPipeIgnoreError "diff" ["-u","-r",toFilePath opath,toFilePath npath] empty
putDoc output
-}
return ()