[utils/lfs] Use custom configparser wrapper

The main reason is to prevent user configs from being overwritten
and also to only actually write the config file if it has been
modified from within Legendary itself.

Closes #279
This commit is contained in:
derrod 2021-05-30 18:57:23 +02:00
parent 7ae4eda5b8
commit 0e6b63d1a2
2 changed files with 51 additions and 3 deletions

View file

@ -2,12 +2,12 @@
import json
import os
import configparser
import logging
from pathlib import Path
from legendary.models.game import *
from legendary.utils.config import LGDConf
from legendary.utils.lfs import clean_filename
@ -29,7 +29,7 @@ class LGDLFS:
# EGS metadata
self._game_metadata = dict()
# Config with game specific settings (e.g. start parameters, env variables)
self.config = configparser.ConfigParser(comment_prefixes='/', allow_no_value=True)
self.config = LGDConf(comment_prefixes='/', allow_no_value=True)
self.config.optionxform = str
# ensure folders exist.
@ -65,7 +65,14 @@ class LGDLFS:
f'{e!r}, please remove manually')
# try loading config
self.config.read(os.path.join(self.path, 'config.ini'))
try:
self.config.read(os.path.join(self.path, 'config.ini'))
except Exception as e:
self.log.error(f'Unable to read configuration file, please ensure that file is valid! '
f'(Error: {repr(e)})')
self.log.warning(f'Continuing with blank config in safe-mode...')
self.config.read_only = True
# make sure "Legendary" section exists
if 'Legendary' not in self.config:
self.config['Legendary'] = dict()
@ -261,6 +268,16 @@ class LGDLFS:
return [InstalledGame.from_json(i) for i in self._installed.values()]
def save_config(self):
# do not save if in read-only mode or file hasn't changed
if self.config.read_only or not self.config.modified:
return
# if config file has been modified externally, back-up the user-modified version before writing
if (modtime := int(os.stat(os.path.join(self.path, 'config.ini')).st_mtime)) != self.config.modtime:
new_filename = f'config.{modtime}.ini'
self.log.warning(f'Configuration file has been modified while legendary was running, '
f'user-modified config will be renamed to "{new_filename}"...')
os.rename(os.path.join(self.path, 'config.ini'), os.path.join(self.path, new_filename))
with open(os.path.join(self.path, 'config.ini'), 'w') as cf:
self.config.write(cf)

31
legendary/utils/config.py Normal file
View file

@ -0,0 +1,31 @@
import configparser
import os
class LGDConf(configparser.ConfigParser):
def __init__(self, *args, **kwargs):
self.modified = False
self.read_only = False
self.modtime = None
super().__init__(*args, **kwargs)
def read(self, filename):
# if config file exists, save modification time
if os.path.exists(filename):
self.modtime = int(os.stat(filename).st_mtime)
return super().read(filename)
def set(self, *args, **kwargs):
if self.read_only:
return
self.modified = True
super().set(*args, **kwargs)
def __setitem__(self, key, value):
if self.read_only:
return
self.modified = True
super().__setitem__(key, value)