From 33ebc912eaf524abbb30952ab8a601502ed53674 Mon Sep 17 00:00:00 2001 From: bescoto Date: Mon, 24 Nov 2003 00:21:50 +0000 Subject: Added restore selection file fix git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/branches/r0-12@500 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109 --- rdiff-backup/CHANGELOG | 9 ++++++ rdiff-backup/rdiff-backup.1 | 7 +++-- rdiff-backup/rdiff_backup/Main.py | 22 +++++++++---- rdiff-backup/rdiff_backup/restore.py | 16 +++++----- rdiff-backup/rdiff_backup/selection.py | 7 ----- rdiff-backup/testing/finaltest.py | 57 ++++++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG index f3faca6..34cfb9c 100644 --- a/rdiff-backup/CHANGELOG +++ b/rdiff-backup/CHANGELOG @@ -1,3 +1,12 @@ +New in v0.12.7 (??????????) +--------------------------- + +Altered file selection when restoring so excluded files will not be +deleted from the target dir. The old behavior was technically +intended and documented but not very convenient. Thanks to Oliver +Kaltenecker for bug report. + + New in v0.12.6 (2003/11/02) --------------------------- diff --git a/rdiff-backup/rdiff-backup.1 b/rdiff-backup/rdiff-backup.1 index 0210424..0044d01 100644 --- a/rdiff-backup/rdiff-backup.1 +++ b/rdiff-backup/rdiff-backup.1 @@ -538,9 +538,10 @@ and Each file selection condition either matches or doesn't match a given file. A given file is excluded by the file selection system exactly when the first matching file selection condition specifies that the -file be excluded; otherwise the file is included. If a file is -excluded, rdiff-backup acts as if that file does not exist in the -source directory. +file be excluded; otherwise the file is included. When backing up, if +a file is excluded, rdiff-backup acts as if that file does not exist +in the source directory. When restoring, an excluded file is +considered to exist in neither the source nor target directories. For instance, .PP diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py index 5eae9bf..ad0440c 100644 --- a/rdiff-backup/rdiff_backup/Main.py +++ b/rdiff-backup/rdiff_backup/Main.py @@ -20,7 +20,7 @@ """Start (and end) here - read arguments, set global settings, etc.""" from __future__ import generators -import getopt, sys, re, os +import getopt, sys, re, os, cStringIO from log import Log, LoggerError, ErrorLog import Globals, Time, SetConnections, selection, robust, rpath, \ manage, backup, connection, restore, FilenameMapping, \ @@ -408,16 +408,26 @@ def restore_common(rpin, target, time): Log("Restore ended", 4) def restore_set_select(mirror_rp, target): - """Set the selection iterator on mirror side from command line args + """Set the selection iterator on both side from command line args - Here we set the selector on the mirror side, because that is where - we will be filtering, but the pathnames are relative to the target - directory. + We must set both sides because restore filtering is different from + select filtering. For instance, if a file is excluded it should + not be deleted from the target directory. + + The StringIO stuff is because filelists need to be read and then + duplicated, because we need two copies of them now. """ + def fp2string(fp): + buf = fp.read() + assert not fp.close() + return buf + select_data = map(fp2string, select_files) if select_opts: mirror_rp.conn.restore.MirrorStruct.set_mirror_select( - target, select_opts, *select_files) + target, select_opts, *map(cStringIO.StringIO, select_data)) + target.conn.restore.TargetStruct.set_target_select( + target, select_opts, *map(cStringIO.StringIO, select_data)) def restore_start_log(rpin, target, time): """Open restore log file, log initial message""" diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py index 0e2e5c0..3ec3a77 100644 --- a/rdiff-backup/rdiff_backup/restore.py +++ b/rdiff-backup/rdiff_backup/restore.py @@ -25,11 +25,6 @@ import Globals, Time, Rdiff, Hardlink, rorpiter, selection, rpath, \ log, static, robust, metadata, statistics, TempFile -# This should be set to selection.Select objects over the source and -# mirror directories respectively. -_select_source = None -_select_mirror = None - # This will be set to the time of the current mirror _mirror_time = None # This will be set to the exact time to restore to (not restore_to_time) @@ -251,9 +246,16 @@ static.MakeClass(MirrorStruct) class TargetStruct: """Hold functions to be run on the target side when restoring""" - def get_initial_iter(cls, target): + _select = None + def set_target_select(cls, target, select_opts, *filelists): """Return a selection object iterating the rorpaths in target""" - return selection.Select(target).set_iter() + cls._select = selection.Select(target) + cls._select.ParseArgs(select_opts, filelists) + cls._select.set_iter() + + def get_initial_iter(cls, target): + """Return selector previously set with set_initial_iter""" + return cls._select or selection.Select(target).set_iter() def patch(cls, target, diff_iter): """Patch target with the diffs from the mirror side diff --git a/rdiff-backup/rdiff_backup/selection.py b/rdiff-backup/rdiff_backup/selection.py index b63db4a..30bc68f 100644 --- a/rdiff-backup/rdiff_backup/selection.py +++ b/rdiff-backup/rdiff_backup/selection.py @@ -694,10 +694,3 @@ class FilterIterITRB(rorpiter.ITRBranch): assert s == 2, s self.base_queue = next_rorp - - - - - - - diff --git a/rdiff-backup/testing/finaltest.py b/rdiff-backup/testing/finaltest.py index 8285b36..9426e18 100644 --- a/rdiff-backup/testing/finaltest.py +++ b/rdiff-backup/testing/finaltest.py @@ -102,6 +102,20 @@ class PathSetter(unittest.TestCase): print "Restoring via cmdline: " + cmdstr assert not os.system(cmdstr) + def exec_rb_restore_extra_args(self, time, extra_args, *args): + """Like exec_rb_restore, but can provide extra arguments""" + arglist = [] + arglist.append("--restore-as-of %s" % str(time)) + arglist.append(extra_args) + arglist.append(self.src_prefix + args[0]) + if len(args) > 1: + arglist.append(self.dest_prefix + args[1]) + assert len(args) == 2 + + cmdstr = self.rb_schema + " ".join(arglist) + print "Restoring via cmdline: " + cmdstr + assert not os.system(cmdstr) + def delete_tmpdirs(self): """Remove any temp directories created by previous tests""" assert not os.system(MiscDir + '/myrm testfiles/output* ' @@ -411,6 +425,49 @@ testfiles/increment2/changed_dir""") self.assertRaises(OSError, os.lstat, 'testfiles/restoretarget1/executable2') + def testSelRestoreLocal(self): + """Test selection options when restoring locally""" + self.set_connections(None, None, None, None) + self.run_sel_restore_test() + + def testSelRestoreRemote(self): + """Test selection options when both sides are remote""" + self.set_connections("test1/", "../", "test2/tmp/", "../../") + self.run_sel_restore_test("../../") + + def run_sel_restore_test(self, prefix = ""): + """Test selection options with restore""" + self.make_restore_sel_dir() + existing_file = self.make_restore_existing_target() + file1_target = Local.rpout1.append("file1") + file2_target = Local.rpout1.append("file2") + excludes = ("--exclude %s --exclude %s --force" % + (prefix + file1_target.path, prefix + existing_file.path)) + self.exec_rb_restore_extra_args("now", excludes, + Local.rpout.path, Local.rpout1.path) + for rp in (file1_target, file2_target, existing_file): + rp.setdata() + assert not file1_target.lstat(), file1_target.lstat() + assert file2_target.lstat() + assert existing_file.lstat() # excluded file shouldn't be deleted + + def make_restore_sel_dir(self): + """Create rdiff-backup repository at Local.rpout""" + self.delete_tmpdirs() + Local.vft_in.mkdir() + rp1 = Local.vft_in.append("file1") + rp2 = Local.vft_in.append("file2") + rp1.touch() + rp2.touch() + self.exec_rb(None, Local.vft_in.path, Local.rpout.path) + Myrm(Local.vft_in.path) + + def make_restore_existing_target(self): + """Create an existing file in the restore target directory""" + Local.rpout1.mkdir() + existing_file = Local.rpout1.append("existing_file") + existing_file.touch() + return existing_file class FinalCorrupt(PathSetter): """Test messing with things a bit and making sure they still work""" -- cgit v1.2.1