# current time for this backup. Used for file names and file creation checks
current_time = None
+ # extra data to included in the header of the index file when creating a
+ # backup
+ extra_data = dict()
+
# valid tarfile modes and their corresponding default file extension
__file_extensions_dict = {
'': '',
key_length=key_length)
def create_full_backup(self, source_path, backup_path,
- max_volume_size=None):
+ max_volume_size=None, extra_data=dict()):
'''
Creates a full backup.
be created if not existent.
- max_volume_size: maximum volume size in megabytes. Used to split the
backup in volumes. Optional (won't split in volumes by default).
+ - extra_data: a json-serializable dictionary with information that you
+ want to be included in the header of the index file
'''
# check input
if not isinstance(source_path, str):
if max_volume_size != None:
max_volume_size = max_volume_size*1024*1024
+ if not isinstance(extra_data, dict):
+ raise Exception('extra_data must be a dictionary')
+
+ try:
+ extra_data_str = json.dumps(extra_data)
+ except:
+ raise Exception('extra_data is not json-serializable')
+
if not os.access(source_path, os.R_OK):
raise Exception('Source path "%s" is not readable' % source_path)
# wraps some args from context into the handler
new_volume_handler = partial(new_volume_handler, self, cwd, backup_path)
- index_fd.write(bytes('{"type": "python-delta-tar-index", "version": 1, "backup-type": "full" }\n', 'UTF-8'))
+ index_fd.write(bytes('{"type": "python-delta-tar-index", "version": 1, "backup-type": "full", "extra_data": %s}\n' % extra_data_str, 'UTF-8'))
s = bytes('{"type": "BEGIN-FILE-LIST"}\n', 'UTF-8')
# calculate checksum and write into the stream
tarobj.close()
def create_diff_backup(self, source_path, backup_path, previous_index_path,
- max_volume_size=None):
+ max_volume_size=None, extra_data=dict()):
'''
Creates a backup.
raise Exception('Source path "%s" does not exist or is not a '\
'directory' % source_path)
+ if not isinstance(extra_data, dict):
+ raise Exception('extra_data must be a dictionary')
+
+ try:
+ extra_data_str = json.dumps(extra_data)
+ except:
+ raise Exception('extra_data is not json-serializable')
+
if not os.access(source_path, os.R_OK):
raise Exception('Source path "%s" is not readable' % source_path)
# wraps some args from context into the handler
new_volume_handler = partial(new_volume_handler, self, cwd, backup_path)
- index_fd.write(bytes('{"type": "python-delta-tar-index", "version": 1, "backup-type": "diff" }\n', 'UTF-8'))
+ index_fd.write(bytes('{"type": "python-delta-tar-index", "version": 1, "backup-type": "diff", "extra_data": %s}\n' % extra_data_str, 'UTF-8'))
s = bytes('{"type": "BEGIN-FILE-LIST"}\n', 'UTF-8')
# calculate checksum and write into the stream
self.delta_tar = delta_tar
self.index_path = index_path
self.f = None
+ self.extra_data = dict()
self.__enter__()
def __iter__(self):
j.get('version', -1) != 1:
raise Exception("invalid index file format: %s" % json.dumps(j))
+ self.extra_data = j.get('extra_data', dict())
+
# find BEGIN-FILE-LIST, ignore other headers
while True:
j, l_no = self.delta_tar._parse_json_line(self.f, l_no)
if value:
assert value == self.md5sum(key)
+ def test_full_backup_index_extra_data(self):
+ '''
+ Tests that the index file for a full backup can store extra_data and
+ that this data can be retrieved.
+ '''
+ deltatar = DeltaTar(mode=self.MODE, password=self.PASSWORD,
+ logger=self.consoleLogger)
+
+ extra_data = dict(
+ hola="caracola",
+ otra_cosa=[1, "lista"],
+ y_otra=dict(bola=1.1)
+ )
+
+ deltatar.create_full_backup(
+ source_path="source_dir",
+ backup_path="backup_dir",
+ extra_data=extra_data)
+
+ index_filename = deltatar.index_name_func(is_full=True)
+ index_path = os.path.join("backup_dir", index_filename)
+
+ # iterate_index_path retrieves extra_data, and thus we can then compare
+ index_it = deltatar.iterate_index_path(index_path)
+ self.assertEqual(index_it.extra_data, extra_data)
+
+
+ def test_diff_backup_index_extra_data(self):
+ '''
+ Tests that the index file for a diff backup can store extra_data and
+ that this data can be retrieved.
+ '''
+ deltatar = DeltaTar(mode=self.MODE, password=self.PASSWORD,
+ logger=self.consoleLogger)
+
+ extra_data = dict(
+ hola="caracola",
+ otra_cosa=[1, "lista"],
+ y_otra=dict(bola=1.1)
+ )
+ # do first backup
+ deltatar.create_full_backup(
+ source_path="source_dir",
+ backup_path="backup_dir")
+
+
+ prev_index_filename = deltatar.index_name_func(is_full=True)
+ prev_index_path = os.path.join("backup_dir", prev_index_filename)
+
+ # create empty diff backup
+ deltatar.create_diff_backup("source_dir", "backup_dir2",
+ prev_index_path, extra_data=extra_data)
+
+ index_filename = deltatar.index_name_func(is_full=False)
+ index_path = os.path.join("backup_dir2", index_filename)
+
+ # iterate_index_path retrieves extra_data, and thus we can then compare
+ index_it = deltatar.iterate_index_path(index_path)
+ self.assertEqual(index_it.extra_data, extra_data)
+
def test_restore_multivol2(self):
'''
Creates a full backup without any filtering with multiple volumes and