mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-28 08:03:36 +00:00
This is recommended by PEP-0597: https://peps.python.org/pep-0597/ Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""
|
|
Utilities for editing configuration files of Deluge.
|
|
"""
|
|
|
|
import copy
|
|
import json
|
|
import os
|
|
import pathlib
|
|
import re
|
|
import shutil
|
|
import tempfile
|
|
|
|
_JSON_FORMAT = {'indent': 4, 'sort_keys': True, 'ensure_ascii': False}
|
|
|
|
|
|
class Config:
|
|
"""Read or edit a Deluge configuration file."""
|
|
|
|
def __init__(self, file_name):
|
|
"""Initialize the configuration object."""
|
|
self.file_name = file_name
|
|
self.file = pathlib.Path(self.file_name)
|
|
self._version = None
|
|
self.content = None
|
|
self._original_content = None
|
|
|
|
def load(self):
|
|
"""Parse the configuration file into memory."""
|
|
text = self.file.read_text(encoding='utf-8')
|
|
matches = re.match(r'^({[^}]*})(.*)$', text, re.DOTALL)
|
|
if not matches:
|
|
raise Exception('Unexpected file format.')
|
|
|
|
try:
|
|
self._version = json.loads(matches.group(1))
|
|
self.content = json.loads(matches.group(2))
|
|
except json.decoder.JSONDecodeError:
|
|
raise Exception('Unable to parse JSON in file.')
|
|
|
|
if self._version['format'] != 1:
|
|
raise Exception('Version of the config file not understood')
|
|
|
|
self._original_content = copy.deepcopy(self.content)
|
|
|
|
def save(self):
|
|
"""Atomically save the modified configuration to file."""
|
|
if self.content == self._original_content:
|
|
return
|
|
|
|
with tempfile.NamedTemporaryFile(dir=self.file.parent,
|
|
delete=False) as new_file:
|
|
new_file.write(json.dumps(self._version, **_JSON_FORMAT).encode())
|
|
new_file.write(json.dumps(self.content, **_JSON_FORMAT).encode())
|
|
new_file.flush()
|
|
os.fsync(new_file.fileno())
|
|
|
|
new_file_path = pathlib.Path(new_file.name)
|
|
new_file_path.chmod(0o600)
|
|
try:
|
|
shutil.chown(str(new_file_path), 'debian-deluged',
|
|
'debian-deluged')
|
|
except (PermissionError, LookupError):
|
|
pass # Not running as root, or deluge is not installed
|
|
|
|
new_file_path.rename(self.file)
|
|
|
|
def __enter__(self):
|
|
"""Enter the context."""
|
|
self.load()
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
"""Exit the context."""
|
|
self.save()
|