Update archiving of state file to use tarfile

This commit is contained in:
Calum Lind 2017-06-09 13:02:45 +01:00
parent 596b5d5cd4
commit 45e0d10932
3 changed files with 69 additions and 27 deletions

View File

@ -11,7 +11,9 @@
from __future__ import division, print_function, unicode_literals
import base64
import datetime
import functools
import glob
import locale
import logging
import numbers
@ -20,6 +22,7 @@ import platform
import re
import subprocess
import sys
import tarfile
import time
import chardet
@ -138,6 +141,45 @@ def get_default_download_dir():
return download_dir
def archive_files(arc_name, filepaths):
"""Compress a list of filepaths into timestamped tarball in config dir.
The archiving config directory is 'archive'.
Args:
arc_name (str): The archive output filename (appended with timestamp).
filepaths (list): A list of the files to be archived into tarball.
Returns:
str: The full archive filepath.
"""
from deluge.configmanager import get_config_dir
# Set archive compression to lzma with bz2 fallback.
arc_comp = 'xz' if not PY2 else 'bz2'
archive_dir = os.path.join(get_config_dir(), 'archive')
timestamp = datetime.datetime.now().replace(microsecond=0).isoformat().replace(':', '-')
arc_filepath = os.path.join(archive_dir, arc_name + '-' + timestamp + '.tar.' + arc_comp)
max_num_arcs = 20
if not os.path.exists(archive_dir):
os.makedirs(archive_dir)
else:
old_arcs = glob.glob(os.path.join(archive_dir, arc_name) + '*')
if len(old_arcs) > max_num_arcs:
# TODO: Remove oldest timestamped archives.
log.warning('More than %s tarballs in config archive', max_num_arcs)
with tarfile.open(arc_filepath, 'w:' + arc_comp) as tf:
for filepath in filepaths:
tf.add(filepath, arcname=os.path.basename(filepath))
return arc_filepath
def windows_check():
"""
Checks if the current platform is Windows

View File

@ -15,7 +15,6 @@ import datetime
import logging
import operator
import os
import shutil
import time
from twisted.internet import defer, reactor, threads
@ -24,7 +23,7 @@ from twisted.internet.task import LoopingCall
import deluge.component as component
from deluge._libtorrent import lt
from deluge.common import decode_bytes, get_magnet_info
from deluge.common import archive_files, decode_bytes, get_magnet_info
from deluge.configmanager import ConfigManager, get_config_dir
from deluge.core.authmanager import AUTH_LEVEL_ADMIN
from deluge.core.torrent import Torrent, TorrentOptions, sanitize_filepath
@ -171,28 +170,14 @@ class TorrentManager(component.Component):
def start(self):
# Check for old temp file to verify safe shutdown
if os.path.isfile(self.temp_file):
def archive_file(filename):
"""Archives the file in 'archive' sub-directory with timestamp appended"""
filepath = os.path.join(self.state_dir, filename)
filepath_bak = filepath + '.bak'
archive_dir = os.path.join(get_config_dir(), 'archive')
if not os.path.exists(archive_dir):
os.makedirs(archive_dir)
for _filepath in (filepath, filepath_bak):
timestamp = datetime.datetime.now().replace(microsecond=0).isoformat().replace(':', '-')
archive_filepath = os.path.join(archive_dir, filename + '-' + timestamp)
try:
shutil.copy2(_filepath, archive_filepath)
except IOError:
log.error('Unable to archive: %s', filename)
else:
log.info('Archive of %s successful: %s', filename, archive_filepath)
log.warning('Potential bad shutdown of Deluge detected, archiving torrent state files...')
archive_file('torrents.state')
archive_file('torrents.fastresume')
else:
arc_filepaths = []
for filename in ('torrents.fastresume', 'torrents.state'):
filepath = os.path.join(self.state_dir, filename)
arc_filepaths.extend([filepath, filepath + '.bak'])
archive_files('torrents_state', arc_filepaths)
os.remove(self.temp_file)
with open(self.temp_file, 'a'):
os.utime(self.temp_file, None)

View File

@ -8,16 +8,20 @@
from __future__ import unicode_literals
import os
import tarfile
from twisted.trial import unittest
from deluge.common import (VersionSplit, fdate, fpcnt, fpeer, fsize, fspeed, ftime, get_path_size, is_infohash, is_ip,
is_ipv4, is_ipv6, is_magnet, is_url)
from deluge.common import (VersionSplit, archive_files, fdate, fpcnt, fpeer, fsize, fspeed, ftime, get_path_size,
is_infohash, is_ip, is_ipv4, is_ipv6, is_magnet, is_url)
from deluge.ui.translations_util import setup_translations
from .common import get_test_data_file, set_tmp_config_dir
class CommonTestCase(unittest.TestCase):
def setUp(self): # NOQA
self.config_dir = set_tmp_config_dir()
setup_translations()
def tearDown(self): # NOQA
@ -127,3 +131,14 @@ class CommonTestCase(unittest.TestCase):
for human_size, byte_size in sizes:
parsed = parse_human_size(human_size)
self.assertEqual(parsed, byte_size, 'Mismatch when converting: %s' % human_size)
def test_archive_files(self):
arc_filelist = [
get_test_data_file('test.torrent'),
get_test_data_file('deluge.png')]
arc_filepath = archive_files('test-arc', arc_filelist)
with tarfile.open(arc_filepath, 'r') as tar:
for tar_info in tar:
self.assertTrue(tar_info.isfile())
self.assertTrue(tar_info.name in [os.path.basename(arcf) for arcf in arc_filelist])