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)
---------------------------
......
......@@ -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
......
......@@ -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"""
......
......@@ -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
......
......@@ -694,10 +694,3 @@ class FilterIterITRB(rorpiter.ITRBranch):
assert s == 2, s
self.base_queue = next_rorp
......@@ -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"""
......
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