Merge lp:~sylvain-pineau/checkbox/plainbox-support into lp:checkbox

Proposed by Sylvain Pineau
Status: Merged
Approved by: Zygmunt Krynicki
Approved revision: 2594
Merged at revision: 2588
Proposed branch: lp:~sylvain-pineau/checkbox/plainbox-support
Merge into: lp:checkbox
Diff against target: 127501 lines (+126960/-1)
98 files modified
checkbox-support/README.rst (+6/-0)
checkbox-support/checkbox_support/contrib/xrandr.py (+1064/-0)
checkbox-support/checkbox_support/dbus/__init__.py (+89/-0)
checkbox-support/checkbox_support/dbus/udisks2.py (+479/-0)
checkbox-support/checkbox_support/heuristics/__init__.py (+56/-0)
checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py (+40/-0)
checkbox-support/checkbox_support/heuristics/udev.py (+44/-0)
checkbox-support/checkbox_support/heuristics/udisks2.py (+62/-0)
checkbox-support/checkbox_support/lib/bit.py (+46/-0)
checkbox-support/checkbox_support/lib/conversion.py (+172/-0)
checkbox-support/checkbox_support/lib/dmi.py (+241/-0)
checkbox-support/checkbox_support/lib/input.py (+585/-0)
checkbox-support/checkbox_support/lib/path.py (+62/-0)
checkbox-support/checkbox_support/lib/pci.py (+89/-0)
checkbox-support/checkbox_support/lib/template.py (+143/-0)
checkbox-support/checkbox_support/lib/tz.py (+55/-0)
checkbox-support/checkbox_support/lib/usb.py (+59/-0)
checkbox-support/checkbox_support/parsers/cpuinfo.py (+180/-0)
checkbox-support/checkbox_support/parsers/dmidecode.py (+126/-0)
checkbox-support/checkbox_support/parsers/efi.py (+52/-0)
checkbox-support/checkbox_support/parsers/lshwjson.py (+23/-0)
checkbox-support/checkbox_support/parsers/meminfo.py (+46/-0)
checkbox-support/checkbox_support/parsers/modinfo.py (+89/-0)
checkbox-support/checkbox_support/parsers/pactl.py (+543/-0)
checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt (+143/-0)
checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt (+166/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt (+33/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt (+51/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt (+30/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt (+41/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt (+608/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon.txt (+608/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-xps1340.txt (+466/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise.txt (+696/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-raring-t430s-dp-available.txt (+889/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-raring-t430s.txt (+889/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/modules-desktop-precise-0.txt (+8/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/modules-desktop-precise.txt (+213/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/samples-desktop-precise.txt (+60/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/sinks-desktop-precise-0.txt (+53/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/sinks-desktop-precise-1.txt (+56/-0)
checkbox-support/checkbox_support/parsers/tests/pactl_data/sinks-desktop-precise.txt (+56/-0)
checkbox-support/checkbox_support/parsers/tests/test_dmi.py (+80/-0)
checkbox-support/checkbox_support/parsers/tests/test_dmidecode.py (+60/-0)
checkbox-support/checkbox_support/parsers/tests/test_efi.py (+63/-0)
checkbox-support/checkbox_support/parsers/tests/test_pactl.py (+561/-0)
checkbox-support/checkbox_support/parsers/tests/test_udevadm.py (+628/-0)
checkbox-support/checkbox_support/parsers/tests/test_xinput.py (+130/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/CALXEDA_HIGHBANK.txt (+6826/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_INSPIRON3521_TOUCHSCREEN.txt (+5642/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_LATITUDEE4310.txt (+5158/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_LATITUDEE6430.txt (+5516/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_OPTIPLEX9020AIO.txt (+5518/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_VOSTRO3460_FINGERPRINT.txt (+5373/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_VOSTROV131.txt (+5357/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/DELL_XPS1340.txt (+5621/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/HOME_MADE.txt (+5383/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/HP_ENVY_15_MEDIATEK_BT.txt (+5163/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/HP_PAVILION14_NOTEBOOK_MEDIATEK_BT.txt (+4947/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/HP_PAVILIONSLEEKBOOK14_ACCELEROMETER.txt (+4447/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/HP_PRO2110.txt (+4642/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/HP_PROBOOK6550B_ACCELEROMETER.txt (+5636/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/LENOVO_E431.txt (+5716/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/LENOVO_E445.txt (+5546/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/LENOVO_T420.txt (+5034/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/LENOVO_T430S.txt (+7630/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/PANDABOARD.txt (+4237/-0)
checkbox-support/checkbox_support/parsers/tests/udevadm_data/SAMSUNG_N310.txt (+4092/-0)
checkbox-support/checkbox_support/parsers/udevadm.py (+781/-0)
checkbox-support/checkbox_support/parsers/xinput.py (+198/-0)
checkbox-support/checkbox_support/scripts/audio_settings.py (+375/-0)
checkbox-support/checkbox_support/scripts/gputest_benchmark.py (+106/-0)
checkbox-support/checkbox_support/scripts/tests/test_audio_settings.py (+151/-0)
checkbox-support/checkbox_support/scripts/tests/test_gputest_benchmark.py (+78/-0)
checkbox-support/checkbox_support/tests/__init__.py (+50/-0)
checkbox-support/checkbox_support/udev.py (+93/-0)
checkbox-support/checkbox_support/vendor/__init__.py (+28/-0)
checkbox-support/checkbox_support/vendor/mock.py (+2367/-0)
checkbox-support/setup.py (+40/-0)
plainbox-provider-checkbox/provider_bin/accelerometer_test (+347/-0)
plainbox-provider-checkbox/provider_bin/audio_driver_info (+109/-0)
plainbox-provider-checkbox/provider_bin/audio_settings (+9/-0)
plainbox-provider-checkbox/provider_bin/filter_templates (+134/-0)
plainbox-provider-checkbox/provider_bin/gputest_benchmark (+27/-0)
plainbox-provider-checkbox/provider_bin/graphics_modes_info (+74/-0)
plainbox-provider-checkbox/provider_bin/graphics_stress_test (+467/-0)
plainbox-provider-checkbox/provider_bin/lock_screen_watcher (+101/-0)
plainbox-provider-checkbox/provider_bin/lsmod_info (+40/-0)
plainbox-provider-checkbox/provider_bin/memory_compare (+91/-0)
plainbox-provider-checkbox/provider_bin/network_bandwidth_test (+671/-0)
plainbox-provider-checkbox/provider_bin/network_device_info (+262/-0)
plainbox-provider-checkbox/provider_bin/removable_storage_test (+594/-0)
plainbox-provider-checkbox/provider_bin/removable_storage_watcher (+890/-0)
plainbox-provider-checkbox/provider_bin/rotation_test (+73/-0)
plainbox-provider-checkbox/provider_bin/run_templates (+144/-0)
plainbox-provider-checkbox/provider_bin/touchpad_driver_info (+82/-0)
plainbox-provider-checkbox/provider_bin/udisks2_monitor (+154/-0)
setup.py (+1/-1)
To merge this branch: bzr merge lp:~sylvain-pineau/checkbox/plainbox-support
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Needs Resubmitting
Review via email: mp+198573@code.launchpad.net

Description of the change

Implementation proposal of the new support library for plainbox provider scripts

Notes:
- Proposed package name: checkbox-support
- Proposed python namespace: checkbox_support
- Remove the original checkbox.parsers.pyparsing to use the ubuntu packaged version for python3
- Tests run ok

To post a comment you must log in.
Revision history for this message
Zygmunt Krynicki (zyga) wrote :

ensure that all commits have correct, scoped first line (summary)

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

It's now ready for review/testing

review: Needs Resubmitting
Revision history for this message
Zygmunt Krynicki (zyga) wrote :

This looks good.
I need to look at it in the tree and think about any potential issues but you have my tentative +1

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'checkbox-support'
=== added symlink 'checkbox-support/COPYING'
=== target is u'../plainbox/COPYING'
=== added file 'checkbox-support/README.rst'
--- checkbox-support/README.rst 1970-01-01 00:00:00 +0000
+++ checkbox-support/README.rst 2014-01-07 13:44:32 +0000
@@ -0,0 +1,6 @@
1CheckBox Support
2================
3
4CheckBox Support library is a collection of python modules used by PlainBox
5providers scripts.
6They were originally provided by the checkbox python package.
07
=== added directory 'checkbox-support/checkbox_support'
=== added file 'checkbox-support/checkbox_support/__init__.py'
=== added directory 'checkbox-support/checkbox_support/contrib'
=== added file 'checkbox-support/checkbox_support/contrib/__init__.py'
=== added file 'checkbox-support/checkbox_support/contrib/xrandr.py'
--- checkbox-support/checkbox_support/contrib/xrandr.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/contrib/xrandr.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,1064 @@
1#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3#
4# Python-XRandR provides a high level API for the XRandR extension of the
5# X.org server. XRandR allows to configure resolution, refresh rate, rotation
6# of the screen and multiple outputs of graphics cards.
7#
8# Copyright 2007 © Sebastian Heinlein <sebastian.heinlein@web.de>
9# Copyright 2007 © Michael Vogt <mvo@ubuntu.com>
10# Copyright 2007 © Canonical Ltd.
11#
12# In many aspects it follows the design of the xrand tool of the X.org, which
13# comes with the following copyright:
14#
15# Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
16# Copyright © 2002 Hewlett Packard Company, Inc.
17# Copyright © 2006 Intel Corporation
18#
19# And can be downloaded here:
20#
21# git://anongit.freedesktop.org/git/xorg/app/xrandr
22#
23# This library is free software; you can redistribute it and/or
24# modify it under the terms of the GNU Lesser General Public
25# License as published by the Free Software Foundation; either
26# version 2.1 of the License, or any later version.
27#
28# This library is distributed in the hope that it will be useful,
29# but WITHOUT ANY WARRANTY; without even the implied warranty of
30# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31# Lesser General Public License for more details.
32#
33# You should have received a copy of the GNU Lesser General Public
34# License along with this library; if not, write to the Free Software
35# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
36# MA 02110-1301 USA
37
38from ctypes import (
39 POINTER,
40 Structure,
41 byref,
42 c_char_p,
43 c_void_p,
44 c_int,
45 c_long,
46 c_ulong,
47 c_ushort,
48 cdll,
49)
50import os
51
52RR_ROTATE_0 = 1
53RR_ROTATE_90 = 2
54RR_ROTATE_180 = 4
55RR_ROTATE_270 = 8
56RR_REFLECT_X = 16
57RR_REFLECT_Y = 32
58
59RR_CONNECTED = 0
60RR_DISCONNECTED = 1
61RR_UNKOWN_CONNECTION = 2
62
63RR_BAD_OUTPUT = 0
64RR_BAD_CRTC = 1
65RR_BAD_MODE = 2
66
67RR_SET_CONFIG_SUCCESS = 0
68RR_SET_CONFIG_INVALID_CONFIG_TIME = 1
69RR_SET_CONFIG_INVALID_TIME = 2
70RR_SET_CONFIG_FAILED = 3
71
72# Flags to keep track of changes
73CHANGES_NONE = 0
74CHANGES_CRTC = 1
75CHANGES_MODE = 2
76CHANGES_RELATION = 4
77CHANGES_POSITION = 8
78CHANGES_ROTATION = 16
79CHANGES_REFLECTION = 32
80CHANGES_AUTOMATIC = 64
81CHANGES_REFRESH = 128
82CHANGES_PROPERTY = 256
83
84# Relation information
85RELATION_ABOVE = 0
86RELATION_BELOW = 1
87RELATION_RIGHT_OF = 2
88RELATION_LEFT_OF = 3
89RELATION_SAME_AS = 4
90
91# some fundamental datatypes
92RRCrtc = c_long
93RROutput = c_long
94RRMode = c_long
95Connection = c_ushort
96SubpixelOrder = c_ushort
97Time = c_ulong
98Rotation = c_ushort
99Status = c_int
100
101# load the libs
102xlib = cdll.LoadLibrary('libX11.so.6')
103rr = cdll.LoadLibrary('libXrandr.so.2')
104
105
106# query resources
107class _XRRModeInfo(Structure):
108 _fields_ = [
109 ("id", RRMode), # XID is c_long
110 ("width", c_int),
111 ("height", c_int),
112 ("dotClock", c_long),
113 ("hSyncStart", c_int),
114 ("hSyncEnd", c_int),
115 ("hTotal", c_int),
116 ("hSkew", c_int),
117 ("vSyncStart", c_int),
118 ("vSyncEnd", c_int),
119 ("vTotal", c_int),
120 ("name", c_char_p),
121 ("nameLength", c_int),
122 ("modeFlags", c_long),
123 ]
124
125
126class _XRRScreenSize(Structure):
127 _fields_ = [
128 ("width", c_int),
129 ("height", c_int),
130 ("mwidth", c_int),
131 ("mheight", c_int)
132 ]
133
134
135class _XRRCrtcInfo(Structure):
136 _fields_ = [
137 ("timestamp", Time),
138 ("x", c_int),
139 ("y", c_int),
140 ("width", c_int),
141 ("height", c_int),
142 ("mode", RRMode),
143 ("rotation", c_int),
144 ("noutput", c_int),
145 ("outputs", POINTER(RROutput)),
146 ("rotations", Rotation),
147 ("npossible", c_int),
148 ("possible", POINTER(RROutput)),
149 ]
150
151
152class _XRRScreenResources(Structure):
153 _fields_ = [
154 ("timestamp", Time),
155 ("configTimestamp", Time),
156 ("ncrtc", c_int),
157 ("crtcs", POINTER(RRCrtc)),
158 ("noutput", c_int),
159 ("outputs", POINTER(RROutput)),
160 ("nmode", c_int),
161 ("modes", POINTER(_XRRModeInfo)),
162 ]
163
164
165class RRError(Exception):
166 """Base exception class of the module"""
167 pass
168
169
170class UnsupportedRRError(RRError):
171 """Raised if the required XRandR extension version is not available"""
172 def __init__(self, required, current):
173 self.required = required
174 self.current = current
175
176
177# XRRGetOutputInfo
178class _XRROutputInfo(Structure):
179 _fields_ = [
180 ("timestamp", Time),
181 ("crtc", c_int),
182 ("name", c_char_p),
183 ("nameLen", c_int),
184 ("mm_width", c_ulong),
185 ("mm_height", c_ulong),
186 ("connection", Connection),
187 ("subpixel_order", SubpixelOrder),
188 ("ncrtc", c_int),
189 ("crtcs", POINTER(RRCrtc)),
190 ("nclone", c_int),
191 ("clones", POINTER(RROutput)),
192 ("nmode", c_int),
193 ("npreferred", c_int),
194 ("modes", POINTER(RRMode))
195 ]
196
197
198class _XRRCrtcGamma(Structure):
199 _fields_ = [
200 ('size', c_int),
201 ('red', POINTER(c_ushort)),
202 ('green', POINTER(c_ushort)),
203 ('blue', POINTER(c_ushort)),
204 ]
205
206
207def _array_conv(array, type, conv=lambda x: x):
208 length = len(array)
209 res = (type * length)()
210 for i in range(length):
211 res[i] = conv(array[i])
212 return res
213
214
215class Output:
216 """The output is a reference to a supported output jacket of the graphics
217 card. Outputs are attached to a hardware pipe to be used. Furthermore
218 they can be a clone of another output or show a subset of the screen"""
219 def __init__(self, info, id, screen):
220 """Initializes an output instance"""
221 self._info = info
222 self.id = id
223 self._screen = screen
224 # Store changes later here
225 self._mode = None
226 self._crtc = None
227 self._rotation = RR_ROTATE_0
228 self._relation = None
229 self._relation_offset = 0
230 self._relative_to = None
231 self._position = None
232 self._reflection = None
233 self._automatic = None
234 self._rate = None
235 self._changes = CHANGES_NONE
236 self._x = 0
237 self._y = 0
238
239 self.name = self._info.contents.name
240
241 def __del__(self):
242 """Frees the internal reference to the output info if the output gets
243 removed"""
244 rr.XRRFreeOutputInfo(self._info)
245
246 def get_physical_width(self):
247 """Returns the display width reported by the connected output device"""
248 return self._info.contents.mm_width
249
250 def get_physical_height(self):
251 """
252 Returns the display height reported by the connected output device
253 """
254 return self._info.contents.mm_height
255
256 def get_crtc(self):
257 """Returns the xid of the hardware pipe to which the output is
258 attached. If the output is disabled it will return 0"""
259 return self._info.contents.crtc
260
261 def get_crtcs(self):
262 """Returns the xids of the hardware pipes to which the output could
263 be attached"""
264 crtcs = []
265 for i in range(self._info.contents.ncrtc):
266 for crtc in self._screen.crtcs:
267 if crtc.xid == self._info.contents.crtcs[i]:
268 crtcs.append(crtc)
269 return crtcs
270
271 def get_available_rotations(self):
272 """Returns a binary flag of the supported rotations of the output or
273 0 if the output is disabled"""
274 rotations = RR_ROTATE_0
275 found = False
276 if self.is_active():
277 # Get the rotations supported by all crtcs to make assigning
278 # crtcs easier. Furthermore there don't seem to be so many
279 # cards which show another behavior
280 for crtc in self.get_crtcs():
281 # Set rotations to the value of the first found crtc and
282 # then create a subset only for all other crtcs
283 if not found:
284 rotations = crtc.get_available_rotations()
285 found = True
286 else:
287 rotations = rotations & crtc.get_available_rotations()
288 return rotations
289
290 def get_available_modes(self):
291 """Returns the list of supported mode lines (resolution, refresh rate)
292 that are supported by the connected device"""
293 modes = []
294 for m in range(self._info.contents.nmode):
295 output_modes = self._info.contents.modes
296 for s in range(self._screen._resources.contents.nmode):
297 screen_modes = self._screen._resources.contents.modes
298 if screen_modes[s].id == output_modes[m]:
299 modes.append(screen_modes[s])
300 return modes
301
302 def get_preferred_mode(self):
303 """Returns an index that refers to the list of available modes and
304 points to the preferred mode of the connected device"""
305 return self._info.contents.npreferred
306
307 def is_active(self):
308 """Returns True if the output is attached to a hardware pipe, is
309 enabled"""
310 return self._info.contents.crtc != 0
311
312 def is_connected(self):
313 """Return True if a device is detected at the output"""
314 if self._info.contents.connection in (RR_CONNECTED,
315 RR_UNKOWN_CONNECTION):
316 return True
317 return False
318
319 def disable(self):
320 """Disables the output"""
321 if not self.is_active():
322 return
323 self._mode = None
324 self._crtc._outputs.remove(self)
325 self._crtc = None
326 self._changes = self._changes | CHANGES_CRTC | CHANGES_MODE
327
328 def set_to_mode(self, mode):
329 modes = self.get_available_modes()
330 if mode in range(len(modes)):
331 self._mode = modes[mode].id
332 return
333 raise RRError("Mode is not available")
334
335 def set_to_preferred_mode(self):
336 modes = self.get_available_modes()
337 mode = modes[self.get_preferred_mode()]
338 if mode != None:
339 self._mode = mode.id
340 return
341 raise RRError("Preferred mode is not available")
342
343 def get_clones(self):
344 """Returns the xids of the outputs which can be clones of the output"""
345 clones = []
346 for i in range(self._info.contents.nclone):
347 id = self._info.contents.clones[i]
348 o = self._screen.get_output_by_id(id)
349 clones.append(o)
350 return clones
351
352 def set_relation(self, relative, relation, offset=0):
353 """Sets the position of the output in relation to the given one"""
354 rel = self._screen.get_output_by_name(relative)
355 if rel and relation in (RELATION_LEFT_OF, RELATION_RIGHT_OF,
356 RELATION_ABOVE, RELATION_BELOW,
357 RELATION_SAME_AS):
358 self._relation = relation
359 self._relative_to = rel
360 self._relation_offset = offset
361 self._changes = self._changes | CHANGES_RELATION
362 else:
363 raise RRError("The given relative output or relation is not "
364 "available")
365
366 def has_changed(self, changes=None):
367 """Checks if the output has changed: Either for a specific change or
368 generally"""
369 if changes:
370 return self._changes & changes
371 else:
372 return self._changes != CHANGES_NONE
373
374
375class Crtc:
376 """The crtc is a reference to a hardware pipe that is provided by the
377 graphics device. Outputs can be attached to crtcs"""
378
379 def __init__(self, info, xid, screen):
380 """Initializes the hardware pipe object"""
381 self._info = info
382 self.xid = xid
383 self._screen = screen
384 self._outputs = []
385
386 def __del__(self):
387 """Frees the reference to the rendering pipe if the instance gets
388 removed"""
389 rr.XRRFreeCrtcConfigInfo(self._info)
390
391 def get_xid(self):
392 """Returns the internal id of the crtc from the X server"""
393 return self.xid
394
395 def get_available_rotations(self):
396 """Returns a binary flag that contains the supported rotations of the
397 hardware pipe"""
398 return self._info.contents.rotations
399
400 def set_config(self, x, y, mode, outputs, rotation=RR_ROTATE_0):
401 """Configures the render pipe with the given mode and outputs. X and y
402 set the position of the crtc output in the screen"""
403 rr.XRRSetCrtcConfig(self._screen._display,
404 self._screen._resources,
405 self.xid,
406 self._screen.get_timestamp(),
407 c_int(x), c_int(y),
408 mode,
409 rotation,
410 _array_conv(outputs, RROutput, lambda x: x.id),
411 len(outputs))
412
413 def apply_changes(self):
414 """Applies the stored changes"""
415 if len(self._outputs) > 0:
416 output = self._outputs[0]
417 self.set_config(output._x, output._y, output._mode,
418 self._outputs, output._rotation)
419 else:
420 self.disable()
421
422 def disable(self):
423 """Turns off all outputs on the crtc"""
424 rr.XRRSetCrtcConfig(self._screen._display,
425 self._screen._resources,
426 self.xid,
427 self._screen.get_timestamp(),
428 0, 0,
429 None,
430 RR_ROTATE_0,
431 0, 0)
432
433 #FIXME: support gamma settings
434 """
435 def get_gamma_size(self):
436 return rr.XRRGetCrtcGammaSize(self._screen._display, self.id)
437 def get_gamma(self):
438 result = rr.XRRGetCrtcGamma(self._screen._display, self.id)
439 return _from_gamma(result)
440 def set_gamma(self, gamma):
441 g = _to_gamma(gamma)
442 rr.XRRSetCrtcGamma(self._screen._display, self.id, g)
443 rr.XRRFreeGamma(g)
444 gamma = property(get_gamma, set_gamma)"""
445
446 def load_outputs(self):
447 """Get the currently assigned outputs"""
448 outputs = []
449 for i in range(self._info.contents.noutput):
450 id = self._info.contents.outputs[i]
451 o = self._screen.get_output_by_id(id)
452 outputs.append(o)
453 self._outputs = outputs
454
455 def get_outputs(self):
456 """Returns the list of attached outputs"""
457 return self._outputs
458
459 def add_output(self, output):
460 """Adds the specified output to the crtc"""
461 output._crtc = self
462 self._outputs.append(output)
463
464 def supports_output(self, output):
465 """Check if the output can be used by the crtc.
466 See check_crtc_for_output in xrandr.c"""
467 if not self.xid in [c.xid for c in output.get_crtcs()]:
468 return False
469 if len(self._outputs):
470 for other in self._outputs:
471 if other == output:
472 continue
473 if other._x != output._x:
474 return False
475 if other._y != output._y:
476 return False
477 if other._mode != output._mode:
478 return False
479 if other._rotation != output._rotation:
480 return False
481 #FIXME: pick_crtc is still missing
482 elif self._info.contents.noutput > 0:
483 if self._info.contents.x != output._x:
484 return False
485 if self._info.contents.y != output._y:
486 return False
487 if self._info.contents.mode_info != output._mode:
488 return False
489 if self._info.rotation != output._rotation:
490 return False
491 return True
492
493 def supports_rotation(self, rotation):
494 """Check if the given rotation is supported by the crtc"""
495 rotations = self._info.contents.rotations
496 dir = rotation & (RR_ROTATE_0 | RR_ROTATE_90 | RR_ROTATE_180 |
497 RR_ROTATE_270)
498 reflect = rotation & (RR_REFLECT_X | RR_REFLECT_Y)
499 if (((rotations & dir) != 0) and ((rotations & reflect) == reflect)):
500 return True
501 return False
502
503 def has_changed(self):
504 """Check if there are any new outputs assigned to the crtc or any
505 outputs with a changed mode or position"""
506 if len(self._outputs) != self._info.contents.noutput:
507 return True
508 for i in range(self._info.contents.noutput):
509 id = self._info.contents.outputs[i]
510 output = self._screen.get_output_by_id(id)
511 if not output in self._outputs:
512 return True
513 if output.has_changed():
514 return True
515 return False
516
517
518class Screen:
519 def __init__(self, dpy, screen=-1):
520 """Initializes the screen"""
521 # Some sane default values
522 self.outputs = {}
523 self.crtcs = []
524 self._width = 0
525 self._height = 0
526 self._width_max = 0
527 self._height_max = 0
528 self._width_min = 0
529 self._height_min = 0
530 self._width_mm = 0
531 self._height_mm = 0
532
533 self._display = dpy
534 if not -1 <= screen < xlib.XScreenCount(dpy):
535 raise RRError("The chosen screen is not available", screen)
536 elif screen == -1:
537 self._screen = xlib.XDefaultScreen(dpy)
538 else:
539 self._screen = screen
540 self._root = xlib.XDefaultRootWindow(self._display, self._screen)
541 self._id = rr.XRRRootToScreen(self._display, self._root)
542
543 self._load_resources()
544 self._load_config()
545 (self._width, self._height,
546 self._width_mm, self._height_mm) = self.get_size()
547 if XRANDR_VERSION >= (1, 2):
548 self._load_screen_size_range()
549 self._load_crtcs()
550 self._load_outputs()
551
552 # Store XRandR 1.0 changes here
553 self._rate = self.get_current_rate()
554 self._rotation = self.get_current_rotation()
555 self._size_index = self.get_current_size_index()
556
557 def __del__(self):
558 """Free the reference to the interal screen config if the screen
559 gets removed"""
560 rr.XRRFreeScreenConfigInfo(self._config)
561
562 def _load_config(self):
563 """Loads the screen configuration. Only needed privately by the
564 the bindings"""
565 class XRRScreenConfiguration(Structure):
566 " private to Xrandr "
567 pass
568 gsi = rr.XRRGetScreenInfo
569 gsi.restype = POINTER(XRRScreenConfiguration)
570 self._config = gsi(self._display, self._root)
571
572 def _load_screen_size_range(self):
573 """Detects the dimensionios of the screen"""
574 minWidth = c_int()
575 minHeight = c_int()
576 maxWidth = c_int()
577 maxHeight = c_int()
578 res = rr.XRRGetScreenSizeRange(self._display, self._root,
579 byref(minWidth), byref(minHeight),
580 byref(maxWidth), byref(maxHeight))
581 if res:
582 self._width_max = maxWidth.value
583 self._width_min = minWidth.value
584 self._height_max = maxHeight.value
585 self._height_min = minHeight.value
586
587 def _load_resources(self):
588 """Loads the screen resources. Only needed privately for the
589 bindings"""
590 gsr = rr.XRRGetScreenResources
591 gsr.restype = POINTER(_XRRScreenResources)
592 self._resources = gsr(self._display, self._root)
593
594 def _load_crtcs(self):
595 """Loads the available XRandR 1.2 crtcs (hardware pipes) of
596 the screen"""
597 gci = rr.XRRGetCrtcInfo
598 gci.restype = POINTER(_XRRCrtcInfo)
599 c = self._resources.contents.crtcs
600 for i in range(self._resources.contents.ncrtc):
601 xrrcrtcinfo = gci(self._display, self._resources, c[i])
602 self.crtcs.append(Crtc(xrrcrtcinfo, c[i], self))
603
604 def _load_outputs(self):
605 """Loads the available XRandR 1.2 outputs of the screen"""
606 goi = rr.XRRGetOutputInfo
607 goi.restype = POINTER(_XRROutputInfo)
608 o = self._resources.contents.outputs
609 for i in range(self._resources.contents.noutput):
610 xrroutputinfo = goi(self._display, self._resources, o[i])
611 output = Output(xrroutputinfo, o[i], self)
612 self.outputs[xrroutputinfo.contents.name] = output
613 # Store the mode of the crtc in the output instance
614 crtc = self.get_crtc_by_xid(output.get_crtc())
615 if crtc:
616 output._mode = crtc._info.contents.mode
617 crtc.add_output(output)
618
619 def get_size(self):
620 """Returns the current pixel and physical size of the screen"""
621 width = xlib.XDisplayWidth(self._display, self._screen)
622 width_mm = xlib.XDisplayWidthMM(self._display, self._screen)
623 height = xlib.XDisplayHeight(self._display, self._screen)
624 height_mm = xlib.XDisplayHeightMM(self._display, self._screen)
625 return width, height, width_mm, height_mm
626
627 def get_timestamp(self):
628 """Creates a X timestamp that must be used when applying changes, since
629 they can be delayed"""
630 config_timestamp = Time()
631 rr.XRRTimes.restpye = c_ulong
632 return rr.XRRTimes(self._display, self._id, byref(config_timestamp))
633
634 def get_crtc_by_xid(self, xid):
635 """Returns the crtc with the given xid or None"""
636 for crtc in self.crtcs:
637 if crtc.xid == xid:
638 return crtc
639 return None
640
641 def get_current_rate(self):
642 """Returns the currently used refresh rate"""
643 _check_required_version((1, 0))
644 xccr = rr.XRRConfigCurrentRate
645 xccr.restype = c_int
646 return xccr(self._config)
647
648 def get_available_rates_for_size_index(self, size_index):
649 """Returns the refresh rates that are supported by the screen for
650 the given resolution. See get_available_sizes for the resolution to
651 which size_index points"""
652 _check_required_version((1, 0))
653 rates = []
654 nrates = c_int()
655 rr.XRRConfigRates.restype = POINTER(c_ushort)
656 _rates = rr.XRRConfigRates(self._config, size_index, byref(nrates))
657 for r in range(nrates.value):
658 rates.append(_rates[r])
659 return rates
660
661 def get_current_rotation(self):
662 """Returns the currently used rotation. Can be RR_ROTATE_0,
663 RR_ROTATE_90, RR_ROTATE_180 or RR_ROTATE_270"""
664 _check_required_version((1, 0))
665 current = c_ushort()
666 rr.XRRConfigRotations(self._config, byref(current))
667 return current.value
668
669 def get_available_rotations(self):
670 """Returns a binary flag that holds the available resolutions"""
671 _check_required_version((1, 0))
672 current = c_ushort()
673 rotations = rr.XRRConfigRotations(self._config, byref(current))
674 return rotations
675
676 def get_current_size_index(self):
677 """Returns the position of the currently used resolution size in the
678 list of available resolutions. See get_available_sizes"""
679 _check_required_version((1, 0))
680 rotation = c_ushort()
681 size = rr.XRRConfigCurrentConfiguration(self._config,
682 byref(rotation))
683 return size
684
685 def get_available_sizes(self):
686 """Returns the available resolution sizes of the screen. The size
687 index points to the corresponding resolution of this list"""
688 _check_required_version((1, 0))
689 sizes = []
690 nsizes = c_int()
691 xcs = rr.XRRConfigSizes
692 xcs.restype = POINTER(_XRRScreenSize)
693 _sizes = xcs(self._config, byref(nsizes))
694 for r in range(nsizes.value):
695 sizes.append(_sizes[r])
696 return sizes
697
698 def set_config(self, size_index, rate, rotation):
699 """Configures the screen with the given resolution at the given size
700 index, rotation and refresh rate. To get in effect call
701 Screen.apply_config()"""
702 _check_required_version((1, 0))
703 self.set_size_index(size_index)
704 self.set_refresh_rate(rate)
705 self.set_rotation(rotation)
706
707 def set_size_index(self, index):
708 """Sets the reoslution of the screen. To get in effect call
709 Screen.apply_config()"""
710 if index in range(len(self.get_available_sizes())):
711 self._size_index = index
712 else:
713 raise RRError("There isn't any size associated "
714 "to the index %s" % index)
715
716 def set_rotation(self, rotation):
717 """Sets the rotation of the screen. To get in effect call
718 Screen.apply_config()"""
719 if self.get_available_rotations() & rotation:
720 self._rotation = rotation
721 else:
722 raise RRError("The chosen rotation is not supported")
723
724 def set_refresh_rate(self, rate):
725 """Sets the refresh rate of the screen. To get in effect call
726 Screen.apply_config()"""
727 if rate in self.get_available_rates_for_size_index(self._size_index):
728 self._rate = rate
729 else:
730 raise RRError("The chosen refresh rate %s is not "
731 "supported" % rate)
732
733 def get_mode_by_xid(self, xid):
734 """Returns the mode of the given xid"""
735 screen_modes = self._resources.contents.modes
736 for s in range(self._resources.contents.nmode):
737 if screen_modes[s].id == xid:
738 return screen_modes[s]
739 return None
740
741 def get_output_by_name(self, name):
742 """Returns the output of the screen with the given name or None"""
743 if name in self.outputs:
744 return self.outputs[name]
745 else:
746 return None
747
748 def get_output_by_id(self, id):
749 """Returns the output of the screen with the given xid or None"""
750 for o in list(self.outputs.values()):
751 if o.id == id:
752 return o
753 return None
754
755 def print_info(self, verbose=False):
756 """Prints some information about the detected screen and its outputs"""
757 _check_required_version((1, 0))
758 print("Screen %s: minimum %s x %s, current %s x %s, maximum %s x %s" %\
759 (self._screen,
760 self._width_min, self._height_min,
761 self._width, self._height,
762 self._width_max, self._height_max))
763 print(" %smm x %smm" % (self._width_mm, self._height_mm))
764 print("Crtcs: %s" % len(self.crtcs))
765 if verbose:
766 print("Modes (%s):" % self._resources.contents.nmode)
767 modes = self._resources.contents.modes
768 for i in range(self._resources.contents.nmode):
769 print(" %s - %sx%s" % (modes[i].name,
770 modes[i].width,
771 modes[i].height))
772 i = 0
773 print("Sizes @ Refresh Rates:")
774 for s in self.get_available_sizes():
775 print(" [%s] %s x %s @ %s" % (
776 i, s.width, s.height,
777 self.get_available_rates_for_size_index(i)))
778 i += 1
779 print("Rotations:")
780 rots = self.get_available_rotations()
781 if rots & RR_ROTATE_0:
782 print("normal")
783 if rots & RR_ROTATE_90:
784 print("right")
785 if rots & RR_ROTATE_180:
786 print("inverted")
787 if rots & RR_ROTATE_270:
788 print("left")
789 print("")
790 print("Outputs:")
791 for o in list(self.outputs.keys()):
792 output = self.outputs[o]
793 print(" %s" % o)
794 if output.is_connected():
795 print("(%smm x %smm)" % (output.get_physical_width(),
796 output.get_physical_height()))
797 modes = output.get_available_modes()
798 print(" Modes:")
799 for m in range(len(modes)):
800 mode = modes[m]
801 refresh = mode.dotClock / (mode.hTotal * mode.vTotal)
802 print(" [%s] %s x %s @ %s" % (m,
803 mode.width,
804 mode.height,
805 refresh))
806 if mode.id == output._mode:
807 print("*")
808 if m == output.get_preferred_mode():
809 print("(preferred)")
810 print("")
811 print(" Rotations:")
812 rots = output.get_available_rotations()
813 if rots & RR_ROTATE_0:
814 print("normal")
815 if rots & RR_ROTATE_90:
816 print("right")
817 if rots & RR_ROTATE_180:
818 print("inverted")
819 if rots & RR_ROTATE_270:
820 print("left")
821 print("")
822 else:
823 print("(not connected)")
824 if verbose:
825 print(" Core properties:")
826 for (f, t) in output._info.contents._fields_:
827 print(" %s: %s" % (
828 f, getattr(output._info.contents, f)))
829
830 def get_outputs(self):
831 """Returns the outputs of the screen"""
832 _check_required_version((1, 2))
833 return list(self.outputs.values())
834
835 def get_output_names(self):
836 _check_required_version((1, 2))
837 return list(self.outputs.keys())
838
839 def set_size(self, width, height, width_mm, height_mm):
840 """Apply the given pixel and physical size to the screen"""
841 _check_required_version((1, 2))
842 # Check if we really need to apply the changes
843 if (width, height, width_mm, height_mm) == self.get_size():
844 return
845 rr.XRRSetScreenSize(self._display, self._root,
846 c_int(width), c_int(height),
847 c_int(width_mm), c_int(height_mm))
848
849 def apply_output_config(self):
850 """Used for instantly applying RandR 1.2 changes"""
851 _check_required_version((1, 2))
852 self._arrange_outputs()
853 self._calculate_size()
854 self.set_size(self._width, self._height,
855 self._width_mm, self._height_mm)
856
857 # Assign all active outputs to crtcs
858 for output in list(self.outputs.values()):
859 if not output._mode or output._crtc:
860 continue
861 for crtc in output.get_crtcs():
862 if crtc and crtc.supports_output(output):
863 crtc.add_output(output)
864 output._changes = output._changes | CHANGES_CRTC
865 break
866 if not output._crtc:
867 #FIXME: Take a look at the pick_crtc code in xrandr.c
868 raise RRError("There is no matching crtc for the output")
869
870 # Apply stored changes of crtcs
871 for crtc in self.crtcs:
872 if crtc.has_changed():
873 crtc.apply_changes()
874
875 def apply_config(self):
876 """Used for instantly applying RandR 1.0 changes"""
877 _check_required_version((1, 0))
878 status = rr.XRRSetScreenConfigAndRate(self._display,
879 self._config,
880 self._root,
881 self._size_index,
882 self._rotation,
883 self._rate,
884 self.get_timestamp())
885 return status
886
887 def _arrange_outputs(self):
888 """Arrange all output positions according to their relative position"""
889 for output in self.get_outputs():
890 # Skip not changed and not used outputs
891 if not output.has_changed(CHANGES_RELATION) or \
892 output._mode == None:
893 continue
894 relative = output._relative_to
895 mode = self.get_mode_by_xid(output._mode)
896 mode_relative = self.get_mode_by_xid(relative._mode)
897 if not relative or not relative._mode:
898 output._x = 0
899 output._y = 0
900 output._changes = output._changes | CHANGES_POSITION
901 if output._relation == RELATION_LEFT_OF:
902 output._y = relative._y + output._relation_offset
903 output._x = relative._x - \
904 get_mode_width(mode, output._rotation)
905 elif output._relation == RELATION_RIGHT_OF:
906 output._y = relative._y + output._relation_offset
907 output._x = relative._x + get_mode_width(mode_relative,
908 output._rotation)
909 elif output._relation == RELATION_ABOVE:
910 output._y = relative._y - get_mode_height(mode,
911 output._rotation)
912 output._x = relative._x + output._relation_offset
913 elif output._relation == RELATION_BELOW:
914 output._y = relative._y + get_mode_height(mode_relative,
915 output._rotation)
916 output._x = relative._x + output._relation_offset
917 elif output._relation == RELATION_SAME_AS:
918 output._y = relative._y + output._relation_offset
919 output._x = relative._x + output._relation_offset
920 output._changes = output._changes | CHANGES_POSITION
921 # Normalize the postions so to the upper left cornor of all outputs
922 # is at 0,0
923 min_x = 32768
924 min_y = 32768
925 for output in self.get_outputs():
926 if output._mode == None:
927 continue
928 if output._x < min_x:
929 min_x = output._x
930 if output._y < min_y:
931 min_y = output._y
932 for output in self.get_outputs():
933 if output._mode == None:
934 continue
935 output._x -= min_x
936 output._y -= min_y
937 output._changes = output._changes | CHANGES_POSITION
938
939 def _calculate_size(self):
940 """Recalculate the pixel and physical size of the screen so that
941 it covers all outputs"""
942 width = self._width
943 height = self._height
944 for output in self.get_outputs():
945 if not output._mode:
946 continue
947 mode = self.get_mode_by_xid(output._mode)
948 x = output._x
949 y = output._y
950 w = get_mode_width(mode, output._rotation)
951 h = get_mode_height(mode, output._rotation)
952 if x + w > width:
953 width = x + w
954 if y + h > height:
955 height = y + h
956 if width > self._width_max or height > self._height_max:
957 raise RRError("The required size is not supported",
958 (width, height), (self._width_max, self._width_min))
959 else:
960 if height < self._height_min:
961 self._fb_height = self._height_min
962 else:
963 self._height = height
964 if width < self._width_min:
965 self._width = self._width_min
966 else:
967 self._width = width
968 #FIXME: Physical size is missing
969
970
971def get_current_display():
972 """Returns the currently used display"""
973 display_url = os.getenv("DISPLAY")
974 open_display = xlib.XOpenDisplay
975 # Set .argtypes and .restype, to ensure proper
976 # type check and conversion
977 open_display.restype = c_void_p
978 open_display.argtypes = [c_char_p]
979 # XOpenDisplay accepts a char*, but
980 # display_url is a unicode string therefore
981 # we convert it to a bytes string
982 dpy = open_display(display_url.encode('utf-8'))
983 return dpy
984
985
986def get_current_screen():
987 """Returns the currently used screen"""
988 screen = Screen(get_current_display())
989 return screen
990
991
992def get_screen_of_display(display, count):
993 """Returns the screen of the given display"""
994 dpy = xlib.XOpenDisplay(display)
995 return Screen(dpy, count)
996
997
998def get_version():
999 """Returns a tuple containing the major and minor version of the xrandr
1000 extension or None if the extension is not available"""
1001 major = c_int()
1002 minor = c_int()
1003 res = rr.XRRQueryVersion(get_current_display(),
1004 byref(major), byref(minor))
1005 if res:
1006 return (major.value, minor.value)
1007 return None
1008
1009
1010def has_extension():
1011 """Returns True if the xrandr extension is available"""
1012 if XRANDR_VERSION:
1013 return True
1014 return False
1015
1016
1017def _to_gamma(gamma):
1018 g = rr.XRRAllocGamma(len(gamma[0]))
1019 for i in range(gamma[0]):
1020 g.red[i] = gamma[0][i]
1021 g.green[i] = gamma[1][i]
1022 g.blue[i] = gamma[2][i]
1023 return g
1024
1025
1026def _from_gamma(g):
1027 gamma = ([], [], [])
1028 for i in range(g.size):
1029 gamma[0].append(g.red[i])
1030 gamma[1].append(g.green[i])
1031 gamma[2].append(g.blue[i])
1032 rr.XRRFreeGamma(g)
1033
1034
1035def _check_required_version(version):
1036 """Raises an exception if the given or a later version of xrandr is not
1037 available"""
1038 if XRANDR_VERSION == None or XRANDR_VERSION < version:
1039 raise UnsupportedRRError(version, XRANDR_VERSION)
1040
1041
1042def get_mode_height(mode, rotation):
1043 """Return the height of the given mode taking the rotation into account"""
1044 if rotation & (RR_ROTATE_0 | RR_ROTATE_180):
1045 return mode.height
1046 elif rotation & (RR_ROTATE_90 | RR_ROTATE_270):
1047 return mode.width
1048 else:
1049 return 0
1050
1051
1052def get_mode_width(mode, rotation):
1053 """Return the width of the given mode taking the rotation into account"""
1054 if rotation & (RR_ROTATE_0 | RR_ROTATE_180):
1055 return mode.width
1056 elif rotation & (RR_ROTATE_90 | RR_ROTATE_270):
1057 return mode.height
1058 else:
1059 return 0
1060
1061
1062XRANDR_VERSION = get_version()
1063
1064# vim:ts=4:sw=4:et
01065
=== added directory 'checkbox-support/checkbox_support/dbus'
=== added file 'checkbox-support/checkbox_support/dbus/__init__.py'
--- checkbox-support/checkbox_support/dbus/__init__.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/dbus/__init__.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,89 @@
1# This file is part of Checkbox.
2#
3# Copyright 2012 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19#
20"""
21checkbox_support.dbus
22=============
23
24Utility modules for working with various things accessible over dbus
25"""
26
27import logging
28
29from dbus import SystemBus
30from dbus.mainloop.glib import DBusGMainLoop
31from dbus import (Array, Boolean, Byte, Dictionary, Double, Int16, Int32,
32 Int64, ObjectPath, String, Struct, UInt16, UInt32, UInt64)
33from gi.repository import GObject
34
35
36def connect_to_system_bus():
37 """
38 Connect to the system bus properly.
39
40 Returns a tuple (system_bus, loop) where loop is a GObject.MainLoop
41 instance. The loop is there so that you can listen to signals.
42 """
43 # We'll need an event loop to observe signals. We will need the instance
44 # later below so let's keep it. Note that we're not passing it directly
45 # below as DBus needs specific API. The DBusGMainLoop class that we
46 # instantiate and pass is going to work with this instance transparently.
47 #
48 # NOTE: DBus tutorial suggests that we should create the loop _before_
49 # connecting to the bus.
50 logging.debug("Setting up glib-based event loop")
51 loop = GObject.MainLoop()
52 # Let's get the system bus object. We need that to access UDisks2 object
53 logging.debug("Connecting to DBus system bus")
54 system_bus = SystemBus(mainloop=DBusGMainLoop())
55 return system_bus, loop
56
57
58def drop_dbus_type(value):
59 """
60 Convert types from the DBus bindings to their python counterparts.
61
62 This function is mostly lossless, except for arrays of bytes (DBus
63 signature "y") that are transparently converted to strings, assuming
64 an UTF-8 encoded string.
65
66 The point of this function is to simplify printing of nested DBus data that
67 gets displayed in a rather illegible way.
68 """
69 if isinstance(value, Array) and value.signature == "y":
70 # Some other things are reported as array of bytes that are just
71 # strings but due to Unix heritage the encoding is not known.
72 # In practice it is better to treat them as UTF-8 strings
73 return bytes(value).decode("UTF-8", "replace").strip("\0")
74 elif isinstance(value, (Struct, Array)):
75 return [drop_dbus_type(item) for item in value]
76 elif isinstance(value, (Dictionary)):
77 return {drop_dbus_type(dict_key): drop_dbus_type(dict_value)
78 for dict_key, dict_value in value.items()}
79 elif isinstance(value, (String, ObjectPath)):
80 return str(value)
81 elif isinstance(value, (Byte, UInt16, UInt32, UInt64,
82 Int16, Int32, Int64)):
83 return int(value)
84 elif isinstance(value, Boolean):
85 return bool(value)
86 elif isinstance(value, Double):
87 return float(value)
88 else:
89 return value
090
=== added file 'checkbox-support/checkbox_support/dbus/udisks2.py'
--- checkbox-support/checkbox_support/dbus/udisks2.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/dbus/udisks2.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,479 @@
1# Copyright 2012 Canonical Ltd.
2# Written by:
3# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3,
7# as published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17"""
18checkbox_support.dbus.udisks2
19=====================
20
21Module for working with UDisks2 from python.
22
23There are two main classes that are interesting here.
24
25The first class is UDisksObserver, which is easy to setup and has pythonic API
26to all of the stuff that happens in UDisks2. It offers simple signal handlers
27for any changes that occur in UDisks2 that were advertised by DBus.
28
29The second class is UDisksModel, that builds on the observer class to offer
30persistent collection of objects managed by UDisks2.
31
32To work with this model you will likely want to look at:
33 http://udisks.freedesktop.org/docs/latest/ref-dbus.html
34"""
35
36import logging
37
38from dbus import Interface, PROPERTIES_IFACE
39from dbus.exceptions import DBusException
40
41from checkbox_support.dbus import drop_dbus_type
42
43__all__ = ['UDisks2Observer', 'UDisks2Model', 'Signal', 'is_udisks2_supported',
44 'lookup_udev_device']
45
46
47def is_udisks2_supported(system_bus):
48 """
49 Check if udisks2 is available on the system bus.
50
51 ..note::
52 Calling this _may_ trigger activation of the UDisks2 daemon but it
53 should only happen on systems where it is already expected to run all
54 the time.
55 """
56 observer = UDisks2Observer()
57 try:
58 logging.debug("Trying to connect to UDisks2...")
59 observer.connect_to_bus(system_bus)
60 except DBusException as exc:
61 if exc.get_dbus_name() == "org.freedesktop.DBus.Error.ServiceUnknown":
62 logging.debug("No UDisks2 on the system bus")
63 return False
64 else:
65 raise
66 else:
67 logging.debug("Got UDisks2 connection")
68 return True
69
70
71def map_udisks1_connection_bus(udisks1_connection_bus):
72 """
73 Map the value of udisks1 ConnectionBus property to the corresponding values
74 in udisks2. This a lossy function as some values are no longer supported.
75
76 Incorrect values raise LookupError
77 """
78 return {
79 'ata_serial_esata': '', # gone from udisks2
80 'firewire': 'ieee1394', # renamed
81 'scsi': '', # gone from udisks2
82 'sdio': 'sdio', # as-is
83 'usb': 'usb', # as-is
84 }[udisks1_connection_bus]
85
86
87def lookup_udev_device(udisks2_object, udev_devices):
88 """
89 Find the udev_device that corresponds to the udisks2 object
90
91 Devices are matched by unix filesystem path of the special file (device).
92 The udisks2_object must implement the block device interface (so that the
93 block device path can be determined) or a ValueError is raised.
94
95 The udisks2_object must be the dictionary that maps from interface names to
96 dictionaries of properties. For compatible data see
97 UDisks2Model.managed_objects The udev_devices must be a list of udev
98 device, as returned from GUdev.
99
100 If there is no match, LookupError is raised with the unix block device
101 path.
102 """
103 try:
104 block_props = udisks2_object[UDISKS2_BLOCK_INTERFACE]
105 except KeyError:
106 raise ValueError("udisks2_object must be a block device")
107 else:
108 block_dev = block_props['Device']
109 for udev_device in udev_devices:
110 if udev_device.get_device_file() == block_dev:
111 return udev_device
112 raise LookupError(block_dev)
113
114
115# The well-known name for the ObjectManager interface, sadly it is not a part
116# of the python binding along with the rest of well-known names.
117OBJECT_MANAGER_INTERFACE = "org.freedesktop.DBus.ObjectManager"
118
119# The well-known name of the filesystem interface implemented by certain
120# objects exposed by UDisks2
121UDISKS2_FILESYSTEM_INTERFACE = "org.freedesktop.UDisks2.Filesystem"
122
123# The well-known name of the block (device) interface implemented by certain
124# objects exposed by UDisks2
125UDISKS2_BLOCK_INTERFACE = "org.freedesktop.UDisks2.Block"
126
127# The well-known name of the drive interface implemented by certain objects
128# exposed by UDisks2
129UDISKS2_DRIVE_INTERFACE = "org.freedesktop.UDisks2.Drive"
130
131
132class Signal:
133 """
134 Basic signal that supports arbitrary listeners.
135
136 While this class can be used directly it is best used with the helper
137 decorator Signal.define on a member function. The function body is ignored,
138 apart from the documentation.
139
140 The function name then becomes a unique (per encapsulating class instance)
141 object (an instance of this Signal class) that is created on demand.
142
143 In practice you just have a documentation and use
144 object.signal_name.connect() and object.signal_name(*args, **kwargs) to
145 fire it.
146 """
147
148 def __init__(self, signal_name):
149 """
150 Construct a signal with the given name
151 """
152 self._listeners = []
153 self._signal_name = signal_name
154
155 def connect(self, listener):
156 """
157 Connect a new listener to this signal
158
159 That listener will be called whenever fire() is invoked on the signal
160 """
161 self._listeners.append(listener)
162
163 def disconnect(self, listener):
164 """
165 Disconnect an existing listener from this signal
166 """
167 self._listeners.remove(listener)
168
169 def fire(self, args, kwargs):
170 """
171 Fire this signal with the specified arguments and keyword arguments.
172
173 Typically this is used by using __call__() on this object which is more
174 natural as it does all the argument packing/unpacking transparently.
175 """
176 for listener in self._listeners:
177 listener(*args, **kwargs)
178
179 def __call__(self, *args, **kwargs):
180 """
181 Call fire() with all arguments forwarded transparently
182 """
183 self.fire(args, kwargs)
184
185 @classmethod
186 def define(cls, dummy_func):
187 """
188 Helper decorator to define a signal descriptor in a class
189
190 The decorated function is never called but is used to get
191 documentation.
192 """
193 return _SignalDescriptor(dummy_func)
194
195
196class _SignalDescriptor:
197 """
198 Descriptor for convenient signal access.
199
200 Typically this class is used indirectly, when accessed from Signal.define
201 method decorator. It is used to do all the magic required when accessing
202 signal name on a class or instance.
203 """
204
205 def __init__(self, dummy_func):
206 self.signal_name = dummy_func.__name__
207 self.__doc__ = dummy_func.__doc__
208
209 def __repr__(self):
210 return "<SignalDecorator for signal: %r>" % self.signal_name
211
212 def __get__(self, instance, owner):
213 if instance is None:
214 return self
215 # Ensure that the instance has __signals__ property
216 if not hasattr(instance, "__signals__"):
217 instance.__signals__ = {}
218 if self.signal_name not in instance.__signals__:
219 instance.__signals__[self.signal_name] = Signal(self.signal_name)
220 return instance.__signals__[self.signal_name]
221
222 def __set__(self, instance, value):
223 raise AttributeError("You cannot overwrite signals")
224
225 def __delete__(self, instance):
226 raise AttributeError("You cannot delete signals")
227
228
229class UDisks2Observer:
230 """
231 Class for observing ongoing changes in UDisks2
232 """
233
234 def __init__(self):
235 """
236 Create a UDisks2 model.
237
238 The model must be connected to a bus before it is first used, see
239 connect()
240 """
241 # Proxy to the UDisks2 object
242 self._udisks2_obj = None
243 # Proxy to the ObjectManager interface exposed by UDisks2 object
244 self._udisks2_obj_manager = None
245
246 @Signal.define
247 def on_initial_objects(self, managed_objects):
248 """
249 Signal fired when the initial list of objects becomes available
250 """
251
252 @Signal.define
253 def on_interfaces_added(self, object_path, interfaces_and_properties):
254 """
255 Signal fired when one or more interfaces gets added to a specific
256 object.
257 """
258
259 @Signal.define
260 def on_interfaces_removed(self, object_path, interfaces):
261 """
262 Signal fired when one or more interface gets removed from a specific
263 object
264 """
265
266 @Signal.define
267 def on_properties_changed(self, interface_name, changed_properties,
268 invalidated_properties, sender=None):
269 """
270 Signal fired when one or more property changes value or becomes
271 invalidated.
272 """
273
274 def connect_to_bus(self, bus):
275 """
276 Establish initial connection to UDisks2 on the specified DBus bus.
277
278 This will also load the initial set of objects from UDisks2 and thus
279 fire the on_initial_objects() signal from the model. Please call this
280 method only after connecting that signal if you want to observe that
281 event.
282 """
283 # Once everything is ready connect to udisks2
284 self._connect_to_udisks2(bus)
285 # And read all the initial objects and setup
286 # change event handlers
287 self._get_initial_objects()
288
289 def _connect_to_udisks2(self, bus):
290 """
291 Setup the initial connection to UDisks2
292
293 This step can fail if UDisks2 is not available and cannot be
294 service-activated.
295 """
296 # Access the /org/freedesktop/UDisks2 object sitting on the
297 # org.freedesktop.UDisks2 bus name. This will trigger the necessary
298 # activation if udisksd is not running for any reason
299 logging.debug("Accessing main UDisks2 object")
300 self._udisks2_obj = bus.get_object(
301 "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2")
302 # Now extract the standard ObjectManager interface so that we can
303 # observe and iterate the collection of objects that UDisks2 provides.
304 logging.debug("Accessing ObjectManager interface on UDisks2 object")
305 self._udisks2_obj_manager = Interface(
306 self._udisks2_obj, OBJECT_MANAGER_INTERFACE)
307 # Connect to the PropertiesChanged signal. Here unlike before we want
308 # to listen to all signals, regardless of who was sending them in the
309 # first place.
310 logging.debug("Setting up DBus signal handler for PropertiesChanged")
311 bus.add_signal_receiver(
312 self._on_properties_changed,
313 signal_name="PropertiesChanged",
314 dbus_interface=PROPERTIES_IFACE,
315 # Use the sender_keyword keyword argument to indicate that we wish
316 # to know the sender of each signal. For consistency with other
317 # signals we choose to use the 'object_path' keyword argument.
318 sender_keyword='sender')
319
320 def _get_initial_objects(self):
321 """
322 Get the initial collection of objects.
323
324 Needs to be called before the first signals from DBus are observed.
325 Requires a working connection to UDisks2.
326 """
327 # Having this interface we can now peek at the existing objects.
328 # We can use the standard method GetManagedObjects() to do that
329 logging.debug("Accessing GetManagedObjects() on UDisks2 object")
330 managed_objects = self._udisks2_obj_manager.GetManagedObjects()
331 managed_objects = drop_dbus_type(managed_objects)
332 # Fire the public signal for getting initial objects
333 self.on_initial_objects(managed_objects)
334 # Connect our internal handles to the DBus signal handlers
335 logging.debug("Setting up DBus signal handler for InterfacesAdded")
336 self._udisks2_obj_manager.connect_to_signal(
337 "InterfacesAdded", self._on_interfaces_added)
338 logging.debug("Setting up DBus signal handler for InterfacesRemoved")
339 self._udisks2_obj_manager.connect_to_signal(
340 "InterfacesRemoved", self._on_interfaces_removed)
341
342 def _on_interfaces_added(self, object_path, interfaces_and_properties):
343 """
344 Internal callback that is called by DBus
345
346 This function is responsible for firing the public signal
347 """
348 # Convert from dbus types
349 object_path = drop_dbus_type(object_path)
350 interfaces_and_properties = drop_dbus_type(interfaces_and_properties)
351 # Log what's going on
352 logging.debug("The object %r has gained the following interfaces and "
353 "properties: %r", object_path, interfaces_and_properties)
354 # Call the signal handler
355 self.on_interfaces_added(object_path, interfaces_and_properties)
356
357 def _on_interfaces_removed(self, object_path, interfaces):
358 """
359 Internal callback that is called by DBus
360
361 This function is responsible for firing the public signal
362 """
363 # Convert from dbus types
364 object_path = drop_dbus_type(object_path)
365 interfaces = drop_dbus_type(interfaces)
366 # Log what's going on
367 logging.debug("The object %r has lost the following interfaces: %r",
368 object_path, interfaces)
369 # Call the signal handler
370 self.on_interfaces_removed(object_path, interfaces)
371
372 def _on_properties_changed(self, interface_name, changed_properties,
373 invalidated_properties, sender=None):
374 """
375 Internal callback that is called by DBus
376
377 This function is responsible for firing the public signal
378 """
379 # Convert from dbus types
380 interface_name = drop_dbus_type(interface_name)
381 changed_properties = drop_dbus_type(changed_properties)
382 invalidated_properties = drop_dbus_type(invalidated_properties)
383 sender = drop_dbus_type(sender)
384 # Log what's going on
385 logging.debug("Some object with the interface %r has changed "
386 "properties: %r and invalidated properties %r "
387 "(sender: %s)",
388 interface_name, changed_properties,
389 invalidated_properties, sender)
390 # Call the signal handler
391 self.on_properties_changed(interface_name, changed_properties,
392 invalidated_properties, sender)
393
394
395class UDisks2Model:
396 """
397 Model for working with UDisks2
398
399 This class maintains a persistent model of what UDisks2 knows about, based
400 on the UDisks2Observer class and the signals it offers.
401 """
402
403 def __init__(self, observer):
404 """
405 Create a UDisks2 model.
406
407 The model will track changes using the specified observer (which is
408 expected to be a UDisks2Observer instance)
409
410 You should only connect the observer to the bus after creating the
411 model otherwise the initial objects will not be detected.
412 """
413 # Local state, everything that UDisks2 tells us
414 self._managed_objects = {}
415 self._observer = observer
416 # Connect all the signals to the observer
417 self._observer.on_initial_objects.connect(self._on_initial_objects)
418 self._observer.on_interfaces_added.connect(self._on_interfaces_added)
419 self._observer.on_interfaces_removed.connect(
420 self._on_interfaces_removed)
421 self._observer.on_properties_changed.connect(
422 self._on_properties_changed)
423
424 @Signal.define
425 def on_change(self):
426 """
427 Signal sent whenever the collection of managed object changes
428
429 Note that this signal is fired _after_ the change has occurred
430 """
431
432 @property
433 def managed_objects(self):
434 """
435 A collection of objects that is managed by this model. All changes as
436 well as the initial state, are reflected here.
437 """
438 return self._managed_objects
439
440 def _on_initial_objects(self, managed_objects):
441 """
442 Internal callback called when we get the initial collection of objects
443 """
444 self._managed_objects = drop_dbus_type(managed_objects)
445
446 def _on_interfaces_added(self, object_path, interfaces_and_properties):
447 """
448 Internal callback called when an interface is added to certain object
449 """
450 # Update internal state
451 if object_path not in self._managed_objects:
452 self._managed_objects[object_path] = {}
453 obj = self._managed_objects[object_path]
454 obj.update(interfaces_and_properties)
455 # Fire the change signal
456 self.on_change()
457
458 def _on_interfaces_removed(self, object_path, interfaces):
459 """
460 Internal callback called when an interface is removed from a certain
461 object
462 """
463 # Update internal state
464 if object_path in self._managed_objects:
465 obj = self._managed_objects[object_path]
466 for interface in interfaces:
467 if interface in obj:
468 del obj[interface]
469 # Fire the change signal
470 self.on_change()
471
472 def _on_properties_changed(self, interface_name, changed_properties,
473 invalidated_properties, sender=None):
474 # XXX: This is a workaround the fact that we cannot
475 # properly track changes to all properties :-(
476 self._managed_objects = drop_dbus_type(
477 self._observer._udisks2_obj_manager.GetManagedObjects())
478 # Fire the change signal()
479 self.on_change()
0480
=== added directory 'checkbox-support/checkbox_support/heuristics'
=== added file 'checkbox-support/checkbox_support/heuristics/__init__.py'
--- checkbox-support/checkbox_support/heuristics/__init__.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/heuristics/__init__.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,56 @@
1# This file is part of Checkbox.
2#
3# Copyright 2012 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21checkbox_support.heuristics
22===================
23
24This module contains implementations behind various heuristics used throughout
25the code. The intent of this module is twofold:
26
27 1) To encourage code reuse so that developers can use one implementation of
28 "guesswork" that is sometimes needed in our test. This reduces duplicate
29 bugs where many scripts do similar things in a different way.
30
31 2) To identify missing features in plumbing layer APIs such as
32 udev/udisks/dbus etc. Ideally no program should have to guess this, the
33 plumbing layer should be able to provide this meta data to allow
34 application developers deliver consistent behavior across userspace.
35
36Heuristics should be reusable from both python and shell. To make that possible
37each heuristics needs to be constrained to serializable input and output. This
38levels the playing field and allows both shell developers and python developers
39to reuse the same function.
40
41Additionally heuristics should try to avoid accessing thick APIs (such as
42objects returned by various libraries. This is meant to decrease the likelihood
43that updates to those libraries break this code. As an added side effect this
44also should make the implementation more explicit and easier to understand.
45
46In the long term each heuristic should be discussed with upstream developers of
47the particular problem area (udev, udisks, etc) to see if that subsystem can
48provide the required information directly, without us having to guess and fill
49the gaps.
50
51Things to consider when adding entries to this package:
52
53 1) File a bug on the upstream package about missing feature.
54
55 2) File a bug on checkbox to de-duplicate similar heuristics
56"""
057
=== added directory 'checkbox-support/checkbox_support/heuristics/tests'
=== added file 'checkbox-support/checkbox_support/heuristics/tests/__init__.py'
=== added file 'checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py'
--- checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,40 @@
1# This file is part of Checkbox.
2#
3# Copyright 2012 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21
22checkbox_support.heuristics.tests.test_udisks2
23======================================
24
25Unit tests for checkbox_support.heuristics.udisks2 module
26"""
27
28from unittest import TestCase
29
30from checkbox_support.heuristics.udisks2 import is_memory_card
31
32
33class TestIsMemoryCard(TestCase):
34
35 def test_generic(self):
36 """
37 Device with vendor string "GENERIC" is a memory card
38 """
39 self.assertTrue(
40 is_memory_card(vendor="Generic", model="", udisks2_media=None))
041
=== added file 'checkbox-support/checkbox_support/heuristics/udev.py'
--- checkbox-support/checkbox_support/heuristics/udev.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/heuristics/udev.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,44 @@
1# This file is part of Checkbox.
2#
3# Copyright 2012 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21checkbox_support.heuristics.dev
22=======================
23
24Heuristics for udev.
25
26 Documentation: http://udisks.freedesktop.org/docs/latest/
27 Source code: http://cgit.freedesktop.org/systemd/systemd/ (src/udev)
28 Bug tracker: http://bugs.freedesktop.org/ (using systemd product)
29"""
30
31
32def is_virtual_device(device_file):
33 """
34 Given a device name like /dev/ramX, /dev/sdX or /dev/loopX determine if
35 this is a virtual device. Virtual devices are typically uninteresting to
36 users. The only exception may be nonempty loopback device.
37
38 Possible prior art: gnome-disks, palimpset (precursor, suffering from this
39 flaw and showing all the /dev/ram devices by default)
40 """
41 for part in device_file.split("/"):
42 if part.startswith("ram") or part.startswith("loop"):
43 return True
44 return False
045
=== added file 'checkbox-support/checkbox_support/heuristics/udisks2.py'
--- checkbox-support/checkbox_support/heuristics/udisks2.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/heuristics/udisks2.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,62 @@
1# This file is part of Checkbox.
2#
3# Copyright 2012 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21checkbox_support.heuristics.udisks2
22===========================
23
24Heuristics for udisks2.
25
26 Documentation: http://udisks.freedesktop.org/docs/latest/
27 Source code: http://cgit.freedesktop.org/systemd/systemd/ (src/udev)
28 Bug tracker: http://bugs.freedesktop.org/ (using systemd product)
29"""
30
31from checkbox_support.parsers.udevadm import CARD_READER_RE, GENERIC_RE, FLASH_RE
32
33
34def is_memory_card(vendor, model, udisks2_media):
35 """
36 Check if the device seems to be a memory card
37
38 The vendor and model arguments are _strings_, not integers.
39 The udisks2_media argument is the value of org.freedesktop.UDisks2.Drive/
40
41
42 This is rather fuzzy, sadly udev and udisks2 don't do a very good job and
43 mostly don't specify the "media" property (it has a few useful values, such
44 as flash_cf, flash_ms, flash_sm, flash_sd, flash_sdhc, flash_sdxc and
45 flash_mmc but I have yet to see a device that reports such values)
46 """
47 # Treat any udisks2_media that contains 'flash' as a memory card
48 if udisks2_media is not None and FLASH_RE.search(udisks2_media):
49 return True
50 # Treat any device that match model name to the following regular
51 # expression as a memory card reader.
52 if CARD_READER_RE.search(model):
53 return True
54 # Treat any device that contains the word 'Generic' in the vendor string as
55 # a memory card reader.
56 #
57 # XXX: This seems odd but strangely enough seems to gets the job done. I
58 # guess if I should start filing tons of bugs/patches on udev/udisks2 to
59 # just have a few more rules and make this rule obsolete.
60 if GENERIC_RE.search(vendor):
61 return True
62 return False
063
=== added directory 'checkbox-support/checkbox_support/lib'
=== added file 'checkbox-support/checkbox_support/lib/__init__.py'
=== added file 'checkbox-support/checkbox_support/lib/bit.py'
--- checkbox-support/checkbox_support/lib/bit.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/bit.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,46 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19from struct import calcsize
20
21
22def get_bitmask(key):
23 bitmask = []
24 for value in reversed(key.split()):
25 value = int(value, 16)
26 bitmask.append(value)
27
28 return bitmask
29
30def get_bitcount(bitmask):
31 bitcount = 0
32 for value in bitmask:
33 while value:
34 bitcount += 1
35 value &= (value - 1)
36
37 return bitcount
38
39def test_bit(bit, bitmask, bits=None):
40 if bits is None:
41 bits = calcsize("l") * 8
42 offset = bit % bits
43 long = int(bit / bits)
44 if long >= len(bitmask):
45 return 0
46 return (bitmask[long] >> offset) & 1
047
=== added file 'checkbox-support/checkbox_support/lib/conversion.py'
--- checkbox-support/checkbox_support/lib/conversion.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/conversion.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,172 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21from datetime import (
22 datetime,
23 timedelta,
24 )
25
26from checkbox_support.lib.tz import tzutc
27
28
29DATETIME_RE = re.compile(r"""
30 ^(?P<year>\d\d\d\d)-?(?P<month>\d\d)-?(?P<day>\d\d)
31 T(?P<hour>\d\d):?(?P<minute>\d\d):?(?P<second>\d\d)
32 (?:\.(?P<second_fraction>\d{0,6}))?
33 (?P<tz>
34 (?:(?P<tz_sign>[-+])(?P<tz_hour>\d\d):(?P<tz_minute>\d\d))
35 | Z)?$
36 """, re.VERBOSE)
37
38TYPE_FORMATS = (
39 (r"(yes|true)", lambda v: True),
40 (r"(no|false)", lambda v: False),
41 (r"-?\d+", lambda v: int(v.group(0))),
42 (r"-?\d+\.\d+", lambda v: float(v.group(0))),
43 (r"(-?\d+) ?([kmgt]?b?)", lambda v: int(v.group(1))),
44 (r"(-?\d+\.\d+) ?([kmgt]?b?)", lambda v: float(v.group(1))),
45 (r"(-?\d+) ?([kmgt]?hz)", lambda v: int(v.group(1))),
46 (r"(-?\d+\.\d+) ?([kmgt]?hz)", lambda v: float(v.group(1))))
47TYPE_FORMATS = tuple(
48 (re.compile(r"^%s$" % pattern, re.IGNORECASE), format)
49 for pattern, format in TYPE_FORMATS)
50
51TYPE_MULTIPLIERS = (
52 (r"b", 1),
53 (r"kb?", 1024),
54 (r"mb?", 1024 * 1024),
55 (r"gb?", 1024 * 1024 * 1024),
56 (r"tb?", 1024 * 1024 * 1024 * 1024),
57 (r"hz", 1),
58 (r"khz?", 1024),
59 (r"mhz?", 1024 * 1024),
60 (r"ghz?", 1024 * 1024 * 1024),
61 (r"thz?", 1024 * 1024 * 1024 * 1024))
62TYPE_MULTIPLIERS = tuple(
63 (re.compile(r"^%s$" % pattern, re.IGNORECASE), multiplier)
64 for pattern, multiplier in TYPE_MULTIPLIERS)
65
66
67def datetime_to_string(dt):
68 """Return a consistent string representation for a given datetime.
69
70 :param dt: The datetime object.
71 """
72 return dt.isoformat()
73
74
75def string_to_datetime(string):
76 """Return a datetime object from a consistent string representation.
77
78 :param string: The string representation.
79 """
80 # we cannot use time.strptime: this function accepts neither fractions
81 # of a second nor a time zone given e.g. as '+02:30'.
82 match = DATETIME_RE.match(string)
83
84 # The Relax NG schema allows a leading minus sign and year numbers
85 # with more than four digits, which are not "covered" by _time_regex.
86 if not match:
87 raise ValueError("Datetime with unreasonable value: %s" % string)
88
89 time_parts = match.groupdict()
90
91 year = int(time_parts['year'])
92 month = int(time_parts['month'])
93 day = int(time_parts['day'])
94 hour = int(time_parts['hour'])
95 minute = int(time_parts['minute'])
96 second = int(time_parts['second'])
97 second_fraction = time_parts['second_fraction']
98 if second_fraction is not None:
99 milliseconds = second_fraction + '0' * (6 - len(second_fraction))
100 milliseconds = int(milliseconds)
101 else:
102 milliseconds = 0
103
104 # The Relax NG validator accepts leap seconds, but the datetime
105 # constructor rejects them. The time values submitted by the HWDB
106 # client are not necessarily very precise, hence we can round down
107 # to 59.999999 seconds without losing any real precision.
108 if second > 59:
109 second = 59
110 milliseconds = 999999
111
112 dt = datetime(
113 year, month, day, hour, minute, second, milliseconds, tzinfo=tzutc)
114
115 tz_sign = time_parts['tz_sign']
116 tz_hour = time_parts['tz_hour']
117 tz_minute = time_parts['tz_minute']
118 if tz_sign in ('-', '+'):
119 delta = timedelta(hours=int(tz_hour), minutes=int(tz_minute))
120 if tz_sign == '-':
121 dt = dt + delta
122 else:
123 dt = dt - delta
124
125 return dt
126
127
128def sizeof_bytes(bytes):
129 for x in ["bytes", "KB", "MB", "GB", "TB"]:
130 string = "%3.1f%s" % (bytes, x)
131 if bytes < 1024.0:
132 break
133 bytes /= 1024.0
134
135 return string
136
137
138def sizeof_hertz(hertz):
139 for x in ["Hz", "KHz", "MHz", "GHz"]:
140 string = "%3.1f%s" % (hertz, x)
141 if hertz < 1000.0:
142 break
143 hertz /= 1000.0
144
145 return string
146
147
148def string_to_type(string):
149 """Return a typed representation for the given string.
150
151 The result might be a bool, int or float. The string might also be
152 supplemented by a multiplier like KB which would return an int or
153 float multiplied by 1024 for example.
154
155 :param string: The string representation.
156 """
157 for regex, formatter in TYPE_FORMATS:
158 match = regex.match(string)
159 if match:
160 string = formatter(match)
161 if len(match.groups()) > 1:
162 unit = match.group(2)
163 for regex, multiplier in TYPE_MULTIPLIERS:
164 match = regex.match(unit)
165 if match:
166 string *= multiplier
167 break
168 else:
169 raise ValueError("Unknown multiplier: %s" % unit)
170 break
171
172 return string
0173
=== added file 'checkbox-support/checkbox_support/lib/dmi.py'
--- checkbox-support/checkbox_support/lib/dmi.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/dmi.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,241 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import os
20
21from checkbox_support.lib.conversion import string_to_type
22
23# See also 3.3.4.1 of the "System Management BIOS Reference Specification,
24# Version 2.6.1" (Preliminary Standard) document, available from
25# http://www.dmtf.org/standards/smbios.
26class Dmi:
27 chassis = (
28 ("Undefined", "unknown"), # 0x00
29 ("Other", "unknown"),
30 ("Unknown", "unknown"),
31 ("Desktop", "desktop"),
32 ("Low Profile Desktop", "desktop"),
33 ("Pizza Box", "server"),
34 ("Mini Tower", "desktop"),
35 ("Tower", "desktop"),
36 ("Portable", "laptop"),
37 ("Laptop", "laptop"),
38 ("Notebook", "laptop"),
39 ("Hand Held", "handheld"),
40 ("Docking Station", "laptop"),
41 ("All In One", "unknown"),
42 ("Sub Notebook", "laptop"),
43 ("Space-saving", "desktop"),
44 ("Lunch Box", "unknown"),
45 ("Main Server Chassis", "server"),
46 ("Expansion Chassis", "unknown"),
47 ("Sub Chassis", "unknown"),
48 ("Bus Expansion Chassis", "unknown"),
49 ("Peripheral Chassis", "unknown"),
50 ("RAID Chassis", "unknown"),
51 ("Rack Mount Chassis", "unknown"),
52 ("Sealed-case PC", "unknown"),
53 ("Multi-system", "unknown"),
54 ("CompactPCI", "unknonw"),
55 ("AdvancedTCA", "unknown"),
56 ("Blade", "server"),
57 ("Blade Enclosure", "unknown"))
58
59 chassis_names = tuple(c[0] for c in chassis)
60 chassis_types = tuple(c[1] for c in chassis)
61 chassis_name_to_type = dict(chassis)
62
63 type_names = (
64 "BIOS", # 0x00
65 "System",
66 "Base Board",
67 "Chassis",
68 "Processor",
69 "Memory Controller",
70 "Memory Module",
71 "Cache",
72 "Port Connector",
73 "System Slots",
74 "On Board Devices",
75 "OEM Strings",
76 "System Configuration Options",
77 "BIOS Language",
78 "Group Associations",
79 "System Event Log",
80 "Physical Memory Array",
81 "Memory Device",
82 "32-bit Memory Error",
83 "Memory Array Mapped Address",
84 "Memory Device Mapped Address",
85 "Built-in Pointing Device",
86 "Portable Battery",
87 "System Reset",
88 "Hardware Security",
89 "System Power Controls",
90 "Voltage Probe",
91 "Cooling Device",
92 "Temperature Probe",
93 "Electrical Current Probe",
94 "Out-of-band Remote Access",
95 "Boot Integrity Services",
96 "System Boot",
97 "64-bit Memory Error",
98 "Management Device",
99 "Management Device Component",
100 "Management Device Threshold Data",
101 "Memory Channel",
102 "IPMI Device",
103 "Power Supply",
104 )
105
106
107class DmiDevice:
108
109 bus = "dmi"
110 driver = None
111 product_id = None
112 vendor_id = None
113
114 _product_blacklist = (
115 "<BAD INDEX>",
116 "N/A",
117 "Not Available",
118 "INVALID",
119 "OEM",
120 "Product Name",
121 "System Product Name",
122 "To be filled by O.E.M.",
123 "To Be Filled By O.E.M.",
124 "To Be Filled By O.E.M. by More String",
125 "Unknown",
126 "Uknown",
127 "Unknow",
128 "xxxxxxxxxxxxxx",
129 )
130 _vendor_blacklist = (
131 "<BAD INDEX>",
132 "Not Available",
133 "OEM",
134 "OEM Manufacturer",
135 "System manufacturer",
136 "System Manufacturer",
137 "System Name",
138 "To be filled by O.E.M.",
139 "To Be Filled By O.E.M.",
140 "To Be Filled By O.E.M. by More String",
141 "Unknow", # XXX This is correct mispelling
142 "Unknown",
143 )
144 _serial_blacklist = (
145 "0",
146 "00000000",
147 "00 00 00 00 00 00 00 00",
148 "0123456789",
149 "Base Board Serial Number",
150 "Chassis Serial Number",
151 "N/A",
152 "None",
153 "Not Applicable",
154 "Not Available",
155 "Not Specified",
156 "OEM",
157 "System Serial Number",
158 )
159 _version_blacklist = (
160 "-1",
161 "<BAD INDEX>",
162 "N/A",
163 "None",
164 "Not Applicable",
165 "Not Available",
166 "Not Specified",
167 "OEM",
168 "System Version",
169 "Unknown",
170 "x.x",
171 )
172
173 def __init__(self, attributes, category):
174 self._attributes = attributes
175 self.category = category
176
177 @property
178 def path(self):
179 path = "/devices/virtual/dmi/id"
180 return os.path.join(path, self.category.lower())
181
182 @property
183 def product(self):
184 if self.category == "CHASSIS":
185 type_string = self._attributes.get("chassis_type", "0")
186 try:
187 type_index = int(type_string)
188 return Dmi.chassis_names[type_index]
189 except ValueError:
190 return type_string
191
192 for name in "name", "version":
193 attribute = "%s_%s" % (self.category.lower(), name)
194 product = self._attributes.get(attribute)
195 if product and product not in self._product_blacklist:
196 return product
197
198 return None
199
200 @property
201 def vendor(self):
202 for name in "manufacturer", "vendor":
203 attribute = "%s_%s" % (self.category.lower(), name)
204 vendor = self._attributes.get(attribute)
205 if vendor and vendor not in self._vendor_blacklist:
206 return vendor
207
208 return None
209
210 @property
211 def serial(self):
212 attribute = "%s_serial" % self.category.lower()
213 serial = self._attributes.get(attribute)
214 if serial and serial not in self._serial_blacklist:
215 return serial
216
217 return None
218
219 @property
220 def version(self):
221 attribute = "%s_version" % self.category.lower()
222 version = self._attributes.get(attribute)
223 if version and version not in self._version_blacklist:
224 return version
225
226 return None
227
228 @property
229 def size(self):
230 attribute = "%s_size" % self.category.lower()
231 size = self._attributes.get(attribute)
232
233 if size:
234 size = string_to_type(size)
235
236 return size
237
238 @property
239 def form(self):
240 attribute = "%s_form" % self.category.lower()
241 return self._attributes.get(attribute)
0242
=== added file 'checkbox-support/checkbox_support/lib/input.py'
--- checkbox-support/checkbox_support/lib/input.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/input.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,585 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19
20# See linux/input.h
21class Input:
22 KEY_RESERVED = 0
23 KEY_ESC = 1
24 KEY_1 = 2
25 KEY_2 = 3
26 KEY_3 = 4
27 KEY_4 = 5
28 KEY_5 = 6
29 KEY_6 = 7
30 KEY_7 = 8
31 KEY_8 = 9
32 KEY_9 = 10
33 KEY_0 = 11
34 KEY_MINUS = 12
35 KEY_EQUAL = 13
36 KEY_BACKSPACE = 14
37 KEY_TAB = 15
38 KEY_Q = 16
39 KEY_W = 17
40 KEY_E = 18
41 KEY_R = 19
42 KEY_T = 20
43 KEY_Y = 21
44 KEY_U = 22
45 KEY_I = 23
46 KEY_O = 24
47 KEY_P = 25
48 KEY_LEFTBRACE = 26
49 KEY_RIGHTBRACE = 27
50 KEY_ENTER = 28
51 KEY_LEFTCTRL = 29
52 KEY_A = 30
53 KEY_S = 31
54 KEY_D = 32
55 KEY_F = 33
56 KEY_G = 34
57 KEY_H = 35
58 KEY_J = 36
59 KEY_K = 37
60 KEY_L = 38
61 KEY_SEMICOLON = 39
62 KEY_APOSTROPHE = 40
63 KEY_GRAVE = 41
64 KEY_LEFTSHIFT = 42
65 KEY_BACKSLASH = 43
66 KEY_Z = 44
67 KEY_X = 45
68 KEY_C = 46
69 KEY_V = 47
70 KEY_B = 48
71 KEY_N = 49
72 KEY_M = 50
73 KEY_COMMA = 51
74 KEY_DOT = 52
75 KEY_SLASH = 53
76 KEY_RIGHTSHIFT = 54
77 KEY_KPASTERISK = 55
78 KEY_LEFTALT = 56
79 KEY_SPACE = 57
80 KEY_CAPSLOCK = 58
81 KEY_F1 = 59
82 KEY_F2 = 60
83 KEY_F3 = 61
84 KEY_F4 = 62
85 KEY_F5 = 63
86 KEY_F6 = 64
87 KEY_F7 = 65
88 KEY_F8 = 66
89 KEY_F9 = 67
90 KEY_F10 = 68
91 KEY_NUMLOCK = 69
92 KEY_SCROLLLOCK = 70
93 KEY_KP7 = 71
94 KEY_KP8 = 72
95 KEY_KP9 = 73
96 KEY_KPMINUS = 74
97 KEY_KP4 = 75
98 KEY_KP5 = 76
99 KEY_KP6 = 77
100 KEY_KPPLUS = 78
101 KEY_KP1 = 79
102 KEY_KP2 = 80
103 KEY_KP3 = 81
104 KEY_KP0 = 82
105 KEY_KPDOT = 83
106
107 KEY_ZENKAKUHANKAKU = 85
108 KEY_102ND = 86
109 KEY_F11 = 87
110 KEY_F12 = 88
111 KEY_RO = 89
112 KEY_KATAKANA = 90
113 KEY_HIRAGANA = 91
114 KEY_HENKAN = 92
115 KEY_KATAKANAHIRAGANA = 93
116 KEY_MUHENKAN = 94
117 KEY_KPJPCOMMA = 95
118 KEY_KPENTER = 96
119 KEY_RIGHTCTRL = 97
120 KEY_KPSLASH = 98
121 KEY_SYSRQ = 99
122 KEY_RIGHTALT = 100
123 KEY_LINEFEED = 101
124 KEY_HOME = 102
125 KEY_UP = 103
126 KEY_PAGEUP = 104
127 KEY_LEFT = 105
128 KEY_RIGHT = 106
129 KEY_END = 107
130 KEY_DOWN = 108
131 KEY_PAGEDOWN = 109
132 KEY_INSERT = 110
133 KEY_DELETE = 111
134 KEY_MACRO = 112
135 KEY_MUTE = 113
136 KEY_VOLUMEDOWN = 114
137 KEY_VOLUMEUP = 115
138 KEY_POWER = 116 # SC System Power Down
139 KEY_KPEQUAL = 117
140 KEY_KPPLUSMINUS = 118
141 KEY_PAUSE = 119
142 KEY_SCALE = 120 # AL Compiz Scale (Expose)
143
144 KEY_KPCOMMA = 121
145 KEY_HANGEUL = 122
146 KEY_HANGUEL = KEY_HANGEUL
147 KEY_HANJA = 123
148 KEY_YEN = 124
149 KEY_LEFTMETA = 125
150 KEY_RIGHTMETA = 126
151 KEY_COMPOSE = 127
152
153 KEY_STOP = 128 # AC Stop
154 KEY_AGAIN = 129
155 KEY_PROPS = 130 # AC Properties
156 KEY_UNDO = 131 # AC Undo
157 KEY_FRONT = 132
158 KEY_COPY = 133 # AC Copy
159 KEY_OPEN = 134 # AC Open
160 KEY_PASTE = 135 # AC Paste
161 KEY_FIND = 136 # AC Search
162 KEY_CUT = 137 # AC Cut
163 KEY_HELP = 138 # AL Integrated Help Center
164 KEY_MENU = 139 # Menu (show menu)
165 KEY_CALC = 140 # AL Calculator
166 KEY_SETUP = 141
167 KEY_SLEEP = 142 # SC System Sleep
168 KEY_WAKEUP = 143 # System Wake Up
169 KEY_FILE = 144 # AL Local Machine Browser
170 KEY_SENDFILE = 145
171 KEY_DELETEFILE = 146
172 KEY_XFER = 147
173 KEY_PROG1 = 148
174 KEY_PROG2 = 149
175 KEY_WWW = 150 # AL Internet Browser
176 KEY_MSDOS = 151
177 KEY_COFFEE = 152 # AL Terminal Lock/Screensaver
178 KEY_SCREENLOCK = KEY_COFFEE
179 KEY_DIRECTION = 153
180 KEY_CYCLEWINDOWS = 154
181 KEY_MAIL = 155
182 KEY_BOOKMARKS = 156 # AC Bookmarks
183 KEY_COMPUTER = 157
184 KEY_BACK = 158 # AC Back
185 KEY_FORWARD = 159 # AC Forward
186 KEY_CLOSECD = 160
187 KEY_EJECTCD = 161
188 KEY_EJECTCLOSECD = 162
189 KEY_NEXTSONG = 163
190 KEY_PLAYPAUSE = 164
191 KEY_PREVIOUSSONG = 165
192 KEY_STOPCD = 166
193 KEY_RECORD = 167
194 KEY_REWIND = 168
195 KEY_PHONE = 169 # Media Select Telephone
196 KEY_ISO = 170
197 KEY_CONFIG = 171 # AL Consumer Control Configuration
198 KEY_HOMEPAGE = 172 # AC Home
199 KEY_REFRESH = 173 # AC Refresh
200 KEY_EXIT = 174 # AC Exit
201 KEY_MOVE = 175
202 KEY_EDIT = 176
203 KEY_SCROLLUP = 177
204 KEY_SCROLLDOWN = 178
205 KEY_KPLEFTPAREN = 179
206 KEY_KPRIGHTPAREN = 180
207 KEY_NEW = 181 # AC New
208 KEY_REDO = 182 # AC Redo/Repeat
209
210 KEY_F13 = 183
211 KEY_F14 = 184
212 KEY_F15 = 185
213 KEY_F16 = 186
214 KEY_F17 = 187
215 KEY_F18 = 188
216 KEY_F19 = 189
217 KEY_F20 = 190
218 KEY_F21 = 191
219 KEY_F22 = 192
220 KEY_F23 = 193
221 KEY_F24 = 194
222
223 KEY_PLAYCD = 200
224 KEY_PAUSECD = 201
225 KEY_PROG3 = 202
226 KEY_PROG4 = 203
227 KEY_DASHBOARD = 204 # AL Dashboard
228 KEY_SUSPEND = 205
229 KEY_CLOSE = 206 # AC Close
230 KEY_PLAY = 207
231 KEY_FASTFORWARD = 208
232 KEY_BASSBOOST = 209
233 KEY_PRINT = 210 # AC Print
234 KEY_HP = 211
235 KEY_CAMERA = 212
236 KEY_SOUND = 213
237 KEY_QUESTION = 214
238 KEY_EMAIL = 215
239 KEY_CHAT = 216
240 KEY_SEARCH = 217
241 KEY_CONNECT = 218
242 KEY_FINANCE = 219 # AL Checkbook/Finance
243 KEY_SPORT = 220
244 KEY_SHOP = 221
245 KEY_ALTERASE = 222
246 KEY_CANCEL = 223 # AC Cancel
247 KEY_BRIGHTNESSDOWN = 224
248 KEY_BRIGHTNESSUP = 225
249 KEY_MEDIA = 226
250
251 KEY_SWITCHVIDEOMODE = 227 # Cycle between available video
252 # outputs (Monitor/LCD/TV-out/etc)
253 KEY_KBDILLUMTOGGLE = 228
254 KEY_KBDILLUMDOWN = 229
255 KEY_KBDILLUMUP = 230
256
257 KEY_SEND = 231 # AC Send
258 KEY_REPLY = 232 # AC Reply
259 KEY_FORWARDMAIL = 233 # AC Forward Msg
260 KEY_SAVE = 234 # AC Save
261 KEY_DOCUMENTS = 235
262
263 KEY_BATTERY = 236
264
265 KEY_BLUETOOTH = 237
266 KEY_WLAN = 238
267 KEY_UWB = 239
268
269 KEY_UNKNOWN = 240
270
271 KEY_VIDEO_NEXT = 241 # drive next video source
272 KEY_VIDEO_PREV = 242 # drive previous video source
273 KEY_BRIGHTNESS_CYCLE = 243 # brightness up, after max is min
274 KEY_BRIGHTNESS_ZERO = 244 # brightness off, use ambient
275 KEY_DISPLAY_OFF = 245 # display device to off state
276
277 KEY_WIMAX = 246
278
279 # Range = 248 - 255 is reserved for special needs of AT keyboard driver
280
281 BTN_MISC = 0x100
282 BTN_0 = 0x100
283 BTN_1 = 0x101
284 BTN_2 = 0x102
285 BTN_3 = 0x103
286 BTN_4 = 0x104
287 BTN_5 = 0x105
288 BTN_6 = 0x106
289 BTN_7 = 0x107
290 BTN_8 = 0x108
291 BTN_9 = 0x109
292
293 BTN_MOUSE = 0x110
294 BTN_LEFT = 0x110
295 BTN_RIGHT = 0x111
296 BTN_MIDDLE = 0x112
297 BTN_SIDE = 0x113
298 BTN_EXTRA = 0x114
299 BTN_FORWARD = 0x115
300 BTN_BACK = 0x116
301 BTN_TASK = 0x117
302
303 BTN_JOYSTICK = 0x120
304 BTN_TRIGGER = 0x120
305 BTN_THUMB = 0x121
306 BTN_THUMB2 = 0x122
307 BTN_TOP = 0x123
308 BTN_TOP2 = 0x124
309 BTN_PINKIE = 0x125
310 BTN_BASE = 0x126
311 BTN_BASE2 = 0x127
312 BTN_BASE3 = 0x128
313 BTN_BASE4 = 0x129
314 BTN_BASE5 = 0x12a
315 BTN_BASE6 = 0x12b
316 BTN_DEAD = 0x12f
317
318 BTN_GAMEPAD = 0x130
319 BTN_A = 0x130
320 BTN_B = 0x131
321 BTN_C = 0x132
322 BTN_X = 0x133
323 BTN_Y = 0x134
324 BTN_Z = 0x135
325 BTN_TL = 0x136
326 BTN_TR = 0x137
327 BTN_TL2 = 0x138
328 BTN_TR2 = 0x139
329 BTN_SELECT = 0x13a
330 BTN_START = 0x13b
331 BTN_MODE = 0x13c
332 BTN_THUMBL = 0x13d
333 BTN_THUMBR = 0x13e
334
335 BTN_DIGI = 0x140
336 BTN_TOOL_PEN = 0x140
337 BTN_TOOL_RUBBER = 0x141
338 BTN_TOOL_BRUSH = 0x142
339 BTN_TOOL_PENCIL = 0x143
340 BTN_TOOL_AIRBRUSH = 0x144
341 BTN_TOOL_FINGER = 0x145
342 BTN_TOOL_MOUSE = 0x146
343 BTN_TOOL_LENS = 0x147
344 BTN_TOUCH = 0x14a
345 BTN_STYLUS = 0x14b
346 BTN_STYLUS2 = 0x14c
347 BTN_TOOL_DOUBLETAP = 0x14d
348 BTN_TOOL_TRIPLETAP = 0x14e
349
350 BTN_WHEEL = 0x150
351 BTN_GEAR_DOWN = 0x150
352 BTN_GEAR_UP = 0x151
353
354 KEY_OK = 0x160
355 KEY_SELECT = 0x161
356 KEY_GOTO = 0x162
357 KEY_CLEAR = 0x163
358 KEY_POWER2 = 0x164
359 KEY_OPTION = 0x165
360 KEY_INFO = 0x166 # AL OEM Features/Tips/Tutorial
361 KEY_TIME = 0x167
362 KEY_VENDOR = 0x168
363 KEY_ARCHIVE = 0x169
364 KEY_PROGRAM = 0x16a # Media Select Program Guide
365 KEY_CHANNEL = 0x16b
366 KEY_FAVORITES = 0x16c
367 KEY_EPG = 0x16d
368 KEY_PVR = 0x16e # Media Select Home
369 KEY_MHP = 0x16f
370 KEY_LANGUAGE = 0x170
371 KEY_TITLE = 0x171
372 KEY_SUBTITLE = 0x172
373 KEY_ANGLE = 0x173
374 KEY_ZOOM = 0x174
375 KEY_MODE = 0x175
376 KEY_KEYBOARD = 0x176
377 KEY_SCREEN = 0x177
378 KEY_PC = 0x178 # Media Select Computer
379 KEY_TV = 0x179 # Media Select TV
380 KEY_TV2 = 0x17a # Media Select Cable
381 KEY_VCR = 0x17b # Media Select VCR
382 KEY_VCR2 = 0x17c # VCR Plus
383 KEY_SAT = 0x17d # Media Select Satellite
384 KEY_SAT2 = 0x17e
385 KEY_CD = 0x17f # Media Select CD
386 KEY_TAPE = 0x180 # Media Select Tape
387 KEY_RADIO = 0x181
388 KEY_TUNER = 0x182 # Media Select Tuner
389 KEY_PLAYER = 0x183
390 KEY_TEXT = 0x184
391 KEY_DVD = 0x185 # Media Select DVD
392 KEY_AUX = 0x186
393 KEY_MP3 = 0x187
394 KEY_AUDIO = 0x188
395 KEY_VIDEO = 0x189
396 KEY_DIRECTORY = 0x18a
397 KEY_LIST = 0x18b
398 KEY_MEMO = 0x18c # Media Select Messages
399 KEY_CALENDAR = 0x18d
400 KEY_RED = 0x18e
401 KEY_GREEN = 0x18f
402 KEY_YELLOW = 0x190
403 KEY_BLUE = 0x191
404 KEY_CHANNELUP = 0x192 # Channel Increment
405 KEY_CHANNELDOWN = 0x193 # Channel Decrement
406 KEY_FIRST = 0x194
407 KEY_LAST = 0x195 # Recall Last
408 KEY_AB = 0x196
409 KEY_NEXT = 0x197
410 KEY_RESTART = 0x198
411 KEY_SLOW = 0x199
412 KEY_SHUFFLE = 0x19a
413 KEY_BREAK = 0x19b
414 KEY_PREVIOUS = 0x19c
415 KEY_DIGITS = 0x19d
416 KEY_TEEN = 0x19e
417 KEY_TWEN = 0x19f
418 KEY_VIDEOPHONE = 0x1a0 # Media Select Video Phone
419 KEY_GAMES = 0x1a1 # Media Select Games
420 KEY_ZOOMIN = 0x1a2 # AC Zoom In
421 KEY_ZOOMOUT = 0x1a3 # AC Zoom Out
422 KEY_ZOOMRESET = 0x1a4 # AC Zoom
423 KEY_WORDPROCESSOR = 0x1a5 # AL Word Processor
424 KEY_EDITOR = 0x1a6 # AL Text Editor
425 KEY_SPREADSHEET = 0x1a7 # AL Spreadsheet
426 KEY_GRAPHICSEDITOR = 0x1a8 # AL Graphics Editor
427 KEY_PRESENTATION = 0x1a9 # AL Presentation App
428 KEY_DATABASE = 0x1aa # AL Database App
429 KEY_NEWS = 0x1ab # AL Newsreader
430 KEY_VOICEMAIL = 0x1ac # AL Voicemail
431 KEY_ADDRESSBOOK = 0x1ad # AL Contacts/Address Book
432 KEY_MESSENGER = 0x1ae # AL Instant Messaging
433 KEY_DISPLAYTOGGLE = 0x1af # Turn display (LCD) on and off
434 KEY_SPELLCHECK = 0x1b0 # AL Spell Check
435 KEY_LOGOFF = 0x1b1 # AL Logoff
436
437 KEY_DOLLAR = 0x1b2
438 KEY_EURO = 0x1b3
439
440 KEY_FRAMEBACK = 0x1b4 # Consumer - transport controls
441 KEY_FRAMEFORWARD = 0x1b5
442 KEY_CONTEXT_MENU = 0x1b6 # GenDesc - system context menu
443 KEY_MEDIA_REPEAT = 0x1b7 # Consumer - transport control
444
445 KEY_DEL_EOL = 0x1c0
446 KEY_DEL_EOS = 0x1c1
447 KEY_INS_LINE = 0x1c2
448 KEY_DEL_LINE = 0x1c3
449
450 KEY_FN = 0x1d0
451 KEY_FN_ESC = 0x1d1
452 KEY_FN_F1 = 0x1d2
453 KEY_FN_F2 = 0x1d3
454 KEY_FN_F3 = 0x1d4
455 KEY_FN_F4 = 0x1d5
456 KEY_FN_F5 = 0x1d6
457 KEY_FN_F6 = 0x1d7
458 KEY_FN_F7 = 0x1d8
459 KEY_FN_F8 = 0x1d9
460 KEY_FN_F9 = 0x1da
461 KEY_FN_F10 = 0x1db
462 KEY_FN_F11 = 0x1dc
463 KEY_FN_F12 = 0x1dd
464 KEY_FN_1 = 0x1de
465 KEY_FN_2 = 0x1df
466 KEY_FN_D = 0x1e0
467 KEY_FN_E = 0x1e1
468 KEY_FN_F = 0x1e2
469 KEY_FN_S = 0x1e3
470 KEY_FN_B = 0x1e4
471
472 KEY_BRL_DOT1 = 0x1f1
473 KEY_BRL_DOT2 = 0x1f2
474 KEY_BRL_DOT3 = 0x1f3
475 KEY_BRL_DOT4 = 0x1f4
476 KEY_BRL_DOT5 = 0x1f5
477 KEY_BRL_DOT6 = 0x1f6
478 KEY_BRL_DOT7 = 0x1f7
479 KEY_BRL_DOT8 = 0x1f8
480 KEY_BRL_DOT9 = 0x1f9
481 KEY_BRL_DOT10 = 0x1fa
482
483 KEY_NUMERIC_0 = 0x200 # used by phones, remote controls,
484 KEY_NUMERIC_1 = 0x201 # and other keypads
485 KEY_NUMERIC_2 = 0x202
486 KEY_NUMERIC_3 = 0x203
487 KEY_NUMERIC_4 = 0x204
488 KEY_NUMERIC_5 = 0x205
489 KEY_NUMERIC_6 = 0x206
490 KEY_NUMERIC_7 = 0x207
491 KEY_NUMERIC_8 = 0x208
492 KEY_NUMERIC_9 = 0x209
493 KEY_NUMERIC_STAR = 0x20a
494 KEY_NUMERIC_POUND = 0x20b
495
496 # Relative axes
497
498 REL_X = 0x00
499 REL_Y = 0x01
500 REL_Z = 0x02
501 REL_RX = 0x03
502 REL_RY = 0x04
503 REL_RZ = 0x05
504 REL_HWHEEL = 0x06
505 REL_DIAL = 0x07
506 REL_WHEEL = 0x08
507 REL_MISC = 0x09
508 REL_MAX = 0x0f
509 REL_CNT = REL_MAX+1
510
511 # Absolute axes
512
513 ABS_X = 0x00
514 ABS_Y = 0x01
515 ABS_Z = 0x02
516 ABS_RX = 0x03
517 ABS_RY = 0x04
518 ABS_RZ = 0x05
519 ABS_THROTTLE = 0x06
520 ABS_RUDDER = 0x07
521 ABS_WHEEL = 0x08
522 ABS_GAS = 0x09
523 ABS_BRAKE = 0x0a
524 ABS_HAT0X = 0x10
525 ABS_HAT0Y = 0x11
526 ABS_HAT1X = 0x12
527 ABS_HAT1Y = 0x13
528 ABS_HAT2X = 0x14
529 ABS_HAT2Y = 0x15
530 ABS_HAT3X = 0x16
531 ABS_HAT3Y = 0x17
532 ABS_PRESSURE = 0x18
533 ABS_DISTANCE = 0x19
534 ABS_TILT_X = 0x1a
535 ABS_TILT_Y = 0x1b
536 ABS_TOOL_WIDTH = 0x1c
537 ABS_VOLUME = 0x20
538 ABS_MISC = 0x28
539 ABS_MAX = 0x3f
540 ABS_CNT = ABS_MAX+1
541
542 # Switch events
543
544 SW_LID = 0x00 # set = lid shut
545 SW_TABLET_MODE = 0x01 # set = tablet mode
546 SW_HEADPHONE_INSERT = 0x02 # set = inserted
547 SW_RFKILL_ALL = 0x03 # rfkill master switch, type "any"
548 # set = radio enabled
549 SW_RADIO = SW_RFKILL_ALL # deprecated
550 SW_MICROPHONE_INSERT = 0x04 # set = inserted
551 SW_DOCK = 0x05 # set = plugged into dock
552 SW_MAX = 0x0f
553 SW_CNT = SW_MAX+1
554
555 # Misc events
556
557 MSC_SERIAL = 0x00
558 MSC_PULSELED = 0x01
559 MSC_GESTURE = 0x02
560 MSC_RAW = 0x03
561 MSC_SCAN = 0x04
562 MSC_MAX = 0x07
563 MSC_CNT = MSC_MAX+1
564
565 # LEDs
566
567 LED_NUML = 0x00
568 LED_CAPSL = 0x01
569 LED_SCROLLL = 0x02
570 LED_COMPOSE = 0x03
571 LED_KANA = 0x04
572 LED_SLEEP = 0x05
573 LED_SUSPEND = 0x06
574 LED_MUTE = 0x07
575 LED_MISC = 0x08
576 LED_MAIL = 0x09
577 LED_CHARGING = 0x0a
578 LED_MAX = 0x0f
579 LED_CNT = LED_MAX+1
580
581 # Autorepeat values
582
583 REP_DELAY = 0x00
584 REP_PERIOD = 0x01
585 REP_MAX = 0x01
0586
=== added file 'checkbox-support/checkbox_support/lib/path.py'
--- checkbox-support/checkbox_support/lib/path.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/path.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,62 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import os
20
21from glob import glob
22
23
24def path_split(path):
25 return path.split(os.path.sep)
26
27def path_common(l1, l2, common=[]):
28 if len(l1) < 1:
29 return (common, l1, l2)
30
31 if len(l2) < 1:
32 return (common, l1, l2)
33
34 if l1[0] != l2[0]:
35 return (common, l1, l2)
36
37 return path_common(l1[1:], l2[1:], common + [l1[0]])
38
39def path_relative(p1, p2):
40 (common, l1, l2) = path_common(path_split(p1), path_split(p2))
41 p = []
42 if len(l1) > 0:
43 p = ["..%s" % os.path.sep * len(l1)]
44
45 p = p + l2
46 return os.path.join( *p )
47
48def path_expand(path):
49 path = os.path.expanduser(path)
50 return glob(path)
51
52def path_expand_recursive(path):
53 paths = []
54 for path in path_expand(path):
55 if os.path.isdir(path):
56 for dirpath, dirnames, filenames in os.walk(path):
57 for filename in filenames:
58 paths.append(os.path.join(dirpath, filename))
59 else:
60 paths.append(path)
61
62 return paths
063
=== added file 'checkbox-support/checkbox_support/lib/pci.py'
--- checkbox-support/checkbox_support/lib/pci.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/pci.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,89 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19
20# See http://pciids.sourceforge.net/pci.ids.bz2
21class Pci:
22
23 BASE_CLASS_STORAGE = 1
24 CLASS_STORAGE_SCSI = 0
25 CLASS_STORAGE_IDE = 1
26 CLASS_STORAGE_FLOPPY = 2
27 CLASS_STORAGE_IPI = 3
28 CLASS_STORAGE_RAID = 4
29 CLASS_STORAGE_OTHER = 80
30
31 BASE_CLASS_NETWORK = 2
32 CLASS_NETWORK_ETHERNET = 0
33 CLASS_NETWORK_TOKEN_RING = 1
34 CLASS_NETWORK_FDDI = 2
35 CLASS_NETWORK_ATM = 3
36 CLASS_NETWORK_OTHER = 80
37 CLASS_NETWORK_WIRELESS = 128
38
39 BASE_CLASS_DISPLAY = 3
40 CLASS_DISPLAY_VGA = 0
41 CLASS_DISPLAY_XGA = 1
42 CLASS_DISPLAY_3D = 2
43 CLASS_DISPLAY_OTHER = 80
44
45 BASE_CLASS_MULTIMEDIA = 4
46 CLASS_MULTIMEDIA_VIDEO = 0
47 CLASS_MULTIMEDIA_AUDIO = 1
48 CLASS_MULTIMEDIA_PHONE = 2
49 CLASS_MULTIMEDIA_AUDIO_DEVICE = 3
50 CLASS_MULTIMEDIA_OTHER = 80
51
52 BASE_CLASS_BRIDGE = 6
53 CLASS_BRIDGE_HOST = 0
54 CLASS_BRIDGE_ISA = 1
55 CLASS_BRIDGE_EISA = 2
56 CLASS_BRIDGE_MC = 3
57 CLASS_BRIDGE_PCI = 4
58 CLASS_BRIDGE_PCMCIA = 5
59 CLASS_BRIDGE_NUBUS = 6
60 CLASS_BRIDGE_CARDBUS = 7
61 CLASS_BRIDGE_RACEWAY = 8
62 CLASS_BRIDGE_OTHER = 80
63
64 BASE_CLASS_COMMUNICATION = 7
65 CLASS_COMMUNICATION_SERIAL = 0
66 CLASS_COMMUNICATION_PARALLEL = 1
67 CLASS_COMMUNICATION_MULTISERIAL = 2
68 CLASS_COMMUNICATION_MODEM = 3
69 CLASS_COMMUNICATION_OTHER = 80
70
71 BASE_CLASS_INPUT = 9
72 CLASS_INPUT_KEYBOARD = 0
73 CLASS_INPUT_PEN = 1
74 CLASS_INPUT_MOUSE = 2
75 CLASS_INPUT_SCANNER = 3
76 CLASS_INPUT_GAMEPORT = 4
77 CLASS_INPUT_OTHER = 80
78
79 BASE_CLASS_SERIAL = 12
80 CLASS_SERIAL_FIREWIRE = 0
81 CLASS_SERIAL_ACCESS = 1
82
83 BASE_CLASS_WIRELESS = 13
84 CLASS_WIRELESS_BLUETOOTH = 17
85
86 CLASS_SERIAL_SSA = 2
87 CLASS_SERIAL_USB = 3
88 CLASS_SERIAL_FIBER = 4
89 CLASS_SERIAL_SMBUS = 5
090
=== added file 'checkbox-support/checkbox_support/lib/template.py'
--- checkbox-support/checkbox_support/lib/template.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/template.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,143 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20import logging
21
22
23EXTENDED_STRING = "_extended"
24
25
26class Template:
27
28 def _reader(self, file, size=4096, delimiter=r"\n{2,}"):
29 buffer_old = ""
30 while True:
31 buffer_new = file.read(size)
32 if not buffer_new:
33 break
34
35 lines = re.split(delimiter, buffer_old + buffer_new)
36 buffer_old = lines.pop(-1)
37
38 for line in lines:
39 yield line
40
41 yield buffer_old
42
43 def dump_file(self, elements, file, filename="<stream>"):
44 for element in elements:
45 for long_key in list(element.keys()):
46 if long_key.endswith(EXTENDED_STRING):
47 short_key = long_key.replace(EXTENDED_STRING, "")
48 del element[short_key]
49
50 for key, value in element.items():
51 if key.endswith(EXTENDED_STRING):
52 key = key.replace(EXTENDED_STRING, "")
53 file.write("%s:\n" % key)
54 for line in value.split("\n"):
55 file.write(" %s\n" % line)
56 elif isinstance(value, (list, tuple)):
57 file.write("%s:\n" % key)
58 for v in value:
59 file.write(" %s\n" % v)
60 else:
61 file.write("%s: %s\n" % (key, value))
62
63 file.write("\n")
64
65 def dump_filename(self, elements, filename):
66 logging.info("Dumping elements to filename: %s", filename)
67
68 with open(filename, "w") as stream:
69 return self.dump_file(elements, stream, filename)
70
71 def load_file(self, file, filename="<stream>"):
72 elements = []
73 for string in self._reader(file):
74 if not string:
75 break
76
77 element = {}
78
79 def _save(field, value, extended):
80 extended = extended.rstrip("\n")
81 if field:
82 if field in element:
83 raise Exception("Template %s has a duplicate "
84 "field '%s' with a new value '%s'."
85 % (filename, field, value))
86 element[field] = value
87 if extended:
88 element["%s%s" % (field, EXTENDED_STRING)] = extended
89
90 string = string.strip("\n")
91 field = value = extended = ""
92 for line in string.split("\n"):
93 line.strip()
94 if line.startswith("#"):
95 continue
96
97 match = re.search(r"^([-_.A-Za-z0-9@]*):\s?(.*)", line)
98 if match:
99 _save(field, value, extended)
100 field = match.groups()[0]
101 value = match.groups()[1].rstrip()
102 extended = ""
103 continue
104
105 if re.search(r"^\s\.$", line):
106 extended += "\n\n"
107 continue
108
109 match = re.search(r"^\s(\s+.*)", line)
110 if match:
111 bit = match.groups()[0].rstrip()
112 if len(extended) and not re.search(r"[\n ]$", extended):
113 extended += "\n"
114
115 extended += bit + "\n"
116 continue
117
118 match = re.search(r"^\s(.*)", line)
119 if match:
120 bit = match.groups()[0].rstrip()
121 if len(extended) and not re.search(r"[\n ]$", extended):
122 if extended.endswith("\\"):
123 extended = extended[:-1].rstrip() + " "
124 else:
125 extended += "\n"
126
127 extended += bit
128 continue
129
130 raise Exception("Template %s parse error at: %s" \
131 % (filename, line))
132
133 _save(field, value, extended)
134
135 elements.append(element)
136
137 return elements
138
139 def load_filename(self, filename):
140 logging.info("Loading elements from filename: %s", filename)
141
142 with open(filename, "r", encoding="utf-8") as stream:
143 return self.load_file(stream, filename)
0144
=== added file 'checkbox-support/checkbox_support/lib/tz.py'
--- checkbox-support/checkbox_support/lib/tz.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/tz.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,55 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2012 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19__all__ = [
20 "tzutc",
21 ]
22
23from datetime import (
24 timedelta,
25 tzinfo,
26 )
27
28
29ZERO = timedelta(0)
30
31
32class _tzutc(tzinfo):
33
34 def utcoffset(self, dt):
35 return ZERO
36
37 def dst(self, dt):
38 return ZERO
39
40 def tzname(self, dt):
41 return "UTC"
42
43 def __eq__(self, other):
44 return isinstance(other, tzutc)
45
46 def __ne__(self, other):
47 return not self.__eq__(other)
48
49 def __repr__(self):
50 return "%s()" % self.__class__.__name__
51
52 __reduce__ = object.__reduce__
53
54
55tzutc = _tzutc()
056
=== added file 'checkbox-support/checkbox_support/lib/usb.py'
--- checkbox-support/checkbox_support/lib/usb.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/lib/usb.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,59 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2008 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19
20# See http://www.linux-usb.org/usb.ids
21class Usb:
22
23 BASE_CLASS_INTERFACE = 0
24
25 BASE_CLASS_AUDIO = 1
26 CLASS_AUDIO_CONTROL_DEVICE = 1
27 CLASS_AUDIO_STREAMING = 2
28 CLASS_AUDIO_MIDI_STREAMING = 3
29
30 BASE_CLASS_COMMUNICATIONS = 2
31 CLASS_COMMUNICATIONS_DIRECT_LINE = 1
32 CLASS_COMMUNICATIONS_ABSTRACT = 2
33 CLASS_COMMUNICATIONS_TELEPHONE = 3
34
35 BASE_CLASS_PRINTER = 7
36 CLASS_PRINTER_OTHER = 1
37
38 BASE_CLASS_STORAGE = 8
39 CLASS_STORAGE_RBC = 1
40 CLASS_STORAGE_SFF = 2
41 CLASS_STORAGE_QIC = 3
42 CLASS_STORAGE_FLOPPY = 4
43 CLASS_STORAGE_SFF = 5
44 CLASS_STORAGE_SCSI = 6
45
46 BASE_CLASS_HUB = 9
47 CLASS_HUB_UNUSED = 0
48
49 BASE_CLASS_VIDEO = 14
50 CLASS_VIDEO_UNDEFINED = 0
51 CLASS_VIDEO_CONTROL = 1
52 CLASS_VIDEO_STREAMING = 2
53 CLASS_VIDEO_INTERFACE_COLLECTION = 3
54
55 BASE_CLASS_WIRELESS = 224
56 CLASS_WIRELESS_RADIO_FREQUENCY = 1
57 CLASS_WIRELESS_USB_ADAPTER = 2
58
59 PROTOCOL_BLUETOOTH = 1
060
=== added directory 'checkbox-support/checkbox_support/parsers'
=== added file 'checkbox-support/checkbox_support/parsers/__init__.py'
=== added file 'checkbox-support/checkbox_support/parsers/cpuinfo.py'
--- checkbox-support/checkbox_support/parsers/cpuinfo.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/cpuinfo.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,180 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21from os import uname
22
23from checkbox_support.lib.conversion import string_to_type
24
25
26class CpuinfoParser:
27 """Parser for the /proc/cpuinfo file."""
28
29 def __init__(self, stream, machine=None):
30 self.stream = stream
31 self.machine = machine or uname()[4].lower()
32
33 def getAttributes(self):
34 count = 0
35 attributes = {}
36 cpuinfo = self.stream.read()
37 for block in re.split(r"\n{2,}", cpuinfo):
38 block = block.strip()
39 if not block:
40 continue
41
42 for line in block.split("\n"):
43 if not line:
44 continue
45 key, value = line.split(":", 1)
46 key, value = key.strip(), value.strip()
47
48 if key == 'processor':
49 count += 1
50
51 # Handle bogomips on sparc
52 if key.endswith("Bogo"):
53 key = "bogomips"
54
55 attributes[key] = value
56
57 if attributes:
58 attributes["count"] = count
59
60 return attributes
61
62 def run(self, result):
63 attributes = self.getAttributes()
64 if not attributes:
65 return
66
67 # Default values
68 machine = self.machine
69 processor = {
70 "platform": machine,
71 "count": 1,
72 "type": machine,
73 "model": machine,
74 "model_number": "",
75 "model_version": "",
76 "model_revision": "",
77 "cache": 0,
78 "bogomips": 0,
79 "speed": -1,
80 "other": ""}
81
82 # Conversion table
83 platform_to_conversion = {
84 ("i386", "i486", "i586", "i686", "x86_64",): {
85 "type": "vendor_id",
86 "model": "model name",
87 "model_number": "cpu family",
88 "model_version": "model",
89 "model_revision": "stepping",
90 "cache": "cache size",
91 "other": "flags",
92 "speed": "cpu MHz"},
93 ("alpha", "alphaev6",): {
94 "count": "cpus detected",
95 "type": "cpu",
96 "model": "cpu model",
97 "model_number": "cpu variation",
98 "model_version": ("system type", "system variation",),
99 "model_revision": "cpu revision",
100 "other": "platform string",
101 "speed": "cycle frequency [Hz]"},
102 ("armv7l",): {
103 "type": "Hardware",
104 "model": "Processor",
105 "model_number": "CPU variant",
106 "model_version": "CPU architecture",
107 "model_revision": "CPU revision",
108 "other": "Features",
109 "bogomips": "BogoMIPS"},
110 ("ia64",): {
111 "type": "vendor",
112 "model": "family",
113 "model_version": "archrev",
114 "model_revision": "revision",
115 "other": "features",
116 "speed": "cpu mhz"},
117 ("ppc64", "ppc",): {
118 "type": "platform",
119 "model": "cpu",
120 "model_version": "revision",
121 "speed": "clock"},
122 ("sparc64", "sparc",): {
123 "count": "ncpus probed",
124 "type": "type",
125 "model": "cpu",
126 "model_version": "type",
127 "speed": "bogomips"}}
128
129 for key in processor:
130 if attributes.get(key):
131 processor[key] = attributes.get(key)
132
133 for platform, conversion in platform_to_conversion.items():
134 if machine in platform:
135 for pkey, ckey in conversion.items():
136 if isinstance(ckey, (list, tuple)):
137 processor[pkey] = "/".join([attributes[k]
138 for k in ckey])
139 elif ckey in attributes:
140 processor[pkey] = attributes[ckey]
141
142 # Adjust platform
143 if machine[0] == "i" and machine[-2:] == "86":
144 processor["platform"] = "i386"
145 elif machine[:5] == "alpha":
146 processor["platform"] = "alpha"
147
148 # Adjust cache
149 if processor["cache"]:
150 processor["cache"] = string_to_type(processor["cache"])
151
152 # Adjust speed
153 try:
154 if machine[:5] == "alpha":
155 speed = processor["speed"].split()[0]
156 processor["speed"] = int(round(float(speed))) / 1000000
157 elif machine[:5] == "sparc":
158 speed = processor["speed"]
159 processor["speed"] = int(round(float(speed))) / 2
160 elif machine[:3] == "ppc":
161 # String is appended with "mhz"
162 speed = processor["speed"][:-3]
163 except ValueError:
164 processor["speed"] = -1
165
166 # Make sure speed and bogomips are integers
167 processor["speed"] = int(round(float(processor["speed"])) - 1)
168 processor["bogomips"] = int(round(float(processor["bogomips"])))
169
170 # Adjust count
171 try:
172 processor["count"] = int(processor["count"])
173 except ValueError:
174 processor["count"] = 1
175 else:
176 # There is at least one processor
177 if processor["count"] == 0:
178 processor["count"] = 1
179
180 result.setProcessor(processor)
0181
=== added file 'checkbox-support/checkbox_support/parsers/dmidecode.py'
--- checkbox-support/checkbox_support/parsers/dmidecode.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/dmidecode.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,126 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21from string import (
22 hexdigits,
23 ascii_uppercase,
24 )
25
26from checkbox_support.lib.dmi import (
27 Dmi,
28 DmiDevice,
29 )
30
31
32HANDLE_RE = re.compile(
33 r"^Handle (?P<handle>0x[%s]{4}), "
34 r"DMI type (?P<type>\d+), "
35 r"(?P<size>\d+) bytes$"
36 % hexdigits)
37KEY_VALUE_RE = re.compile(
38 r"^\t(?P<key>[%s].+):( (?P<value>.+))?$"
39 % ascii_uppercase)
40
41
42class DmidecodeParser:
43 """Parser for the dmidecode command."""
44
45 _key_map = {
46 "ID": "serial",
47 "Manufacturer": "vendor",
48 "Product Name": "name",
49 "Serial Number": "serial",
50 "Type": "type",
51 "Vendor": "vendor",
52 "Version": "version",
53 "Size": "size",
54 "Form Factor": "form",
55 }
56
57 def __init__(self, stream):
58 self.stream = stream
59
60 def _parseKey(self, key):
61 return self._key_map.get(key)
62
63 def _parseValue(self, value):
64 if value is not None:
65 value = value.strip()
66 if not value:
67 value = None
68
69 return value
70
71 def run(self, result):
72 output = self.stream.read()
73 for record in re.split(r"\n{2,}", output):
74 record = record.strip()
75 # Skip empty records
76 if not record:
77 continue
78
79 # Skip header record
80 lines = record.split("\n")
81 line = lines.pop(0)
82 if line.startswith("#"):
83 continue
84
85 # Skip records with an unsupported handle
86 match = HANDLE_RE.match(line)
87 if not match:
88 continue
89
90 # Skip records that are empty or inactive
91 if not lines or lines.pop(0) == "Inactive":
92 continue
93
94 # Skip disabled entries and end-of-table marker
95 type_index = int(match.group("type"))
96 if type_index >= len(Dmi.type_names):
97 continue
98
99 category = Dmi.type_names[type_index]
100 category = category.upper().split(" ")[-1]
101 if category not in (
102 "BOARD", "BIOS", "CHASSIS", "DEVICE", "PROCESSOR", "SYSTEM"):
103 continue
104
105 # Parse attributes
106 attributes = {}
107
108 for line in lines:
109 # Skip lines with an unsupported key/value pair
110 match = KEY_VALUE_RE.match(line)
111 if not match:
112 continue
113
114 # Skip lines with an unsupported key
115 key = self._parseKey(match.group("key"))
116 if not key:
117 continue
118
119 key = "%s_%s" % (category.lower(), key)
120 value = self._parseValue(match.group("value"))
121 attributes[key] = value
122
123 device = DmiDevice(attributes, category)
124 result.addDmiDevice(device)
125
126 return result
0127
=== added file 'checkbox-support/checkbox_support/parsers/efi.py'
--- checkbox-support/checkbox_support/parsers/efi.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/efi.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,52 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21
22class EfiDevice:
23
24 path = "/sys/class/dmi/id/bios_version"
25 category = "EFI"
26
27 def __init__(self, product, vendor=None):
28 self.product = product
29 self.vendor = vendor
30
31
32class EfiParser:
33 """Parser for EFI information."""
34
35 def __init__(self, stream):
36 self.stream = stream
37
38 def run(self, result):
39 vendor_product_pattern = re.compile(
40 r"^(?P<vendor>.*)\s+by\s+(?P<product>.*)$")
41
42 for line in self.stream.readlines():
43 line = line.strip()
44 match = vendor_product_pattern.match(line)
45 if match:
46 product = match.group("product")
47 vendor = match.group("vendor")
48 device = EfiDevice(product, vendor)
49 else:
50 device = EfiDevice(line)
51
52 result.setEfiDevice(device)
053
=== added file 'checkbox-support/checkbox_support/parsers/lshwjson.py'
--- checkbox-support/checkbox_support/parsers/lshwjson.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/lshwjson.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,23 @@
1import sys
2import json
3
4class LshwJsonParser:
5
6 def __init__(self, stream_or_string):
7 self.stream_or_string = stream_or_string
8
9 def _parse_lshw(self, lshw, result):
10 if 'children' in lshw.keys():
11 for child in lshw['children']:
12 self._parse_lshw(child, result)
13 del lshw['children']
14
15 result.addHardware(lshw)
16
17 def run(self, result):
18 try:
19 lshw = json.loads(self.stream_or_string)
20 except:
21 print('not valid json')
22
23 self._parse_lshw(lshw, result)
024
=== added file 'checkbox-support/checkbox_support/parsers/meminfo.py'
--- checkbox-support/checkbox_support/parsers/meminfo.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/meminfo.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,46 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19import re
20
21
22class MeminfoParser:
23 """Parser for the /proc/meminfo file."""
24
25 def __init__(self, stream):
26 self.stream = stream
27
28 def run(self, result):
29 key_value_pattern = re.compile(r"(?P<key>.*):\s+(?P<value>.*)")
30 meminfo_map = {
31 "MemTotal": "total",
32 "SwapTotal": "swap"}
33
34 meminfo = {}
35 for line in self.stream.readlines():
36 line = line.strip()
37 match = key_value_pattern.match(line)
38 if match:
39 key = match.group("key")
40 if key in meminfo_map:
41 key = meminfo_map[key]
42 value = match.group("value")
43 (integer, factor) = value.split()
44 meminfo[key] = int(integer) * 1024
45
46 result.setMemory(meminfo)
047
=== added file 'checkbox-support/checkbox_support/parsers/modinfo.py'
--- checkbox-support/checkbox_support/parsers/modinfo.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/modinfo.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,89 @@
1#
2# This file is part of Checkbox.
3#
4# Copyright 2011 Canonical Ltd.
5#
6# Checkbox is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3,
8# as published by the Free Software Foundation.
9
10#
11# Checkbox is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
18#
19
20
21class ModinfoParser:
22 """
23 Parser for modinfo information.
24 This will take the stdout for modinfo output and return a dict populated
25 with each field.
26
27 Basic usage in your script:
28 try:
29 output = subprocess.check_output('/sbin/modinfo e1000e',
30 stderr=subprocess.STDOUT,
31 universal_newlines=True)
32 except CalledProcessError as err:
33 print("Error while running modinfo")
34 print(err.output)
35 return err.returncode
36
37 parser = ModinfoParser(output)
38 all_fields = parser.get_all()
39 one_field = parser.get_field(field)
40 """
41
42 def __init__(self, stream):
43 self._modinfo = {'alias': [],
44 'author': '',
45 'depends': [],
46 'description': '',
47 'filename': '',
48 'firmware': [],
49 'intree': '',
50 'license': '',
51 'parm': [],
52 'srcversion': '',
53 'vermagic': '',
54 'version': ''}
55 self._get_info(stream)
56
57 def _get_info(self, stream):
58 for line in stream.splitlines():
59 # At this point, stream should be the stdout from the modinfo
60 # command, in a list.
61 try:
62 key, data = line.split(':', 1)
63 except ValueError:
64 # Most likely this will be caused by a blank line in the
65 # stream, so we just ignore it and move on.
66 continue
67 else:
68 key = key.strip()
69 data = data.strip()
70 # First, we need to handle alias, parm, firmware, and depends
71 # because there can be multiple lines of output for these.
72 if key in ('alias', 'depend', 'firmware', 'parm',):
73 self._modinfo[key].append(data)
74 # Now handle unknown keys
75 elif key not in self._modinfo.keys():
76 self._modinfo[key] = ("WARNING: Unknown Key %s providing "
77 "data: %s") % (key, data)
78 # And finally known keys
79 else:
80 self._modinfo[key] = data
81
82 def get_all(self):
83 return self._modinfo
84
85 def get_field(self, field):
86 if field not in self._modinfo.keys():
87 raise Exception("Key not found: %s" % field)
88 else:
89 return self._modinfo[field]
090
=== added file 'checkbox-support/checkbox_support/parsers/pactl.py'
--- checkbox-support/checkbox_support/parsers/pactl.py 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/pactl.py 2014-01-07 13:44:32 +0000
@@ -0,0 +1,543 @@
1# This file is part of Checkbox.
2#
3# Copyright 2013 Canonical Ltd.
4# Written by:
5# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
6#
7# Checkbox is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 3,
9# as published by the Free Software Foundation.
10
11#
12# Checkbox is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21:mod:`checkbox_support.parsers.pactl` -- `pactl list` parser
22====================================================
23
24Parser for the output of ``pactl list`` syntax.
25
26The abstract syntax tree of 'pactl list' is as follows::
27
28 Document: Record + ('\n' + Record)*
29
30 Record: RECORD-NAME ':' Attribute+
31
32 Attribute: ATTRIBUTE-NAME ':' AttributeValue
33
34 AttributeValue: SIMPLE-VALUE '\n'
35 | PropertyValue
36 | VOLUME-VALUE
37 | BASE-VOLUME-VALUE
38 | PORT+
39 | PORT-WITH-PROFILE+
40
41 PropertyValue: PROPERTY-NAME '=' PROPERTY-VALUE
42
43 (other all-upsercase values are not specified in detail)
44
45Some parts of the output are always localized while others depend on the
46locale of the current user. This is caused by the fact that ``pactl`` talks to
47pulse audio server over DBus. Some of the data obtained from pulse that was is
48localized and it is difficult to influence. This should be of no problem for
49the parser but actual usage of the data can be more difficult.
50"""
51
52from collections import OrderedDict
53from inspect import isroutine
54
55import pyparsing as p
56
57
58# Enable packrat paring.
59#
60# This reduces the complexity of the parser
61# from O(2**N) to O(N) at the cost of memory O(N) vs O(1).
62p.ParserElement.enablePackrat()
63
64# XXX: Hack, changes global stuff
65#
66# This makes pyparsing not so ignorant to whitespace. Normally pyparsing is
67# happily treating newlines, tabs, spaces and carriage returns as irrelevant
68# spacers between tokens. Because pactl syntax is so whitespace-sensitive this
69# is globally turned off. A proper solution would apply this on a
70# per-ParserElement level
71p.ParserElement.DEFAULT_WHITE_CHARS = " "
72
73
74class NodeMeta(type):
75 """
76 Metaclass for all Node types.
77
78 Helps to setup the `Syntax` attribute using the special `__syntax__`
79 attribute. It also calls from_tokens() with the appropriate class.
80 """
81
82 def __new__(mcls, name, bases, ns):
83 cls = type.__new__(mcls, name, bases, ns)
84 if hasattr(cls, '__syntax__'):
85 cls.Syntax = (
86 cls.__syntax__
87 ).setParseAction(
88 cls.from_tokens
89 ).parseWithTabs()
90 return cls
91
92
93class Node(metaclass=NodeMeta):
94 """
95 Base class for things parsed by pyparsing.
96
97 Defines sensible __repr__(), __init__() and from_tokens(). That
98 last class method uses __fragments__ to pick things from pyparsing
99 ParseResults and assign them to attributes of the Node instance.
100
101 This serves as a buffer between pyparsing and external code, so that
102 anything we do to the syntax is irrelevant as long as the tree of
103 Nodes remains the same.
104 """
105
106 __fragments__ = {}
107
108 def __init__(self, **kwargs):
109 for attr, value in kwargs.items():
110 setattr(self, attr, value)
111
112 def __repr__(self):
113 return "{}({})".format(
114 type(self).__name__, ", ".join([
115 "{}={!r}".format(attr, getattr(self, attr))
116 for attr in self.__fragments__]))
117
118 @classmethod
119 def from_tokens(cls, tokens):
120 """
121 Create a node from tokens that were matched from __syntax__
122 """
123 data = {
124 attr: mapper(tokens) if isroutine(mapper) else tokens[mapper]
125 for attr, mapper in cls.__fragments__.items()
126 }
127 return cls(**data)
128
129
130class Property(Node):
131 """
132 A key=value pair.
133
134 A list of properties is a possible syntax for Attribute value.
135 """
136
137 __fragments__ = {
138 'name': 'property-name',
139 'value': 'property-value'
140 }
141
142 __syntax__ = (
143 p.Word(p.alphanums + "-_.").setResultsName("property-name")
144 + p.Suppress('=')
145 + p.QuotedString('"').setResultsName("property-value")
146 ).setResultsName('property')
147
148
149class Profile(Node):
150 """
151 Description of a pulseaudio profile.
152 """
153
154 __fragments__ = {
155 'name': 'profile-name',
156 'label': 'profile-label',
157 'sink_cnt': 'profile-sink-count',
158 'source_cnt': 'profile-source-count',
159 'priority': 'profile-priority',
160 }
161
162 __syntax__ = (
163 p.Word(p.alphanums + "+-:").setParseAction(
164 lambda t: t[0].rstrip(':')
165 ).setResultsName("profile-name")
166 + p.delimitedList(
167 p.Literal("(HDMI)") | p.Literal("(IEC958)") | p.Regex('[^ (\n]+'),
168 ' ', combine=True
169 ).setResultsName('profile-label')
170 + p.Suppress('(')
171 + p.Keyword('sinks').suppress()
172 + p.Suppress(':')
173 + p.Word(p.nums).setParseAction(
174 lambda t: int(t[0])
175 ).setResultsName('profile-sink-count')
176 + p.Suppress(',')
177 + p.Keyword('sources').suppress()
178 + p.Suppress(':')
179 + p.Word(p.nums).setParseAction(
180 lambda t: int(t[0])
181 ).setResultsName('profile-source-count')
182 + p.Suppress(',')
183 + p.Keyword('priority').suppress()
184 + p.MatchFirst([
185 p.Suppress('.'),
186 # http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/src/utils/pactl.c?id=83c3cf0a65fb05900f81bd2dbb38e6956eb23935
187 p.Suppress(':'),
188 ])
189 + p.Word(p.nums).setParseAction(
190 lambda t: int(t[0])
191 ).setResultsName('profile-priority')
192 + p.Suppress(')')
193 ).setResultsName("profile")
194
195
196class Port(Node):
197 """
198 Description of a port on a sink
199 """
200
201 __fragments__ = {
202 'name': 'port-name',
203 'label': 'port-label',
204 'priority': 'port-priority',
205 'availability': 'port-availability'
206 }
207
208 __syntax__ = (
209 p.Word(p.alphanums + "-;").setResultsName('port-name')
210 + p.Suppress(':')
211 # This part was very tricky to write. The label is basically
212 # arbitrary localized Unicode text. We want to grab all of it in
213 # one go but without consuming the upcoming '(' character or the
214 # space that comes immediately before.
215 #
216 # The syntax here combines a sequence of words, as defined by
217 # anything other than a space and '(', delimited by a single
218 # whitespace.
219 + p.delimitedList(
220 p.Regex('[^ (\n]+'), ' ', combine=True
221 ).setResultsName('port-label')
222 + p.Suppress('(')
223 + p.Keyword('priority').suppress()
224 + p.Suppress(':')
225 + p.Word(p.nums).setParseAction(
226 lambda t: int(t[0])
227 ).setResultsName('port-priority')
228 + p.MatchFirst([
229 p.Suppress(',') + p.Literal('not available'),
230 p.Suppress(',') + p.Literal('available'),
231 p.Empty().setParseAction(lambda t: '')
232 ]).setResultsName('port-availability')
233 + p.Suppress(')')
234 ).setResultsName("port")
235
236
237# =================
238# Shared Attributes
239# =================
240
241PropertyAttributeValue = (
242 p.Group(
243 p.OneOrMore(
244 p.LineStart().suppress()
245 + p.Optional(p.White('\t')).suppress()
246 + p.Optional(Property.Syntax)
247 + p.LineEnd().suppress()
248 )
249 ).setResultsName("attribute-value"))
250
251
252class PortWithProfile(Node):
253 """
254 Variant of :class:`Port` that is used by "card" records inside
255 the "Ports" property. It differs from the normal port syntax by having
256 different entries inside the last section. Availability is not listed
257 here, only priority. Priority does not have a colon before the actual
258 number. This port is followed by profile assignment.
259 """
260 __fragments__ = {
261 'name': 'port-name',
262 'label': 'port-label',
263 'priority': 'port-priority',
264 'latency_offset': 'port-latency-offset',
265 'availability': 'port-availability',
266 'properties': lambda t: t['port-properties'].asList(),
267 'profile_list': lambda t: t['port-profile-list'].asList(),
268 }
269
270 __syntax__ = (
271 p.Word(p.alphanums + "-;").setResultsName('port-name')
272 + p.Suppress(':')
273 # This part was very tricky to write. The label is basically arbitrary
274 # localized Unicode text. We want to grab all of it in one go but
275 # without consuming the upcoming and latest '(' character or the space
276 # that comes immediately before.
277 #
278 # The syntax here combines a sequence of words, as defined by anything
279 # other than a space and '(', delimited by a single whitespace.
280 + p.Combine(
281 p.OneOrMore(
282 ~p.FollowedBy(
283 p.Regex('\(.+?\)')
284 + p.LineEnd()
285 )
286 + p.Regex('[^ \n]+')
287 + p.White().suppress()
288 ),
289 ' '
290 ).setResultsName('port-label')
291 + p.Suppress('(')
292 + p.Keyword('priority').suppress()
293 + p.Optional(
294 p.Suppress(':')
295 )
296 + p.Word(p.nums).setParseAction(
297 lambda t: int(t[0])
298 ).setResultsName('port-priority')
299 + p.Optional(
300 p.MatchFirst([
301 p.Suppress(',') + p.Keyword('latency offset:').suppress()
302 + p.Word(p.nums).setParseAction(lambda t: int(t[0]))
303 + p.Literal("usec").suppress(),
304 p.Empty().setParseAction(lambda t: '')
305 ]).setResultsName('port-latency-offset')
306 )
307 + p.Optional(
308 p.MatchFirst([
309 p.Suppress(',') + p.Literal('not available'),
310 p.Suppress(',') + p.Literal('available'),
311 p.Empty().setParseAction(lambda t: '')
312 ]).setResultsName('port-availability')
313 )
314 + p.Suppress(')')
315 + p.LineEnd().suppress()
316 + p.Optional(
317 p.MatchFirst([
318 p.LineStart().suppress()
319 + p.NotAny(p.White(' '))
320 + p.White('\t').suppress()
321 + p.Keyword('Properties:').suppress()
322 + p.LineEnd().suppress()
323 + PropertyAttributeValue,
324 p.Empty().setParseAction(lambda t: [])
325 ]).setResultsName('port-properties')
326 )
327 + p.White('\t', max=3).suppress()
328 + p.Literal("Part of profile(s)").suppress()
329 + p.Suppress(":")
330 + p.delimitedList(
331 p.Word(p.alphanums + "+-:"), ", "
332 ).setResultsName("port-profile-list")
333 ).setResultsName("port")
334
335
336# =========================
337# Non-collection attributes
338# =========================
339
340AttributeName = p.Regex("[a-zA-Z][^:\n]+").setResultsName("attribute-name")
341
342
343VolumeAttributeValue = (
344 p.Combine(
345 p.Or([
346 p.Literal("(invalid)"),
347 p.Regex("([0-9]+: +[0-9]+% ?)+")
348 ])
349 + p.LineEnd()
350 + p.Optional(p.White('\t').suppress())
351 + p.Or([
352 p.Literal("(invalid)"),
353 p.Regex("([0-9]+: -?[0-9]+\.[0-9]+ dB ?)+")
354 ])
355 + p.LineEnd()
356 + p.Optional(p.White('\t').suppress())
357 + p.Regex("balance [0-9]+\.[0-9]+")
358 + p.LineEnd(),
359 adjacent=False
360 ).setResultsName("attribute-value")
361)
362
363
364BaseVolumeAttributeValue = (
365 p.Combine(
366 p.Regex("[0-9]+%")
367 + p.LineEnd()
368 + p.Optional(p.White('\t').suppress())
369 + p.Regex("-?[0-9]+\.[0-9]+ dB")
370 + p.LineEnd(),
371 adjacent=False
372 ).setResultsName("attribute-value")
373)
374
375
376SimpleAttributeValue = (
377 p.Regex("[^\n]*").setResultsName("attribute-value")
378 + p.LineEnd().suppress())
379
380# simple values
381GenericSimpleAttributeValue = p.MatchFirst([
382 VolumeAttributeValue,
383 BaseVolumeAttributeValue,
384 SimpleAttributeValue,
385])
386
387
388class GenericSimpleAttribute(Node):
389
390 __fragments__ = {
391 'name': 'attribute-name',
392 'value': 'attribute-value',
393 }
394
395 __syntax__ = (
396 p.LineStart().suppress()
397 + p.NotAny(p.White(' '))
398 + p.Optional(p.White('\t')).suppress()
399 + AttributeName
400 + p.Literal(':').suppress()
401 + GenericSimpleAttributeValue
402 ).setResultsName("attribute")
403
404
405# =====================
406# Collection Attributes
407# =====================
408
409PortsAttributeValue = (
410 p.Group(
411 p.OneOrMore(
412 p.LineStart().suppress()
413 + p.Optional(p.White('\t')).suppress()
414 + Port.Syntax
415 + p.LineEnd().suppress())
416 ).setResultsName("attribute-value"))
417
418PortsWithProfilesAttributeValue = (
419 p.Group(
420 p.OneOrMore(
421 p.LineStart().suppress()
422 + p.Optional(p.White('\t')).suppress()
423 + PortWithProfile.Syntax
424 + p.LineEnd().suppress())
425 ).setResultsName("attribute-value"))
426
427FormatsAttributeValue = (
428 p.Group(
429 p.OneOrMore(
430 p.LineStart().suppress()
431 + p.Optional(p.White('\t')).suppress()
432 + p.Word(p.alphas)
433 + p.LineEnd().suppress())
434 ).setResultsName("attribute-value"))
435
436ProfilesAttributeValue = (
437 p.Group(
438 p.OneOrMore(
439 p.LineStart().suppress()
440 + p.Optional(p.White('\t')).suppress()
441 + Profile.Syntax
442 + p.LineEnd().suppress())
443 ).setResultsName("attribute-value"))
444
445
446GenericListAttributeValue = p.MatchFirst([
447 PortsAttributeValue,
448 PropertyAttributeValue,
449 PortsWithProfilesAttributeValue,
450 ProfilesAttributeValue,
451 FormatsAttributeValue,
452])
453
454
455class GenericListAttribute(Node):
456
457 __fragments__ = {
458 'name': 'attribute-name',
459 'value': lambda t: t['attribute-value'].asList()
460 }
461
462 __syntax__ = (
463 p.LineStart().suppress()
464 + p.NotAny(p.White(' '))
465 + p.Optional(p.White('\t')).suppress()
466 + AttributeName
467 + p.Literal(':').suppress()
468 + p.LineEnd().suppress()
469 + GenericListAttributeValue
470 ).setResultsName("attribute")
471
472
473class Record(Node):
474 """
475 Single standalone entry of `pactl list`.
476
477 The record is composed of a name and a list of attributes. Pulseaudio
478 exposes objects such as cards, sinks and sources as separate records.
479
480 Each attribute may be of a different type. Some attributes are simple
481 values while others have finer structure, including lits and even
482 additional recursive attributes.
483 """
484
485 __fragments__ = {
486 'name': 'record-name',
487 'attribute_list': lambda t: t['record-attributes'].asList(),
488 'attribute_map': lambda t: OrderedDict(
489 (attr.name, attr)
490 for attr in t['record-attributes'].asList()),
491 }
492
493 __syntax__ = (
494 p.LineStart()
495 + p.NotAny(p.White(' \t'))
496 + p.Regex("[A-Z][a-zA-Z ]+ #[0-9]+").setResultsName("record-name")
497 + p.LineEnd().suppress()
498 + p.OneOrMore(
499 p.Or([
500 GenericListAttribute.Syntax,
501 GenericSimpleAttribute.Syntax,
502 ])
503 ).setResultsName("record-attributes")
504 ).setResultsName("record")
505
506 def as_json(self):
507 return {
508 'name': self.name,
509 'attribute_list': self.attribute_list,
510 }
511
512 def __repr__(self):
513 # Custom __repr__ that skips attribute_map
514 return "{}({})".format(
515 type(self).__name__, ", ".join([
516 "{}={!r}".format(attr, getattr(self, attr))
517 for attr in ['name', 'attribute_list']]))
518
519
520class Document(Node):
521 """
522 Encompasses whole output of `pactl list`
523 The document is composed of a list of :class:`Record` objects
524 """
525
526 __fragments__ = {
527 'record_list': lambda t: t['record-list'].asList(),
528 }
529
530 __syntax__ = (
531 p.OneOrMore(
532 Record.Syntax + p.Optional("\n").suppress()
533 ).setResultsName("record-list")
534 ).parseWithTabs()
535
536
537def parse_pactl_output(output):
538 """
539 Parse output of `LANG=C pactl list`
540
541 :returns: :class:`Document` object that corresponds to the parsed input
542 """
543 return Document.Syntax.parseString(output, parseAll=True)[0]
0544
=== added directory 'checkbox-support/checkbox_support/parsers/tests'
=== added file 'checkbox-support/checkbox_support/parsers/tests/__init__.py'
=== added directory 'checkbox-support/checkbox_support/parsers/tests/fixtures'
=== added file 'checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt'
--- checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,143 @@
1⎡ Virtual core pointer id=2 [master pointer (3)]
2Reporting 4 classes:
3Class originated from: 10. Type: XIButtonClass
4Buttons supported: 10
5Button labels: "Button Unknown" "Button Unknown" "Button Unknown"
6"Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button
7Horiz Wheel Right" None None None
8Button state:
9Class originated from: 10. Type: XIValuatorClass
10Detail for Valuator 0:
11Label: Abs MT Position X
12Range: 0.000000 - 1919.000000
13Resolution: 0 units/m
14Mode: absolute
15Current value: 1664.000000
16Class originated from: 10. Type: XIValuatorClass
17Detail for Valuator 1:
18Label: Abs MT Position Y
19Range: 0.000000 - 1079.000000
20Resolution: 0 units/m
21Mode: absolute
22Current value: 932.000000
23Class originated from: 0. Type: XITouchClass
24Touch mode: direct
25Max number of touches: 17
26
27⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
28Reporting 3 classes:
29Class originated from: 4. Type: XIButtonClass
30Buttons supported: 10
31Button labels: "Button Left" "Button Middle" "Button Right" "Button
32Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz
33Wheel Right" None None None
34Button state:
35Class originated from: 4. Type: XIValuatorClass
36Detail for Valuator 0:
37Label: Rel X
38Range: -1.000000 - -1.000000
39Resolution: 0 units/m
40Mode: relative
41Class originated from: 4. Type: XIValuatorClass
42Detail for Valuator 1:
43Label: Rel Y
44Range: -1.000000 - -1.000000
45Resolution: 0 units/m
46Mode: relative
47
48⎜ ↳ Quanta OpticalTouchScreen id=10 [slave pointer (2)]
49Reporting 4 classes:
50Class originated from: 10. Type: XIButtonClass
51Buttons supported: 5
52Button labels: "Button Unknown" "Button Unknown" "Button Unknown"
53"Button Wheel Up" "Button Wheel Down"
54Button state:
55Class originated from: 10. Type: XIValuatorClass
56Detail for Valuator 0:
57Label: Abs MT Position X
58Range: 0.000000 - 1919.000000
59Resolution: 0 units/m
60Mode: absolute
61Current value: 1664.000000
62Class originated from: 10. Type: XIValuatorClass
63Detail for Valuator 1:
64Label: Abs MT Position Y
65Range: 0.000000 - 1079.000000
66Resolution: 0 units/m
67Mode: absolute
68Current value: 932.000000
69Class originated from: 0. Type: XITouchClass
70Touch mode: direct
71Max number of touches: 9
72
73⎜ ↳ MCE IR Keyboard/Mouse (nuvoton-cir) id=12 [slave pointer (2)]
74Reporting 4 classes:
75Class originated from: 12. Type: XIButtonClass
76Buttons supported: 5
77Button labels: "Button Left" "Button Unknown" "Button Right" "Button
78Wheel Up" "Button Wheel Down"
79Button state:
80Class originated from: 12. Type: XIKeyClass
81Keycodes supported: 248
82Class originated from: 12. Type: XIValuatorClass
83Detail for Valuator 0:
84Label: Rel X
85Range: -1.000000 - -1.000000
86Resolution: 1 units/m
87Mode: relative
88Class originated from: 12. Type: XIValuatorClass
89Detail for Valuator 1:
90Label: Rel Y
91Range: -1.000000 - -1.000000
92Resolution: 1 units/m
93Mode: relative
94
95⎣ Virtual core keyboard id=3 [master keyboard (2)]
96Reporting 1 classes:
97Class originated from: 14. Type: XIKeyClass
98Keycodes supported: 248
99
100↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
101Reporting 1 classes:
102Class originated from: 5. Type: XIKeyClass
103Keycodes supported: 248
104
105↳ Power Button id=6 [slave keyboard (3)]
106Reporting 1 classes:
107Class originated from: 6. Type: XIKeyClass
108Keycodes supported: 248
109
110↳ Power Button id=7 [slave keyboard (3)]
111Reporting 1 classes:
112Class originated from: 7. Type: XIKeyClass
113Keycodes supported: 248
114
115↳ Laptop_Integrated_Webcam_2M id=8 [slave keyboard (3)]
116Reporting 1 classes:
117Class originated from: 8. Type: XIKeyClass
118Keycodes supported: 248
119
120↳ HID 413c:8161 id=9 [slave keyboard (3)]
121Reporting 1 classes:
122Class originated from: 9. Type: XIKeyClass
123Keycodes supported: 248
124
125↳ Nuvoton w836x7hg Infrared Remote Transceiver id=11 [slave keyboard (3)]
126Reporting 1 classes:
127Class originated from: 11. Type: XIKeyClass
128Keycodes supported: 248
129
130↳ Dell AIO WMI hotkeys id=13 [slave keyboard (3)]
131Reporting 1 classes:
132Class originated from: 13. Type: XIKeyClass
133Keycodes supported: 248
134
135↳ Chicony USB Keyboard id=14 [slave keyboard (3)]
136Reporting 1 classes:
137Class originated from: 14. Type: XIKeyClass
138Keycodes supported: 248
139
140↳ Chicony USB Keyboard id=15 [slave keyboard (3)]
141Reporting 1 classes:
142Class originated from: 15. Type: XIKeyClass
143Keycodes supported: 248
0144
=== added file 'checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt'
--- checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,166 @@
1⎡ Virtual core pointer id=2 [master pointer (3)]
2 Reporting 8 classes:
3 Class originated from: 12. Type: XIButtonClass
4 Buttons supported: 12
5 Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" None None None None None
6 Button state:
7 Class originated from: 12. Type: XIValuatorClass
8 Detail for Valuator 0:
9 Label: Rel X
10 Range: 0.000000 - 2000.000000
11 Resolution: 0 units/m
12 Mode: relative
13 Class originated from: 12. Type: XIValuatorClass
14 Detail for Valuator 1:
15 Label: Rel Y
16 Range: 0.000000 - 1400.000000
17 Resolution: 0 units/m
18 Mode: relative
19 Class originated from: 12. Type: XIValuatorClass
20 Detail for Valuator 2:
21 Label: Rel Horiz Scroll
22 Range: 0.000000 - -1.000000
23 Resolution: 0 units/m
24 Mode: relative
25 Class originated from: 12. Type: XIValuatorClass
26 Detail for Valuator 3:
27 Label: Rel Vert Scroll
28 Range: 0.000000 - -1.000000
29 Resolution: 0 units/m
30 Mode: relative
31 Class originated from: 12. Type: XIScrollClass
32 Scroll info for Valuator 2
33 type: 2 (horizontal)
34 increment: 48.000000
35 flags: 0x0
36 Class originated from: 12. Type: XIScrollClass
37 Scroll info for Valuator 3
38 type: 1 (vertical)
39 increment: 48.000000
40 flags: 0x0
41 Class originated from: 0. Type: XITouchClass
42 Touch mode: dependent
43 Max number of touches: 2
44
45⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
46 Reporting 3 classes:
47 Class originated from: 4. Type: XIButtonClass
48 Buttons supported: 10
49 Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" None None None
50 Button state:
51 Class originated from: 4. Type: XIValuatorClass
52 Detail for Valuator 0:
53 Label: Rel X
54 Range: -1.000000 - -1.000000
55 Resolution: 0 units/m
56 Mode: relative
57 Class originated from: 4. Type: XIValuatorClass
58 Detail for Valuator 1:
59 Label: Rel Y
60 Range: -1.000000 - -1.000000
61 Resolution: 0 units/m
62 Mode: relative
63
64⎜ ↳ DualPoint Stick id=11 [slave pointer (2)]
65 Reporting 3 classes:
66 Class originated from: 11. Type: XIButtonClass
67 Buttons supported: 7
68 Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right"
69 Button state:
70 Class originated from: 11. Type: XIValuatorClass
71 Detail for Valuator 0:
72 Label: Rel X
73 Range: -1.000000 - -1.000000
74 Resolution: 1 units/m
75 Mode: relative
76 Class originated from: 11. Type: XIValuatorClass
77 Detail for Valuator 1:
78 Label: Rel Y
79 Range: -1.000000 - -1.000000
80 Resolution: 1 units/m
81 Mode: relative
82
83⎜ ↳ AlpsPS/2 ALPS DualPoint TouchPad id=12 [slave pointer (2)]
84 Reporting 8 classes:
85 Class originated from: 12. Type: XIButtonClass
86 Buttons supported: 12
87 Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" None None None None None
88 Button state:
89 Class originated from: 12. Type: XIValuatorClass
90 Detail for Valuator 0:
91 Label: Rel X
92 Range: 0.000000 - 2000.000000
93 Resolution: 0 units/m
94 Mode: relative
95 Class originated from: 12. Type: XIValuatorClass
96 Detail for Valuator 1:
97 Label: Rel Y
98 Range: 0.000000 - 1400.000000
99 Resolution: 0 units/m
100 Mode: relative
101 Class originated from: 12. Type: XIValuatorClass
102 Detail for Valuator 2:
103 Label: Rel Horiz Scroll
104 Range: 0.000000 - -1.000000
105 Resolution: 0 units/m
106 Mode: relative
107 Class originated from: 12. Type: XIValuatorClass
108 Detail for Valuator 3:
109 Label: Rel Vert Scroll
110 Range: 0.000000 - -1.000000
111 Resolution: 0 units/m
112 Mode: relative
113 Class originated from: 12. Type: XIScrollClass
114 Scroll info for Valuator 2
115 type: 2 (horizontal)
116 increment: 48.000000
117 flags: 0x0
118 Class originated from: 12. Type: XIScrollClass
119 Scroll info for Valuator 3
120 type: 1 (vertical)
121 increment: 48.000000
122 flags: 0x0
123 Class originated from: 0. Type: XITouchClass
124 Touch mode: dependent
125 Max number of touches: 2
126
127⎣ Virtual core keyboard id=3 [master keyboard (2)]
128 Reporting 1 classes:
129 Class originated from: 10. Type: XIKeyClass
130 Keycodes supported: 248
131
132 ↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
133 Reporting 1 classes:
134 Class originated from: 5. Type: XIKeyClass
135 Keycodes supported: 248
136
137 ↳ Power Button id=6 [slave keyboard (3)]
138 Reporting 1 classes:
139 Class originated from: 6. Type: XIKeyClass
140 Keycodes supported: 248
141
142 ↳ Video Bus id=7 [slave keyboard (3)]
143 Reporting 1 classes:
144 Class originated from: 7. Type: XIKeyClass
145 Keycodes supported: 248
146
147 ↳ Power Button id=8 [slave keyboard (3)]
148 Reporting 1 classes:
149 Class originated from: 8. Type: XIKeyClass
150 Keycodes supported: 248
151
152 ↳ CNF9055 id=9 [slave keyboard (3)]
153 Reporting 1 classes:
154 Class originated from: 9. Type: XIKeyClass
155 Keycodes supported: 248
156
157 ↳ AT Translated Set 2 keyboard id=10 [slave keyboard (3)]
158 Reporting 1 classes:
159 Class originated from: 10. Type: XIKeyClass
160 Keycodes supported: 248
161
162 ↳ Toshiba input device id=13 [slave keyboard (3)]
163 Reporting 1 classes:
164 Class originated from: 13. Type: XIKeyClass
165 Keycodes supported: 248
166
0167
=== added directory 'checkbox-support/checkbox_support/parsers/tests/pactl_data'
=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt'
--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,33 @@
1Card #0
2 Name: alsa_card.pci-0000_02_00.1
3 Driver: module-alsa-card.c
4 Owner Module: 4
5 Properties:
6 alsa.card = "2"
7 alsa.card_name = "HDA NVidia"
8 alsa.long_card_name = "HDA NVidia at 0xfbdfc000 irq 34"
9 alsa.driver_name = "snd_hda_intel"
10 device.bus_path = "pci-0000:02:00.1"
11 sysfs.path = "/devices/pci0000:00/0000:00:03.0/0000:02:00.1/sound/card2"
12 device.bus = "pci"
13 device.vendor.id = "10de"
14 device.vendor.name = "NVIDIA Corporation"
15 device.string = "2"
16 device.description = "HDA NVidia"
17 module-udev-detect.discovered = "1"
18 device.icon_name = "audio-card-pci"
19 Profiles:
20 output:hdmi-stereo: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5400)
21 output:hdmi-surround: Wyjście Digital Surround 5.1 (HDMI) (sinks: 1, sources: 0, priority. 300)
22 output:hdmi-stereo-extra1: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5200)
23 output:hdmi-stereo-extra2: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5200)
24 output:hdmi-surround-extra2: Wyjście Digital Surround 5.1 (HDMI) (sinks: 1, sources: 0, priority. 100)
25 off: Wyłącz (sinks: 0, sources: 0, priority. 0)
26 Active Profile: output:hdmi-stereo-extra1
27 Ports:
28 hdmi-output-0: HDMI / DisplayPort (priority 5900)
29 Part of profile(s): output:hdmi-stereo, output:hdmi-surround
30 hdmi-output-1: HDMI / DisplayPort 2 (priority 5800)
31 Part of profile(s): output:hdmi-stereo-extra1
32 hdmi-output-2: HDMI / DisplayPort 3 (priority 5700)
33 Part of profile(s): output:hdmi-stereo-extra2, output:hdmi-surround-extra2
034
=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt'
--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,51 @@
1Card #1
2 Name: alsa_card.pci-0000_00_1b.0
3 Driver: module-alsa-card.c
4 Owner Module: 5
5 Properties:
6 alsa.card = "0"
7 alsa.card_name = "HDA Intel"
8 alsa.long_card_name = "HDA Intel at 0xf9ff8000 irq 70"
9 alsa.driver_name = "snd_hda_intel"
10 device.bus_path = "pci-0000:00:1b.0"
11 sysfs.path = "/devices/pci0000:00/0000:00:1b.0/sound/card0"
12 device.bus = "pci"
13 device.vendor.id = "8086"
14 device.vendor.name = "Intel Corporation"
15 device.product.name = "82801JI (ICH10 Family) HD Audio Controller"
16 device.form_factor = "internal"
17 device.string = "0"
18 device.description = "Wbudowany dźwięk"
19 module-udev-detect.discovered = "1"
20 device.icon_name = "audio-card-pci"
21 Profiles:
22 output:analog-stereo: Wyjście Analogowe stereo (sinks: 1, sources: 0, priority. 6000)
23 output:analog-stereo+input:analog-stereo: Analogowy dupleks stereo (sinks: 1, sources: 1, priority. 6060)
24 output:analog-surround-40: Wyjście Analogowe surround 4.0 (sinks: 1, sources: 0, priority. 700)
25 output:analog-surround-40+input:analog-stereo: Wyjście Analogowe surround 4.0 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 760)
26 output:analog-surround-41: Wyjście Analogowe surround 4.1 (sinks: 1, sources: 0, priority. 800)
27 output:analog-surround-41+input:analog-stereo: Wyjście Analogowe surround 4.1 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 860)
28 output:analog-surround-50: Wyjście Analogowe surround 5.0 (sinks: 1, sources: 0, priority. 700)
29 output:analog-surround-50+input:analog-stereo: Wyjście Analogowe surround 5.0 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 760)
30 output:analog-surround-51: Wyjście Analogowe surround 5.1 (sinks: 1, sources: 0, priority. 800)
31 output:analog-surround-51+input:analog-stereo: Wyjście Analogowe surround 5.1 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 860)
32 output:analog-surround-71: Wyjście Analog Surround 7.1 (sinks: 1, sources: 0, priority. 700)
33 output:analog-surround-71+input:analog-stereo: Wyjście Analog Surround 7.1 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 760)
34 output:iec958-stereo: Wyjście Cyfrowe stereo (IEC958) (sinks: 1, sources: 0, priority. 5500)
35 output:iec958-stereo+input:analog-stereo: Wyjście Cyfrowe stereo (IEC958) + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 5560)
36 input:analog-stereo: Wejście Analogowe stereo (sinks: 0, sources: 1, priority. 60)
37 off: Wyłącz (sinks: 0, sources: 0, priority. 0)
38 Active Profile: output:analog-stereo+input:analog-stereo
39 Ports:
40 analog-output: Wyjście analogowe (priority 9900)
41 Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo, output:analog-surround-40, output:analog-surround-40+input:analog-stereo, output:analog-surround-41, output:analog-surround-41+input:analog-stereo, output:analog-surround-50, output:analog-surround-50+input:analog-stereo, output:analog-surround-51, output:analog-surround-51+input:analog-stereo, output:analog-surround-71, output:analog-surround-71+input:analog-stereo
42 analog-output-headphones: Słuchawki (priority 9000)
43 Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo
44 analog-input-microphone-front: Przedni mikrofon (priority 8500)
45 Part of profile(s): output:analog-stereo+input:analog-stereo, output:analog-surround-40+input:analog-stereo, output:analog-surround-41+input:analog-stereo, output:analog-surround-50+input:analog-stereo, output:analog-surround-51+input:analog-stereo, output:analog-surround-71+input:analog-stereo, output:iec958-stereo+input:analog-stereo, input:analog-stereo
46 analog-input-microphone-rear: Tylny mikrofon (priority 8200)
47 Part of profile(s): output:analog-stereo+input:analog-stereo, output:analog-surround-40+input:analog-stereo, output:analog-surround-41+input:analog-stereo, output:analog-surround-50+input:analog-stereo, output:analog-surround-51+input:analog-stereo, output:analog-surround-71+input:analog-stereo, output:iec958-stereo+input:analog-stereo, input:analog-stereo
48 analog-input-linein: Wejście liniowe (priority 8100)
49 Part of profile(s): output:analog-stereo+input:analog-stereo, output:analog-surround-40+input:analog-stereo, output:analog-surround-41+input:analog-stereo, output:analog-surround-50+input:analog-stereo, output:analog-surround-51+input:analog-stereo, output:analog-surround-71+input:analog-stereo, output:iec958-stereo+input:analog-stereo, input:analog-stereo
50 iec958-stereo-output: Wyjście cyfrowe (S/PDIF) (priority 0)
51 Part of profile(s): output:iec958-stereo, output:iec958-stereo+input:analog-stereo
052
=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt'
--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,30 @@
1Card #2
2 Name: alsa_card.usb-046d_0825_0E3A8A10-02-U0x46d0x825
3 Driver: module-alsa-card.c
4 Owner Module: 6
5 Properties:
6 alsa.card = "1"
7 alsa.card_name = "USB Device 0x46d:0x825"
8 alsa.long_card_name = "USB Device 0x46d:0x825 at usb-0000:00:1d.7-1, high speed"
9 alsa.driver_name = "snd_usb_audio"
10 device.bus_path = "pci-0000:00:1d.7-usb-0:1:1.2"
11 sysfs.path = "/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.2/sound/card1"
12 udev.id = "usb-046d_0825_0E3A8A10-02-U0x46d0x825"
13 device.bus = "usb"
14 device.vendor.id = "046d"
15 device.vendor.name = "Logitech, Inc."
16 device.product.id = "0825"
17 device.product.name = "Webcam C270"
18 device.serial = "046d_0825_0E3A8A10"
19 device.form_factor = "webcam"
20 device.string = "1"
21 device.description = "Webcam C270"
22 module-udev-detect.discovered = "1"
23 device.icon_name = "camera-web-usb"
24 Profiles:
25 input:analog-mono: Wejście Analogowe mono (sinks: 0, sources: 1, priority. 1)
26 off: Wyłącz (sinks: 0, sources: 0, priority. 0)
27 Active Profile: input:analog-mono
28 Ports:
29 analog-input-microphone: Mikrofon (priority 8700)
30 Part of profile(s): input:analog-mono
031
=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt'
--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,41 @@
1Card #0
2 Name: alsa_card.pci-0000_00_1b.0
3 Driver: module-alsa-card.c
4 Owner Module: 4
5 Properties:
6 alsa.card = "0"
7 alsa.card_name = "HDA Intel PCH"
8 alsa.long_card_name = "HDA Intel PCH at 0xe0610000 irq 46"
9 alsa.driver_name = "snd_hda_intel"
10 device.bus_path = "pci-0000:00:1b.0"
11 sysfs.path = "/devices/pci0000:00/0000:00:1b.0/sound/card0"
12 device.bus = "pci"
13 device.vendor.id = "8086"
14 device.vendor.name = "Intel Corporation"
15 device.product.name = "Panther Point High Definition Audio Controller"
16 device.form_factor = "internal"
17 device.string = "0"
18 device.description = "Wbudowany dźwięk"
19 module-udev-detect.discovered = "1"
20 device.icon_name = "audio-card-pci"
21 Profiles:
22 output:analog-stereo: Wyjście Analogowe stereo (sinks: 1, sources: 0, priority. 6000)
23 output:analog-stereo+input:analog-stereo: Analogowy dupleks stereo (sinks: 1, sources: 1, priority. 6060)
24 output:hdmi-stereo: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5400)
25 output:hdmi-stereo+input:analog-stereo: Wyjście Digital Stereo (HDMI) + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 5460)
26 output:hdmi-surround: Wyjście Digital Surround 5.1 (HDMI) (sinks: 1, sources: 0, priority. 300)
27 output:hdmi-surround+input:analog-stereo: Wyjście Digital Surround 5.1 (HDMI) + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 360)
28 input:analog-stereo: Wejście Analogowe stereo (sinks: 0, sources: 1, priority. 60)
29 off: Wyłącz (sinks: 0, sources: 0, priority. 0)
30 Active Profile: output:analog-stereo+input:analog-stereo
31 Ports:
32 analog-output-speaker: Głośniki (priority 10000)
33 Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo
34 analog-output-headphones: Słuchawki (priority 9000)
35 Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo
36 analog-input-microphone-internal: Wewnętrzny mikrofon (priority 8900)
37 Part of profile(s): output:analog-stereo+input:analog-stereo, output:hdmi-stereo+input:analog-stereo, output:hdmi-surround+input:analog-stereo, input:analog-stereo
38 analog-input-microphone: Mikrofon (priority 8700)
39 Part of profile(s): output:analog-stereo+input:analog-stereo, output:hdmi-stereo+input:analog-stereo, output:hdmi-surround+input:analog-stereo, input:analog-stereo
40 hdmi-output-0: HDMI / DisplayPort (priority 5900)
41 Part of profile(s): output:hdmi-stereo, output:hdmi-stereo+input:analog-stereo, output:hdmi-surround, output:hdmi-surround+input:analog-stereo
042
=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt'
--- checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt 1970-01-01 00:00:00 +0000
+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt 2014-01-07 13:44:32 +0000
@@ -0,0 +1,608 @@
1Module #0
2 Name: module-device-restore
3 Argument:
4 Usage counter: n/a
5 Properties:
6 module.author = "Lennart Poettering"
7 module.description = "Automatically restore the volume/mute state of devices"
8 module.version = "1.1"
9
10Module #1
11 Name: module-stream-restore
12 Argument:
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches