Commit 348ef5ce authored by bescoto's avatar bescoto

Restore excludes now leave existing files on target alone


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@497 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent ef4fc2dd
......@@ -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, \
......@@ -501,16 +501,26 @@ def restore_set_fs_globals(target):
else: SetConnections.UpdateGlobal('chars_to_quote', "")
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, eas_acls
# 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)
......@@ -263,9 +258,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* '
......@@ -510,6 +524,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