1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# Copyright (C) 2015 Lars Wirzenius
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import re
import obnamlib
class ExcludePathnamesPlugin(obnamlib.ObnamPlugin):
def enable(self):
backup_group = obnamlib.option_group['backup'] = 'Backing up'
self.app.settings.string_list(
['exclude'],
'regular expression for pathnames to '
'exclude from backup (can be used multiple '
'times)',
group=backup_group)
self.app.settings.string_list(
['exclude-from'],
'read exclude patterns from FILE',
metavar='FILE',
group=backup_group)
self.app.settings.string_list(
['include'],
'regular expression for pathnames to include from backup '
'even if it matches an exclude rule '
'(can be used multiple times)',
group=backup_group)
self.app.hooks.add_callback('config-loaded', self.config_loaded)
def config_loaded(self):
self.app.hooks.add_callback('backup-exclude', self.exclude)
self.pathname_excluder = obnamlib.PathnameExcluder()
self.patterns_have_been_compiled = False
def exclude(self, pathname=None, stat_result=None, exclude=None,
progress=None, **kwargs):
if not self.patterns_have_been_compiled:
self.compile_exclusion_patterns(progress)
self.compile_inclusion_patterns(progress)
self.patterns_have_been_compiled = True
is_excluded, regexp = self.pathname_excluder.exclude(pathname)
if is_excluded:
logging.debug('Exclude (pattern): %s', pathname)
exclude[0] = True
elif regexp is not None:
logging.debug('Include due to regexp: %s', pathname)
def compile_exclusion_patterns(self, progress):
regexps = self.read_patterns_from_files(
self.app.settings['exclude-from'])
regexps.extend(self.app.settings['exclude'])
# Ignore log file, except don't exclude the words cliapp uses
# for not logging or for logging to syslog.
log = self.app.settings['log']
if log and log not in ('none', 'syslog'):
regexps.append(log)
logging.debug('Compiling exclusion patterns')
self.compile_regexps(
regexps, self.pathname_excluder.exclude_regexp, progress)
def compile_inclusion_patterns(self, progress):
logging.debug('Compiling inclusion patterns')
self.compile_regexps(
self.app.settings['include'],
self.pathname_excluder.allow_regexp,
progress)
def compile_regexps(self, regexps, compiler, progress):
for regexp in regexps:
if not regexp:
logging.debug('Ignoring empty pattern')
continue
logging.debug('Regular expression: %s', regexp)
try:
compiler(regexp)
except re.error as e:
msg = ('error compiling regular expression "%s": %s' %
(regexp, e))
logging.error(msg)
progress.error(msg)
def read_patterns_from_files(self, filenames):
patterns = []
for filename in filenames:
with open(filename) as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
patterns.append(line)
return patterns
|