diff --git a/dbus-glib-0.77-bash-completion.patch b/dbus-glib-0.77-bash-completion.patch new file mode 100644 index 0000000..7f89968 --- /dev/null +++ b/dbus-glib-0.77-bash-completion.patch @@ -0,0 +1,629 @@ +From 91f6977a2dc01207072b5718b89c57f439f9339a Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 31 Jul 2008 12:28:07 -0400 +Subject: [PATCH] add bash completion for dbus-send(1) + +For now, it's in dbus-glib since dbus doesn't have an introspection +XML parser (yet). +--- + configure.ac | 13 + + dbus/Makefile.am | 17 ++- + dbus/dbus-bash-completion-helper.c | 513 ++++++++++++++++++++++++++++++++++++ + dbus/dbus-bash-completion.sh.in | 21 ++ + 4 files changed, 563 insertions(+), 1 deletions(-) + create mode 100644 dbus/dbus-bash-completion-helper.c + create mode 100644 dbus/dbus-bash-completion.sh.in + +diff --git a/configure.ac b/configure.ac +index 839e0e1..a163935 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -54,11 +54,23 @@ AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion chec + AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes) + AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto) + AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no) ++AC_ARG_ENABLE(bash-completion, AS_HELP_STRING([--enable-bash-completion],[install bash completion scripts]),enable_bash_completion=$enableval,enable_bash_completion=yes) + AC_ARG_WITH(test-socket-dir, AS_HELP_STRING([--with-test-socket-dir=[dirname]],[Where to put sockets for make check])) + + + AC_ARG_WITH(introspect-xml, AS_HELP_STRING([--with-introspect-xml=[filename]],[Pass in a pregenerated dbus daemon introspection xml file (as generated by 'dbus-daemon --introspect') to use instead of querying the installed dbus daemon])) + ++ ++AM_CONDITIONAL(DBUS_BASH_COMPLETION, test x$enable_bash_completion = xyes) ++if test x$enable_bash_completion = xyes; then ++ AC_DEFINE(DBUS_BASH_COMPLETION,1,[Enable bash completion]) ++fi ++ ++if test x$enable_verbose_mode = xyes; then ++ AC_DEFINE(DBUS_ENABLE_VERBOSE_MODE,1,[Support a verbose mode]) ++fi ++ ++ + dnl DBUS_BUILD_TESTS controls unit tests built in to .c files + dnl and also some stuff in the test/ subdir + AM_CONDITIONAL(DBUS_BUILD_TESTS, test x$enable_tests = xyes) +@@ -867,6 +879,7 @@ echo " + Building checks: ${enable_checks} + Building Doxygen docs: ${enable_doxygen_docs} + Building Gtk-doc docs: ${enable_gtk_doc} ++ Bash Completion: ${enable_bash_completion} + Gettext libs (empty OK): ${INTLLIBS} + Using XML parser: ${with_xml} + 'make check' socket dir: ${TEST_SOCKET_DIR} +diff --git a/dbus/Makefile.am b/dbus/Makefile.am +index 2650e8b..bd01d7f 100644 +--- a/dbus/Makefile.am ++++ b/dbus/Makefile.am +@@ -91,7 +91,22 @@ regenerate-built-sources: + echo '#include "dbus-gmarshal.h"' > dbus-gmarshal.c && \ + @GLIB_GENMARSHAL@ --prefix=_dbus_g_marshal dbus-gmarshal.list --body >> dbus-gmarshal.c + +-EXTRA_DIST=dbus-gmarshal.list make-dbus-glib-error-switch.sh make-dbus-glib-error-enum.sh ++ ++profiledir = $(sysconfdir)/profile.d ++if DBUS_BASH_COMPLETION ++libexec_PROGRAMS=dbus-bash-completion-helper ++profile_SCRIPTS=dbus-bash-completion.sh ++endif ++ ++dbus-bash-completion.sh : dbus-bash-completion.sh.in ++ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ ++ ++dbus_bash_completion_helper_SOURCES = \ ++ dbus-bash-completion-helper.c ++dbus_bash_completion_helper_LDADD=$(DBUS_LIBS) $(DBUS_GLIB_LIBS) -lexpat libdbus-gtool.la libdbus-glib-1.la ++ ++ ++EXTRA_DIST=dbus-gmarshal.list make-dbus-glib-error-switch.sh make-dbus-glib-error-enum.sh dbus-bash-completion.sh.in + + if DBUS_BUILD_TESTS + +diff --git a/dbus/dbus-bash-completion-helper.c b/dbus/dbus-bash-completion-helper.c +new file mode 100644 +index 0000000..022c722 +--- /dev/null ++++ b/dbus/dbus-bash-completion-helper.c +@@ -0,0 +1,513 @@ ++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ ++/* dbus-bash-completion-helper.c Bash Completion helper routines ++ * ++ * Copyright (C) 2008 David Zeuthen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include "dbus-gparser.h" ++ ++static void ++print_services (DBusConnection *connection) ++{ ++ DBusMessage *message; ++ DBusMessage *reply; ++ DBusError error; ++ DBusMessageIter iter; ++ DBusMessageIter iter_array; ++ const char *name; ++ ++ /* list both active and activatable names (the shell will sort and ++ * uniquify them) - also avoid names that are not well-known ++ * (e.g. :1.42). ++ */ ++ ++ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "ListNames"); ++ dbus_error_init (&error); ++ reply = dbus_connection_send_with_reply_and_block (connection, ++ message, ++ -1, ++ &error); ++ dbus_message_unref (message); ++ dbus_message_iter_init (reply, &iter); ++ dbus_message_iter_recurse (&iter, &iter_array); ++ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) ++ { ++ dbus_message_iter_get_basic (&iter_array, &name); ++ if (name[0] != ':') ++ printf ("%s \n", name); ++ dbus_message_iter_next (&iter_array); ++ } ++ dbus_message_unref (reply); ++ ++ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS, ++ "ListActivatableNames"); ++ dbus_error_init (&error); ++ reply = dbus_connection_send_with_reply_and_block (connection, ++ message, ++ -1, ++ &error); ++ dbus_message_unref (message); ++ dbus_message_iter_init (reply, &iter); ++ dbus_message_iter_recurse (&iter, &iter_array); ++ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) ++ { ++ dbus_message_iter_get_basic (&iter_array, &name); ++ printf ("%s \n", name); ++ dbus_message_iter_next (&iter_array); ++ } ++ dbus_message_unref (reply); ++} ++ ++static gboolean ++have_option (char **tokens, const char *option) ++{ ++ int n; ++ for (n = 0; tokens[n] != NULL; n++) ++ if (strcmp (tokens[n], option) == 0) ++ return TRUE; ++ return FALSE; ++} ++ ++static gboolean ++have_option_with_value (char **tokens, const char *option, const char **value) ++{ ++ int n; ++ for (n = 0; tokens[n] != NULL; n++) ++ { ++ if (g_str_has_prefix (tokens[n], option)) ++ { ++ if (strlen (tokens[n]) > strlen (option)) ++ *value = tokens[n] + strlen (option); ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ ++static void ++print_objects (DBusConnection *connection, const char *service_name, const char *cur) ++{ ++ DBusMessage *message; ++ DBusMessage *reply; ++ DBusError error; ++ DBusMessageIter iter; ++ const char *introspection_xml; ++ NodeInfo *root; ++ GSList *nodes; ++ GSList *l; ++ ++ if (cur == NULL) ++ cur = "/"; ++ ++ message = dbus_message_new_method_call (service_name, ++ cur, ++ DBUS_INTERFACE_INTROSPECTABLE, ++ "Introspect"); ++ dbus_error_init (&error); ++ reply = dbus_connection_send_with_reply_and_block (connection, ++ message, ++ -1, ++ &error); ++ dbus_message_unref (message); ++ dbus_message_iter_init (reply, &iter); ++ dbus_message_iter_get_basic (&iter, &introspection_xml); ++ ++ root = description_load_from_string (introspection_xml, strlen (introspection_xml), NULL); ++ nodes = node_info_get_nodes (root); ++ ++ if (g_slist_length (node_info_get_interfaces (root)) > 0) ++ printf ("%s \n", cur); ++ ++ for (l = nodes; l != NULL; l = l->next) ++ { ++ NodeInfo *node = (NodeInfo *) l->data; ++ const char *name; ++ char *new_path; ++ ++ name = node_info_get_name (node); ++ if (strcmp (cur, "/") == 0) ++ new_path = g_strdup_printf ("/%s", name); ++ else ++ new_path = g_strdup_printf ("%s/%s", cur, name); ++ ++ print_objects (connection, service_name, new_path); ++ ++ g_free (new_path); ++ } ++ node_info_unref (root); ++ ++ dbus_message_unref (reply); ++} ++ ++static gboolean ++is_object_path_with_interfaces (DBusConnection *connection, const char *service_name, const char *object_path) ++{ ++ DBusMessage *message; ++ DBusMessage *reply; ++ DBusError error; ++ DBusMessageIter iter; ++ const char *introspection_xml; ++ NodeInfo *root; ++ gboolean ret; ++ ++ ret = FALSE; ++ ++ message = dbus_message_new_method_call (service_name, ++ object_path, ++ DBUS_INTERFACE_INTROSPECTABLE, ++ "Introspect"); ++ dbus_error_init (&error); ++ reply = dbus_connection_send_with_reply_and_block (connection, ++ message, ++ -1, ++ &error); ++ dbus_message_unref (message); ++ dbus_message_iter_init (reply, &iter); ++ dbus_message_iter_get_basic (&iter, &introspection_xml); ++ ++ root = description_load_from_string (introspection_xml, strlen (introspection_xml), NULL); ++ ++ if (g_slist_length (node_info_get_interfaces (root)) > 0) ++ ret = TRUE; ++ ++ node_info_unref (root); ++ dbus_message_unref (reply); ++ ++ return ret; ++} ++ ++static void ++print_methods (DBusConnection *connection, const char *service_name, const char *object_path) ++{ ++ DBusMessage *message; ++ DBusMessage *reply; ++ DBusError error; ++ DBusMessageIter iter; ++ const char *introspection_xml; ++ NodeInfo *root; ++ GSList *interfaces; ++ GSList *l; ++ ++ message = dbus_message_new_method_call (service_name, ++ object_path, ++ DBUS_INTERFACE_INTROSPECTABLE, ++ "Introspect"); ++ dbus_error_init (&error); ++ reply = dbus_connection_send_with_reply_and_block (connection, ++ message, ++ -1, ++ &error); ++ dbus_message_unref (message); ++ dbus_message_iter_init (reply, &iter); ++ dbus_message_iter_get_basic (&iter, &introspection_xml); ++ ++ root = description_load_from_string (introspection_xml, strlen (introspection_xml), NULL); ++ interfaces = node_info_get_interfaces (root); ++ for (l = interfaces; l != NULL; l = l->next) ++ { ++ InterfaceInfo *interface = (InterfaceInfo *) l->data; ++ GSList *methods; ++ GSList *ll; ++ methods = interface_info_get_methods (interface); ++ for (ll = methods; ll != NULL; ll = ll->next) ++ { ++ MethodInfo *method = (MethodInfo *) ll->data; ++ printf ("%s.%s \n", interface_info_get_name (interface), method_info_get_name (method)); ++ } ++ } ++ node_info_unref (root); ++ dbus_message_unref (reply); ++} ++ ++static void ++print_signature (DBusConnection *connection, const char *service_name, const char *object_path, const char *method) ++{ ++ DBusMessage *message; ++ DBusMessage *reply; ++ DBusError error; ++ DBusMessageIter iter; ++ const char *introspection_xml; ++ NodeInfo *root; ++ GSList *interfaces; ++ GSList *l; ++ char *s; ++ char *method_name; ++ char *interface_name; ++ int n; ++ ++ method_name = NULL; ++ interface_name = NULL; ++ ++ s = strrchr (method, '.'); ++ if (s == NULL || strlen (s) < 2 || s - method < 1) ++ goto fail; ++ method_name = g_strdup (s + 1); ++ interface_name = g_strndup (method, s - method); ++ printf (" \n"); ++ ++ message = dbus_message_new_method_call (service_name, ++ object_path, ++ DBUS_INTERFACE_INTROSPECTABLE, ++ "Introspect"); ++ dbus_error_init (&error); ++ reply = dbus_connection_send_with_reply_and_block (connection, ++ message, ++ -1, ++ &error); ++ dbus_message_unref (message); ++ dbus_message_iter_init (reply, &iter); ++ dbus_message_iter_get_basic (&iter, &introspection_xml); ++ ++ root = description_load_from_string (introspection_xml, strlen (introspection_xml), NULL); ++ interfaces = node_info_get_interfaces (root); ++ for (l = interfaces; l != NULL; l = l->next) ++ { ++ InterfaceInfo *interface = (InterfaceInfo *) l->data; ++ ++ if (strcmp (interface_name, interface_info_get_name (interface)) == 0) ++ { ++ GSList *methods; ++ GSList *ll; ++ methods = interface_info_get_methods (interface); ++ for (ll = methods; ll != NULL; ll = ll->next) ++ { ++ MethodInfo *method = (MethodInfo *) ll->data; ++ if (strcmp (method_name, method_info_get_name (method)) == 0) ++ { ++ GSList *args; ++ GSList *lll; ++ args = method_info_get_args (method); ++ for (lll = args, n = 0; lll != NULL; lll = lll->next, n++) ++ { ++ ArgInfo *arg = (ArgInfo *) lll->data; ++ printf ("# %s: arg %d: %s (%s) \n", ++ arg_info_get_direction (arg) == ARG_IN ? " IN" : "OUT", ++ n, ++ arg_info_get_name (arg), ++ arg_info_get_type (arg)); ++ } ++ break; ++ } ++ } ++ } ++ } ++ node_info_unref (root); ++ dbus_message_unref (reply); ++ fail: ++ g_free (method_name); ++ g_free (interface_name); ++} ++ ++ ++static int ++complete_dbus_send (char *str) ++{ ++ int ret; ++ char **tokens; ++ int num_tokens; ++ const char *cur; ++ const char *prev; ++ gboolean have_system; ++ gboolean have_session; ++ gboolean have_print_reply; ++ gboolean have_dest; ++ DBusConnection *connection; ++ DBusBusType bus_type; ++ DBusError error; ++ const char *target_service; ++ const char *object_path; ++ const char *method; ++ int n; ++ int object_path_index; ++ ++ ret = 1; ++ connection = NULL; ++ target_service = NULL; ++ ++ tokens = g_strsplit (str, " ", 0); ++ num_tokens = g_strv_length (tokens); ++ if (num_tokens >= 2) { ++ cur = tokens[num_tokens - 1]; ++ prev = tokens[num_tokens - 2]; ++ } else if (num_tokens == 1) { ++ cur = tokens[num_tokens - 1]; ++ prev = ""; ++ } else { ++ cur = ""; ++ prev = ""; ++ } ++ ++ have_system = have_option (tokens, "--system"); ++ have_session = have_option (tokens, "--session"); ++ have_print_reply = have_option (tokens, "--print-reply"); ++ have_dest = have_option_with_value (tokens, "--dest=", &target_service); ++ ++ if (!have_print_reply) ++ printf ("--print-reply \n"); ++ ++ if (!have_system && !have_session) ++ { ++ printf ("--system \n"); ++ printf ("--session \n"); ++ goto done; ++ } ++ ++ if (!have_dest && !g_str_has_prefix (cur, "--dest=")) ++ { ++ printf ("--dest=\n"); ++ goto done; ++ } ++ ++ if (have_system || have_session) ++ { ++ bus_type = have_system ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION; ++ ++ dbus_error_init (&error); ++ connection = dbus_bus_get (bus_type, &error); ++ if (connection == NULL) ++ { ++ fprintf (stderr, "Failed to open connection to %s message bus: %s: %s\n", ++ (bus_type == DBUS_BUS_SYSTEM) ? "system" : "session", ++ error.name, error.message); ++ dbus_error_free (&error); ++ goto fail; ++ } ++ } ++ ++ if (connection != NULL && g_str_has_prefix (cur, "--dest=")) ++ { ++ print_services (connection); ++ goto done; ++ } ++ ++ /* see if we have an object path */ ++ object_path = NULL; ++ object_path_index = 0; ++ if (connection != NULL && target_service != NULL) ++ { ++ for (n = 0; tokens[n] != NULL; n++) ++ { ++ if (tokens[n] == cur) ++ continue; ++ ++ if (*(tokens[n]) == '/') ++ { ++ if (is_object_path_with_interfaces (connection, target_service, tokens[n])) ++ { ++ object_path = tokens[n]; ++ object_path_index = n; ++ } ++ } ++ } ++ } ++ ++ /* if we have a connection and a destination but no object path, go ahead and list the object paths */ ++ if (connection != NULL && target_service != NULL && object_path == NULL) ++ { ++ print_objects (connection, target_service, NULL); ++ goto done; ++ } ++ ++ /* see if we have a method; it's directly after the object_path */ ++ method = NULL; ++ if (connection != NULL && target_service != NULL && object_path != NULL) ++ { ++ if ((object_path_index + 1 < num_tokens - 1) && ++ (strlen (tokens[object_path_index + 1]) > 0) && ++ !(strcmp (cur, tokens[object_path_index + 1]) == 0)) ++ method = tokens[object_path_index + 1]; ++ } ++ ++ /* if we have connection, destination and object path but no method yet, list the methods */ ++ if (connection != NULL && target_service != NULL && object_path != NULL && method == NULL) ++ { ++ print_methods (connection, target_service, object_path); ++ goto done; ++ } ++ ++ /* print signature as comment */ ++ if (connection != NULL && target_service != NULL && object_path != NULL && method != NULL) ++ { ++ print_signature (connection, target_service, object_path, method); ++ } ++ ++ done: ++ ret = 0; ++ ++ fail: ++ ++ g_strfreev (tokens); ++ ++ if (connection != NULL) ++ dbus_connection_unref (connection); ++ return ret; ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ int ret; ++ char *cur; ++ gboolean dbus_send; ++ ++ ret = 1; ++ dbus_send = FALSE; ++ ++ if (argc != 3) ++ { ++ fprintf (stderr, "invalid use\n"); ++ goto out; ++ } ++ ++ if (strcmp (argv[1], "dbus-send") == 0) ++ { ++ dbus_send = TRUE; ++ } ++ else ++ { ++ fprintf (stderr, "unknown program '%s'\n", argv[1]); ++ goto out; ++ } ++ ++ if (strlen (argv[2]) < strlen (argv[1]) + 1) ++ { ++ fprintf (stderr, "error"); ++ goto out; ++ } ++ ++ cur = argv[2] + strlen (argv[1]) + 1; ++ ++ if (dbus_send) ++ ret = complete_dbus_send (cur); ++ ++ out: ++ return ret; ++} +diff --git a/dbus/dbus-bash-completion.sh.in b/dbus/dbus-bash-completion.sh.in +new file mode 100644 +index 0000000..a7751da +--- /dev/null ++++ b/dbus/dbus-bash-completion.sh.in +@@ -0,0 +1,21 @@ ++ ++# Check for bash ++[ -z "$BASH_VERSION" ] && return ++ ++################################################################################ ++ ++__dbus_send() { ++ local IFS=$'\n' ++ local cur="${COMP_WORDS[COMP_CWORD]}" ++ ++ # --name=value style option ++ if [[ "$cur" == *=* ]] ; then ++ cur=${cur/*=/} ++ fi ++ ++ COMPREPLY=($(compgen -W "$(@libexecdir@/dbus-bash-completion-helper dbus-send ${COMP_WORDS[@]:0})" -- $cur)) ++} ++ ++################################################################################ ++ ++complete -o nospace -F __dbus_send dbus-send +-- +1.5.6.4 + diff --git a/dbus-glib.spec b/dbus-glib.spec index 3a533a5..fe02b27 100644 --- a/dbus-glib.spec +++ b/dbus-glib.spec @@ -8,7 +8,7 @@ Summary: GLib bindings for D-Bus Name: dbus-glib Version: 0.76 -Release: 1%{?dist} +Release: 2%{?dist} URL: http://www.freedesktop.org/software/dbus/ Source0: http://dbus.freedesktop.org/releases/dbus-glib/%{name}-%{version}.tar.gz Source1: dbus-bus-introspect.xml @@ -26,6 +26,10 @@ BuildRequires: glib2-devel >= %{glib2_version} BuildRequires: gettext BuildRequires: autoconf +# TODO +Patch10: dbus-glib-0.77-bash-completion.patch +# this patch requires autoreconf +BuildRequires: autoconf automake libtool gettext-devel gtk-doc %description @@ -61,9 +65,10 @@ D-Bus tools written using the gtk+ GUI libaries %setup -q %patch7 -p1 -b .getall-wincaps-to-uscore +%patch10 -p1 -b .bash-completion %build - +autoreconf %configure --disable-tests \ --enable-verbose-mode=yes \ --enable-asserts=yes \ @@ -83,6 +88,8 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.a rm -f $RPM_BUILD_ROOT%{_libdir}/*.la +chmod 644 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/dbus-bash-completion.sh + %clean rm -rf %{buildroot} @@ -106,6 +113,8 @@ rm -rf %{buildroot} %{_libdir}/pkgconfig/dbus-glib-1.pc %{_includedir}/* %{_datadir}/gtk-doc/html/dbus-glib +%{_sysconfdir}/profile.d/dbus-bash-completion.sh +%{_libexecdir}/dbus-bash-completion-helper %if 0 %files gtk @@ -116,6 +125,9 @@ rm -rf %{buildroot} %endif %changelog +* Thu Jul 31 2008 David Zeuthen - 0.76-2 +- Add bash completion for dbus-send(1) + * Thu Jun 05 2008 Colin Walters - 0.76-1 - New upstream 0.76 - Drop all upstreamed patches