~ubuntu-branches/ubuntu/quantal/debtags/quantal

« back to all changes in this revision

Viewing changes to debtagshw/detectors.py

  • Committer: Package Import Robot
  • Author(s): Michael Vogt
  • Date: 2012-02-13 10:33:06 UTC
  • Revision ID: package-import@ubuntu.com-20120213103306-71cdhoe5b0zb5r1k
Tags: 1.8.0+git20120213ubuntu1
* updated git snapshot:
  - include new debtags-hardware command
  - include support for postive/negative match generator

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# detectors: lib to detect what hardware tags apply to the current system
 
2
#
 
3
# Copyright (C) 2012  Canonical
 
4
#
 
5
# Author:
 
6
#  Michael Vogt <mvo@ubuntu.com>
 
7
#
 
8
# This program is free software; you can redistribute it and/or modify
 
9
# it under the terms of the GNU General Public License as published by
 
10
# the Free Software Foundation; either version 2 of the License, or
 
11
# (at your option) any later version.
 
12
#
 
13
# This program is distributed in the hope that it will be useful,
 
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
# GNU General Public License for more details.
 
17
#
 
18
# You should have received a copy of the GNU General Public License
 
19
# along with this program; if not, write to the Free Software
 
20
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
21
 
 
22
import logging
 
23
import os
 
24
import subprocess
 
25
import multiprocessing
 
26
 
 
27
LOG=logging.getLogger(__name__)
 
28
 
 
29
try:
 
30
    from gi.repository import GUdev
 
31
    HAVE_GUDEV = True
 
32
except ImportError:
 
33
    HAVE_GUDEV = False
 
34
 
 
35
from enums import HardwareSupported
 
36
 
 
37
class Detector(object):
 
38
    """ Base detector class """
 
39
 
 
40
    # helper functions for tags have this prefix, so the code can find them
 
41
    # via introspecton, e.g.
 
42
    # hardware::video:opengl -> _run_check_hardware__video_opengl
 
43
    CHECK_FUNCTION_PREFIX = "_run_check_"
 
44
 
 
45
    def is_supported(self, tag):
 
46
        """ check if the given tag is supported, returns a
 
47
            HardwareSupported class
 
48
        """
 
49
        f = self._get_func_for_tag(tag)
 
50
        if f:
 
51
            return f()
 
52
        return HardwareSupported.UNKNOWN
 
53
 
 
54
    def generate_tag_expressions(self):
 
55
        """ Generate debtags expressions for the given HW """
 
56
        for tag in self.get_supported_tags():
 
57
            res = self.is_supported(tag)
 
58
            if res == HardwareSupported.UNKNOWN:
 
59
                continue
 
60
            yield res, [tag]
 
61
 
 
62
    def get_supported_tags(self):
 
63
        """ return list of supported tags by this detector """
 
64
        supported = []
 
65
        for name in dir(self):
 
66
            tag = self._get_tag_for_func(name)
 
67
            if tag:
 
68
                supported.append(tag)
 
69
        return supported
 
70
 
 
71
    # private helpers
 
72
    def _has_func_for_tag(self, tag):
 
73
        return hasattr(self, "%s%s" % (
 
74
            self.CHECK_FUNCTION_PREFIX, tag.replace(":", "_")))
 
75
 
 
76
    def _get_func_for_tag(self, tag):
 
77
        return getattr(self, "%s%s" % (
 
78
            self.CHECK_FUNCTION_PREFIX, tag.replace(":", "_")), None)
 
79
 
 
80
    def _get_tag_for_func(self, func_name):
 
81
        if not func_name.startswith("%shardware" % self.CHECK_FUNCTION_PREFIX):
 
82
            return None
 
83
        tag = func_name[len(self.CHECK_FUNCTION_PREFIX):].replace("_",":")
 
84
        return tag
 
85
 
 
86
 
 
87
class DetectorUdev(Detector):
 
88
    """ detect hardware based on udev """
 
89
 
 
90
    DEBTAG_TO_UDEV_PROPERTY = {
 
91
        # storage
 
92
        "hardware::storage:cd" : "ID_CDROM",
 
93
        "hardware::storage:cd-writer" : "ID_CDROM_CD_R",
 
94
        "hardware::storage:dvd" : "ID_CDROM_DVD",
 
95
        "hardware::storage:dvd-writer" : "ID_CDROM_DVD_R",
 
96
        # input
 
97
        "hardware::input:touchscreen" : "ID_INPUT_TOUCH",
 
98
        "hardware::input:mouse" : "ID_INPUT_MOUSE",
 
99
        "hardware::input:keyboard" : "ID_INPUT_KEYBOARD",
 
100
        "hardware::input:joystick" : "ID_INPUT_JOYSTICK",
 
101
    }
 
102
 
 
103
    def __init__(self):
 
104
        if HAVE_GUDEV:
 
105
            self._uc = GUdev.Client()
 
106
        else:
 
107
            self._uc = None
 
108
 
 
109
    def is_supported(self, tag):
 
