[Workman-devel] [PATCH] CLI: workman command line interface framework

Josh Poimboeuf jpoimboe at redhat.com
Wed Apr 17 20:07:47 UTC 2013


NOTE: This compiles but doesn't actually work yet.  It will need some of the
patches still under review on the mailing list (particularly the WorkmanManager
patch at least), a dummy plugin, as well as some additional fixes.

The additional fixes include checking for NULL pointers before calling
g_object_free or g_boxed_free throughout libworkman, as well as calling
g_type_init() in workman_init_check().

Daniel, I haven't posted those fixes since you're making some changes to
libworkman.  I'll post them and a dummy plugin later once your changes to
libworkman have been sorted out.

---8<---

This adds the framework for the "workman" tool which will be the command
line interface to libworkman.

- Add a barely functional workman.c with the basic interfaces in place,
  and one of the commands implemented.
- Update the makefiles to build tools/Makefile and workman.
- Update the libworkman makefile to link with libgobject.
- Export some needed libworkman symbols.
---
 .gitignore             |   1 +
 Makefile.am            |   2 +-
 configure.ac           |   1 +
 tools/Makefile.am      |  14 +++
 tools/workman.c        | 226 +++++++++++++++++++++++++++++++++++++++++++++++++
 workman/Makefile.am    |   5 +-
 workman/libworkman.sym |   2 +
 7 files changed, 249 insertions(+), 2 deletions(-)
 create mode 100644 tools/Makefile.am
 create mode 100644 tools/workman.c

diff --git a/.gitignore b/.gitignore
index 348274b..b4996bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,4 @@ docs/workman/version.xml
 *.swp
 cscope.*
 workman/workman-enums.[ch]
+tools/workman
diff --git a/Makefile.am b/Makefile.am
index 4eac35b..4cec125 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
 
-SUBDIRS = workman docs
+SUBDIRS = workman tools docs
 
 ACLOCAL_AMFLAGS = -I m4
 
