Commit 93badba0 authored by bescoto's avatar bescoto

Added restore selection file fix


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@500 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent f149f831
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) New in v0.12.6 (2003/11/02)
--------------------------- ---------------------------
......
...@@ -538,9 +538,10 @@ and ...@@ -538,9 +538,10 @@ and
Each file selection condition either matches or doesn't match a given Each file selection condition either matches or doesn't match a given
file. A given file is excluded by the file selection system exactly file. A given file is excluded by the file selection system exactly
when the first matching file selection condition specifies that the when the first matching file selection condition specifies that the
file be excluded; otherwise the file is included. If a file is file be excluded; otherwise the file is included. When backing up, if
excluded, rdiff-backup acts as if that file does not exist in the a file is excluded, rdiff-backup acts as if that file does not exist
source directory. in the source directory. When restoring, an excluded file is
considered to exist in neither the source nor target directories.
For instance, For instance,
.PP .PP
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
"""Start (and end) here - read arguments, set global settings, etc.""" """Start (and end) here - read arguments, set global settings, etc."""
from __future__ import generators from __future__ import generators
import getopt, sys, re, os import getopt, sys, re, os, cStringIO
from log import Log, LoggerError, ErrorLog from log import Log, LoggerError, ErrorLog
import Globals, Time, SetConnections, selection, robust, rpath, \ import Globals, Time, SetConnections, selection, robust, rpath, \
manage, backup, connection, restore, FilenameMapping, \ manage, backup, connection, restore, FilenameMapping, \
...@@ -408,16 +408,26 @@ def restore_common(rpin, target, time): ...@@ -408,16 +408,26 @@ def restore_common(rpin, target, time):
Log("Restore ended", 4) Log("Restore ended", 4)
def restore_set_select(mirror_rp, target): 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 must set both sides because restore filtering is different from
we will be filtering, but the pathnames are relative to the target select filtering. For instance, if a file is excluded it should
directory. 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: if select_opts:
mirror_rp.conn.restore.MirrorStruct.set_mirror_select( 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): def restore_start_log(rpin, target, time):
"""Open restore log file, log initial message""" """Open restore log file, log initial message"""
......
...@@ -25,11 +25,6 @@ import Globals, Time, Rdiff, Hardlink, rorpiter, selection, rpath, \ ...@@ -25,11 +25,6 @@ import Globals, Time, Rdiff, Hardlink, rorpiter, selection, rpath, \
log, static, robust, metadata, statistics, TempFile 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 # This will be set to the time of the current mirror
_mirror_time = None _mirror_time = None
# This will be set to the exact time to restore to (not restore_to_time) # This will be set to the exact time to restore to (not restore_to_time)
...@@ -251,9 +246,16 @@ static.MakeClass(MirrorStruct) ...@@ -251,9 +246,16 @@ static.MakeClass(MirrorStruct)
class TargetStruct: class TargetStruct:
"""Hold functions to be run on the target side when restoring""" """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 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): def patch(cls, target, diff_iter):
"""Patch target with the diffs from the mirror side """Patch target with the diffs from the mirror side
......
...@@ -694,10 +694,3 @@ class FilterIterITRB(rorpiter.ITRBranch): ...@@ -694,10 +694,3 @@ class FilterIterITRB(rorpiter.ITRBranch):
assert s == 2, s assert s == 2, s
self.base_queue = next_rorp self.base_queue = next_rorp
...@@ -102,6 +102,20 @@ class PathSetter(unittest.TestCase): ...@@ -102,6 +102,20 @@ class PathSetter(unittest.TestCase):
print "Restoring via cmdline: " + cmdstr print "Restoring via cmdline: " + cmdstr
assert not os.system(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): def delete_tmpdirs(self):
"""Remove any temp directories created by previous tests""" """Remove any temp directories created by previous tests"""
assert not os.system(MiscDir + '/myrm testfiles/output* ' assert not os.system(MiscDir + '/myrm testfiles/output* '
...@@ -411,6 +425,49 @@ testfiles/increment2/changed_dir""") ...@@ -411,6 +425,49 @@ testfiles/increment2/changed_dir""")
self.assertRaises(OSError, os.lstat, self.assertRaises(OSError, os.lstat,
'testfiles/restoretarget1/executable2') '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): class FinalCorrupt(PathSetter):
"""Test messing with things a bit and making sure they still work""" """Test messing with things a bit and making sure they still work"""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment