pass error messages into environment, None's are empty strings
[dbuscron] / dbuscron / command.py
index 776d474..e25c5f6 100644 (file)
@@ -1,3 +1,4 @@
+# encoding: utf-8
 
 import os
 from dbuscron.bus import get_dbus_message_type, dbus_to_str
@@ -13,26 +14,53 @@ class Command(object):
         else:
             self.__args = cmd.split(' ')
             self.__file = self.__args[0]
+            if len(self.__args) == 1 \
+                and self.__file.startswith('!'):
+                self.__file = self.__file.lstrip('!')
+                self.__auto_args = True
+            else:
+                self.__auto_args = False
 
     def __call__(self, bus, message, environ):
-        args_list = message.get_args_list()
+        args_list = map(dbus_to_str, message.get_args_list())
         env = dict()
         env.update(environ)
-        dbus_env = dict(
-                (('DBUS_ARG%d' % i, dbus_to_str(a)) for i, a in enumerate(args_list)),
-                DBUS_ARGN   = str(len(args_list)),
-                DBUS_SENDER = str(message.get_sender()),
-                DBUS_DEST   = str(message.get_destination()),
-                DBUS_IFACE  = str(message.get_interface()),
-                DBUS_PATH   = str(message.get_path()),
-                DBUS_MEMBER = str(message.get_member()),
-                DBUS_BUS    = bus.__class__.__name__.lower()[0:-3],
-                DBUS_TYPE   = get_dbus_message_type(message)
-                )
-        env.update(dbus_env)
-        result = os.spawnvpe(os.P_WAIT, self.__file, self.__args, env)
+        try:
+            dbus_env = dict(
+                    (('DBUS_ARG%d' % i, a) for i, a in enumerate(args_list)),
+                    DBUS_ARGN   = str(len(args_list)),
+                    DBUS_SENDER = str(message.get_sender() or ''),
+                    DBUS_DEST   = str(message.get_destination() or ''),
+                    DBUS_IFACE  = str(message.get_interface() or ''),
+                    DBUS_PATH   = str(message.get_path() or ''),
+                    DBUS_MEMBER = str(message.get_member() or ''),
+                    DBUS_BUS    = bus.__class__.__name__.lower()[0:-3],
+                    DBUS_ERROR  = str(message.get_error_name() or ''),
+                    DBUS_TYPE   = get_dbus_message_type(message)
+                    )
+            env.update(dbus_env)
+        except Exception, e:
+            log.error('environ exception', e)
+            raise e
+
+        if self.__auto_args:
+            if dbus_env['DBUS_TYPE'] in ('signal', 'method_call'):
+                args_list[0:0] = [
+                    dbus_env['DBUS_IFACE'],
+                    dbus_env['DBUS_MEMBER']]
+            elif dbus_env['DBUS_TYPE'] == 'error':
+               args_list.insert(0, dbus_env['DBUS_ERROR'])
+
+            args_list[0:0] = [
+                    self.__file,
+                    dbus_env['DBUS_SENDER'],
+                    dbus_env['DBUS_DEST']]
+        else:
+            args_list = self.__args
+
+        result = os.spawnvpe(os.P_WAIT, self.__file, args_list, env)
         if result != 0:
-            log.warn('run', self.__file, self.__args, dbus_env, result)
+            log.warn('command returned non-zero status', self.__file, args_list, dbus_env, result)
         return result
 
     @property
@@ -66,10 +94,13 @@ class Commands(object):
     def handler(self, bus, message):
         for rule, command in self.__commands.iteritems():
             if rule.match(bus, message):
-                log.info('matched %s %s' % (rule, command))
+                log('rule matched', rule, command)
                 command(bus, message, self.__environ)
                 return
 
     def add(self, matcher, command):
         self.__commands[matcher] = command
 
+    def clear(self):
+        self.__commands = {}
+