Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
.gitignore | 3 +
configure.ac | 18 ++
libreport.spec.in | 18 ++
src/include/internal_libreport.h | 2 +
src/lib/strbuf.c | 30 ++++
src/plugins/Makefile.am | 29 +++
src/plugins/abrt-bodhi.c | 271 +++++++++++++++++++++++++++++
src/plugins/analyze_LocalGDB_Bodhi.xml.in | 7 +
src/plugins/bodhi_event.conf | 10 +
src/plugins/reporter-bugzilla.c | 40 ++++-
10 files changed, 424 insertions(+), 4 deletions(-)
create mode 100644 src/plugins/abrt-bodhi.c
create mode 100644 src/plugins/analyze_LocalGDB_Bodhi.xml.in
create mode 100644 src/plugins/bodhi_event.conf
diff --git a/.gitignore b/.gitignore
index 7b57798..c5b3edf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@ src/plugins/reporter-print
src/plugins/reporter-rhtsupport
src/plugins/reporter-upload
src/plugins/report
+src/plugins/abrt-bodhi
src/report-newt/report-newt
# autotools
@@ -79,6 +80,8 @@ tests/atlocal
tests/testsuite
tests/testsuite.log
tests/package.m4
+testsuite.dir/
+testsuite.log
# misc
\#*
diff --git a/configure.ac b/configure.ac
index c0eecf0..6fc3960 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,9 @@ AC_ARG_ENABLE(debug,
[Enable debug information])],
[CFLAGS="$CFLAGS -DDEBUG -ggdb -g"])
+AC_ARG_ENABLE([bodhi],
+ AC_HELP_STRING([--disable-bodhi], [do not use bodhi plugin]))
+
dnl ****** INTERNATIONALIZATION **********************
GETTEXT_PACKAGE=libreport
AC_SUBST(GETTEXT_PACKAGE)
@@ -73,6 +76,21 @@ PKG_CHECK_MODULES([PYTHON], [python],,[
])
PKG_CHECK_MODULES([NEWT], [libnewt])
+AS_IF([test "x$enable_bodhi" != "xno"], [
+ dnl Do the stuff needed for enabling the feature
+ AC_CHECK_LIB([json], [json_tokener_parse],
+ [AM_CONDITIONAL(HAVE_BODHI, true)
+ AC_DEFINE([HAVE_BODHI], [1], [have bodhi])
+ PKG_CHECK_MODULES([JSON_C], [json])],
+ [AM_CONDITIONAL(HAVE_BODHI, false)
+ AC_DEFINE([HAVE_BODHI], [0], [have bodhi])])
+ ],
+ [test "x$enable_bodhi" = xno], [
+ AM_CONDITIONAL(HAVE_BODHI, false)
+ AC_DEFINE([HAVE_BODHI], [0], [have bodhi])
+ ]
+)
+
PKG_PROG_PKG_CONFIG
AC_CHECK_HEADER([libtar.h], [],
diff --git a/libreport.spec.in b/libreport.spec.in
index 48f7484..cd48a57 100644
--- a/libreport.spec.in
+++ b/libreport.spec.in
@@ -150,6 +150,18 @@ Obsoletes: report-plugin-bugzilla < 0.23-1
Provides: report-config-bugzilla-redhat-com = 0.23-1
Obsoletes: report-config-bugzilla-redhat-com < 0.23-1
+%if 0%{?fedora}
+%package plugin-bodhi
+Summary: %{name}'s bodhi plugin
+BuildRequires: json-c-devel
+Group: System Environment/Libraries
+Requires: %{name} = %{version}-%{release}
+Requires: PackageKit
+
+%description plugin-bodhi
+Search for a new updates in bodhi server
+%endif
+
%description plugin-bugzilla
Plugin to report bugs into the bugzilla.
@@ -312,6 +324,12 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null ||
:
%{_mandir}/man*/reporter-mailx.*
%{_bindir}/reporter-mailx
+%if 0%{?fedora}
+%files plugin-bodhi
+%defattr(-,root,root,-)
+%{_bindir}/abrt-action-bodhi
+%endif
+
%files plugin-bugzilla
%defattr(-,root,root,-)
%config(noreplace) %{_sysconfdir}/libreport/plugins/bugzilla.conf
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
index 4982ef0..af1e7ca 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -100,6 +100,8 @@ int prefixcmp(const char *str, const char *prefix);
int suffixcmp(const char *str, const char *suffix);
#define strtrim libreport_strtrim
char *strtrim(char *str);
+#define strtrimch libreport_strtrimch
+char *strtrimch(char *str, int ch);
#define concat_path_file libreport_concat_path_file
char *concat_path_file(const char *path, const char *filename);
#define append_to_malloced_string libreport_append_to_malloced_string
diff --git a/src/lib/strbuf.c b/src/lib/strbuf.c
index e1477e1..365f31a 100644
--- a/src/lib/strbuf.c
+++ b/src/lib/strbuf.c
@@ -60,6 +60,36 @@ char *strtrim(char *str)
return str;
}
+/*
+ * Trims characters both from left and right side of a string.
+ * Modifies the string in-place. Returns the trimmed string.
+ */
+char *strtrimch(char *str, int ch)
+{
+ if (!str)
+ return NULL;
+
+ char *tmp = str;
+
+
+ // Remove leading characters.
+ while (*tmp == ch)
+ ++tmp;
+
+ memmove(str, tmp, strlen(str));
+
+ // Remove trailing spaces.
+ int i = strlen(str);
+ while (--i >= 0)
+ {
+ if (str[i] != ch)
+ break;
+ }
+ str[++i] = '\0';
+ return str;
+}
+
+
struct strbuf *strbuf_new(void)
{
struct strbuf *buf = xzalloc(sizeof(*buf));
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index cee4f14..c5f1810 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -10,6 +10,9 @@ bin_PROGRAMS = \
reporter-mailx \
reporter-print \
report
+if HAVE_BODHI
+bin_PROGRAMS += abrt-bodhi
+endif
pluginsconfdir = $(PLUGINS_CONF_DIR)
@@ -30,6 +33,9 @@ dist_events_DATA = \
report_RHTSupport.xml \
report_Kerneloops.xml \
report_Uploader.xml
+if HAVE_BODHI
+dist_events_DATA += analyze_LocalGDB_Bodhi.xml
+endif
@INTLTOOL_XML_RULE@
@@ -41,6 +47,9 @@ dist_eventsconf_DATA = \
bugzilla_event.conf \
rhtsupport_event.conf \
uploader_event.conf
+if HAVE_BODHI
+dist_eventsconf_DATA += bodhi_event.conf
+endif
MAN_TXT = \
reporter-print.txt \
@@ -74,6 +83,9 @@ EXTRA_DIST = \
report_RHTSupport.xml.in \
report_Kerneloops.xml.in \
report_Uploader.xml.in
+if HAVE_BODHI
+EXTRA_DIST += analyze_LocalGDB_Bodhi.xml.in
+endif
$(DESTDIR)/$(DEBUG_INFO_DIR):
$(mkdir_p) '$@'
@@ -234,4 +246,21 @@ report_CPPFLAGS = \
report_LDADD = \
../lib/libreport.la
+if HAVE_BODHI
+abrt_bodhi_SOURCES = \
+ abrt-bodhi.c
+abrt_bodhi_CPPFLAGS = \
+ -I$(srcdir)/../include \
+ -I$(srcdir)/../lib \
+ $(GLIB_CFLAGS) \
+ $(LIBREPORT_CFLAGS) \
+ $(JSON_C_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Wwrite-strings -Werror
+abrt_bodhi_LDADD = \
+ $(JSON_C_LIBS) \
+ ../lib/libreport.la \
+ ../lib/libabrt_web.la
+endif
+
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
diff --git a/src/plugins/abrt-bodhi.c b/src/plugins/abrt-bodhi.c
new file mode 100644
index 0000000..427fd39
--- /dev/null
+++ b/src/plugins/abrt-bodhi.c
@@ -0,0 +1,271 @@
+/*
+ Copyright (C) 2011 ABRT Team
+ Copyright (C) 2011 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "internal_libreport.h"
+#include "abrt_curl.h"
+#include "client.h"
+
+#include <json/json.h>
+
+//699198,705037,705036
+
+static const char *const bodhi_url =
"https://admin.fedoraproject.org/updates/%s";
+
+struct bodhi {
+ GList *nvr;
+ char *date_pushed;
+ char *status;
+ char *dist_tag;
+ int karma;
+
+ GList *bz_ids;
+};
+
+enum {
+ BODHI_READ_STR,
+ BODHI_READ_INT,
+ BODHI_READ_JSON_OBJ,
+};
+
+static void free_bodhi_list(GList *bodhi_list)
+{
+ if (!bodhi_list)
+ return;
+
+ for (GList *li = bodhi_list; li; li = li->next)
+ {
+ struct bodhi *b = (struct bodhi *) li->data;
+ list_free_with_free(b->bz_ids);
+ list_free_with_free(b->nvr);
+ free(b);
+ }
+
+ g_list_free(bodhi_list);
+}
+
+static void bodhi_read_value(json_object *json, const char *item_name,
+ void *value, int flags)
+{
+ json_object *j = json_object_object_get(json, item_name);
+ if (!j)
+ {
+ error_msg("'%s' section is not available", item_name);
+ return;
+ }
+
+ switch (flags) {
+ case BODHI_READ_INT:
+ *(int *) value = json_object_get_int(j);
+ break;
+ case BODHI_READ_STR:
+ *(char **) value = (char *) xstrdup(json_object_to_json_string(j));
+ value = strtrimch(*(char **) value, '"');
+ break;
+ case BODHI_READ_JSON_OBJ:
+ *(json_object **) value = (json_object *) j;
+ break;
+ };
+}
+
+#if 0
+static void print_bodhi(struct bodhi *b)
+{
+ for (GList *l = b->nvr; l; l = l->next)
+ printf("'%s' ", (char *)l->data);
+
+ if (b->date_pushed)
+ printf(" '%s'", b->date_pushed);
+
+ if (b->status)
+ printf(" '%s'", b->status);
+
+ if (b->dist_tag)
+ printf(" '%s'", b->dist_tag);
+
+ printf(" %i", b->karma);
+
+
+/*
+ for (GList *li = b->bz_ids; li; li = li->next)
+ printf(" %i", *(int*) li->data);
+*/
+ puts("");
+}
+#endif
+
+static GList *bodhi_parse_json(json_object *json, const char *release)
+{
+
+ int num_items = 0;
+ bodhi_read_value(json, "num_items", &num_items, BODHI_READ_INT);
+ if (num_items <= 0)
+ return NULL;
+
+ json_object *updates = NULL;
+ bodhi_read_value(json, "updates", &updates, BODHI_READ_JSON_OBJ);
+ if (!updates)
+ return NULL;
+
+ int updates_len = json_object_array_length(updates);
+
+ GList *bodhi_list = NULL;
+ for (int i = 0; i < updates_len; ++i)
+ {
+ json_object *updates_item = json_object_array_get_idx(updates, i);
+
+ /* some of item are null */
+ if (!updates_item)
+ continue;
+
+ struct bodhi *b = xzalloc(sizeof(struct bodhi));
+ bodhi_read_value(updates_item, "date_pushed", &b->date_pushed,
BODHI_READ_STR);
+ bodhi_read_value(updates_item, "karma", &b->karma,
BODHI_READ_INT);
+ bodhi_read_value(updates_item, "status", &b->status,
BODHI_READ_STR);
+
+ json_object *release_item = NULL;
+ bodhi_read_value(updates_item, "release", &release_item,
BODHI_READ_JSON_OBJ);
+ if (release_item)
+ bodhi_read_value(release_item, "dist_tag", &b->dist_tag,
BODHI_READ_STR);
+
+ json_object *bugs = NULL;
+ bodhi_read_value(updates_item, "bugs", &release_item,
BODHI_READ_JSON_OBJ);
+ if (bugs)
+ {
+ for (int j = 0; j < json_object_array_length(bugs); ++j)
+ {
+ int *bz_id = xmalloc(sizeof(int));
+ json_object *bug_item = json_object_array_get_idx(bugs, j);
+ bodhi_read_value(bug_item, "bz_id", bz_id, BODHI_READ_INT);
+ b->bz_ids = g_list_append(b->bz_ids, bz_id);
+ }
+ }
+
+ json_object *builds_item = NULL;
+ bodhi_read_value(updates_item, "builds", &builds_item,
BODHI_READ_JSON_OBJ);
+ if (builds_item)
+ {
+ int builds_len = json_object_array_length(builds_item);
+ for (int k = 0; k < builds_len; ++k)
+ {
+ char *nvr = NULL;
+ json_object *build = json_object_array_get_idx(builds_item, k);
+ bodhi_read_value(build, "nvr", &nvr, BODHI_READ_STR);
+ b->nvr = g_list_append(b->nvr, nvr);
+ }
+ }
+
+ bodhi_list = g_list_append(bodhi_list, b);
+
+// print_bodhi(b);
+ }
+
+ return bodhi_list;
+}
+
+static GList *bodhi_query_list(const char *query, const char *release)
+{
+ char *bodhi_url_bugs = xasprintf(bodhi_url, "list");
+
+ abrt_post_state_t *post_state = new_abrt_post_state(
+ ABRT_POST_WANT_BODY|ABRT_POST_WANT_SSL_VERIFY);
+
+ const char *headers[] = {
+ "Accept: application/json",
+ NULL
+ };
+
+ abrt_post_string(post_state, bodhi_url_bugs,
"application/x-www-form-urlencoded",
+ headers, query);
+ free(bodhi_url_bugs);
+
+// log("%s", post_state->body);
+
+ json_object *json = json_tokener_parse(post_state->body);
+ if (is_error(json))
+ error_msg_and_die("fatal: unable parse response from bodhi server");
+
+ GList *bodhi_list = bodhi_parse_json(json, release);
+ json_object_put(json);
+ free_abrt_post_state(post_state);
+
+ return bodhi_list;
+}
+
+int main(int argc, char **argv)
+{
+ abrt_init(argv);
+
+ char *bugs = NULL, *release = NULL;
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_STRING('b', "bugs", &bugs, "ID1[,ID2,...]" ,
_("List of bug ids")),
+ OPT_STRING('r', "release", &release, "RELEASE",
_("Specify a release")),
+ OPT_END()
+ };
+
+ const char *program_usage_string = _(
+ "\1 [-v] [-r] (-b ID1[,ID2,...] | PKG-NAME) [PKG-NAME]... \n"
+ "\n"
+ "Search for a new updates in bodhi server"
+ );
+
+ /* unsigned opts = */ parse_opts(argc, argv, program_options, program_usage_string);
+
+ if (!bugs && !argv[optind])
+ show_usage_and_die(program_usage_string, program_options);
+
+ struct strbuf *query = strbuf_new();
+ if (bugs)
+ query = strbuf_append_strf(query, "bugs=%s&", bugs);
+
+ if (release)
+ query = strbuf_append_strf(query, "release=%s&", release);
+
+ if (argv[optind])
+ query = strbuf_append_strf(query, "package=%s&", argv[optind]);
+
+ if (query->buf[query->len - 1] == '&')
+ query->buf[query->len - 1] = '\0';
+
+ GList *update_list = bodhi_query_list(query->buf, release);
+ strbuf_free(query);
+
+ if (!update_list)
+ return 0;
+
+ struct strbuf *q = strbuf_new();
+ strbuf_append_str(q, "pkcon --repo-enable=fedora
--repo-repo=updates-testing");
+ for (GList *l = update_list; l; l = l->next)
+ {
+ struct bodhi *b = (struct bodhi *) l->data;
+ for (GList *nvr = b->nvr; nvr; nvr = nvr->next)
+ strbuf_append_strf(q, " %s", (char *) nvr->data);
+ }
+
+ int ret = ask_yes_no(q->buf);
+ if (ret)
+ {
+ log("start downloading pkg and stop reporting");
+ return ret;
+ }
+ strbuf_free(q);
+ free_bodhi_list(update_list);
+ return ret;
+}
diff --git a/src/plugins/analyze_LocalGDB_Bodhi.xml.in
b/src/plugins/analyze_LocalGDB_Bodhi.xml.in
new file mode 100644
index 0000000..6fa480f
--- /dev/null
+++ b/src/plugins/analyze_LocalGDB_Bodhi.xml.in
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<event>
+ <_name>Local GNU Debugger + bodhi client</_name>
+ <_description>write doc</_description>
+ <_long-description>write doc</_long-description>
+ <creates-items>backtrace</creates-items>
+</event>
diff --git a/src/plugins/bodhi_event.conf b/src/plugins/bodhi_event.conf
new file mode 100644
index 0000000..3e0cd79
--- /dev/null
+++ b/src/plugins/bodhi_event.conf
@@ -0,0 +1,10 @@
+EVENT=analyze_LocalGDB_Bodhi analyzer=CCpp
+ abrt-action-analyze-core --core=coredump -o build_ids &&
+ /usr/libexec/abrt-action-install-debuginfo-to-abrt-cache --size_mb=4096
&&
+ abrt-action-generate-backtrace &&
+ abrt-action-analyze-backtrace &&
+ (
+ release=$(rpm --eval '%dist' | cut -d"." -f2) &&
+ bug_id=$(reporter-bugzilla -h `cat duphash`) &&
+ abrt-bodhi -r $release -b $bug_id
+ )
\ No newline at end of file
diff --git a/src/plugins/reporter-bugzilla.c b/src/plugins/reporter-bugzilla.c
index 83995b7..cbd06f7 100644
--- a/src/plugins/reporter-bugzilla.c
+++ b/src/plugins/reporter-bugzilla.c
@@ -252,7 +252,7 @@ int main(int argc, char **argv)
OPT_b = 1 << 4,
};
- char *ticket_no = NULL;
+ char *ticket_no = NULL, *duphash = NULL;
/* Keep enum above and order of options below in sync! */
struct options program_options[] = {
OPT__VERBOSE(&g_verbose),
@@ -260,6 +260,7 @@ int main(int argc, char **argv)
OPT_LIST( 'c', NULL, &conf_file , "FILE",
_("Configuration file (may be given many times)")),
OPT_OPTSTRING('t', "ticket", &ticket_no, "ID" ,
_("Attach FILEs [to bug with this ID]")),
OPT_BOOL( 'b', NULL, NULL, _("When creating
bug, attach binary files too")),
+ OPT_STRING( 'h', "duphash", &duphash,
"DUPHASH", _("Find BUG-ID according to DUPHASH")),
OPT_END()
};
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
@@ -317,9 +318,6 @@ int main(int argc, char **argv)
login = environ ? environ : get_map_string_item_or_empty(settings,
"Login");
environ = getenv("Bugzilla_Password");
password = environ ? environ : get_map_string_item_or_empty(settings,
"Password");
- if (!login[0] || !password[0])
- error_msg_and_die(_("Empty login or password, please check your
configuration"));
-
environ = getenv("Bugzilla_BugzillaURL");
bugzilla_url = environ ? environ : get_map_string_item_or_empty(settings,
"BugzillaURL");
if (!bugzilla_url[0])
@@ -329,6 +327,40 @@ int main(int argc, char **argv)
environ = getenv("Bugzilla_SSLVerify");
ssl_verify = string_to_bool(environ ? environ :
get_map_string_item_or_empty(settings, "SSLVerify"));
+ if (duphash)
+ {
+ char *hash;
+ if (prefixcmp(duphash, "abrt_hash:"))
+ hash = xasprintf("abrt_hash:%s", duphash);
+ else
+ hash = xstrdup(duphash);
+
+ struct abrt_xmlrpc *client = abrt_xmlrpc_new_client(bugzilla_xmlrpc,
ssl_verify);
+
+ /* it's fedora specific */
+ char *query = xasprintf("ALL whiteboard:\"%s\"
product:\"Fedora\"", hash);
+ free(hash);
+
+ xmlrpc_value *result = abrt_xmlrpc_call(client, "Bug.search",
"({s:s})",
+ "quicksearch", query);
+ free(query);
+
+ xmlrpc_value *all_bugs = rhbz_get_member("bugs", result);
+ xmlrpc_DECREF(result);
+
+ int all_bugs_size = rhbz_array_size(all_bugs);
+ if (all_bugs_size > 0)
+ {
+ int bug_id = rhbz_bug_id(all_bugs);
+ printf("%i", bug_id);
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+
+ if (!login[0] || !password[0])
+ error_msg_and_die(_("Empty login or password, please check your
configuration"));
+
if (opts & OPT_t)
{
if (!argv[optind])
--
1.7.7.1.431.g10b2a