summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2019-12-19 14:12:55 +0100
committerCarlos Garnacho <carlosg@gnome.org>2019-12-29 22:46:16 +0100
commit8da1f13c7df386163b26277cfb92b80d1e0c7f8a (patch)
tree338b108ff1007d2c229821e089d7568197c584e9
parent7bd6b4cce0de53f43833a8b1b270087ead8f8e5f (diff)
downloadtracker-8da1f13c7df386163b26277cfb92b80d1e0c7f8a.tar.gz
tracker: Allow extending the CLI tool with additional subcommands
We still link all the builtin tools in a single binary, and create specific links in $libexecdir/tracker/. External subcommands may install their binaries on $libexecdir/tracker right away. During (sub)command execution, the tracker binary will look for the proper subcommand and execve it. As the same tracker binary implements those same subcommands, it does check argv[0] to know if it is running as one of those subcommands. This keeps a single binary around, but allows transparently falling back to other executables.
-rw-r--r--src/tracker/make-subcommand-links.sh25
-rw-r--r--src/tracker/meson.build16
-rw-r--r--src/tracker/tracker-main.c75
3 files changed, 83 insertions, 33 deletions
diff --git a/src/tracker/make-subcommand-links.sh b/src/tracker/make-subcommand-links.sh
new file mode 100644
index 000000000..a257d1612
--- /dev/null
+++ b/src/tracker/make-subcommand-links.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+bindir=$MESON_INSTALL_PREFIX/bin
+libexecdir=$MESON_INSTALL_PREFIX/libexec
+
+if [ -d $libexecdir/tracker ]
+then
+ for l in `find $libexecdir/tracker -type l`
+ do
+ # Delete all previous links to our own binary
+ if [[ `readlink $l` = "$bindir/tracker" ]]
+ then
+ rm $l
+ fi
+ done
+fi
+
+mkdir -p $libexecdir/tracker
+
+for subcommand in $@
+do
+ ln -s $bindir/tracker $libexecdir/tracker/$subcommand
+done
diff --git a/src/tracker/meson.build b/src/tracker/meson.build
index 48bc3e7c5..af6e5f7b7 100644
--- a/src/tracker/meson.build
+++ b/src/tracker/meson.build
@@ -1,11 +1,18 @@
+modules = [
+ 'help',
+ 'info',
+ 'sparql',
+ 'sql',
+]
+
sources = [
'tracker-main.c',
- 'tracker-help.c',
- 'tracker-info.c',
- 'tracker-sparql.c',
- 'tracker-sql.c',
]
+foreach m: modules
+ sources += 'tracker-@0@.c'.format(m)
+endforeach
+
executable('tracker', sources,
c_args: tracker_c_args + [
'-DLIBEXECDIR="@0@"'.format(join_paths(get_option('prefix'), get_option('libexecdir'))),
@@ -19,6 +26,7 @@ executable('tracker', sources,
include_directories: [commoninc, configinc, srcinc],
)
+meson.add_install_script('make-subcommand-links.sh', modules)
if install_bash_completion
install_data(
diff --git a/src/tracker/tracker-main.c b/src/tracker/tracker-main.c
index fde5be4f6..b65ee5bbc 100644
--- a/src/tracker/tracker-main.c
+++ b/src/tracker/tracker-main.c
@@ -66,7 +66,7 @@ tracker_help (int argc, const char **argv)
}
static int
-tracker_version (int argc, const char **argv)
+print_version (void)
{
puts (about);
return 0;
@@ -91,7 +91,6 @@ static struct cmd_struct commands[] = {
{ "info", tracker_info, NEED_WORK_TREE, N_("Show information known about local files or items indexed") },
{ "sparql", tracker_sparql, NEED_WORK_TREE, N_("Query and update the index using SPARQL or search, list and tree the ontology") },
{ "sql", tracker_sql, NEED_WORK_TREE, N_("Query the database at the lowest level using SQL") },
- { "version", tracker_version, NEED_NOTHING, N_("Show the license and version in use") },
};
static int
@@ -118,15 +117,9 @@ static void
handle_command (int argc, const char **argv)
{
gchar *log_filename = NULL;
- const char *cmd = argv[0];
+ char *cmd = g_path_get_basename (argv[0]);
int i;
- /* Turn "tracker cmd --help" into "tracker help cmd" */
- if (argc > 1 && !strcmp (argv[1], "--help")) {
- argv[1] = argv[0];
- argv[0] = cmd = "help";
- }
-
tracker_log_init (0, &log_filename);
if (log_filename != NULL) {
g_message ("Using log file:'%s'", log_filename);
@@ -140,11 +133,13 @@ handle_command (int argc, const char **argv)
continue;
}
+ g_free (cmd);
exit (run_builtin (p, argc, argv));
}
g_printerr (_("“%s” is not a tracker command. See “tracker --help”"), argv[0]);
g_printerr ("\n");
+ g_free (cmd);
exit (EXIT_FAILURE);
}
@@ -190,10 +185,10 @@ print_usage (void)
}
int
-main (int original_argc, char **original_argv)
+main (int argc, char *argv[])
{
- const char **argv = (const char **) original_argv;
- int argc = original_argc;
+ gboolean basename_is_bin = FALSE;
+ gchar *command_basename;
setlocale (LC_ALL, "");
@@ -201,24 +196,46 @@ main (int original_argc, char **original_argv)
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
- argv++;
- argc--;
-
- if (argc > 0) {
- /* For cases like --version */
- if (g_str_has_prefix (argv[0], "--")) {
- argv[0] += 2;
+ command_basename = g_path_get_basename (argv[0]);
+ basename_is_bin = g_strcmp0 (command_basename, "tracker") == 0;
+ g_free (command_basename);
+
+ if (g_path_is_absolute (argv[0]) &&
+ g_str_has_prefix (argv[0], LIBEXECDIR "/tracker/")) {
+ /* This is a subcommand call */
+ handle_command (argc, (const gchar **) argv);
+ exit (EXIT_FAILURE);
+ } else if (basename_is_bin) {
+ /* This is a call to the main tracker executable,
+ * look up and exec the subcommand if any.
+ */
+ if (argc > 1) {
+ const gchar *subcommand = argv[1];
+ gchar *path;
+
+ if (g_strcmp0 (subcommand, "--version") == 0) {
+ print_version ();
+ exit (EXIT_SUCCESS);
+ } else if (g_strcmp0 (subcommand, "--help") == 0) {
+ subcommand = "help";
+ }
+
+ path = g_build_filename (LIBEXECDIR, "tracker", subcommand, NULL);
+
+ if (g_file_test (path, G_FILE_TEST_EXISTS)) {
+ /* Manipulate argv in place, in order to launch subcommand */
+ argv[1] = path;
+ execv (path, &argv[1]);
+ } else {
+ print_usage ();
+ }
+
+ g_free (path);
+ } else {
+ /* The user didn't specify a command; give them help */
+ print_usage ();
+ exit (EXIT_SUCCESS);
}
- } else {
- /* The user didn't specify a command; give them help */
- print_usage ();
- exit (1);
- }
-
- handle_command (argc, argv);
-
- if ((char **) argv != original_argv) {
- g_strfreev ((char **) argv);
}
return EXIT_FAILURE;