[nautilus/sam/tracker-3: 14/14] Import starred files data from Tracker 2.x




commit e1efd7001183aecb33a9eeccabd0ab42e3fe78c9
Author: Sam Thursfield <sam afuera me uk>
Date:   Sat Aug 29 21:10:48 2020 +0200

    Import starred files data from Tracker 2.x
    
    Starred files data is now migrated from the Tracker 2.x database if
    found. This depends on the `tracker3` CLI tool, which should be
    present anywhere that we find libtracker-sparql 3.0. The --2to3
    export functionality was added in
    https://gitlab.gnome.org/GNOME/tracker/-/merge_requests/308
    
    If/when the migration completes successfully, a stamp file named
    `~/.local/share/nautilus/tracker2-migration-complete` is created.

 meson.build                          |   3 +
 src/nautilus-application.c           |   2 +
 src/nautilus-search-engine-tracker.c |   2 +-
 src/nautilus-tag-manager.c           | 168 +++++++++++++++++++++++++++++++++++
 src/nautilus-tag-manager.h           |   2 +
 5 files changed, 176 insertions(+), 1 deletion(-)
---
diff --git a/meson.build b/meson.build
index c33c0c5e7..680e488ef 100644
--- a/meson.build
+++ b/meson.build
@@ -127,6 +127,8 @@ endif
 tracker_sparql = dependency('tracker-sparql-3.0')
 xml = dependency('libxml-2.0', version: '>= 2.7.8')
 
+tracker_cli = find_program('tracker3')
+
 ####################
 # End dependencies #
 ####################
@@ -153,6 +155,7 @@ conf.set_quoted('NAUTILUS_DATADIR', join_paths(prefix, datadir, 'nautilus'))
 conf.set_quoted('NAUTILUS_EXTENSIONDIR', join_paths(prefix, extensiondir))
 conf.set_quoted('PACKAGE_VERSION', meson.project_version())
 conf.set_quoted('PROFILE', profile)
+conf.set_quoted('TRACKER3_CLI_PATH', tracker_cli.path())
 conf.set_quoted('VERSION', '@0@-@VCS_TAG@'.format(meson.project_version()))
 
 conf.set('ENABLE_PACKAGEKIT', get_option('packagekit'))
diff --git a/src/nautilus-application.c b/src/nautilus-application.c
index 17f1da59a..10478da9c 100644
--- a/src/nautilus-application.c
+++ b/src/nautilus-application.c
@@ -1351,6 +1351,8 @@ nautilus_application_startup_common (NautilusApplication *self)
 
     nautilus_init_application_actions (self);
 
+    nautilus_tag_manager_maybe_migrate_tracker2_data (priv->tag_manager);
+
     nautilus_profile_end (NULL);
 
     g_signal_connect (self, "notify::active-window", G_CALLBACK (on_application_active_window_changed), 
NULL);
diff --git a/src/nautilus-search-engine-tracker.c b/src/nautilus-search-engine-tracker.c
index 69b309be8..b8b4aaaae 100644
--- a/src/nautilus-search-engine-tracker.c
+++ b/src/nautilus-search-engine-tracker.c
@@ -368,7 +368,7 @@ nautilus_search_engine_tracker_start (NautilusSearchProvider *provider)
                          "    nie:mimeType ?mime");
     }
 
