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 from __future__ import division, print_function, unicode_literals
import base64 import base64
import datetime
import functools import functools
import glob
import locale import locale
import logging import logging
import numbers import numbers
@ -20,6 +22,7 @@ import platform
import re import re
import subprocess import subprocess
import sys import sys
import tarfile
import time import time
import chardet import chardet
@ -138,6 +141,45 @@ def get_default_download_dir():
return 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(): def windows_check():
""" """
Checks if the current platform is Windows Checks if the current platform is Windows

View File

@ -15,7 +15,6 @@ import datetime
import logging import logging
import operator import operator
import os import os
import shutil
import time import time
from twisted.internet import defer, reactor, threads from twisted.internet import defer, reactor, threads
@ -24,7 +23,7 @@ from twisted.internet.task import LoopingCall
import deluge.component as component import deluge.component as component
from deluge._libtorrent import lt 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.configmanager import ConfigManager, get_config_dir
from deluge.core.authmanager import AUTH_LEVEL_ADMIN from deluge.core.authmanager import AUTH_LEVEL_ADMIN
from deluge.core.torrent import Torrent, TorrentOptions, sanitize_filepath from deluge.core.torrent import Torrent, TorrentOptions, sanitize_filepath
@ -171,28 +170,14 @@ class TorrentManager(component.Component):
def start(self): def start(self):
# Check for old temp file to verify safe shutdown # Check for old temp file to verify safe shutdown
if os.path.isfile(self.temp_file): 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...') log.warning('Potential bad shutdown of Deluge detected, archiving torrent state files...')
archive_file('torrents.state') arc_filepaths = []
archive_file('torrents.fastresume') for filename in ('torrents.fastresume', 'torrents.state'):
else: 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'): with open(self.temp_file, 'a'):
os.utime(self.temp_file, None) os.utime(self.temp_file, None)

View File

@ -8,16 +8,20 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os import os
import tarfile
from twisted.trial import unittest from twisted.trial import unittest
from deluge.common import (VersionSplit, fdate, fpcnt, fpeer, fsize, fspeed, ftime, get_path_size, is_infohash, is_ip, from deluge.common import (VersionSplit, archive_files, fdate, fpcnt, fpeer, fsize, fspeed, ftime, get_path_size,
is_ipv4, is_ipv6, is_magnet, is_url) is_infohash, is_ip, is_ipv4, is_ipv6, is_magnet, is_url)
from deluge.ui.translations_util import setup_translations from deluge.ui.translations_util import setup_translations
from .common import get_test_data_file, set_tmp_config_dir
class CommonTestCase(unittest.TestCase): class CommonTestCase(unittest.TestCase):
def setUp(self): # NOQA def setUp(self): # NOQA
self.config_dir = set_tmp_config_dir()
setup_translations() setup_translations()
def tearDown(self): # NOQA def tearDown(self): # NOQA
@ -127,3 +131,14 @@ class CommonTestCase(unittest.TestCase):
for human_size, byte_size in sizes: for human_size, byte_size in sizes:
parsed = parse_human_size(human_size) parsed = parse_human_size(human_size)
self.assertEqual(parsed, byte_size, 'Mismatch when converting: %s' % 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])