summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rdiff-backup/CHANGELOG4
-rw-r--r--rdiff-backup/rdiff_backup/Main.py13
-rw-r--r--rdiff-backup/rdiff_backup/restore.py18
-rw-r--r--rdiff-backup/rdiff_backup/rpath.py21
-rw-r--r--rdiff-backup/testing/finaltest.py46
5 files changed, 71 insertions, 31 deletions
diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG
index 8871415..d468dc2 100644
--- a/rdiff-backup/CHANGELOG
+++ b/rdiff-backup/CHANGELOG
@@ -11,6 +11,10 @@ information. As John says:
> * dual integer location
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
large directories (noticed by Luke Mewburn and others).
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index 1177296..b25f1ad 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -1,4 +1,4 @@
-# Copyright 2002, 2003 Ben Escoto
+# Copyright 2002, 2003, 2004 Ben Escoto
#
# This file is part of rdiff-backup.
#
@@ -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
# whether to restore or to backup
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):
"""Parse argument list and set global preferences"""
@@ -188,7 +189,7 @@ def final_set_action(rps):
def commandline_error(message):
sys.stderr.write("Error: %s\n" % message)
sys.stderr.write("See the rdiff-backup manual page for instructions\n")
- sys.exit(1)
+ sys.exit(2)
def misc_setup(rps):
"""Set default change ownership flag, umask, relay regexps"""
@@ -253,6 +254,7 @@ def Main(arglist):
misc_setup(rps)
take_action(rps)
cleanup()
+ if return_val is not None: sys.exit(return_val)
def Backup(rpin, rpout):
@@ -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.
"""
+ global return_val
require_root_set(dest_rp)
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))
restore_check_backup_dir(restore_root)
mirror_rp = restore_root.new_index(restore_index)
inc_rp = mirror_rp.append_path("increments", restore_index)
backup_set_select(src_rp) # Sets source rorp iterator
- restore.Compare(src_rp.conn.backup.SourceStruct.get_source_select(),
- src_iter, mirror_rp, inc_rp, compare_time)
+ src_iter = src_rp.conn.backup.SourceStruct.get_source_select()
+ return_val = restore.Compare(src_iter, mirror_rp, inc_rp, compare_time)
def CheckDest(dest_rp):
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index af097b1..1c1d1cc 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -1,4 +1,4 @@
-# Copyright 2002, 2003 Ben Escoto
+# Copyright 2002, 2003, 2004 Ben Escoto
#
# This file is part of rdiff-backup.
#
@@ -106,18 +106,22 @@ def Compare(src_iter, mirror_rp, inc_rp, compare_time):
mir_iter = MirrorStruct.get_mirror_rorp_iter(compare_time, 1)
collated = rorpiter.Collate2Iters(src_iter, mir_iter)
changed_files_found = 0
- for src_rorp, mir_rorp in collated:
- if src_rorp == mir_rorp: continue
- changed_files_found = 1
+ for src_rorp, mir_rorp in collated:
if not mir_rorp: change = "new"
elif not src_rorp: change = "deleted"
+ elif src_rorp == mir_rorp: continue
else: change = "changed"
+ changed_files_found = 1
path_desc = (src_rorp and src_rorp.get_indexpath() or
mir_rorp.get_indexpath())
- Log("%-7s %s" % (change, path_desc), 3)
- if not changed_file_found:
- Log("No changes found. Directory matches archive data.", 3)
+ log.Log("%-7s %s" % (change, path_desc), 2)
+ if change == "changed": # Log more description of difference
+ 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()
+ return changed_files_found
class MirrorStruct:
diff --git a/rdiff-backup/rdiff_backup/rpath.py b/rdiff-backup/rdiff_backup/rpath.py
index ef38402..e1228e9 100644
--- a/rdiff-backup/rdiff_backup/rpath.py
+++ b/rdiff-backup/rdiff_backup/rpath.py
@@ -1,4 +1,4 @@
-# Copyright 2002, 2003 Ben Escoto
+# Copyright 2002, 2003, 2004 Ben Escoto
#
# This file is part of rdiff-backup.
#
@@ -352,10 +352,11 @@ class RORPath:
def equal_verbose(self, other, check_index = 1,
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"""
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
for key in self.data.keys(): # compare dicts key by key
@@ -374,12 +375,22 @@ class RORPath:
elif (not other.data.has_key(key) or
self.data[key] != other.data[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" %
- (key, self.data[key], other.data[key]), 2)
+ (key, self.data[key], other.data[key]),
+ verbosity)
return None
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 __str__(self):
diff --git a/rdiff-backup/testing/finaltest.py b/rdiff-backup/testing/finaltest.py
index 26ff171..ffe175c 100644
--- a/rdiff-backup/testing/finaltest.py
+++ b/rdiff-backup/testing/finaltest.py
@@ -64,20 +64,18 @@ class PathSetter(unittest.TestCase):
def exec_rb(self, time, *args):
"""Run rdiff-backup on given arguments"""
- arglist = []
- 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)
+ self.exec_rb_extra_args(time, '', *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 = []
if time: arglist.extend(["--current-time", str(time)])
arglist.append(self.src_prefix + args[0])
@@ -85,9 +83,13 @@ class PathSetter(unittest.TestCase):
arglist.append(self.dest_prefix + args[1])
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
- 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):
"""Restore using rdiff-backup's new syntax and given time"""
@@ -417,6 +419,22 @@ class FinalMisc(PathSetter):
for inc in self.get_all_increments(rbdir):
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):
"""Test selection options"""