On 07/31/2012 11:40 AM, Jakub Filak wrote:
> * naive implementation of running of event chain in report-cli
> 
> Signed-off-by: Jakub Filak <[email protected]>
> ---
>  src/cli/cli-report.c |  223 
> ++++++++++++++++++++++++++++++++++++++------------
>  src/cli/cli-report.h |    1 +
>  src/cli/cli.c        |   34 ++++----
>  3 files changed, 187 insertions(+), 71 deletions(-)
> 
> diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c
> index 988bfc7..e204435 100644
> --- a/src/cli/cli-report.c
> +++ b/src/cli/cli-report.c
> @@ -520,10 +520,30 @@ static char *do_log_and_save_line(char *log_line, void 
> *param)
>      l_state->last_line = log_line;
>      return NULL;
>  }
> +
> +static int run_event(struct run_event_state *state, const char 
> *dump_dir_name,
> +                     const char *event, struct logging_state *l_state)
> +{
> +    // Export overridden settings as environment variables
> +    GList *env_list = export_event_config(event);
> +
> +    int r = run_event_on_dir_name(state, dump_dir_name, event);
> +    if (r == 0 && state->children_count == 0)
> +    {
> +        l_state->last_line = xasprintf("Error: no processing is specified 
> for event '%s'",
> +                event);
> +        r = -1;
> +    }
> +
> +    // Unexport overridden settings
> +    unexport_event_config(env_list);
> +
> +    return r;
> +}
> +
>  static int run_events(const char *dump_dir_name, GList *events, const char 
> *event_type)
>  {
>      int error_cnt = 0;
> -    GList *env_list = NULL;
>  
>      // Run events
>      struct logging_state l_state;
> @@ -534,18 +554,7 @@ static int run_events(const char *dump_dir_name, GList 
> *events, const char *even
>      for (GList *li = events; li; li = li->next)
>      {
>          char *event = (char *) li->data;
> -
> -        // Export overridden settings as environment variables
> -        env_list = export_event_config(event);
> -
> -        int r = run_event_on_dir_name(run_state, dump_dir_name, event);
> -        if (r == 0 && run_state->children_count == 0)
> -        {
> -            l_state.last_line = xasprintf("Error: no processing is specified 
> for event '%s'",
> -                                          event);
> -            r = -1;
> -        }
> -        if (r == 0)
> +        if (run_event(run_state, dump_dir_name, event, &l_state) == 0)
>          {
>              printf("%s: ", event);
>              if (l_state.last_line)
> @@ -560,14 +569,11 @@ static int run_events(const char *dump_dir_name, GList 
> *events, const char *even
>                      event,
>                      l_state.last_line ? ": " : "",
>                      l_state.last_line ? l_state.last_line : ""
> -            );
> -            error_cnt++;
> +                    );
> +            ++error_cnt;
>          }
>          free(l_state.last_line);
>          l_state.last_line = NULL;
> -
> -        // Unexport overridden settings
> -        unexport_event_config(env_list);
>      }
>      free_run_event_state(run_state);
>  
> @@ -742,6 +748,51 @@ int collect(const char *dump_dir_name, int batch)
>      return errors;
>  }
>  
> +static int review_problem_data(const char *dump_dir_name, problem_data_t 
> *problem_data)
> +{
> +    /* Open text editor and give a chance to review the backtrace etc */
> +    create_fields_for_editor(problem_data);
> +    int result = run_report_editor(problem_data);
> +    if (result != 0)
> +        return 1;
> +
> +    /* Save comment, backtrace */
> +    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
> +    if (dd)
> +    {
> +        //TODO: we should iterate through problem_data and modify all 
> modifiable fields
> +        const char *comment = problem_data_get_content_or_NULL(problem_data, 
> FILENAME_COMMENT);
> +        const char *backtrace = 
> problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
> +        if (comment)
> +            dd_save_text(dd, FILENAME_COMMENT, comment);
> +        if (backtrace)
> +            dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
> +        dd_close(dd);
> +    }
> +
> +    return 0;
> +}
> +
> +static int is_backtrace_rating_usable(event_config_t *config, problem_data_t 
> *problem_data)
> +{
> +    char *usability_description = NULL;
> +    char *usability_detail = NULL;
> +    const bool usable_rating = check_problem_rating_usability(config, 
> problem_data,
> +                                                              
> &usability_description,
> +                                                              
> &usability_detail);
> +
> +    if (!usable_rating)
> +    {
> +        printf("%s\n", usability_description);
> +        printf("%s\n", usability_detail);
> +    }
> +
> +    free(usability_description);
> +    free(usability_detail);
> +
> +    return usable_rating;
> +}
> +
>  /* Report the crash */
>  int report(const char *dump_dir_name, int flags)
>  {
> @@ -804,30 +855,12 @@ int report(const char *dump_dir_name, int flags)
>      problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
>      dd_close(dd);
>  
> -    if (!(flags & (CLI_REPORT_BATCH)))
> +    if (!(flags & (CLI_REPORT_BATCH))
> +        && review_problem_data(dump_dir_name, problem_data))
>      {
> -        /* Open text editor and give a chance to review the backtrace etc */
> -        create_fields_for_editor(problem_data);
> -        int result = run_report_editor(problem_data);
> -        if (result != 0)
> -        {
> -            problem_data_free(problem_data);
> -            free(report_events_as_lines);
> -            return 1;
> -        }
> -        /* Save comment, backtrace */
> -        dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
> -        if (dd)
> -        {
> -//TODO: we should iterate through problem_data and modify all modifiable 
> fields
> -            const char *comment = 
> problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
> -            const char *backtrace = 
> problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
> -            if (comment)
> -                dd_save_text(dd, FILENAME_COMMENT, comment);
> -            if (backtrace)
> -                dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
> -            dd_close(dd);
> -        }
> +        problem_data_free(problem_data);
> +        free(report_events_as_lines);
> +        return 1;
>      }
>  
>      /* Get possible reporters associated with this particular crash */
> @@ -885,17 +918,8 @@ int report(const char *dump_dir_name, int flags)
>              if (!is_number_in_string(i, wanted_reporters))
>                  continue;
>  
> -            char *usability_description = NULL;
> -            char *usability_detail = NULL;
> -            const bool usable_rating = 
> check_problem_rating_usability(config, problem_data,
> -                                                                      
> &usability_description,
> -                                                                      
> &usability_detail);
> -
> -            if (!usable_rating)
> +            if (!is_backtrace_rating_usable(config, problem_data))
>              {
> -                printf("%s\n", usability_description);
> -                printf("%s\n", usability_detail);
> -
>                  errors++;
>                  goto next_plugin;
>              }
> @@ -914,8 +938,6 @@ int report(const char *dump_dir_name, int flags)
>  
>  next_plugin:
>              plugins++;
> -            free(usability_description);
> -            free(usability_detail);
>          }
>      }
>  
> @@ -924,3 +946,98 @@ next_plugin:
>      list_free_with_free(report_events);
>      return errors;
>  }
> +
> +struct chain_logging_param
> +{
> +    struct logging_state l_state;
> +    bool terminate;
> +};
> +
> +static char *do_log_and_terminate_chain_on_request(char *log_line, void 
> *param)
> +{
> +    struct chain_logging_param *arg = (struct chain_logging_param *)param;
> +
> +    arg->terminate = strcmp("THANKYOU", log_line) == 0;
> +
> +    return do_log_and_save_line(log_line, &(arg->l_state));
> +}
> +
> +/*
> + * Runs event from chain. Perform the following steps for each event from 
> chain.
> + * 1. Terminates a chain run if a backtrace is not usable.
> + * 2. Asks for missing settings.
> + * 3. Performs review of problem data if event requires review.
> + * 4. Runs events commands.
> + * 5. Terminates a chain run if any event from the chain requires termination
> + *    (prints THANKYOU to stdout in the current implementation)
> + * 6. Terminates a chain run if any error occurs.
> + * 7. Continues immediately with processing of next event.
> + */
> +int run_events_chain(const char *dump_dir_name, GList *chain)
> +{
> +    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
> +    if (!dd)
> +        return -1;
> +
> +    problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
> +
> +    dd_close(dd);
> +
> +    struct chain_logging_param chain_state = {
> +        .l_state = {
> +            .last_line = NULL,
> +        },
> +        .terminate = false,
> +    };

I would just memset it to 0. Code will be more readable this way (IMO).

> +    struct run_event_state *run_state = new_run_event_state();
> +    run_state->logging_callback = do_log_and_terminate_chain_on_request;
> +    run_state->logging_param = &chain_state;
> +
> +    int returncode = 0;
> +
> +    for (GList *eitem = chain; !chain_state.terminate && eitem; eitem = 
> g_list_next(eitem))
> +    {
> +        const char *const event = (const char *)eitem->data;
> +        event_config_t *config = get_event_config(event);
> +
> +        if (!is_backtrace_rating_usable(config, problem_data))
> +            /* it is not a failure of event if the backtrace is unusable */
> +            break;
> +
> +        if (config)
> +        {
> +            /* can't fail */
> +            ask_for_missing_settings(event);
> +
> +            /* review problem data only if the event needs it */
> +            if (!config->ec_skip_review
> +                && review_problem_data(dump_dir_name, problem_data))
> +            {
> +                /* review failed, an error message was already logged */
> +                returncode = -1;
> +                break;
> +            }
> +        }
> +
> +        returncode = run_event(run_state, dump_dir_name, event, 
> &chain_state.l_state);
> +        if (returncode != 0)
> +        {
> +            error_msg("'%s' event was not successful%s%s",
> +                      event,
> +                      chain_state.l_state.last_line ? ": " : "",
> +                      chain_state.l_state.last_line ? 
> chain_state.l_state.last_line : ""
> +                     );
> +            break;
> +        }
> +
> +        free(chain_state.l_state.last_line);
> +        chain_state.l_state.last_line = NULL;
> +    }
> +
> +    free_run_event_state(run_state);
> +    free(chain_state.l_state.last_line);
> +    problem_data_free(problem_data);
> +
> +    return returncode;
> +}
> diff --git a/src/cli/cli-report.h b/src/cli/cli-report.h
> index b34293d..8dd3773 100644
> --- a/src/cli/cli-report.h
> +++ b/src/cli/cli-report.h
> @@ -32,6 +32,7 @@ enum {
>  };
>  int report(const char *dump_dir_name, int flags);
>  int collect(const char *dump_dir_name, int batch);
> +int run_events_chain(const char *dump_dir_name, GList *chain);
>  
>  #ifdef __cplusplus
>  }
> diff --git a/src/cli/cli.c b/src/cli/cli.c
> index 66ebbe2..5a221ad 100644
> --- a/src/cli/cli.c
> +++ b/src/cli/cli.c
> @@ -23,10 +23,18 @@
>  #include "internal_libreport.h"
>  #include "cli-report.h"
>  
> -static char *do_log(char *log_line, void *param)
> +static char *steal_directory_if_needed(char *dump_dir_name)
>  {
> -    log("%s", log_line);
> -    return log_line;
> +    struct dump_dir *dd = open_directory_for_writing(dump_dir_name,
> +                                                     /* ask callback */ 
> NULL);
> +
> +    if (dd)
> +    {
> +        dump_dir_name = xstrdup(dd->dd_dirname);
> +        dd_close(dd);
> +    }
> +
> +    return dump_dir_name;
>  }
>  
>  int main(int argc, char** argv)
> @@ -47,7 +55,7 @@ int main(int argc, char** argv)
>      textdomain(PACKAGE);
>  #endif
>  
> -    const char *event_name = NULL;
> +    GList *event_list = NULL;
>      const char *pfx = "";
>  
>      /* Can't keep these strings/structs static: _() doesn't support that */
> @@ -77,7 +85,7 @@ int main(int argc, char** argv)
>      struct options program_options[] = {
>          /*      short_name long_name  value    parameter_name  help */
>          OPT_OPTSTRING('L', NULL     , &pfx, "PREFIX",          _("List 
> possible events [which start with PREFIX]")),
> -        OPT_STRING(   'e', NULL     , &event_name, "EVENT",    _("Run EVENT 
> on DUMP_DIR")),
> +        OPT_LIST(     'e', "event"  , &event_list, "EVENT",    _("Run only 
> these events")),
>          OPT_BOOL(     'a', "analyze", NULL,                    _("Run 
> analyze event(s) on DUMP_DIR")),
>          OPT_BOOL(     'c', "collect", NULL,                    _("Run 
> collect event(s) on DUMP_DIR")),
>          OPT_BOOL(     'r', "report" , NULL,                    _("Analyze, 
> collect and report problem data in DUMP_DIR")),
> @@ -144,12 +152,8 @@ int main(int argc, char** argv)
>          }
>          case OPT_run_event: /* -e EVENT: run event */
>          {
> -            struct run_event_state *run_state = new_run_event_state();
> -            run_state->logging_callback = do_log;
> -            int r = run_event_on_dir_name(run_state, dump_dir_name, 
> event_name);
> -            if (r == 0 && run_state->children_count == 0)
> -                error_msg_and_die("No actions are found for event '%s'", 
> event_name);
> -            free_run_event_state(run_state);
> +            dump_dir_name = steal_directory_if_needed(dump_dir_name);
> +            exitcode = run_events_chain(dump_dir_name, event_list);
>              break;
>          }
>          case OPT_analyze:
> @@ -184,13 +188,7 @@ int main(int argc, char** argv)
>          }
>          case OPT_report:
>          {
> -            struct dump_dir *dd = open_directory_for_writing(dump_dir_name, 
> NULL);
> -
> -            if (dd)
> -            {
> -                dump_dir_name = xstrdup(dd->dd_dirname);
> -                dd_close(dd);
> -            }
> +            dump_dir_name = steal_directory_if_needed(dump_dir_name);
>  
>              exitcode = report(dump_dir_name,
>                      (always ? CLI_REPORT_BATCH : 0));

Looks good to me.

Reply via email to