Make babeltrace(1)'s CLI Git-like and implement the list-plugins command
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 9 Feb 2017 19:42:57 +0000 (14:42 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:38 +0000 (12:57 -0400)
This patch adds a command concept to the babeltrace(1) program, so that
the usage becomes:

    babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]

The idea is to support multiple actions performed by the same program
without having to deal with a single command-line option parsing phase.

The default command is `convert`: it builds a trace conversion graph and
runs it. Therefore the current behaviour without a command name remains
the same.

The general command-line options, which can apply to all commands, are:

    -d, --debug        Enable debug mode
    -h  --help         Show general help and quit
        --help-legacy  Show Babeltrace 1.x legacy help and quit
    -v, --verbose      Enable verbose output
    -V, --version      Show version and quit

You can get the usage of a specific command with:

    babeltrace COMMAND --help

Because there is a default command, the parsing of the general options
is done manually to catch the first unknown option OR positional
argument. If an unknown option is found, all the arguments are given
back to the convert command. This is why the convert command also
parses --verbose, for example, because of this situation:

    babeltrace --debug --sink=my.sink --verbose

Here, the general options parsing stops at --sink because it's unknown,
and no explicit command name was found so far, so everything starting
with --debug is given to the convert command.

I also implemented the `list-plugins` command which lists plugins, their
component classes, and their properties:

    babeltrace list-plugins

You can still specify a plugin path or use the BABELTRACE_PLUGIN_PATH
environment variable with this command:

    babeltrace list-plugins --plugin-path=/path/to/other/plugins

I added color support in libbabeltrace-common and used it in the
`list-plugins` command. Color codes are only printed when color support
is detected, that is, when the standard output is connected to a
color-compatible terminal.

I also improved the way bt_value objects are printed with print_value()
in babeltrace.c to make it look more YAML-ish. This is easier on the
eyes.

This patch introduces a backward compatibility break in the very
specific scenario where an explicit command name is used and a directory
in the CWD exists with this name:

    babeltrace list-plugins

If `list-plugins` is a directory in the CWD, the legacy behaviour is to
recursively find CTF traces in it. With this patch, plugins are listed.
However a message is printed at the end of the command in this case:

    NOTE: The `list-plugins` command was executed. If you meant to
    convert a trace located in the local `list-plugins` directory,
    please use:

        babeltrace convert list-plugins [OPTIONS]

In other words, `babeltrace convert` (with 2.x) is a drop-in replacement
of `babeltrace` (with 1.x).

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
common/common.c
converter/babeltrace-cfg.c
converter/babeltrace-cfg.h
converter/babeltrace.c
converter/default-cfg.c
converter/default-cfg.h
include/babeltrace/common-internal.h

index 47186e164a74e23b83270ed882d38209fc87a173..379b13012a9a09b6575625ef4dee7e7e72d46355 100644 (file)
@@ -22,6 +22,7 @@
  * SOFTWARE.
  */
 
+#include <unistd.h>
 #include <string.h>
 #include <sys/types.h>
 #include <pwd.h>
@@ -163,3 +164,145 @@ error:
 end:
        return ret;
 }
