From 16b7710b6a8548ca9ab58ca94fce60dcc92c1ba2 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Mon, 8 Feb 2010 20:36:19 +0100 Subject: Add component owner to the output --- src/Backtrace/abrt-bz-dupchecker | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Backtrace/abrt-bz-dupchecker b/src/Backtrace/abrt-bz-dupchecker index cbdafc5..cb11bf1 100755 --- a/src/Backtrace/abrt-bz-dupchecker +++ b/src/Backtrace/abrt-bz-dupchecker @@ -25,6 +25,8 @@ import sys import os.path import subprocess import cPickle +import urllib +import json parser = OptionParser(version="%prog 1.0") parser.add_option("-u", "--user", dest="user", @@ -87,6 +89,7 @@ for buginfo in buginfos: if ids.has_key(buginfo.bug_id): continue + ids[buginfo.bug_id] = True if not buginfo.bug_status in ["NEW", "ASSIGNED", "MODIFIED", "VERIFIED"]: @@ -177,9 +180,17 @@ print "------------------------------" for backtrace, components in database.items(): for component, bugitems in components.items(): if len(bugitems) > 1: + # Get the component owner + component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/packages/name/{0}?tg_format=json".format(buginfo.component))) + component_packages = component_info['packageListings'] + component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) + owner = "Failed to get component owner" + if len(component_f12) == 1: + owner = component_f12["owner"] + if options.wiki: print "----" - print "* component: '''{0}'''".format(component) + print "* component: '''{0}''' ({1})".format(component, owner) print "* duplicates: {0}".format( reduce(lambda x,y: x+", "+y, map(lambda x: "#[https://bugzilla.redhat.com/show_bug.cgi?id={0} {0}] ({1} comments)".format(x['id'],x['comments']), @@ -188,7 +199,7 @@ for backtrace, components in database.items(): for line in backtrace.replace("Thread\n", "").splitlines(): print "*# {0}".format(line) else: - print "Component: {0}".format(component) + print "Component: {0} ({1})".format(component, owner) print "Duplicates: {0}".format( reduce(lambda x,y: x+", "+y, map(lambda x: "{0} ({1})".format(x['id'],x['comments']), -- cgit From fb406ac2bd88b6c02d8bc8a814cc3095b9bd4868 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Mon, 8 Feb 2010 22:22:49 +0100 Subject: GUI: respect system settings for toolbars rhbz#552161 --- src/Gui/ccgui.glade | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/Gui/ccgui.glade b/src/Gui/ccgui.glade index 237f23a..652e6ff 100644 --- a/src/Gui/ccgui.glade +++ b/src/Gui/ccgui.glade @@ -208,7 +208,6 @@ Patrick Connelly <pcon@fedoraproject.org> True - both True @@ -225,7 +224,6 @@ Patrick Connelly <pcon@fedoraproject.org> True - False Report Report gtk-go-up -- cgit From c4425b1a6f3be01c0e7b8d58ebfd2b2df836ed0a Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Tue, 9 Feb 2010 00:14:14 +0100 Subject: GUI: fixed exception in plugin settings dialog rhbz#560851 --- src/Gui/PluginsSettingsDialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Gui/PluginsSettingsDialog.py b/src/Gui/PluginsSettingsDialog.py index 0ba390d..d6129b1 100644 --- a/src/Gui/PluginsSettingsDialog.py +++ b/src/Gui/PluginsSettingsDialog.py @@ -141,7 +141,7 @@ class PluginsSettingsDialog: def on_bConfigurePlugin_clicked(self, button, pluginview): pluginsListStore, path = pluginview.get_selection().get_selected_rows() if not path: - self.builder.get_object("lDescription").set_label(_("Can't get plugin description")) + gui_info_dialog(_("Please select a plugin from the list to edit it's options."), self.window) return # this should work until we keep the row object in the last position pluginfo = pluginsListStore.get_value(pluginsListStore.get_iter(path[0]), pluginsListStore.get_n_columns()-1) -- cgit From 0822de0cd0017929b66a231734e9d01a5e4971ea Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 9 Feb 2010 14:25:37 +0100 Subject: GUI: make text fields in report wnd more consistent (no border for all) Signed-off-by: Denys Vlasenko --- src/Gui/report.glade | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/Gui/report.glade b/src/Gui/report.glade index e7f37ec..cff0dc8 100644 --- a/src/Gui/report.glade +++ b/src/Gui/report.glade @@ -297,7 +297,6 @@ True automatic automatic - in 200 -- cgit From 726a6d328e84b9409acdd57e8575225b2be9ee48 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Tue, 9 Feb 2010 14:35:48 +0100 Subject: GUI: only urls should be clickable --- src/Gui/CCMainWindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index 0d9b0a2..7967028 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -234,7 +234,7 @@ class MainWindow(): for message in dump.getMessage().split(';'): if message: message_clean = message.strip() - if "http" in message_clean[0:5] or "file:///"[0:8] in message_clean: + if "http" in message_clean[0:5] or "file:///" in message_clean[0:8]: report_message = "%s" % (message_clean, message_clean) else: report_message = message_clean -- cgit From ea11e91fd0ddfa51568e9d52e7ce0dc19971c745 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 9 Feb 2010 14:48:27 +0100 Subject: GUI: remove code which unconditionally throws out BIN files Signed-off-by: Denys Vlasenko --- src/Gui/CCReporterDialog.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py index 816164b..bc4a1e0 100644 --- a/src/Gui/CCReporterDialog.py +++ b/src/Gui/CCReporterDialog.py @@ -290,11 +290,11 @@ class ReporterDialog(): self.tevHowToReproduce.set_buffer(buff) def dehydrate(self): - # handle attachments - vbAttachments = self.builder.get_object("vbAttachments") - for attachment in vbAttachments.get_children(): - #print "%s file %s" % (["not sending","sending"][attachment.get_active()], attachment.get_label()) - del self.report[attachment.item] + ## # handle attachments + ## vbAttachments = self.builder.get_object("vbAttachments") + ## for attachment in vbAttachments.get_children(): + ## #print "%s file %s" % (["not sending","sending"][attachment.get_active()], attachment.get_label()) + ## del self.report[attachment.item] # handle comment buff = self.tvComment.get_buffer() -- cgit From e6e28fefb05eb5e2c137fd8eca26f7ba6e011e22 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Tue, 9 Feb 2010 14:58:28 +0100 Subject: Results are sorted by component owner --- src/Backtrace/abrt-bz-dupchecker | 79 ++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/Backtrace/abrt-bz-dupchecker b/src/Backtrace/abrt-bz-dupchecker index cb11bf1..d7798ac 100755 --- a/src/Backtrace/abrt-bz-dupchecker +++ b/src/Backtrace/abrt-bz-dupchecker @@ -157,9 +157,6 @@ for buginfo in buginfos: bz.logout() -print "SUMMARY" -print "==========================================================================" - # The number of duplicates. dupcount = 0 # The number of duplicates that can be closed. @@ -172,36 +169,56 @@ for backtrace, components in database.items(): bugitems))), len(bugitems) - 1) -print "Total number of duplicate bugs detected: {0}".format(dupcount) -print "Number of duplicate bugs that will be closed : {0}".format(dupclosecount) -print "------------------------------" - -# Print the duplicates +# Sort the duplicates by the component owner, and +# filter out those which should not be printed. +dups = [] for backtrace, components in database.items(): for component, bugitems in components.items(): if len(bugitems) > 1: # Get the component owner - component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/packages/name/{0}?tg_format=json".format(buginfo.component))) - component_packages = component_info['packageListings'] - component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) owner = "Failed to get component owner" - if len(component_f12) == 1: - owner = component_f12["owner"] - - if options.wiki: - print "----" - print "* component: '''{0}''' ({1})".format(component, owner) - print "* duplicates: {0}".format( - reduce(lambda x,y: x+", "+y, - map(lambda x: "#[https://bugzilla.redhat.com/show_bug.cgi?id={0} {0}] ({1} comments)".format(x['id'],x['comments']), - bugitems))) - print "* backtrace:" - for line in backtrace.replace("Thread\n", "").splitlines(): - print "*# {0}".format(line) - else: - print "Component: {0} ({1})".format(component, owner) - print "Duplicates: {0}".format( - reduce(lambda x,y: x+", "+y, - map(lambda x: "{0} ({1})".format(x['id'],x['comments']), - bugitems))) - print "Backtrace: {0}".format(backtrace) + try: + component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/packages/name/{0}?tg_format=json".format(component))) + component_packages = component_info['packageListings'] + component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) + if len(component_f12) == 1: + owner = component_f12[0]["owner"] + except KeyError: + pass + + dups.append((component, owner, bugitems, backtrace)) + print ".", + +print +print "SUMMARY" +print "==========================================================================" +print "Total number of duplicate bugs detected: {0}".format(dupcount) +print "Number of duplicate bugs that will be closed : {0}".format(dupclosecount) +print "------------------------------" + +# Print the duplicates sorted by package owner. +def cmp(x, y): + if x[1] < y[1]: + return -1 + elif x[1] == y[1]: + return 0 + else: + return 1 +for (component, owner, bugitems, backtrace) in sorted(dups, cmp): + if options.wiki: + print "----" + print "* component: '''{0}''' ({1})".format(component, owner) + print "* duplicates: {0}".format( + reduce(lambda x,y: x+", "+y, + map(lambda x: "#[https://bugzilla.redhat.com/show_bug.cgi?id={0} {0}] ({1} comments)".format(x['id'],x['comments']), + bugitems))) + print "* backtrace:" + for line in backtrace.replace("Thread\n", "").splitlines(): + print "*# {0}".format(line) + else: + print "Component: {0} ({1})".format(component, owner) + print "Duplicates: {0}".format( + reduce(lambda x,y: x+", "+y, + map(lambda x: "{0} ({1})".format(x['id'],x['comments']), + bugitems))) + print "Backtrace: {0}".format(backtrace) -- cgit From 4df13ffe0f3b9952dcd68263fb51cac842b193b1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 9 Feb 2010 17:07:44 +0100 Subject: cli: fix trivial error counter bug Signed-off-by: Denys Vlasenko --- src/CLI/report.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp index 7ef33ac..6a8f9f4 100644 --- a/src/CLI/report.cpp +++ b/src/CLI/report.cpp @@ -427,12 +427,12 @@ int report(const char *uuid, bool always) // Skip nonReporter plugins. if (0 != strcmp(it->second["Type"].c_str(), "Reporter")) continue; - + map_string_t settings = call_GetPluginSettings(it->first.c_str()); // Login information is missing. - bool loginMissing = settings.find("Login") != settings.end() + bool loginMissing = settings.find("Login") != settings.end() && 0 == strcmp(settings["Login"].c_str(), ""); - bool passwordMissing = settings.find("Password") != settings.end() + bool passwordMissing = settings.find("Password") != settings.end() && 0 == strcmp(settings["Password"].c_str(), ""); if (!loginMissing && !passwordMissing) continue; @@ -461,7 +461,7 @@ int report(const char *uuid, bool always) fgets(answer, sizeof(answer), stdin); if (strlen(answer) > 0) pluginSettings[it->first]["Password"] = answer; - } + } } } @@ -475,7 +475,7 @@ int report(const char *uuid, bool always) vector_string_t &v = it->second; printf("%s: %s\n", it->first.c_str(), v[REPORT_STATUS_IDX_MSG].c_str()); plugins++; - if (v[REPORT_STATUS_IDX_FLAG] != "0") + if (v[REPORT_STATUS_IDX_FLAG] == "0") errors++; it++; } -- cgit From d0f19e435b5a3fecb3fd74b1ba0202364e6dc545 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Tue, 9 Feb 2010 21:51:20 +0100 Subject: GUI: escape plugin messages before using them in set_markup() - if the messages contain tags like it would break the markup and end-up with message like: GtkWarning: Failed to set text from markup due to error parsing markup --- src/Gui/CCMainWindow.py | 3 ++- src/Gui/CC_gui_functions.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index 7967028..c0666f0 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -2,6 +2,7 @@ import sys import pwd import getopt +from glib import markup_escape_text from abrt_utils import _, init_logging, log, log1, log2 import gobject @@ -233,7 +234,7 @@ class MainWindow(): # it is not informative (no URL to the report) for message in dump.getMessage().split(';'): if message: - message_clean = message.strip() + message_clean = markup_escape_text(message.strip()) if "http" in message_clean[0:5] or "file:///" in message_clean[0:8]: report_message = "%s" % (message_clean, message_clean) else: diff --git a/src/Gui/CC_gui_functions.py b/src/Gui/CC_gui_functions.py index 9378de5..acfd2a5 100644 --- a/src/Gui/CC_gui_functions.py +++ b/src/Gui/CC_gui_functions.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from glib import markup_escape_text import gtk import pango import subprocess @@ -66,7 +67,7 @@ def gui_report_dialog ( report_status_dict, parent_dialog, # this first one is actually a fallback to set at least # a raw text in case when set_markup() fails status_label.set_text(report_status_dict[plugin][MESSAGE]) - status_label.set_markup("%s" % report_status_dict[plugin][MESSAGE]) + status_label.set_markup("%s" % markup_escape_text(report_status_dict[plugin][MESSAGE])) # if the report was not succesful then this won't pass so this runs only # if report succeds and gets overwriten by the status message if report_status_dict[plugin][STATUS] == '1': -- cgit From 2a7e09e60a40bc9874c41ceb85856688f5a81099 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Tue, 9 Feb 2010 23:19:15 +0100 Subject: Don't show empty 'Not loaded plugins' section - fix#2 rhbz#560971 --- src/Gui/PluginsSettingsDialog.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/Gui/PluginsSettingsDialog.py b/src/Gui/PluginsSettingsDialog.py index d6129b1..787faee 100644 --- a/src/Gui/PluginsSettingsDialog.py +++ b/src/Gui/PluginsSettingsDialog.py @@ -107,7 +107,7 @@ class PluginsSettingsDialog: # cell_text, toggle_active, toggle_visible, group_name_visible, color, plugin ["%s" % PluginInfo.types[plugin_type], 0, 0, 1, "gray", None]) plugin_rows[plugin_type] = it - group_empty[plugin_type] = 1 + group_empty[plugin_type] = it for entry in pluginlist: if entry.Description: text = "%s\n%s" % (entry.getName(), entry.Description) @@ -118,13 +118,13 @@ class PluginsSettingsDialog: self.pluginsListStore.append(plugin_rows[plugin_type], # cell_text, toggle_active, toggle_visible, group_name_visible, color, plugin [text, entry.Enabled == "yes", 1, 0, "white", entry]) - group_empty[plugin_type] = 0 + if group_empty.has_key(plugin_type): + del group_empty[plugin_type] # rhbz#560971 "Don't show empty 'Not loaded plugins' section" - for plugin_type in group_empty.keys(): - if group_empty[plugin_type]: - self.pluginsListStore.append(plugin_rows[plugin_type], - # cell_text, toggle_active, toggle_visible, group_name_visible, color, plugin - ["(none)", 0, 1, 0, "white", None]) + # don't show any empty groups + for it in group_empty.values(): + self.pluginsListStore.remove(it) + self.pluginlist.expand_all() def dehydrate(self): -- cgit From 1d41334f27073ebe851f88847f5578fed42fa6d6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 11 Feb 2010 17:44:53 +0100 Subject: fix bz#563484 "abrt uses unnecessary disk space when getting debug info" Signed-off-by: Denys Vlasenko --- src/Daemon/abrt-debuginfo-install | 83 +++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/Daemon/abrt-debuginfo-install b/src/Daemon/abrt-debuginfo-install index 35f4d6a..3bb9c41 100755 --- a/src/Daemon/abrt-debuginfo-install +++ b/src/Daemon/abrt-debuginfo-install @@ -145,7 +145,9 @@ print_package_names() { fi # when we look for debuginfo we need only -debuginfo* repos, so we can disable the rest and thus make it faster # also we want only fedora repositories, because abrt won't work for other packages anyway - local cmd="yum $yumopts '--disablerepo=*' '--enablerepo=fedora-debuginfo*' '--enablerepo=updates-debuginfo*' --quiet provides $missing_debuginfo_files" + # --showduplicates: do not just show the latest package + # -R2: wait two minutes max (hopefully this prevents infinite hang on yum lock) + local cmd="yum $yumopts '--disablerepo=*' '--enablerepo=fedora-debuginfo*' '--enablerepo=updates-debuginfo*' --showduplicates -R2 --quiet provides $missing_debuginfo_files" echo "$cmd" >"yum_provides.$1.OUT" # eval is needed to strip away ''s; cant remove them above and just use # $cmd, that would perform globbing on '*' @@ -194,53 +196,56 @@ download_packages() { for pkg in $packages; do echo "Download $i/$num_packages: $pkg" echo "Download $i/$num_packages: $pkg" >>yumdownloader.OUT - # we can't handle packages from non Fedora repos, so we look and download only + # We can't handle packages from non Fedora repos, so we look and download only # from Fedora repos which makes it faster yumdownloader --disablerepo="*" --enablerepo="fedora-debuginfo*" --enablerepo="updates-debuginfo*" --quiet $pkg >>yumdownloader.OUT 2>&1 err=$? echo "exitcode:$err" >>yumdownloader.OUT echo >>yumdownloader.OUT test $err = 0 || { echo "Download of $pkg failed!"; sleep 1; } - : $((i++)) - done - - for file in *.rpm; do - # Happens if no .rpm's were downloaded (yumdownloader problem) - # In this case, $f is the literal "*.rpm" string - test -f "$file" || error_msg_and_die "not a rpm file: '$file'" - echo "Unpacking: $file" - echo "Processing: $file" >>unpack.OUT - rpm2cpio <"$file" 2>>unpack.OUT | cpio -id >>unpack.OUT 2>&1 -#TODO: error check? - done - - # Copy debuginfo files to cachedir - if test x"$cachedir" != x"" && test -d "$cachedir"; then - for build_id in $build_ids; do - build_id1=${build_id:0:2} - build_id2=${build_id:2} - - file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug" - - # Do not copy it if it can be found in any of $debuginfodirs - test -f "/$file" && continue - if test x"$cachedir" != x""; then - for d in $debuginfodirs; do - test -f "$d/$file" && continue 2 + # Process and delete the *.rpm file just downloaded + # We do it right after download: some users have smallish disks... + for file in *.rpm; do + # Happens if no .rpm's were downloaded (yumdownloader problem) + # In this case, $f is the literal "*.rpm" string + test -f "$file" || { echo "No rpm file downloaded"; continue; } + echo "Unpacking: $file" + echo "Processing: $file" >>unpack.OUT + rpm2cpio <"$file" >"unpacked.cpio" 2>>unpack.OUT || error_msg_and_die "Can't convert '$file' to cpio" + rm "$file" + cpio -id <"unpacked.cpio" >>unpack.OUT 2>&1 || error_msg_and_die "Can't unpack '$file' cpio archive" + rm "unpacked.cpio" + # Copy debuginfo files to cachedir + if test x"$cachedir" != x"" && test -d "$cachedir"; then + # For every needed debuginfo, check whether we have it + for build_id in $build_ids; do + build_id1=${build_id:0:2} + build_id2=${build_id:2} + file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug" + # Do not copy it if it can be found in any of $debuginfodirs + test -f "/$file" && continue + if test x"$cachedir" != x""; then + for d in $debuginfodirs; do + test -f "$d/$file" && continue 2 + done + fi + if test -f "$file"; then + # File is one of those we just installed, cache it + mkdir -p "$cachedir/usr/lib/debug/.build-id/$build_id1" + # Note: this does not preserve symlinks. This is intentional + $debug && echo Copying "$file" to "$cachedir/$file" >&2 + echo "Caching debuginfo: $file" + cp --remove-destination "$file" "$cachedir/$file" || error_msg_and_die "Can't copy $file (disk full?)" + continue + fi done fi - - if test -f "$file"; then - # File is one of those we just installed, cache it. - mkdir -p "$cachedir/usr/lib/debug/.build-id/$build_id1" - # Note: this does not preserve symlinks. This is intentional - $debug && echo Copying "$file" to "$cachedir/$file" >&2 - cp --remove-destination "$file" "$cachedir/$file" -#TODO: error check? - continue - fi + # Delete remaining files unpacked from .cpio + # which we didn't need after all + rm -r etc bin sbin usr var opt 2>/dev/null done - fi + : $((i++)) + done } -- cgit From bdfbf7ea8b427a03dee94cb0f071f66c6fa436f0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 11 Feb 2010 18:15:14 +0100 Subject: fix bz#554242 "Cannot tab between input areas in report dialog" Signed-off-by: Denys Vlasenko --- src/Gui/report.glade | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/Gui/report.glade b/src/Gui/report.glade index cff0dc8..7b3aac4 100644 --- a/src/Gui/report.glade +++ b/src/Gui/report.glade @@ -302,6 +302,7 @@ 200 True True + False @@ -377,6 +378,7 @@ True True word-char + False @@ -414,6 +416,7 @@ True True word-char + False -- cgit From b2903ca6b5ddf65d4e9f390649797546568c0170 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 11 Feb 2010 19:49:46 +0100 Subject: fix bz#541088 "abrt should not catch python excp EPIPE" Signed-off-by: Denys Vlasenko --- src/Hooks/abrt_exception_handler.py.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src') diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in index 89f3013..b5e15b8 100644 --- a/src/Hooks/abrt_exception_handler.py.in +++ b/src/Hooks/abrt_exception_handler.py.in @@ -59,8 +59,22 @@ def handleMyException((etype, value, tb)): return sys.__excepthook__(etype, value, tb) try: + import os import os.path import traceback + import errno + + # EPIPE is not a crash, it happens all the time + # Testcase: script.py | true, where script.py is: + ## #!/usr/bin/python + ## import os + ## import time + ## time.sleep(1) + ## os.write(1, "Hello\n") # print "Hello" wouldn't be the same + # + if etype == IOError or etype == OSError: + if value.errno == errno.EPIPE: + return sys.__excepthook__(etype, value, tb) # "-c" appears in this case: # $ python -c 'import sys; print "argv0 is:%s" % sys.argv[0]' -- cgit From 3f50601035b949db58b336e693362b0dbf1c870f Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Fri, 12 Feb 2010 11:06:08 +0100 Subject: fixed problem with bugzilla+nss - it's more workaround which makes rpmlib to reinitialize nss hash functions and that make xmlrpc works properly after fork() we need to find a proper place to fix this! --- src/Daemon/Settings.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Daemon/Settings.cpp b/src/Daemon/Settings.cpp index 9b0376b..5644d37 100644 --- a/src/Daemon/Settings.cpp +++ b/src/Daemon/Settings.cpp @@ -376,8 +376,16 @@ void LoadSettings() ParseCommon(); ParseAnalyzerActionsAndReporters(); ParseCron(); - if(g_settings_bOpenGPGCheck) - LoadGPGKeys(); + + /* + loading gpg keys will invoke LoadOpenGPGPublicKey() from rpm.cpp + pgpReadPkts which makes nss to re-init and thus makes + bugzilla plugin work :-/ + */ + + //FIXME FIXME FIXME FIXME FIXME FIXME!!! + //if(g_settings_bOpenGPGCheck) + LoadGPGKeys(); } /* dbus call to retrieve .conf file data from daemon */ -- cgit From ea024040e517732f4c1195f9d804624d3a876671 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Fri, 12 Feb 2010 13:25:32 +0100 Subject: Remove newline from user input, separate run_report_editor from the report --- src/CLI/report.cpp | 183 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 122 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp index 6a8f9f4..39eccfb 100644 --- a/src/CLI/report.cpp +++ b/src/CLI/report.cpp @@ -300,7 +300,12 @@ static int read_crash_report(map_crash_data_t &report, const char *text) return result; } -/* Runs external editor. */ +/** + * Runs external editor. + * Returns: + * 0 if the launch was successful + * 1 if it failed. The error reason is logged using error_msg() + */ static int launch_editor(const char *path) { const char *editor, *terminal; @@ -330,6 +335,85 @@ static int launch_editor(const char *path) return 0; } +/** + * Returns: + * 0 on success, crash data has been updated + * 2 on failure, unable to create, open, or close temporary file + * 3 on failure, cannot launch text editor + */ +static int run_report_editor(map_crash_data_t &cr) +{ + /* Open a temporary file and write the crash report to it. */ + char filename[] = "/tmp/abrt-report.XXXXXX"; + int fd = mkstemp(filename); + if (fd == -1) /* errno is set */ + { + perror_msg("can't generate temporary file name"); + return 2; + } + + FILE *fp = fdopen(fd, "w"); + if (!fp) /* errno is set */ + { + perror_msg("can't open '%s' to save the crash report", filename); + return 2; + } + + write_crash_report(cr, fp); + + if (fclose(fp)) /* errno is set */ + { + perror_msg("can't close '%s'", filename); + return 2; + } + + // Start a text editor on the temporary file. + if (launch_editor(filename) != 0) + return 3; /* exit with error */ + + // Read the file back and update the report from the file. + fp = fopen(filename, "r"); + if (!fp) /* errno is set */ + { + perror_msg("can't open '%s' to read the crash report", filename); + return 2; + } + + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + char *text = (char*)xmalloc(size + 1); + if (fread(text, 1, size, fp) != size) + { + error_msg("can't read '%s'", filename); + return 2; + } + text[size] = '\0'; + if (fclose(fp) != 0) /* errno is set */ + { + perror_msg("can't close '%s'", filename); + return 2; + } + + // Delete the tempfile. + if (unlink(filename) == -1) /* errno is set */ + { + perror_msg("can't unlink %s", filename); + } + + remove_comments_and_unescape(text); + // Updates the crash report from the file text. + int report_changed = read_crash_report(cr, text); + free(text); + if (report_changed) + puts(_("\nThe report has been updated.")); + else + puts(_("\nNo changes were detected in the report.")); + + return 0; +} + /* Reports the crash with corresponding uuid over DBus. */ int report(const char *uuid, bool always) { @@ -337,69 +421,17 @@ int report(const char *uuid, bool always) map_crash_data_t cr = call_CreateReport(uuid); //TODO: error check? + /* Open text editor and give a chance to review the backtrace etc. */ if (!always) { - /* Open a temporary file and write the crash report to it. */ - char filename[] = "/tmp/abrt-report.XXXXXX"; - int fd = mkstemp(filename); - if (fd == -1) - { - error_msg("can't generate temporary file name"); - return 1; - } - - FILE *fp = fdopen(fd, "w"); - if (!fp) - { - error_msg("can't open '%s' to save the crash report", filename); - return 1; - } - - write_crash_report(cr, fp); - - if (fclose(fp)) - { - error_msg("can't close '%s'", filename); - return 2; - } - - // Start a text editor on the temporary file. - launch_editor(filename); - - // Read the file back and update the report from the file. - fp = fopen(filename, "r"); - if (!fp) - { - error_msg("can't open '%s' to read the crash report", filename); - return 1; - } - - fseek(fp, 0, SEEK_END); - long size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - char *text = (char*)xmalloc(size + 1); - if (fread(text, 1, size, fp) != size) - { - error_msg("can't read '%s'", filename); - return 1; - } - text[size] = '\0'; - fclose(fp); - - remove_comments_and_unescape(text); - // Updates the crash report from the file text. - int report_changed = read_crash_report(cr, text); - if (report_changed) - puts(_("\nThe report has been updated.")); - else - puts(_("\nNo changes were detected in the report.")); - - free(text); - - if (unlink(filename) != 0) // Delete the tempfile. - perror_msg("can't unlink %s", filename); + int result = run_report_editor(cr); + if (result != 0) + return result; + } + /* Ask if user really want to send the report. */ + if (!always) + { // Report only if the user is sure. printf(_("Do you want to send the report? [y/N]: ")); fflush(NULL); @@ -413,6 +445,25 @@ int report(const char *uuid, bool always) } map_map_string_t pluginSettings; +/* + std::string home; + map_plugin_settings_t oldSettings; + map_plugin_settings_t newSettings; + + if (pUID != "") + { + home = get_home_dir(xatoi_u(pUID.c_str())); + if (home != "") + { + oldSettings = reporter->GetSettings(); + + if (LoadPluginSettings(home + "/.abrt/" + plugin_name + "."PLUGINS_CONF_EXTENSION, newSettings)) + { + reporter->SetSettings(newSettings); + } + } + } +*/ if (!always) { // Get informations about all plugins. @@ -449,6 +500,11 @@ int report(const char *uuid, bool always) fflush(NULL); char answer[64] = ""; fgets(answer, sizeof(answer), stdin); + // Remove the newline from the login. + char *newline = strchr(answer, '\n'); + if (newline) + *newline = '\0'; + // Push it to plugin settings. if (strlen(answer) > 0) pluginSettings[it->first]["Login"] = answer; } @@ -459,6 +515,11 @@ int report(const char *uuid, bool always) fflush(NULL); char answer[64] = ""; fgets(answer, sizeof(answer), stdin); + // Remove the newline from the login. + char *newline = strchr(answer, '\n'); + if (newline) + *newline = '\0'; + // Push it to plugin settings. if (strlen(answer) > 0) pluginSettings[it->first]["Password"] = answer; } -- cgit From a4ff7719867332304e5b44d7e24e3333dab256b6 Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Fri, 12 Feb 2010 16:08:30 +0100 Subject: Move LoadPluginSettings to the shared utils library. Add parameter skipKeysWithoutValue. --- src/Daemon/PluginManager.cpp | 54 -------------------------------------------- src/Daemon/PluginManager.h | 9 -------- 2 files changed, 63 deletions(-) (limited to 'src') diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp index e63cb3a..f01d943 100644 --- a/src/Daemon/PluginManager.cpp +++ b/src/Daemon/PluginManager.cpp @@ -80,60 +80,6 @@ static const char *const plugin_type_str[] = { }; -bool LoadPluginSettings(const char *pPath, map_plugin_settings_t& pSettings) -{ - FILE *fp = fopen(pPath, "r"); - if (!fp) - return false; - - char line[512]; - while (fgets(line, sizeof(line), fp)) - { - strchrnul(line, '\n')[0] = '\0'; - unsigned ii; - bool is_value = false; - bool valid = false; - bool in_quote = false; - string key; - string value; - for (ii = 0; line[ii] != '\0'; ii++) - { - if (line[ii] == '"') - { - in_quote = !in_quote; - } - if (isspace(line[ii]) && !in_quote) - { - continue; - } - if (line[ii] == '#' && !in_quote && key == "") - { - break; - } - if (line[ii] == '=' && !in_quote) - { - is_value = true; - continue; - } - if (!is_value) - { - key += line[ii]; - } - else - { - valid = true; - value += line[ii]; - } - } - if (valid && !in_quote) - { - pSettings[key] = value; - } - } - fclose(fp); - return true; -} - /** * A function. It saves settings. On success it returns true, otherwise returns false. * @param path A path of config file. diff --git a/src/Daemon/PluginManager.h b/src/Daemon/PluginManager.h index b5dcebc..bf6952f 100644 --- a/src/Daemon/PluginManager.h +++ b/src/Daemon/PluginManager.h @@ -154,13 +154,4 @@ class CPluginManager map_plugin_settings_t GetPluginSettings(const char *pName); }; -/** - * Loads settings and stores it in second parameter. On success it - * returns true, otherwise returns false. - * @param path A path of config file. - * @param settings A readed plugin's settings. - * @return if it success it returns true, otherwise it returns false. - */ -bool LoadPluginSettings(const char *pPath, - map_plugin_settings_t& pSettings); #endif /*PLUGINMANAGER_H_*/ -- cgit From 84e194ff23222f2fef7dc0918a2dedd005ecd72b Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Fri, 12 Feb 2010 16:09:21 +0100 Subject: Load plugin settings also from ~/.abrt/*.conf --- src/CLI/report.cpp | 196 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp index 39eccfb..ebade16 100644 --- a/src/CLI/report.cpp +++ b/src/CLI/report.cpp @@ -21,6 +21,7 @@ #include "abrtlib.h" #include "DebugDump.h" #include "CrashTypes.h" // FILENAME_* defines +#include "Plugin.h" // LoadPluginSettings #if HAVE_CONFIG_H # include #endif @@ -414,6 +415,115 @@ static int run_report_editor(map_crash_data_t &cr) return 0; } +/** + * Asks user for a text response. + * @param question + * Question displayed to user. + * @param result + * Output array. + * @param result_size + * Maximum byte count to be written. + */ +static void read_from_stdin(const char *question, char *result, int result_size) +{ + printf(question); + fflush(NULL); + fgets(result, result_size, stdin); + // Remove the newline from the login. + char *newline = strchr(result, '\n'); + if (newline) + *newline = '\0'; +} + +/** + * Gets reporter plugin settings. + * @param ask_user + * If it's set to true and some reporter plugin settings are found to be missing + * (like login name or password), user is asked to provide the missing parts. + * @param settings + * A structure filled with reporter plugin settings. + */ +static void get_reporter_plugin_settings(map_map_string_t &settings, bool ask_user) +{ + /* First of all, load system-wide report plugin settings. */ + // Get informations about all plugins. + map_map_string_t plugins = call_GetPluginsInfo(); + // Check the configuration of each enabled Reporter plugin. + map_map_string_t::iterator it, itend = plugins.end(); + for (it = plugins.begin(); it != itend; ++it) + { + // Skip disabled plugins. + if (0 != strcmp(it->second["Enabled"].c_str(), "yes")) + continue; + // Skip nonReporter plugins. + if (0 != strcmp(it->second["Type"].c_str(), "Reporter")) + continue; + map_string_t single_plugin_settings = call_GetPluginSettings(it->first.c_str()); + // Copy the received settings as defaults. + // Plugins won't work without it, if some value is missing + // they use their default values for all fields. + settings[it->first] = single_plugin_settings; + } + + /* Second, load user-specific settings, which override + the system-wide settings. */ + struct passwd* pw = getpwuid(geteuid()); + const char* homedir = pw ? pw->pw_dir : NULL; + if (homedir) + { + itend = settings.end(); + for (it = settings.begin(); it != itend; ++it) + { + map_string_t single_plugin_settings; + std::string path = std::string(homedir) + "/.abrt/" + + it->first + "."PLUGINS_CONF_EXTENSION; + /* Load plugin config in the home dir. Do not skip lines with empty value (but containing a "key="), + because user may want to override password from /etc/abrt/plugins/*.conf, but he prefers to + enter it every time he reports. */ + bool success = LoadPluginSettings(path.c_str(), single_plugin_settings, false); + if (!success) + continue; + // Merge user's plugin settings into already loaded settings. + map_string_t::const_iterator valit, valitend = single_plugin_settings.end(); + for (valit = single_plugin_settings.begin(); valit != valitend; ++valit) + it->second[valit->first] = valit->second; + } + } + + if (!ask_user) + return; + + /* Third, check if a login or password is missing, + and ask for it. */ + itend = settings.end(); + for (it = settings.begin(); it != itend; ++it) + { + map_string_t &single_plugin_settings = it->second; + // Login information is missing. + bool loginMissing = single_plugin_settings.find("Login") != single_plugin_settings.end() + && 0 == strcmp(single_plugin_settings["Login"].c_str(), ""); + bool passwordMissing = single_plugin_settings.find("Password") != single_plugin_settings.end() + && 0 == strcmp(single_plugin_settings["Password"].c_str(), ""); + if (!loginMissing && !passwordMissing) + continue; + + // Read the missing information and push it to plugin settings. + printf(_("Wrong settings were detected for plugin %s.\n"), it->first.c_str()); + char result[64]; + if (loginMissing) + { + read_from_stdin(_("Enter your login: "), result, 64); + single_plugin_settings["Login"] = std::string(result); + } + if (passwordMissing) + { +// TODO: echo off, see http://fixunix.com/unix/84474-echo-off.html + read_from_stdin(_("Enter your password: "), result, 64); + single_plugin_settings["Password"] = std::string(result); + } + } +} + /* Reports the crash with corresponding uuid over DBus. */ int report(const char *uuid, bool always) { @@ -429,6 +539,10 @@ int report(const char *uuid, bool always) return result; } + /* Read the plugin settings. */ + map_map_string_t pluginSettings; + get_reporter_plugin_settings(pluginSettings, !always); + /* Ask if user really want to send the report. */ if (!always) { @@ -444,88 +558,6 @@ int report(const char *uuid, bool always) } } - map_map_string_t pluginSettings; -/* - std::string home; - map_plugin_settings_t oldSettings; - map_plugin_settings_t newSettings; - - if (pUID != "") - { - home = get_home_dir(xatoi_u(pUID.c_str())); - if (home != "") - { - oldSettings = reporter->GetSettings(); - - if (LoadPluginSettings(home + "/.abrt/" + plugin_name + "."PLUGINS_CONF_EXTENSION, newSettings)) - { - reporter->SetSettings(newSettings); - } - } - } -*/ - if (!always) - { - // Get informations about all plugins. - map_map_string_t plugins = call_GetPluginsInfo(); - // Check the configuration of each enabled Reporter plugin. - map_map_string_t::iterator it, itend = plugins.end(); - for (it = plugins.begin(); it != itend; ++it) - { - // Skip disabled plugins. - if (0 != strcmp(it->second["Enabled"].c_str(), "yes")) - continue; - // Skip nonReporter plugins. - if (0 != strcmp(it->second["Type"].c_str(), "Reporter")) - continue; - - map_string_t settings = call_GetPluginSettings(it->first.c_str()); - // Login information is missing. - bool loginMissing = settings.find("Login") != settings.end() - && 0 == strcmp(settings["Login"].c_str(), ""); - bool passwordMissing = settings.find("Password") != settings.end() - && 0 == strcmp(settings["Password"].c_str(), ""); - if (!loginMissing && !passwordMissing) - continue; - - // Copy the received settings as defaults. - // Plugins won't work without it, if some value is missing - // they use their default values for all fields. - pluginSettings[it->first] = settings; - - printf(_("Wrong settings were detected for plugin %s.\n"), it->second["Name"].c_str()); - if (loginMissing) - { - printf(_("Enter your login: ")); - fflush(NULL); - char answer[64] = ""; - fgets(answer, sizeof(answer), stdin); - // Remove the newline from the login. - char *newline = strchr(answer, '\n'); - if (newline) - *newline = '\0'; - // Push it to plugin settings. - if (strlen(answer) > 0) - pluginSettings[it->first]["Login"] = answer; - } - if (passwordMissing) - { -// TODO: echo off, see http://fixunix.com/unix/84474-echo-off.html - printf(_("Enter your password: ")); - fflush(NULL); - char answer[64] = ""; - fgets(answer, sizeof(answer), stdin); - // Remove the newline from the login. - char *newline = strchr(answer, '\n'); - if (newline) - *newline = '\0'; - // Push it to plugin settings. - if (strlen(answer) > 0) - pluginSettings[it->first]["Password"] = answer; - } - } - } - int errors = 0; int plugins = 0; puts(_("Reporting...")); -- cgit From 78b940643724e2ea9dc32cadfc2750ea3af571a5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 12 Feb 2010 17:52:11 +0100 Subject: abrt-hook-ccpp: do not consider SIGQUIT to be a crash Signed-off-by: Denys Vlasenko --- src/Hooks/abrt-hook-ccpp.cpp | 60 +++++++++++++++++++++++------------------- src/Hooks/abrt-hook-python.cpp | 15 ----------- 2 files changed, 33 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/Hooks/abrt-hook-ccpp.cpp b/src/Hooks/abrt-hook-ccpp.cpp index 9d1dc19..d21b8e6 100644 --- a/src/Hooks/abrt-hook-ccpp.cpp +++ b/src/Hooks/abrt-hook-ccpp.cpp @@ -82,31 +82,52 @@ int main(int argc, char** argv) /* set to max possible >0 value */ ulimit_c = ~((off_t)1 << (sizeof(off_t)*8-1)); } - off_t core_size = 0; - if (errno || pid <= 0) { error_msg_and_die("pid '%s' or limit '%s' is bogus", argv[2], argv[5]); } + char* executable = get_executable(pid); + if (executable == NULL) + { + error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); + } + if (strstr(executable, "/abrt-hook-ccpp")) + { + error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", + (long)pid, executable); + } + + char *user_pwd = get_cwd(pid); /* may be NULL on error */ + + /* Parse abrt.conf and plugins/CCpp.conf */ + unsigned setting_MaxCrashReportsSize = 0; + bool setting_MakeCompatCore = false; + parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); + + int core_fd = STDIN_FILENO; + off_t core_size = 0; + const char *signame = NULL; /* Tried to use array for this but C++ does not support v[] = { [IDX] = "str" } */ switch (signal_no) { - case SIGQUIT: signame = "QUIT"; break; case SIGILL : signame = "ILL" ; break; - case SIGABRT: signame = "ABRT"; break; case SIGFPE : signame = "FPE" ; break; case SIGSEGV: signame = "SEGV"; break; + case SIGBUS : signame = "BUS" ; break; //Bus error (bad memory access) + case SIGABRT: signame = "ABRT"; break; //usually when abort() was called + //case SIGQUIT: signame = "QUIT"; break; //Quit from keyboard + //case SIGSYS : signame = "SYS" ; break; //Bad argument to routine (SVr4) + //case SIGTRAP: signame = "TRAP"; break; //Trace/breakpoint trap + //case SIGXCPU: signame = "XCPU"; break; //CPU time limit exceeded (4.2BSD) + //case SIGXFSZ: signame = "XFSZ"; break; //File size limit exceeded (4.2BSD) } if (signame == NULL) { - /* not a signal we care about, exit silently */ - return 0; + /* not a signal we care about */ + goto create_user_core; } - char *user_pwd = get_cwd(pid); /* may be NULL on error */ - int core_fd = STDIN_FILENO; - if (!daemon_is_ok()) { /* not an error, exit with exitcode 0 */ @@ -119,22 +140,6 @@ int main(int argc, char** argv) try { - char* executable = get_executable(pid); - if (executable == NULL) - { - error_msg_and_die("can't read /proc/%lu/exe link", (long)pid); - } - if (strstr(executable, "/abrt-hook-ccpp")) - { - error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion", - (long)pid, executable); - } - - /* Parse abrt.conf and plugins/CCpp.conf */ - unsigned setting_MaxCrashReportsSize = 0; - bool setting_MakeCompatCore = false; - parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore); - if (setting_MaxCrashReportsSize > 0) { check_free_space(setting_MaxCrashReportsSize); @@ -267,8 +272,6 @@ int main(int argc, char** argv) trim_debug_dumps(setting_MaxCrashReportsSize, path); } - if (!setting_MakeCompatCore) - return 0; /* fall through to creating user core */ } catch (CABRTException& e) @@ -282,6 +285,9 @@ int main(int argc, char** argv) create_user_core: + if (!setting_MakeCompatCore) + return 0; + /* note: core_size may be == 0 ("unknown") */ if (core_size > ulimit_c || ulimit_c == 0) return 0; diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp index 356174f..3445954 100644 --- a/src/Hooks/abrt-hook-python.cpp +++ b/src/Hooks/abrt-hook-python.cpp @@ -37,21 +37,6 @@ static char *pid; static char *executable; -// Note: "" will return false -static bool isxdigit_str(const char *str) -{ - do { - if ((*str < '0' || *str > '9') // not a digit - && ((*str | 0x20) < 'a' || (*str | 0x20) > 'f') // not A-F or a-f - ) - { - return false; - } - str++; - } while (*str); - return true; -} - static bool printable_str(const char *str) { do { -- cgit From 1e62058198dfc1d299117742c4bddc7441c2f076 Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Sun, 14 Feb 2010 17:39:56 +0100 Subject: GUI: enabled searching in the main window - just write the package name --- src/Gui/ccgui.glade | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/Gui/ccgui.glade b/src/Gui/ccgui.glade index 652e6ff..3050d65 100644 --- a/src/Gui/ccgui.glade +++ b/src/Gui/ccgui.glade @@ -265,6 +265,8 @@ Patrick Connelly <pcon@fedoraproject.org> True True + True + 1 -- cgit From ff954f994bba93c4664c6ef0bd1bbbe492ffb21a Mon Sep 17 00:00:00 2001 From: Jiri Moskovcak Date: Mon, 15 Feb 2010 11:51:24 +0100 Subject: GUI: enabled column sorting rhbz#541853 --- src/Gui/CCMainWindow.py | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index c0666f0..dfcfaf1 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -65,12 +65,18 @@ class MainWindow(): #init the dumps treeview self.dlist = self.wTree.get_widget("tvDumps") #rows of items with: - #icon, package_name, application, date, crash_rate, user, is_reported, ?object? - self.dumpsListStore = gtk.ListStore(gtk.gdk.Pixbuf, str,str,str,str,str,bool, object) - # set filter - modelfilter = self.dumpsListStore.filter_new() - modelfilter.set_visible_func(self.filter_dumps, None) - self.dlist.set_model(modelfilter) + ICON_COL = 0 + PACKAGE_COL = 1 + APPLICATION_COL = 2 + TIME_STR_COL = 3 + CRASH_RATE_COL = 4 + USER_COL = 5 + IS_REPORTED_COL = 6 + UNIX_TIME_COL = 7 + DUMP_OBJECT_COL = 8 + #icon, package_name, application, date, crash_rate, user, is_reported, time_in_sec ?object? + self.dumpsListStore = gtk.ListStore(gtk.gdk.Pixbuf, str,str,str,str,str,bool, int, object) + self.dlist.set_model(self.dumpsListStore) # add pixbuff separatelly icon_column = gtk.TreeViewColumn(_("Icon")) icon_column.cell = gtk.CellRendererPixbuf() @@ -79,13 +85,17 @@ class MainWindow(): icon_column.pack_start(icon_column.cell, False) icon_column.set_attributes(icon_column.cell, pixbuf=(n-1), cell_background_set=6) # =============================================== - columns = [None]*4 - columns[0] = gtk.TreeViewColumn(_("Package")) - columns[1] = gtk.TreeViewColumn(_("Application")) - columns[2] = gtk.TreeViewColumn(_("Date")) - columns[3] = gtk.TreeViewColumn(_("Crash count")) - column = gtk.TreeViewColumn(_("User")) - columns.append(column) + columns = [] + columns.append(gtk.TreeViewColumn(_("Package"))) + columns[-1].set_sort_column_id(PACKAGE_COL) + columns.append(gtk.TreeViewColumn(_("Application"))) + columns[-1].set_sort_column_id(APPLICATION_COL) + columns.append(gtk.TreeViewColumn(_("Date"))) + columns[-1].set_sort_column_id(UNIX_TIME_COL) + columns.append(gtk.TreeViewColumn(_("Crash count"))) + columns[-1].set_sort_column_id(CRASH_RATE_COL) + columns.append(gtk.TreeViewColumn(_("User"))) + columns[-1].set_sort_column_id(USER_COL) # create list for column in columns: n = self.dlist.append_column(column) @@ -205,7 +215,7 @@ class MainWindow(): except Exception, ex: user = "UID: %s" % entry.getUID() n = self.dumpsListStore.append([icon, entry.getPackage(), entry.getExecutable(), - entry.getTime("%c"), entry.getCount(), user, entry.isReported(), entry]) + entry.getTime("%c"), entry.getCount(), user, entry.isReported(), entry.getTime(""), entry]) # activate the first row if any.. if n: # we can use (0,) as path for the first row, but what if API changes? -- cgit From ba32bbb864eec78e0d17f5a75fc3a58d5762d04a Mon Sep 17 00:00:00 2001 From: Karel Klic Date: Mon, 15 Feb 2010 15:07:24 +0100 Subject: Added option to close bugs recognized as a duplicate: --close --- src/Backtrace/abrt-bz-dupchecker | 79 ++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/Backtrace/abrt-bz-dupchecker b/src/Backtrace/abrt-bz-dupchecker index d7798ac..dc2ef8e 100755 --- a/src/Backtrace/abrt-bz-dupchecker +++ b/src/Backtrace/abrt-bz-dupchecker @@ -33,10 +33,12 @@ parser.add_option("-u", "--user", dest="user", help="Bugzilla user name (REQUIRED)", metavar="USERNAME") parser.add_option("-p", "--password", dest="password", help="Bugzilla password (REQUIRED)", metavar="PASSWORD") -parser.add_option("-b", "--bugzilla", dest="bugzilla", +parser.add_option("-b", "--bugzilla", dest="bugzilla", default="https://bugzilla.redhat.com/xmlrpc.cgi", help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") parser.add_option("-v", "--verbose", dest="verbose", help="Detailed output") +parser.add_option("-c", "--close", help="Close some of the bugs in Bugzilla (DANGEROUS)", + action="store_true", default=False, dest="close") parser.add_option("-i", "--wiki", help="Generate output in wiki syntax", action="store_true", default=False, dest="wiki") @@ -48,9 +50,6 @@ if not options.user or len(options.user) == 0: if not options.password or len(options.password) == 0: parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) -if not options.bugzilla or len(options.bugzilla) == 0: - options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi" - bz = RHBugzilla() bz.connect(options.bugzilla) bz.login(options.user, options.password) @@ -155,8 +154,6 @@ for buginfo in buginfos: else: database[backtrace] = { buginfo.component: [ bugitem ] } -bz.logout() - # The number of duplicates. dupcount = 0 # The number of duplicates that can be closed. @@ -168,26 +165,67 @@ for backtrace, components in database.items(): map(lambda x: x["comments"], bugitems))), len(bugitems) - 1) - + +# Get the component owner. # Sort the duplicates by the component owner, and # filter out those which should not be printed. dups = [] for backtrace, components in database.items(): for component, bugitems in components.items(): - if len(bugitems) > 1: - # Get the component owner - owner = "Failed to get component owner" - try: - component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/packages/name/{0}?tg_format=json".format(component))) - component_packages = component_info['packageListings'] - component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) - if len(component_f12) == 1: - owner = component_f12[0]["owner"] - except KeyError: - pass + if len(bugitems) <= 1: + continue + + # Get the component owner + owner = "Failed to get component owner" + try: + component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/packages/name/{0}?tg_format=json".format(component))) + component_packages = component_info['packageListings'] + component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) + if len(component_f12) == 1: + owner = component_f12[0]["owner"] + except KeyError: + pass - dups.append((component, owner, bugitems, backtrace)) - print ".", + dups.append((component, owner, bugitems, backtrace)) + print "." + +# Close all bugs where it is appropriate. +if options.close: + for (component, owner, bugitems, backtrace) in dups: + # Find the master bug item + # Its the one with the most comments. + + # Sort function sorting by comment count. + def commentCmp(x, y): + if x['comments'] < y['comments']: + return 1 + elif x['comments'] == y['comments']: + # Sort by bug id, older bugs should became the master bug + if x['id'] > y['id']: + return 1 + elif x['id'] == y['id']: + return 0 + else: + return -1 + else: + return -1 + + sorteditems = sorted(bugitems, commentCmp) + + master = sorteditems[0] + for item in sorteditems[1:]: + if item['comments'] > 2: + continue + + print "Closing bug #{0} with {1} comments as a duplicate of #{2}.".format(item['id'], item['comments'], master['id']) + bug = bz.getbug(int(item['id'])) + bug.close("DUPLICATE", int(master['id']), "", + "This bug appears to have been filled using a buggy version of ABRT, because\n" + + "it contains a backtrace which is considered as a duplicate of the backtrace in #{0}." + + "Sorry for the inconvenience.\n\n" + + "Closing as a duplicate of #{0}.".format(master['id'])) + +bz.logout() print print "SUMMARY" @@ -204,6 +242,7 @@ def cmp(x, y): return 0 else: return 1 + for (component, owner, bugitems, backtrace) in sorted(dups, cmp): if options.wiki: print "----" -- cgit