r23291 - gnucash/trunk/src - Prefs migration improvements

Geert Janssens gjanssens at code.gnucash.org
Wed Oct 16 11:22:06 EDT 2013


Author: gjanssens
Date: 2013-10-16 11:22:04 -0400 (Wed, 16 Oct 2013)
New Revision: 23291
Trac: http://svn.gnucash.org/trac/changeset/23291

Modified:
   gnucash/trunk/src/app-utils/gnc-gsettings.c
   gnucash/trunk/src/app-utils/make-prefs-migration-script.xsl
   gnucash/trunk/src/app-utils/migrate-prefs.scm
   gnucash/trunk/src/gnome/gschemas/org.gnucash.gschema.xml.in
Log:
Prefs migration improvements

- check if all parents of .gconf/apps/gnucash exist before attempting migration
- wrap guile parts in catch/throw handlers to prevent GnuCash from crashing
  if something goes wrong during the prefereces migration
- add more sanity checks and debugging information
- set flag after first successful migration to prevent future runs

Modified: gnucash/trunk/src/app-utils/gnc-gsettings.c
===================================================================
--- gnucash/trunk/src/app-utils/gnc-gsettings.c	2013-10-13 17:11:39 UTC (rev 23290)
+++ gnucash/trunk/src/app-utils/gnc-gsettings.c	2013-10-16 15:22:04 UTC (rev 23291)
@@ -47,12 +47,14 @@
 #define CLIENT_TAG  "%s-%s-client"
 #define NOTIFY_TAG  "%s-%s-notify_id"
 
+#define GNC_PREF_MIGRATE_PREFS_DONE "migrate-prefs-done"
+
 static GHashTable *schema_hash = NULL;
 static const gchar *gsettings_prefix;
 static xmlExternalEntityLoader defaultEntityLoader = NULL;
 
 /* This static indicates the debugging module that this .o belongs to.  */
-static QofLogModule log_module = G_LOG_DOMAIN;
+static QofLogModule log_module = "gnc.app-utils.gsettings";
 
 /************************************************************/
 /*               Internal helper functions                  */
@@ -615,26 +617,43 @@
     return(NULL);
 }
 
-
+/* Tool to migrate existing user settings from GConf to GSettings
+ *
+ * This tool will first run some sanity checks to see if migration
+ * is necessary/possible. The actual migration works directly from
+ * the GConf .xml files. Using an xsl transform it will convert them
+ * in a guile script to set most settings found.
+ *
+ * Notes:
+ * - due to some limitations in the xslt code, all the gconf xml files are
+ *   first copied into a temporary directory. After the migration has finished,
+ *   that temporary directory and its contents are removed.
+ * - not all settings can be migrated. All the important ones are though.
+ *   The ones that are missing are mostly with respect to window position
+ *   and size.
+ * - column widths/visibilities, sorting orders,... are no longer stored
+ *   in gsettings, so these will obviously not be migrated either.
+ * - upon a successful run, a flag will be set to prevent the migration
+ *   from running again. So in normal circumstances the migration will
+ *   be executed only once.
+ */
 void gnc_gsettings_migrate_from_gconf (void)
 {
     gchar *pkgdatadir, *stylesheet, *input, *output, *command;
+    gchar *gconf_root, *gconf_apps, *gconf_gnucash;
     gchar *base_dir, *iter;
     SCM migr_script, result;
     xsltStylesheetPtr stylesheetptr = NULL;
     xmlDocPtr inputxml, transformedxml;
     FILE *outfile;
+    gboolean migration_ok = FALSE;
 
-    pkgdatadir = gnc_path_get_pkgdatadir();
-    stylesheet = g_build_filename(pkgdatadir, "make-prefs-migration-script.xsl", NULL);
-    input      = g_build_filename(pkgdatadir, "migratable-prefs.xml", NULL);
+    ENTER ();
 
-    if ((!g_file_test (stylesheet, G_FILE_TEST_IS_REGULAR)) ||
-        (!g_file_test (input, G_FILE_TEST_IS_REGULAR)))
+    /* Only attempt to migrate if no successful migration has been done before */
+    if (gnc_gsettings_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_MIGRATE_PREFS_DONE))
     {
-        /* Critical files not found, abort migration */
-        g_free (stylesheet);
-        g_free (input);
+        LEAVE ("Preferences migration ran successfully before. Skipping.");
         return;
     }
 
@@ -645,13 +664,59 @@
             *iter = '/';
     }
 
