summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2010-06-08 08:58:10 -0400
committerMatthew Barnes <mbarnes@redhat.com>2010-07-27 09:02:30 -0400
commitb44a797f95532c4da253b50b7cfc79e5c3b455ec (patch)
treeb10c8c2e5549df48fd0ad3458b240c99bd98bf26
parent2f00a805a78bb80729c5f7c801e31facc9123611 (diff)
downloadevolution-data-server-b44a797f95532c4da253b50b7cfc79e5c3b455ec.tar.gz
Add a migration routine to EDataCalFactory.
Migration runs just before the main loop starts. It's just a sequence of local directory renames. ~/.evolution/cache/calendar --> $XDG_CACHE_HOME/evolution/calendar ~/.evolution/cache/memos --> $XDG_CACHE_HOME/evolution/memos ~/.evolution/cache/tasks --> $XDG_CACHE_HOME/evolution/tasks ~/.evolution/calendar/local --> $XDG_DATA_HOME/evolution/calendar ~/.evolution/memos/local --> $XDG_DATA_HOME/evolution/memos ~/.evolution/tasks/local --> $XDG_DATA_HOME/evolution/tasks We also migrate Evolution-Exchange account storage: ~/.evolution/exchange --> $XDG_DATA_HOME/evolution/exchange (After first cleaning up Exchange attachment cache directories.)
-rw-r--r--calendar/libedata-cal/Makefile.am1
-rw-r--r--calendar/libedata-cal/e-data-cal-factory.c6
-rw-r--r--calendar/libedata-cal/e-data-cal-migrate.c353
3 files changed, 360 insertions, 0 deletions
diff --git a/calendar/libedata-cal/Makefile.am b/calendar/libedata-cal/Makefile.am
index c32c6812f..ef5f90426 100644
--- a/calendar/libedata-cal/Makefile.am
+++ b/calendar/libedata-cal/Makefile.am
@@ -98,6 +98,7 @@ factory_PROGRAMS = e-calendar-factory
e_calendar_factory_SOURCES = \
e-data-cal-factory.c \
e-data-cal-factory.h \
+ e-data-cal-migrate.c \
e-cal-backend-loader-factory.c \
e-cal-backend-loader-factory.h
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index a69cf3829..cd3e20a7d 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -91,6 +91,9 @@ struct _EDataCalFactoryPrivate {
guint exit_timeout;
};
+/* Forward Declarations */
+void e_data_cal_migrate (void);
+
/* Create the EDataCalFactory error quark */
GQuark
e_data_cal_factory_error_quark (void)
@@ -846,6 +849,9 @@ main (gint argc, gchar **argv)
printf ("Server is up and running...\n");
+ /* Migrate user data from ~/.evolution to XDG base directories. */
+ e_data_cal_migrate ();
+
g_main_loop_run (loop);
dbus_g_connection_unref (connection);
diff --git a/calendar/libedata-cal/e-data-cal-migrate.c b/calendar/libedata-cal/e-data-cal-migrate.c
new file mode 100644
index 000000000..5fce9ee41
--- /dev/null
+++ b/calendar/libedata-cal/e-data-cal-migrate.c
@@ -0,0 +1,353 @@
+/*
+ * e-data-cal-migrate.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <errno.h>
+#include <glib/gstdio.h>
+#include <libedataserver/e-data-server-util.h>
+
+void e_data_cal_migrate (void);
+
+static gboolean
+data_cal_migrate_rename (const gchar *old_filename,
+ const gchar *new_filename)
+{
+ gboolean success = TRUE;
+
+ if (g_file_test (old_filename, G_FILE_TEST_IS_DIR)) {
+ g_print (" mv %s %s\n", old_filename, new_filename);
+ if (g_rename (old_filename, new_filename) < 0) {
+ g_printerr (" FAILED: %s\n", g_strerror (errno));
+ success = FALSE;
+ }
+ }
+
+ return success;
+}
+
+static gboolean
+data_cal_migrate_rmdir (const gchar *dirname)
+{
+ gboolean success = TRUE;
+
+ if (g_file_test (dirname, G_FILE_TEST_IS_DIR)) {
+ g_print (" rmdir %s\n", dirname);
+ if (g_rmdir (dirname) < 0) {
+ g_printerr (" FAILED: %s\n", g_strerror (errno));
+ success = FALSE;
+ }
+ }
+
+ return success;
+}
+
+static void
+data_cal_migrate_process_corrections (GHashTable *corrections)
+{
+ GHashTableIter iter;
+ gpointer old_filename;
+ gpointer new_filename;
+
+ g_hash_table_iter_init (&iter, corrections);
+
+ while (g_hash_table_iter_next (&iter, &old_filename, &new_filename)) {
+ data_cal_migrate_rename (old_filename, new_filename);
+ g_hash_table_iter_remove (&iter);
+ }
+}
+
+static gboolean
+data_cal_migrate_move_contents (const gchar *src_directory,
+ const gchar *dst_directory)
+{
+ GDir *dir;
+ GHashTable *corrections;
+ const gchar *basename;
+
+ dir = g_dir_open (src_directory, 0, NULL);
+ if (dir == NULL)
+ return FALSE;
+
+ /* This is to avoid renaming files while we're iterating over the
+ * directory. POSIX says the outcome of that is unspecified. */
+ corrections = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ g_mkdir_with_parents (dst_directory, 0700);
+
+ while ((basename = g_dir_read_name (dir)) != NULL) {
+ gchar *old_filename;
+ gchar *new_filename;
+
+ old_filename = g_build_filename (src_directory, basename, NULL);
+ new_filename = g_build_filename (dst_directory, basename, NULL);
+
+ g_hash_table_insert (corrections, old_filename, new_filename);
+ }
+
+ g_dir_close (dir);
+
+ data_cal_migrate_process_corrections (corrections);
+ g_hash_table_destroy (corrections);
+
+ /* It's tempting to want to remove the source directory here.
+ * Don't. We might be iterating over the source directory's
+ * parent directory, and removing the source directory would
+ * screw up the iteration. */
+
+ return TRUE;
+}
+
+static void
+data_cal_migrate_fix_exchange_bug (const gchar *old_base_dir)
+{
+ GDir *dir;
+ GHashTable *corrections;
+ const gchar *basename;
+ gchar *exchange_dir;
+ gchar *old_cache_dir;
+
+ /* The exchange backend mistakenly cached calendar attachments in
+ * ~/.evolution/exchange instead of ~/.evolution/cache/calendar.
+ * Fix that before we migrate the cache directory. */
+
+ exchange_dir = g_build_filename (old_base_dir, "exchange", NULL);
+ old_cache_dir = g_build_filename (old_base_dir, "cache", "calendar", NULL);
+
+ dir = g_dir_open (exchange_dir, 0, NULL);
+ if (dir == NULL)
+ goto exit;
+
+ /* This is to avoid renaming files while we're iterating over the
+ * directory. POSIX says the outcome of that is unspecified. */
+ corrections = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ while ((basename = g_dir_read_name (dir)) != NULL) {
+ gchar *old_filename;
+ gchar *new_filename;
+
+ if (!g_str_has_prefix (basename, "exchange___"))
+ continue;
+
+ old_filename = g_build_filename (exchange_dir, basename, NULL);
+ new_filename = g_build_filename (old_cache_dir, basename, NULL);
+
+ g_hash_table_insert (corrections, old_filename, new_filename);
+ }
+
+ g_dir_close (dir);
+
+ data_cal_migrate_process_corrections (corrections);
+ g_hash_table_destroy (corrections);
+
+exit:
+ g_free (exchange_dir);
+ g_free (old_cache_dir);
+}
+
+static void
+data_cal_migrate_fix_memos_cache_bug (const gchar *old_base_dir)
+{
+ gchar *src_directory;
+ gchar *dst_directory;
+
+ /* Some calendar backends cached memo data under
+ * ~/.evolution/cache/journal instead of ~/.evolution/cache/memos.
+ * Fix that before we migrate the cache directory. */
+
+ src_directory = g_build_filename (old_base_dir, "cache", "journal", NULL);
+ dst_directory = g_build_filename (old_base_dir, "cache", "memos", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+}
+
+static void
+data_cal_migrate_to_user_cache_dir (const gchar *old_base_dir)
+{
+ const gchar *new_cache_dir;
+ gchar *old_cache_dir;
+ gchar *src_directory;
+ gchar *dst_directory;
+
+ old_cache_dir = g_build_filename (old_base_dir, "cache", NULL);
+ new_cache_dir = e_get_user_cache_dir ();
+
+ g_print ("Migrating cached backend data\n");
+
+ /* We don't want to move the source directory directly because the
+ * destination directory may already exist with content. Instead
+ * we want to merge the content of the source directory into the
+ * destination directory.
+ *
+ * For example, given:
+ *
+ * $(src_directory)/A and $(dst_directory)/B
+ * $(src_directory)/C
+ *
+ * we want to end up with:
+ *
+ * $(dst_directory)/A
+ * $(dst_directory)/B
+ * $(dst_directory)/C
+ *
+ * Any name collisions will be left in the source directory.
+ */
+
+ src_directory = g_build_filename (old_cache_dir, "calendar", NULL);
+ dst_directory = g_build_filename (new_cache_dir, "calendar", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+
+ src_directory = g_build_filename (old_cache_dir, "memos", NULL);
+ dst_directory = g_build_filename (new_cache_dir, "memos", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+
+ src_directory = g_build_filename (old_cache_dir, "tasks", NULL);
+ dst_directory = g_build_filename (new_cache_dir, "tasks", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+
+ /* Try to remove the old cache directory. Good chance this will
+ * fail on the first try, since Evolution puts stuff here too. */
+ data_cal_migrate_rmdir (old_cache_dir);
+
+ g_free (old_cache_dir);
+}
+
+static void
+data_cal_migrate_to_user_data_dir (const gchar *old_base_dir)
+{
+ const gchar *new_data_dir;
+ gchar *src_directory;
+ gchar *dst_directory;
+
+ new_data_dir = e_get_user_data_dir ();
+
+ g_print ("Migrating local backend data\n");
+
+ /* We don't want to move the source directory directly because the
+ * destination directory may already exist with content. Instead
+ * we want to merge the content of the source directory into the
+ * destination directory.
+ *
+ * For example, given:
+ *
+ * $(src_directory)/A and $(dst_directory)/B
+ * $(src_directory)/C
+ *
+ * we want to end up with:
+ *
+ * $(dst_directory)/A
+ * $(dst_directory)/B
+ * $(dst_directory)/C
+ *
+ * Any name collisions will be left in the source directory.
+ */
+
+ src_directory = g_build_filename (old_base_dir, "calendar", "local", NULL);
+ dst_directory = g_build_filename (new_data_dir, "calendar", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+
+ src_directory = g_build_filename (old_base_dir, "memos", "local", NULL);
+ dst_directory = g_build_filename (new_data_dir, "memos", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+
+ src_directory = g_build_filename (old_base_dir, "tasks", "local", NULL);
+ dst_directory = g_build_filename (new_data_dir, "tasks", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+
+ /* XXX This is not really the right place to be migrating
+ * exchange data, but since we already cleaned out the
+ * cached attachment files from this directory, may as
+ * well move the user accounts too while we're at it. */
+
+ src_directory = g_build_filename (old_base_dir, "exchange", NULL);
+ dst_directory = g_build_filename (new_data_dir, "exchange", NULL);
+
+ data_cal_migrate_move_contents (src_directory, dst_directory);
+ data_cal_migrate_rmdir (src_directory);
+
+ g_free (src_directory);
+ g_free (dst_directory);
+}
+
+void
+e_data_cal_migrate (void)
+{
+ const gchar *home_dir;
+ gchar *old_base_dir;
+
+ /* XXX This blocks, but it's all just local file
+ * renames so it should be nearly instantaneous. */
+
+ home_dir = g_get_home_dir ();
+ old_base_dir = g_build_filename (home_dir, ".evolution", NULL);
+
+ /* Is there even anything to migrate? */
+ if (!g_file_test (old_base_dir, G_FILE_TEST_IS_DIR))
+ goto exit;
+
+ data_cal_migrate_fix_exchange_bug (old_base_dir);
+ data_cal_migrate_fix_memos_cache_bug (old_base_dir);
+
+ data_cal_migrate_to_user_cache_dir (old_base_dir);
+ data_cal_migrate_to_user_data_dir (old_base_dir);
+
+ /* Try to remove the old base directory. Good chance this will
+ * fail on the first try, since Evolution puts stuff here too. */
+ data_cal_migrate_rmdir (old_base_dir);
+
+exit:
+ g_free (old_base_dir);
+}