[conduit] Port from HAL to GUDEV



commit da3e1dba45fd722aed0bad2f9c9921f404d883c0
Author: John Stowers <john stowers gmail com>
Date:   Tue Feb 9 00:49:21 2010 +0100

    Port from HAL to GUDEV

 conduit/dataproviders/DataProvider.py       |   12 ++
 conduit/dataproviders/HalFactory.py         |  104 ++++++++++--------
 conduit/dataproviders/MediaPlayerFactory.py |   66 +++++++++++
 conduit/dataproviders/SimpleFactory.py      |    2 +
 conduit/dataproviders/VolumeFactory.py      |   58 ----------
 conduit/modules/N800Module/N800Module.py    |    2 +-
 conduit/modules/iPodModule/iPodModule.py    |  161 ++++++++++++++++++++++-----
 conduit/utils/Singleton.py                  |    8 +-
 conduit/utils/UDev.py                       |   13 ++
 conduit/utils/__init__.py                   |   13 ++
 configure.ac                                |    1 +
 setup-env.sh                                |    1 +
 12 files changed, 302 insertions(+), 139 deletions(-)
---
diff --git a/conduit/dataproviders/DataProvider.py b/conduit/dataproviders/DataProvider.py
index 839b6e4..5fbb95f 100644
--- a/conduit/dataproviders/DataProvider.py
+++ b/conduit/dataproviders/DataProvider.py
@@ -568,6 +568,11 @@ class DataProviderFactory(gobject.GObject):
         gobject.GObject.__init__(self)
 
     def emit_added(self, klass, initargs, category, customKey=None):