diff --git a/configure.ac b/configure.ac
index 3ea30da..8df0ed2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -89,6 +89,7 @@ AM_CONDITIONAL([WITH_GOBJECT_INTROSPECTION], [test "x$enable_introspection" = "x
 
 AC_OUTPUT(Makefile
           workman/Makefile
+          tools/Makefile
           docs/Makefile
           docs/workman/Makefile
           docs/workman/version.xml
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..1cfc65c
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,14 @@
+bin_PROGRAMS = workman
+
+workman_SOURCES = workman.c
+
+workman_CFLAGS = \
+		 -I$(top_srcdir) \
+		 $(GOBJECT2_CFLAGS) \
+		 $(WARN_CFLAGS) \
+		 $(NULL)
+
+workman_LDADD = \
+		../workman/libworkman-1.0.la \
+		$(NULL)
+
diff --git a/tools/workman.c b/tools/workman.c
new file mode 100644
index 0000000..9f868a3
--- /dev/null
+++ b/tools/workman.c
@@ -0,0 +1,226 @@
+/*
+ * workman.c: cmdline interface to libworkman
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Josh Poimboeuf <jpoimboe at redhat.com>
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <glib.h>
+#include <config.h>
+#include "workman/workman.h"
+
+struct workman_args {
+    WorkmanState state;
+    int cmd_argc;
+    char **cmd_argv;
+};
+
+struct workman_cmd {
+    const char *name;
+    const char *arg_description;
+    int min_args;
+    int max_args;
+    void (*handler)(WorkmanManager *, struct workman_args *);
+};
+
+
+#define WORKMAN_ERROR_EXIT(err, fmt, ...)                                   \
+({                                                                          \
+    fprintf(stderr, fmt, ##__VA_ARGS__);                                    \
+    if (err)                                                                \
+        fprintf(stderr, ": %s", err->message);                              \
+    fprintf(stderr, "\n");                                                  \
+    exit(1);                                                                \
+})
+
+#define WORKMAN_USAGE_EXIT(...)                                             \
+({                                                                          \
+    GError *err = NULL;                                                     \
+    WORKMAN_ERROR_EXIT(err, __VA_ARGS__);                                   \
+})
+
+static void
+list_partitions(WorkmanManager *mgr,
+                struct workman_args *args)
+{
+    GList *partitions, *p;
+    GError *err = NULL;
+    char *parent_name = NULL;
+
+    if (args->cmd_argc == 1)
+        parent_name = args->cmd_argv[0];
+    else if (args->cmd_argc != 0)
+        WORKMAN_USAGE_EXIT("unknown arguments");
+
+    partitions = workman_manager_get_partitions(mgr, args->state, &err);
+
+    if (partitions) {
+        g_warn_if_fail(err == NULL);
+        for (p = partitions; p; p = p->next) {
+            WorkmanPartition *part = WORKMAN_PARTITION(p->data);
+
+            if (parent_name) {
+                WorkmanPartition *parent;
+                parent = workman_partition_get_parent(part, args->state, &err);
+                if (err)
+                    WORKMAN_ERROR_EXIT(err,
+                                       "workman_partition_get_parent failed");
+                if (!parent ||
+                    g_strcmp0(parent_name,
+                              workman_object_get_name(WORKMAN_OBJECT(parent))))
+                    continue;
+            }
+
+            printf("%s\n", workman_object_get_name(WORKMAN_OBJECT(part)));
+        }
+
+        g_boxed_free(WORKMAN_TYPE_PARTITION_LIST, partitions);
+    }
+}
+
+static void list_consumers(WorkmanManager *mgr, struct workman_args *args) {}
+static void list_attributes(WorkmanManager *mgr, struct workman_args *args) {}
+static void list_processes(WorkmanManager *mgr, struct workman_args *args) {}
+static void show_partition(WorkmanManager *mgr, struct workman_args *args) {}
+static void show_attribute(WorkmanManager *mgr, struct workman_args *args) {}
+static void set_partition(WorkmanManager *mgr, struct workman_args *args) {}
+static void set_attribute(WorkmanManager *mgr, struct workman_args *args) {}
+static void create_partition(WorkmanManager *mgr, struct workman_args *args) {}
+
+static const struct workman_cmd workman_cmds[] = {
+    {"partitions",          "[PARTITION]",              0, 0, list_partitions},
+    {"consumers",           "[PARTITION]",              0, 1, list_consumers},
+    {"attributes",          "OBJECT",                   1, 1, list_attributes},
+    {"processes",           "CONSUMER",                 1, 1, list_processes},
+    {"partition",           "PARTITION|CONSUMER",       1, 1, show_partition},
+    {"attribute",           "OBJECT ATTRIBUTE",         2, 2, show_attribute},
+    {"set-partition",       "PARTITION|CONSUMER",       2, 2, set_partition},
+    {"set-attribute",       "OBJECT ATTRIBUTE VALUE",   3, 3, set_attribute},
+    {"create-partition",    "NAME",                     1, 1, create_partition},
+    {},
+};
+
+
+static void
+workman_usage()
+{
+    const struct workman_cmd *cmd;
+    extern char *program_invocation_short_name;
+
+    printf("Usage: %s [OPTION...] COMMAND [ARGS...]\n\n",
+           program_invocation_short_name);
+    printf("  -h, --help                Give this help list\n");
+    printf("  -s, --state=STATE         active, persistent, or all (default=active)\n");
+
+    printf("\nCommands:\n");
+    for (cmd = workman_cmds; cmd->name; cmd++)
+        printf("  %s %s\n", cmd->name, cmd->arg_description);
+}
+
+
+int
+main(int argc, char **argv)
+{
+    const struct workman_cmd *cmd;
+    struct workman_args args;
+    char arg;
+
+    args.state = WORKMAN_STATE_ACTIVE;
+
+    const struct option long_options[] = {
+        {"help",    no_argument,        NULL,   'h'},
+        {"state",   required_argument,  NULL,   's'},
+        {},
+    };
+
+    while ((arg = getopt_long(argc, argv, ":hs:", long_options, NULL)) != -1) {
+        switch (arg) {
+            case 'h':
+                workman_usage();
+                exit(0);
+                break;
+            case 's':
+                if (!g_strcmp0(optarg, "active"))
+                    args.state = WORKMAN_STATE_ACTIVE;
+                else if (!g_strcmp0(optarg, "persistent"))
+                    args.state = WORKMAN_STATE_PERSISTENT;
+                else if (!g_strcmp0(optarg, "all"))
+                    args.state = WORKMAN_STATE_ALL;
+                else
+                    WORKMAN_USAGE_EXIT("invalid state");
+                break;
+            case ':':
+                WORKMAN_USAGE_EXIT("option '%c' requires an argument", optopt);
+                break;
+            case '?':
+                WORKMAN_USAGE_EXIT("unknown option '%c'", optopt);
+                break;
+        }
+    }
+
+    if (optind == argc)
+        WORKMAN_USAGE_EXIT("missing command");
+
+    for (cmd = workman_cmds; ; cmd++) {
+
+        if (!cmd->name)
+            WORKMAN_USAGE_EXIT("unknown command '%s'", argv[optind]);
+
+        if (!g_strcmp0(argv[optind], cmd->name)) {
+
+            WorkmanManager *mgr;
+            GError *err = NULL;
+
+            args.cmd_argc = argc - optind - 1;
+            args.cmd_argv = &argv[optind + 1];
+
+
+            if (args.cmd_argc < cmd->min_args || args.cmd_argc > cmd->max_args)
+                WORKMAN_USAGE_EXIT("invalid number of arguments for '%s'",
+                                   cmd->name);
+
+            workman_init(NULL, NULL);
+
+            mgr = workman_manager_get_default(&err);
+            if (!mgr)
+                WORKMAN_ERROR_EXIT(err, "workman_manager_get_default failed");
+
+            cmd->handler(mgr, &args);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ *
+ * vim: set expandtab shiftwidth=4 tabstop=4 :
+ */
diff --git a/workman/Makefile.am b/workman/Makefile.am
index 063504d..59508a5 100644
--- a/workman/Makefile.am
+++ b/workman/Makefile.am
@@ -37,10 +37,13 @@ libworkman_1_0_la_CFLAGS = \
 			-I$(top_srcdir) \
 			$(GLIB2_CFLAGS) \
 			$(GTHREAD2_CFLAGS) \
+			$(GOBJECT2_CFLAGS) \
 			$(WARN_CFLAGS)
 libworkman_1_0_la_LIBADD = \
 			$(GLIB2_LIBS) \
-			$(GTHREAD2_LIBS)
+			$(GTHREAD2_LIBS) \
+			$(GOBJECT2_LIBS) \
+			$(NULL)
 libworkman_1_0_la_DEPENDENCIES = \
 			libworkman.sym
 libworkman_1_0_la_LDFLAGS = \
diff --git a/workman/libworkman.sym b/workman/libworkman.sym
index 53a0460..114f326 100644
--- a/workman/libworkman.sym
+++ b/workman/libworkman.sym
@@ -10,6 +10,7 @@ LIBworkman_0.0.1 {
         workman_object_save_attributes;
         workman_object_get_state;
         workman_object_attribute_list_get_type;
+        workman_object_get_name;
 
         workman_attribute_get_name;
         workman_attribute_get_type;
@@ -29,6 +30,7 @@ LIBworkman_0.0.1 {
         workman_manager_get_partitions;
         workman_manager_new;
         workman_manager_remove_partition;
+        workman_manager_get_default;
 
         workman_partition_get_consumers;
         workman_partition_get_children;
-- 
1.7.11.7




More information about the Workman-devel mailing list