mirror of
https://github.com/SickGear/SickGear.git
synced 2024-11-15 01:15:05 +00:00
Add config.ini backup
try to validate saved config.ini try to use backed up config.ini file if saving fails check config.ini copy before compressing it to backup
This commit is contained in:
parent
e7d06c541a
commit
ca6e399ae9
3 changed files with 125 additions and 3 deletions
|
@ -13,7 +13,6 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
|
@ -23,6 +22,7 @@ import os
|
||||||
import re
|
import re
|
||||||
import signal
|
import signal
|
||||||
import socket
|
import socket
|
||||||
|
import time
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
# apparently py2exe won't build these unless they're imported somewhere
|
# apparently py2exe won't build these unless they're imported somewhere
|
||||||
|
@ -54,6 +54,7 @@ from configobj import ConfigObj
|
||||||
from api_trakt import TraktAPI
|
from api_trakt import TraktAPI
|
||||||
|
|
||||||
from _23 import b64encodestring, decode_bytes, scandir
|
from _23 import b64encodestring, decode_bytes, scandir
|
||||||
|
from sg_helpers import remove_file_perm
|
||||||
from six import iteritems, string_types
|
from six import iteritems, string_types
|
||||||
import sg_helpers
|
import sg_helpers
|
||||||
|
|
||||||
|
@ -2423,7 +2424,69 @@ def save_config():
|
||||||
new_config['ANIME'] = {}
|
new_config['ANIME'] = {}
|
||||||
new_config['ANIME']['anime_treat_as_hdtv'] = int(ANIME_TREAT_AS_HDTV)
|
new_config['ANIME']['anime_treat_as_hdtv'] = int(ANIME_TREAT_AS_HDTV)
|
||||||
|
|
||||||
new_config.write()
|
from sg_helpers import copy_file
|
||||||
|
backup_config = re.sub(r'\.ini$', '.bak', CONFIG_FILE)
|
||||||
|
from .config import check_valid_config
|
||||||
|
try:
|
||||||
|
copy_file(CONFIG_FILE, backup_config)
|
||||||
|
if not check_valid_config(backup_config):
|
||||||
|
logger.error('config file seams to be invalid, not backing up.')
|
||||||
|
remove_file_perm(backup_config)
|
||||||
|
backup_config = None
|
||||||
|
except (BaseException, Exception):
|
||||||
|
backup_config = None
|
||||||
|
|
||||||
|
for _ in range(0, 3):
|
||||||
|
new_config.write()
|
||||||
|
if check_valid_config(CONFIG_FILE):
|
||||||
|
return
|
||||||
|
logger.warning('saving config file failed, retrying...')
|
||||||
|
remove_file_perm(CONFIG_FILE)
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
# we only get here if the config saving failed multiple times
|
||||||
|
if None is not backup_config and os.path.isfile(backup_config):
|
||||||
|
logger.error('saving config file failed, using backup file')
|
||||||
|
try:
|
||||||
|
copy_file(backup_config, CONFIG_FILE)
|
||||||
|
logger.log('using old backup config file')
|
||||||
|
return
|
||||||
|
except (BaseException, Exception):
|
||||||
|
logger.error('failed to use backup config file')
|
||||||
|
|
||||||
|
from sg_helpers import scantree
|
||||||
|
try:
|
||||||
|
target_base = os.path.join(BACKUP_DB_PATH or os.path.join(DATA_DIR, 'backup'))
|
||||||
|
file_list = [f for f in scantree(target_base, include='config', filter_kind=False)]
|
||||||
|
if file_list:
|
||||||
|
logger.log('trying to use latest config.ini backup')
|
||||||
|
# sort newest to oldest backup
|
||||||
|
file_list.sort(key=lambda _f: _f.stat(follow_symlinks=False).st_mtime)
|
||||||
|
import zipfile
|
||||||
|
try:
|
||||||
|
with zipfile.ZipFile(file_list[0].path, mode='r') as zf:
|
||||||
|
zf.extractall(target_base)
|
||||||
|
backup_config_file = os.path.join(target_base, 'config.ini')
|
||||||
|
if os.path.isfile(backup_config_file):
|
||||||
|
os.replace(backup_config_file, CONFIG_FILE)
|
||||||
|
if check_valid_config(CONFIG_FILE):
|
||||||
|
logger.log(f'used latest config.ini backup file: {file_list[0].name}')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logger.error(f'failed to use latest config.ini backup file: {file_list[0].name}')
|
||||||
|
remove_file_perm(CONFIG_FILE)
|
||||||
|
except (BaseException, Exception):
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
remove_file_perm(backup_config_file)
|
||||||
|
except (BaseException, Exception):
|
||||||
|
pass
|
||||||
|
logger.error('failed to use latest config.ini')
|
||||||
|
except (BaseException, Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
logger.error('saving config file failed and no backup available')
|
||||||
|
|
||||||
|
|
||||||
def launch_browser(start_port=None):
|
def launch_browser(start_port=None):
|
||||||
|
|
|
@ -24,6 +24,7 @@ from . import db, helpers, logger, naming
|
||||||
from lib.api_trakt import TraktAPI
|
from lib.api_trakt import TraktAPI
|
||||||
|
|
||||||
from _23 import urlsplit, urlunsplit
|
from _23 import urlsplit, urlunsplit
|
||||||
|
from sg_helpers import compress_file, copy_file, remove_file_perm, scantree, try_int
|
||||||
from six import string_types
|
from six import string_types
|
||||||
|
|
||||||
|
|
||||||
|
@ -455,6 +456,58 @@ def check_setting_str(config, cfg_name, item_name, def_val, log=True):
|
||||||
|
|
||||||
return (my_val, def_val)['None' == my_val]
|
return (my_val, def_val)['None' == my_val]
|
||||||
|
|
||||||
|
def check_valid_config(filename):
|
||||||
|
# type: (str) -> bool
|
||||||
|
"""
|
||||||
|
check if file appears to be a vaild config file
|
||||||
|
:param filename: full path config file name
|
||||||
|
"""
|
||||||
|
from configobj import ConfigObj
|
||||||
|
try:
|
||||||
|
conf_obj = ConfigObj(filename)
|
||||||
|
if not (all(section in conf_obj for section in ('General', 'GUI')) and 'config_version' in conf_obj['General']
|
||||||
|
and isinstance(try_int(conf_obj['General']['config_version'], None), int)):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
except (BaseException, Exception):
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
del conf_obj
|
||||||
|
except (BaseException, Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def backup_config():
|
||||||
|
"""
|
||||||
|
backup config.ini
|
||||||
|
"""
|
||||||
|
logger.log('backing up config.ini')
|
||||||
|
try:
|
||||||
|
if not check_valid_config(sickgear.CONFIG_FILE):
|
||||||
|
logger.error('config file seams to be invalid, not backing up.')
|
||||||
|
return
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
d = datetime.datetime.strftime(now, '%Y-%m-%d')
|
||||||
|
t = datetime.datetime.strftime(now, '%H-%M')
|
||||||
|
target_base = os.path.join(sickgear.BACKUP_DB_PATH or os.path.join(sickgear.DATA_DIR, 'backup'))
|
||||||
|
target = os.path.join(target_base, 'config.ini')
|
||||||
|
copy_file(sickgear.CONFIG_FILE, target)
|
||||||
|
if not check_valid_config(target):
|
||||||
|
logger.error('config file seams to be invalid, not backing up.')
|
||||||
|
remove_file_perm(target)
|
||||||
|
return
|
||||||
|
compress_file(target, 'config.ini')
|
||||||
|
os.rename(re.sub(r'\.ini$', '.zip', target), os.path.join(target_base, f'config_{d}_{t}.zip'))
|
||||||
|
# remove old files
|
||||||
|
use_count = (1, sickgear.BACKUP_DB_MAX_COUNT)[not sickgear.BACKUP_DB_ONEDAY]
|
||||||
|
file_list = [f for f in scantree(target_base, include='config', filter_kind=False)]
|
||||||
|
if use_count < len(file_list):
|
||||||
|
file_list.sort(key=lambda _f: _f.stat(follow_symlinks=False).st_mtime, reverse=True)
|
||||||
|
for direntry in file_list[use_count:]:
|
||||||
|
remove_file_perm(direntry.path)
|
||||||
|
except (BaseException, Exception):
|
||||||
|
logger.error('backup config.ini error')
|
||||||
|
|
||||||
|
|
||||||
class ConfigMigrator(object):
|
class ConfigMigrator(object):
|
||||||
def __init__(self, config_obj):
|
def __init__(self, config_obj):
|
||||||
|
@ -926,3 +979,4 @@ class ConfigMigrator(object):
|
||||||
|
|
||||||
def _migrate_v22(self):
|
def _migrate_v22(self):
|
||||||
self.deprecate_anon_service()
|
self.deprecate_anon_service()
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ from exceptions_helper import ex
|
||||||
import sickgear
|
import sickgear
|
||||||
from . import db, logger, network_timezones, properFinder, ui
|
from . import db, logger, network_timezones, properFinder, ui
|
||||||
from .scheduler import Job
|
from .scheduler import Job
|
||||||
|
from .config import backup_config
|
||||||
|
|
||||||
# noinspection PyUnreachableCode
|
# noinspection PyUnreachableCode
|
||||||
if False:
|
if False:
|
||||||
|
@ -70,7 +71,11 @@ class ShowUpdater(Job):
|
||||||
if sickgear.db.db_supports_backup and 0 < sickgear.BACKUP_DB_MAX_COUNT:
|
if sickgear.db.db_supports_backup and 0 < sickgear.BACKUP_DB_MAX_COUNT:
|
||||||
logger.log('backing up all db\'s')
|
logger.log('backing up all db\'s')
|
||||||
try:
|
try:
|
||||||
sickgear.db.backup_all_dbs(sickgear.BACKUP_DB_PATH or os.path.join(sickgear.DATA_DIR, 'backup'))
|
backup_success = sickgear.db.backup_all_dbs(
|
||||||
|
sickgear.BACKUP_DB_PATH or os.path.join(sickgear.DATA_DIR, 'backup'))
|
||||||
|
if isinstance(backup_success, tuple) and backup_success[0]:
|
||||||
|
# backup config.ini
|
||||||
|
backup_config()
|
||||||
except (BaseException, Exception):
|
except (BaseException, Exception):
|
||||||
logger.error('backup db error')
|
logger.error('backup db error')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue