self._logging_level = logging_level
if type(params) is str:
- self._params = bt2.create_value({'paths': [params]})
+ self._params = bt2.create_value({'inputs': [params]})
else:
self._params = bt2.create_value(params)
def _create_stream_intersection_trimmer(self, component, port):
# find the original parameters specified by the user to create
- # this port's component to get the `path` parameter
+ # this port's component to get the `inputs` parameter
for src_comp_and_spec in self._src_comps_and_specs:
if component == src_comp_and_spec.comp:
break
try:
- paths = src_comp_and_spec.spec.params['paths']
+ inputs = src_comp_and_spec.spec.params['inputs']
except Exception as e:
raise bt2.Error(
- 'all source components must be created with a "paths" parameter in stream intersection mode'
+ 'all source components must be created with an "inputs" parameter in stream intersection mode'
) from e
- params = {'paths': paths}
+ params = {'inputs': inputs}
# query the port's component for the `trace-info` object which
# contains the stream intersection range for each exposed
babeltrace2-cfg-cli-args-default.c \
babeltrace2-cfg-cli-params-arg.c \
babeltrace2-cfg-cli-params-arg.h \
+ babeltrace2-cfg-src-auto-disc.c \
+ babeltrace2-cfg-src-auto-disc.h \
babeltrace2-plugins.c \
babeltrace2-plugins.h \
logging.c \
#include "babeltrace2-cfg-cli-args.h"
#include "babeltrace2-cfg-cli-args-connect.h"
#include "babeltrace2-cfg-cli-params-arg.h"
+#include "babeltrace2-plugins.h"
+#include "babeltrace2-cfg-src-auto-disc.h"
#include "common/version.h"
static const int cli_default_log_level = BT_LOG_WARNING;
struct implicit_component_args {
bool exists;
+
+ /* The component class name (e.g. src.ctf.fs). */
GString *comp_arg;
+
+ /* The component instance name. */
GString *name_arg;
+
GString *params_arg;
bt_value *extra_params;
};
return ret;
}
+/* Free the fields of a `struct implicit_component_args`. */
+
static
void finalize_implicit_component_args(struct implicit_component_args *args)
{
bt_value_put_ref(args->extra_params);
}
+/* Destroy a dynamically-allocated `struct implicit_component_args`. */
+
+static
+void destroy_implicit_component_args(struct implicit_component_args *args)
+{
+ finalize_implicit_component_args(args);
+ g_free(args);
+}
+
+/* Initialize the fields of an already allocated `struct implicit_component_args`. */
+
static
int init_implicit_component_args(struct implicit_component_args *args,
const char *comp_arg, bool exists)
return ret;
}
+/* Dynamically allocate and initialize a `struct implicit_component_args`. */
+
+static
+struct implicit_component_args *create_implicit_component_args(
+ const char *comp_arg)
+{
+ struct implicit_component_args *args;
+ int status;
+
+ args = g_new(struct implicit_component_args, 1);
+ if (!args) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto end;
+ }
+
+ status = init_implicit_component_args(args, comp_arg, true);
+ if (status != 0) {
+ g_free(args);
+ args = NULL;
+ }
+
+end:
+ return args;
+}
+
static
void append_implicit_component_param(struct implicit_component_args *args,
const char *key, const char *value)
append_param_arg(args->params_arg, key, value);
}
+/*
+ * Append the given parameter (`key=value`) to all component specifications
+ * in `implicit_comp_args` (an array of `struct implicit_component_args *`)
+ * which match `comp_arg`.
+ *
+ * Return the number of matching components.
+ */
+
+static
+int append_multiple_implicit_components_param(GPtrArray *implicit_comp_args,
+ const char *comp_arg, const char *key, const char *value)
+{
+ int i;
+ int n = 0;
+
+ for (i = 0; i < implicit_comp_args->len; i++) {
+ struct implicit_component_args *args = implicit_comp_args->pdata[i];
+
+ if (strcmp(args->comp_arg->str, comp_arg) == 0) {
+ append_implicit_component_param(args, key, value);
+ n++;
+ }
+ }
+
+ return n;
+}
+
/* Escape value to make it suitable to use as a string parameter value. */
static
gchar *escape_string_value(const char *value)
return ret;
}
+/*
+ * Create `struct implicit_component_args` structures for each of the source
+ * components we identified. Add them to `component_args`.
+ */
+
+static
+void create_implicit_component_args_from_auto_discovered_sources(
+ const struct auto_source_discovery *auto_disc, GPtrArray *component_args)
+{
+ gchar *cc_name = NULL;
+ struct implicit_component_args *comp = NULL;
+ int status;
+ guint i, len;
+
+ len = auto_disc->results->len;
+
+ for (i = 0; i < len; i++) {
+ struct auto_source_discovery_result *res =
+ g_ptr_array_index(auto_disc->results, i);
+
+ g_free(cc_name);
+ cc_name = g_strdup_printf("source.%s.%s", res->plugin_name, res->source_cc_name);
+ if (!cc_name) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto end;
+ }
+
+ comp = create_implicit_component_args(cc_name);
+ if (!comp) {
+ goto end;
+ }
+
+ status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs);
+ if (status != 0) {
+ goto end;
+ }
+
+ g_ptr_array_add(component_args, comp);
+ comp = NULL;
+ }
+
+end:
+ g_free(cc_name);
+
+ if (comp) {
+ destroy_implicit_component_args(comp);
+ }
+}
+
/*
* Creates a Babeltrace config object from the arguments of a convert
* command.
GList *filter_names = NULL;
GList *sink_names = NULL;
bt_value *leftovers = NULL;
- struct implicit_component_args 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 };
size_t i;
struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
char *output = NULL;
+ struct auto_source_discovery auto_disc = { NULL };
+ GString *auto_disc_comp_name = NULL;
+
+ /*
+ * Array of `struct implicit_component_args *` created for the sources
+ * we have auto-discovered.
+ */
+ GPtrArray *discovered_source_args = NULL;
+
+ /*
+ * If set, restrict automatic source discovery to this component class
+ * of this plugin.
+ */
+ const char *auto_source_discovery_restrict_plugin_name = NULL;
+ const char *auto_source_discovery_restrict_component_class_name = NULL;
+
+ gchar *ctf_fs_source_clock_class_offset_arg = NULL;
+ gchar *ctf_fs_source_clock_class_offset_ns_arg = NULL;
(void) bt_value_copy(initial_plugin_paths, &plugin_paths);
goto end;
}
- if (init_implicit_component_args(&implicit_ctf_input_args,
- "source.ctf.fs", false)) {
- goto error;
- }
-
if (init_implicit_component_args(&implicit_ctf_output_args,
"sink.ctf.fs", false)) {
goto error;
goto error;
}
+ if (auto_source_discovery_init(&auto_disc) != 0) {
+ goto error;
+ }
+
+ discovered_source_args =
+ g_ptr_array_new_with_free_func((GDestroyNotify) destroy_implicit_component_args);
+ if (!discovered_source_args) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
+
+ auto_disc_comp_name = g_string_new(NULL);
+ if (!auto_disc_comp_name) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
+
/*
* First pass: collect all arguments which need to be passed
* as is to the run command. This pass can also add --name
implicit_text_args.exists = true;
break;
case OPT_CLOCK_OFFSET:
- implicit_ctf_input_args.exists = true;
- append_implicit_component_param(
- &implicit_ctf_input_args,
- "clock-class-offset-s", arg);
+ if (ctf_fs_source_clock_class_offset_arg) {
+ BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset option\n");
+ goto error;
+ }
+
+ ctf_fs_source_clock_class_offset_arg = g_strdup(arg);
+ if (!ctf_fs_source_clock_class_offset_arg) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
break;
case OPT_CLOCK_OFFSET_NS:
- implicit_ctf_input_args.exists = true;
- append_implicit_component_param(
- &implicit_ctf_input_args,
- "clock-class-offset-ns", arg);
+ if (ctf_fs_source_clock_class_offset_ns_arg) {
+ BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset-ns option\n");
+ goto error;
+ }
+
+ ctf_fs_source_clock_class_offset_ns_arg = g_strdup(arg);
+ if (!ctf_fs_source_clock_class_offset_ns_arg) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
break;
case OPT_CLOCK_SECONDS:
append_implicit_component_param(
got_input_format_opt = true;
if (strcmp(arg, "ctf") == 0) {
- implicit_ctf_input_args.exists = true;
+ auto_source_discovery_restrict_plugin_name = "ctf";
+ auto_source_discovery_restrict_component_class_name = "fs";
} else if (strcmp(arg, "lttng-live") == 0) {
+ auto_source_discovery_restrict_plugin_name = "ctf";
+ auto_source_discovery_restrict_component_class_name = "lttng-live";
implicit_lttng_live_args.exists = true;
} else {
BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy input format:\n %s",
goto error;
}
} else {
- /*
- * Create one source.ctf.fs component, pass it an array
- * with the leftovers.
- * Note that it still has to be named later.
- */
- implicit_ctf_input_args.exists = true;
- ret = append_parameter_to_args(implicit_ctf_input_args.extra_params,
- "paths", leftovers);
- if (ret) {
+ int status;
+
+ status = auto_discover_source_components(plugin_paths, leftovers,
+ auto_source_discovery_restrict_plugin_name,
+ auto_source_discovery_restrict_component_class_name,
+ *default_log_level >= 0 ? *default_log_level : cli_default_log_level,
+ &auto_disc);
+
+ if (status != 0) {
goto error;
}
+
+ create_implicit_component_args_from_auto_discovered_sources(
+ &auto_disc, discovered_source_args);
}
}
- /*
- * 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) {
- BT_CLI_LOGE_APPEND_CAUSE("Cannot create both implicit `%s` and `%s` components.",
- implicit_ctf_input_args.comp_arg->str,
- implicit_lttng_live_args.comp_arg->str);
- goto error;
+ /* If --clock-offset was given, apply it to any src.ctf.fs component. */
+ if (ctf_fs_source_clock_class_offset_arg) {
+ int n;
+
+ n = append_multiple_implicit_components_param(
+ discovered_source_args, "source.ctf.fs", "clock-class-offset-s",
+ ctf_fs_source_clock_class_offset_arg);
+
+ if (n == 0) {
+ BT_CLI_LOGE_APPEND_CAUSE("--clock-offset specified, but no source.ctf.fs component instantiated.");
+ goto error;
+ }
}
- /*
- * If the implicit `source.ctf.fs` or `source.ctf.lttng-live`
- * components exists, make sure there's at least one leftover
- * (which is the path or URL).
- */
- if (implicit_ctf_input_args.exists && bt_value_array_is_empty(leftovers)) {
- BT_CLI_LOGE_APPEND_CAUSE("Missing path for implicit `%s` component.",
- implicit_ctf_input_args.comp_arg->str);
- goto error;
+ /* If --clock-offset-ns was given, apply it to any src.ctf.fs component. */
+ if (ctf_fs_source_clock_class_offset_ns_arg) {
+ int n;
+
+ n = append_multiple_implicit_components_param(
+ discovered_source_args, "source.ctf.fs", "clock-class-offset-ns",
+ ctf_fs_source_clock_class_offset_ns_arg);
+
+ if (n == 0) {
+ BT_CLI_LOGE_APPEND_CAUSE("--clock-offset-ns specified, but no source.ctf.fs component instantiated.");
+ goto error;
+ }
}
+ /*
+ * If the implicit `source.ctf.lttng-live` component exists, make sure
+ * there's at least one leftover (which is the URL).
+ */
if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) {
BT_CLI_LOGE_APPEND_CAUSE("Missing URL for implicit `%s` component.",
implicit_lttng_live_args.comp_arg->str);
}
/* 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 < discovered_source_args->len; i++) {
+ struct implicit_component_args *args;
+ int j;
+
+ args = discovered_source_args->pdata[i];
+
+ g_string_printf(auto_disc_comp_name, "auto-disc-%s", args->comp_arg->str);
+
+ /* Give it a name like `auto-disc-src-ctf-fs`. */
+ for (j = 0; j < auto_disc_comp_name->len; j++) {
+ if (auto_disc_comp_name->str[j] == '.') {
+ auto_disc_comp_name->str[j] = '-';
+ }
+ }
+
+ ret = assign_name_to_implicit_component(args,
+ auto_disc_comp_name->str, all_names, &source_names, true);
+ if (ret) {
+ goto error;
+ }
}
ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
* 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 < discovered_source_args->len; i++) {
+ struct implicit_component_args *args =
+ discovered_source_args->pdata[i];
+
+ ret = append_run_args_for_implicit_component(args, run_args);
+ if (ret) {
+ goto error;
+ }
}
ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
destroy_glist_of_gstring(filter_names);
destroy_glist_of_gstring(sink_names);
bt_value_put_ref(leftovers);
- finalize_implicit_component_args(&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_trimmer_args);
bt_value_put_ref(plugin_paths);
bt_common_destroy_lttng_live_url_parts(<tng_live_url_parts);
+ auto_source_discovery_fini(&auto_disc);
+
+ if (discovered_source_args) {
+ g_ptr_array_free(discovered_source_args, TRUE);
+ }
+
+ g_free(ctf_fs_source_clock_class_offset_arg);
+ g_free(ctf_fs_source_clock_class_offset_ns_arg);
+
+ if (auto_disc_comp_name) {
+ g_string_free(auto_disc_comp_name, TRUE);
+ }
+
return cfg;
}
--- /dev/null
+/*
+ * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CLI-CFG-SRC-AUTO-DISC"
+#include "logging.h"
+
+#include "babeltrace2-cfg-src-auto-disc.h"
+#include "babeltrace2-plugins.h"
+#include "common/common.h"
+
+/* Finalize and free a `struct auto_source_discovery_result`. */
+
+static
+void auto_source_discovery_result_destroy(struct auto_source_discovery_result *res)
+{
+ if (res) {
+ g_free(res->group);
+ bt_value_put_ref(res->inputs);
+ g_free(res);
+ }
+}
+
+/* Allocate and initialize a `struct auto_source_discovery_result`. */
+
+static
+struct auto_source_discovery_result *auto_source_discovery_result_create(
+ const char *plugin_name, const char *source_cc_name,
+ const char *group)
+{
+ struct auto_source_discovery_result *res;
+
+ res = g_new0(struct auto_source_discovery_result, 1);
+ if (!res) {
+ BT_CLI_LOGE_APPEND_CAUSE(
+ "Failed to allocate a auto_source_discovery_result structure.");
+ goto error;
+ }
+
+ res->plugin_name = plugin_name;
+ res->source_cc_name = source_cc_name;
+ res->group = g_strdup(group);
+ if (group && !res->group) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to allocate a string.");
+ goto error;
+ }
+
+ res->inputs = bt_value_array_create();
+ if (!res->inputs) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to allocate an array value.");
+ goto error;
+ }
+
+ goto end;
+error:
+ auto_source_discovery_result_destroy(res);
+
+end:
+ return res;
+}
+
+/* Finalize a `struct auto_source_discovery`. */
+
+void auto_source_discovery_fini(struct auto_source_discovery *auto_disc)
+{
+ if (auto_disc->results) {
+ g_ptr_array_free(auto_disc->results, TRUE);
+ }
+}
+
+/* Initialize an already allocated `struct auto_source_discovery`. */
+
+int auto_source_discovery_init(struct auto_source_discovery *auto_disc)
+{
+ int status;
+
+ auto_disc->results = g_ptr_array_new_with_free_func(
+ (GDestroyNotify) auto_source_discovery_result_destroy);
+
+ if (!auto_disc->results) {
+ goto error;
+ }
+
+ status = 0;
+ goto end;
+
+error:
+ auto_source_discovery_fini(auto_disc);
+ status = -1;
+
+end:
+
+ return status;
+}
+
+/*
+ * Assign `input` to source component class `source_cc_name` of plugin
+ * `plugin_name`, in the group with key `group`.
+ */
+
+static
+int auto_source_discovery_add(struct auto_source_discovery *auto_disc,
+ const char *plugin_name,
+ const char *source_cc_name,
+ const char *group,
+ const char *input)
+{
+ int status;
+ bt_value_array_append_element_status append_status;
+ guint len;
+ guint i;
+ struct auto_source_discovery_result *res = NULL;
+
+ len = auto_disc->results->len;
+ i = len;
+
+ if (group) {
+ for (i = 0; i < len; i++) {
+ res = g_ptr_array_index(auto_disc->results, i);
+
+ if (strcmp(res->plugin_name, plugin_name) != 0) {
+ continue;
+ }
+
+ if (strcmp(res->source_cc_name, source_cc_name) != 0) {
+ continue;
+ }
+
+ if (g_strcmp0(res->group, group) != 0) {
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ if (i == len) {
+ /* Add a new result entry. */
+ res = auto_source_discovery_result_create(plugin_name,
+ source_cc_name, group);
+ if (!res) {
+ goto error;
+ }
+
+ g_ptr_array_add(auto_disc->results, res);
+ }
+
+ append_status = bt_value_array_append_string_element(res->inputs, input);
+ if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to append a string value.");
+ goto error;
+ }
+
+
+ status = 0;
+ goto end;
+
+error:
+ status = -1;
+
+end:
+ return status;
+}
+
+static
+int convert_weight_value(const bt_value *weight_value, double *weight,
+ const char *plugin_name, const char *source_cc_name,
+ const char *input, const char *input_type)
+{
+ enum bt_value_type weight_value_type;
+ int status;
+
+ weight_value_type = bt_value_get_type(weight_value);
+
+ if (weight_value_type == BT_VALUE_TYPE_REAL) {
+ *weight = bt_value_real_get(weight_value);
+ } else if (weight_value_type == BT_VALUE_TYPE_SIGNED_INTEGER) {
+ /* Accept signed integer as a convenience for "return 0" or "return 1" in Python. */
+ *weight = bt_value_integer_signed_get(weight_value);
+ } else {
+ BT_LOGW("support-info query: unexpected type for weight: "
+ "component-class-name=source.%s.%s, input=%s, input-type=%s, "
+ "expected-entry-type=%s, actual-entry-type=%s",
+ plugin_name, source_cc_name, input, input_type,
+ bt_common_value_type_string(BT_VALUE_TYPE_REAL),
+ bt_common_value_type_string(bt_value_get_type(weight_value)));
+ goto error;
+ }
+
+ if (*weight < 0.0 || *weight > 1.0) {
+ BT_LOGW("support-info query: weight value is out of range [0.0, 1.0]: "
+ "component-class-name=source.%s.%s, input=%s, input-type=%s, "
+ "weight=%f",
+ plugin_name, source_cc_name, input, input_type, *weight);
+ goto error;
+ }
+
+ status = 0;
+ goto end;
+
+error:
+ status = -1;
+
+end:
+ return status;
+}
+
+/*
+ * Query all known source components to see if any of them can handle `input`
+ * as the given `type`(arbitrary string, directory or file).
+ *
+ * If `plugin_restrict` is non-NULL, only query source component classes provided
+ * by the plugin with that name.
+ *
+ * If `component_class_restrict` is non-NULL, only query source component classes
+ * with that name.
+ *
+ * Return:
+ *
+ * - > 0 on success, if no source component class has reported that it handles `input`
+ * - 0 on success, if a source component class has reported that it handles `input`
+ * - < 0 on failure (e.g. memory error)
+ */
+static
+int support_info_query_all_sources(const char *input,
+ const char *input_type,
+ bt_query_executor *query_executor, size_t plugin_count,
+ const char *plugin_restrict,
+ const char *component_class_restrict,
+ enum bt_logging_level log_level,
+ struct auto_source_discovery *auto_disc)
+{
+ bt_value_map_insert_entry_status insert_status;
+ bt_value *query_params = NULL;
+ int status;
+ size_t i_plugins;
+ const struct bt_value *query_result = NULL;
+ struct {
+ const bt_component_class_source *source;
+ const bt_plugin *plugin;
+ const bt_value *group;
+ double weigth;
+ } winner = { NULL, NULL, NULL, 0 };
+
+ query_params = bt_value_map_create();
+ if (!query_params) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to allocate a map value.");
+ goto error;
+ }
+
+ insert_status = bt_value_map_insert_string_entry(query_params, "input", input);
+ if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
+ goto error;
+ }
+
+ insert_status = bt_value_map_insert_string_entry(query_params, "type", input_type);
+ if (insert_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to insert a map entry.");
+ goto error;
+ }
+
+ for (i_plugins = 0; i_plugins < plugin_count; i_plugins++) {
+ const bt_plugin *plugin;
+ const char *plugin_name;
+ uint64_t source_count;
+ uint64_t i_sources;
+
+ plugin = borrow_loaded_plugin(i_plugins);
+ plugin_name = bt_plugin_get_name(plugin);
+
+ /*
+ * If the search is restricted to a specific plugin, only consider
+ * the plugin with that name.
+ */
+ if (plugin_restrict && strcmp(plugin_restrict, plugin_name) != 0) {
+ continue;
+ }
+
+ source_count = bt_plugin_get_source_component_class_count(plugin);
+
+ for (i_sources = 0; i_sources < source_count; i_sources++) {
+ const bt_component_class_source *source_cc;
+ const bt_component_class *cc;
+ const char *source_cc_name;
+ bt_query_executor_query_status query_status;
+
+ source_cc = bt_plugin_borrow_source_component_class_by_index_const(plugin, i_sources);
+ cc = bt_component_class_source_as_component_class_const(source_cc);
+ source_cc_name = bt_component_class_get_name(cc);
+
+ /*
+ * If the search is restricted to a specific component class, only consider the
+ * component classes with that name.
+ */
+ if (component_class_restrict && strcmp(component_class_restrict, source_cc_name) != 0) {
+ continue;
+ }
+
+ BT_LOGD("support-info query: before: component-class-name=source.%s.%s, input=%s, "
+ "type=%s", plugin_name, source_cc_name, input, input_type);
+
+ BT_VALUE_PUT_REF_AND_RESET(query_result);
+ query_status = bt_query_executor_query(query_executor, cc, "support-info",
+ query_params, log_level, &query_result);
+
+ if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_OK) {
+ double weight;
+ const bt_value *group_value = NULL;
+ enum bt_value_type query_result_type;
+
+ BT_ASSERT(query_result);
+
+ query_result_type = bt_value_get_type(query_result);
+
+ if (query_result_type == BT_VALUE_TYPE_REAL || query_result_type == BT_VALUE_TYPE_SIGNED_INTEGER) {
+ if (convert_weight_value(query_result, &weight, plugin_name, source_cc_name, input, input_type) != 0) {
+ /* convert_weight_value has already warned. */
+ continue;
+ }
+ } else if (query_result_type == BT_VALUE_TYPE_MAP) {
+ const bt_value *weight_value;
+
+ if (!bt_value_map_has_entry(query_result, "weight")) {
+ BT_LOGW("support-info query: result is missing `weight` entry: "
+ "component-class-name=source.%s.%s, input=%s, input-type=%s",
+ bt_plugin_get_name(plugin),
+ bt_component_class_get_name(cc), input,
+ input_type);
+ continue;
+ }
+
+ weight_value = bt_value_map_borrow_entry_value_const(query_result, "weight");
+ BT_ASSERT(weight_value);
+
+ if (convert_weight_value(weight_value, &weight, plugin_name, source_cc_name, input, input_type) != 0) {
+ /* convert_weight_value has already warned. */
+ continue;
+ }
+
+ if (bt_value_map_has_entry(query_result, "group")) {
+ enum bt_value_type group_value_type;
+
+ group_value = bt_value_map_borrow_entry_value_const(query_result, "group");
+ BT_ASSERT(group_value);
+
+ group_value_type = bt_value_get_type(group_value);
+
+ if (group_value_type == BT_VALUE_TYPE_NULL) {
+ /* Do as if no value was passed. */
+ group_value = NULL;
+ } else if (bt_value_get_type(group_value) != BT_VALUE_TYPE_STRING) {
+ BT_LOGW("support-info query: unexpected type for entry `group`: "
+ "component-class-name=source.%s.%s, input=%s, input-type=%s, "
+ "expected-entry-type=%s,%s, actual-entry-type=%s",
+ bt_plugin_get_name(plugin),
+ bt_component_class_get_name(cc), input,
+ input_type,
+ bt_common_value_type_string(BT_VALUE_TYPE_NULL),
+ bt_common_value_type_string(BT_VALUE_TYPE_STRING),
+ bt_common_value_type_string(bt_value_get_type(group_value)));
+ continue;
+ }
+ }
+ } else {
+ BT_LOGW("support-info query: unexpected result type: "
+ "component-class-name=source.%s.%s, input=%s, input-type=%s, "
+ "expected-types=%s,%s,%s, actual-type=%s",
+ bt_plugin_get_name(plugin),
+ bt_component_class_get_name(cc), input,
+ input_type,
+ bt_common_value_type_string(BT_VALUE_TYPE_REAL),
+ bt_common_value_type_string(BT_VALUE_TYPE_MAP),
+ bt_common_value_type_string(BT_VALUE_TYPE_SIGNED_INTEGER),
+ bt_common_value_type_string(bt_value_get_type(query_result)));
+ continue;
+ }
+
+ BT_LOGD("support-info query: success: component-class-name=source.%s.%s, input=%s, "
+ "type=%s, weight=%f\n",
+ bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
+ input_type, weight);
+
+ if (weight > winner.weigth) {
+ winner.source = source_cc;
+ winner.plugin = plugin;
+
+ bt_value_put_ref(winner.group);
+ winner.group = group_value;
+ bt_value_get_ref(winner.group);
+
+ winner.weigth = weight;
+ }
+ } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_ERROR) {
+ BT_CLI_LOGE_APPEND_CAUSE("support-info query failed.");
+ goto error;
+ } else if (query_status == BT_QUERY_EXECUTOR_QUERY_STATUS_MEMORY_ERROR) {
+ BT_CLI_LOGE_APPEND_CAUSE("Memory error.");
+ goto error;
+ } else {
+ BT_LOGD("support-info query: failure: component-class-name=source.%s.%s, input=%s, "
+ "type=%s, status=%s\n",
+ bt_plugin_get_name(plugin), bt_component_class_get_name(cc), input,
+ input_type,
+ bt_common_func_status_string(query_status));
+ }
+ }
+ }
+
+ if (winner.source) {
+ const char *source_name;
+ const char *plugin_name;
+ const char *group;
+
+ source_name = bt_component_class_get_name(
+ bt_component_class_source_as_component_class_const(winner.source));
+ plugin_name = bt_plugin_get_name(winner.plugin);
+ group = winner.group ? bt_value_string_get(winner.group) : NULL;
+
+ BT_LOGI("Input %s is awarded to component class source.%s.%s with weight %f",
+ input, plugin_name, source_name, winner.weigth);
+
+ status = auto_source_discovery_add(auto_disc, plugin_name, source_name, group, input);
+ if (status != 0) {
+ goto error;
+ }
+ } else {
+ BT_LOGI("Input %s (%s) was not recognized by any source component class.",
+ input, input_type);
+ status = 1;
+ }
+
+ goto end;
+
+error:
+ status = -1;
+
+end:
+ bt_value_put_ref(query_result);
+ bt_value_put_ref(query_params);
+ bt_value_put_ref(winner.group);
+
+ return status;
+}
+
+/*
+ * Look for a source component class that recognizes `input` as an arbitrary
+ * string.
+ *
+ * Same return value semantic as `support_info_query_all_sources`.
+ */
+
+static
+int auto_discover_source_for_input_as_string(const char *input,
+ bt_query_executor *query_executor, size_t plugin_count,
+ const char *plugin_restrict,
+ const char *component_class_restrict,
+ enum bt_logging_level log_level,
+ struct auto_source_discovery *auto_disc)
+{
+ return support_info_query_all_sources(input, "string",
+ query_executor, plugin_count, plugin_restrict,
+ component_class_restrict, log_level, auto_disc);
+}
+
+static
+int auto_discover_source_for_input_as_dir_or_file_rec(GString *input,
+ bt_query_executor *query_executor, size_t plugin_count,
+ const char *plugin_restrict,
+ const char *component_class_restrict,
+ enum bt_logging_level log_level,
+ struct auto_source_discovery *auto_disc)
+{
+ int status;
+ GError *error = NULL;
+
+ if (g_file_test(input->str, G_FILE_TEST_IS_REGULAR)) {
+ /* It's a file. */
+ status = support_info_query_all_sources(input->str,
+ "file", query_executor, plugin_count,
+ plugin_restrict, component_class_restrict, log_level, auto_disc);
+ } else if (g_file_test(input->str, G_FILE_TEST_IS_DIR)) {
+ GDir *dir;
+ const gchar *dirent;
+ gsize saved_input_len;
+ int dir_status = 1;
+
+ /* It's a directory. */
+ status = support_info_query_all_sources(input->str,
+ "directory", query_executor, plugin_count,
+ plugin_restrict, component_class_restrict, log_level,
+ auto_disc);
+
+ if (status < 0) {
+ /* Fatal error. */
+ goto error;
+ } else if (status == 0) {
+ /*
+ * A component class claimed this input as a directory,
+ * don't recurse.
+ */
+ goto end;
+ }
+
+ dir = g_dir_open(input->str, 0, &error);
+ if (!dir) {
+ const char *fmt = "Failed to open directory %s: %s";
+ BT_LOGW(fmt, input->str, error->message);
+
+ if (errno == EACCES) {
+ /* This is not a fatal error, we just skip it. */
+ status = 1;
+ goto end;
+ } else {
+ BT_CLI_LOGE_APPEND_CAUSE(fmt, input->str,
+ error->message);
+ goto error;
+ }
+ }
+
+ saved_input_len = input->len;
+
+ do {
+ errno = 0;
+ dirent = g_dir_read_name(dir);
+ if (dirent) {
+ g_string_append_c_inline(input, G_DIR_SEPARATOR);
+ g_string_append(input, dirent);
+
+ status = auto_discover_source_for_input_as_dir_or_file_rec(
+ input, query_executor, plugin_count,
+ plugin_restrict, component_class_restrict,
+ log_level, auto_disc);
+
+ g_string_truncate(input, saved_input_len);
+
+ if (status < 0) {
+ /* Fatal error. */
+ goto error;
+ } else if (status == 0) {
+ dir_status = 0;
+ }
+ } else if (errno != 0) {
+ BT_LOGW_ERRNO("Failed to read directory entry", ": dir=%s", input->str);
+ goto error;
+ }
+ } while (dirent != NULL);
+
+ status = dir_status;
+
+ g_dir_close(dir);
+ } else {
+ BT_LOGD("Skipping %s, not a file or directory", input->str);
+ status = 1;
+ }
+
+ goto end;
+
+error:
+ status = -1;
+
+end:
+
+ if (error) {
+ g_error_free(error);
+ }
+
+ return status;
+}
+
+/*
+ * Look for a source component class that recognizes `input` as a directory or
+ * file. If `input` is a directory and is not directly recognized, recurse and
+ * apply the same logic to children nodes.
+ *
+ * Same return value semantic as `support_info_query_all_sources`.
+ */
+
+static
+int auto_discover_source_for_input_as_dir_or_file(const char *input,
+ bt_query_executor *query_executor, size_t plugin_count,
+ const char *plugin_restrict,
+ const char *component_class_restrict,
+ enum bt_logging_level log_level,
+ struct auto_source_discovery *auto_disc)
+{
+ GString *mutable_input;
+ int status;
+
+ mutable_input = g_string_new(input);
+ if (!mutable_input) {
+ status = -1;
+ goto end;
+ }
+
+ status = auto_discover_source_for_input_as_dir_or_file_rec(
+ mutable_input, query_executor, plugin_count, plugin_restrict,
+ component_class_restrict, log_level, auto_disc);
+
+ g_string_free(mutable_input, TRUE);
+end:
+ return status;
+}
+
+int auto_discover_source_components(
+ const bt_value *plugin_paths,
+ const bt_value *inputs,
+ const char *plugin_restrict,
+ const char *component_class_restrict,
+ enum bt_logging_level log_level,
+ struct auto_source_discovery *auto_disc)
+{
+ uint64_t i_inputs, input_count;
+ int status;
+ size_t plugin_count;
+ bt_query_executor *query_executor = NULL;
+
+ input_count = bt_value_array_get_size(inputs);
+
+ status = require_loaded_plugins(plugin_paths);
+ if (status != 0) {
+ goto end;
+ }
+
+ plugin_count = get_loaded_plugins_count();
+
+ query_executor = bt_query_executor_create();
+ if (!query_executor) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to allocate a query executor.");
+ goto end;
+ }
+
+ for (i_inputs = 0; i_inputs < input_count; i_inputs++) {
+ const bt_value *input_value;
+ const char *input;
+
+ input_value = bt_value_array_borrow_element_by_index_const(inputs, i_inputs);
+ input = bt_value_string_get(input_value);
+ status = auto_discover_source_for_input_as_string(input, query_executor,
+ plugin_count, plugin_restrict, component_class_restrict,
+ log_level, auto_disc);
+ if (status < 0) {
+ /* Fatal error. */
+ goto end;
+ } else if (status == 0) {
+ /* A component class has claimed this input as an arbitrary string. */
+ continue;
+ }
+
+ status = auto_discover_source_for_input_as_dir_or_file(input,
+ query_executor, plugin_count, plugin_restrict,
+ component_class_restrict, log_level, auto_disc);
+ if (status < 0) {
+ /* Fatal error. */
+ goto end;
+ } else if (status == 0) {
+ /*
+ * This input (or something under it) was recognized.
+ */
+ continue;
+ }
+
+ BT_LOGW("No trace was found based on input `%s`.", input);
+ }
+
+ status = 0;
+end:
+ bt_query_executor_put_ref(query_executor);
+ return status;
+}
--- /dev/null
+#ifndef CLI_BABELTRACE_CFG_SRC_AUTO_DISC_H
+#define CLI_BABELTRACE_CFG_SRC_AUTO_DISC_H
+
+/*
+ * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+
+#include <babeltrace2/babeltrace.h>
+
+struct auto_source_discovery {
+ /* Array of `struct auto_source_discovery_result *`. */
+ GPtrArray *results;
+};
+
+/* Value type of the `auto_source_discovery::results` array. */
+
+struct auto_source_discovery_result {
+ /*
+ * `plugin_name` and `source_cc_name` are borrowed from the plugin and source
+ * component class (which outlive this structure).
+ */
+ const char *plugin_name;
+ const char *source_cc_name;
+
+ /*
+ * `group` is owned by this structure.
+ *
+ * May be NULL, to mean "no group".
+ */
+ gchar *group;
+
+ /* Array of input strings. */
+ bt_value *inputs;
+};
+
+int auto_source_discovery_init(struct auto_source_discovery *auto_disc);
+void auto_source_discovery_fini(struct auto_source_discovery *auto_disc);
+
+/*
+ * Given `inputs` a list of strings, query source component classes to discover
+ * which source components should be instantiated to deal with these inputs.
+ *
+ * Return 0 if execution completed successfully, < 0 otherwise.
+ */
+
+int auto_discover_source_components(
+ const bt_value *plugin_paths,
+ const bt_value *inputs,
+ const char *plugin_filter,
+ const char *component_class_filter,
+ enum bt_logging_level log_level,
+ struct auto_source_discovery *auto_disc);
+
+#endif /* CLI_BABELTRACE_CFG_SRC_AUTO_DISC_H */
return ret;
}
-int load_all_plugins(const bt_value *plugin_paths)
+int require_loaded_plugins(const bt_value *plugin_paths)
{
static bool loaded = false;
static int ret = 0;
BT_HIDDEN void init_loaded_plugins(void);
BT_HIDDEN void fini_loaded_plugins(void);
-BT_HIDDEN int load_all_plugins(const bt_value *plugin_paths);
+BT_HIDDEN int require_loaded_plugins(const bt_value *plugin_paths);
BT_HIDDEN const bt_plugin *find_loaded_plugin(const char *name);
BT_HIDDEN size_t get_loaded_plugins_count(void);
print_cfg(cfg);
if (cfg->command_needs_plugins) {
- ret = load_all_plugins(cfg->plugin_paths);
+ ret = require_loaded_plugins(cfg->plugin_paths);
if (ret) {
BT_CLI_LOGE_APPEND_CAUSE(
"Failed to load plugins: ret=%d", ret);
for (i = 0; i < bt_value_array_get_size(paths_value); i++) {
const bt_value *path_value = bt_value_array_borrow_element_by_index_const(paths_value, i);
- const char *path = bt_value_string_get(path_value);
+ const char *input = bt_value_string_get(path_value);
ret = ctf_fs_component_create_ctf_fs_traces_one_root(ctf_fs,
- path);
+ input);
if (ret) {
goto end;
}
*/
static
-bool validate_paths_parameter(struct ctf_fs_component *ctf_fs,
- const bt_value *paths)
+bool validate_inputs_parameter(struct ctf_fs_component *ctf_fs,
+ const bt_value *inputs)
{
bool ret;
bt_value_type type;
bt_logging_level log_level = ctf_fs->log_level;
bt_self_component *self_comp = ctf_fs->self_comp;
- if (!paths) {
- BT_COMP_LOGE("missing \"paths\" parameter");
+ if (!inputs) {
+ BT_COMP_LOGE("missing \"inputs\" parameter");
goto error;
}
- type = bt_value_get_type(paths);
+ type = bt_value_get_type(inputs);
if (type != BT_VALUE_TYPE_ARRAY) {
- BT_COMP_LOGE("`paths` parameter: expecting array value: type=%s",
+ BT_COMP_LOGE("`inputs` parameter: expecting array value: type=%s",
bt_common_value_type_string(type));
goto error;
}
- for (i = 0; i < bt_value_array_get_size(paths); i++) {
+ for (i = 0; i < bt_value_array_get_size(inputs); i++) {
const bt_value *elem;
- elem = bt_value_array_borrow_element_by_index_const(paths, i);
+ elem = bt_value_array_borrow_element_by_index_const(inputs, i);
type = bt_value_get_type(elem);
if (type != BT_VALUE_TYPE_STRING) {
- BT_COMP_LOGE("`paths` parameter: expecting string value: index=%" PRIu64 ", type=%s",
+ BT_COMP_LOGE("`inputs` parameter: expecting string value: index=%" PRIu64 ", type=%s",
i, bt_common_value_type_string(type));
goto error;
}
}
bool read_src_fs_parameters(const bt_value *params,
- const bt_value **paths, struct ctf_fs_component *ctf_fs) {
+ const bt_value **inputs, struct ctf_fs_component *ctf_fs) {
bool ret;
const bt_value *value;
bt_logging_level log_level = ctf_fs->log_level;
bt_self_component *self_comp = ctf_fs->self_comp;
- /* paths parameter */
- *paths = bt_value_map_borrow_entry_value_const(params, "paths");
- if (!validate_paths_parameter(ctf_fs, *paths)) {
+ /* inputs parameter */
+ *inputs = bt_value_map_borrow_entry_value_const(params, "inputs");
+ if (!validate_inputs_parameter(ctf_fs, *inputs)) {
goto error;
}
{
struct ctf_fs_component *ctf_fs = NULL;
guint i;
- const bt_value *paths_value;
+ const bt_value *inputs_value;
bt_self_component *self_comp =
bt_self_component_source_as_self_component(self_comp_src);
goto error;
}
- if (!read_src_fs_parameters(params, &paths_value, ctf_fs)) {
+ if (!read_src_fs_parameters(params, &inputs_value, ctf_fs)) {
goto error;
}
ctf_fs->self_comp = self_comp;
ctf_fs->self_comp_src = self_comp_src;
- if (ctf_fs_component_create_ctf_fs_traces(self_comp_src, ctf_fs, paths_value)) {
+ if (ctf_fs_component_create_ctf_fs_traces(self_comp_src, ctf_fs, inputs_value)) {
goto error;
}
} else if (strcmp(object, "trace-info") == 0) {
status = trace_info_query(comp_class, params, log_level,
result);
+ } else if (!strcmp(object, "support-info")) {
+ status = support_info_query(comp_class, params, log_level, result);
} else {
BT_LOGE("Unknown query object `%s`", object);
status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_INVALID_OBJECT;
bt_component_class_query_method_status status =
BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
bt_value *result = NULL;
- const bt_value *paths_value = NULL;
+ const bt_value *inputs_value = NULL;
int ret = 0;
guint i;
goto error;
}
- if (!read_src_fs_parameters(params, &paths_value, ctf_fs)) {
+ if (!read_src_fs_parameters(params, &inputs_value, ctf_fs)) {
status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_INVALID_PARAMS;
goto error;
}
- if (ctf_fs_component_create_ctf_fs_traces(NULL, ctf_fs, paths_value)) {
+ if (ctf_fs_component_create_ctf_fs_traces(NULL, ctf_fs, inputs_value)) {
goto error;
}
*user_result = result;
return status;
}
+
+BT_HIDDEN
+bt_component_class_query_method_status support_info_query(
+ bt_self_component_class_source *comp_class,
+ const bt_value *params, bt_logging_level log_level,
+ const bt_value **user_result)
+{
+ const bt_value *input_type_value;
+ const char *input_type;
+ bt_component_class_query_method_status status;
+ double weight = 0;
+ gchar *metadata_path = NULL;
+ bt_value *result = NULL;
+
+ input_type_value = bt_value_map_borrow_entry_value_const(params, "type");
+ BT_ASSERT(input_type_value);
+ BT_ASSERT(bt_value_get_type(input_type_value) == BT_VALUE_TYPE_STRING);
+ input_type = bt_value_string_get(input_type_value);
+
+ result = bt_value_map_create();
+ if (!result) {
+ status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+ goto end;
+ }
+
+ if (strcmp(input_type, "directory") == 0) {
+ const bt_value *input_value;
+ const char *path;
+
+ input_value = bt_value_map_borrow_entry_value_const(params, "input");
+ BT_ASSERT(input_value);
+ BT_ASSERT(bt_value_get_type(input_value) == BT_VALUE_TYPE_STRING);
+ path = bt_value_string_get(input_value);
+
+ metadata_path = g_build_filename(path, CTF_FS_METADATA_FILENAME, NULL);
+ if (!metadata_path) {
+ status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+ goto end;
+ }
+
+ /*
+ * If the metadata file exists in this directory, consider it to
+ * be a CTF trace.
+ */
+ if (g_file_test(metadata_path, G_FILE_TEST_EXISTS)) {
+ weight = 0.5;
+ }
+ }
+
+ if (bt_value_map_insert_real_entry(result, "weight", weight) != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
+ status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+ goto end;
+ }
+
+ /*
+ * Use the arbitrary constant string "ctf" as the group, such that all
+ * found ctf traces are passed to the same instance of src.ctf.fs.
+ */
+ if (bt_value_map_insert_string_entry(result, "group", "ctf") != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
+ status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR;
+ goto end;
+ }
+
+ *user_result = result;
+ result = NULL;
+ status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
+
+end:
+ g_free(metadata_path);
+ bt_value_put_ref(result);
+
+ return status;
+}
const bt_value *params, bt_logging_level log_level,
const bt_value **result);
+BT_HIDDEN
+bt_component_class_query_method_status support_info_query(
+ bt_self_component_class_source *comp_class,
+ const bt_value *params, bt_logging_level log_level,
+ const bt_value **result);
+
#endif /* BABELTRACE_PLUGIN_CTF_FS_QUERY_H */
def test_create_good_with_path_params(self):
spec = bt2.ComponentSpec('plugin', 'compcls', 'a path')
- self.assertEqual(spec.params['paths'], ['a path'])
+ self.assertEqual(spec.params['inputs'], ['a path'])
def test_create_wrong_plugin_name_type(self):
with self.assertRaises(TypeError):
hist = _count_msgs_by_type(msgs)
self.assertEqual(hist[bt2.message._EventMessage], 3)
- def test_iter_intersection_no_path_param(self):
+ def test_iter_intersection_no_inputs_param(self):
specs = [bt2.ComponentSpec('text', 'dmesg', {'read-from-stdin': True})]
with self.assertRaises(bt2.Error):
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License, version 2 only, as
+# published by the Free Software Foundation.
+#
+# 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.
+
+# Test the auto source disovery mechanism of the CLI.
+
+if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+SH_TAP=1 source "$UTILSSH"
+
+NUM_TESTS=2
+
+plan_tests $NUM_TESTS
+
+data_dir=$(readlink -f "${BT_TESTS_DATADIR}/cli/auto-source-discovery")
+plugin_dir="${data_dir}"
+trace_dir="${data_dir}/traces"
+
+expected_file=$(mktemp expected.XXXXXX)
+actual_file=$(mktemp actual.XXXXXX)
+
+run_python_bt2 "$BT_TESTS_BT2_BIN" convert --plugin-path "${plugin_dir}" "ABCDE" "${trace_dir}" some_other_leftover | sort > "$actual_file"
+ok "${PIPESTATUS[0]}" "successful execution"
+
+cat > "$expected_file" <<END
+TestSourceABCDE: ABCDE
+TestSourceExt: ${trace_dir}/aaa1, ${trace_dir}/aaa2, ${trace_dir}/aaa3
+TestSourceExt: ${trace_dir}/bbb1, ${trace_dir}/bbb2
+TestSourceExt: ${trace_dir}/ccc1
+TestSourceExt: ${trace_dir}/ccc2
+TestSourceExt: ${trace_dir}/ccc3
+TestSourceExt: ${trace_dir}/ccc4
+TestSourceSomeDir: ${trace_dir}/some-dir
+END
+
+diff -u "$expected_file" "$actual_file"
+ok "$?" "sources are auto-discovered"
+
+rm -f "$expected_file" "$actual_file"
path_to_trace="C://path/to/trace"
output_path="C://output/path"
else
- path_to_trace="/path/to/trace"
+ path_to_trace=$(readlink -f "${BT_CTF_TRACES_PATH}/succeed/succeed1")
+ path_to_trace2=$(readlink -f "${BT_CTF_TRACES_PATH}/succeed/succeed2")
output_path="/output/path"
fi
plan_tests 77
-test_bt_convert_run_args 'path leftover' "$path_to_trace" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftovers' "$path_to_trace ${path_to_trace}2 ${path_to_trace}3" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\", \"${path_to_trace}2\", \"${path_to_trace}3\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer: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 --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect ZZ:muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + named user source with --name --params' "$path_to_trace --component source.another.source --name HELLO --params salut=yes" "--component source.another.source --name HELLO --params salut=yes --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect HELLO:muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + user source with --path --params' "$path_to_trace --component source.another.source --path some-path --params salut=yes" "--component source.another.source --params 'path=\"some-path\"' --params salut=yes --name source.another.source --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect 'source\\.another\\.source:muxer' --connect source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover' "$path_to_trace" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftovers' "$path_to_trace $path_to_trace2" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\", \"${path_to_trace2}\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer: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 auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect ZZ:muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + named user source with --name --params' "$path_to_trace --component source.another.source --name HELLO --params salut=yes" "--component source.another.source --name HELLO --params salut=yes --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect HELLO:muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + user source with --path --params' "$path_to_trace --component source.another.source --path some-path --params salut=yes" "--component source.another.source --params 'path=\"some-path\"' --params salut=yes --name source.another.source --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect 'source\\.another\\.source:muxer' --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
test_bt_convert_run_args 'user source with --url + -o dummy' '--component MY:source.my.source --url the-url -o dummy' "--component MY:source.my.source --params 'url=\"the-url\"' --component sink.utils.dummy --name dummy --component filter.utils.muxer --name muxer --connect MY:muxer --connect muxer:dummy"
-test_bt_convert_run_args 'path leftover + --omit-home-plugin-path' "$path_to_trace --omit-home-plugin-path" "--omit-home-plugin-path --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --omit-system-plugin-path' "$path_to_trace --omit-system-plugin-path" "--omit-system-plugin-path --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --plugin-path' "--plugin-path=PATH1:PATH2 $path_to_trace" "--plugin-path PATH1:PATH2 --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --omit-home-plugin-path' "$path_to_trace --omit-home-plugin-path" "--omit-home-plugin-path --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --omit-system-plugin-path' "$path_to_trace --omit-system-plugin-path" "--omit-system-plugin-path --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --plugin-path' "--plugin-path=PATH1:PATH2 $path_to_trace" "--plugin-path PATH1:PATH2 --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
test_bt_convert_run_args 'unnamed user source' '--component source.salut.com' "--component source.salut.com --name source.salut.com --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect 'source\.salut\.com:muxer' --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + user source named `source-ctf-fs`' "--component source-ctf-fs:source.salut.com $path_to_trace" "--component source-ctf-fs:source.salut.com --component source.ctf.fs --name source-ctf-fs-0 --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect source-ctf-fs-0:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + user sink named `pretty`' "--component pretty:sink.my.sink $path_to_trace" "--component pretty:sink.my.sink --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-seconds + user sink named `pretty`' "--clock-seconds --component pretty:sink.my.sink $path_to_trace" "--component pretty:sink.my.sink --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty-0 --params clock-seconds=yes --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty --connect muxer:pretty-0"
-test_bt_convert_run_args 'path leftover + user filter named `muxer`' "--component muxer:filter.salut.com $path_to_trace" "--component muxer:filter.salut.com --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer-0 --connect source-ctf-fs:muxer-0 --connect muxer-0:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --begin + user filter named `trimmer`' "$path_to_trace --component trimmer:filter.salut.com --begin=abc" "--component trimmer:filter.salut.com --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer-0 --params 'begin=\"abc\"' --connect source-ctf-fs:muxer --connect muxer:trimmer-0 --connect trimmer-0:trimmer --connect trimmer:pretty"
-test_bt_convert_run_args 'path leftover + --plugin-path' "$path_to_trace --plugin-path a:b:c" "--plugin-path a:b:c --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --omit-home-plugin-path --omit-system-plugin-path' "$path_to_trace --omit-home-plugin-path --omit-system-plugin-path" "--omit-home-plugin-path --omit-system-plugin-path --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --begin' "$path_to_trace --begin=123" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer --params 'begin=\"123\"' --connect source-ctf-fs:muxer --connect muxer:trimmer --connect trimmer:pretty"
-test_bt_convert_run_args 'path leftover + --begin --end' "$path_to_trace --end=456 --begin 123" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer --params 'end=\"456\"' --params 'begin=\"123\"' --connect source-ctf-fs:muxer --connect muxer:trimmer --connect trimmer:pretty"
-test_bt_convert_run_args 'path leftover + --timerange' "$path_to_trace --timerange=[abc,xyz]" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer --params 'begin=\"abc\"' --params 'end=\"xyz\"' --connect source-ctf-fs:muxer --connect muxer:trimmer --connect trimmer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-cycles' "$path_to_trace --clock-cycles" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-cycles=yes --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-date' "$path_to_trace --clock-date" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-date=yes --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-force-correlate' "$path_to_trace --clock-force-correlate" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --params assume-absolute-clock-classes=yes --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-gmt' "$path_to_trace --clock-gmt" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-gmt=yes --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-offset' "$path_to_trace --clock-offset=15487" "--component source.ctf.fs --name source-ctf-fs --params clock-class-offset-s=15487 --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-offset-ns' "$path_to_trace --clock-offset-ns=326159487" "--component source.ctf.fs --name source-ctf-fs --params clock-class-offset-ns=326159487 --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --clock-seconds' "$path_to_trace --clock-seconds" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-seconds=yes --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --color' "$path_to_trace --color=never" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params 'color=\"never\"' --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --debug-info' "$path_to_trace --debug-info" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$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 + --debug-info-dir' "$path_to_trace --debug-info-dir=${output_path}" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --params 'debug-info-dir=\"${output_path}\"' --connect source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
-test_bt_convert_run_args 'path leftover + --debug-info-target-prefix' "$path_to_trace --debug-info-target-prefix=${output_path}" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --params 'target-prefix=\"${output_path}\"' --connect source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
-test_bt_convert_run_args 'path leftover + --debug-info-full-path' "$path_to_trace --debug-info-full-path" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --params full-path=yes --connect source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
-test_bt_convert_run_args 'path leftover + --fields=trace:domain,loglevel' "--fields=trace:domain,loglevel $path_to_trace" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params field-trace:domain=yes,field-loglevel=yes,field-default=hide --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --fields=all' "--fields=all $path_to_trace" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params field-default=show --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --names=context,header' "--names=context,header $path_to_trace" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params name-context=yes,name-header=yes,name-default=hide --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --names=all' "--names=all $path_to_trace" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params name-default=show --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --no-delta' "$path_to_trace --no-delta" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params no-delta=yes --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + --output' "$path_to_trace --output $output_path" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params 'path=\"$output_path\"' --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + -i ctf' "$path_to_trace -i ctf" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + user source named `auto-disc-source-ctf-fs`' "--component auto-disc-source-ctf-fs:source.salut.com $path_to_trace" "--component auto-disc-source-ctf-fs:source.salut.com --component source.ctf.fs --name auto-disc-source-ctf-fs-0 --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect auto-disc-source-ctf-fs-0:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + user sink named `pretty`' "--component pretty:sink.my.sink $path_to_trace" "--component pretty:sink.my.sink --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-seconds + user sink named `pretty`' "--clock-seconds --component pretty:sink.my.sink $path_to_trace" "--component pretty:sink.my.sink --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty-0 --params clock-seconds=yes --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty --connect muxer:pretty-0"
+test_bt_convert_run_args 'path leftover + user filter named `muxer`' "--component muxer:filter.salut.com $path_to_trace" "--component muxer:filter.salut.com --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer-0 --connect auto-disc-source-ctf-fs:muxer-0 --connect muxer-0:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --begin + user filter named `trimmer`' "$path_to_trace --component trimmer:filter.salut.com --begin=abc" "--component trimmer:filter.salut.com --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer-0 --params 'begin=\"abc\"' --connect auto-disc-source-ctf-fs:muxer --connect muxer:trimmer-0 --connect trimmer-0:trimmer --connect trimmer:pretty"
+test_bt_convert_run_args 'path leftover + --plugin-path' "$path_to_trace --plugin-path a:b:c" "--plugin-path a:b:c --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --omit-home-plugin-path --omit-system-plugin-path' "$path_to_trace --omit-home-plugin-path --omit-system-plugin-path" "--omit-home-plugin-path --omit-system-plugin-path --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --begin' "$path_to_trace --begin=123" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer --params 'begin=\"123\"' --connect auto-disc-source-ctf-fs:muxer --connect muxer:trimmer --connect trimmer:pretty"
+test_bt_convert_run_args 'path leftover + --begin --end' "$path_to_trace --end=456 --begin 123" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer --params 'end=\"456\"' --params 'begin=\"123\"' --connect auto-disc-source-ctf-fs:muxer --connect muxer:trimmer --connect trimmer:pretty"
+test_bt_convert_run_args 'path leftover + --timerange' "$path_to_trace --timerange=[abc,xyz]" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.utils.trimmer --name trimmer --params 'begin=\"abc\"' --params 'end=\"xyz\"' --connect auto-disc-source-ctf-fs:muxer --connect muxer:trimmer --connect trimmer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-cycles' "$path_to_trace --clock-cycles" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-cycles=yes --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-date' "$path_to_trace --clock-date" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-date=yes --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-force-correlate' "$path_to_trace --clock-force-correlate" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --params assume-absolute-clock-classes=yes --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-gmt' "$path_to_trace --clock-gmt" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-gmt=yes --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-offset' "$path_to_trace --clock-offset=15487" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params clock-class-offset-s=15487 --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-offset-ns' "$path_to_trace --clock-offset-ns=326159487" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params clock-class-offset-ns=326159487 --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --clock-seconds' "$path_to_trace --clock-seconds" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-seconds=yes --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --color' "$path_to_trace --color=never" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params 'color=\"never\"' --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --debug-info' "$path_to_trace --debug-info" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$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 auto-disc-source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
+test_bt_convert_run_args 'path leftover + --debug-info-dir' "$path_to_trace --debug-info-dir=${output_path}" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --params 'debug-info-dir=\"${output_path}\"' --connect auto-disc-source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
+test_bt_convert_run_args 'path leftover + --debug-info-target-prefix' "$path_to_trace --debug-info-target-prefix=${output_path}" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --params 'target-prefix=\"${output_path}\"' --connect auto-disc-source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
+test_bt_convert_run_args 'path leftover + --debug-info-full-path' "$path_to_trace --debug-info-full-path" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --component filter.lttng-utils.debug-info --name debug-info --params full-path=yes --connect auto-disc-source-ctf-fs:muxer --connect muxer:debug-info --connect debug-info:pretty"
+test_bt_convert_run_args 'path leftover + --fields=trace:domain,loglevel' "--fields=trace:domain,loglevel $path_to_trace" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params field-trace:domain=yes,field-loglevel=yes,field-default=hide --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --fields=all' "--fields=all $path_to_trace" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params field-default=show --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --names=context,header' "--names=context,header $path_to_trace" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params name-context=yes,name-header=yes,name-default=hide --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --names=all' "--names=all $path_to_trace" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params name-default=show --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --no-delta' "$path_to_trace --no-delta" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params no-delta=yes --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + --output' "$path_to_trace --output $output_path" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params 'path=\"$output_path\"' --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + -i ctf' "$path_to_trace -i ctf" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
test_bt_convert_run_args 'URL leftover + -i lttng-live' 'net://some-host/host/target/session -i lttng-live' "--component source.ctf.lttng-live --name lttng-live --params 'url=\"net://some-host/host/target/session\"' --params 'session-not-found-action=\"end\"' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect lttng-live:muxer --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + user sink + -o text' "$path_to_trace --component=sink.abc.def -o text" "--component sink.abc.def --name sink.abc.def --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect 'muxer:sink\.abc\.def' --connect muxer:pretty"
-test_bt_convert_run_args 'path leftover + -o dummy' "$path_to_trace -o dummy" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.utils.dummy --name dummy --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:dummy"
-test_bt_convert_run_args 'path leftover + -o dummy + --clock-seconds' "$path_to_trace -o dummy --clock-seconds" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-seconds=yes --component sink.utils.dummy --name dummy --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:pretty --connect muxer:dummy"
-test_bt_convert_run_args 'path leftover + -o ctf + --output' "$path_to_trace -o ctf --output $output_path" "--component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component sink.ctf.fs --name sink-ctf-fs --params 'path=\"$output_path\"' --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect muxer:sink-ctf-fs"
-test_bt_convert_run_args 'path leftover + user sink with log level' "$path_to_trace -c sink.mein.sink -lW" "--component sink.mein.sink --log-level W --name sink.mein.sink --component source.ctf.fs --name source-ctf-fs --params 'paths=[\"$path_to_trace\"]' --component filter.utils.muxer --name muxer --connect source-ctf-fs:muxer --connect 'muxer:sink\.mein\.sink'"
+test_bt_convert_run_args 'path leftover + user sink + -o text' "$path_to_trace --component=sink.abc.def -o text" "--component sink.abc.def --name sink.abc.def --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect 'muxer:sink\.abc\.def' --connect muxer:pretty"
+test_bt_convert_run_args 'path leftover + -o dummy' "$path_to_trace -o dummy" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.utils.dummy --name dummy --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:dummy"
+test_bt_convert_run_args 'path leftover + -o dummy + --clock-seconds' "$path_to_trace -o dummy --clock-seconds" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.text.pretty --name pretty --params clock-seconds=yes --component sink.utils.dummy --name dummy --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty --connect muxer:dummy"
+test_bt_convert_run_args 'path leftover + -o ctf + --output' "$path_to_trace -o ctf --output $output_path" "--component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component sink.ctf.fs --name sink-ctf-fs --params 'path=\"$output_path\"' --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:sink-ctf-fs"
+test_bt_convert_run_args 'path leftover + user sink with log level' "$path_to_trace -c sink.mein.sink -lW" "--component sink.mein.sink --log-level W --name sink.mein.sink --component source.ctf.fs --name auto-disc-source-ctf-fs --params 'inputs=[\"$path_to_trace\"]' --component filter.utils.muxer --name muxer --connect auto-disc-source-ctf-fs:muxer --connect 'muxer:sink\.mein\.sink'"
test_bt_convert_fails 'bad --component format (plugin only)' '--component salut'
test_bt_convert_fails 'bad --component format (name and plugin only)' '--component name:salut'
--- /dev/null
+import bt2
+import os
+
+
+class TestIter(bt2._UserMessageIterator):
+ pass
+
+
+class Base:
+ @classmethod
+ def _print_params(cls, params):
+ inputs = sorted([str(x) for x in params['inputs']])
+ print('{}: {}'.format(cls.__name__, ', '.join(inputs)))
+
+
+@bt2.plugin_component_class
+class TestSourceExt(Base, bt2._UserSourceComponent, message_iterator_class=TestIter):
+ """
+ Recognize files whose name start with 'aaa', 'bbb' or 'ccc'.
+
+ 'aaa' files are grouped together, 'bbb' files are grouped together, 'ccc'
+ files are not grouped.
+ """
+
+ def __init__(self, params):
+ self._print_params(params)
+
+ @staticmethod
+ def _query(query_exec, obj, params, log_level):
+ if obj == 'support-info':
+ if params['type'] == 'file':
+ name = os.path.basename(str(params['input']))
+
+ if name.startswith('aaa'):
+ return {'weight': 1, 'group': 'aaa'}
+ elif name.startswith('bbb'):
+ return {'weight': 0.5, 'group': 'bbb'}
+ elif name.startswith('ccc'):
+ # Try two different ways of returning "no group", and two
+ # different ways of returning 1 (an int and a float).
+ if name[3] == '1':
+ return {'weight': 1, 'group': None}
+ elif name[3] == '2':
+ return {'weight': 1.0, 'group': None}
+ elif name[3] == '3':
+ return 1
+ else:
+ return 1.0
+ else:
+ return 0
+ else:
+ raise bt2.InvalidObject
+
+
+@bt2.plugin_component_class
+class TestSourceSomeDir(
+ Base, bt2._UserSourceComponent, message_iterator_class=TestIter
+):
+ """Recognizes directories named "some-dir". The file "aaa10" in the
+ directory "some-dir" won't be found by TestSourceExt, because we won't
+ recurse in "some-dir"."""
+
+ def __init__(self, params):
+ self._print_params(params)
+
+ @staticmethod
+ def _query(query_exec, obj, params, log_level):
+ if obj == 'support-info':
+ if params['type'] == 'directory':
+ name = os.path.basename(str(params['input']))
+ return 1 if name == 'some-dir' else 0
+ else:
+ return 0
+ else:
+ raise bt2.InvalidObject
+
+
+@bt2.plugin_component_class
+class TestSourceABCDE(Base, bt2._UserSourceComponent, message_iterator_class=TestIter):
+ """A source that recognizes the arbitrary string input "ABCDE"."""
+
+ def __init__(self, params):
+ self._print_params(params)
+
+ @staticmethod
+ def _query(query_exec, obj, params, log_level):
+ if obj == 'support-info':
+ return (
+ 1.0
+ if params['type'] == 'string' and params['input'] == 'ABCDE'
+ else 0.0
+ )
+ else:
+ raise bt2.InvalidObject
+
+
+class TestSourceNoQuery(bt2._UserSourceComponent, message_iterator_class=TestIter):
+ """A source that does not implement _query at all."""
+
+
+bt2.register_plugin(module_name=__name__, name="test")
ctf = bt2.find_plugin('ctf')
self._fs = ctf.source_component_classes['fs']
- self._paths = [
+ self._inputs = [
os.path.join(test_ctf_traces_path, 'intersection', '3eventsintersect')
]
self._executor = bt2.QueryExecutor()
# Without clock class offset
def test_no_clock_class_offset(self):
- res = self._executor.query(self._fs, 'trace-info', {'paths': self._paths})
+ res = self._executor.query(self._fs, 'trace-info', {'inputs': self._inputs})
trace = res[0]
self._check(trace, 0)
def test_clock_class_offset_s(self):
res = self._executor.query(
- self._fs, 'trace-info', {'paths': self._paths, 'clock-class-offset-s': 2}
+ self._fs, 'trace-info', {'inputs': self._inputs, 'clock-class-offset-s': 2}
)
trace = res[0]
self._check(trace, 2000000000)
def test_clock_class_offset_ns(self):
res = self._executor.query(
- self._fs, 'trace-info', {'paths': self._paths, 'clock-class-offset-ns': 2}
+ self._fs, 'trace-info', {'inputs': self._inputs, 'clock-class-offset-ns': 2}
)
trace = res[0]
self._check(trace, 2)
self._fs,
'trace-info',
{
- 'paths': self._paths,
+ 'inputs': self._inputs,
'clock-class-offset-s': -2,
'clock-class-offset-ns': -2,
},
self._executor.query(
self._fs,
'trace-info',
- {'paths': self._paths, 'clock-class-offset-s': "2"},
+ {'inputs': self._inputs, 'clock-class-offset-s': "2"},
)
def test_clock_class_offset_s_wrong_type_none(self):
self._executor.query(
self._fs,
'trace-info',
- {'paths': self._paths, 'clock-class-offset-s': None},
+ {'inputs': self._inputs, 'clock-class-offset-s': None},
)
def test_clock_class_offset_ns_wrong_type(self):
self._executor.query(
self._fs,
'trace-info',
- {'paths': self._paths, 'clock-class-offset-ns': "2"},
+ {'inputs': self._inputs, 'clock-class-offset-ns': "2"},
)
def test_clock_class_offset_ns_wrong_type_none(self):
self._executor.query(
self._fs,
'trace-info',
- {'paths': self._paths, 'clock-class-offset-ns': None},
+ {'inputs': self._inputs, 'clock-class-offset-ns': None},
)
self._fs,
"trace-info",
{
- "paths": [
+ "inputs": [
os.path.join(
test_ctf_traces_path, "intersection", "3eventsintersect"
)
res = self._executor.query(
self._fs,
"trace-info",
- {"paths": [os.path.join(test_ctf_traces_path, "succeed", "succeed1")]},
+ {"inputs": [os.path.join(test_ctf_traces_path, "succeed", "succeed1")]},
)
os_stream_path = PurePosixPath(
res = self._executor.query(
self._fs,
"trace-info",
- {"paths": [os.path.join(test_ctf_traces_path, "succeed", "succeed1")]},
+ {"inputs": [os.path.join(test_ctf_traces_path, "succeed", "succeed1")]},
)
self.assertEqual(len(res), 1)