[tracker/tracker-tag-and-operator-fix] tracker-tag: Replace --or-operator with --and-operator for --list option



commit fa3d5e238d70dfd004fbbb2a4420744888b7078d
Author: Martyn Russell <martyn lanedo com>
Date:   Thu Mar 20 15:47:33 2014 +0000

    tracker-tag: Replace --or-operator with --and-operator for --list option
    
    Currently all arguments supplied for --list are handled with an OR condition,
    making the existing --or-operator redundant.
    
    This makes --and-operator useful for querying for files matching 1 or more tag
    labels.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=725717

 docs/manpages/tracker-tag.1     |   21 ++-
 src/tracker-utils/tracker-tag.c |  310 +++++++++++++++++++++++++++------------
 2 files changed, 233 insertions(+), 98 deletions(-)
---
diff --git a/docs/manpages/tracker-tag.1 b/docs/manpages/tracker-tag.1
index 73519a4..8b7b8d3 100644
--- a/docs/manpages/tracker-tag.1
+++ b/docs/manpages/tracker-tag.1
@@ -29,8 +29,18 @@ Limit search to N results. The default is 512.
 Offset the search results by N. For example, start at item number 10
 in the results. The default is 0.
 .TP
-.B \-r, \-\-or-operator
-Use OR for search terms instead of AND (the default)
+.B \-r, \-\-and-operator
+Use AND operator for search terms instead of OR(the default). For
+example:
+
+.nf
+$ tracker-tag -s -t sliff sloff
+.fi
+
+Should show files in the database that have both the \fIsliff\fR
+.B AND
+\fIsloff\fR tags.
+
 .TP
 .B \-t, \-\-list
 List all tags. Results include the number of files associated with
@@ -39,10 +49,11 @@ associated with each tag by using --show-files.
 
 The \fITAG\fR arguments are optional. If no \fITAG\fR argument
 is specified, all tags are listed. If one or more \fITAG\fRs are
-given, all matching tags are listed. For example, this will match any
-tags named either \fIfoo\fR, \fIbar\fR or \fIbaz\fR:
+given, either matching tags are listed (OR condition). For example,
+this will match any tags named either \fIfoo\fR, \fIbar\fR or
+\fIbaz\fR:
+
 .nf
-.BR
 $ tracker-tag -t foo bar baz
 .fi
 
diff --git a/src/tracker-utils/tracker-tag.c b/src/tracker-utils/tracker-tag.c
index 42c4b95..f836b97 100644
--- a/src/tracker-utils/tracker-tag.c
+++ b/src/tracker-utils/tracker-tag.c
@@ -41,13 +41,13 @@
 
 static gint limit = 512;
 static gint offset;
-static gchar **files;
-static gboolean or_operator;
+static gchar **resources;
+static gboolean and_operator;
 static gchar *add_tag;
 static gchar *remove_tag;
 static gchar *description;
 static gboolean *list;