-    if (tracker->fts_enabled)
+    if (tracker->fts_enabled && *search_text)
     {
         /* Use fts:match only for content search to not lose some filename results due to stop words. */
         g_string_append_printf (sparql,
diff --git a/src/nautilus-tag-manager.c b/src/nautilus-tag-manager.c
index f9936df28..0c2f8605d 100644
--- a/src/nautilus-tag-manager.c
+++ b/src/nautilus-tag-manager.c
@@ -25,6 +25,7 @@
 #define DEBUG_FLAG NAUTILUS_DEBUG_TAG_MANAGER
 #include "nautilus-debug.h"
 
+#include <gio/gunixinputstream.h>
 #include <tracker-sparql.h>
 
 #include "config.h"
@@ -84,6 +85,14 @@ enum
 
 static guint signals[LAST_SIGNAL];
 
+/* Limit to 10MB output from Tracker -- surely, nobody has over a million starred files. */
+#define TRACKER2_MAX_IMPORT_BYTES 10 * 1024 * 1024
+
+static const gchar *tracker2_migration_stamp (void)
+{
+    return g_build_filename (g_get_user_data_dir (), "nautilus", "tracker2-migration-complete", NULL);
+}
+
 static void
 start_query_or_update (TrackerSparqlConnection *db,
                        GString                 *query,
@@ -687,3 +696,162 @@ nautilus_tag_manager_can_star_contents (NautilusTagManager *tag_manager,
      */
     return g_file_has_prefix (directory, tag_manager->home) || g_file_equal (directory, tag_manager->home);
 }
+
+static void
+process_tracker2_data_cb (GObject      *source_object,
+                          GAsyncResult *res,
+                          gpointer      user_data)
+{
+    NautilusTagManager *self = NAUTILUS_TAG_MANAGER (source_object);
+    const gchar *path = tracker2_migration_stamp ();
+    g_autoptr (GError) error = NULL;
+
+    tracker_sparql_connection_update_finish (self->db, res, &error);
+
+    if (!error)
+    {
+        DEBUG ("Data migration was successful. Creating stamp %s", path);
+
+        g_file_set_contents (path, "", -1, &error);
+        if (error) {
+            g_warning ("Failed to create %s after migration: %s", path, error->message);
+        }
+    }
+    else
+    {
+        g_warning ("Error during data migration: %s", error->message);
+    }
+}
+
+static void
+process_tracker2_data (NautilusTagManager *self, GBytes *key_file_data)
+{
+    g_autoptr (GKeyFile) key_file = NULL;
+    g_autoptr (GError) error = NULL;
+    gchar **groups, **group;
+    GList *selection = NULL;
+    NautilusFile *file;
+
+    key_file = g_key_file_new ();
+    g_key_file_load_from_bytes (key_file,
+                                key_file_data,
+                                G_KEY_FILE_NONE,
+                                &error);
+    g_bytes_unref (key_file_data);
+
+    if (error)
+    {
+        g_warning ("Tracker 2 migration: Failed to parse key file data: %s", error->message);
+        return;
+    }
+
+    groups = g_key_file_get_groups (key_file, NULL);
+
+    for (group = groups; *group != NULL; group ++)
+    {
+        file = nautilus_file_get_by_uri (*group);
+
+        if (file)
+        {
+            DEBUG ("Tracker 2 migration: starring %s", *group);
+            selection = g_list_prepend (selection, file);
+        }
+        else
+        {
+            DEBUG ("Tracker 2 migration: couldn't get NautilusFile for %s", *group);
+        }
+    }
+
+    nautilus_tag_manager_star_files (self,
+                                     G_OBJECT (self),
+                                     selection,
+                                     process_tracker2_data_cb,
+                                     self->cancellable);
+
+    g_free (groups);
+}
+
+static void
+export_tracker2_data_cb (GObject *source_object,
+                         GAsyncResult *res,
+                         gpointer user_data)
+{
+    GInputStream *stream = G_INPUT_STREAM (source_object);
+    NautilusTagManager *self = NAUTILUS_TAG_MANAGER (user_data);
+    g_autoptr (GError) error = NULL;
+    GBytes *key_file_data;
+
+    key_file_data = g_input_stream_read_bytes_finish (stream, res, &error);
+
+    if (key_file_data)
+    {
+        process_tracker2_data (self, key_file_data);
+    }
+    else
+    {
+        g_warning ("Tracker2 migration: Failed to read data from pipe: %s", error->message);
+    }
+}
+
+static void
+child_watch_cb (GPid     pid,
+                gint     status,
+                gpointer user_data)
+{
+    DEBUG ("Child %" G_PID_FORMAT " exited %s", pid,
+           g_spawn_check_exit_status (status, NULL) ? "normally" : "abnormally");
+    g_spawn_close_pid (pid);
+}
+
+static void
+export_tracker2_data (NautilusTagManager *self)
+{
+    gchar *argv[] = {TRACKER3_CLI_PATH, "export", "--2to3", "files-starred", "--keyfile", NULL};
+    gint stdout_fd;
+    GPid child_pid;
+    g_autoptr (GError) error = NULL;
+    gboolean success;
+    g_autoptr (GInputStream) stream = NULL;
+    GSpawnFlags flags;
+
+    flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_STDERR_TO_DEV_NULL;
+    success = g_spawn_async_with_pipes (NULL,
+                                        argv,
+                                        NULL,
+                                        flags,
+                                        NULL,
+                                        NULL,
+                                        &child_pid,
+                                        NULL,
+                                        &stdout_fd,
+                                        NULL,
+                                        &error);
+    if (!success) {
+        g_warning ("Tracker 2 migration: Couldn't run %s: %s", TRACKER3_CLI_PATH, error->message);
+        return;
+    }
+
+    g_child_watch_add (child_pid, child_watch_cb, NULL);
+
+    stream = g_unix_input_stream_new (stdout_fd, TRUE);
+    g_input_stream_read_bytes_async (stream,
+                                     TRACKER2_MAX_IMPORT_BYTES,
+                                     G_PRIORITY_LOW,
+                                     self->cancellable,
+                                     export_tracker2_data_cb,
+                                     self);
+}
+
+void
+nautilus_tag_manager_maybe_migrate_tracker2_data (NautilusTagManager *self)
+{
+    if (g_file_test (tracker2_migration_stamp (), G_FILE_TEST_EXISTS))
+    {
+        DEBUG ("Tracker 2 migration: already completed.");
+    }
+    else
+    {
+        DEBUG ("Tracker 2 migration: starting.");
+        export_tracker2_data (self);
+    }
+}
diff --git a/src/nautilus-tag-manager.h b/src/nautilus-tag-manager.h
index c0d793adc..2e926ae75 100644
--- a/src/nautilus-tag-manager.h
+++ b/src/nautilus-tag-manager.h
@@ -54,4 +54,6 @@ gboolean            nautilus_tag_manager_file_is_starred   (NautilusTagManager *
 gboolean            nautilus_tag_manager_can_star_contents (NautilusTagManager *self,
                                                             GFile              *directory);
 
+void                nautilus_tag_manager_maybe_migrate_tracker2_data (NautilusTagManager *self);
+
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]