[tracker/tracker-tag-and-operator-fix] tracker-tag: Replace --or-operator with --and-operator for --list option
- From: Martyn James Russell <mr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/tracker-tag-and-operator-fix] tracker-tag: Replace --or-operator with --and-operator for --list option
- Date: Thu, 20 Mar 2014 15:50:24 +0000 (UTC)
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]