Commit 6a98bce8 authored by bescoto's avatar bescoto

Added session number like '3B' to general time specification


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@415 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent b323d84d
......@@ -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)
---------------------------
......
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:
......
......@@ -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
......
......@@ -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)
......
......@@ -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()
......@@ -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)
......
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"""
......
......@@ -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):
......
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