From 94023a1ca37149e98644dfbb4287bcdbf9f119fd Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 9 Jun 2017 17:15:55 -0400 Subject: [PATCH] cli: convert: allow multiple paths to be passed as leftover arguments MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Allow this: babeltrace /path/to/trace1 /path/to/trace2 /path/to/trace3 This worked with Babeltrace 1 and needs to work with Babeltrace 2. What's done here is that a _base_ implicit set of arguments for an eventual source.ctf.fs component is created implicitly or by default like it used to be. For each leftover argument, we copy this base set of arguments and append the `path` parameter with the specific leftover argument. Then we name and connect those source components as usual. What's left is one source.ctf.fs component for each individual path. Each individual component can still recurse. tests/cli/test_convert_args is updated because it used to check that a command line with multiple leftovers was expected to fail, but it doesn't with this patch. Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- cli/babeltrace-cfg-cli-args.c | 252 ++++++++++++++++++++++++++------- tests/cli/test_convert_args.in | 3 +- 2 files changed, 201 insertions(+), 54 deletions(-) diff --git a/cli/babeltrace-cfg-cli-args.c b/cli/babeltrace-cfg-cli-args.c index 757ed112..6a711726 100644 --- a/cli/babeltrace-cfg-cli-args.c +++ b/cli/babeltrace-cfg-cli-args.c @@ -932,12 +932,12 @@ end: static void destroy_glist_of_gstring(GList *list) { + GList *at; + if (!list) { return; } - GList *at; - for (at = list; at != NULL; at = g_list_next(at)) { g_string_free(at->data, TRUE); } @@ -3083,7 +3083,7 @@ end: } static -void destroy_implicit_component_args(struct implicit_component_args *args) +void finalize_implicit_component_args(struct implicit_component_args *args) { assert(args); @@ -3102,6 +3102,17 @@ void destroy_implicit_component_args(struct implicit_component_args *args) bt_put(args->extra_params); } +static +void destroy_implicit_component_args(void *args) +{ + if (!args) { + return; + } + + finalize_implicit_component_args(args); + g_free(args); +} + static int init_implicit_component_args(struct implicit_component_args *args, const char *comp_arg, bool exists) @@ -3117,7 +3128,7 @@ int init_implicit_component_args(struct implicit_component_args *args, if (!args->comp_arg || !args->name_arg || !args->params_arg || !args->extra_params) { ret = -1; - destroy_implicit_component_args(args); + finalize_implicit_component_args(args); print_err_oom(); goto end; } @@ -3486,6 +3497,84 @@ end: return ret; } +static +struct implicit_component_args *create_implicit_component_args(void) +{ + struct implicit_component_args *impl_args = + g_new0(struct implicit_component_args, 1); + + if (!impl_args) { + goto end; + } + + if (init_implicit_component_args(impl_args, NULL, true)) { + destroy_implicit_component_args(impl_args); + impl_args = NULL; + goto end; + } + +end: + return impl_args; +} + +static +int fill_implicit_ctf_inputs_args(GPtrArray *implicit_ctf_inputs_args, + struct implicit_component_args *base_implicit_ctf_input_args, + GList *leftovers) +{ + int ret = 0; + GList *leftover; + + for (leftover = leftovers; leftover != NULL; + leftover = g_list_next(leftover)) { + GString *gs_leftover = leftover->data; + struct implicit_component_args *impl_args = + create_implicit_component_args(); + + if (!impl_args) { + print_err_oom(); + goto error; + } + + impl_args->exists = true; + g_string_assign(impl_args->comp_arg, + base_implicit_ctf_input_args->comp_arg->str); + g_string_assign(impl_args->params_arg, + base_implicit_ctf_input_args->params_arg->str); + + /* + * We need our own copy of the extra parameters because + * this is where the unique path goes. + */ + BT_PUT(impl_args->extra_params); + impl_args->extra_params = + bt_value_copy(base_implicit_ctf_input_args->extra_params); + if (!impl_args) { + print_err_oom(); + destroy_implicit_component_args(impl_args); + goto error; + } + + /* Append unique path parameter */ + ret = append_implicit_component_extra_param(impl_args, + "path", gs_leftover->str); + if (ret) { + destroy_implicit_component_args(impl_args); + goto error; + } + + g_ptr_array_add(implicit_ctf_inputs_args, impl_args); + } + + goto end; + +error: + ret = -1; + +end: + return ret; +} + /* * Creates a Babeltrace config object from the arguments of a convert * command. @@ -3521,7 +3610,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], GList *source_names = NULL; GList *filter_names = NULL; GList *sink_names = NULL; - struct implicit_component_args implicit_ctf_input_args = { 0 }; + GList *leftovers = NULL; + GPtrArray *implicit_ctf_inputs_args = NULL; + struct implicit_component_args base_implicit_ctf_input_args = { 0 }; struct implicit_component_args implicit_ctf_output_args = { 0 }; struct implicit_component_args implicit_lttng_live_args = { 0 }; struct implicit_component_args implicit_dummy_args = { 0 }; @@ -3543,7 +3634,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto end; } - if (init_implicit_component_args(&implicit_ctf_input_args, + if (init_implicit_component_args(&base_implicit_ctf_input_args, "source.ctf.fs", false)) { goto error; } @@ -3583,6 +3674,13 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + implicit_ctf_inputs_args = g_ptr_array_new_with_free_func( + (GDestroyNotify) destroy_implicit_component_args); + if (!implicit_ctf_inputs_args) { + print_err_oom(); + goto error; + } + all_names = bt_value_map_create(); if (!all_names) { print_err_oom(); @@ -4006,17 +4104,18 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], implicit_text_args.exists = true; break; case OPT_CLOCK_OFFSET: - implicit_ctf_input_args.exists = true; + base_implicit_ctf_input_args.exists = true; ret = append_implicit_component_extra_param( - &implicit_ctf_input_args, "clock-offset-cycles", arg); + &base_implicit_ctf_input_args, "clock-offset-cycles", arg); if (ret) { goto error; } break; case OPT_CLOCK_OFFSET_NS: - implicit_ctf_input_args.exists = true; + base_implicit_ctf_input_args.exists = true; ret = append_implicit_component_extra_param( - &implicit_ctf_input_args, "clock-offset-ns", arg); + &base_implicit_ctf_input_args, + "clock-offset-ns", arg); if (ret) { goto error; } @@ -4109,7 +4208,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], got_input_format_opt = true; if (strcmp(arg, "ctf") == 0) { - implicit_ctf_input_args.exists = true; + base_implicit_ctf_input_args.exists = true; } else if (strcmp(arg, "lttng-live") == 0) { implicit_lttng_live_args.exists = true; } else { @@ -4169,9 +4268,10 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], print_run_args_0 = true; break; case OPT_STREAM_INTERSECTION: - append_implicit_component_param(&implicit_ctf_input_args, + append_implicit_component_param( + &base_implicit_ctf_input_args, "stream-intersection", "yes"); - implicit_ctf_input_args.exists = true; + base_implicit_ctf_input_args.exists = true; break; case OPT_VERBOSE: if (got_verbose_opt) { @@ -4210,22 +4310,37 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - /* Consume leftover argument */ - leftover = poptGetArg(pc); + /* Consume and keep leftover arguments */ + while ((leftover = poptGetArg(pc))) { + GString *gs_leftover = g_string_new(leftover); - if (poptPeekArg(pc)) { - printf_err("Unexpected argument:\n %s\n", - poptPeekArg(pc)); - goto error; + if (!gs_leftover) { + print_err_oom(); + goto error; + } + + leftovers = g_list_append(leftovers, gs_leftover); + if (!leftovers) { + g_string_free(gs_leftover, TRUE); + print_err_oom(); + goto error; + } } /* Print CTF metadata or print LTTng live sessions */ if (print_ctf_metadata) { - if (!leftover) { + GString *gs_leftover; + + if (g_list_length(leftovers) == 0) { printf_err("--output-format=ctf-metadata specified without a path\n"); goto error; } + if (g_list_length(leftovers) > 1) { + printf_err("Too many paths specified for --output-format=ctf-metadata\n"); + goto error; + } + cfg = bt_config_print_ctf_metadata_create(plugin_paths); if (!cfg) { goto error; @@ -4233,8 +4348,9 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], cfg->debug = got_debug_opt; cfg->verbose = got_verbose_opt; + gs_leftover = leftovers->data; g_string_assign(cfg->cmd_data.print_ctf_metadata.path, - leftover); + gs_leftover->str); goto end; } @@ -4292,11 +4408,19 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], } } - /* Decide where the leftover argument goes */ - if (leftover) { + /* Decide where the leftover argument(s) go */ + if (g_list_length(leftovers) > 0) { if (implicit_lttng_live_args.exists) { + GString *gs_leftover; + + if (g_list_length(leftovers) > 1) { + printf_err("Too many URLs specified for --output-format=lttng-live\n"); + goto error; + } + + gs_leftover = leftovers->data; lttng_live_url_parts = - bt_common_parse_lttng_live_url(leftover, + bt_common_parse_lttng_live_url(gs_leftover->str, error_buf, sizeof(error_buf)); if (!lttng_live_url_parts.proto) { printf_err("Invalid LTTng live URL format: %s\n", @@ -4315,19 +4439,26 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], cfg->debug = got_debug_opt; cfg->verbose = got_verbose_opt; g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url, - leftover); + gs_leftover->str); goto end; } ret = append_implicit_component_extra_param( - &implicit_lttng_live_args, "url", leftover); + &implicit_lttng_live_args, "url", + gs_leftover->str); if (ret) { goto error; } } else { - ret = append_implicit_component_extra_param( - &implicit_ctf_input_args, "path", leftover); - implicit_ctf_input_args.exists = true; + /* + * Append one implicit component argument set + * for each leftover (souce.ctf.fs paths). Copy + * the base implicit component arguments. + * Note that they still have to be named later. + */ + ret = fill_implicit_ctf_inputs_args( + implicit_ctf_inputs_args, + &base_implicit_ctf_input_args, leftovers); if (ret) { goto error; } @@ -4338,35 +4469,42 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * Ensure mutual exclusion between implicit `source.ctf.fs` and * `source.ctf.lttng-live` components. */ - if (implicit_ctf_input_args.exists && implicit_lttng_live_args.exists) { + if (base_implicit_ctf_input_args.exists && + implicit_lttng_live_args.exists) { printf_err("Cannot create both implicit `%s` and `%s` components\n", - implicit_ctf_input_args.comp_arg->str, + base_implicit_ctf_input_args.comp_arg->str, implicit_lttng_live_args.comp_arg->str); goto error; } /* * If the implicit `source.ctf.fs` or `source.ctf.lttng-live` - * components exists, make sure there's a leftover (which is the - * path or URL). + * components exists, make sure there's at least one leftover + * (which is the path or URL). */ - if (implicit_ctf_input_args.exists && !leftover) { + if (base_implicit_ctf_input_args.exists && + g_list_length(leftovers) == 0) { printf_err("Missing path for implicit `%s` component\n", - implicit_ctf_input_args.comp_arg->str); + base_implicit_ctf_input_args.comp_arg->str); goto error; } - if (implicit_lttng_live_args.exists && !leftover) { + if (implicit_lttng_live_args.exists && g_list_length(leftovers) == 0) { printf_err("Missing URL for implicit `%s` component\n", implicit_lttng_live_args.comp_arg->str); goto error; } /* Assign names to implicit components */ - ret = assign_name_to_implicit_component(&implicit_ctf_input_args, - "source-ctf-fs", all_names, &source_names, true); - if (ret) { - goto error; + for (i = 0; i < implicit_ctf_inputs_args->len; i++) { + struct implicit_component_args *impl_args = + g_ptr_array_index(implicit_ctf_inputs_args, i); + + ret = assign_name_to_implicit_component(impl_args, + "source-ctf-fs", all_names, &source_names, true); + if (ret) { + goto error; + } } ret = assign_name_to_implicit_component(&implicit_lttng_live_args, @@ -4452,10 +4590,15 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], * Append the equivalent run arguments for the implicit * components. */ - ret = append_run_args_for_implicit_component(&implicit_ctf_input_args, - run_args); - if (ret) { - goto error; + for (i = 0; i < implicit_ctf_inputs_args->len; i++) { + struct implicit_component_args *impl_args = + g_ptr_array_index(implicit_ctf_inputs_args, i); + + ret = append_run_args_for_implicit_component(impl_args, + run_args); + if (ret) { + goto error; + } } ret = append_run_args_for_implicit_component(&implicit_lttng_live_args, @@ -4582,19 +4725,24 @@ end: g_string_free(cur_name_prefix, TRUE); } + if (implicit_ctf_inputs_args) { + g_ptr_array_free(implicit_ctf_inputs_args, TRUE); + } + bt_put(run_args); bt_put(all_names); destroy_glist_of_gstring(source_names); destroy_glist_of_gstring(filter_names); destroy_glist_of_gstring(sink_names); - destroy_implicit_component_args(&implicit_ctf_input_args); - destroy_implicit_component_args(&implicit_ctf_output_args); - destroy_implicit_component_args(&implicit_lttng_live_args); - destroy_implicit_component_args(&implicit_dummy_args); - destroy_implicit_component_args(&implicit_text_args); - destroy_implicit_component_args(&implicit_debug_info_args); - destroy_implicit_component_args(&implicit_muxer_args); - destroy_implicit_component_args(&implicit_trimmer_args); + destroy_glist_of_gstring(leftovers); + finalize_implicit_component_args(&base_implicit_ctf_input_args); + finalize_implicit_component_args(&implicit_ctf_output_args); + finalize_implicit_component_args(&implicit_lttng_live_args); + finalize_implicit_component_args(&implicit_dummy_args); + finalize_implicit_component_args(&implicit_text_args); + finalize_implicit_component_args(&implicit_debug_info_args); + finalize_implicit_component_args(&implicit_muxer_args); + finalize_implicit_component_args(&implicit_trimmer_args); bt_put(plugin_paths); bt_common_destroy_lttng_live_url_parts(<tng_live_url_parts); return cfg; diff --git a/tests/cli/test_convert_args.in b/tests/cli/test_convert_args.in index 896a8d1d..7498f120 100644 --- a/tests/cli/test_convert_args.in +++ b/tests/cli/test_convert_args.in @@ -70,7 +70,7 @@ comment() { echo "### $1 ###" } -plan_tests 77 +plan_tests 76 test_bt_convert_run_args 'path leftover' '/path/to/trace' '--component source.ctf.fs --name source-ctf-fs --key path --value /path/to/trace --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --connect source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty' test_bt_convert_run_args 'path leftover + named user source with --params' '/path/to/trace --component ZZ:source.another.source --params salut=yes' '--component ZZ:source.another.source --params salut=yes --component source.ctf.fs --name source-ctf-fs --key path --value /path/to/trace --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --connect ZZ:muxer --connect source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty' @@ -142,7 +142,6 @@ test_bt_convert_fails 'unknown -o' '-o lol' test_bt_convert_fails 'duplicate -o' '-o dummy --clock-seconds --output-format=text' test_bt_convert_fails '--run-args and --run-args-0' '/path/to/trace --run-args --run-args-0' test_bt_convert_fails 'duplicate -v' '/path/to/trace -vv' -test_bt_convert_fails 'two leftover arguments' '/path/to/trace /other/path' test_bt_convert_fails '-o ctf-metadata without path' '-o ctf-metadata' test_bt_convert_fails '-i lttng-live and implicit source.ctf.fs' '-i lttng-live net://some-host/host/target/session --clock-offset=23' test_bt_convert_fails 'implicit source.ctf.fs without path' '--clock-offset=23' -- 2.34.1