+        """
+        Emits the dataprovider-added signal for the given class with the
+        given conctruction arguments
+        """
+        print "emit_added",klass,initargs,category,customKey
         dpw = ModuleWrapper.ModuleWrapper(   
                     klass=klass,
                     initargs=initargs,
@@ -580,10 +585,17 @@ class DataProviderFactory(gobject.GObject):
         return key
 
     def emit_removed(self, key):
+        """
+        Emits the dataprovider-removed signal
+        """
         log.debug("DataProviderFactory %s: Emitting dataprovider-removed for %s" % (self, key))
         self.emit("dataprovider-removed", key)
 
     def probe(self):
+        """
+        Search for appropriate connected devices, calling emit_added or
+        emit_removed for each device
+        """
         pass
 
     def quit(self):
diff --git a/conduit/dataproviders/HalFactory.py b/conduit/dataproviders/HalFactory.py
index 16fe4fe..2801ea4 100644
--- a/conduit/dataproviders/HalFactory.py
+++ b/conduit/dataproviders/HalFactory.py
@@ -1,62 +1,74 @@
 import gobject
-import dbus
+import gudev
+import gio
 
 import logging
 log = logging.getLogger("dataproviders.HalFactory")
 
 import conduit.utils as Utils
+import conduit.utils.UDev as UDev
 import conduit.dataproviders.SimpleFactory as SimpleFactory
 
+log.info("Module Information: %s" % Utils.get_module_information(gudev, "__version__"))
+
 class HalFactory(SimpleFactory.SimpleFactory):
 
+    SUBSYSTEMS = ("usb", "block")
+
     def __init__(self, **kwargs):
         SimpleFactory.SimpleFactory.__init__(self, **kwargs)
 
-        # Connect to system HAL
-        self.bus = dbus.SystemBus()
-        self.hal_obj = self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager")
-        self.hal = dbus.Interface(self.hal_obj, "org.freedesktop.Hal.Manager")
-
-        # Hookup signals
-        self.hal.connect_to_signal("DeviceAdded", self._device_added)
-        self.hal.connect_to_signal("DeviceRemoved", self._device_removed)
-        self.hal.connect_to_signal("NewCapability", self._new_capability)
-
-    def _maybe_new(self, device_udi):
-        props = self._get_properties(device_udi)
-        if self.is_interesting(device_udi, props):
-            self.item_added(device_udi, **props)
-
-    def _device_added(self, device_udi, *args):
-        self._maybe_new(device_udi)
-
-    def _new_capability(self, device_udi, *args):
-        if not device_udi in self.items.keys():
-            self._maybe_new(device_udi)
-
-    def _device_removed(self, device_udi):
-        self.item_removed(device_udi)
-
-    def _get_properties(self, device):
-        buf = {}
-        try:
-            device_dbus_obj = self.bus.get_object("org.freedesktop.Hal" ,device)
-            for x, y in device_dbus_obj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device").items():
-                #DBus *still* does not marshal dbus.String to str correctly,
-                #so we force it to
-                buf[str(x)] = y
-        except:
-            log.warn("Could not get HAL properties for %s" % device)
-        return buf
+        assert hasattr(self.SUBSYSTEMS, "__iter__")
+
+        self.gudev = UDev.UDevSingleton(self.SUBSYSTEMS)
+        self.gudev.connect("uevent", self._on_uevent)
+        self.vm = gio.volume_monitor_get()
+
+    def _print_device(self, device):
+        print "subsystem", device.get_subsystem()
+        print "devtype", device.get_devtype()
+        print "name", device.get_name()
+        print "number", device.get_number()
+        print "sysfs_path:", device.get_sysfs_path()
+        print "driver:", device.get_driver()
+        print "action:", device.get_action()
+        print "seqnum:", device.get_seqnum()
+        print "device type:", device.get_device_type()
+        print "device number:", device.get_device_number()
+        print "device file:", device.get_device_file()
+        print "device file symlinks:", ", ".join(device.get_device_file_symlinks())
+        print "device keys:", ", ".join(device.get_property_keys())
+        for device_key in device.get_property_keys():
+            print "   device property %s: %s"  % (device_key, device.get_property(device_key))
+
+    def _on_uevent(self, client, action, device):
+        self._print_device(device)
+        if action == "add":
+            self._maybe_new(device)
+        elif action == "remove":
+            sysfs_path = self.get_sysfs_path_for_device(device)
+            self.item_removed(sysfs_path)
+
+    def _get_device_properties(self, device):
+        props = {}
+        for key in device.get_property_keys():
+            props[key.upper()] = device.get_property(key)
+        return props
+
+    def _maybe_new(self, device):
+        props = self._get_device_properties(device)
+        sysfs_path = self.get_sysfs_path_for_device(device)
+        if self.is_interesting(sysfs_path, props):
+            self.item_added(sysfs_path, **props)
+
+    def get_udev_device_for_sysfs_path(self, sysfs_path):
+        return self.gudev.query_by_sysfs_path(sysfs_path)
+
+    def get_sysfs_path_for_device(self, device):
+        return device.get_sysfs_path()
 
     def probe(self):
-        """
-        Enumerate HAL for any entries of interest
-        """
-        devices = self.hal.GetAllDevices()
-        for device in self.hal.GetAllDevices():
-            self._maybe_new(str(device))
-
-    def get_args(self, udi, **kwargs):
-        return (udi,)
+        for s in self.SUBSYSTEMS:
+            for d in self.gudev.query_by_subsystem(s):
+                self._maybe_new(d)
 
diff --git a/conduit/dataproviders/MediaPlayerFactory.py b/conduit/dataproviders/MediaPlayerFactory.py
new file mode 100644
index 0000000..3273caa
--- /dev/null
+++ b/conduit/dataproviders/MediaPlayerFactory.py
@@ -0,0 +1,66 @@
+import os.path
+import ConfigParser
+import logging
+log = logging.getLogger("dataproviders.MediaPlayerFactory")
+
+import conduit.utils as Utils
+import conduit.dataproviders.HalFactory as HalFactory
+
+class MediaPlayerFactory(HalFactory.HalFactory):
+
+    #keys to interrogate according to the media-player-info spec
+    #                      section,  key name,         store as property
+    MPI_ACCESS_PROTOCOL = ("Device", "AccessProtocol", "MPI_ACCESS_PROTOCOL")
+    MPI_ICON            = ("Device", "Icon",           "MPI_ICON")
+    MPI_KEYS = (MPI_ACCESS_PROTOCOL, MPI_ICON)
+
+    def __init__(self, *args, **kwargs):
+        HalFactory.HalFactory.__init__(self, *args, **kwargs)
+
+    #taken from quodlibet
+    def __get_mpi_dir(self):
+        for d in Utils.get_system_data_dirs():
+            path = os.path.join(d, "media-player-info")
+            if os.path.isdir(path):
+                return path
+
+    #taken from quodlibet
+    def __get_mpi_file(self, mplayer_id):
+        """
+        Returns a SafeConfigParser instance of the mpi file or None.
+        MPI files are INI like files usually located in
+        /usr/local/media-player-info/*.mpi
+        """
+        f = os.path.join( self.__get_mpi_dir() , mplayer_id + ".mpi")
+        if os.path.isfile(f):
+            parser = ConfigParser.SafeConfigParser()
+            read = parser.read(f)
+            if read: return parser
+
+    def _maybe_new(self, device):
+        props = self._get_device_properties(device)
+        sysfs_path = self.get_sysfs_path_for_device(device)
+        try:
+            mplayer_id = props["ID_MEDIA_PLAYER"]
+
+            #taken from quodlibet
+            config = self.__get_mpi_file(mplayer_id)
+            if config is not None:
+                for (section_name, key_name, prop_name) in self.MPI_KEYS:
+                    try:
+                        props[prop_name] = config.get(section_name, key_name)
+                    except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+                        pass
+
+            if self.is_interesting(sysfs_path, props):
+                self.item_added(sysfs_path, **props)
+
+        except KeyError:
+            log.debug("Device not media player")
+
+    def get_mpi_access_protocol(self, props):
+        return props.get(self.MPI_ACCESS_PROTOCOL[2], "")
+
+    def get_mpi_icon(self, props, fallback="media-player"):
+        return props.get(self.MPI_ICON[2], fallback)
+
diff --git a/conduit/dataproviders/SimpleFactory.py b/conduit/dataproviders/SimpleFactory.py
index c5573a9..d504dd3 100644
--- a/conduit/dataproviders/SimpleFactory.py
+++ b/conduit/dataproviders/SimpleFactory.py
@@ -20,7 +20,9 @@ class SimpleFactory(DataProvider.DataProviderFactory):
         idxs = []
         for klass in self.get_dataproviders(key, **kwargs):
             args = self.get_args(key, **kwargs)
+            print "emit_added"
             idx = self.emit_added(klass, args, cat)
+            print "emmitted"
             idxs.append(idx)
         self.items[key] = idxs
 
diff --git a/conduit/modules/N800Module/N800Module.py b/conduit/modules/N800Module/N800Module.py
index 036dc6b..0b3cd7e 100644
--- a/conduit/modules/N800Module/N800Module.py
+++ b/conduit/modules/N800Module/N800Module.py
@@ -23,7 +23,7 @@ import conduit.vfs as Vfs
 from gettext import gettext as _
 
 MODULES = {
-    "N800Factory" : { "type": "dataprovider-factory" },
+#    "N800Factory" : { "type": "dataprovider-factory" },
 }
 
 
diff --git a/conduit/modules/iPodModule/iPodModule.py b/conduit/modules/iPodModule/iPodModule.py
index 48dcc3b..f41e83d 100644
--- a/conduit/modules/iPodModule/iPodModule.py
+++ b/conduit/modules/iPodModule/iPodModule.py
@@ -10,6 +10,7 @@ order to listen to HAL events
 Copyright: John Stowers, 2006
 License: GPLv2
 """
+import sys
 import os
 import pickle
 import logging
@@ -24,7 +25,8 @@ log = logging.getLogger("modules.iPod")
 import conduit
 import conduit.dataproviders.DataProvider as DataProvider
 import conduit.dataproviders.DataProviderCategory as DataProviderCategory
-import conduit.dataproviders.VolumeFactory as VolumeFactory
+import conduit.dataproviders.MediaPlayerFactory as MediaPlayerFactory
+import conduit.dataproviders.HalFactory as HalFactory
 import conduit.utils as Utils
 import conduit.datatypes.Note as Note
 import conduit.datatypes.Contact as Contact
@@ -38,9 +40,10 @@ from gettext import gettext as _
 errormsg = ""
 try:
     import gpod
-    if gpod.version_info >= (0,6,0):
+    if gpod.version_info >= (0,7,0):
         MODULES = {
             "iPodFactory" :         { "type":   "dataprovider-factory"  },
+            "iPhoneFactory" :       { "type":   "dataprovider-factory"  },
         }
         log.info("Module Information: %s" % Utils.get_module_information(gpod, 'version_info'))
 except ImportError:
@@ -48,6 +51,10 @@ except ImportError:
 except locale.Error:
     errormsg = "iPod support disabled (Incorrect locale)"
 
+PROPS_KEY_MOUNT = "CONDUIT_MOUNTPOINT"
+PROPS_KEY_NAME  = "CONDUIT_NAME"
+PROPS_KEY_ICON  = "CONDUIT_ICON"
+
 if errormsg:
     MODULES = {}
     log.warn(errormsg)
@@ -66,33 +73,104 @@ def _string_to_unqiue_file(txt, base_uri, prefix, postfix=''):
     temp.set_UID(os.path.basename(uri))
     return temp.get_rid()
 
-class iPodFactory(VolumeFactory.VolumeFactory):
+def _supports_photos(db):
+    if isinstance(p, gpod.PhotoDatabase) or isinstance(m, gpod.Database):
+        return gpod.itdb_device_supports_photo(db._itdb.device)
+    else:
+        log.critical("could not determine if device supports photos")
+        return False
 
-    def _get_mount_path(self, props):
-        return str(props["volume.mount_point"])
+def _get_apple_label(props):
+    return props.get(PROPS_KEY_NAME,
+            "Apple " + props.get("ID_MODEL", "Device"))
+
+def _get_apple_icon(props):
+    return props.get(PROPS_KEY_ICON, "multimedia-player-apple-ipod")
+
+class iPhoneFactory(HalFactory.HalFactory):
+
+    def is_interesting(self, sysfs_path, props):
+        #there is no media-player-info support for the apple iphone, so instead 
+        #we have to look for the correct model name instead.
+        if "Apple" in props.get("ID_VENDOR", "") and "iPhone" in props.get("ID_MODEL", ""):
+            #also have to check the iPhone has a valid serial, as that is used
+            #with gvfs to generate the uuid of the moint
+            self._print_device(self.get_udev_device_for_sysfs_path(sysfs_path))
+            if props.get("ID_SERIAL_SHORT"):
+                uuid = "afc://%s/" % props["ID_SERIAL_SHORT"]
+                for m in self.vm.get_mounts():
+                    root = m.get_root()
+                    uri = root.get_uri()
+                    if uuid == uri:
+                        #check that gvfs has mounted the volume at the expected location
+                        #FIXME: this is not very nice, as it depends on an implementation
+                        #detail of gvfs-afc backend. It would be best if there was some UUID
+                        #that was present in udev and guarenteed to be present in all gio mounts
+                        #but experimentation tells me there is no such uuid, it returns None
+                        props[PROPS_KEY_MOUNT] = root.get_path()
+                        props[PROPS_KEY_NAME]  = m.get_name()
+                        props[PROPS_KEY_ICON]  = "phone"
+                        return True
+                log.warning("iPhone not mounted by gvfs")
+            else:
+                log.critical("iPhone missing ID_SERIAL_SHORT udev property")
+        return False
 
-    def is_interesting(self, udi, props):
-        if props.get("info.parent"):
-            parent = self._get_properties(props["info.parent"])
-            if parent.get("storage.model") == "iPod":
-                props.update(parent)
-                return True
+    def get_category(self, key, **props):
+        """ Return a category to contain these dataproviders """
+        print "get_category", props.get(PROPS_KEY_MOUNT)
+        return DataProviderCategory.DataProviderCategory(
+                    _get_apple_label(props),
+                    _get_apple_icon(props),
+                    key)
+    
+    def get_dataproviders(self, key, **props):
+        """ Return a list of dataproviders for this class of device """
+        print "get_dataproviders", props.get(PROPS_KEY_MOUNT)
+        return [IPodDummy, IPodPhotoSink]
+
+    def get_args(self, key, **props):
+        print "get_args", props.get(PROPS_KEY_MOUNT)
+        return (props[PROPS_KEY_MOUNT], key)
+
+class iPodFactory(MediaPlayerFactory.MediaPlayerFactory):
+
+    def is_interesting(self, sysfs_path, props):
+        #just like rhythmbox, we let media-player-info do the matching, and
+        #instead just check if it has told us that the media player uses the
+        #ipod storage protocol
+        access_protocols = self.get_mpi_access_protocol(props)
+        if "ipod" in access_protocols.split(";"):
+            uuid = props.get("ID_FS_UUID")
+            for vol in self.vm.get_volumes():
+                #is this the disk corresponding to the ipod
+                #FIXME: we should be able to do gio.VolumeMonitor.get_volume_for_uuid()
+                #but that doesnt work
+                if vol.get_identifier('uuid') == uuid:
+                    #now check it is mounted
+                    mount = vol.get_mount()
+                    if mount:
+                        f = mount.get_root()
+                        props[PROPS_KEY_MOUNT] = f.get_path()
+                        props[PROPS_KEY_NAME]  = "%s's %s" % (mount.get_name(), props.get("ID_MODEL", "iPod"))
+                        props[PROPS_KEY_ICON]  = self.get_mpi_icon(props, fallback="multimedia-player-apple-ipod")
+                        return True
+                    else:
+                        log.warn("ipod not mounted")
+            log.warn("could not find volume with udev ID_FS_UUID: %s" % uuid)
         return False
 
-    def get_category(self, udi, **kwargs):
-        label = kwargs['volume.label']
-        if not label:
-            label = "Apple iPod Music Player"
+    def get_category(self, key, **props):
         return DataProviderCategory.DataProviderCategory(
-                    label,
-                    "multimedia-player-ipod-standard-color",
-                    self._get_mount_path(kwargs))
+                    _get_apple_label(props),
+                    _get_apple_icon(props),
+                    key)
 
-    def get_dataproviders(self, udi, **kwargs):
+    def get_dataproviders(self, udi, **props):
         #Read information about the ipod, like if it supports
         #photos or not
         d = gpod.itdb_device_new()
-        gpod.itdb_device_set_mountpoint(d,self._get_mount_path(kwargs))
+        gpod.itdb_device_set_mountpoint(d, props[PROPS_KEY_MOUNT])
         supportsPhotos = gpod.itdb_device_supports_photo(d)
         gpod.itdb_device_free(d)
         if supportsPhotos:
@@ -101,12 +179,24 @@ class iPodFactory(VolumeFactory.VolumeFactory):
             log.info("iPod does not report photo support")
             return [IPodMusicTwoWay, IPodVideoTwoWay, IPodNoteTwoWay, IPodContactsTwoWay, IPodCalendarTwoWay]
 
-    def get_args(self, udi, **kwargs):
-        """
-        iPod needs a local path to the DB, not a URI
-        """
-        kwargs["mount_path"] = self._get_mount_path(kwargs)
-        return (kwargs['mount_path'], udi)
+    def get_args(self, key, **props):
+        return (props[PROPS_KEY_MOUNT], key)
+
+class IPodDummy(DataProvider.TwoWay):
+
+    _name_ = "Dummy"
+    _description_ = "Dummy iPod"
+    _module_type_ = "twoway"
+    _in_type_ = "file"
+    _out_type_ = "file"
+
+    def __init__(self, *args):
+        DataProvider.TwoWay.__init__(self)
+        print "CONSTRUCTED ", args
+        self.args = args or "q"
+
+    def get_UID(self):
+        print "-----".join(self.args)
 
 class IPodBase(DataProvider.TwoWay):
     def __init__(self, *args):
@@ -383,6 +473,7 @@ class IPodPhotoSink(IPodBase):
         )
 
     def _set_sysinfo(self, modelnumstr, model):
+        #this must only be used from TestDataProvideriPod.py
         gpod.itdb_device_set_sysinfo(self.db._itdb.device, modelnumstr, model)
 
     def _get_photo_album(self, albumName):
@@ -419,9 +510,13 @@ class IPodPhotoSink(IPodBase):
                         album.remove(photo)
                     self.db.remove(album)
 
-    def _empty_all_photos(self):
-        for photo in self.db.PhotoAlbums[0][:]:
-            self.db.remove(photo)
+    def _delete_all_photos(self):
+        for album in self.db.PhotoAlbums:
+            for photo in album[:]:
+                album.remove(photo)
+            if album.name != self.SAFE_PHOTO_ALBUM:
+                self.db.remove(album)
+        gpod.itdb_photodb_write(self.db._itdb, None)
 
     def _get_photo_albums(self):
         i = []
@@ -458,13 +553,19 @@ class IPodPhotoSink(IPodBase):
             self._delete_album(album_config.get_value())
             album_config.choices = self._get_photo_albums()
 
+        def _delete_all_click(button):
+            self._delete_all_photos()
+
         album_config = config.add_item(_('Album'), 'combotext',
             config_name = 'albumName',
             choices = self._get_photo_albums(),
         )
         config.add_item(_("Delete"), "button",
             initial_value = _delete_click
-        )    
+        )
+        config.add_item(_("Delete All Photos"), "button",
+            initial_value = _delete_all_click
+        )
 
 
     def is_configured (self, isSource, isTwoWay):
diff --git a/conduit/utils/Singleton.py b/conduit/utils/Singleton.py
index d90e400..d0cf31b 100644
--- a/conduit/utils/Singleton.py
+++ b/conduit/utils/Singleton.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: UTF8 -*-
 #
-#  GObjectSingleton.py
+#  Singleton.py
 #  Copyright (c) 2006 INdT (Instituto Nokia de Tecnologia)
 #  Author: Eduardo de Barros Lima <eduardo lima indt org br>
 #
@@ -22,7 +22,7 @@
 
 import gobject
 
-class GObjectSingleton(gobject.GObjectMeta):
+class _GObjectSingleton(gobject.GObjectMeta):
 
     def __init__(cls, name, base, dict):
         gobject.GObjectMeta.__init__(cls, name, base, dict)
@@ -32,7 +32,7 @@ class GObjectSingleton(gobject.GObjectMeta):
 
     def __call__(cls, *args, **kwargs):
         if not cls.__instance:
-            cls.__instance = super(GObjectSingleton, cls).__call__(*args, **kwargs)
+            cls.__instance = super(_GObjectSingleton, cls).__call__(*args, **kwargs)
         return cls.__instance
 
 class Singleton:
@@ -40,7 +40,7 @@ class Singleton:
     A model that implements the Singleton pattern.
     """
 
-    __metaclass__ = GObjectSingleton
+    __metaclass__ = _GObjectSingleton
 
     pass
 
diff --git a/conduit/utils/UDev.py b/conduit/utils/UDev.py
new file mode 100644
index 0000000..62cb5aa
--- /dev/null
+++ b/conduit/utils/UDev.py
@@ -0,0 +1,13 @@
+import gobject
+import gudev
+
+import logging
+log = logging.getLogger("utils.UDev")
+
+import conduit.utils as Utils
+import conduit.utils.Singleton as Singleton
+
+class UDevSingleton(Singleton.Singleton, gudev.Client):
+    def __init__(self, *args, **kwargs):
+        super(UDevSingleton, self).__init__(*args, **kwargs)
+        log.debug("Constructed: %s" % self)
diff --git a/conduit/utils/__init__.py b/conduit/utils/__init__.py
index 0067620..7f9b7ca 100644
--- a/conduit/utils/__init__.py
+++ b/conduit/utils/__init__.py
@@ -407,3 +407,16 @@ def exec_command_and_return_result(cmd, arg):
     except OSError:
         return None
 
+def get_system_data_dirs():
+    """
+    Returns the system data dirs as specified by the XDG spec. 
+    http://standards.freedesktop.org/basedir-spec/latest/
+
+    This function should be removed once g_get_system_data_dirs () is wrapped
+    """
+    data_dirs = os.getenv("XDG_DATA_DIRS")
+    if data_dirs:
+        return data_dirs.split(":")
+    else:
+        return ("/usr/local/share/", "/usr/share/")
+
diff --git a/configure.ac b/configure.ac
index f4bec4d..a86a5e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,6 +47,7 @@ AM_CHECK_PYMOD([dateutil], , , AC_MSG_ERROR([Python module dateutil required to
 AM_CHECK_PYMOD_VERSION([goocanvas], [pygoocanvas_version], [0.9.0], , AC_MSG_ERROR([Python module goocanvas >= 0.9.0 required to run Conduit]))
 AM_CHECK_PYMOD_VERSION([dbus], [__version__], [0.80.0], , AC_MSG_ERROR([Python module dbus >= 0.80.0 required to run Conduit]))
 AM_CHECK_PYMOD_VERSION([gio], [pygio_version], [2.16.1], , AC_MSG_ERROR([Python module gio >= 2.16.1 required to run Conduit]))
+AM_CHECK_PYMOD_VERSION([gudev], [__version__], [147.1], , AC_MSG_ERROR([Python module gudev >= 147.1 required to run Conduit]))
 
 ################################################################################
 # DBus
diff --git a/setup-env.sh b/setup-env.sh
new file mode 100644
index 0000000..82d1191
--- /dev/null
+++ b/setup-env.sh
@@ -0,0 +1 @@
+export PYTHONPATH=/opt/gudev/lib/python2.6/site-packages/gtk-2.0/



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