+
+static bool supports_colors(void)
+{
+       static bool supports_colors = false;
+       static bool supports_colors_set = false;
+       const char *term;
+
+       if (supports_colors_set) {
+               goto end;
+       }
+
+       supports_colors_set = true;
+
+       term = getenv("TERM");
+       if (!term) {
+               goto end;
+       }
+
+       if (strncmp(term, "xterm", 5) != 0 &&
+                       strncmp(term, "rxvt", 4) != 0 &&
+                       strncmp(term, "konsole", 7) != 0 &&
+                       strncmp(term, "gnome", 5) != 0) {
+               goto end;
+       }
+
+       if (!isatty(1)) {
+               goto end;
+       }
+
+       supports_colors = true;
+
+end:
+       return supports_colors;
+}
+
+BT_HIDDEN
+const char *bt_common_color_reset(void)
+{
+       return supports_colors() ? "\033[0m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bold(void)
+{
+       return supports_colors() ? "\033[1m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_default(void)
+{
+       return supports_colors() ? "\033[39m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_red(void)
+{
+       return supports_colors() ? "\033[31m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_green(void)
+{
+       return supports_colors() ? "\033[32m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_yellow(void)
+{
+       return supports_colors() ? "\033[33m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_blue(void)
+{
+       return supports_colors() ? "\033[34m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_magenta(void)
+{
+       return supports_colors() ? "\033[35m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_cyan(void)
+{
+       return supports_colors() ? "\033[36m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_light_gray(void)
+{
+       return supports_colors() ? "\033[37m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_default(void)
+{
+       return supports_colors() ? "\033[49m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_red(void)
+{
+       return supports_colors() ? "\033[41m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_green(void)
+{
+       return supports_colors() ? "\033[42m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_yellow(void)
+{
+       return supports_colors() ? "\033[43m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_blue(void)
+{
+       return supports_colors() ? "\033[44m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_magenta(void)
+{
+       return supports_colors() ? "\033[45m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_cyan(void)
+{
+       return supports_colors() ? "\033[46m" : "";
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_light_gray(void)
+{
+       return supports_colors() ? "\033[47m" : "";
+}
index f045bf94e973b6c4c16ef989b64cb4e516d8eff9..1d4e7537394f1933acf2590310d6ea738b1a2de9 100644 (file)
@@ -691,143 +691,6 @@ void print_version(void)
        puts("Babeltrace " VERSION);
 }
 
-/*
- * Prints the legacy, Babeltrace 1.x command usage. Those options are
- * still compatible in Babeltrace 2.x, but it is recommended to use
- * the more generic plugin/component parameters instead of those
- * hard-coded option names.
- */
-static
-void print_legacy_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --help-legacy            Show this help\n");
-       fprintf(fp, "  -V, --version                Show version\n");
-       fprintf(fp, "      --clock-force-correlate  Assume that clocks are inherently correlated\n");
-       fprintf(fp, "                               across traces\n");
-       fprintf(fp, "  -d, --debug                  Enable debug mode\n");
-       fprintf(fp, "  -i, --input-format=FORMAT    Input trace format (default: ctf)\n");
-       fprintf(fp, "  -l, --list                   List available formats\n");
-       fprintf(fp, "  -o, --output-format=FORMAT   Output trace format (default: text)\n");
-       fprintf(fp, "  -v, --verbose                Enable verbose output\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  Available input formats:  ctf, lttng-live, ctf-metadata\n");
-       fprintf(fp, "  Available output formats: text, dummy\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Input formats specific options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  INPUT...                     Input trace file(s), directory(ies), or URLs\n");
-       fprintf(fp, "      --clock-offset=SEC       Set clock offset to SEC seconds\n");
-       fprintf(fp, "      --clock-offset-ns=NS     Set clock offset to NS nanoseconds\n");
-       fprintf(fp, "      --stream-intersection    Only process events when all streams are active\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "text output format specific options:\n");
-       fprintf(fp, "  \n");
-       fprintf(fp, "      --clock-cycles           Print timestamps in clock cycles\n");
-       fprintf(fp, "      --clock-date             Print timestamp dates\n");
-       fprintf(fp, "      --clock-gmt              Print and parse timestamps in GMT time zone\n");
-       fprintf(fp, "                               (default: local time zone)\n");
-       fprintf(fp, "      --clock-seconds          Print the timestamps as [SEC.NS]\n");
-       fprintf(fp, "                               (default format: [HH:MM:SS.NS])\n");
-       fprintf(fp, "      --debug-info-dir=DIR     Search for debug info in directory DIR\n");
-       fprintf(fp, "                               (default: `/usr/lib/debug`)\n");
-       fprintf(fp, "      --debug-info-full-path   Show full debug info source and binary paths\n");
-       fprintf(fp, "      --debug-info-target-prefix=DIR  Use directory DIR as a prefix when looking\n");
-       fprintf(fp, "                                      up executables during debug info analysis\n");
-       fprintf(fp, "                               (default: `/usr/lib/debug`)\n");
-       fprintf(fp, "  -f, --fields=NAME[,NAME]...  Print additional fields:\n");
-       fprintf(fp, "                                 all, trace, trace:hostname, trace:domain,\n");
-       fprintf(fp, "                                 trace:procname, trace:vpid, loglevel, emf\n");
-       fprintf(fp, "                                 (default: trace:hostname, trace:procname,\n");
-       fprintf(fp, "                                           trace:vpid)\n");
-       fprintf(fp, "  -n, --names=NAME[,NAME]...   Print field names:\n");
-       fprintf(fp, "                                 payload (or arg or args)\n");
-       fprintf(fp, "                                 none, all, scope, header, context (or ctx)\n");
-       fprintf(fp, "                                 (default: payload, context)\n");
-       fprintf(fp, "      --no-delta               Do not print time delta between consecutive\n");
-       fprintf(fp, "                               events\n");
-       fprintf(fp, "  -w, --output=PATH            Write output to PATH (default: standard output)\n");
-}
-
-/*
- * Prints the Babeltrace 2.x usage.
- */
-static
-void print_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace [OPTIONS]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  -b, --base-params=PARAMS          Set PARAMS as the current base parameters\n");
-       fprintf(fp, "                                    of the following source and sink component\n");
-       fprintf(fp, "                                    instances (see the exact format of PARAMS\n");
-       fprintf(fp, "                                    below)\n");
-       fprintf(fp, "      --begin=BEGIN                 Set beginning time to BEGIN\n");
-       fprintf(fp, "                                    (format: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn])\n");
-       fprintf(fp, "  -d, --debug                       Enable debug mode\n");
-       fprintf(fp, "      --end=END                     Set end time to END\n");
-       fprintf(fp, "                                    (format: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn])\n");
-       fprintf(fp, "  -l, --list                        List available plugins and their components\n");
-       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
-       fprintf(fp, "                                    (~/.local/lib/babeltrace/plugins)\n");
-       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
-       fprintf(fp, "  -p, --params=PARAMS               Set the parameters of the latest source or\n");
-       fprintf(fp, "                                    sink component instance (in command-line \n");
-       fprintf(fp, "                                    order) to PARAMS (see the exact format of\n");
-       fprintf(fp, "                                    PARAMS below)\n");
-       fprintf(fp, "  -P, --path=PATH                   Set the `path` parameter of the latest source\n");
-       fprintf(fp, "                                    or sink component to PATH\n");
-       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which dynamic\n");
-       fprintf(fp, "                                    plugins can be loaded\n");
-       fprintf(fp, "  -r, --reset-base-params           Reset the current base parameters of the\n");
-       fprintf(fp, "                                    following source and sink component\n");
-       fprintf(fp, "                                    instances to an empty map\n");
-       fprintf(fp, "  -o, --sink=PLUGIN.COMPCLS         Instantiate a sink component from plugin\n");
-       fprintf(fp, "                                    PLUGIN and component class COMPCLS (may be\n");
-       fprintf(fp, "                                    repeated)\n");
-       fprintf(fp, "  -i, --source=PLUGIN.COMPCLS       Instantiate a source component from plugin\n");
-       fprintf(fp, "                                    PLUGIN and component class COMPCLS (may be\n");
-       fprintf(fp, "                                    repeated)\n");
-       fprintf(fp, "      --timerange=TIMERANGE         Set time range to TIMERANGE: BEGIN,END or\n");
-       fprintf(fp, "                                    [BEGIN,END] (where [ and ] are actual brackets)\n");
-       fprintf(fp, "  -h  --help                        Show this help\n");
-       fprintf(fp, "      --help-legacy                 Show Babeltrace 1.x legacy options\n");
-       fprintf(fp, "  -v, --verbose                     Enable verbose output\n");
-       fprintf(fp, "  -V, --version                     Show version\n");
-       fprintf(fp, "\n\n");
-       fprintf(fp, "Format of PARAMS\n");
-       fprintf(fp, "----------------\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    PARAM=VALUE[,PARAM=VALUE]...\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
-       fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
-       fprintf(fp, "VALUE can be one of:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
-       fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
-       fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
-       fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
-       fprintf(fp, "  (`0x` prefix) signed 64-bit integer.\n");
-       fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
-       fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
-       fprintf(fp, "  the null and boolean value symbols above.\n");
-       fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Example:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    many=null, fresh=yes, condition=false, squirrel=-782329,\n");
-       fprintf(fp, "    observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
-       fprintf(fp, "    escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
-       fprintf(fp, "from a shell.\n");
-}
-
 /*
  * Destroys a component configuration.
  */
@@ -944,23 +807,35 @@ end:
 static
 void bt_config_destroy(struct bt_object *obj)
 {
-       struct bt_config *bt_config =
+       struct bt_config *cfg =
                container_of(obj, struct bt_config, base);
 
        if (!obj) {
                goto end;
        }
 
-       if (bt_config->sources) {
-               g_ptr_array_free(bt_config->sources, TRUE);
-       }
+       switch (cfg->command) {
+       case BT_CONFIG_COMMAND_CONVERT:
+               if (cfg->cmd_data.convert.sources) {
+                       g_ptr_array_free(cfg->cmd_data.convert.sources, TRUE);
+               }
 
-       if (bt_config->sinks) {
-               g_ptr_array_free(bt_config->sinks, TRUE);
+               if (cfg->cmd_data.convert.sinks) {
+                       g_ptr_array_free(cfg->cmd_data.convert.sinks, TRUE);
+               }
+
+               BT_PUT(cfg->cmd_data.convert.plugin_paths);
+               break;
+
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               BT_PUT(cfg->cmd_data.list_plugins.plugin_paths);
+               break;
+
+       default:
+               assert(false);
        }
 
-       BT_PUT(bt_config->plugin_paths);
-       g_free(bt_config);
+       g_free(cfg);
 
 end:
        return;
@@ -2022,7 +1897,7 @@ bool validate_cfg(struct bt_config *cfg,
                }
 
                /* Make sure no non-legacy sources are specified */
-               if (cfg->sources->len != 0) {
+               if (cfg->cmd_data.convert.sources->len != 0) {
                        print_input_legacy_to_sources(*legacy_input_format,
                                legacy_input_paths, ctf_legacy_opts);
                        goto error;
@@ -2050,7 +1925,7 @@ bool validate_cfg(struct bt_config *cfg,
                }
 
                /* Make sure no non-legacy sinks are specified */
-               if (cfg->sinks->len != 0) {
+               if (cfg->cmd_data.convert.sinks->len != 0) {
                        print_output_legacy_to_sinks(*legacy_output_format,
                                text_legacy_opts);
                        goto error;
@@ -2111,15 +1986,16 @@ enum {
        OPT_END,
        OPT_FIELDS,
        OPT_HELP,
-       OPT_HELP_LEGACY,
        OPT_INPUT_FORMAT,
        OPT_LIST,
        OPT_NAMES,
        OPT_NO_DELTA,
+       OPT_OMIT_HOME_PLUGIN_PATH,
+       OPT_OMIT_SYSTEM_PLUGIN_PATH,
        OPT_OUTPUT_FORMAT,
        OPT_OUTPUT_PATH,
-       OPT_PATH,
        OPT_PARAMS,
+       OPT_PATH,
        OPT_PLUGIN_PATH,
        OPT_RESET_BASE_PARAMS,
        OPT_SINK,
@@ -2127,50 +2003,6 @@ enum {
        OPT_STREAM_INTERSECTION,
        OPT_TIMERANGE,
        OPT_VERBOSE,
-       OPT_VERSION,
-       OPT_OMIT_SYSTEM_PLUGIN_PATH,
-       OPT_OMIT_HOME_PLUGIN_PATH,
-};
-
-/* popt long option descriptions */
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
-       { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
-       { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
-       { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
-       { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
-       { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
-       { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
-       { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
-       { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
-       { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
-       { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
-       { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
-       { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
-       { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
-       { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
-       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-       { "help-legacy", '\0', POPT_ARG_NONE, NULL, OPT_HELP_LEGACY, NULL, NULL },
-       { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
-       { "list", 'l', POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL },
-       { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
-       { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
-       { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
-       { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
-       { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
-       { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
-       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
-       { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
-       { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
-       { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
-       { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
-       { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
-       { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
-       { "version", 'V', POPT_ARG_NONE, NULL, OPT_VERSION, NULL, NULL },
-       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
-       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
-       { NULL, 0, 0, NULL, 0, NULL, NULL },
 };
 
 /*
@@ -2196,9 +2028,9 @@ static void add_cfg_comp(struct bt_config *cfg,
                enum bt_config_component_dest dest)
 {
        if (dest == BT_CONFIG_COMPONENT_DEST_SOURCE) {
-               g_ptr_array_add(cfg->sources, cfg_comp);
+               g_ptr_array_add(cfg->cmd_data.convert.sources, cfg_comp);
        } else {
-               g_ptr_array_add(cfg->sinks, cfg_comp);
+               g_ptr_array_add(cfg->cmd_data.convert.sinks, cfg_comp);
        }
 }
 
@@ -2235,7 +2067,7 @@ not_found:
        return -1;
 }
 
-static int add_env_var_plugin_paths(struct bt_config *cfg)
+static int append_env_var_plugin_paths(struct bt_value *plugin_paths)
 {
        int ret = 0;
        const char *envvar;
@@ -2250,17 +2082,18 @@ static int add_env_var_plugin_paths(struct bt_config *cfg)
                goto end;
        }
 
-       ret = bt_config_append_plugin_paths(cfg->plugin_paths, envvar);
+       ret = bt_config_append_plugin_paths(plugin_paths, envvar);
 
 end:
        return ret;
 }
 
-static int append_home_and_system_plugin_paths(struct bt_config *cfg)
+static int append_home_and_system_plugin_paths(struct bt_value *plugin_paths,
+               bool omit_system_plugin_path, bool omit_home_plugin_path)
 {
        int ret;
 
-       if (!cfg->omit_home_plugin_path) {
+       if (!omit_home_plugin_path) {
                if (bt_common_is_setuid_setgid()) {
                        printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
                } else {
@@ -2268,7 +2101,8 @@ static int append_home_and_system_plugin_paths(struct bt_config *cfg)
                                bt_common_get_home_plugin_path();
 
                        if (home_plugin_dir) {
-                               ret = bt_config_append_plugin_paths(cfg->plugin_paths,
+                               ret = bt_config_append_plugin_paths(
+                                       plugin_paths,
                                        home_plugin_dir);
                                free(home_plugin_dir);
 
@@ -2280,8 +2114,8 @@ static int append_home_and_system_plugin_paths(struct bt_config *cfg)
                }
        }
 
-       if (!cfg->omit_system_plugin_path) {
-               if (bt_config_append_plugin_paths(cfg->plugin_paths,
+       if (!omit_system_plugin_path) {
+               if (bt_config_append_plugin_paths(plugin_paths,
                                bt_common_get_system_plugin_path())) {
                        printf_err("Invalid system plugin path\n");
                        goto error;
@@ -2316,7 +2150,7 @@ error:
        return -1;
 }
 
-struct bt_config *bt_config_create(void)
+static struct bt_config *bt_config_base_create(enum bt_config_command command)
 {
        struct bt_config *cfg;
 
@@ -2328,113 +2162,167 @@ struct bt_config *bt_config_create(void)
        }
 
        bt_object_init(cfg, bt_config_destroy);
-       cfg->sources = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
-       if (!cfg->sources) {
-               print_err_oom();
-               goto error;
-       }
+       cfg->command = command;
+       goto end;
 
-       cfg->sinks = g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
-       if (!cfg->sinks) {
-               print_err_oom();
-               goto error;
-       }
+error:
+       BT_PUT(cfg);
 
-       cfg->plugin_paths = bt_value_array_create();
-       if (!cfg->plugin_paths) {
-               print_err_oom();
-               goto error;
-       }
 end:
        return cfg;
-error:
-       BT_PUT(cfg);
-       goto end;
 }
 
-/*
- * Initializes a created Babeltrace config object according to the
- * command-line arguments found in argv.
- *
- * Return value is set to the appropriate exit code to use.
- */
-int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[])
+static struct bt_config *bt_config_convert_create(
+               struct bt_value *initial_plugin_paths)
 {
-       poptContext pc = NULL;
-       char *arg = NULL;
-       struct ctf_legacy_opts ctf_legacy_opts;
-       struct text_legacy_opts text_legacy_opts;
-       enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
-       enum legacy_output_format legacy_output_format =
-                       LEGACY_OUTPUT_FORMAT_NONE;
-       struct bt_value *legacy_input_paths = NULL;
-       struct bt_config_component *implicit_source_comp = NULL;
-       struct bt_config_component *cur_cfg_comp = NULL;
-       bool cur_is_implicit_source = false;
-       bool use_implicit_source = false;
-       enum bt_config_component_dest cur_cfg_comp_dest =
-               BT_CONFIG_COMPONENT_DEST_SOURCE;
-       struct bt_value *cur_base_params = NULL;
-       int opt, ret = 0;
-
-       memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
-       memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
+       struct bt_config *cfg;
 
-       text_legacy_opts.output = g_string_new(NULL);
-       if (!text_legacy_opts.output) {
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_CONVERT);
+       if (!cfg) {
                print_err_oom();
                goto error;
        }
 
-       text_legacy_opts.dbg_info_dir = g_string_new(NULL);
-       if (!text_legacy_opts.dbg_info_dir) {
+       cfg->cmd_data.convert.sources = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_put);
+       if (!cfg->cmd_data.convert.sources) {
                print_err_oom();
                goto error;
        }
 
-       text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
-       if (!text_legacy_opts.dbg_info_target_prefix) {
+       cfg->cmd_data.convert.sinks = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_put);
+       if (!cfg->cmd_data.convert.sinks) {
                print_err_oom();
                goto error;
        }
 
-       cur_base_params = bt_value_map_create();
-       if (!cur_base_params) {
-               print_err_oom();
-               goto error;
+       if (initial_plugin_paths) {
+               cfg->cmd_data.convert.plugin_paths =
+                       bt_get(initial_plugin_paths);
+       } else {
+               cfg->cmd_data.convert.plugin_paths = bt_value_array_create();
+               if (!cfg->cmd_data.convert.plugin_paths) {
+                       print_err_oom();
+                       goto error;
+               }
        }
 
-       legacy_input_paths = bt_value_array_create();
-       if (!legacy_input_paths) {
-               print_err_oom();
-               goto error;
-       }
+       goto end;
 
-       ret = add_env_var_plugin_paths(cfg);
-       if (ret) {
-               printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
+error:
+       BT_PUT(cfg);
+
+end:
+       return cfg;
+}
+
+static struct bt_config *bt_config_list_plugins_create(
+               struct bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS);
+       if (!cfg) {
+               print_err_oom();
                goto error;
        }
 
-       /* Note: implicit source never gets positional base params. */
-       implicit_source_comp = bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME);
-       if (implicit_source_comp) {
-               cur_cfg_comp = implicit_source_comp;
-               cur_is_implicit_source = true;
-               use_implicit_source = true;
+       if (initial_plugin_paths) {
+               cfg->cmd_data.list_plugins.plugin_paths =
+                       bt_get(initial_plugin_paths);
        } else {
-               printf_debug("Cannot find implicit source plugin \"%s\"",
-                       DEFAULT_SOURCE_COMPONENT_NAME);
-       }
-
-       /* Parse options */
-       pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
+               cfg->cmd_data.list_plugins.plugin_paths =
+                       bt_value_array_create();
+               if (!cfg->cmd_data.list_plugins.plugin_paths) {
+                       print_err_oom();
+                       goto error;
+               }
        }
 
-       poptReadDefaultConfig(pc, 0);
+       goto end;
+
+error:
+       BT_PUT(cfg);
+
+end:
+       return cfg;
+}
+
+/*
+ * Prints the list-plugins command usage.
+ */
+static
+void print_list_plugins_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "  -h  --help                        Show this help and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
+}
+
+static struct poptOption list_plugins_long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { NULL, 0, 0, NULL, 0, NULL, NULL },
+};
+
+/*
+ * Creates a Babeltrace config object from the arguments of a
+ * list-plugins command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
+               int *retcode, bool omit_system_plugin_path,
+               bool omit_home_plugin_path,
+               struct bt_value *initial_plugin_paths)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       int opt;
+       int ret;
+       struct bt_config *cfg = NULL;
+       const char *leftover;
+
+       *retcode = 0;
+       cfg = bt_config_list_plugins_create(initial_plugin_paths);
+       if (!cfg) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.list_plugins.omit_system_plugin_path = omit_system_plugin_path;
+       cfg->cmd_data.list_plugins.omit_home_plugin_path = omit_home_plugin_path;
+       ret = append_env_var_plugin_paths(
+               cfg->cmd_data.list_plugins.plugin_paths);
+       if (ret) {
+               printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
+               goto error;
+       }
+
+       /* Parse options */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               list_plugins_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
 
        while ((opt = poptGetNextOpt(pc)) > 0) {
                arg = poptGetOptArg(pc);
@@ -2444,17 +2332,378 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                        if (bt_common_is_setuid_setgid()) {
                                printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
                        } else {
-                               if (bt_config_append_plugin_paths(cfg->plugin_paths, arg)) {
+                               if (bt_config_append_plugin_paths(
+                                               cfg->cmd_data.list_plugins.plugin_paths,
+                                               arg)) {
                                        printf_err("Invalid --plugin-path option's argument\n");
                                        goto error;
                                }
                        }
                        break;
                case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                       cfg->omit_system_plugin_path = true;
+                       cfg->cmd_data.list_plugins.omit_system_plugin_path = true;
                        break;
                case OPT_OMIT_HOME_PLUGIN_PATH:
-                       cfg->omit_home_plugin_path = true;
+                       cfg->cmd_data.list_plugins.omit_home_plugin_path = true;
+                       break;
+               case OPT_HELP:
+                       print_list_plugins_usage(stdout);
+                       *retcode = -1;
+                       BT_PUT(cfg);
+                       goto end;
+               default:
+                       printf_err("Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               printf_err("Invalid argument: %s\n", leftover);
+               goto error;
+       }
+
+       if (append_home_and_system_plugin_paths(
+                       cfg->cmd_data.list_plugins.plugin_paths,
+                       cfg->cmd_data.list_plugins.omit_system_plugin_path,
+                       cfg->cmd_data.list_plugins.omit_home_plugin_path)) {
+               printf_err("Cannot append home and system plugin paths\n");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_PUT(cfg);
+
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       free(arg);
+       return cfg;
+}
+
+
+/*
+ * Prints the legacy, Babeltrace 1.x command usage. Those options are
+ * still compatible in Babeltrace 2.x, but it is recommended to use
+ * the more generic plugin/component parameters instead of those
+ * hard-coded option names.
+ */
+static
+void print_legacy_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace [OPTIONS] INPUT...\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "The following options are compatible with the Babeltrace 1.x options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --clock-force-correlate  Assume that clocks are inherently correlated\n");
+       fprintf(fp, "                               across traces\n");
+       fprintf(fp, "  -d, --debug                  Enable debug mode\n");
+       fprintf(fp, "  -i, --input-format=FORMAT    Input trace format (default: ctf)\n");
+       fprintf(fp, "  -l, --list                   List available formats\n");
+       fprintf(fp, "  -o, --output-format=FORMAT   Output trace format (default: text)\n");
+       fprintf(fp, "  -v, --verbose                Enable verbose output\n");
+       fprintf(fp, "      --help-legacy            Show this help and quit\n");
+       fprintf(fp, "  -V, --version                Show version and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  Available input formats:  ctf, lttng-live, ctf-metadata\n");
+       fprintf(fp, "  Available output formats: text, dummy\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Input formats specific options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  INPUT...                     Input trace file(s), directory(ies), or URLs\n");
+       fprintf(fp, "      --clock-offset=SEC       Set clock offset to SEC seconds\n");
+       fprintf(fp, "      --clock-offset-ns=NS     Set clock offset to NS nanoseconds\n");
+       fprintf(fp, "      --stream-intersection    Only process events when all streams are active\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "text output format specific options:\n");
+       fprintf(fp, "  \n");
+       fprintf(fp, "      --clock-cycles           Print timestamps in clock cycles\n");
+       fprintf(fp, "      --clock-date             Print timestamp dates\n");
+       fprintf(fp, "      --clock-gmt              Print and parse timestamps in GMT time zone\n");
+       fprintf(fp, "                               (default: local time zone)\n");
+       fprintf(fp, "      --clock-seconds          Print the timestamps as [SEC.NS]\n");
+       fprintf(fp, "                               (default format: [HH:MM:SS.NS])\n");
+       fprintf(fp, "      --debug-info-dir=DIR     Search for debug info in directory DIR\n");
+       fprintf(fp, "                               (default: `/usr/lib/debug`)\n");
+       fprintf(fp, "      --debug-info-full-path   Show full debug info source and binary paths\n");
+       fprintf(fp, "      --debug-info-target-prefix=DIR  Use directory DIR as a prefix when looking\n");
+       fprintf(fp, "                                      up executables during debug info analysis\n");
+       fprintf(fp, "                               (default: `/usr/lib/debug`)\n");
+       fprintf(fp, "  -f, --fields=NAME[,NAME]...  Print additional fields:\n");
+       fprintf(fp, "                                 all, trace, trace:hostname, trace:domain,\n");
+       fprintf(fp, "                                 trace:procname, trace:vpid, loglevel, emf\n");
+       fprintf(fp, "                                 (default: trace:hostname, trace:procname,\n");
+       fprintf(fp, "                                           trace:vpid)\n");
+       fprintf(fp, "  -n, --names=NAME[,NAME]...   Print field names:\n");
+       fprintf(fp, "                                 payload (or arg or args)\n");
+       fprintf(fp, "                                 none, all, scope, header, context (or ctx)\n");
+       fprintf(fp, "                                 (default: payload, context)\n");
+       fprintf(fp, "      --no-delta               Do not print time delta between consecutive\n");
+       fprintf(fp, "                               events\n");
+       fprintf(fp, "  -w, --output=PATH            Write output to PATH (default: standard output)\n");
+}
+
+/*
+ * Prints the convert command usage.
+ */
+static
+void print_convert_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] convert [OPTIONS]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -b, --base-params=PARAMS          Set PARAMS as the current base parameters\n");
+       fprintf(fp, "                                    for the following component instances\n");
+       fprintf(fp, "                                    (see the expected format of PARAMS below)\n");
+       fprintf(fp, "      --begin=BEGIN                 Set the `begin` parameter of the latest\n");
+       fprintf(fp, "                                    source component instance to BEGIN\n");
+       fprintf(fp, "                                    (see the suggested format of BEGIN below)\n");
+       fprintf(fp, "  -d, --debug                       Enable debug mode\n");
+       fprintf(fp, "      --end=END                     Set the `end` parameter of the latest\n");
+       fprintf(fp, "                                    source component instance to END\n");
+       fprintf(fp, "                                    (see the suggested format of BEGIN below)\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "  -p, --params=PARAMS               Set the parameters of the latest component\n");
+       fprintf(fp, "                                    instance (in command-line order) to PARAMS\n");
+       fprintf(fp, "                                    (see the expected format of PARAMS below)\n");
+       fprintf(fp, "  -P, --path=PATH                   Set the `path` parameter of the latest\n");
+       fprintf(fp, "                                    component instance to PATH\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "  -r, --reset-base-params           Reset the current base parameters of the\n");
+       fprintf(fp, "                                    following source and sink component\n");
+       fprintf(fp, "                                    instances to an empty map\n");
+       fprintf(fp, "  -o, --sink=PLUGIN.COMPCLS         Instantiate a sink component from plugin\n");
+       fprintf(fp, "                                    PLUGIN and component class COMPCLS (may be\n");
+       fprintf(fp, "                                    repeated)\n");
+       fprintf(fp, "  -i, --source=PLUGIN.COMPCLS       Instantiate a source component from plugin\n");
+       fprintf(fp, "                                    PLUGIN and component class COMPCLS (may be\n");
+       fprintf(fp, "                                    repeated)\n");
+       fprintf(fp, "      --timerange=TIMERANGE         Set time range to TIMERANGE: BEGIN,END or\n");
+       fprintf(fp, "                                    [BEGIN,END] (literally `[` and `]`)\n");
+       fprintf(fp, "                                    (suggested format of BEGIN/END below)\n");
+       fprintf(fp, "  -v, --verbose                     Enable verbose output\n");
+       fprintf(fp, "  -h  --help                        Show this help and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "See `babeltrace --help` for the list of general options.\n");
+       fprintf(fp, "\n\n");
+       fprintf(fp, "Suggested format of BEGIN and END\n");
+       fprintf(fp, "---------------------------------\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
+       fprintf(fp, "\n\n");
+       fprintf(fp, "Expected format of PARAMS\n");
+       fprintf(fp, "-------------------------\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    PARAM=VALUE[,PARAM=VALUE]...\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
+       fprintf(fp, "where PARAM is the parameter name (C identifier plus [:.-] characters), and\n");
+       fprintf(fp, "VALUE can be one of:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
+       fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
+       fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
+       fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
+       fprintf(fp, "  (`0x` prefix) signed 64-bit integer.\n");
+       fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
+       fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
+       fprintf(fp, "  the null and boolean value symbols above.\n");
+       fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Whitespaces are allowed around individual `=` and `,` tokens.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Example:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    many=null, fresh=yes, condition=false, squirrel=-782329,\n");
+       fprintf(fp, "    observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
+       fprintf(fp, "    escape.chars-are:allowed=\"this is a \\\" double quote\"\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run babeltrace\n");
+       fprintf(fp, "from a shell.\n");
+}
+
+static struct poptOption convert_long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
+       { "begin", '\0', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
+       { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
+       { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
+       { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
+       { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
+       { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
+       { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
+       { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
+       { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
+       { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
+       { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
+       { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
+       { "end", '\0', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
+       { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
+       { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
+       { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT_PATH, NULL, NULL },
+       { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
+       { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
+       { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
+       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
+       { "sink", '\0', POPT_ARG_STRING, NULL, OPT_SINK, NULL, NULL },
+       { "source", '\0', POPT_ARG_STRING, NULL, OPT_SOURCE, NULL, NULL },
+       { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
+       { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
+       { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
+       { NULL, 0, 0, NULL, 0, NULL, NULL },
+};
+
+/*
+ * Creates a Babeltrace config object from the arguments of a convert
+ * command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
+               int *retcode, bool omit_system_plugin_path,
+               bool omit_home_plugin_path,
+               struct bt_value *initial_plugin_paths)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       struct ctf_legacy_opts ctf_legacy_opts;
+       struct text_legacy_opts text_legacy_opts;
+       enum legacy_input_format legacy_input_format = LEGACY_INPUT_FORMAT_NONE;
+       enum legacy_output_format legacy_output_format =
+                       LEGACY_OUTPUT_FORMAT_NONE;
+       struct bt_value *legacy_input_paths = NULL;
+       struct bt_config_component *implicit_source_comp = NULL;
+       struct bt_config_component *cur_cfg_comp = NULL;
+       bool cur_is_implicit_source = false;
+       bool use_implicit_source = false;
+       enum bt_config_component_dest cur_cfg_comp_dest =
+               BT_CONFIG_COMPONENT_DEST_SOURCE;
+       struct bt_value *cur_base_params = NULL;
+       int opt, ret = 0;
+       struct bt_config *cfg = NULL;
+
+       *retcode = 0;
+       memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
+       memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
+
+       if (argc <= 1) {
+               print_convert_usage(stdout);
+               *retcode = -1;
+               goto end;
+       }
+
+       cfg = bt_config_convert_create(initial_plugin_paths);
+       if (!cfg) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.convert.omit_system_plugin_path = omit_system_plugin_path;
+       cfg->cmd_data.convert.omit_home_plugin_path = omit_home_plugin_path;
+       text_legacy_opts.output = g_string_new(NULL);
+       if (!text_legacy_opts.output) {
+               print_err_oom();
+               goto error;
+       }
+
+       text_legacy_opts.dbg_info_dir = g_string_new(NULL);
+       if (!text_legacy_opts.dbg_info_dir) {
+               print_err_oom();
+               goto error;
+       }
+
+       text_legacy_opts.dbg_info_target_prefix = g_string_new(NULL);
+       if (!text_legacy_opts.dbg_info_target_prefix) {
+               print_err_oom();
+               goto error;
+       }
+
+       cur_base_params = bt_value_map_create();
+       if (!cur_base_params) {
+               print_err_oom();
+               goto error;
+       }
+
+       legacy_input_paths = bt_value_array_create();
+       if (!legacy_input_paths) {
+               print_err_oom();
+               goto error;
+       }
+
+       ret = append_env_var_plugin_paths(cfg->cmd_data.convert.plugin_paths);
+       if (ret) {
+               printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
+               goto error;
+       }
+
+       /* Note: implicit source never gets positional base params. */
+       implicit_source_comp = bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME);
+       if (implicit_source_comp) {
+               cur_cfg_comp = implicit_source_comp;
+               cur_is_implicit_source = true;
+               use_implicit_source = true;
+       } else {
+               printf_debug("Cannot find implicit source plugin \"%s\"",
+                       DEFAULT_SOURCE_COMPONENT_NAME);
+       }
+
+       /* Parse options */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               convert_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_PLUGIN_PATH:
+                       if (bt_common_is_setuid_setgid()) {
+                               printf_debug("Skipping non-system plugin paths for setuid/setgid binary\n");
+                       } else {
+                               if (bt_config_append_plugin_paths(
+                                               cfg->cmd_data.convert.plugin_paths,
+                                               arg)) {
+                                       printf_err("Invalid --plugin-path option's argument\n");
+                                       goto error;
+                               }
+                       }
+                       break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       cfg->cmd_data.convert.omit_system_plugin_path = true;
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       cfg->cmd_data.convert.omit_home_plugin_path = true;
                        break;
                case OPT_OUTPUT_PATH:
                        if (text_legacy_opts.output->len > 0) {
@@ -2528,7 +2777,7 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                        cur_cfg_comp->params = bt_value_copy(cur_base_params);
                        if (!cur_cfg_comp->params) {
                                print_err_oom();
-                               goto end;
+                               goto error;
                        }
 
                        cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
@@ -2590,7 +2839,7 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                        cur_cfg_comp->params = bt_value_copy(cur_base_params);
                        if (!cur_cfg_comp->params) {
                                print_err_oom();
-                               goto end;
+                               goto error;
                        }
 
                        cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
@@ -2742,7 +2991,7 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                        ctf_legacy_opts.stream_intersection = true;
                        break;
                case OPT_CLOCK_FORCE_CORRELATE:
-                       cfg->force_correlate = true;
+                       cfg->cmd_data.convert.force_correlate = true;
                        break;
                case OPT_BEGIN:
                        if (!cur_cfg_comp) {
@@ -2806,16 +3055,9 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                        break;
                }
                case OPT_HELP:
-                       print_usage(stdout);
-                       goto end;
-               case OPT_HELP_LEGACY:
-                       print_legacy_usage(stdout);
-                       goto end;
-               case OPT_VERSION:
-                       print_version();
-                       goto end;
-               case OPT_LIST:
-                       cfg->do_list = true;
+                       print_convert_usage(stdout);
+                       *retcode = -1;
+                       BT_PUT(cfg);
                        goto end;
                case OPT_VERBOSE:
                        cfg->verbose = true;
@@ -2833,11 +3075,6 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                arg = NULL;
        }
 
-       if (argc <= 1) {
-               print_usage(stdout);
-               goto end;
-       }
-
        /* Check for option parsing error */
        if (opt < -1) {
                printf_err("While parsing command-line options, at option %s: %s\n",
@@ -2860,7 +3097,11 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
                }
        }
 
-       if (append_home_and_system_plugin_paths(cfg)) {
+       if (append_home_and_system_plugin_paths(
+                       cfg->cmd_data.convert.plugin_paths,
+                       cfg->cmd_data.convert.omit_system_plugin_path,
+                       cfg->cmd_data.convert.omit_home_plugin_path)) {
+               printf_err("Cannot append home and system plugin paths\n");
                goto error;
        }
 
@@ -2883,13 +3124,15 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
         * component configurations.
         */
        if (legacy_input_format) {
-               if (append_sources_from_legacy_opts(cfg->sources,
+               if (append_sources_from_legacy_opts(
+                               cfg->cmd_data.convert.sources,
                                legacy_input_format, &ctf_legacy_opts,
                                legacy_input_paths)) {
                        printf_err("Cannot convert legacy input format options to source component instance(s)\n");
                        goto error;
                }
-               if (append_sources_from_implicit_params(cfg->sources,
+               if (append_sources_from_implicit_params(
+                               cfg->cmd_data.convert.sources,
                                implicit_source_comp)) {
                        printf_err("Cannot initialize legacy component parameters\n");
                        goto error;
@@ -2914,14 +3157,14 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
         * component configurations.
         */
        if (legacy_output_format) {
-               if (append_sinks_from_legacy_opts(cfg->sinks,
+               if (append_sinks_from_legacy_opts(cfg->cmd_data.convert.sinks,
                                legacy_output_format, &text_legacy_opts)) {
                        printf_err("Cannot convert legacy output format options to sink component instance(s)\n");
                        goto error;
                }
        }
 
-       if (cfg->sinks->len == 0) {
+       if (cfg->cmd_data.convert.sinks->len == 0) {
                /* Use implicit sink as default. */
                cur_cfg_comp = bt_config_component_from_arg(DEFAULT_SINK_COMPONENT_NAME);
                if (!cur_cfg_comp) {
@@ -2936,7 +3179,9 @@ int bt_config_init_from_args(struct bt_config *cfg, int argc, const char *argv[]
        goto end;
 
 error:
-       ret = 1;
+       *retcode = 1;
+       BT_PUT(cfg);
+
 end:
        if (pc) {
                poptFreeContext(pc);
@@ -2961,5 +3206,145 @@ end:
        BT_PUT(text_legacy_opts.names);
        BT_PUT(text_legacy_opts.fields);
        BT_PUT(legacy_input_paths);
-       return ret;
+       return cfg;
+}
+
+/*
+ * Prints the Babeltrace 2.x general usage.
+ */
+static
+void print_gen_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace [GENERAL OPTIONS] [COMMAND] [COMMAND OPTIONS]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "General options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -d, --debug        Enable debug mode\n");
+       fprintf(fp, "  -h  --help         Show this help and quit\n");
+       fprintf(fp, "      --help-legacy  Show Babeltrace 1.x legacy help and quit\n");
+       fprintf(fp, "  -v, --verbose      Enable verbose output\n");
+       fprintf(fp, "  -V, --version      Show version and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Available commands:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    convert       Build a trace conversion graph and run it (default)\n");
+       fprintf(fp, "    list-plugins  List available plugins and their content\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n");
+}
+
+struct bt_config *bt_config_from_args(int argc, const char *argv[],
+               int *retcode, bool omit_system_plugin_path,
+               bool omit_home_plugin_path,
+               struct bt_value *initial_plugin_paths)
+{
+       struct bt_config *config = NULL;
+       bool verbose = false;
+       bool debug = false;
+       int i;
+       enum bt_config_command command = -1;
+       const char **command_argv = NULL;
+       int command_argc = -1;
+       const char *command_name = NULL;
+
+       *retcode = -1;
+
+       if (argc <= 1) {
+               print_gen_usage(stdout);
+               goto end;
+       }
+
+       for (i = 1; i < argc; i++) {
+               const char *cur_arg = argv[i];
+
+               if (strcmp(cur_arg, "-d") == 0 ||
+                               strcmp(cur_arg, "--debug") == 0) {
+                       debug = true;
+               } else if (strcmp(cur_arg, "-v") == 0 ||
+                               strcmp(cur_arg, "--verbose") == 0) {
+                       verbose = true;
+               } else if (strcmp(cur_arg, "-V") == 0 ||
+                               strcmp(cur_arg, "--version") == 0) {
+                       print_version();
+                       goto end;
+               } else if (strcmp(cur_arg, "-h") == 0 ||
+                               strcmp(cur_arg, "--help") == 0) {
+                       print_gen_usage(stdout);
+                       goto end;
+               } else if (strcmp(cur_arg, "--help-legacy") == 0) {
+                       print_legacy_usage(stdout);
+                       goto end;
+               } else {
+                       /*
+                        * First unknown argument: is it a known command
+                        * name?
+                        */
+                       if (strcmp(cur_arg, "convert") == 0) {
+                               command = BT_CONFIG_COMMAND_CONVERT;
+                               command_argv = &argv[i];
+                               command_argc = argc - i;
+                               command_name = cur_arg;
+                       } else if (strcmp(cur_arg, "list-plugins") == 0) {
+                               command = BT_CONFIG_COMMAND_LIST_PLUGINS;
+                               command_argv = &argv[i];
+                               command_argc = argc - i;
+                               command_name = cur_arg;
+                       } else {
+                               /*
+                                * Unknown argument, but not a known
+                                * command name: assume the whole
+                                * arguments are for the default convert
+                                * command.
+                                */
+                               command = BT_CONFIG_COMMAND_CONVERT;
+                               command_argv = argv;
+                               command_argc = argc;
+                       }
+                       break;
+               }
+       }
+
+       if ((int) command < 0) {
+               /*
+                * We only got non-help, non-version general options
+                * like --verbose and --debug, without any other
+                * arguments, so we can't do anything useful: print the
+                * usage and quit.
+                */
+               print_gen_usage(stdout);
+               goto end;
+       }
+
+       assert(command_argv);
+       assert(command_argc >= 0);
+
+       switch (command) {
+       case BT_CONFIG_COMMAND_CONVERT:
+               config = bt_config_convert_from_args(command_argc, command_argv,
+                       retcode, omit_system_plugin_path,
+                       omit_home_plugin_path, initial_plugin_paths);
+               break;
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               config = bt_config_list_plugins_from_args(command_argc,
+                       command_argv, retcode, omit_system_plugin_path,
+                       omit_home_plugin_path, initial_plugin_paths);
+               break;
+       default:
+               assert(false);
+       }
+
+       if (config) {
+               if (verbose) {
+                       config->verbose = true;
+               }
+
+               if (debug) {
+                       config->debug = true;
+               }
+
+               config->command_name = command_name;
+       }
+
+end:
+       return config;
 }
index f32bf07aab0af42c38f794c2f8808e9580adad4b..20c1606667cc722c004f754c83016305ac1f5fe9 100644 (file)
@@ -40,22 +40,40 @@ struct bt_config_component {
        struct bt_value *params;
 };
 
+enum bt_config_command {
+       BT_CONFIG_COMMAND_CONVERT,
+       BT_CONFIG_COMMAND_LIST_PLUGINS,
+};
+
 struct bt_config {
        struct bt_object base;
-       struct bt_value *plugin_paths;
+       bool debug;
+       bool verbose;
+       const char *command_name;
+       enum bt_config_command command;
+       union {
+               /* BT_CONFIG_COMMAND_CONVERT */
+               struct {
+                       struct bt_value *plugin_paths;
 
-       /* Array of pointers to struct bt_config_component */
-       GPtrArray *sources;
+                       /* Array of pointers to struct bt_config_component */
+                       GPtrArray *sources;
 
-       /* Array of pointers to struct bt_config_component */
-       GPtrArray *sinks;
+                       /* Array of pointers to struct bt_config_component */
+                       GPtrArray *sinks;
 
-       bool debug;
-       bool verbose;
-       bool do_list;
-       bool force_correlate;
-       bool omit_system_plugin_path;
-       bool omit_home_plugin_path;
+                       bool force_correlate;
+                       bool omit_system_plugin_path;
+                       bool omit_home_plugin_path;
+               } convert;
+
+               /* BT_CONFIG_COMMAND_LIST_PLUGINS */
+               struct {
+                       struct bt_value *plugin_paths;
+                       bool omit_system_plugin_path;
+                       bool omit_home_plugin_path;
+               } list_plugins;
+       } cmd_data;
 };
 
 static inline
@@ -65,10 +83,10 @@ struct bt_config_component *bt_config_get_component(GPtrArray *array,
        return bt_get(g_ptr_array_index(array, index));
 }
 
-struct bt_config *bt_config_create(void);
-
-int bt_config_init_from_args(struct bt_config *cfg, int argc,
-               const char *argv[]);
+struct bt_config *bt_config_from_args(int argc, const char *argv[],
+               int *retcode, bool omit_system_plugin_path,
+               bool omit_home_plugin_path,
+               struct bt_value *initial_plugin_paths);
 
 enum bt_value_status bt_config_append_plugin_paths(
                struct bt_value *plugin_paths, const char *arg);
index 14954f1db12c7047d3ee4a1cf22a9fec42f85ca1..65d2ec9310af9b1aecbfdec03de520b5bde58282 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <babeltrace/babeltrace.h>
 #include <babeltrace/plugin/plugin.h>
+#include <babeltrace/common-internal.h>
 #include <babeltrace/component/component.h>
 #include <babeltrace/component/component-source.h>
 #include <babeltrace/component/component-sink.h>
@@ -97,102 +98,6 @@ end:
        return comp_class;
 }
 
-static
-const char *component_type_str(enum bt_component_class_type type)
-{
-       switch (type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-               return "source";
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-               return "sink";
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-               return "filter";
-       case BT_COMPONENT_CLASS_TYPE_UNKNOWN:
-       default:
-               return "unknown";
-       }
-}
-
-static
-void print_component_classes_found(void)
-{
-       int plugins_count, component_classes_count = 0, i;
-
-       if (!babeltrace_verbose) {
-               return;
-       }
-
-       plugins_count = loaded_plugins->len;
-       if (plugins_count == 0) {
-               fprintf(stderr, "No plugins found. Please make sure your plug-in search path is set correctly.\n");
-               return;
-       }
-
-       for (i = 0; i < plugins_count; i++) {
-               struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
-
-               component_classes_count += bt_plugin_get_component_class_count(plugin);
-       }
-
-       printf("Found %d component classes in %d plugins.\n",
-               component_classes_count, plugins_count);
-
-       for (i = 0; i < plugins_count; i++) {
-               int j;
-               struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
-               unsigned int major, minor, patch;
-               const char *extra;
-               enum bt_plugin_status version_status;
-
-               component_classes_count =
-                       bt_plugin_get_component_class_count(plugin);
-               version_status = bt_plugin_get_version(plugin, &major, &minor,
-                       &patch, &extra);
-
-               for (j = 0; j < component_classes_count; j++) {
-                       struct bt_component_class *comp_class =
-                               bt_plugin_get_component_class(plugin, j);
-                       const char *plugin_name = bt_plugin_get_name(plugin);
-                       const char *comp_class_name =
-                               bt_component_class_get_name(comp_class);
-                       const char *path = bt_plugin_get_path(plugin);
-                       const char *author = bt_plugin_get_author(plugin);
-                       const char *license = bt_plugin_get_license(plugin);
-                       const char *plugin_description =
-                               bt_plugin_get_description(plugin);
-                       const char *comp_class_description =
-                               bt_component_class_get_description(comp_class);
-                       enum bt_component_class_type type =
-                               bt_component_class_get_type(comp_class);
-
-                       printf("[%s - %s (%s)]\n", plugin_name,
-                               comp_class_name, component_type_str(type));
-                       printf("\tpath: %s\n", path ? path : "None");
-                       printf("\tauthor: %s\n",
-                               author ? author : "Unknown");
-                       printf("\tlicense: %s\n",
-                               license ? license : "Unknown");
-                       printf("\tplugin description: %s\n",
-                               plugin_description ? plugin_description : "None");
-
-                       if (version_status == BT_PLUGIN_STATUS_OK) {
-                               printf("\tplugin version: %u.%u.%u",
-                                       major, minor, patch);
-
-                               if (extra) {
-                                       printf("%s", extra);
-                               }
-
-                               printf("\n");
-                       }
-
-                       printf("\tcomponent description: %s\n",
-                               comp_class_description ? comp_class_description : "None");
-                       bt_put(comp_class);
-               }
-       }
-}
-
 static
 void print_indent(size_t indent)
 {
@@ -204,22 +109,39 @@ void print_indent(size_t indent)
 }
 
 static
-void print_value(struct bt_value *, size_t, bool);
+void print_value(struct bt_value *, size_t);
 
 static
 bool print_map_value(const char *key, struct bt_value *object, void *data)
 {
-       size_t indent = (size_t) data;
+       size_t *indent = data;
+
+       print_indent(*indent);
+       printf("%s: ", key);
+
+       if (bt_value_is_array(object) &&
+                       bt_value_array_is_empty(object)) {
+               printf("[ ]\n");
+               return true;
+       }
+
+       if (bt_value_is_map(object) &&
+                       bt_value_map_is_empty(object)) {
+               printf("{ }\n");
+               return true;
+       }
 
-       print_indent(indent);
-       printf("\"%s\": ", key);
-       print_value(object, indent, false);
+       if (bt_value_is_array(object) ||
+                       bt_value_is_map(object)) {
+               printf("\n");
+       }
 
+       print_value(object, *indent + 2);
        return true;
 }
 
 static
-void print_value(struct bt_value *value, size_t indent, bool do_indent)
+void print_value(struct bt_value *value, size_t indent)
 {
        bool bool_val;
        int64_t int_val;
@@ -232,17 +154,13 @@ void print_value(struct bt_value *value, size_t indent, bool do_indent)
                return;
        }
 
-       if (do_indent) {
-               print_indent(indent);
-       }
-
        switch (bt_value_get_type(value)) {
        case BT_VALUE_TYPE_NULL:
                printf("null\n");
                break;
        case BT_VALUE_TYPE_BOOL:
                bt_value_bool_get(value, &bool_val);
-               printf("%s\n", bool_val ? "true" : "false");
+               printf("%s\n", bool_val ? "yes" : "no");
                break;
        case BT_VALUE_TYPE_INTEGER:
                bt_value_integer_get(value, &int_val);
@@ -254,34 +172,55 @@ void print_value(struct bt_value *value, size_t indent, bool do_indent)
                break;
        case BT_VALUE_TYPE_STRING:
                bt_value_string_get(value, &str_val);
-               printf("\"%s\"\n", str_val);
+               printf("%s\n", str_val);
                break;
        case BT_VALUE_TYPE_ARRAY:
                size = bt_value_array_size(value);
-               printf("[\n");
+               assert(size >= 0);
+
+               if (size == 0) {
+                       print_indent(indent);
+                       printf("[ ]\n");
+                       break;
+               }
 
                for (i = 0; i < size; i++) {
                        struct bt_value *element =
                                        bt_value_array_get(value, i);
 
-                       print_value(element, indent + 2, true);
+                       assert(element);
+                       print_indent(indent);
+                       printf("- ");
+
+                       if (bt_value_is_array(element) &&
+                                       bt_value_array_is_empty(element)) {
+                               printf("[ ]\n");
+                               continue;
+                       }
+
+                       if (bt_value_is_map(element) &&
+                                       bt_value_map_is_empty(element)) {
+                               printf("{ }\n");
+                               continue;
+                       }
+
+                       if (bt_value_is_array(element) ||
+                                       bt_value_is_map(element)) {
+                               printf("\n");
+                       }
+
+                       print_value(element, indent + 2);
                        BT_PUT(element);
                }
-
-               print_indent(indent);
-               printf("]\n");
                break;
        case BT_VALUE_TYPE_MAP:
                if (bt_value_map_is_empty(value)) {
-                       printf("{}\n");
-                       return;
+                       print_indent(indent);
+                       printf("{ }\n");
+                       break;
                }
 
-               printf("{\n");
-               bt_value_map_foreach(value, print_map_value,
-                       (void *) (indent + 2));
-               print_indent(indent);
-               printf("}\n");
+               bt_value_map_foreach(value, print_map_value, &indent);
                break;
        default:
                assert(false);
@@ -291,10 +230,10 @@ void print_value(struct bt_value *value, size_t indent, bool do_indent)
 static
 void print_bt_config_component(struct bt_config_component *bt_config_component)
 {
-       printf("  %s.%s\n", bt_config_component->plugin_name->str,
+       printf("    %s.%s:\n", bt_config_component->plugin_name->str,
                bt_config_component->component_name->str);
-       printf("    params:\n");
-       print_value(bt_config_component->params, 6, true);
+       printf("      Parameters:\n");
+       print_value(bt_config_component->params, 8);
 }
 
 static
@@ -310,6 +249,31 @@ void print_bt_config_components(GPtrArray *array)
        }
 }
 
+static
+void print_plugin_paths(struct bt_value *plugin_paths)
+{
+       printf("  Plugin paths:\n");
+       print_value(plugin_paths, 4);
+}
+
+static
+void print_cfg_convert(struct bt_config *cfg)
+{
+       printf("  Force correlate: %s\n",
+               cfg->cmd_data.convert.force_correlate ? "yes" : "no");
+       print_plugin_paths(cfg->cmd_data.convert.plugin_paths);
+       printf("  Source component instances:\n");
+       print_bt_config_components(cfg->cmd_data.convert.sources);
+       printf("  Sink component instances:\n");
+       print_bt_config_components(cfg->cmd_data.convert.sinks);
+}
+
+static
+void print_cfg_list_plugins(struct bt_config *cfg)
+{
+       print_plugin_paths(cfg->cmd_data.list_plugins.plugin_paths);
+}
+
 static
 void print_cfg(struct bt_config *cfg)
 {
@@ -317,16 +281,20 @@ void print_cfg(struct bt_config *cfg)
                return;
        }
 
-       printf("debug:           %d\n", cfg->debug);
-       printf("verbose:         %d\n", cfg->verbose);
-       printf("do list:         %d\n", cfg->do_list);
-       printf("force correlate: %d\n", cfg->force_correlate);
-       printf("plugin paths:\n");
-       print_value(cfg->plugin_paths, 2, true);
-       printf("sources:\n");
-       print_bt_config_components(cfg->sources);
-       printf("sinks:\n");
-       print_bt_config_components(cfg->sinks);
+       printf("Configuration:\n");
+       printf("  Debug mode: %s\n", cfg->debug ? "yes" : "no");
+       printf("  Verbose mode: %s\n", cfg->verbose ? "yes" : "no");
+
+       switch (cfg->command) {
+       case BT_CONFIG_COMMAND_CONVERT:
+               print_cfg_convert(cfg);
+               break;
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               print_cfg_list_plugins(cfg);
+               break;
+       default:
+               assert(false);
+       }
 }
 
 static
@@ -479,11 +447,11 @@ void add_to_loaded_plugins(struct bt_plugin **plugins)
 }
 
 static
-int load_dynamic_plugins(struct bt_config *cfg)
+int load_dynamic_plugins(struct bt_value *plugin_paths)
 {
        int nr_paths, i, ret = 0;
 
-       nr_paths = bt_value_array_size(cfg->plugin_paths);
+       nr_paths = bt_value_array_size(plugin_paths);
        if (nr_paths < 0) {
                ret = -1;
                goto end;
@@ -494,7 +462,7 @@ int load_dynamic_plugins(struct bt_config *cfg)
                const char *plugin_path;
                struct bt_plugin **plugins;
 
-               plugin_path_value = bt_value_array_get(cfg->plugin_paths, i);
+               plugin_path_value = bt_value_array_get(plugin_paths, i);
                if (bt_value_string_get(plugin_path_value,
                                &plugin_path)) {
                        BT_PUT(plugin_path_value);
@@ -537,62 +505,192 @@ end:
        return ret;
 }
 
-int main(int argc, const char **argv)
+static
+const char *component_type_str(enum bt_component_class_type type)
 {
-       int ret;
-       struct bt_component_class *source_class = NULL;
-       struct bt_component_class *sink_class = NULL;
-       struct bt_component *source = NULL, *sink = NULL;
-       struct bt_value *source_params = NULL, *sink_params = NULL;
-       struct bt_config *cfg;
-       enum bt_component_status sink_status;
-       struct bt_config_component *source_cfg = NULL, *sink_cfg = NULL;
+       switch (type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+               return "source";
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+               return "sink";
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+               return "filter";
+       case BT_COMPONENT_CLASS_TYPE_UNKNOWN:
+       default:
+               return "unknown";
+       }
+}
 
-       init_loaded_plugins_array();
+static int load_all_plugins(struct bt_value *plugin_paths)
+{
+       int ret = 0;
 
-       cfg = bt_config_create();
-       if (!cfg) {
-               fprintf(stderr, "Failed to create Babeltrace configuration\n");
-               ret = 1;
+       if (load_dynamic_plugins(plugin_paths)) {
+               fprintf(stderr, "Failed to load dynamic plugins.\n");
+               ret = -1;
                goto end;
        }
 
-       ret = set_default_config(cfg);
-       if (ret) {
+       if (load_static_plugins()) {
+               fprintf(stderr, "Failed to load static plugins.\n");
+               ret = -1;
                goto end;
        }
 
-       ret = bt_config_init_from_args(cfg, argc, argv);
-       if (ret == 0) {
-               babeltrace_verbose = cfg->verbose;
-               babeltrace_debug = cfg->debug;
-               print_cfg(cfg);
-       } else {
+end:
+       return ret;
+}
+
+static int cmd_list_plugins(struct bt_config *cfg)
+{
+       int ret;
+       int plugins_count, component_classes_count = 0, i;
+
+       ret = load_all_plugins(cfg->cmd_data.list_plugins.plugin_paths);
+       if (ret) {
                goto end;
        }
 
-       /* TODO handle more than 1 source and 1 sink. */
-       if (cfg->sources->len != 1 || cfg->sinks->len != 1) {
+       plugins_count = loaded_plugins->len;
+       if (plugins_count == 0) {
+               fprintf(stderr, "%s%sNo plugins found.%s\n",
+                       bt_common_color_bold(), bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               fprintf(stderr, "\n");
+               fprintf(stderr, "Please make sure your plugin search path is set correctly. You can use\n");
+               fprintf(stderr, "the --plugin-path command-line option or the BABELTRACE_PLUGIN_PATH\n");
+               fprintf(stderr, "environment variable.\n");
                ret = -1;
                goto end;
        }
 
-       printf_verbose("Verbose mode active.\n");
-       printf_debug("Debug mode active.\n");
+       for (i = 0; i < plugins_count; i++) {
+               struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
+
+               component_classes_count += bt_plugin_get_component_class_count(plugin);
+       }
 
-       if (load_dynamic_plugins(cfg)) {
-               fprintf(stderr, "Failed to load dynamic plugins.\n");
+       printf("Found %s%d%s component classes in %s%d%s plugins.\n",
+               bt_common_color_bold(),
+               component_classes_count,
+               bt_common_color_reset(),
+               bt_common_color_bold(),
+               plugins_count,
+               bt_common_color_reset());
+
+       for (i = 0; i < plugins_count; i++) {
+               int j;
+               struct bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
+               unsigned int major, minor, patch;
+               const char *extra;
+               enum bt_plugin_status version_status;
+               const char *plugin_name = bt_plugin_get_name(plugin);
+               const char *path = bt_plugin_get_path(plugin);
+               const char *author = bt_plugin_get_author(plugin);
+               const char *license = bt_plugin_get_license(plugin);
+               const char *plugin_description =
+                       bt_plugin_get_description(plugin);
+
+               component_classes_count =
+                       bt_plugin_get_component_class_count(plugin);
+               version_status = bt_plugin_get_version(plugin, &major, &minor,
+                       &patch, &extra);
+
+               printf("\n%s%s%s%s:\n", bt_common_color_bold(),
+                       bt_common_color_fg_blue(), plugin_name,
+                       bt_common_color_reset());
+               printf("  %sPath%s: %s\n", bt_common_color_bold(),
+                       bt_common_color_reset(), path ? path : "(None)");
+
+               if (version_status == BT_PLUGIN_STATUS_OK) {
+                       printf("  %sVersion%s: %u.%u.%u",
+                               bt_common_color_bold(), bt_common_color_reset(),
+                               major, minor, patch);
+
+                       if (extra) {
+                               printf("%s", extra);
+                       }
+
+                       printf("\n");
+               }
+
+               printf("  %sDescription%s: %s\n", bt_common_color_bold(),
+                       bt_common_color_reset(),
+                       plugin_description ? plugin_description : "(None)");
+               printf("  %sAuthor%s: %s\n", bt_common_color_bold(),
+                       bt_common_color_reset(), author ? author : "(Unknown)");
+               printf("  %sLicense%s: %s\n", bt_common_color_bold(),
+                       bt_common_color_reset(),
+                       license ? license : "(Unknown)");
+
+               if (component_classes_count == 0) {
+                       printf("  %sComponent classes%s: (None)\n",
+                               bt_common_color_bold(),
+                               bt_common_color_reset());
+               } else {
+                       printf("  %sComponent classes%s:\n",
+                               bt_common_color_bold(),
+                               bt_common_color_reset());
+               }
+
+               for (j = 0; j < component_classes_count; j++) {
+                       struct bt_component_class *comp_class =
+                               bt_plugin_get_component_class(plugin, j);
+                       const char *comp_class_name =
+                               bt_component_class_get_name(comp_class);
+                       const char *comp_class_description =
+                               bt_component_class_get_description(comp_class);
+                       enum bt_component_class_type type =
+                               bt_component_class_get_type(comp_class);
+
+                       printf("    %s%s--%s%s %s%s%s.%s%s%s",
+                               bt_common_color_bold(),
+                               bt_common_color_fg_cyan(),
+                               component_type_str(type),
+                               bt_common_color_fg_default(),
+                               bt_common_color_fg_blue(),
+                               plugin_name,
+                               bt_common_color_fg_default(),
+                               bt_common_color_fg_yellow(),
+                               comp_class_name,
+                               bt_common_color_reset());
+
+                       if (comp_class_description) {
+                               printf(": %s", comp_class_description);
+                       }
+
+                       printf("\n");
+                       bt_put(comp_class);
+               }
+       }
+
+end:
+       return ret;
+}
+
+static int cmd_convert(struct bt_config *cfg)
+{
+       int ret = 0;
+       struct bt_component_class *source_class = NULL;
+       struct bt_component_class *sink_class = NULL;
+       struct bt_component *source = NULL, *sink = NULL;
+       struct bt_value *source_params = NULL, *sink_params = NULL;
+       enum bt_component_status sink_status;
+       struct bt_config_component *source_cfg = NULL, *sink_cfg = NULL;
+
+       /* TODO handle more than 1 source and 1 sink. */
+       if (cfg->cmd_data.convert.sources->len != 1 ||
+                       cfg->cmd_data.convert.sinks->len != 1) {
                ret = -1;
                goto end;
        }
 
-       if (load_static_plugins()) {
-               fprintf(stderr, "Failed to load static plugins.\n");
+       ret = load_all_plugins(cfg->cmd_data.convert.plugin_paths);
+       if (ret) {
                goto end;
        }
 
-       print_component_classes_found();
-       source_cfg = bt_config_get_component(cfg->sources, 0);
+       source_cfg = bt_config_get_component(cfg->cmd_data.convert.sources, 0);
        source_params = bt_get(source_cfg->params);
        source_class = find_component_class(source_cfg->plugin_name->str,
                        source_cfg->component_name->str,
@@ -605,7 +703,7 @@ int main(int argc, const char **argv)
                goto end;
        }
 
-       sink_cfg = bt_config_get_component(cfg->sinks, 0);
+       sink_cfg = bt_config_get_component(cfg->cmd_data.convert.sinks, 0);
        sink_params = bt_get(sink_cfg->params);
        sink_class = find_component_class(sink_cfg->plugin_name->str,
                        sink_cfg->component_name->str,
@@ -634,6 +732,7 @@ int main(int argc, const char **argv)
 
        ret = connect_source_sink(source, source_cfg, sink);
        if (ret) {
+               ret = -1;
                goto end;
        }
 
@@ -654,6 +753,7 @@ int main(int argc, const char **argv)
                        goto end;
                }
        }
+
 end:
        BT_PUT(sink_class);
        BT_PUT(source_class);
@@ -661,9 +761,73 @@ end:
        BT_PUT(sink);
        BT_PUT(source_params);
        BT_PUT(sink_params);
-       BT_PUT(cfg);
        BT_PUT(sink_cfg);
        BT_PUT(source_cfg);
+       return ret;
+}
+
+static void warn_command_name_and_directory_clash(struct bt_config *cfg)
+{
+       if (!cfg->command_name) {
+               return;
+       }
+
+       if (g_file_test(cfg->command_name,
+                       G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+               fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
+                       cfg->command_name);
+               fprintf(stderr, "trace located in the local `%s` directory, please use:\n",
+                       cfg->command_name);
+               fprintf(stderr, "\n");
+               fprintf(stderr, "    babeltrace convert %s [OPTIONS]\n",
+                       cfg->command_name);
+       }
+}
+
+int main(int argc, const char **argv)
+{
+       int ret;
+       int retcode;
+       struct bt_config *cfg;
+
+       init_loaded_plugins_array();
+       cfg = bt_config_from_args_with_defaults(argc, argv, &retcode);
+
+       if (retcode < 0) {
+               /* Quit without errors; typically usage/version */
+               retcode = 0;
+               goto end;
+       }
+
+       if (retcode > 0) {
+               goto end;
+       }
+
+       if (!cfg) {
+               fprintf(stderr, "Failed to create Babeltrace configuration\n");
+               goto end;
+       }
+
+       babeltrace_debug = cfg->debug;
+       babeltrace_verbose = cfg->verbose;
+       print_cfg(cfg);
+
+       switch (cfg->command) {
+       case BT_CONFIG_COMMAND_CONVERT:
+               ret = cmd_convert(cfg);
+               break;
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               ret = cmd_list_plugins(cfg);
+               break;
+       default:
+               assert(false);
+       }
+
+       warn_command_name_and_directory_clash(cfg);
+       retcode = ret ? 1 : 0;
+
+end:
+       BT_PUT(cfg);
        fini_loaded_plugins_array();
-       return ret ? 1 : 0;
+       return retcode;
 }
index 5368c7a0affb0bc531aaa8fbab48cc2a096835e4..fb32543143be9afe8bc069fc6766be87a47b2619 100644 (file)
 
 #ifdef BT_SET_DEFAULT_IN_TREE_CONFIGURATION
 
-int set_default_config(struct bt_config *cfg)
+struct bt_config *bt_config_from_args_with_defaults(int argc,
+               const char *argv[], int *retcode)
 {
+       struct bt_value *initial_plugin_paths;
+       struct bt_config *cfg = NULL;
        int ret;
 
-       cfg->omit_system_plugin_path = true;
-       cfg->omit_home_plugin_path = true;
-       ret = bt_config_append_plugin_paths(cfg->plugin_paths,
+       initial_plugin_paths = bt_value_array_create();
+       if (!initial_plugin_paths) {
+               goto error;
+       }
+
+       ret = bt_config_append_plugin_paths(initial_plugin_paths,
                CONFIG_IN_TREE_PLUGIN_PATH);
-       return ret;
+       if (ret) {
+               goto error;
+       }
+
+       cfg = bt_config_from_args(argc, argv, retcode, true, true,
+               initial_plugin_paths);
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_PUT(cfg);
+
+end:
+       bt_put(initial_plugin_paths);
+       return cfg;
 }
 
 #else /* BT_SET_DEFAULT_IN_TREE_CONFIGURATION */
 
-int set_default_config(struct bt_config *cfg)
+struct bt_config *bt_config_from_args_with_defaults(int argc,
+               const char *argv[], int *retcode)
 {
-       /* Nothing to set. */
-       return 0;
+       return bt_config_from_args(argc, argv, retcode, false, false, NULL);
 }
 
 #endif /* BT_SET_DEFAULT_IN_TREE_CONFIGURATION */
index 9d9cd6bffaf90ad181d26d6194120e046c2272b6..d6b918889d5fd188ba16829e2dbc801bd9c6e76b 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "babeltrace-cfg.h"
 
-int set_default_config(struct bt_config *cfg);
+struct bt_config *bt_config_from_args_with_defaults(int argc,
+               const char *argv[], int *retcode);
 
 #endif /* BABELTRACE_DEFAULT_CFG_H */
index 64299e9dd0e36d7ef6d524435f12c58db5fab768..1beb9d9bf1cb5510b0f72bd11e5edad1503e1603 100644 (file)
@@ -15,4 +15,58 @@ char *bt_common_get_home_plugin_path(void);
 BT_HIDDEN
 int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs);
 
+BT_HIDDEN
+const char *bt_common_color_reset(void);
+
+BT_HIDDEN
+const char *bt_common_color_bold(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_default(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_red(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_green(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_yellow(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_blue(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_magenta(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_cyan(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_light_gray(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_default(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_red(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_green(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_yellow(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_blue(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_magenta(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_cyan(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_light_gray(void);
+
 #endif /* BABELTRACE_COMMON_INTERNAL_H */
This page took 0.053816 seconds and 4 git commands to generate.