% Copyright (C) 2002-2004,2007 David Roundy
%
% 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.
\darcsCommand{rollback}
\begin{code}

{-# OPTIONS_GHC -cpp #-}{-# LANGUAGE CPP #-}moduleDarcs.Commands.Rollback(rollback)whereimportControl.Monad(when)importSystem.Exit(exitWith,ExitCode(..))importData.List(sort)importData.Maybe(isJust)importSystem.Directory(removeFile)importDarcs.Commands(DarcsCommand(..),nodefaults)importDarcs.Arguments(DarcsFlag(MarkConflicts),fixSubPaths,getAuthor,definePatches,workingRepoDir,nocompress,author,patchnameOption,askLongComment,leaveTestDir,notest,listRegisteredFiles,matchSeveralOrLast,allInteractive,umaskOption)importDarcs.RepoPath(toFilePath)importDarcs.Repository(Repository,amInRepository,withRepoLock,($-),applyToWorking,readRepo,tentativelyMergePatches,withGutsOf,finalizeRepositoryChanges,invalidateIndex)importDarcs.Patch(RepoPatch,summary,invert,namepatch,effect,fromPrims,sortCoalesceFL,canonize)importDarcs.Patch.Set(newset2RL)importDarcs.Patch.Prim(Prim)importDarcs.Witnesses.OrderedimportDarcs.Hopefully(PatchInfoAnd,n2pia)importDarcs.Lock(worldReadableTemp)importDarcs.Match(firstMatch)importDarcs.SelectChanges(selectChanges,WhichChanges(..),selectionContext,selectionContextPrim,runSelection)importDarcs.Commands.Record(getLog)importDarcs.Commands.Unrecord(getLastPatches)importDarcs.Commands.WhatsNew(announceFiles)importDarcs.Utils(clarifyErrors)importPrinter(renderString)importProgress(debugMessage)importDarcs.Witnesses.Sealed(Sealed(..),FlippedSeal(..))importIsoDate(getIsoDateTime)#include "impossible.h"#include "gadts.h"rollbackDescription::StringrollbackDescription="Record a new patch reversing some recorded changes."rollbackHelp::StringrollbackHelp="Rollback is used to undo the effects of one or more patches without actually\n"++"deleting them. Instead, it creates a new patch reversing selected portions.\n"++"of those changes. Unlike obliterate and unrecord (which accomplish a similar\n"++"goal) rollback is perfectly safe, since it leaves in the repository a record\n"++"of its changes.\n"rollback::DarcsCommandrollback=DarcsCommand{commandProgramName="darcs",commandName="rollback",commandHelp=rollbackHelp,commandDescription=rollbackDescription,commandExtraArgs=-1,commandExtraArgHelp=["[FILE or DIRECTORY]..."],commandCommand=rollbackCmd,commandPrereq=amInRepository,commandGetArgPossibilities=listRegisteredFiles,commandArgdefaults=nodefaults,commandAdvancedOptions=[nocompress,umaskOption],commandBasicOptions=[matchSeveralOrLast,allInteractive,author,patchnameOption,askLongComment,notest,leaveTestDir,workingRepoDir]}rollbackCmd::[DarcsFlag]->[String]->IO()rollbackCmdoptsargs=withRepoLockopts$-\repository->dofiles<-sort`fmap`fixSubPathsoptsargsletfiles_fp=maptoFilePathfilesexisting_files<-announceFilesrepositoryfiles"Recording changes in"when(nullexisting_files&&(not$nullfiles))$fail"None of the files you specified exist!"allpatches<-readReporepositoryFlippedSealpatches<-return$iffirstMatchoptsthengetLastPatchesoptsallpatcheselseFlippedSeal$newset2RLallpatchesletpatches_context=selectionContext"rollback"optsNothingfiles_fp(_:>ps)<-runSelection(selectChangesLastReversed(reverseRLpatches))patches_contextwhen(nullFLps)$doputStrLn"No patches selected!"exitWithExitSuccessdefinePatchespslethunks_context=selectionContextPrim"rollback"optsNothingfiles_fphunks=(concatFL$mapFL_FLcanonize$sortCoalesceFL$effectps)runSelection(selectChangesLasthunks)hunks_context>>=(rollItBackNowoptsrepositoryps)rollItBackNow::(RepoPatchp1,RepoPatchp)=>[DarcsFlag]->Repositoryp1C(rut)->FL(PatchInfoAndp)C(xy)->(q:>FLPrim)C(at)->IO()rollItBackNowoptsrepositoryps(_:>ps'')=dowhen(nullFLps'')$doputStrLn"No changes selected!"exitWithExitSuccessletmake_log=worldReadableTemp"darcs-rollback"newlog=Just("","":"rolling back:":"":lines(renderString$summaryps))--tentativelyRemovePatches repository opts (mapFL_FL hopefully ps)(name,my_log,logf)<-getLogoptsnewlogmake_log$invertps''date<-getIsoDateTimemy_author<-getAuthoroptsrbp<-n2pia`fmap`namepatchdatenamemy_authormy_log(fromPrims$invertps'')debugMessage"Adding rollback patch to repository."Sealedpw<-tentativelyMergePatchesrepository"rollback"(MarkConflicts:opts)NilFL(rbp:>:NilFL)debugMessage"Finalizing rollback changes..."invalidateIndexrepositorywithGutsOfrepository$dofinalizeRepositoryChangesrepositorydebugMessage"About to apply rolled-back changes to working directory."revertable$applyToWorkingrepositoryoptspwreturn()when(isJustlogf)$removeFile(fromJustlogf)putStrLn"Finished rolling back."whererevertablex=x`clarifyErrors`unlines["Error applying patch to the working directory.","","This may have left your working directory an inconsistent","but recoverable state. If you had no un-recorded changes","by using 'darcs revert' you should be able to make your","working directory consistent again."]