Commit b9949a62 authored by bescoto's avatar bescoto

Fixes for --compare, --compare-at-time switches


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@513 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent f6505e4b
...@@ -11,6 +11,10 @@ information. As John says: ...@@ -11,6 +11,10 @@ information. As John says:
> * dual integer location > * dual integer location
Much thanks to John for adding this useful feature all by himself! Much thanks to John for adding this useful feature all by himself!
Added --compare and --compare-at-time switches for comparing a
directory with the backup information saved about it. Thanks to Erik
Forsberg, who noticed that this feature was missing.
Regressing and restoring should now take less memory when processing Regressing and restoring should now take less memory when processing
large directories (noticed by Luke Mewburn and others). large directories (noticed by Luke Mewburn and others).
......
# Copyright 2002, 2003 Ben Escoto # Copyright 2002, 2003, 2004 Ben Escoto
# #
# This file is part of rdiff-backup. # This file is part of rdiff-backup.
# #
...@@ -36,6 +36,7 @@ user_mapping_filename, group_mapping_filename = None, None ...@@ -36,6 +36,7 @@ user_mapping_filename, group_mapping_filename = None, None
# These are global because they are set while we are trying to figure # These are global because they are set while we are trying to figure
# whether to restore or to backup # whether to restore or to backup
restore_root, restore_index, restore_root_set = None, None, 0 restore_root, restore_index, restore_root_set = None, None, 0
return_val = None # Set to cause exit code to be specified value
def parse_cmdlineoptions(arglist): def parse_cmdlineoptions(arglist):
"""Parse argument list and set global preferences""" """Parse argument list and set global preferences"""
...@@ -188,7 +189,7 @@ def final_set_action(rps): ...@@ -188,7 +189,7 @@ def final_set_action(rps):
def commandline_error(message): def commandline_error(message):
sys.stderr.write("Error: %s\n" % message) sys.stderr.write("Error: %s\n" % message)
sys.stderr.write("See the rdiff-backup manual page for instructions\n") sys.stderr.write("See the rdiff-backup manual page for instructions\n")
sys.exit(1) sys.exit(2)
def misc_setup(rps): def misc_setup(rps):
"""Set default change ownership flag, umask, relay regexps""" """Set default change ownership flag, umask, relay regexps"""
...@@ -253,6 +254,7 @@ def Main(arglist): ...@@ -253,6 +254,7 @@ def Main(arglist):
misc_setup(rps) misc_setup(rps)
take_action(rps) take_action(rps)
cleanup() cleanup()
if return_val is not None: sys.exit(return_val)
def Backup(rpin, rpout): def Backup(rpin, rpout):
...@@ -732,17 +734,18 @@ def Compare(src_rp, dest_rp, compare_time = None): ...@@ -732,17 +734,18 @@ def Compare(src_rp, dest_rp, compare_time = None):
Session time is read from restore_timestr if compare_time is None. Session time is read from restore_timestr if compare_time is None.
""" """
global return_val
require_root_set(dest_rp) require_root_set(dest_rp)
if not compare_time: if not compare_time:
try: compare_time = Time.getstrtotime(restore_timestr) try: compare_time = Time.genstrtotime(restore_timestr)
except Time.TimeException, exc: Log.FatalError(str(exc)) except Time.TimeException, exc: Log.FatalError(str(exc))
restore_check_backup_dir(restore_root) restore_check_backup_dir(restore_root)
mirror_rp = restore_root.new_index(restore_index) mirror_rp = restore_root.new_index(restore_index)
inc_rp = mirror_rp.append_path("increments", restore_index) inc_rp = mirror_rp.append_path("increments", restore_index)
backup_set_select(src_rp) # Sets source rorp iterator backup_set_select(src_rp) # Sets source rorp iterator
restore.Compare(src_rp.conn.backup.SourceStruct.get_source_select(), src_iter = src_rp.conn.backup.SourceStruct.get_source_select()
src_iter, mirror_rp, inc_rp, compare_time) return_val = restore.Compare(src_iter, mirror_rp, inc_rp, compare_time)
def CheckDest(dest_rp): def CheckDest(dest_rp):
......
# Copyright 2002, 2003 Ben Escoto # Copyright 2002, 2003, 2004 Ben Escoto
# #
# This file is part of rdiff-backup. # This file is part of rdiff-backup.
# #
...@@ -106,18 +106,22 @@ def Compare(src_iter, mirror_rp, inc_rp, compare_time): ...@@ -106,18 +106,22 @@ def Compare(src_iter, mirror_rp, inc_rp, compare_time):
mir_iter = MirrorStruct.get_mirror_rorp_iter(compare_time, 1) mir_iter = MirrorStruct.get_mirror_rorp_iter(compare_time, 1)
collated = rorpiter.Collate2Iters(src_iter, mir_iter) collated = rorpiter.Collate2Iters(src_iter, mir_iter)
changed_files_found = 0 changed_files_found = 0
for src_rorp, mir_rorp in collated: for src_rorp, mir_rorp in collated:
if src_rorp == mir_rorp: continue
changed_files_found = 1
if not mir_rorp: change = "new" if not mir_rorp: change = "new"
elif not src_rorp: change = "deleted" elif not src_rorp: change = "deleted"
elif src_rorp == mir_rorp: continue
else: change = "changed" else: change = "changed"
changed_files_found = 1
path_desc = (src_rorp and src_rorp.get_indexpath() or path_desc = (src_rorp and src_rorp.get_indexpath() or
mir_rorp.get_indexpath()) mir_rorp.get_indexpath())
Log("%-7s %s" % (change, path_desc), 3) log.Log("%-7s %s" % (change, path_desc), 2)
if not changed_file_found: if change == "changed": # Log more description of difference
Log("No changes found. Directory matches archive data.", 3) assert not src_rorp.equal_verbose_auto(mir_rorp, 3)
if not changed_files_found:
log.Log("No changes found. Directory matches archive data.", 2)
MirrorStruct.close_rf_cache() MirrorStruct.close_rf_cache()
return changed_files_found
class MirrorStruct: class MirrorStruct:
......
# Copyright 2002, 2003 Ben Escoto # Copyright 2002, 2003, 2004 Ben Escoto
# #
# This file is part of rdiff-backup. # This file is part of rdiff-backup.
# #
...@@ -352,10 +352,11 @@ class RORPath: ...@@ -352,10 +352,11 @@ class RORPath:
def equal_verbose(self, other, check_index = 1, def equal_verbose(self, other, check_index = 1,
compare_inodes = 0, compare_ownership = 0, compare_inodes = 0, compare_ownership = 0,
compare_acls = 0, compare_eas = 0): compare_acls = 0, compare_eas = 0, verbosity = 2):
"""Like __eq__, but log more information. Useful when testing""" """Like __eq__, but log more information. Useful when testing"""
if check_index and self.index != other.index: if check_index and self.index != other.index:
log.Log("Index %s != index %s" % (self.index, other.index), 2) log.Log("Index %s != index %s" % (self.index, other.index),
verbosity)
return None return None
for key in self.data.keys(): # compare dicts key by key for key in self.data.keys(): # compare dicts key by key
...@@ -374,12 +375,22 @@ class RORPath: ...@@ -374,12 +375,22 @@ class RORPath:
elif (not other.data.has_key(key) or elif (not other.data.has_key(key) or
self.data[key] != other.data[key]): self.data[key] != other.data[key]):
if not other.data.has_key(key): if not other.data.has_key(key):
log.Log("Second is missing key %s" % (key,), 2) log.Log("Second is missing key %s" % (key,), verbosity)
else: log.Log("Value of %s differs: %s vs %s" % else: log.Log("Value of %s differs: %s vs %s" %
(key, self.data[key], other.data[key]), 2) (key, self.data[key], other.data[key]),
verbosity)
return None return None
return 1 return 1
def equal_verbose_auto(self, other, verbosity = 2):
"""Like equal_verbose, but set parameters like __eq__ does"""
compare_inodes = ((self.getnumlinks() != 1) and
Globals.compare_inode and Globals.preserve_hardlinks)
return self.equal_verbose(other,
compare_inodes = compare_inodes,
compare_eas = Globals.eas_active,
compare_acls = Globals.acls_active)
def __ne__(self, other): return not self.__eq__(other) def __ne__(self, other): return not self.__eq__(other)
def __str__(self): def __str__(self):
......
...@@ -64,20 +64,18 @@ class PathSetter(unittest.TestCase): ...@@ -64,20 +64,18 @@ class PathSetter(unittest.TestCase):
def exec_rb(self, time, *args): def exec_rb(self, time, *args):
"""Run rdiff-backup on given arguments""" """Run rdiff-backup on given arguments"""
arglist = [] self.exec_rb_extra_args(time, '', *args)
if time: arglist.extend(["--current-time", str(time)])
arglist.append(self.src_prefix + args[0])
if len(args) > 1:
arglist.append(self.dest_prefix + args[1])
assert len(args) == 2
argstring = ' '.join(map(lambda s: "'%s'" % (s,), arglist))
cmdstr = self.rb_schema + argstring
print "executing " + cmdstr
assert not os.system(cmdstr)
def exec_rb_extra_args(self, time, extra_args, *args): def exec_rb_extra_args(self, time, extra_args, *args):
"""Run rdiff-backup on given arguments""" self.exec_rb_extra_args_retval(time, extra_args, 0, *args)
def exec_rb_extra_args_retval(self, time, extra_args, ret_val, *args):
"""Like exec_rb_extra_args, but require return val to be ret_val
Because of some problems I have with os.system, return val is
only accurate to 0 or non-zero.
"""
arglist = [] arglist = []
if time: arglist.extend(["--current-time", str(time)]) if time: arglist.extend(["--current-time", str(time)])
arglist.append(self.src_prefix + args[0]) arglist.append(self.src_prefix + args[0])
...@@ -85,9 +83,13 @@ class PathSetter(unittest.TestCase): ...@@ -85,9 +83,13 @@ class PathSetter(unittest.TestCase):
arglist.append(self.dest_prefix + args[1]) arglist.append(self.dest_prefix + args[1])
assert len(args) == 2 assert len(args) == 2
cmdstr = "%s %s %s" % (self.rb_schema, extra_args, ' '.join(arglist)) arg_string = ' '.join(map(lambda s: "'%s'" % (s,), arglist))
cmdstr = "%s %s %s" % (self.rb_schema, extra_args, arg_string)
print "executing " + cmdstr print "executing " + cmdstr
assert not os.system(cmdstr) actual_val = os.system(cmdstr)
assert ((actual_val == 0 and ret_val == 0) or
(actual_val > 0 and ret_val > 0)), \
"Bad return val %s" % (actual_val,)
def exec_rb_restore(self, time, *args): def exec_rb_restore(self, time, *args):
"""Restore using rdiff-backup's new syntax and given time""" """Restore using rdiff-backup's new syntax and given time"""
...@@ -417,6 +419,22 @@ class FinalMisc(PathSetter): ...@@ -417,6 +419,22 @@ class FinalMisc(PathSetter):
for inc in self.get_all_increments(rbdir): for inc in self.get_all_increments(rbdir):
assert inc.getinctime() >= 30000 assert inc.getinctime() >= 30000
def testCompare(self):
"""Test --compare and --compare-older-than modes"""
Myrm("testfiles/output")
self.set_connections(None, None, None, None)
self.exec_rb(10000, 'testfiles/increment1', 'testfiles/output')
self.exec_rb(20000, 'testfiles/increment2', 'testfiles/output')
self.exec_rb_extra_args_retval(20000, '--compare', 0,
'testfiles/increment2', 'testfiles/output')
self.exec_rb_extra_args_retval(20000, '--compare', 1,
'testfiles/increment1', 'testfiles/output')
self.exec_rb_extra_args_retval(20000, '--compare-at-time 10000', 1,
'testfiles/increment2', 'testfiles/output')
self.exec_rb_extra_args_retval(20000, '--compare-at-time 10000', 0,
'testfiles/increment1', 'testfiles/output')
class FinalSelection(PathSetter): class FinalSelection(PathSetter):
"""Test selection options""" """Test selection options"""
......
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