|
@@ -49,11 +49,44 @@ from PyQt5.QtGui import QColor, QIcon
|
|
|
from PyQt5.QtWidgets import QMessageBox
|
|
|
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
|
|
|
|
|
|
+from contextlib import contextmanager
|
|
|
+
|
|
|
import sys
|
|
|
import os.path
|
|
|
import numpy
|
|
|
import copy
|
|
|
import urllib
|
|
|
+import os
|
|
|
+import time
|
|
|
+
|
|
|
+CONFIG_LOCK_FILENAME = "cura.lock"
|
|
|
+
|
|
|
+## Contextmanager to create a lock file and remove it afterwards.
|
|
|
+@contextmanager
|
|
|
+def lockFile(filename):
|
|
|
+ try:
|
|
|
+ with open(filename, 'w') as lock_file:
|
|
|
+ lock_file.write("Lock file - Cura is currently writing")
|
|
|
+ except:
|
|
|
+ Logger.log("e", "Could not create lock file [%s]" % filename)
|
|
|
+ yield
|
|
|
+ try:
|
|
|
+ if os.path.exists(filename):
|
|
|
+ os.remove(filename)
|
|
|
+ except:
|
|
|
+ Logger.log("e", "Could not delete lock file [%s]" % filename)
|
|
|
+
|
|
|
+
|
|
|
+## Wait for a lock file to disappear
|
|
|
+# the maximum allowable age is settable; if the file is too old, it will be ignored too
|
|
|
+def waitFileDisappear(filename, max_age_seconds=10, msg=""):
|
|
|
+ now = time.time()
|
|
|
+ while os.path.exists(filename) and now < os.path.getmtime(filename) + max_age_seconds and now > os.path.getmtime(filename):
|
|
|
+ if msg:
|
|
|
+ Logger.log("d", msg)
|
|
|
+ time.sleep(1)
|
|
|
+ now = time.time()
|
|
|
+
|
|
|
|
|
|
numpy.seterr(all="ignore")
|
|
|
|
|
@@ -201,6 +234,11 @@ class CuraApplication(QtApplication):
|
|
|
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
|
|
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
|
|
|
|
|
+ # Set the filename to create if cura is writing in the config dir.
|
|
|
+ self._config_lock_filename = os.path.join(Resources.getConfigStoragePath(), CONFIG_LOCK_FILENAME)
|
|
|
+ # Lock file check: if (another) Cura is writing in the Config dir, one may not be able to read a
|
|
|
+ # valid set of files. Not entirely fool-proof, but works when you start Cura shortly after shutting down.
|
|
|
+ waitFileDisappear(self._config_lock_filename, max_age_seconds=10, msg="Waiting for Cura to finish writing in the config dir...")
|
|
|
ContainerRegistry.getInstance().load()
|
|
|
|
|
|
Preferences.getInstance().addPreference("cura/active_mode", "simple")
|
|
@@ -308,38 +346,41 @@ class CuraApplication(QtApplication):
|
|
|
if not self._started: # Do not do saving during application start
|
|
|
return
|
|
|
|
|
|
- for instance in ContainerRegistry.getInstance().findInstanceContainers():
|
|
|
- if not instance.isDirty():
|
|
|
- continue
|
|
|
-
|
|
|
- try:
|
|
|
- data = instance.serialize()
|
|
|
- except NotImplementedError:
|
|
|
- continue
|
|
|
- except Exception:
|
|
|
- Logger.logException("e", "An exception occurred when serializing container %s", instance.getId())
|
|
|
- continue
|
|
|
-
|
|
|
- mime_type = ContainerRegistry.getMimeTypeForContainer(type(instance))
|
|
|
- file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix
|
|
|
- instance_type = instance.getMetaDataEntry("type")
|
|
|
- path = None
|
|
|
- if instance_type == "material":
|
|
|
- path = Resources.getStoragePath(self.ResourceTypes.MaterialInstanceContainer, file_name)
|
|
|
- elif instance_type == "quality" or instance_type == "quality_changes":
|
|
|
- path = Resources.getStoragePath(self.ResourceTypes.QualityInstanceContainer, file_name)
|
|
|
- elif instance_type == "user":
|
|
|
- path = Resources.getStoragePath(self.ResourceTypes.UserInstanceContainer, file_name)
|
|
|
- elif instance_type == "variant":
|
|
|
- path = Resources.getStoragePath(self.ResourceTypes.VariantInstanceContainer, file_name)
|
|
|
-
|
|
|
- if path:
|
|
|
- instance.setPath(path)
|
|
|
- with SaveFile(path, "wt", -1, "utf-8") as f:
|
|
|
- f.write(data)
|
|
|
-
|
|
|
- for stack in ContainerRegistry.getInstance().findContainerStacks():
|
|
|
- self.saveStack(stack)
|
|
|
+ # When starting Cura, we check for the lockFile which is created and deleted here
|
|
|
+ with lockFile(self._config_lock_filename):
|
|
|
+
|
|
|
+ for instance in ContainerRegistry.getInstance().findInstanceContainers():
|
|
|
+ if not instance.isDirty():
|
|
|
+ continue
|
|
|
+
|
|
|
+ try:
|
|
|
+ data = instance.serialize()
|
|
|
+ except NotImplementedError:
|
|
|
+ continue
|
|
|
+ except Exception:
|
|
|
+ Logger.logException("e", "An exception occurred when serializing container %s", instance.getId())
|
|
|
+ continue
|
|
|
+
|
|
|
+ mime_type = ContainerRegistry.getMimeTypeForContainer(type(instance))
|
|
|
+ file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix
|
|
|
+ instance_type = instance.getMetaDataEntry("type")
|
|
|
+ path = None
|
|
|
+ if instance_type == "material":
|
|
|
+ path = Resources.getStoragePath(self.ResourceTypes.MaterialInstanceContainer, file_name)
|
|
|
+ elif instance_type == "quality" or instance_type == "quality_changes":
|
|
|
+ path = Resources.getStoragePath(self.ResourceTypes.QualityInstanceContainer, file_name)
|
|
|
+ elif instance_type == "user":
|
|
|
+ path = Resources.getStoragePath(self.ResourceTypes.UserInstanceContainer, file_name)
|
|
|
+ elif instance_type == "variant":
|
|
|
+ path = Resources.getStoragePath(self.ResourceTypes.VariantInstanceContainer, file_name)
|
|
|
+
|
|
|
+ if path:
|
|
|
+ instance.setPath(path)
|
|
|
+ with SaveFile(path, "wt", -1, "utf-8") as f:
|
|
|
+ f.write(data)
|
|
|
+
|
|
|
+ for stack in ContainerRegistry.getInstance().findContainerStacks():
|
|
|
+ self.saveStack(stack)
|
|
|
|
|
|
def saveStack(self, stack):
|
|
|
if not stack.isDirty():
|