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
|
import fcntl
import logging
import os
import os.path
import subprocess
class StepResult:
success = None
output = None
def __init__(self, success = True, output = ''):
self.success = success
self.output = output
class BackupResult:
target_results = None
par2_result = None
def __init__(self):
self.target_results = {}
self.par2_result = StepResult()
class Repo:
"""
A single Bup repository into which the data will be backed up, plus a
separate directory for extra runtime data.
:param str bup_dir: path to the bup repository, defaults to BUP_DIR or ~/.bup
:param str data_dir: path to the directory for storing the runtime data,
defaults to ~/.local/var/lbup
"""
bup_dir = None
data_dir = None
lock_name = 'lock'
_logger = None
def __init__(self, bup_dir = None, data_dir = None, logger = None):
if bup_dir is None:
if 'BUP_DIR' in os.environ:
bup_dir = os.environ['BUP_DIR']
else:
bup_dir = os.path.expanduser('~/.bup')
if data_dir is None:
data_dir = os.path.expanduser('~/.local/var/lbup/')
if logger is None:
self._logger = logging.getLogger('%s.%s' % (self.__class__.__name__, bup_dir))
else:
self._logger = logger
# create the data dir, if it does not already exist
os.makedirs(data_dir, 0o700, exist_ok = True)
self.bup_dir = bup_dir
self.data_dir = data_dir
def backup(self, tgts, gen_par2 = True):
"""
Backup the supplied targets.
:param list of Target tgts: List of targets to back up.
:param bool gen_par2: Whether to generate par2 recovery information
after the backup concludes'
"""
with open(os.path.join(self.data_dir, self.lock_name), 'w') as lockfile:
result = BackupResult()
self._logger.debug('Acquiring repository lock')
fcntl.lockf(lockfile, fcntl.LOCK_EX)
try:
for tgt in tgts:
self._logger.info('Backing up %s...' % tgt.name)
try:
res = tgt.save(self.data_dir)
except Exception as e:
self._logger.error('Exception backing up %s: %s' % (tgt.name, str(e)))
res = StepResult(False, str(e).encode('utf-8'))
else:
self._logger.info('Backing up %s done' % tgt.name)
result.target_results[tgt.name] = res
if gen_par2:
self._logger.info('Generating par2 files...')
res = subprocess.run(['bup', 'fsck', '-g'],
capture_output = True)
self._logger.info('Generating par2 files done')
result.par2_result = StepResult(res.returncode == 0,
res.stderr + res.stdout)
finally:
self._logger.debug('Releasing repository lock')
fcntl.lockf(lockfile, fcntl.LOCK_UN)
self._logger.debug('Backup finished')
return result
|