+    /* Only attempt to migrate if there is something to migrate */
+    gconf_root    = g_build_filename(base_dir, ".gconf", NULL);
+    gconf_apps    = g_build_filename(gconf_root, "apps", NULL);
+    gconf_gnucash = g_build_filename(gconf_apps, "gnucash", NULL);
+    migration_ok = (g_file_test (gconf_root, G_FILE_TEST_IS_DIR) &&
+                    g_file_test (gconf_apps, G_FILE_TEST_IS_DIR) &&
+                    g_file_test (gconf_gnucash, G_FILE_TEST_IS_DIR));
+    g_free (gconf_root);
+    g_free (gconf_apps);
+    g_free (gconf_gnucash);
+    if (!migration_ok)
+    {
+        g_free (base_dir);
+        gnc_gsettings_set_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_MIGRATE_PREFS_DONE, TRUE);
+        LEAVE ("No pre-existing GConf gnucash section found.\n"
+               "Most likely this system never ran GnuCash before.\n"
+               "Assume migration is not needed.");
+        return;
+    }
+
+    pkgdatadir = gnc_path_get_pkgdatadir();
+    stylesheet = g_build_filename(pkgdatadir, "make-prefs-migration-script.xsl", NULL);
+    input      = g_build_filename(pkgdatadir, "migratable-prefs.xml", NULL);
+    g_free (pkgdatadir);
+
+    migration_ok = (g_file_test (stylesheet, G_FILE_TEST_IS_REGULAR) &&
+                    g_file_test (input, G_FILE_TEST_IS_REGULAR));
+    if (!migration_ok)
+    {
+        /* Critical files not found, abort migration */
+        g_free (base_dir);
+        g_free (stylesheet);
+        g_free (input);
+        LEAVE ("Migration input file and stylesheet missing. Skip migration.");
+        return;
+    }
+
     command = g_strconcat ("(use-modules (migrate-prefs))(migration-prepare \"",
                              base_dir, "\")", NULL);
     DEBUG ("command = %s", command);
-    result = scm_c_eval_string (command);
+    migration_ok = scm_is_true (scm_c_eval_string (command));
     g_free (command);
+    if (!migration_ok)
+    {
+        /* Preparation step failed */
+        g_free (base_dir);
+        g_free (stylesheet);
+        g_free (input);
+        LEAVE ("Migration preparation step failed. Skip migration.");
+        return;
+    }
 
-    output     = g_build_filename(base_dir, ".gnc-migration-tmp", "migrate-prefs-user.scm", NULL);
+    output  = g_build_filename(base_dir, ".gnc-migration-tmp", "migrate-prefs-user.scm", NULL);
     xmlSubstituteEntitiesDefault(1);
     xmlLoadExtDtdDefaultValue = 1;
     defaultEntityLoader = xmlGetExternalEntityLoader();
@@ -664,27 +729,46 @@
     xsltSaveResultToFile(outfile, transformedxml, stylesheetptr);
     fclose(outfile);
 
-    migr_script = scm_from_locale_string (output);
-    scm_primitive_load (migr_script);
-    result = scm_c_eval_string ("(use-modules (migrate-prefs-user))(run-migration)");
-
     xsltFreeStylesheet(stylesheetptr);
     xmlFreeDoc(inputxml);
     xmlFreeDoc(transformedxml);
 
     xsltCleanupGlobals();
     xmlCleanupParser();
+    g_free (stylesheet);
+    g_free (input);
 
+    migr_script = scm_from_locale_string (output);
+    scm_primitive_load (migr_script);
+    g_free (output);
+
+    migration_ok = scm_is_true (scm_c_eval_string ("(use-modules (migrate-prefs-user))(run-migration)"));
+    if (!migration_ok)
+    {
+        /* Actual migration step failed */
+        g_free (base_dir);
+        LEAVE ("Actual migration step failed. Skip migration.");
+        return;
+    }
+
+    /* If we got here, the preferences were migrated successfully
+     * Mark this success in gsettings, so we won't run the migration again.
+     */
+    gnc_gsettings_set_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_MIGRATE_PREFS_DONE, TRUE);
+
+    /* All that is left now is to cleanup... */
     command = g_strconcat ("(use-modules (migrate-prefs))(migration-cleanup \"",
                              base_dir, "\")", NULL);
     DEBUG ("command = %s", command);
-    result = scm_c_eval_string (command);
+    migration_ok = scm_is_true (scm_c_eval_string (command));
     g_free (command);
+    if (!migration_ok)
+    {
+        /* Actual migration step failed */
+        DEBUG ("Cleanup step failed. You may need to delete %s/.gnc-migration-tmp manually.", base_dir);
+    }
 
-    g_free (pkgdatadir);
-    g_free (stylesheet);
-    g_free (input);
-    g_free (output);
+    LEAVE ("");
     g_free (base_dir);
 
 }

Modified: gnucash/trunk/src/app-utils/make-prefs-migration-script.xsl
===================================================================
--- gnucash/trunk/src/app-utils/make-prefs-migration-script.xsl	2013-10-13 17:11:39 UTC (rev 23290)
+++ gnucash/trunk/src/app-utils/make-prefs-migration-script.xsl	2013-10-16 15:22:04 UTC (rev 23291)
@@ -34,7 +34,7 @@
 ;    (load-extension "libgnc-core-utils" "scm_init_sw_core_utils_module")))
 ;(use-modules (sw_core_utils))
 
