Made metadata saving for gcode files more error resilient (hopefully that is)

This commit is contained in:
Gina Häußge 2013-11-15 20:54:13 +01:00
parent 895d077d85
commit 4d2213544e
2 changed files with 55 additions and 3 deletions

View file

@ -70,6 +70,7 @@ class GcodeManager:
self._metadata = {}
self._metadataDirty = False
self._metadataFile = os.path.join(self._uploadFolder, "metadata.yaml")
self._metadataTempFile = os.path.join(self._uploadFolder, "metadata.yaml.tmp")
self._metadataFileAccessMutex = threading.Lock()
self._metadataAnalyzer = MetadataAnalyzer(getPathCallback=self.getAbsolutePath, loadedCallback=self._onMetadataAnalysisFinished)
@ -111,7 +112,7 @@ class GcodeManager:
if gcode.extrusionAmount:
analysisResult["filament"] = "%.2fm" % (gcode.extrusionAmount / 1000)
if gcode.calculateVolumeCm3():
analysisResult["filament"] += " / %.2fcm³" % gcode.calculateVolumeCm3()
analysisResult["filament"] += " / %.2fcm³" % gcode.calculateVolumeCm3()
dirty = True
if dirty:
@ -134,9 +135,11 @@ class GcodeManager:
return
with self._metadataFileAccessMutex:
with open(self._metadataFile, "wb") as f:
with open(self._metadataTempFile, "wb") as f:
yaml.safe_dump(self._metadata, f, default_flow_style=False, indent=" ", allow_unicode=True)
self._metadataDirty = False
util.safeRename(self._metadataTempFile, self._metadataFile)
self._loadMetadata()
self._sendUpdateTrigger("gcodeFiles")
@ -326,7 +329,7 @@ class GcodeManager:
if key == "prints":
val = self._metadata[filename][key]
formattedLast = None
if val["last"] is not None:
if "last" in val and val["last"] is not None:
formattedLast = {
"date": util.getFormattedDateTime(datetime.datetime.fromtimestamp(val["last"]["date"])),
"success": val["last"]["success"]

View file

@ -7,6 +7,7 @@ import traceback
import sys
import time
import re
import tempfile
from octoprint.settings import settings
@ -139,3 +140,51 @@ def findCollisionfreeName(input, extension, existingFilenames):
power += 1
raise ValueError("Can't create a collision free filename")
def safeRename(old, new):
"""
Safely renames a file.
On Windows this is achieved by first creating a backup file of the new file (if it
already exists), thus moving it, then renaming the old into the new file and finally removing the backup. If
anything goes wrong during those steps, the backup (if already there) will be renamed to its old name and thus
the operation hopefully result in a no-op.
On other operating systems the atomic os.rename function will be used instead.
@param old the path to the old file to be renamed
@param new the path to the new file to be created/replaced
"""
if sys.platform == "win32":
fh, backup = tempfile.mkstemp()
os.close(fh)
try:
if os.path.exists(new):
silentRemove(backup)
os.rename(new, backup)
os.rename(old, new)
os.remove(backup)
except OSError:
# if anything went wrong, try to rename the backup file to its original name
if os.path.exists(backup):
os.remove(new)
os.rename(backup, new)
else:
# on anything else than windows it's ooooh so much easier...
os.rename(old, new)
def silentRemove(file):
"""
Silently removes a file. Does not raise an error if the file doesn't exist.
@param file the path of the file to be removed
"""
try:
os.remove(file)
except OSError:
pass