summaryrefslogtreecommitdiff
path: root/rdiff-backup
diff options
context:
space:
mode:
Diffstat (limited to 'rdiff-backup')
-rw-r--r--rdiff-backup/CHANGELOG4
-rw-r--r--rdiff-backup/TODO2
-rw-r--r--rdiff-backup/rdiff-backup.14
-rw-r--r--rdiff-backup/rdiff_backup/Main.py8
-rw-r--r--rdiff-backup/rdiff_backup/Time.py31
-rw-r--r--rdiff-backup/rdiff_backup/restore.py14
-rw-r--r--rdiff-backup/testing/finaltest.py39
-rw-r--r--rdiff-backup/testing/restoretest.py20
8 files changed, 108 insertions, 14 deletions
diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG
index 4a1bdde..a74cf10 100644
--- a/rdiff-backup/CHANGELOG
+++ b/rdiff-backup/CHANGELOG
@@ -20,6 +20,10 @@ forthcoming attr/facl utilities.
Fixed problems with --restrict options that would cause proper
sessions to fail. Thanks to Randall Nortman for error report.
+Added new time specification by backup number. So now you can
+'--remove-older-than 2B' or '--list-at-time 0B'. Original suggestion
+by Alan Bailward.
+
New in v0.13.1 (2003/08/08)
---------------------------
diff --git a/rdiff-backup/TODO b/rdiff-backup/TODO
index 6741564..79b5894 100644
--- a/rdiff-backup/TODO
+++ b/rdiff-backup/TODO
@@ -1,7 +1,5 @@
See if regressing takes too much memory (large directories).
-Alan Bailward's suggestion to add removing older than 4 sessions.
-
write test case for --calculate-statistics
Use ctime to check whether files have been changed. See message:
diff --git a/rdiff-backup/rdiff-backup.1 b/rdiff-backup/rdiff-backup.1
index ad17e7a..f3db272 100644
--- a/rdiff-backup/rdiff-backup.1
+++ b/rdiff-backup/rdiff-backup.1
@@ -536,6 +536,10 @@ A date format of the form YYYY/MM/DD, YYYY-MM-DD, MM/DD/YYYY, or
MM/DD/YYYY, which indicates midnight on the day in question, relative
to the current timezone settings. For instance, "2002/3/5",
"03-05-2002", and "2002-3-05" all mean March 5th, 2002.
+.IP 6.
+A backup session specification which is a non-negative integer
+followed by 'B'. For instance, '0B' specifies the time of the current
+mirror, and '3B' specifies the time of the 3rd newest increment.
.SH REMOTE OPERATION
In order to access remote files, rdiff-backup opens up a pipe to a
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index ab26903..ef3537d 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -413,11 +413,11 @@ def Restore(src_rp, dest_rp, restore_as_of = None):
restore_set_fs_globals(dest_rp)
src_rp = restore_init_quoting(src_rp)
restore_check_backup_dir(restore_root, src_rp, restore_as_of)
+ inc_rpath = Globals.rbdir.append_path('increments', restore_index)
if restore_as_of:
- try: time = Time.genstrtotime(restore_timestr)
+ try: time = Time.genstrtotime(restore_timestr, rp = inc_rpath)
except Time.TimeException, exc: Log.FatalError(str(exc))
else: time = src_rp.getinctime()
- inc_rpath = Globals.rbdir.append_path('increments', restore_index)
restore_set_select(restore_root, dest_rp)
restore_start_log(src_rp, dest_rp, time)
restore.Restore(restore_root.new_index(restore_index),
@@ -632,9 +632,9 @@ def rot_check_dir(rootrp):
def ListChangedSince(rp):
"""List all the files under rp that have changed since restoretime"""
+ assert restore_set_root(rp)
try: rest_time = Time.genstrtotime(restore_timestr)
except Time.TimeException, exc: Log.FatalError(str(exc))
- assert restore_set_root(rp)
restore_check_backup_dir(restore_root)
mirror_rp = restore_root.new_index(restore_index)
inc_rp = mirror_rp.append_path("increments", restore_index)
@@ -643,9 +643,9 @@ def ListChangedSince(rp):
def ListAtTime(rp):
"""List files in archive under rp that are present at restoretime"""
+ assert restore_set_root(rp)
try: rest_time = Time.genstrtotime(restore_timestr)
except Time.TimeException, exc: Log.FatalError(str(exc))
- assert restore_set_root(rp)
restore_check_backup_dir(restore_root)
mirror_rp = restore_root.new_index(restore_index)
inc_rp = mirror_rp.append_path("increments", restore_index)
diff --git a/rdiff-backup/rdiff_backup/Time.py b/rdiff-backup/rdiff_backup/Time.py
index 289df0a..e3a6173 100644
--- a/rdiff-backup/rdiff_backup/Time.py
+++ b/rdiff-backup/rdiff_backup/Time.py
@@ -19,7 +19,7 @@
"""Provide time related exceptions and functions"""
-import time, types, re
+import time, types, re, sys
import Globals
@@ -28,6 +28,7 @@ class TimeException(Exception): pass
_interval_conv_dict = {"s": 1, "m": 60, "h": 3600, "D": 86400,
"W": 7*86400, "M": 30*86400, "Y": 365*86400}
_integer_regexp = re.compile("^[0-9]+$")
+_session_regexp = re.compile("^[0-9]+B$")
_interval_regexp = re.compile("^([0-9]+)([smhDWMY])")
_genstr_date_regexp1 = re.compile("^(?P<year>[0-9]{4})[-/]"
"(?P<month>[0-9]{1,2})[-/](?P<day>[0-9]{1,2})$")
@@ -174,8 +175,27 @@ def cmp(time1, time2):
elif time1 == time2: return 0
else: return 1
-def genstrtotime(timestr, curtime = None):
- """Convert a generic time string to a time in seconds"""
+def time_from_session(session_num, rp = None):
+ """Return time in seconds of given backup
+
+ The current mirror is session_num 0, the next oldest increment has
+ number 1, etc. Requires that the Globals.rbdir directory be set.
+
+ """
+ session_times = Globals.rbdir.conn.restore.MirrorStruct \
+ .get_increment_times()
+ session_times.sort()
+ if len(session_times) < session_num:
+ return session_times[0] # Use oldest if two few backups
+ return session_times[-session_num-1]
+
+def genstrtotime(timestr, curtime = None, rp = None):
+ """Convert a generic time string to a time in seconds
+
+ rp is used when the time is of the form "4B" or similar. Then the
+ times of the increments of that particular file are used.
+
+ """
if curtime is None: curtime = globals()['curtime']
if timestr == "now": return curtime
@@ -196,6 +216,10 @@ the day).""" % timestr)
t = stringtotime(timestr) or stringtotime(timestr+gettzd())
if t: return t
+ # Test for time given as number of backups, like 3B
+ if _session_regexp.search(timestr):
+ return time_from_session(int(timestr[:-1]), rp)
+
try: # test for an interval, like "2 days ago"
return curtime - intstringtoseconds(timestr)
except TimeException: pass
@@ -209,3 +233,4 @@ the day).""" % timestr)
t = stringtotime(timestr)
if t: return t
else: error()
+
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index f4add16..aa6c6fe 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -125,16 +125,20 @@ class MirrorStruct:
older one here.
"""
- global _rest_time
- base_incs = get_inclist(Globals.rbdir.append("increments"))
- if not base_incs: return _mirror_time
- inctimes = [inc.getinctime() for inc in base_incs]
- inctimes.append(_mirror_time)
+ inctimes = cls.get_increment_times()
older_times = filter(lambda time: time <= restore_to_time, inctimes)
if older_times: return max(older_times)
else: # restore time older than oldest increment, just return that
return min(inctimes)
+ def get_increment_times(cls, rp = None):
+ """Return list of times of backups, including current mirror"""
+ if not _mirror_time: return_list = [cls.get_mirror_time()]
+ else: return_list = [_mirror_time]
+ if not rp or not rp.index: rp = Globals.rbdir.append("increments")
+ for inc in get_inclist(rp): return_list.append(inc.getinctime())
+ return return_list
+
def initialize_rf_cache(cls, mirror_base, inc_base):
"""Set cls.rf_cache to CachedRF object"""
inc_list = get_inclist(inc_base)
diff --git a/rdiff-backup/testing/finaltest.py b/rdiff-backup/testing/finaltest.py
index 85f3378..5608220 100644
--- a/rdiff-backup/testing/finaltest.py
+++ b/rdiff-backup/testing/finaltest.py
@@ -1,3 +1,4 @@
+from __future__ import generators
import unittest, os, re, sys, time
from commontest import *
from rdiff_backup import Globals, log, rpath, robust, FilenameMapping
@@ -333,6 +334,8 @@ class FinalMisc(PathSetter):
self.set_connections(None, None, None, None)
self.exec_rb_extra_args(None, '--list-changed-since 10000',
'testfiles/restoretest3')
+ self.exec_rb_extra_args(None, '--list-changed-since 2B',
+ 'testfiles/restoretest3')
def testListChangeSinceRemote(self):
"""Test --list-changed-since mode remotely. Uses restoretest3"""
@@ -364,6 +367,42 @@ class FinalMisc(PathSetter):
self.exec_rb_extra_args(None, "--list-increment-sizes",
"testfiles/restoretest3")
+ def get_all_increments(self, rp):
+ """Iterate all increments at or below given directory"""
+ assert rp.isdir()
+ dirlist = rp.listdir()
+ dirlist.sort()
+ for filename in dirlist:
+ subrp = rp.append(filename)
+ if subrp.isincfile(): yield subrp
+ elif subrp.isdir():
+ for subsubrp in self.get_all_increments(subrp):
+ yield subsubrp
+
+ def testRemoveOlderThan(self):
+ """Test --remove-older-than. Uses restoretest3"""
+ Myrm("testfiles/output")
+ assert not os.system("cp -a testfiles/restoretest3 testfiles/output")
+ self.set_connections(None, None, None, None)
+ self.exec_rb_extra_args(None, "--remove-older-than 20000",
+ "testfiles/output")
+ rbdir = rpath.RPath(Globals.local_connection,
+ "testfiles/output/rdiff-backup-data")
+ for inc in self.get_all_increments(rbdir):
+ assert inc.getinctime() >= 20000
+
+ def testRemoveOlderThan2(self):
+ """Test --remove-older-than, but '1B'. Uses restoretest3"""
+ Myrm("testfiles/output")
+ assert not os.system("cp -a testfiles/restoretest3 testfiles/output")
+ self.set_connections(None, None, None, None)
+ self.exec_rb_extra_args(None, "--remove-older-than 1B --force",
+ "testfiles/output")
+ rbdir = rpath.RPath(Globals.local_connection,
+ "testfiles/output/rdiff-backup-data")
+ for inc in self.get_all_increments(rbdir):
+ assert inc.getinctime() >= 30000
+
class FinalSelection(PathSetter):
"""Test selection options"""
diff --git a/rdiff-backup/testing/restoretest.py b/rdiff-backup/testing/restoretest.py
index b401643..5f939f9 100644
--- a/rdiff-backup/testing/restoretest.py
+++ b/rdiff-backup/testing/restoretest.py
@@ -51,6 +51,26 @@ class RestoreFileComparer:
for t in self.time_rp_dict.keys(): self.compare_at_time(t)
+class RestoreTimeTest(unittest.TestCase):
+ def test_time_from_session(self):
+ """Test getting time from session number (as in Time.time_from_session)
+
+ Test here instead of in timetest because it depends on an
+ rdiff-backup-data directory already being laid out.
+
+ """
+ restore._mirror_time = None # Reset
+ Globals.rbdir = rpath.RPath(lc,
+ "testfiles/restoretest3/rdiff-backup-data")
+ assert Time.genstrtotime("0B") == Time.time_from_session(0)
+ assert Time.genstrtotime("2B") == Time.time_from_session(2)
+ assert Time.genstrtotime("23B") == Time.time_from_session(23)
+
+ assert Time.time_from_session(0) == 40000, Time.time_from_session(0)
+ assert Time.time_from_session(2) == 20000, Time.time_from_session(2)
+ assert Time.time_from_session(5) == 10000, Time.time_from_session(5)
+
+
class RestoreTest(unittest.TestCase):
"""Test Restore class"""
def get_rfcs(self):