110
        LOG.debug("DetectorUdev.is_supported: '%s'" % tag)
 
111
        if self._uc is None:
 
112
            return HardwareSupported.UNKNOWN
 
113
        for device in self._uc.query_by_subsystem(None):
 
114
            #print device.get_property_keys(), device.get_property("DEVPATH")
 
115
            # supported a (theoretical at this point) udev property that
 
116
            # sets the debtag tag directly
 
117
            if device.has_property("HW_DEBTAGS"):
 
118
                return tag in device.get_property("HW_DEBTAGS")
 
119
            # use our own device detection magic
 
120
            prop = self.DEBTAG_TO_UDEV_PROPERTY.get(tag)
 
121
            if prop and device.has_property(prop):
 
122
                #print device.get_property(prop)
 
123
                if bool(device.get_property(prop)):
 
124
                    return HardwareSupported.YES
 
125
                else:
 
126
                    return HardwareSupported.NO
 
127
        return HardwareSupported.UNKNOWN
 
128
 
 
129
    def get_supported_tags(self):
 
130
        return self.DEBTAG_TO_UDEV_PROPERTY.keys()
 
131
 
 
132
class DetectorCmdline(Detector):
 
133
    """ detect hardware using cmdline helpers """
 
134
    
 
135
    LAPTOP_DETECT = "/usr/sbin/laptop-detect"
 
136
    SCANIMAGE = ["scanimage", "-L"]
 
137
 
 
138
    # hardware::laptop
 
139
    def _run_check_hardware__laptop(self):
 
140
        if os.path.exists(self.LAPTOP_DETECT):
 
141
            if subprocess.call([self.LAPTOP_DETECT]) == 0:
 
142
                return HardwareSupported.YES
 
143
            else:
 
144
                return HardwareSupported.NO
 
145
        else:
 
146
            LOG.warn(
 
147
                "No laptop-detect '%s' helper found" % self.LAPTOP_DETECT)
 
148
        return HardwareSupported.UNKOWN
 
149
 
 
150
    # hardware::scanner
 
151
    def _run_check_hardware__scanner(self):
 
152
        # note that this is slow to run (1-2s)
 
153
        #ver = c_int()
 
154
        #devices = c_long()
 
155
        #sane = cdll.LoadLibrary("libsane.so.1")
 
156
        #res = sane.sane_init(byref(ver), None)
 
157
        #print res, ver
 
158
        #if not res == SANE_STATUS_GOOD:
 
159
        #    return False
 
160
        #print res
 
161
        #sane.sane_get_devices(byref(devices), False)
 
162
        # device is SANE_device** device_list how to get data?
 
163
        #
 
164
        # Note: you can use multiprocessing.Pool.map to run all checks in
 
165
        # parallel
 
166
        try:
 
167
            output = subprocess.check_output(self.SCANIMAGE)
 
168
            if output.startswith("device"):
 
169
                return HardwareSupported.YES
 
170
            else:
 
171
                return HardwareSupported.NO
 
172
        except Exception:
 
173
            LOG.warn("error running '%s'" % self.SCANIMAGE)
 
174
        return HardwareSupported.UNKNOWN
 
175
 
 
176
class DetectorCtypes(Detector):
 
177
    """ detect hardware using ctypes c calls """
 
178
 
 
179
    # hardware::opengl
 
180
    def _run_check_hardware__video_opengl(self):
 
181
        # Launch in a seperate subprocess, since the ctypes opengl stuff might
 
182
        # be fragile (segfault happy)
 
183
        # multiprocessing is python 2.6+
 
184
        import opengl
 
185
        pool = multiprocessing.Pool(1)
 
186
        res = pool.apply(opengl.run_check)
 
187
        pool.close()
 
188
        pool.join()
 
189
        if res:
 
190
            return HardwareSupported.YES
 
191
        else:
 
192
            return HardwareSupported.NO
 
193
 
 
194
 
 
195
class DetectorPython(Detector):
 
196
    """ detect hadware using python imports """
 
197
 
 
198
    # hardware::printer
 
199
    def _run_check_hardware__printer(self):
 
200
        try:
 
201
            # alternative use lpstat -p
 
202
            import cups
 
203
            c = cups.Connection()
 
204
            if len(c.getPrinters()) > 0:
 
205
                return HardwareSupported.YES
 
206
            else:
 
207
                return HardwareSupported.NO
 
208
        except ImportError:
 
209
            LOG.warn("No python-cups installed")
 
210
        except:
 
211
            LOG.exception("_run_cups_check")
 
212
        return HardwareSupported.UNKNOWN
 
213
 
 
214
 
 
215
def get_detectors():
 
216
    """ hepler that returns a list of all lowlevel detector classes """
 
217
    # introspect the detectors modules to load all availalbe detectors
 
218
    detectors = []
 
219
    for name, klass in globals().iteritems():
 
220
        if name.startswith("Detector"):
 
221
            detectors.append(klass())
 
222
    return detectors