-(define (run-migration)
+(define (run-migration-internal)
  <xsl:for-each select="//prefsgroup">
   <xsl:if test="document(gconfpath)//entry">
 ;; Processing preferences in group <xsl:value-of select="gschemaid"/>
@@ -47,6 +47,17 @@
 (display "Preference migration has finished")(newline)
 )
 
+(define (run-migration)
+  (catch #t
+    run-migration-internal
+    (lambda args 
+        (display (string-append
+                   "An error occurred while migrating preferences."
+                   (newline) "The error is: "
+                   (symbol->string key) " - "  (car (caddr args))  "."))
+        #f))
+)
+
 (export run-migration)
 </xsl:template>
 

Modified: gnucash/trunk/src/app-utils/migrate-prefs.scm
===================================================================
--- gnucash/trunk/src/app-utils/migrate-prefs.scm	2013-10-13 17:11:39 UTC (rev 23290)
+++ gnucash/trunk/src/app-utils/migrate-prefs.scm	2013-10-16 15:22:04 UTC (rev 23291)
@@ -66,27 +66,33 @@
 ; cleanup first if a previous migration attempt failed to do so
   (if (access? migration-dir (logior R_OK W_OK X_OK))
       (begin
-        (format #t "Clear previous tmp dir ~A\n" migration-dir)
+        (format #t "Clear previous migration tmp dir ~A\n" migration-dir)
         (migration-cleanup-internal)))
+  (display "*** GnuCash switched to a new preferences system ***\n")
+  (display "Attempt to migrate your preferences from the old to the new system\n")
   (mkdir migration-dir)
   (format #t "Copy all gconf files to tmp dir ~A\n" migration-dir)
   (display "Note: you can ignore the failed to load extnral entity warnings below. They are harmless.\n")
   (apply find copy-one-file (list gconf-dir))
+  ; Indicate successful preparation
+  #t
 )
 
 (define (migration-prepare base-dir)
   (set! gconf-dir (string-append base-dir "/.gconf/apps/gnucash"))
+  ; Note: calling script should already have checked whether 
+  ;       gconf-dir and its parent directories exist
   (set! prefix-length (+ (string-length gconf-dir) 1))
   (set! migration-dir (string-append base-dir "/.gnc-migration-tmp"))
-  (if (access? gconf-dir R_OK)
-    (begin
-      (display "*** GnuCash switched to a new preferences system ***\n")
-      (display "Attempt to migrate your preferences from the old to the new system\n")
-        (catch #t
-          migration-prepare-internal
-          (lambda args 
-                  (display "An error occurred when trying to migrate preferences")))
-    )))
+  (catch #t
+    migration-prepare-internal
+    (lambda args 
+            (display (string-append
+                       "An error occurred while preparing to migrate preferences."
+                       (newline) "The error is: "
+                       (symbol->string key) " - "  (car (caddr args))  "."))
+            #f))
+)
 
 (define (rmtree args)
   (define (zap f)
@@ -99,13 +105,23 @@
 
 (define (migration-cleanup-internal)
   (rmtree (list migration-dir))
-  (rmdir migration-dir))
+  (rmdir migration-dir)
+  ; Indicate successful cleanup
+  #t)
 
 (define (migration-cleanup base-dir)
   (set! migration-dir (string-append base-dir "/.gnc-migration-tmp"))
   (if (access? migration-dir (logior R_OK W_OK X_OK))
     (begin
       (format #t "Delete tmp dir ~A\n" migration-dir)
-      (migration-cleanup-internal))))
+      (catch #t
+        migration-cleanup-internal
+        (lambda args 
+            (display (string-append
+                       "An error occurred while cleaning up after preferences migration."
+                       (newline) "The error is: "
+                       (symbol->string key) " - "  (car (caddr args))  "."))
+            #f))))
+)
 
 (export migration-prepare migration-cleanup)
\ No newline at end of file

Modified: gnucash/trunk/src/gnome/gschemas/org.gnucash.gschema.xml.in
===================================================================
--- gnucash/trunk/src/gnome/gschemas/org.gnucash.gschema.xml.in	2013-10-13 17:11:39 UTC (rev 23290)
+++ gnucash/trunk/src/gnome/gschemas/org.gnucash.gschema.xml.in	2013-10-16 15:22:04 UTC (rev 23291)
@@ -3,6 +3,7 @@
     <child name="general" schema="org.gnucash.general"/>
     <child name="dev" schema="org.gnucash.dev"/>
   </schema>
+
   <schema id="org.gnucash.general" path="/org/gnucash/general/">
     <key name="save-window-geometry" type="b">
       <default>true</default>
@@ -44,6 +45,11 @@
       <summary>Number of automatic decimal places</summary>
       <description>This field specifies the number of automatic decimal places that will be filled in.</description>
     </key>
+    <key name="migrate-prefs-done" type="b">
+      <default>false</default>
+      <summary>Tool to migrate preferences from old backend (CGonf) to new one (GSettings) has run successfully.</summary>
+      <description>GnuCash switched to another backend to store user preferences between 2.4 and 2.6. To smooth the transition, most preferences will be migrated the first time a 2.6 version of GnuCash is run. This migration should only run once. This preference keeps track whether or not this migration tool has run successfully.</description>
+    </key>
     <key name="retain-type-never" type="b">
       <default>false</default>
       <summary>Do not create log/backup files.</summary>



More information about the gnucash-changes mailing list