atomic_write context to save configs first to temp file, then move
Should prevent corruption of files
This commit is contained in:
parent
8dfb0cadd7
commit
c6d02903fa
3 changed files with 27 additions and 9 deletions
|
|
@ -329,12 +329,14 @@ class PrinterProfileManager(object):
|
||||||
if os.path.exists(path) and not allow_overwrite:
|
if os.path.exists(path) and not allow_overwrite:
|
||||||
raise SaveError("Profile %s already exists and not allowed to overwrite" % profile["id"])
|
raise SaveError("Profile %s already exists and not allowed to overwrite" % profile["id"])
|
||||||
|
|
||||||
|
from octoprint.util import atomic_write
|
||||||
import yaml
|
import yaml
|
||||||
with open(path, "wb") as f:
|
try:
|
||||||
try:
|
with atomic_write(path, "wb") as f:
|
||||||
yaml.safe_dump(profile, f, default_flow_style=False, indent=" ", allow_unicode=True)
|
yaml.safe_dump(profile, f, default_flow_style=False, indent=" ", allow_unicode=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise SaveError("Cannot save profile %s: %s" % (profile["id"], str(e)))
|
self._logger.exception("Error while trying to save profile %s" % profile["id"])
|
||||||
|
raise SaveError("Cannot save profile %s: %s" % (profile["id"], str(e)))
|
||||||
|
|
||||||
def _remove_from_path(self, path):
|
def _remove_from_path(self, path):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -798,11 +798,17 @@ class Settings(object):
|
||||||
if not self._dirty and not force:
|
if not self._dirty and not force:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
with open(self._configfile, "wb") as configFile:
|
from octoprint.util import atomic_write
|
||||||
yaml.safe_dump(self._config, configFile, default_flow_style=False, indent=" ", allow_unicode=True)
|
try:
|
||||||
self._dirty = False
|
with atomic_write(self._configfile, "wb", prefix="octoprint-config-", suffix=".yaml") as configFile:
|
||||||
self.load()
|
yaml.safe_dump(self._config, configFile, default_flow_style=False, indent=" ", allow_unicode=True)
|
||||||
return True
|
self._dirty = False
|
||||||
|
except:
|
||||||
|
self._logger.exception("Error while saving config.yaml!")
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self.load()
|
||||||
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def last_modified(self):
|
def last_modified(self):
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import shutil
|
||||||
import threading
|
import threading
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import warnings
|
import warnings
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -513,6 +514,15 @@ def address_for_client(host, port):
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def atomic_write(filename, mode="w+b", prefix="tmp", suffix=""):
|
||||||
|
temp_config = tempfile.NamedTemporaryFile(mode=mode, prefix=prefix, suffix=suffix, delete=False)
|
||||||
|
yield temp_config
|
||||||
|
temp_config.close()
|
||||||
|
shutil.move(temp_config.name, filename)
|
||||||
|
|
||||||
|
|
||||||
class RepeatedTimer(threading.Thread):
|
class RepeatedTimer(threading.Thread):
|
||||||
"""
|
"""
|
||||||
This class represents an action that should be run repeatedly in an interval. It is similar to python's
|
This class represents an action that should be run repeatedly in an interval. It is similar to python's
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue