diff options
-rw-r--r-- | src/applet/applet_gtk.c | 4 | ||||
-rw-r--r-- | src/gui-gtk/abrt-gtk.c | 11 | ||||
-rw-r--r-- | src/gui-wizard-gtk/wizard.c | 192 | ||||
-rw-r--r-- | src/include/abrtlib.h | 2 | ||||
-rw-r--r-- | src/include/report/report.h | 29 | ||||
-rw-r--r-- | src/lib/make_descr.c | 25 | ||||
-rw-r--r-- | src/lib/report.c | 103 | ||||
-rw-r--r-- | src/plugins/abrt-action-bugzilla.c | 28 | ||||
-rw-r--r-- | src/report-python/Makefile.am | 1 | ||||
-rw-r--r-- | src/report-python/README | 44 | ||||
-rw-r--r-- | src/report-python/__init__.py | 4 | ||||
-rw-r--r-- | src/report-python/common.h | 15 | ||||
-rw-r--r-- | src/report-python/report.c | 59 | ||||
-rw-r--r-- | src/report-python/reportmodule.c | 33 |
14 files changed, 318 insertions, 232 deletions
diff --git a/src/applet/applet_gtk.c b/src/applet/applet_gtk.c index 74347963..9e3c68f7 100644 --- a/src/applet/applet_gtk.c +++ b/src/applet/applet_gtk.c @@ -86,7 +86,8 @@ static void action_report(NotifyNotification *notification, gchar *action, gpoin struct applet *applet = (struct applet *)user_data; if (applet->ap_daemon_running) { - analyze_and_report_dir(applet->ap_last_crash_id, LIBREPORT_NOWAIT); + report_problem_in_dir(applet->ap_last_crash_id, LIBREPORT_ANALYZE | LIBREPORT_NOWAIT); + GError *err = NULL; notify_notification_close(notification, &err); if (err != NULL) @@ -94,6 +95,7 @@ static void action_report(NotifyNotification *notification, gchar *action, gpoin error_msg("%s", err->message); g_error_free(err); } + hide_icon(applet); stop_animate_icon(applet); } diff --git a/src/gui-gtk/abrt-gtk.c b/src/gui-gtk/abrt-gtk.c index f6e9c5c2..a3bf1cab 100644 --- a/src/gui-gtk/abrt-gtk.c +++ b/src/gui-gtk/abrt-gtk.c @@ -108,8 +108,8 @@ static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTre GValue d_dir = { 0 }; gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir); - const char *dirname= g_value_get_string(&d_dir); - analyze_and_report_dir(dirname, LIBREPORT_NOWAIT); + const char *dirname = g_value_get_string(&d_dir); + report_problem_in_dir(dirname, LIBREPORT_ANALYZE | LIBREPORT_NOWAIT); } } } @@ -203,8 +203,11 @@ static void on_button_send_cb(GtkWidget *button, gpointer data) /* why it doesn't want to hide before report ends? */ gtk_widget_destroy(s_report_window); - int status = report(pd); - VERB1 log("Reporting finished with status: %i", status); +//TODO: LIBREPORT_WAIT is used here only because we don't want to leave temp dir. +//Change to LIBREPORT_NOWAIT when libreport is taught to +//properly delete temp dir even with LIBREPORT_NOWAIT. + int status = report_problem_in_memory(pd, LIBREPORT_WAIT); + VERB1 log("Reporting finished with status %i", status); free_problem_data(pd); } diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c index 6d682233..12e6a81c 100644 --- a/src/gui-wizard-gtk/wizard.c +++ b/src/gui-wizard-gtk/wizard.c @@ -60,7 +60,6 @@ static GtkLabel *g_lbl_cd_reason; static GtkTextView *g_tv_backtrace; static GtkTextView *g_tv_comment; static GtkEventBox *g_eb_comment; -static GtkTreeView *g_tv_details; static GtkWidget *g_widget_warnings_area; static GtkBox *g_box_warning_labels; static GtkToggleButton *g_tb_approve_bt; @@ -69,10 +68,18 @@ static GtkButton *g_btn_refresh; static GtkLabel *g_lbl_reporters; static GtkLabel *g_lbl_size; -static GtkCellRenderer *g_tv_details_col2; +static GtkTreeView *g_tv_details; +static GtkCellRenderer *g_tv_details_renderer_value; +static GtkTreeViewColumn *g_tv_details_col_checkbox; +//static GtkCellRenderer *g_tv_details_renderer_checkbox; static GtkListStore *g_ls_details; enum { + /* Note: need to update types in + * gtk_list_store_new(DETAIL_NUM_COLUMNS, TYPE1, TYPE2...) + * if you change these: + */ + DETAIL_COLUMN_CHECKBOX, DETAIL_COLUMN_NAME, DETAIL_COLUMN_VALUE, DETAIL_NUM_COLUMNS, @@ -351,37 +358,48 @@ static void free_event_gui_data_t(event_gui_data_t *evdata, void *unused) /* tv_details handling */ -static void tv_details_row_activated( - GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - gpointer user_data) +static struct problem_item *get_current_problem_item_or_NULL(GtkTreeView *tree_view, gchar **pp_item_name) { GtkTreeModel *model; GtkTreeIter iter; GtkTreeSelection* selection = gtk_tree_view_get_selection(tree_view); if (!gtk_tree_selection_get_selected(selection, &model, &iter)) - return; + return NULL; + + *pp_item_name = NULL; + gtk_tree_model_get(model, &iter, DETAIL_COLUMN_NAME, pp_item_name, -1); + if (!*pp_item_name) /* paranoia, should never happen */ + return NULL; + struct problem_item *item = get_problem_data_item_or_NULL(g_cd, *pp_item_name); - gchar *column_name; - gtk_tree_model_get(model, &iter, DETAIL_COLUMN_NAME, &column_name, -1); - struct problem_item *item = get_problem_data_item_or_NULL(g_cd, column_name); + return item; +} + +static void tv_details_row_activated( + GtkTreeView *tree_view, + GtkTreePath *tree_path_UNUSED, + GtkTreeViewColumn *column, + gpointer user_data) +{ + gchar *item_name; + struct problem_item *item = get_current_problem_item_or_NULL(tree_view, &item_name); if (!item || !(item->flags & CD_FLAG_TXT)) - return; + goto ret; if (!strchr(item->content, '\n')) /* one line? */ - return; + goto ret; /* yes */ gchar *arg[3]; arg[0] = (char *) "xdg-open"; - arg[1] = concat_path_file(g_dump_dir_name, column_name); + arg[1] = concat_path_file(g_dump_dir_name, item_name); arg[2] = NULL; - g_free(column_name); g_spawn_sync(NULL, arg, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL, NULL, NULL, NULL, NULL, NULL, NULL); free(arg[1]); + ret: + g_free(item_name); } /* static gboolean tv_details_select_cursor_row( @@ -391,17 +409,11 @@ static void tv_details_row_activated( static void tv_details_cursor_changed( GtkTreeView *tree_view, - gpointer user_data) + gpointer user_data_UNUSED) { - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreeSelection* selection = gtk_tree_view_get_selection(tree_view); - if (!gtk_tree_selection_get_selected(selection, &model, &iter)) - return; - - gchar *column_name; - gtk_tree_model_get(model, &iter, DETAIL_COLUMN_NAME, &column_name, -1); - struct problem_item *item = get_problem_data_item_or_NULL(g_cd, column_name); + gchar *item_name; + struct problem_item *item = get_current_problem_item_or_NULL(tree_view, &item_name); + g_free(item_name); gboolean editable = (item && (item->flags & CD_FLAG_TXT) && !strchr(item->content, '\n')); @@ -410,11 +422,37 @@ static void tv_details_cursor_changed( * but changes aren't saved (the old text reappears as soon as user * leaves the field). Need to disable editing somehow. */ - g_object_set(G_OBJECT(g_tv_details_col2), + g_object_set(G_OBJECT(g_tv_details_renderer_value), "editable", editable, NULL); } +static void g_tv_details_checkbox_toggled( + GtkCellRendererToggle *cell_renderer_UNUSED, + gchar *tree_path, + gpointer user_data_UNUSED) +{ + //log("%s: path:'%s'", __func__, tree_path); + GtkTreeIter iter; + if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(g_ls_details), &iter, tree_path)) + return; + + gchar *item_name = NULL; + gtk_tree_model_get(GTK_TREE_MODEL(g_ls_details), &iter, DETAIL_COLUMN_NAME, &item_name, -1); + if (!item_name) /* paranoia, should never happen */ + return; + struct problem_item *item = get_problem_data_item_or_NULL(g_cd, item_name); + g_free(item_name); + if (!item) /* paranoia */ + return; + + item->flags ^= 0x8000000; + //log("%s: item->flags=%x", __func__, item->flags); + gtk_list_store_set(g_ls_details, &iter, + DETAIL_COLUMN_CHECKBOX, !!(item->flags & 0x8000000), + -1); +} + /* update_gui_state_from_problem_data */ @@ -623,10 +661,10 @@ static void append_item_to_ls_details(gpointer name, gpointer value, gpointer da stats->filecount++; //FIXME: use the human-readable format_problem_item(item) instead of item->content. - /* If text and not multiline... */ if (item->flags & CD_FLAG_TXT) { stats->filesize += strlen(item->content); + /* If not multiline... */ if (!strchr(item->content, '\n')) { gtk_list_store_set(g_ls_details, &iter, @@ -1265,6 +1303,13 @@ static void on_page_prepare(GtkAssistant *assistant, GtkWidget *page, gpointer u g_container_details1 : g_container_details2, w ); + /* Make checkbox column visible only on the last page */ + gtk_tree_view_column_set_visible(g_tv_details_col_checkbox, + (pages[PAGENO_REVIEW_DATA].page_widget == page) + ); + //gtk_cell_renderer_set_visible(g_tv_details_renderer_checkbox, + // (pages[PAGENO_REVIEW_DATA].page_widget == page) + //); } if (pages[PAGENO_EDIT_COMMENT].page_widget == page) @@ -1382,39 +1427,6 @@ static void search_timeout(GtkEntry *entry) /* Initialization */ -static void create_details_treeview() -{ - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Name"), - renderer, - "text", - DETAIL_COLUMN_NAME, - NULL); - gtk_tree_view_column_set_sort_column_id(column, DETAIL_COLUMN_NAME); - gtk_tree_view_append_column(g_tv_details, column); - - g_tv_details_col2 = renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Value"), - renderer, - "text", - DETAIL_COLUMN_VALUE, - NULL); - gtk_tree_view_append_column(g_tv_details, column); - - /* - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Path"), - renderer, - "text", - DETAIL_COLUMN_PATH, - NULL); - gtk_tree_view_append_column(g_tv_details, column); - */ -} - /* wizard.glade file as a string WIZARD_GLADE_CONTENTS: */ #include "wizard_glade.c" @@ -1527,6 +1539,57 @@ static void add_pages() gtk_widget_modify_bg(GTK_WIDGET(g_eb_comment), GTK_STATE_NORMAL, &color); } +static void create_details_treeview() +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + //g_tv_details_renderer_checkbox = + renderer = gtk_cell_renderer_toggle_new(); + g_tv_details_col_checkbox = column = gtk_tree_view_column_new_with_attributes( + _("Include"), renderer, + /* which "attr" of renderer to set from which COLUMN? (can be repeated) */ + "active", DETAIL_COLUMN_CHECKBOX, + NULL); + gtk_tree_view_append_column(g_tv_details, column); + /* This column has a handler */ + g_signal_connect(renderer, "toggled", G_CALLBACK(g_tv_details_checkbox_toggled), NULL); + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Name"), renderer, + "text", DETAIL_COLUMN_NAME, + NULL); + gtk_tree_view_append_column(g_tv_details, column); + + g_tv_details_renderer_value = renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Value"), renderer, + "text", DETAIL_COLUMN_VALUE, + NULL); + gtk_tree_view_append_column(g_tv_details, column); + + /* + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + _("Path"), renderer, + "text", DETAIL_COLUMN_PATH, + NULL); + gtk_tree_view_append_column(g_tv_details, column); + */ + + gtk_tree_view_column_set_sort_column_id(column, DETAIL_COLUMN_NAME); + + g_ls_details = gtk_list_store_new(DETAIL_NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(g_tv_details, GTK_TREE_MODEL(g_ls_details)); + + g_signal_connect(g_tv_details, "row-activated", G_CALLBACK(tv_details_row_activated), NULL); + g_signal_connect(g_tv_details, "cursor-changed", G_CALLBACK(tv_details_cursor_changed), NULL); + /* [Enter] on a row: + * g_signal_connect(g_tv_details, "select-cursor-row", G_CALLBACK(tv_details_select_cursor_row), NULL); + */ +} + void create_assistant(void) { monospace_font = pango_font_description_from_string("monospace"); @@ -1541,8 +1604,8 @@ void create_assistant(void) g_parent_window = wnd_assistant; gtk_window_set_default_size(wnd_assistant, DEFAULT_WIDTH, DEFAULT_HEIGHT); /* set_default sets icon for every windows used in this app, so we don't - have to set the icon for those windows manually - */ + * have to set the icon for those windows manually + */ gtk_window_set_default_icon_name("abrt"); GObject *obj_assistant = G_OBJECT(g_assistant); @@ -1554,15 +1617,10 @@ void create_assistant(void) add_pages(); create_details_treeview(); - g_ls_details = gtk_list_store_new(DETAIL_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - gtk_tree_view_set_model(g_tv_details, GTK_TREE_MODEL(g_ls_details)); g_signal_connect(g_tb_approve_bt, "toggled", G_CALLBACK(on_bt_approve_toggle), NULL); g_signal_connect(g_btn_refresh, "clicked", G_CALLBACK(on_btn_refresh_clicked), NULL); g_signal_connect(gtk_text_view_get_buffer(g_tv_comment), "changed", G_CALLBACK(on_comment_changed), NULL); - g_signal_connect(g_tv_details, "row-activated", G_CALLBACK(tv_details_row_activated), NULL); - /* [Enter] on a row: g_signal_connect(g_tv_details, "select-cursor-row", G_CALLBACK(tv_details_select_cursor_row), NULL); */ - g_signal_connect(g_tv_details, "cursor-changed", G_CALLBACK(tv_details_cursor_changed), NULL); /* init searching */ GtkTextBuffer *backtrace_buf = gtk_text_view_get_buffer(g_tv_backtrace); diff --git a/src/include/abrtlib.h b/src/include/abrtlib.h index 5d03ee49..1e68a661 100644 --- a/src/include/abrtlib.h +++ b/src/include/abrtlib.h @@ -251,8 +251,6 @@ enum { char *make_description(problem_data_t *problem_data, char **names_to_skip, unsigned max_text_size, unsigned desc_flags); #define make_description_bz abrt_make_description_bz char* make_description_bz(problem_data_t *problem_data); -#define make_description_comment abrt_make_description_comment -char* make_description_comment(problem_data_t *problem_data); #define make_description_logger abrt_make_description_logger char* make_description_logger(problem_data_t *problem_data); #define make_description_mailx abrt_make_description_mailx diff --git a/src/include/report/report.h b/src/include/report/report.h index e441875b..269866b2 100644 --- a/src/include/report/report.h +++ b/src/include/report/report.h @@ -22,28 +22,21 @@ #include "problem_data.h" enum { - LIBREPORT_NOWAIT = 0, - LIBREPORT_WAIT = (1 << 0), /* wait for report to finish and reload the problem data */ + LIBREPORT_NOWAIT = 0, + LIBREPORT_WAIT = (1 << 0), /* wait for report to finish and reload the problem data */ + LIBREPORT_ANALYZE = (1 << 1), /* run analyzers? */ + /* ("run reporters" is always on, has no flag (for now?)) */ + LIBREPORT_RELOAD_DATA = (1 << 3), /* reload problem data after run (needs WAIT) */ }; +int report_problem_in_dir(const char *dirname, int flags); -/* analyzes AND reports a problem saved on disk - * - takes user through all the steps in reporting wizard +/* Reports a problem stored in problem_data_t. + * It's first saved to /tmp and then processed as a dump dir. */ -int analyze_and_report_dir(const char* dirname, int flags); +int report_problem_in_memory(problem_data_t *pd, int flags); -/* analyzes AND reports a problem stored in problem_data_t - * it's first saved to /tmp and then processed as a dump_dir - * - takes user through all the steps in reporting wizard - */ -int analyze_and_report(problem_data_t *pd, int flags); - -/* reports a problem saved on disk - * - shows only reporter selector and progress -*/ -int report_dir(const char* dirname); - -/* to report a problem stored in memory */ -int report(problem_data_t *pd); +/* Simple wrapper for trivial uses */ +int report_problem(problem_data_t *pd); #endif /* REPORT_H_ */ diff --git a/src/lib/make_descr.c b/src/lib/make_descr.c index 036d7770..d0afc8cb 100644 --- a/src/lib/make_descr.c +++ b/src/lib/make_descr.c @@ -260,28 +260,3 @@ char* make_description_logger(problem_data_t *problem_data) MAKEDESC_SHOW_FILES | MAKEDESC_SHOW_MULTILINE ); } - -char* make_description_comment(problem_data_t *problem_data) -{ - char *comment = NULL; - struct problem_item *value; - - value = get_problem_data_item_or_NULL(problem_data, FILENAME_COMMENT); - if (value) - { - if (value->content[0]) - comment = xasprintf("\n\nComment\n-----\n%s", value->content); - } - - if (!comment) - return NULL; - - struct strbuf *buf_dsc = strbuf_new(); - - if (comment) - strbuf_append_str(buf_dsc, comment); - - free(comment); - - return strbuf_free_nobuf(buf_dsc); -} diff --git a/src/lib/report.c b/src/lib/report.c index 99a3f919..07299e48 100644 --- a/src/lib/report.c +++ b/src/lib/report.c @@ -20,7 +20,7 @@ #include "abrtlib.h" #include "report.h" -static int run_reporter_ui(char **args, int flags) +int report_problem_in_dir(const char *dirname, int flags) { const char *path; /* @@ -29,6 +29,15 @@ static int run_reporter_ui(char **args, int flags) path = "cli" */ + char *args[5], **pp; + pp = args; + *pp++ = (char *)"bug-reporting-wizard"; + if (!(flags & LIBREPORT_ANALYZE)) + *pp++ = (char *)"--report-only"; + *pp++ = (char *)"--"; + *pp++ = (char *)dirname; + *pp++ = NULL; + pid_t pid = vfork(); if (pid < 0) /* error */ { @@ -79,22 +88,7 @@ static int run_reporter_ui(char **args, int flags) return 0; } -int analyze_and_report_dir(const char* dirname, int flags) -{ - char *args[4]; - - args[0] = (char *)"bug-reporting-wizard"; - args[1] = (char *)"--"; - args[2] = (char *)dirname; - args[3] = NULL; - - return run_reporter_ui(args, flags); -} - -/* analyzes AND reports a problem saved on disk - * - takes user through all the steps in reporting wizard - */ -int analyze_and_report(problem_data_t *pd, int flags) +int report_problem_in_memory(problem_data_t *pd, int flags) { int result = 0; struct dump_dir *dd = create_dump_dir_from_problem_data(pd, "/tmp"/* /var/tmp ?? */); @@ -103,78 +97,33 @@ int analyze_and_report(problem_data_t *pd, int flags) char *dir_name = xstrdup(dd->dd_dirname); dd_close(dd); VERB2 log("Temp problem dir: '%s'", dir_name); - result = analyze_and_report_dir(dir_name, flags); - /* if we wait for reporter to finish, we can clean the tmp dir - * and we should reload the problem data, so caller doesn't see the stalled - * data - */ +// TODO: if !LIBREPORT_WAIT pass LIBREPORT_DEL_DIR, and teach bug-reporting-wizard +// an option to delete directory after reporting? +// It will make !LIBREPORT_WAIT reporting possible + result = report_problem_in_dir(dir_name, flags); + + /* If we wait for reporter to finish, we should clean the tmp dir. + * We can also reload the problem data if requested. + */ if (flags & LIBREPORT_WAIT) { - g_hash_table_remove_all(pd); + if (flags & LIBREPORT_RELOAD_DATA) + g_hash_table_remove_all(pd); dd = dd_opendir(dir_name, 0); if (dd) { - load_problem_data_from_dump_dir(pd, dd); + if (flags & LIBREPORT_RELOAD_DATA) + load_problem_data_from_dump_dir(pd, dd); dd_delete(dd); } } + free(dir_name); return result; } -/* report() and report_dir() don't take flags, because in all known use-cases - * it doesn't make sense to not wait for the result - * -*/ - -/* reports a problem saved on disk - * - shows only reporter selector and progress -*/ -int report_dir(const char* dirname) +int report_problem(problem_data_t *pd) { - char *args[5]; - - args[0] = (char *)"bug-reporting-wizard"; - args[1] = (char *)"--report-only"; - args[2] = (char *)"--"; - args[3] = (char *)dirname; - args[4] = NULL; - - int flags = LIBREPORT_WAIT; - int status = run_reporter_ui(args, flags); - return status; -} - -int report(problem_data_t *pd) -{ - /* adds: - * analyzer:libreport - * executable:readlink(/proc/<pid>/exe) - * tries to guess component - */ - add_basics_to_problem_data(pd); - struct dump_dir *dd = create_dump_dir_from_problem_data(pd, "/tmp"/* /var/tmp ?? */); - if (!dd) - return -1; - dd_create_basic_files(dd, getuid()); - char *dir_name = xstrdup(dd->dd_dirname); - dd_close(dd); - VERB2 log("Temp problem dir: '%s'", dir_name); - int result = report_dir(dir_name); - - /* here we always wait for reporter to finish, we can clean the tmp dir - * and we should reload the problem data, so caller doesn't see the stalled - * data - */ - g_hash_table_remove_all(pd); //what if something fails? is it ok to return empty pd rather then stalled pd? - dd = dd_opendir(dir_name, 0); - if (dd) - { - load_problem_data_from_dump_dir(pd, dd); - dd_delete(dd); - } - free(dir_name); - - return result; + return report_problem_in_memory(pd, LIBREPORT_WAIT); } diff --git a/src/plugins/abrt-action-bugzilla.c b/src/plugins/abrt-action-bugzilla.c index d617d4bb..9290112a 100644 --- a/src/plugins/abrt-action-bugzilla.c +++ b/src/plugins/abrt-action-bugzilla.c @@ -170,26 +170,24 @@ static void report_to_bugzilla(const char *dump_dir_name, map_string_h *settings rhbz_mail_to_cc(client, bz->bi_id, login, RHBZ_NOMAIL_NOTIFY); } - char *dsc = make_description_comment(problem_data); - if (dsc) + const char *comment = get_problem_item_content_or_NULL(problem_data, FILENAME_COMMENT); + if (comment && comment[0]) { - const char *package = get_problem_item_content_or_NULL(problem_data, - FILENAME_PACKAGE); - const char *release = get_problem_item_content_or_NULL(problem_data, - FILENAME_OS_RELEASE); - if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */ - release = get_problem_item_content_or_NULL(problem_data, "release"); - const char *arch = get_problem_item_content_or_NULL(problem_data, - FILENAME_ARCHITECTURE); - + const char *package = get_problem_item_content_or_NULL(problem_data, FILENAME_PACKAGE); + const char *release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE); +//COMPAT, remove in abrt-2.1 release + if (!release)release= get_problem_item_content_or_NULL(problem_data, "release"); + const char *arch = get_problem_item_content_or_NULL(problem_data, FILENAME_ARCHITECTURE); char *full_dsc = xasprintf("Package: %s\n" "Architecture: %s\n" "OS Release: %s\n" - "%s", package, arch, release, dsc); - + "\n" + "Comment\n" + "-----\n" + "%s\n", + package, arch, release, comment + ); log(_("Adding new comment to bug %d"), bz->bi_id); - free(dsc); - /* unused code, enable it when gui/cli will be ready int is_priv = is_private && string_to_bool(is_private); const char *is_private = get_problem_item_content_or_NULL(problem_data, diff --git a/src/report-python/Makefile.am b/src/report-python/Makefile.am index c7b2dd67..c1b37596 100644 --- a/src/report-python/Makefile.am +++ b/src/report-python/Makefile.am @@ -11,6 +11,7 @@ _pyreport_la_SOURCES = \ problem_data.c \ dump_dir.c \ run_event.c \ + report.c \ common.h _pyreport_la_CPPFLAGS = \ -I$(srcdir)/../include/report -I$(srcdir)/../include \ diff --git a/src/report-python/README b/src/report-python/README new file mode 100644 index 00000000..1c9c3a27 --- /dev/null +++ b/src/report-python/README @@ -0,0 +1,44 @@ +Currently (2011-05), include/report/*.h are: + +dump_dir.h +event_config.h +problem_data.h +report.h +run_event.h + +and we wrap all of them except event_config.h. + +Python wrappers for C types and functions declared in include/report/FOO.h +should be implemented in corresponding FOO.c file in this directory. + +Their (C-level) declarations should go to common.h. + +Note that methods don't have to be declared in common.h: +they can be static functions inside FOO.c, and exposed to the rest +of the world via PyTypeObject instance. In FOO.c: + +static PyObject *p_method_name(PyObject *pself, PyObject *args) +... +static PyMethodDef p_FOO_methods[] = { +{ "method_name", p_method_name, METH_VARARGS, NULL } +... +}; +PyTypeObject p_FOO_type = { + .tp_methods = p_FOO_methods, +... +}; + +and only p_FOO_type needs to be declared in common.h. + +Similarly, (de)allocators, attr getters/setters also can be static functions +and be hooked into p_FOO_type. + +However, non-method functions can't be static. + + +File reportmodule.c contains the initialization function which should +initialize types (p_FOO_type objects) and hook up finctions from every +FOO.c so that they are usable from python code. + +Python wrappers for C constants (enums, defines) are created directly +by reportmodule.c. diff --git a/src/report-python/__init__.py b/src/report-python/__init__.py index 2e875638..78beff6d 100644 --- a/src/report-python/__init__.py +++ b/src/report-python/__init__.py @@ -112,7 +112,7 @@ def createAlertSignature(component, hashmarkername, hashvalue, summary, alertSig cd.add("component", component) cd.add("hashmarkername", hashmarkername) #cd.add("localhash", hashvalue) - cd.add("global_uuid", hashvalue) + cd.add("duphash", hashvalue) cd.add("reason", summary) cd.add("description", alertSignature) cd.add("product", getProduct()) @@ -127,4 +127,4 @@ def report(cd, io_unused): """ def report(pd, io_unused): - result = report_problem_data(pd) + result = report_problem(pd) diff --git a/src/report-python/common.h b/src/report-python/common.h index ee56ad9a..713aa2f2 100644 --- a/src/report-python/common.h +++ b/src/report-python/common.h @@ -31,11 +31,6 @@ extern PyTypeObject p_problem_data_type; extern PyTypeObject p_dump_dir_type; extern PyTypeObject p_run_event_state_type; -/* module-level functions */ -PyObject *p_dd_opendir(PyObject *module, PyObject *args); -PyObject *p_dd_create(PyObject *module, PyObject *args); -PyObject *p_delete_dump_dir(PyObject *pself, PyObject *args); - /* python objects' struct defs */ typedef struct { PyObject_HEAD @@ -46,3 +41,13 @@ typedef struct { PyObject_HEAD problem_data_t *cd; } p_problem_data; + +/* module-level functions */ +/* for include/report/dump_dir.h */ +PyObject *p_dd_opendir(PyObject *module, PyObject *args); +PyObject *p_dd_create(PyObject *module, PyObject *args); +PyObject *p_delete_dump_dir(PyObject *pself, PyObject *args); +/* for include/report/report.h */ +PyObject *p_report_problem_in_dir(PyObject *pself, PyObject *args); +PyObject *p_report_problem_in_memory(PyObject *pself, PyObject *args); +PyObject *p_report_problem(PyObject *pself, PyObject *args); diff --git a/src/report-python/report.c b/src/report-python/report.c new file mode 100644 index 00000000..0bdd4076 --- /dev/null +++ b/src/report-python/report.c @@ -0,0 +1,59 @@ +/* + Copyright (C) 2010 Abrt team. + Copyright (C) 2010 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 <Python.h> + +#include "common.h" + +/* C: int report_problem_in_dir(const char *dirname, int flags); */ +PyObject *p_report_problem_in_dir(PyObject *pself, PyObject *args) +{ + const char *dirname; + int flags; + if (!PyArg_ParseTuple(args, "si", &dirname, &flags)) + { + return NULL; + } + int r = report_problem_in_dir(dirname, flags); + return Py_BuildValue("i", r); +} + +/* C: int report_problem_in_memory(problem_data_t *pd, int flags); */ +PyObject *p_report_problem_in_memory(PyObject *pself, PyObject *args) +{ + p_problem_data *pd; + int flags; + if (!PyArg_ParseTuple(args, "O!i", &p_problem_data_type, &pd, &flags)) + { + return NULL; + } + int r = report_problem_in_memory(pd->cd, flags); + return Py_BuildValue("i", r); +} + +/* C: int report_problem(problem_data_t *pd); */ +PyObject *p_report_problem(PyObject *pself, PyObject *args) +{ + p_problem_data *pd; + if (!PyArg_ParseTuple(args, "O!", &p_problem_data_type, &pd)) + { + return NULL; + } + int r = report_problem(pd->cd); + return Py_BuildValue("i", r); +} diff --git a/src/report-python/reportmodule.c b/src/report-python/reportmodule.c index 1cae783f..539c66aa 100644 --- a/src/report-python/reportmodule.c +++ b/src/report-python/reportmodule.c @@ -22,21 +22,16 @@ PyObject *ReportError; - -static PyObject *p_report(PyObject *pself, PyObject *problem_data) -{ - p_problem_data *p_pd = (p_problem_data*)problem_data; - report(p_pd->cd); - //FIXME return status as integer object - Py_RETURN_NONE; -} - static PyMethodDef module_methods[] = { /* method_name, func, flags, doc_string */ - { "dd_opendir" , p_dd_opendir , METH_VARARGS }, - { "dd_create" , p_dd_create , METH_VARARGS }, - { "delete_dump_dir", p_delete_dump_dir, METH_VARARGS }, - { "report_problem_data" , p_report, METH_O}, + /* for include/report/dump_dir.h */ + { "dd_opendir" , p_dd_opendir , METH_VARARGS }, + { "dd_create" , p_dd_create , METH_VARARGS }, + { "delete_dump_dir" , p_delete_dump_dir , METH_VARARGS }, + /* for include/report/report.h */ + { "report_problem_in_dir" , p_report_problem_in_dir , METH_VARARGS }, + { "report_problem_in_memory" , p_report_problem_in_memory, METH_VARARGS }, + { "report_problem" , p_report_problem , METH_VARARGS }, { NULL } }; @@ -75,20 +70,26 @@ init_pyreport(void) Py_INCREF(ReportError); PyModule_AddObject(m, "error", ReportError); - /* init type objects */ + /* init type objects and constants */ + /* for include/report/problem_data.h */ Py_INCREF(&p_problem_data_type); PyModule_AddObject(m, "problem_data", (PyObject *)&p_problem_data_type); PyModule_AddObject(m, "CD_FLAG_BIN" , Py_BuildValue("i", CD_FLAG_BIN )); PyModule_AddObject(m, "CD_FLAG_TXT" , Py_BuildValue("i", CD_FLAG_TXT )); PyModule_AddObject(m, "CD_FLAG_ISEDITABLE" , Py_BuildValue("i", CD_FLAG_ISEDITABLE )); PyModule_AddObject(m, "CD_FLAG_ISNOTEDITABLE", Py_BuildValue("i", CD_FLAG_ISNOTEDITABLE)); - + /* for include/report/dump_dir.h */ Py_INCREF(&p_dump_dir_type); PyModule_AddObject(m, "dump_dir", (PyObject *)&p_dump_dir_type); PyModule_AddObject(m, "DD_FAIL_QUIETLY_ENOENT" , Py_BuildValue("i", DD_FAIL_QUIETLY_ENOENT )); PyModule_AddObject(m, "DD_FAIL_QUIETLY_EACCES" , Py_BuildValue("i", DD_FAIL_QUIETLY_EACCES )); PyModule_AddObject(m, "DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE", Py_BuildValue("i", DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE)); - + /* for include/report/run_event.h */ Py_INCREF(&p_run_event_state_type); PyModule_AddObject(m, "run_event_state", (PyObject *)&p_run_event_state_type); + /* for include/report/report.h */ + PyModule_AddObject(m, "LIBREPORT_NOWAIT" , Py_BuildValue("i", LIBREPORT_NOWAIT )); + PyModule_AddObject(m, "LIBREPORT_WAIT" , Py_BuildValue("i", LIBREPORT_WAIT )); + PyModule_AddObject(m, "LIBREPORT_ANALYZE" , Py_BuildValue("i", LIBREPORT_ANALYZE )); + PyModule_AddObject(m, "LIBREPORT_RELOAD_DATA", Py_BuildValue("i", LIBREPORT_RELOAD_DATA)); } |