[tracker/wip/carlosg/cli-split: 2/4] tracker: Allow extending the CLI tool with additional subcommands



commit 8da1f13c7df386163b26277cfb92b80d1e0c7f8a
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Dec 19 14:12:55 2019 +0100

    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.

 src/tracker/make-subcommand-links.sh | 25 ++++++++++++
 src/tracker/meson.build              | 16 ++++++--
 src/tracker/tracker-main.c           | 75 ++++++++++++++++++++++--------------
 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]