Browse Source

Added lock file writing and checking. CURA-2449

Jack Ha 8 years ago
parent
commit
8b0d6e974a
1 changed files with 73 additions and 32 deletions
  1. 73 32
      cura/CuraApplication.py

+ 73 - 32
cura/CuraApplication.py

@@ -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():