% Copyright (C) 2002-2003 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; if not, write to the Free Software Foundation, % Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. \section{darcs revert} \begin{code} module Revert ( revert ) where import IO ( hFlush, stdout ) import System ( ExitCode(..), exitWith ) import Monad ( when ) import List ( sort ) import Control.Exception ( block ) import System.Directory ( removeFile ) import DarcsCommands ( DarcsCommand(..), nodefaults ) import DarcsArguments ( DarcsFlag( AnyOrder, All, Unified ), ignoretimes, verbose, working_repo_dir, all_gui_interactive, fix_filepath, list_registered_files, ) import Repository ( am_in_repo, get_unrecorded, read_repo, write_pending, sift_for_pending, sync_repo, slurp_recorded, ) import Patch ( commute, join_patches, namepatch, invert, apply_to_slurpy, flatten, apply_to_filepath ) import SlurpDirectory import Lock ( withLock, writeBinFile ) import Depends ( get_common_and_uncommon ) import SelectChanges ( with_selected_last_changes_to_files ) import TouchesFiles ( choose_touching ) import PatchBundle ( make_bundle ) import IsoDate ( getIsoDateTime ) import DarcsUtils ( catchall ) \end{code} \begin{code} revert_description :: String revert_description = "Revert to recorded version.\n" \end{code} \options{revert} \haskell{revert_help} The actions of a revert may be reversed using the unrevert command (see section~\ref{unrevert}). However, if you've made changes since the revert your mileage may vary, so please be careful. \begin{code} revert_help :: String revert_help = "Revert is used to undo changes made to the local tree which have\n"++ "not yet been recorded. You will be prompted for which changes you\n"++ "wish to undo.\n" \end{code} \begin{code} revert :: DarcsCommand revert = DarcsCommand {command_name = "revert", command_help = revert_help, command_description = revert_description, command_extra_args = -1, command_extra_arg_help = ["[FILE or DIRECTORY]..."], command_command = revert_cmd, command_prereq = am_in_repo, command_get_arg_possibilities = list_registered_files, command_argdefaults = nodefaults, command_darcsoptions = [verbose, ignoretimes, all_gui_interactive, working_repo_dir]} \end{code} You can give revert optional arguments indicating files or directories. If you do so it will only prompt you to revert changes in those files or in files in those directories. \begin{code} revert_cmd :: [DarcsFlag] -> [String] -> IO () revert_cmd opts args = let files = sort $ map (fix_filepath opts) args in withLock "./_darcs/lock" $ do when (concat files /= "") $ putStr $ "Reverting changes in "++unwords (map show files)++"..\n\n" maybe_changes <- if All `elem` opts then get_unrecorded (AnyOrder:opts) else get_unrecorded opts working_dir <- slurp "." case maybe_changes of Nothing -> putStr "There are no changes to revert!\n" Just changes -> let pre_changed_files = map (apply_to_filepath (invert changes)) files in if choose_touching pre_changed_files changes == join_patches [] then putStr "There are no changes to revert!\n" else with_selected_last_changes_to_files "revert" opts working_dir pre_changed_files (flatten changes) $ \ (p, skipped) -> if p == [] then putStr $ "If you don't want to revert after all," ++ " that's fine with me!\n" else do putStr "Do you really want to do this? " hFlush stdout yorn <- getLine case yorn of ('y':_) -> return () _ -> exitWith $ ExitSuccess case apply_to_slurpy (invert $ join_patches p) working_dir of Nothing -> fail "Unable to apply inverse patch!" Just working -> case commute (join_patches p, join_patches skipped) of Nothing -> do putStr "This operation will be unrevertable! Proceed? " hFlush stdout really <- getLine case really of ('y':_) -> return () _ -> exitWith $ ExitSuccess block $ do slurp_write_dirty working write_pending $ sift_for_pending $ join_patches skipped Just (_,p') -> do rep <- read_repo "." s <- slurp_recorded "." case get_common_and_uncommon (rep,rep) of (common,_,_) -> do removeFile "_darcs/patches/unrevert_context" `catchall` return () date <- getIsoDateTime writeBinFile "_darcs/patches/unrevert" $ make_bundle [Unified] s common [namepatch date "unrevert" "anonymous" [] p'] block $ do slurp_write_dirty working write_pending $ sift_for_pending $ join_patches skipped sync_repo putStr $ "Finished reverting.\n" \end{code}