← Back to team overview

gtg team mailing list archive

[Merge] lp:~izidor/gtg/pickle_backups into lp:gtg

 

Izidor Matušov has proposed merging lp:~izidor/gtg/pickle_backups into lp:gtg.

Requested reviews:
  Gtg developers (gtg)
Related bugs:
  Bug #1036554 in Getting Things GNOME!: "Backup and restore pickle files"
  https://bugs.launchpad.net/gtg/+bug/1036554

For more details, see:
https://code.launchpad.net/~izidor/gtg/pickle_backups/+merge/119734

Backup pickle files for synchronization services and then restore them when something goes wrong.
-- 
https://code.launchpad.net/~izidor/gtg/pickle_backups/+merge/119734
Your team Gtg developers is requested to review the proposed merge of lp:~izidor/gtg/pickle_backups into lp:gtg.
=== modified file 'CHANGELOG'
--- CHANGELOG	2012-08-14 07:08:45 +0000
+++ CHANGELOG	2012-08-15 15:29:33 +0000
@@ -48,6 +48,7 @@
     * Fix for bug #1027844: Fuzzy date shouldn't become start date
     * Save backups into backup/ folder, creates backups of tags.xml closes #993920
     * Search filter is deleted on empty search if tag_pane is closed, by Stefan Handschuh, closes #996236
+    * Pickle files for synchronization services are backuped to prevent loosing files, closes #1036554
 
 2012-02-13 Getting Things GNOME! 0.2.9
     * Big refractorization of code, now using liblarch

=== modified file 'GTG/backends/genericbackend.py'
--- GTG/backends/genericbackend.py	2012-07-24 15:09:38 +0000
+++ GTG/backends/genericbackend.py	2012-08-15 15:29:33 +0000
@@ -35,6 +35,8 @@
 from GTG.tools.logger            import Log
 from GTG.tools.interruptible     import _cancellation_point
 
+PICKLE_BACKUP_NBR = 2
+
 
 class GenericBackend(object):
     '''
@@ -543,6 +545,24 @@
         except OSError, exception:
             if exception.errno != errno.EEXIST: 
                 raise
+
+        # Shift backups
+        for i in range(PICKLE_BACKUP_NBR, 1, -1):
+            destination = "%s.bak.%d" % (path, i)
+            source = "%s.bak.%d" % (path, i-1)
+
+            if os.path.exists(destination):
+                os.unlink(destination)
+
+            if os.path.exists(source):
+                os.rename(source, destination)
+
+        # Backup main file
+        if PICKLE_BACKUP_NBR > 0:
+            destination = "%s.bak.1" % path
+            if os.path.exists(path):
+                os.rename(path, destination)
+
         #saving
         with open(path, 'wb') as file:
                 pickle.dump(data, file)
@@ -559,13 +579,32 @@
         path = os.path.join(CoreConfig().get_data_dir(), path)
         if not os.path.exists(path):
             return default_value
-        else:
-            with open(path, 'r') as file:
-                try:
-                    return pickle.load(file)
-                except pickle.PickleError:
-                    Log.error("PICKLE ERROR")
-                    return default_value
+
+        with open(path, 'r') as file:
+            try:
+                return pickle.load(file)
+            except Exception:
+                Log.error("Pickle file for backend '%s' is damaged" % \
+                    self.get_name())
+
+        # Loading file failed, trying backups
+        for i in range(1, PICKLE_BACKUP_NBR+1):
+            backup_file = "%s.bak.%d" % (path, i)
+            if os.path.exists(backup_file):
+                with open(backup_file, 'r') as file:
+                    try:
+                        data = pickle.load(file)
+                        Log.info("Succesfully restored backup #%d for '%s'" % \
+                            (i, self.get_name()))
+                    except Exception:
+                        Log.error("Backup #%d for '%s' is damaged as well" % \
+                            (i, self.get_name()))
+
+        # Data could not be loaded, degrade to default data
+        Log.error("There is no suitable backup for '%s', " \
+            "loading default data" % self.get_name())
+        return default_value
+
 
     def _gtg_task_is_syncable_per_attached_tags(self, task):
         '''