Commit 9259a402 authored by ben's avatar ben

Belatedly added filename_mapping (should have been added with 0.7.4).

Changed various files to fix --exclude-filelist problems when source
remote.


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@85 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent 3d5b5edd
from __future__ import generators
execfile("rdiff.py") execfile("rdiff.py")
import types, os, tempfile, cPickle, shutil, traceback import types, os, tempfile, cPickle, shutil, traceback
...@@ -487,3 +488,10 @@ class VirtualFile: ...@@ -487,3 +488,10 @@ class VirtualFile:
def close(self): def close(self):
return self.connection.VirtualFile.closebyid(self.id) return self.connection.VirtualFile.closebyid(self.id)
def __iter__(self):
"""Iterates lines in file, like normal iter(file) behavior"""
while 1:
line = self.readline()
if not line: break
yield line
...@@ -157,7 +157,7 @@ class Select: ...@@ -157,7 +157,7 @@ class Select:
if result is not None: return result if result is not None: return result
return 1 return 1
def ParseArgs(self, argtuples): def ParseArgs(self, argtuples, filelists):
"""Create selection functions based on list of tuples """Create selection functions based on list of tuples
The tuples have the form (option string, additional argument) The tuples have the form (option string, additional argument)
...@@ -169,6 +169,7 @@ class Select: ...@@ -169,6 +169,7 @@ class Select:
information is sent over the link. information is sent over the link.
""" """
filelists_index = 0
try: try:
for opt, arg in argtuples: for opt, arg in argtuples:
if opt == "--exclude": if opt == "--exclude":
...@@ -176,19 +177,22 @@ class Select: ...@@ -176,19 +177,22 @@ class Select:
elif opt == "--exclude-device-files": elif opt == "--exclude-device-files":
self.add_selection_func(self.devfiles_get_sf()) self.add_selection_func(self.devfiles_get_sf())
elif opt == "--exclude-filelist": elif opt == "--exclude-filelist":
self.add_selection_func(self.filelist_get_sf(arg[1], self.add_selection_func(self.filelist_get_sf(
0, arg[0])) filelists[filelists_index], 0, arg))
filelists_index += 1
elif opt == "--exclude-regexp": elif opt == "--exclude-regexp":
self.add_selection_func(self.regexp_get_sf(arg, 0)) self.add_selection_func(self.regexp_get_sf(arg, 0))
elif opt == "--include": elif opt == "--include":
self.add_selection_func(self.glob_get_sf(arg, 1)) self.add_selection_func(self.glob_get_sf(arg, 1))
elif opt == "--include-filelist": elif opt == "--include-filelist":
self.add_selection_func(self.filelist_get_sf(arg[1], self.add_selection_func(self.filelist_get_sf(
1, arg[0])) filelists[filelists_index], 1, arg))
filelists_index += 1
elif opt == "--include-regexp": elif opt == "--include-regexp":
self.add_selection_func(self.regexp_get_sf(arg, 1)) self.add_selection_func(self.regexp_get_sf(arg, 1))
else: assert 0, "Bad selection option %s" % opt else: assert 0, "Bad selection option %s" % opt
except SelectError, e: self.parse_catch_error(e) except SelectError, e: self.parse_catch_error(e)
assert filelists_index == len(filelists)
self.parse_last_excludes() self.parse_last_excludes()
self.parse_rbdir_exclude() self.parse_rbdir_exclude()
......
from __future__ import generators
execfile("rdiff.py") execfile("rdiff.py")
import types, os, tempfile, cPickle, shutil, traceback import types, os, tempfile, cPickle, shutil, traceback
...@@ -487,3 +488,10 @@ class VirtualFile: ...@@ -487,3 +488,10 @@ class VirtualFile:
def close(self): def close(self):
return self.connection.VirtualFile.closebyid(self.id) return self.connection.VirtualFile.closebyid(self.id)
def __iter__(self):
"""Iterates lines in file, like normal iter(file) behavior"""
while 1:
line = self.readline()
if not line: break
yield line
execfile("selection.py")
import re
#######################################################################
#
# filename_mapping - used to coordinate related filenames
#
# For instance, some source filenames may contain characters not
# allowed on the mirror end. Also, if a source filename is very long
# (say 240 characters), the extra characters added to related
# increments may put them over the usual 255 character limit.
#
class FilenameMapping:
"""Contains class methods which coordinate related filenames"""
max_filename_length = 255
# If true, enable character quoting, and set characters making
# regex-style range.
chars_to_quote = None
# These compiled regular expressions are used in quoting and unquoting
chars_to_quote_regexp = None
unquoting_regexp = None
# Use given char to quote. Default is set in Globals.
quoting_char = None
def set_init_quote_vals(cls):
"""Set quoting value from Globals on all conns"""
for conn in Globals.connections:
conn.FilenameMapping.set_init_quote_vals_local()
def set_init_quote_vals_local(cls):
"""Set value on local connection, initialize regexps"""
cls.chars_to_quote = Globals.chars_to_quote
if len(Globals.quoting_char) != 1:
Log.FatalError("Expected single character for quoting char,"
"got '%s' instead" % (Globals.quoting_char,))
cls.quoting_char = Globals.quoting_char
cls.init_quoting_regexps()
def init_quoting_regexps(cls):
"""Compile quoting regular expressions"""
try:
cls.chars_to_quote_regexp = \
re.compile("[%s%s]" % (cls.chars_to_quote,
cls.quoting_char), re.S)
cls.unquoting_regexp = \
re.compile("%s[0-9]{3}" % cls.quoting_char, re.S)
except re.error:
Log.FatalError("Error '%s' when processing char quote list %s" %
(re.error, cls.chars_to_quote))
def quote(cls, path):
"""Return quoted version of given path
Any characters quoted will be replaced by the quoting char and
the ascii number of the character. For instance, "10:11:12"
would go to "10;05811;05812" if ":" were quoted and ";" were
the quoting character.
"""
return cls.chars_to_quote_regexp.sub(cls.quote_single, path)
def quote_single(cls, match):
"""Return replacement for a single character"""
return "%s%03d" % (cls.quoting_char, ord(match.group()))
def unquote(cls, path):
"""Return original version of quoted filename"""
return cls.unquoting_regexp.sub(cls.unquote_single, path)
def unquote_single(cls, match):
"""Unquote a single quoted character"""
assert len(match.group()) == 4
return chr(int(match.group()[1:]))
def get_quoted_dir_children(cls, rpath):
"""For rpath directory, return list of quoted children in dir"""
if not rpath.isdir(): return []
dir_pairs = [(cls.unquote(filename), filename)
for filename in rpath.listdir()]
dir_pairs.sort() # sort by real index, not quoted part
child_list = []
for unquoted, filename in dir_pairs:
childrp = rpath.append(unquoted)
childrp.quote_path()
child_list.append(childrp)
return child_list
MakeClass(FilenameMapping)
...@@ -192,12 +192,19 @@ class Globals: ...@@ -192,12 +192,19 @@ class Globals:
else: cls.__dict__[name] = re.compile(re_string) else: cls.__dict__[name] = re.compile(re_string)
postset_regexp_local = classmethod(postset_regexp_local) postset_regexp_local = classmethod(postset_regexp_local)
def set_select(cls, dsrpath, tuplelist, quote_mode = None): def set_select(cls, dsrpath, tuplelist, quote_mode, *filelists):
"""Initialize select object using tuplelist""" """Initialize select object using tuplelist
Note that each list in filelists must each be passed as
separate arguments, so each is recognized as a file by the
connection. Otherwise we will get an error because a list
containing files can't be pickled.
"""
if dsrpath.source: if dsrpath.source:
cls.select_source = Select(dsrpath, quote_mode) cls.select_source = Select(dsrpath, quote_mode)
cls.select_source.ParseArgs(tuplelist) cls.select_source.ParseArgs(tuplelist, filelists)
else: else:
cls.select_mirror = Select(dsrpath, quote_mode) cls.select_mirror = Select(dsrpath, quote_mode)
cls.select_mirror.ParseArgs(tuplelist) cls.select_mirror.ParseArgs(tuplelist, filelists)
set_select = classmethod(set_select) set_select = classmethod(set_select)
...@@ -14,6 +14,7 @@ class Main: ...@@ -14,6 +14,7 @@ class Main:
self.remote_cmd, self.remote_schema = None, None self.remote_cmd, self.remote_schema = None, None
self.force = None self.force = None
self.select_opts, self.select_mirror_opts = [], [] self.select_opts, self.select_mirror_opts = [], []
self.select_files = []
def parse_cmdlineoptions(self): def parse_cmdlineoptions(self):
"""Parse argument list and set global preferences""" """Parse argument list and set global preferences"""
...@@ -37,8 +38,8 @@ class Main: ...@@ -37,8 +38,8 @@ class Main:
"restore-as-of=", "resume", "resume-window=", "server", "restore-as-of=", "resume", "resume-window=", "server",
"terminal-verbosity=", "test-server", "verbosity", "terminal-verbosity=", "test-server", "verbosity",
"version", "windows-mode", "windows-time-format"]) "version", "windows-mode", "windows-time-format"])
except getopt.error: except getopt.error, e:
self.commandline_error("Error parsing commandline options") self.commandline_error("Bad commandline options: %s" % str(e))
for opt, arg in optlist: for opt, arg in optlist:
if opt == "-b" or opt == "--backup-mode": self.action = "backup" if opt == "-b" or opt == "--backup-mode": self.action = "backup"
...@@ -55,20 +56,24 @@ class Main: ...@@ -55,20 +56,24 @@ class Main:
elif opt == "--exclude-device-files": elif opt == "--exclude-device-files":
self.select_opts.append((opt, arg)) self.select_opts.append((opt, arg))
elif opt == "--exclude-filelist": elif opt == "--exclude-filelist":
self.select_opts.append((opt, (arg, sel_fl(arg)))) self.select_opts.append((opt, arg))
self.select_files.append(sel_fl(arg))
elif opt == "--exclude-filelist-stdin": elif opt == "--exclude-filelist-stdin":
self.select_opts.append(("--exclude-filelist", self.select_opts.append(("--exclude-filelist",
("standard input", sys.stdin))) "standard input"))
self.select_files.append(sys.stdin)
elif opt == "--exclude-mirror": elif opt == "--exclude-mirror":
self.select_mirror_opts.append(("--exclude", arg)) self.select_mirror_opts.append(("--exclude", arg))
elif opt == "--exclude-regexp": self.select_opts.append((opt, arg)) elif opt == "--exclude-regexp": self.select_opts.append((opt, arg))
elif opt == "--force": self.force = 1 elif opt == "--force": self.force = 1
elif opt == "--include": self.select_opts.append((opt, arg)) elif opt == "--include": self.select_opts.append((opt, arg))
elif opt == "--include-filelist": elif opt == "--include-filelist":
self.select_opts.append((opt, (arg, sel_fl(arg)))) self.select_opts.append((opt, arg))
self.select_files.append(sel_fl(arg))
elif opt == "--include-filelist-stdin": elif opt == "--include-filelist-stdin":
self.select_opts.append(("--include-filelist", self.select_opts.append(("--include-filelist",
("standard input", sys.stdin))) "standard input"))
self.select_files.append(sys.stdin)
elif opt == "--include-regexp": elif opt == "--include-regexp":
self.select_opts.append((opt, arg)) self.select_opts.append((opt, arg))
elif opt == "-l" or opt == "--list-increments": elif opt == "-l" or opt == "--list-increments":
...@@ -227,7 +232,8 @@ rdiff-backup with the --force option if you want to mirror anyway.""" % ...@@ -227,7 +232,8 @@ rdiff-backup with the --force option if you want to mirror anyway.""" %
def backup_init_select(self, rpin, rpout): def backup_init_select(self, rpin, rpout):
"""Create Select objects on source and dest connections""" """Create Select objects on source and dest connections"""
rpin.conn.Globals.set_select(DSRPath(1, rpin), self.select_opts) rpin.conn.Globals.set_select(DSRPath(1, rpin), self.select_opts,
None, *self.select_files)
rpout.conn.Globals.set_select(DSRPath(None, rpout), rpout.conn.Globals.set_select(DSRPath(None, rpout),
self.select_mirror_opts, 1) self.select_mirror_opts, 1)
...@@ -378,8 +384,9 @@ Try restoring from an increment file (the filenames look like ...@@ -378,8 +384,9 @@ Try restoring from an increment file (the filenames look like
the restore operation isn't. the restore operation isn't.
""" """
Globals.set_select(DSRPath(1, rpin), self.select_mirror_opts) Globals.set_select(DSRPath(1, rpin), self.select_mirror_opts, None)
Globals.set_select(DSRPath(None, rpout), self.select_opts) Globals.set_select(DSRPath(None, rpout), self.select_opts, None,
*self.select_files)
def restore_get_root(self, rpin): def restore_get_root(self, rpin):
"""Return (mirror root, index) and set the data dir """Return (mirror root, index) and set the data dir
......
...@@ -157,7 +157,7 @@ class Select: ...@@ -157,7 +157,7 @@ class Select:
if result is not None: return result if result is not None: return result
return 1 return 1
def ParseArgs(self, argtuples): def ParseArgs(self, argtuples, filelists):
"""Create selection functions based on list of tuples """Create selection functions based on list of tuples
The tuples have the form (option string, additional argument) The tuples have the form (option string, additional argument)
...@@ -169,6 +169,7 @@ class Select: ...@@ -169,6 +169,7 @@ class Select:
information is sent over the link. information is sent over the link.
""" """
filelists_index = 0
try: try:
for opt, arg in argtuples: for opt, arg in argtuples:
if opt == "--exclude": if opt == "--exclude":
...@@ -176,19 +177,22 @@ class Select: ...@@ -176,19 +177,22 @@ class Select:
elif opt == "--exclude-device-files": elif opt == "--exclude-device-files":
self.add_selection_func(self.devfiles_get_sf()) self.add_selection_func(self.devfiles_get_sf())
elif opt == "--exclude-filelist": elif opt == "--exclude-filelist":
self.add_selection_func(self.filelist_get_sf(arg[1], self.add_selection_func(self.filelist_get_sf(
0, arg[0])) filelists[filelists_index], 0, arg))
filelists_index += 1
elif opt == "--exclude-regexp": elif opt == "--exclude-regexp":
self.add_selection_func(self.regexp_get_sf(arg, 0)) self.add_selection_func(self.regexp_get_sf(arg, 0))
elif opt == "--include": elif opt == "--include":
self.add_selection_func(self.glob_get_sf(arg, 1)) self.add_selection_func(self.glob_get_sf(arg, 1))
elif opt == "--include-filelist": elif opt == "--include-filelist":
self.add_selection_func(self.filelist_get_sf(arg[1], self.add_selection_func(self.filelist_get_sf(
1, arg[0])) filelists[filelists_index], 1, arg))
filelists_index += 1
elif opt == "--include-regexp": elif opt == "--include-regexp":
self.add_selection_func(self.regexp_get_sf(arg, 1)) self.add_selection_func(self.regexp_get_sf(arg, 1))
else: assert 0, "Bad selection option %s" % opt else: assert 0, "Bad selection option %s" % opt
except SelectError, e: self.parse_catch_error(e) except SelectError, e: self.parse_catch_error(e)
assert filelists_index == len(filelists)
self.parse_last_excludes() self.parse_last_excludes()
self.parse_rbdir_exclude() self.parse_rbdir_exclude()
......
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