-static gboolean show_files;
+static gboolean show_resources;
 static gboolean print_version;
 
 static GOptionEntry entries[] = {
@@ -59,15 +59,15 @@ static GOptionEntry entries[] = {
          N_("Offset the results"),
          "0"
        },
-       { "or-operator", 'r', 0, G_OPTION_ARG_NONE, &or_operator,
-         N_("Use OR for search terms instead of AND (the default)"),
+       { "and-operator", 'n', 0, G_OPTION_ARG_NONE, &and_operator,
+         N_("Use AND for search terms instead of OR (the default)"),
          NULL
        },
        { "list", 't', 0, G_OPTION_ARG_NONE, &list,
          N_("List all tags (using FILTER if specified; FILTER always uses logical OR)"),
          N_("FILTER"),
        },
-       { "show-files", 's', 0, G_OPTION_ARG_NONE, &show_files,
+       { "show-files", 's', 0, G_OPTION_ARG_NONE, &show_resources,
          N_("Show files associated with each tag (this is only used with --list)"),
          NULL
        },
@@ -88,7 +88,7 @@ static GOptionEntry entries[] = {
          NULL
        },
        { G_OPTION_REMAINING, 0, 0,
-         G_OPTION_ARG_FILENAME_ARRAY, &files,
+         G_OPTION_ARG_FILENAME_ARRAY, &resources,
          N_("FILE…"),
          N_("FILE [FILE…]")},
        { NULL }
@@ -149,18 +149,19 @@ get_escaped_sparql_string (const gchar *str)
 }
 
 static gchar *
-get_filter_string (GStrv        files,
-                   gboolean     files_are_urns,
+get_filter_string (GStrv        resources,
+                   const gchar *subject,
+                   gboolean     resources_are_urns,
                    const gchar *tag)
 {
        GString *filter;
        gint i, len;
 
-       if (!files) {
+       if (!resources) {
                return NULL;
        }
 
-       len = g_strv_length (files);
+       len = g_strv_length (resources);
 
        if (len < 1) {
                return NULL;
@@ -175,11 +176,11 @@ get_filter_string (GStrv        files,
        }
 
        for (i = 0; i < len; i++) {
-               if (files_are_urns) {
-                       g_string_append_printf (filter, "?urn = <%s>", files[i]);
-               } else {
-                       g_string_append_printf (filter, "?f = \"%s\"", files[i]);
-               }
+               g_string_append_printf (filter, "%s = %s%s%s",
+                                       subject,
+                                       resources_are_urns ? "<" : "\"",
+                                       resources[i],
+                                       resources_are_urns ? ">" : "\"");
 
                if (i < len - 1) {
                        g_string_append (filter, " || ");
@@ -196,16 +197,16 @@ get_filter_string (GStrv        files,
 }
 
 static GStrv
-get_uris (GStrv files)
+get_uris (GStrv resources)
 {
        GStrv uris;
        gint len, i;
 
-       if (!files) {
+       if (!resources) {
                return NULL;
        }
 
-       len = g_strv_length (files);
+       len = g_strv_length (resources);
 
        if (len < 1) {
                return NULL;
@@ -213,10 +214,10 @@ get_uris (GStrv files)
 
        uris = g_new0 (gchar *, len + 1);
 
-       for (i = 0; files[i]; i++) {
+       for (i = 0; resources[i]; i++) {
                GFile *file;
 
-               file = g_file_new_for_commandline_arg (files[i]);
+               file = g_file_new_for_commandline_arg (resources[i]);
                uris[i] = g_file_get_uri (file);
                g_object_unref (file);
        }
@@ -233,7 +234,7 @@ get_file_urns (TrackerSparqlConnection *connection,
        gchar *query, *filter;
        GError *error = NULL;
 
-       filter = get_filter_string (uris, FALSE, tag);
+       filter = get_filter_string (uris, "?f", FALSE, tag);
        query = g_strdup_printf ("SELECT ?urn ?f "
                                 "WHERE { "
                                 "  ?urn "
@@ -303,7 +304,7 @@ get_all_tags_show_tag_id (TrackerSparqlConnection *connection,
        GError *error = NULL;
        gchar *query;
 
-       /* Get files associated */
+       /* Get resources associated */
        query = g_strdup_printf ("SELECT ?uri WHERE {"
                                 "  ?urn a rdfs:Resource; "
                                 "  nie:url ?uri ; "
@@ -337,62 +338,180 @@ get_all_tags_show_tag_id (TrackerSparqlConnection *connection,
        g_object_unref (cursor);
 }
 
+static inline gchar *
+get_filter_in_for_strv (GStrv        resources,
+                        const gchar *subject)
+{
+       gchar *filter, *filter_in;
+
+       /* e.g. '?label IN ("foo", "bar")' */
+       filter_in = g_strjoinv ("\",\"", resources);
+       filter = g_strdup_printf ("FILTER (%s IN (\"%s\"))", subject, filter_in);
+       g_free (filter_in);
+
+       return filter;
+}
+
+static gboolean
+get_all_resources_with_tags (TrackerSparqlConnection *connection,
+                             GStrv                    tags,
+                             gint                     search_offset,
+                             gint                     search_limit)
+{
+       TrackerSparqlCursor *cursor;
+       GError *error = NULL;
+       GStrv tag_urns, p;
+       GString *s;
+       gchar *filter, *query;
+
+       if (!tags) {
+               return FALSE;
+       }
+
+       /* First, get matching tags */
+       filter = get_filter_in_for_strv (tags, "?label");
+       query = g_strdup_printf ("SELECT ?t "
+                                "WHERE { "
+                                "  ?t a nao:Tag ;"
+                                "     nao:prefLabel ?label ."
+                                "  %s"
+                                "}",
+                                filter);
+       g_free (filter);
+
+       cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
+       g_free (query);
+
+       if (error) {
+               g_printerr ("%s, %s\n",
+                           _("Could not get all tags in the database"),
+                           error->message);
+               g_error_free (error);
+
+               return FALSE;
+       }
+
+       tag_urns = result_to_strv (cursor, 0);
+       if (!tag_urns) {
+               g_print ("%s\n",
+                        _("No files have been tagged"));
+
+               if (cursor) {
+                       g_object_unref (cursor);
+               }
+
+               return TRUE;
+       }
+
+       s = g_string_new ("");
+
+       for (p = tag_urns; p && *p; p++) {
+               g_string_append_printf (s, "; nao:hasTag <%s>", *p);
+       }
+
+       s = g_string_append (s, " .");
+       filter = g_string_free (s, FALSE);
+       g_strfreev (tag_urns);
+
+       query = g_strdup_printf ("SELECT DISTINCT nie:url(?r) "
+                                "WHERE {"
+                                "  ?r a rdfs:Resource %s"
+                                "} "
+                                "OFFSET %d "
+                                "LIMIT %d",
+                                filter,
+                                search_offset,
+                                search_limit);
+       g_free (filter);
+
+       cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
+       g_free (query);
+
+       if (error) {
+               g_printerr ("%s, %s\n",
+                           _("Could not get files for matching tags"),
+                           error->message);
+               g_error_free (error);
+
+               return FALSE;
+       }
+
+       if (!cursor) {
+               g_print ("%s\n",
+                        _("No files were found matching ALL of those tags"));
+       } else {
+               gint count = 0;
+
+               g_print ("%s:\n", _("Files"));
+
+               while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
+                       g_print ("  %s\n",
+                                tracker_sparql_cursor_get_string (cursor, 0, NULL));
+                       count++;
+               }
+
+               if (count == 0) {
+                       /* To translators: This is to say there are no
+                        * files found associated with multiple tags, e.g.:
+                        *
+                        *   Files:
+                        *     None
+                        *
+                        */
+                       g_print ("  %s\n", _("None"));
+               }
+
+               g_print ("\n");
+
+               if (count >= search_limit) {
+                       show_limit_warning ();
+               }
+
+               g_object_unref (cursor);
+       }
+
+       return TRUE;
+}
+
+
 static gboolean
 get_all_tags (TrackerSparqlConnection *connection,
-              GStrv                    files,
+              GStrv                    resources,
               gint                     search_offset,
               gint                     search_limit,
-              gboolean                 use_or_operator,
-              gboolean                 show_files)
+              gboolean                 show_resources)
 {
        TrackerSparqlCursor *cursor;
        GError *error = NULL;
        gchar *query;
+       gchar *filter = NULL;
 
-       if (files && g_strv_length (files) > 0) {
-               gchar *filter;
-
-               /* e.g. '?label IN ("foo", "bar")' */
-               filter = g_strjoinv ("\",\"", files);
-
-               /* You might be asking, why not logical AND here, why
-                * logical OR for FILTER, well, tags can't have
-                * multiple labels is the simple answer.
-                */
-               query = g_strdup_printf ("SELECT ?tag ?label nao:description(?tag) COUNT(?urns) AS urns "
-                                        "WHERE {"
-                                        "  ?tag a nao:Tag ;"
-                                        "  nao:prefLabel ?label ."
-                                        "  OPTIONAL {"
-                                        "     ?urns nao:hasTag ?tag"
-                                        "  } ."
-                                        "  FILTER (?label IN (\"%s\"))"
-                                        "} "
-                                        "GROUP BY ?tag "
-                                        "ORDER BY ASC(?label) "
-                                        "OFFSET %d "
-                                        "LIMIT %d",
-                                        filter,
-                                        search_offset,
-                                        search_limit);
-               g_free (filter);
-       } else {
-               query = g_strdup_printf ("SELECT ?tag ?label nao:description(?tag) COUNT(?urns) AS urns "
-                                        "WHERE {"
-                                        "  ?tag a nao:Tag ;"
-                                        "  nao:prefLabel ?label ."
-                                        "  OPTIONAL {"
-                                        "     ?urns nao:hasTag ?tag"
-                                        "  }"
-                                        "} "
-                                        "GROUP BY ?tag "
-                                        "ORDER BY ASC(?label) "
-                                        "OFFSET %d "
-                                        "LIMIT %d",
-                                        search_offset,
-                                        search_limit);
+       if (resources && g_strv_length (resources) > 0) {
+               filter = get_filter_in_for_strv (resources, "?label");
        }
 
+       /* You might be asking, why not logical AND here, why
+        * logical OR for FILTER, well, tags can't have
+        * multiple labels is the simple answer.
+        */
+       query = g_strdup_printf ("SELECT ?tag ?label nao:description(?tag) COUNT(?urns) AS urns "
+                                "WHERE {"
+                                "  ?tag a nao:Tag ;"
+                                "  nao:prefLabel ?label ."
+                                "  OPTIONAL {"
+                                "     ?urns nao:hasTag ?tag"
+                                "  } ."
+                                "  %s"
+                                "} "
+                                "GROUP BY ?tag "
+                                "ORDER BY ASC(?label) "
+                                "OFFSET %d "
+                                "LIMIT %d",
+                                filter ? filter : "",
+                                search_offset,
+                                search_limit);
+       g_free (filter);
+
        cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
        g_free (query);
 
@@ -417,12 +536,12 @@ get_all_tags (TrackerSparqlConnection *connection,
                        const gchar *id;
                        const gchar *tag;
                        const gchar *description;
-                       const gchar *files;
-                       gint n_files = 0;
+                       const gchar *resources;
+                       gint n_resources = 0;
 
                        id = tracker_sparql_cursor_get_string (cursor, 0, NULL);
-                       files = tracker_sparql_cursor_get_string (cursor, 3, NULL);
-                       n_files = atoi (files);
+                       resources = tracker_sparql_cursor_get_string (cursor, 3, NULL);
+                       n_resources = atoi (resources);
 
                        tag = tracker_sparql_cursor_get_string (cursor, 1, NULL);
                        description = tracker_sparql_cursor_get_string (cursor, 2, NULL);
@@ -437,7 +556,7 @@ get_all_tags (TrackerSparqlConnection *connection,
                                 description ? description : "",
                                 description ? ")" : "");
 
-                       if (show_files && n_files > 0) {
+                       if (show_resources && n_resources > 0) {
                                get_all_tags_show_tag_id (connection, id);
                        } else {
                                g_print ("    %s\n", id);
@@ -445,8 +564,8 @@ get_all_tags (TrackerSparqlConnection *connection,
                                g_print (g_dngettext (NULL,
                                                      "%d file",
                                                      "%d files",
-                                                     n_files),
-                                        n_files);
+                                                     n_resources),
+                                        n_resources);
                                g_print ("\n");
                        }
 
@@ -455,7 +574,7 @@ get_all_tags (TrackerSparqlConnection *connection,
 
                if (count == 0) {
                        /* To translators: This is to say there are no
-                        * files found associated with this tag, e.g.:
+                        * resources found associated with this tag, e.g.:
                         *
                         *   Tags (shown by name):
                         *     None
@@ -513,7 +632,7 @@ print_file_report (TrackerSparqlCursor *cursor,
 
 static gboolean
 add_tag_for_urns (TrackerSparqlConnection *connection,
-                  GStrv                    files,
+                  GStrv                    resources,
                   const gchar             *tag,
                   const gchar             *description)
 {
@@ -525,8 +644,8 @@ add_tag_for_urns (TrackerSparqlConnection *connection,
 
        tag_escaped = get_escaped_sparql_string (tag);
 
-       if (files) {
-               uris = get_uris (files);
+       if (resources) {
+               uris = get_uris (resources);
 
                if (!uris) {
                        return FALSE;
@@ -535,7 +654,7 @@ add_tag_for_urns (TrackerSparqlConnection *connection,
                cursor = get_file_urns (connection, uris, NULL);
 
                if (!cursor) {
-                       g_printerr ("Files do not exist or aren't indexed\n");
+                       g_printerr ("%s\n", _("Files do not exist or aren't indexed"));
                        g_strfreev (uris);
                        return FALSE;
                }
@@ -543,10 +662,9 @@ add_tag_for_urns (TrackerSparqlConnection *connection,
                urns_strv = result_to_strv (cursor, 0);
 
                if (!urns_strv || g_strv_length (urns_strv) < 1) {
-                       g_printerr ("Files do not exist or aren't indexed\n");
+                       g_printerr ("%s\n", _("Files do not exist or aren't indexed"));
                        g_object_unref (cursor);
                        g_strfreev (uris);
-
                        return FALSE;
                }
        }
@@ -618,7 +736,7 @@ add_tag_for_urns (TrackerSparqlConnection *connection,
        if (urns_strv) {
                gchar *filter;
 
-               filter = get_filter_string (urns_strv, TRUE, NULL);
+               filter = get_filter_string (urns_strv, "?urn", TRUE, NULL);
 
                /* Add tag to specific urns */
                query = g_strdup_printf ("INSERT { "
@@ -665,7 +783,7 @@ add_tag_for_urns (TrackerSparqlConnection *connection,
 
 static gboolean
 remove_tag_for_urns (TrackerSparqlConnection *connection,
-                     GStrv                    files,
+                     GStrv                    resources,
                      const gchar             *tag)
 {
        TrackerSparqlCursor *urns_cursor = NULL;
@@ -675,7 +793,7 @@ remove_tag_for_urns (TrackerSparqlConnection *connection,
        GStrv uris;
 
        tag_escaped = get_escaped_sparql_string (tag);
-       uris = get_uris (files);
+       uris = get_uris (resources);
 
        if (uris && *uris) {
                TrackerSparqlCursor *tag_cursor;
@@ -738,7 +856,7 @@ remove_tag_for_urns (TrackerSparqlConnection *connection,
                }
 
                urns_strv = result_to_strv (urns_cursor, 0);
-               filter = get_filter_string (urns_strv, TRUE, urn);
+               filter = get_filter_string (urns_strv, "?urn", TRUE, urn);
                g_strfreev (urns_strv);
 
                query = g_strdup_printf ("DELETE { "
@@ -883,11 +1001,13 @@ main (int argc, char **argv)
                return EXIT_SUCCESS;
        }
 
-       if (!list && show_files) {
+       if (!list && show_resources) {
                failed = _("The --list option is required for --show-files");
+       } else if (and_operator && (!list || !resources)) {
+               failed = _("The --and-operator option can only be used with --list and tag label arguments");
        } else if (add_tag && remove_tag) {
                failed = _("Add and delete actions can not be used together");
-       } else if (!list && !add_tag && !remove_tag && !files) {
+       } else if (!list && !add_tag && !remove_tag && !resources) {
                failed = _("No arguments were provided");
        } else if (description && !add_tag) {
                failed = _("The --description option can only be used with --add");
@@ -921,7 +1041,11 @@ main (int argc, char **argv)
        if (list) {
                gboolean success;
 
-               success = get_all_tags (connection, files, offset, limit, or_operator, show_files);
+               if (G_UNLIKELY (and_operator)) {
+                       success = get_all_resources_with_tags (connection, resources, offset, limit);
+               } else {
+                       success = get_all_tags (connection, resources, offset, limit, show_resources);
+               }
                g_object_unref (connection);
 
                return success ? EXIT_SUCCESS : EXIT_FAILURE;
@@ -930,7 +1054,7 @@ main (int argc, char **argv)
        if (add_tag) {
                gboolean success;
 
-               success = add_tag_for_urns (connection, files, add_tag, description);
+               success = add_tag_for_urns (connection, resources, add_tag, description);
                g_object_unref (connection);
 
                return success ? EXIT_SUCCESS : EXIT_FAILURE;
@@ -939,17 +1063,17 @@ main (int argc, char **argv)
        if (remove_tag) {
                gboolean success;
 
-               success = remove_tag_for_urns (connection, files, remove_tag);
+               success = remove_tag_for_urns (connection, resources, remove_tag);
                g_object_unref (connection);
 
                return success ? EXIT_SUCCESS : EXIT_FAILURE;
        }
 
-       if (files) {
+       if (resources) {
                gboolean success = TRUE;
                gchar **p;
 
-               for (p = files; *p; p++) {
+               for (p = resources; *p; p++) {
                        GFile *file;
                        gchar *uri;
                        


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