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
1=== added directory 'checkbox-support'
2=== added symlink 'checkbox-support/COPYING'
3=== target is u'../plainbox/COPYING'
4=== added file 'checkbox-support/README.rst'
5--- checkbox-support/README.rst 1970-01-01 00:00:00 +0000
6+++ checkbox-support/README.rst 2014-01-07 13:44:32 +0000
7@@ -0,0 +1,6 @@
8+CheckBox Support
9+================
10+
11+CheckBox Support library is a collection of python modules used by PlainBox
12+providers scripts.
13+They were originally provided by the checkbox python package.
14
15=== added directory 'checkbox-support/checkbox_support'
16=== added file 'checkbox-support/checkbox_support/__init__.py'
17=== added directory 'checkbox-support/checkbox_support/contrib'
18=== added file 'checkbox-support/checkbox_support/contrib/__init__.py'
19=== added file 'checkbox-support/checkbox_support/contrib/xrandr.py'
20--- checkbox-support/checkbox_support/contrib/xrandr.py 1970-01-01 00:00:00 +0000
21+++ checkbox-support/checkbox_support/contrib/xrandr.py 2014-01-07 13:44:32 +0000
22@@ -0,0 +1,1064 @@
23+#!/usr/bin/python3
24+# -*- coding: utf-8 -*-
25+#
26+# Python-XRandR provides a high level API for the XRandR extension of the
27+# X.org server. XRandR allows to configure resolution, refresh rate, rotation
28+# of the screen and multiple outputs of graphics cards.
29+#
30+# Copyright 2007 © Sebastian Heinlein <sebastian.heinlein@web.de>
31+# Copyright 2007 © Michael Vogt <mvo@ubuntu.com>
32+# Copyright 2007 © Canonical Ltd.
33+#
34+# In many aspects it follows the design of the xrand tool of the X.org, which
35+# comes with the following copyright:
36+#
37+# Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
38+# Copyright © 2002 Hewlett Packard Company, Inc.
39+# Copyright © 2006 Intel Corporation
40+#
41+# And can be downloaded here:
42+#
43+# git://anongit.freedesktop.org/git/xorg/app/xrandr
44+#
45+# This library is free software; you can redistribute it and/or
46+# modify it under the terms of the GNU Lesser General Public
47+# License as published by the Free Software Foundation; either
48+# version 2.1 of the License, or any later version.
49+#
50+# This library is distributed in the hope that it will be useful,
51+# but WITHOUT ANY WARRANTY; without even the implied warranty of
52+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
53+# Lesser General Public License for more details.
54+#
55+# You should have received a copy of the GNU Lesser General Public
56+# License along with this library; if not, write to the Free Software
57+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
58+# MA 02110-1301 USA
59+
60+from ctypes import (
61+ POINTER,
62+ Structure,
63+ byref,
64+ c_char_p,
65+ c_void_p,
66+ c_int,
67+ c_long,
68+ c_ulong,
69+ c_ushort,
70+ cdll,
71+)
72+import os
73+
74+RR_ROTATE_0 = 1
75+RR_ROTATE_90 = 2
76+RR_ROTATE_180 = 4
77+RR_ROTATE_270 = 8
78+RR_REFLECT_X = 16
79+RR_REFLECT_Y = 32
80+
81+RR_CONNECTED = 0
82+RR_DISCONNECTED = 1
83+RR_UNKOWN_CONNECTION = 2
84+
85+RR_BAD_OUTPUT = 0
86+RR_BAD_CRTC = 1
87+RR_BAD_MODE = 2
88+
89+RR_SET_CONFIG_SUCCESS = 0
90+RR_SET_CONFIG_INVALID_CONFIG_TIME = 1
91+RR_SET_CONFIG_INVALID_TIME = 2
92+RR_SET_CONFIG_FAILED = 3
93+
94+# Flags to keep track of changes
95+CHANGES_NONE = 0
96+CHANGES_CRTC = 1
97+CHANGES_MODE = 2
98+CHANGES_RELATION = 4
99+CHANGES_POSITION = 8
100+CHANGES_ROTATION = 16
101+CHANGES_REFLECTION = 32
102+CHANGES_AUTOMATIC = 64
103+CHANGES_REFRESH = 128
104+CHANGES_PROPERTY = 256
105+
106+# Relation information
107+RELATION_ABOVE = 0
108+RELATION_BELOW = 1
109+RELATION_RIGHT_OF = 2
110+RELATION_LEFT_OF = 3
111+RELATION_SAME_AS = 4
112+
113+# some fundamental datatypes
114+RRCrtc = c_long
115+RROutput = c_long
116+RRMode = c_long
117+Connection = c_ushort
118+SubpixelOrder = c_ushort
119+Time = c_ulong
120+Rotation = c_ushort
121+Status = c_int
122+
123+# load the libs
124+xlib = cdll.LoadLibrary('libX11.so.6')
125+rr = cdll.LoadLibrary('libXrandr.so.2')
126+
127+
128+# query resources
129+class _XRRModeInfo(Structure):
130+ _fields_ = [
131+ ("id", RRMode), # XID is c_long
132+ ("width", c_int),
133+ ("height", c_int),
134+ ("dotClock", c_long),
135+ ("hSyncStart", c_int),
136+ ("hSyncEnd", c_int),
137+ ("hTotal", c_int),
138+ ("hSkew", c_int),
139+ ("vSyncStart", c_int),
140+ ("vSyncEnd", c_int),
141+ ("vTotal", c_int),
142+ ("name", c_char_p),
143+ ("nameLength", c_int),
144+ ("modeFlags", c_long),
145+ ]
146+
147+
148+class _XRRScreenSize(Structure):
149+ _fields_ = [
150+ ("width", c_int),
151+ ("height", c_int),
152+ ("mwidth", c_int),
153+ ("mheight", c_int)
154+ ]
155+
156+
157+class _XRRCrtcInfo(Structure):
158+ _fields_ = [
159+ ("timestamp", Time),
160+ ("x", c_int),
161+ ("y", c_int),
162+ ("width", c_int),
163+ ("height", c_int),
164+ ("mode", RRMode),
165+ ("rotation", c_int),
166+ ("noutput", c_int),
167+ ("outputs", POINTER(RROutput)),
168+ ("rotations", Rotation),
169+ ("npossible", c_int),
170+ ("possible", POINTER(RROutput)),
171+ ]
172+
173+
174+class _XRRScreenResources(Structure):
175+ _fields_ = [
176+ ("timestamp", Time),
177+ ("configTimestamp", Time),
178+ ("ncrtc", c_int),
179+ ("crtcs", POINTER(RRCrtc)),
180+ ("noutput", c_int),
181+ ("outputs", POINTER(RROutput)),
182+ ("nmode", c_int),
183+ ("modes", POINTER(_XRRModeInfo)),
184+ ]
185+
186+
187+class RRError(Exception):
188+ """Base exception class of the module"""
189+ pass
190+
191+
192+class UnsupportedRRError(RRError):
193+ """Raised if the required XRandR extension version is not available"""
194+ def __init__(self, required, current):
195+ self.required = required
196+ self.current = current
197+
198+
199+# XRRGetOutputInfo
200+class _XRROutputInfo(Structure):
201+ _fields_ = [
202+ ("timestamp", Time),
203+ ("crtc", c_int),
204+ ("name", c_char_p),
205+ ("nameLen", c_int),
206+ ("mm_width", c_ulong),
207+ ("mm_height", c_ulong),
208+ ("connection", Connection),
209+ ("subpixel_order", SubpixelOrder),
210+ ("ncrtc", c_int),
211+ ("crtcs", POINTER(RRCrtc)),
212+ ("nclone", c_int),
213+ ("clones", POINTER(RROutput)),
214+ ("nmode", c_int),
215+ ("npreferred", c_int),
216+ ("modes", POINTER(RRMode))
217+ ]
218+
219+
220+class _XRRCrtcGamma(Structure):
221+ _fields_ = [
222+ ('size', c_int),
223+ ('red', POINTER(c_ushort)),
224+ ('green', POINTER(c_ushort)),
225+ ('blue', POINTER(c_ushort)),
226+ ]
227+
228+
229+def _array_conv(array, type, conv=lambda x: x):
230+ length = len(array)
231+ res = (type * length)()
232+ for i in range(length):
233+ res[i] = conv(array[i])
234+ return res
235+
236+
237+class Output:
238+ """The output is a reference to a supported output jacket of the graphics
239+ card. Outputs are attached to a hardware pipe to be used. Furthermore
240+ they can be a clone of another output or show a subset of the screen"""
241+ def __init__(self, info, id, screen):
242+ """Initializes an output instance"""
243+ self._info = info
244+ self.id = id
245+ self._screen = screen
246+ # Store changes later here
247+ self._mode = None
248+ self._crtc = None
249+ self._rotation = RR_ROTATE_0
250+ self._relation = None
251+ self._relation_offset = 0
252+ self._relative_to = None
253+ self._position = None
254+ self._reflection = None
255+ self._automatic = None
256+ self._rate = None
257+ self._changes = CHANGES_NONE
258+ self._x = 0
259+ self._y = 0
260+
261+ self.name = self._info.contents.name
262+
263+ def __del__(self):
264+ """Frees the internal reference to the output info if the output gets
265+ removed"""
266+ rr.XRRFreeOutputInfo(self._info)
267+
268+ def get_physical_width(self):
269+ """Returns the display width reported by the connected output device"""
270+ return self._info.contents.mm_width
271+
272+ def get_physical_height(self):
273+ """
274+ Returns the display height reported by the connected output device
275+ """
276+ return self._info.contents.mm_height
277+
278+ def get_crtc(self):
279+ """Returns the xid of the hardware pipe to which the output is
280+ attached. If the output is disabled it will return 0"""
281+ return self._info.contents.crtc
282+
283+ def get_crtcs(self):
284+ """Returns the xids of the hardware pipes to which the output could
285+ be attached"""
286+ crtcs = []
287+ for i in range(self._info.contents.ncrtc):
288+ for crtc in self._screen.crtcs:
289+ if crtc.xid == self._info.contents.crtcs[i]:
290+ crtcs.append(crtc)
291+ return crtcs
292+
293+ def get_available_rotations(self):
294+ """Returns a binary flag of the supported rotations of the output or
295+ 0 if the output is disabled"""
296+ rotations = RR_ROTATE_0
297+ found = False
298+ if self.is_active():
299+ # Get the rotations supported by all crtcs to make assigning
300+ # crtcs easier. Furthermore there don't seem to be so many
301+ # cards which show another behavior
302+ for crtc in self.get_crtcs():
303+ # Set rotations to the value of the first found crtc and
304+ # then create a subset only for all other crtcs
305+ if not found:
306+ rotations = crtc.get_available_rotations()
307+ found = True
308+ else:
309+ rotations = rotations & crtc.get_available_rotations()
310+ return rotations
311+
312+ def get_available_modes(self):
313+ """Returns the list of supported mode lines (resolution, refresh rate)
314+ that are supported by the connected device"""
315+ modes = []
316+ for m in range(self._info.contents.nmode):
317+ output_modes = self._info.contents.modes
318+ for s in range(self._screen._resources.contents.nmode):
319+ screen_modes = self._screen._resources.contents.modes
320+ if screen_modes[s].id == output_modes[m]:
321+ modes.append(screen_modes[s])
322+ return modes
323+
324+ def get_preferred_mode(self):
325+ """Returns an index that refers to the list of available modes and
326+ points to the preferred mode of the connected device"""
327+ return self._info.contents.npreferred
328+
329+ def is_active(self):
330+ """Returns True if the output is attached to a hardware pipe, is
331+ enabled"""
332+ return self._info.contents.crtc != 0
333+
334+ def is_connected(self):
335+ """Return True if a device is detected at the output"""
336+ if self._info.contents.connection in (RR_CONNECTED,
337+ RR_UNKOWN_CONNECTION):
338+ return True
339+ return False
340+
341+ def disable(self):
342+ """Disables the output"""
343+ if not self.is_active():
344+ return
345+ self._mode = None
346+ self._crtc._outputs.remove(self)
347+ self._crtc = None
348+ self._changes = self._changes | CHANGES_CRTC | CHANGES_MODE
349+
350+ def set_to_mode(self, mode):
351+ modes = self.get_available_modes()
352+ if mode in range(len(modes)):
353+ self._mode = modes[mode].id
354+ return
355+ raise RRError("Mode is not available")
356+
357+ def set_to_preferred_mode(self):
358+ modes = self.get_available_modes()
359+ mode = modes[self.get_preferred_mode()]
360+ if mode != None:
361+ self._mode = mode.id
362+ return
363+ raise RRError("Preferred mode is not available")
364+
365+ def get_clones(self):
366+ """Returns the xids of the outputs which can be clones of the output"""
367+ clones = []
368+ for i in range(self._info.contents.nclone):
369+ id = self._info.contents.clones[i]
370+ o = self._screen.get_output_by_id(id)
371+ clones.append(o)
372+ return clones
373+
374+ def set_relation(self, relative, relation, offset=0):
375+ """Sets the position of the output in relation to the given one"""
376+ rel = self._screen.get_output_by_name(relative)
377+ if rel and relation in (RELATION_LEFT_OF, RELATION_RIGHT_OF,
378+ RELATION_ABOVE, RELATION_BELOW,
379+ RELATION_SAME_AS):
380+ self._relation = relation
381+ self._relative_to = rel
382+ self._relation_offset = offset
383+ self._changes = self._changes | CHANGES_RELATION
384+ else:
385+ raise RRError("The given relative output or relation is not "
386+ "available")
387+
388+ def has_changed(self, changes=None):
389+ """Checks if the output has changed: Either for a specific change or
390+ generally"""
391+ if changes:
392+ return self._changes & changes
393+ else:
394+ return self._changes != CHANGES_NONE
395+
396+
397+class Crtc:
398+ """The crtc is a reference to a hardware pipe that is provided by the
399+ graphics device. Outputs can be attached to crtcs"""
400+
401+ def __init__(self, info, xid, screen):
402+ """Initializes the hardware pipe object"""
403+ self._info = info
404+ self.xid = xid
405+ self._screen = screen
406+ self._outputs = []
407+
408+ def __del__(self):
409+ """Frees the reference to the rendering pipe if the instance gets
410+ removed"""
411+ rr.XRRFreeCrtcConfigInfo(self._info)
412+
413+ def get_xid(self):
414+ """Returns the internal id of the crtc from the X server"""
415+ return self.xid
416+
417+ def get_available_rotations(self):
418+ """Returns a binary flag that contains the supported rotations of the
419+ hardware pipe"""
420+ return self._info.contents.rotations
421+
422+ def set_config(self, x, y, mode, outputs, rotation=RR_ROTATE_0):
423+ """Configures the render pipe with the given mode and outputs. X and y
424+ set the position of the crtc output in the screen"""
425+ rr.XRRSetCrtcConfig(self._screen._display,
426+ self._screen._resources,
427+ self.xid,
428+ self._screen.get_timestamp(),
429+ c_int(x), c_int(y),
430+ mode,
431+ rotation,
432+ _array_conv(outputs, RROutput, lambda x: x.id),
433+ len(outputs))
434+
435+ def apply_changes(self):
436+ """Applies the stored changes"""
437+ if len(self._outputs) > 0:
438+ output = self._outputs[0]
439+ self.set_config(output._x, output._y, output._mode,
440+ self._outputs, output._rotation)
441+ else:
442+ self.disable()
443+
444+ def disable(self):
445+ """Turns off all outputs on the crtc"""
446+ rr.XRRSetCrtcConfig(self._screen._display,
447+ self._screen._resources,
448+ self.xid,
449+ self._screen.get_timestamp(),
450+ 0, 0,
451+ None,
452+ RR_ROTATE_0,
453+ 0, 0)
454+
455+ #FIXME: support gamma settings
456+ """
457+ def get_gamma_size(self):
458+ return rr.XRRGetCrtcGammaSize(self._screen._display, self.id)
459+ def get_gamma(self):
460+ result = rr.XRRGetCrtcGamma(self._screen._display, self.id)
461+ return _from_gamma(result)
462+ def set_gamma(self, gamma):
463+ g = _to_gamma(gamma)
464+ rr.XRRSetCrtcGamma(self._screen._display, self.id, g)
465+ rr.XRRFreeGamma(g)
466+ gamma = property(get_gamma, set_gamma)"""
467+
468+ def load_outputs(self):
469+ """Get the currently assigned outputs"""
470+ outputs = []
471+ for i in range(self._info.contents.noutput):
472+ id = self._info.contents.outputs[i]
473+ o = self._screen.get_output_by_id(id)
474+ outputs.append(o)
475+ self._outputs = outputs
476+
477+ def get_outputs(self):
478+ """Returns the list of attached outputs"""
479+ return self._outputs
480+
481+ def add_output(self, output):
482+ """Adds the specified output to the crtc"""
483+ output._crtc = self
484+ self._outputs.append(output)
485+
486+ def supports_output(self, output):
487+ """Check if the output can be used by the crtc.
488+ See check_crtc_for_output in xrandr.c"""
489+ if not self.xid in [c.xid for c in output.get_crtcs()]:
490+ return False
491+ if len(self._outputs):
492+ for other in self._outputs:
493+ if other == output:
494+ continue
495+ if other._x != output._x:
496+ return False
497+ if other._y != output._y:
498+ return False
499+ if other._mode != output._mode:
500+ return False
501+ if other._rotation != output._rotation:
502+ return False
503+ #FIXME: pick_crtc is still missing
504+ elif self._info.contents.noutput > 0:
505+ if self._info.contents.x != output._x:
506+ return False
507+ if self._info.contents.y != output._y:
508+ return False
509+ if self._info.contents.mode_info != output._mode:
510+ return False
511+ if self._info.rotation != output._rotation:
512+ return False
513+ return True
514+
515+ def supports_rotation(self, rotation):
516+ """Check if the given rotation is supported by the crtc"""
517+ rotations = self._info.contents.rotations
518+ dir = rotation & (RR_ROTATE_0 | RR_ROTATE_90 | RR_ROTATE_180 |
519+ RR_ROTATE_270)
520+ reflect = rotation & (RR_REFLECT_X | RR_REFLECT_Y)
521+ if (((rotations & dir) != 0) and ((rotations & reflect) == reflect)):
522+ return True
523+ return False
524+
525+ def has_changed(self):
526+ """Check if there are any new outputs assigned to the crtc or any
527+ outputs with a changed mode or position"""
528+ if len(self._outputs) != self._info.contents.noutput:
529+ return True
530+ for i in range(self._info.contents.noutput):
531+ id = self._info.contents.outputs[i]
532+ output = self._screen.get_output_by_id(id)
533+ if not output in self._outputs:
534+ return True
535+ if output.has_changed():
536+ return True
537+ return False
538+
539+
540+class Screen:
541+ def __init__(self, dpy, screen=-1):
542+ """Initializes the screen"""
543+ # Some sane default values
544+ self.outputs = {}
545+ self.crtcs = []
546+ self._width = 0
547+ self._height = 0
548+ self._width_max = 0
549+ self._height_max = 0
550+ self._width_min = 0
551+ self._height_min = 0
552+ self._width_mm = 0
553+ self._height_mm = 0
554+
555+ self._display = dpy
556+ if not -1 <= screen < xlib.XScreenCount(dpy):
557+ raise RRError("The chosen screen is not available", screen)
558+ elif screen == -1:
559+ self._screen = xlib.XDefaultScreen(dpy)
560+ else:
561+ self._screen = screen
562+ self._root = xlib.XDefaultRootWindow(self._display, self._screen)
563+ self._id = rr.XRRRootToScreen(self._display, self._root)
564+
565+ self._load_resources()
566+ self._load_config()
567+ (self._width, self._height,
568+ self._width_mm, self._height_mm) = self.get_size()
569+ if XRANDR_VERSION >= (1, 2):
570+ self._load_screen_size_range()
571+ self._load_crtcs()
572+ self._load_outputs()
573+
574+ # Store XRandR 1.0 changes here
575+ self._rate = self.get_current_rate()
576+ self._rotation = self.get_current_rotation()
577+ self._size_index = self.get_current_size_index()
578+
579+ def __del__(self):
580+ """Free the reference to the interal screen config if the screen
581+ gets removed"""
582+ rr.XRRFreeScreenConfigInfo(self._config)
583+
584+ def _load_config(self):
585+ """Loads the screen configuration. Only needed privately by the
586+ the bindings"""
587+ class XRRScreenConfiguration(Structure):
588+ " private to Xrandr "
589+ pass
590+ gsi = rr.XRRGetScreenInfo
591+ gsi.restype = POINTER(XRRScreenConfiguration)
592+ self._config = gsi(self._display, self._root)
593+
594+ def _load_screen_size_range(self):
595+ """Detects the dimensionios of the screen"""
596+ minWidth = c_int()
597+ minHeight = c_int()
598+ maxWidth = c_int()
599+ maxHeight = c_int()
600+ res = rr.XRRGetScreenSizeRange(self._display, self._root,
601+ byref(minWidth), byref(minHeight),
602+ byref(maxWidth), byref(maxHeight))
603+ if res:
604+ self._width_max = maxWidth.value
605+ self._width_min = minWidth.value
606+ self._height_max = maxHeight.value
607+ self._height_min = minHeight.value
608+
609+ def _load_resources(self):
610+ """Loads the screen resources. Only needed privately for the
611+ bindings"""
612+ gsr = rr.XRRGetScreenResources
613+ gsr.restype = POINTER(_XRRScreenResources)
614+ self._resources = gsr(self._display, self._root)
615+
616+ def _load_crtcs(self):
617+ """Loads the available XRandR 1.2 crtcs (hardware pipes) of
618+ the screen"""
619+ gci = rr.XRRGetCrtcInfo
620+ gci.restype = POINTER(_XRRCrtcInfo)
621+ c = self._resources.contents.crtcs
622+ for i in range(self._resources.contents.ncrtc):
623+ xrrcrtcinfo = gci(self._display, self._resources, c[i])
624+ self.crtcs.append(Crtc(xrrcrtcinfo, c[i], self))
625+
626+ def _load_outputs(self):
627+ """Loads the available XRandR 1.2 outputs of the screen"""
628+ goi = rr.XRRGetOutputInfo
629+ goi.restype = POINTER(_XRROutputInfo)
630+ o = self._resources.contents.outputs
631+ for i in range(self._resources.contents.noutput):
632+ xrroutputinfo = goi(self._display, self._resources, o[i])
633+ output = Output(xrroutputinfo, o[i], self)
634+ self.outputs[xrroutputinfo.contents.name] = output
635+ # Store the mode of the crtc in the output instance
636+ crtc = self.get_crtc_by_xid(output.get_crtc())
637+ if crtc:
638+ output._mode = crtc._info.contents.mode
639+ crtc.add_output(output)
640+
641+ def get_size(self):
642+ """Returns the current pixel and physical size of the screen"""
643+ width = xlib.XDisplayWidth(self._display, self._screen)
644+ width_mm = xlib.XDisplayWidthMM(self._display, self._screen)
645+ height = xlib.XDisplayHeight(self._display, self._screen)
646+ height_mm = xlib.XDisplayHeightMM(self._display, self._screen)
647+ return width, height, width_mm, height_mm
648+
649+ def get_timestamp(self):
650+ """Creates a X timestamp that must be used when applying changes, since
651+ they can be delayed"""
652+ config_timestamp = Time()
653+ rr.XRRTimes.restpye = c_ulong
654+ return rr.XRRTimes(self._display, self._id, byref(config_timestamp))
655+
656+ def get_crtc_by_xid(self, xid):
657+ """Returns the crtc with the given xid or None"""
658+ for crtc in self.crtcs:
659+ if crtc.xid == xid:
660+ return crtc
661+ return None
662+
663+ def get_current_rate(self):
664+ """Returns the currently used refresh rate"""
665+ _check_required_version((1, 0))
666+ xccr = rr.XRRConfigCurrentRate
667+ xccr.restype = c_int
668+ return xccr(self._config)
669+
670+ def get_available_rates_for_size_index(self, size_index):
671+ """Returns the refresh rates that are supported by the screen for
672+ the given resolution. See get_available_sizes for the resolution to
673+ which size_index points"""
674+ _check_required_version((1, 0))
675+ rates = []
676+ nrates = c_int()
677+ rr.XRRConfigRates.restype = POINTER(c_ushort)
678+ _rates = rr.XRRConfigRates(self._config, size_index, byref(nrates))
679+ for r in range(nrates.value):
680+ rates.append(_rates[r])
681+ return rates
682+
683+ def get_current_rotation(self):
684+ """Returns the currently used rotation. Can be RR_ROTATE_0,
685+ RR_ROTATE_90, RR_ROTATE_180 or RR_ROTATE_270"""
686+ _check_required_version((1, 0))
687+ current = c_ushort()
688+ rr.XRRConfigRotations(self._config, byref(current))
689+ return current.value
690+
691+ def get_available_rotations(self):
692+ """Returns a binary flag that holds the available resolutions"""
693+ _check_required_version((1, 0))
694+ current = c_ushort()
695+ rotations = rr.XRRConfigRotations(self._config, byref(current))
696+ return rotations
697+
698+ def get_current_size_index(self):
699+ """Returns the position of the currently used resolution size in the
700+ list of available resolutions. See get_available_sizes"""
701+ _check_required_version((1, 0))
702+ rotation = c_ushort()
703+ size = rr.XRRConfigCurrentConfiguration(self._config,
704+ byref(rotation))
705+ return size
706+
707+ def get_available_sizes(self):
708+ """Returns the available resolution sizes of the screen. The size
709+ index points to the corresponding resolution of this list"""
710+ _check_required_version((1, 0))
711+ sizes = []
712+ nsizes = c_int()
713+ xcs = rr.XRRConfigSizes
714+ xcs.restype = POINTER(_XRRScreenSize)
715+ _sizes = xcs(self._config, byref(nsizes))
716+ for r in range(nsizes.value):
717+ sizes.append(_sizes[r])
718+ return sizes
719+
720+ def set_config(self, size_index, rate, rotation):
721+ """Configures the screen with the given resolution at the given size
722+ index, rotation and refresh rate. To get in effect call
723+ Screen.apply_config()"""
724+ _check_required_version((1, 0))
725+ self.set_size_index(size_index)
726+ self.set_refresh_rate(rate)
727+ self.set_rotation(rotation)
728+
729+ def set_size_index(self, index):
730+ """Sets the reoslution of the screen. To get in effect call
731+ Screen.apply_config()"""
732+ if index in range(len(self.get_available_sizes())):
733+ self._size_index = index
734+ else:
735+ raise RRError("There isn't any size associated "
736+ "to the index %s" % index)
737+
738+ def set_rotation(self, rotation):
739+ """Sets the rotation of the screen. To get in effect call
740+ Screen.apply_config()"""
741+ if self.get_available_rotations() & rotation:
742+ self._rotation = rotation
743+ else:
744+ raise RRError("The chosen rotation is not supported")
745+
746+ def set_refresh_rate(self, rate):
747+ """Sets the refresh rate of the screen. To get in effect call
748+ Screen.apply_config()"""
749+ if rate in self.get_available_rates_for_size_index(self._size_index):
750+ self._rate = rate
751+ else:
752+ raise RRError("The chosen refresh rate %s is not "
753+ "supported" % rate)
754+
755+ def get_mode_by_xid(self, xid):
756+ """Returns the mode of the given xid"""
757+ screen_modes = self._resources.contents.modes
758+ for s in range(self._resources.contents.nmode):
759+ if screen_modes[s].id == xid:
760+ return screen_modes[s]
761+ return None
762+
763+ def get_output_by_name(self, name):
764+ """Returns the output of the screen with the given name or None"""
765+ if name in self.outputs:
766+ return self.outputs[name]
767+ else:
768+ return None
769+
770+ def get_output_by_id(self, id):
771+ """Returns the output of the screen with the given xid or None"""
772+ for o in list(self.outputs.values()):
773+ if o.id == id:
774+ return o
775+ return None
776+
777+ def print_info(self, verbose=False):
778+ """Prints some information about the detected screen and its outputs"""
779+ _check_required_version((1, 0))
780+ print("Screen %s: minimum %s x %s, current %s x %s, maximum %s x %s" %\
781+ (self._screen,
782+ self._width_min, self._height_min,
783+ self._width, self._height,
784+ self._width_max, self._height_max))
785+ print(" %smm x %smm" % (self._width_mm, self._height_mm))
786+ print("Crtcs: %s" % len(self.crtcs))
787+ if verbose:
788+ print("Modes (%s):" % self._resources.contents.nmode)
789+ modes = self._resources.contents.modes
790+ for i in range(self._resources.contents.nmode):
791+ print(" %s - %sx%s" % (modes[i].name,
792+ modes[i].width,
793+ modes[i].height))
794+ i = 0
795+ print("Sizes @ Refresh Rates:")
796+ for s in self.get_available_sizes():
797+ print(" [%s] %s x %s @ %s" % (
798+ i, s.width, s.height,
799+ self.get_available_rates_for_size_index(i)))
800+ i += 1
801+ print("Rotations:")
802+ rots = self.get_available_rotations()
803+ if rots & RR_ROTATE_0:
804+ print("normal")
805+ if rots & RR_ROTATE_90:
806+ print("right")
807+ if rots & RR_ROTATE_180:
808+ print("inverted")
809+ if rots & RR_ROTATE_270:
810+ print("left")
811+ print("")
812+ print("Outputs:")
813+ for o in list(self.outputs.keys()):
814+ output = self.outputs[o]
815+ print(" %s" % o)
816+ if output.is_connected():
817+ print("(%smm x %smm)" % (output.get_physical_width(),
818+ output.get_physical_height()))
819+ modes = output.get_available_modes()
820+ print(" Modes:")
821+ for m in range(len(modes)):
822+ mode = modes[m]
823+ refresh = mode.dotClock / (mode.hTotal * mode.vTotal)
824+ print(" [%s] %s x %s @ %s" % (m,
825+ mode.width,
826+ mode.height,
827+ refresh))
828+ if mode.id == output._mode:
829+ print("*")
830+ if m == output.get_preferred_mode():
831+ print("(preferred)")
832+ print("")
833+ print(" Rotations:")
834+ rots = output.get_available_rotations()
835+ if rots & RR_ROTATE_0:
836+ print("normal")
837+ if rots & RR_ROTATE_90:
838+ print("right")
839+ if rots & RR_ROTATE_180:
840+ print("inverted")
841+ if rots & RR_ROTATE_270:
842+ print("left")
843+ print("")
844+ else:
845+ print("(not connected)")
846+ if verbose:
847+ print(" Core properties:")
848+ for (f, t) in output._info.contents._fields_:
849+ print(" %s: %s" % (
850+ f, getattr(output._info.contents, f)))
851+
852+ def get_outputs(self):
853+ """Returns the outputs of the screen"""
854+ _check_required_version((1, 2))
855+ return list(self.outputs.values())
856+
857+ def get_output_names(self):
858+ _check_required_version((1, 2))
859+ return list(self.outputs.keys())
860+
861+ def set_size(self, width, height, width_mm, height_mm):
862+ """Apply the given pixel and physical size to the screen"""
863+ _check_required_version((1, 2))
864+ # Check if we really need to apply the changes
865+ if (width, height, width_mm, height_mm) == self.get_size():
866+ return
867+ rr.XRRSetScreenSize(self._display, self._root,
868+ c_int(width), c_int(height),
869+ c_int(width_mm), c_int(height_mm))
870+
871+ def apply_output_config(self):
872+ """Used for instantly applying RandR 1.2 changes"""
873+ _check_required_version((1, 2))
874+ self._arrange_outputs()
875+ self._calculate_size()
876+ self.set_size(self._width, self._height,
877+ self._width_mm, self._height_mm)
878+
879+ # Assign all active outputs to crtcs
880+ for output in list(self.outputs.values()):
881+ if not output._mode or output._crtc:
882+ continue
883+ for crtc in output.get_crtcs():
884+ if crtc and crtc.supports_output(output):
885+ crtc.add_output(output)
886+ output._changes = output._changes | CHANGES_CRTC
887+ break
888+ if not output._crtc:
889+ #FIXME: Take a look at the pick_crtc code in xrandr.c
890+ raise RRError("There is no matching crtc for the output")
891+
892+ # Apply stored changes of crtcs
893+ for crtc in self.crtcs:
894+ if crtc.has_changed():
895+ crtc.apply_changes()
896+
897+ def apply_config(self):
898+ """Used for instantly applying RandR 1.0 changes"""
899+ _check_required_version((1, 0))
900+ status = rr.XRRSetScreenConfigAndRate(self._display,
901+ self._config,
902+ self._root,
903+ self._size_index,
904+ self._rotation,
905+ self._rate,
906+ self.get_timestamp())
907+ return status
908+
909+ def _arrange_outputs(self):
910+ """Arrange all output positions according to their relative position"""
911+ for output in self.get_outputs():
912+ # Skip not changed and not used outputs
913+ if not output.has_changed(CHANGES_RELATION) or \
914+ output._mode == None:
915+ continue
916+ relative = output._relative_to
917+ mode = self.get_mode_by_xid(output._mode)
918+ mode_relative = self.get_mode_by_xid(relative._mode)
919+ if not relative or not relative._mode:
920+ output._x = 0
921+ output._y = 0
922+ output._changes = output._changes | CHANGES_POSITION
923+ if output._relation == RELATION_LEFT_OF:
924+ output._y = relative._y + output._relation_offset
925+ output._x = relative._x - \
926+ get_mode_width(mode, output._rotation)
927+ elif output._relation == RELATION_RIGHT_OF:
928+ output._y = relative._y + output._relation_offset
929+ output._x = relative._x + get_mode_width(mode_relative,
930+ output._rotation)
931+ elif output._relation == RELATION_ABOVE:
932+ output._y = relative._y - get_mode_height(mode,
933+ output._rotation)
934+ output._x = relative._x + output._relation_offset
935+ elif output._relation == RELATION_BELOW:
936+ output._y = relative._y + get_mode_height(mode_relative,
937+ output._rotation)
938+ output._x = relative._x + output._relation_offset
939+ elif output._relation == RELATION_SAME_AS:
940+ output._y = relative._y + output._relation_offset
941+ output._x = relative._x + output._relation_offset
942+ output._changes = output._changes | CHANGES_POSITION
943+ # Normalize the postions so to the upper left cornor of all outputs
944+ # is at 0,0
945+ min_x = 32768
946+ min_y = 32768
947+ for output in self.get_outputs():
948+ if output._mode == None:
949+ continue
950+ if output._x < min_x:
951+ min_x = output._x
952+ if output._y < min_y:
953+ min_y = output._y
954+ for output in self.get_outputs():
955+ if output._mode == None:
956+ continue
957+ output._x -= min_x
958+ output._y -= min_y
959+ output._changes = output._changes | CHANGES_POSITION
960+
961+ def _calculate_size(self):
962+ """Recalculate the pixel and physical size of the screen so that
963+ it covers all outputs"""
964+ width = self._width
965+ height = self._height
966+ for output in self.get_outputs():
967+ if not output._mode:
968+ continue
969+ mode = self.get_mode_by_xid(output._mode)
970+ x = output._x
971+ y = output._y
972+ w = get_mode_width(mode, output._rotation)
973+ h = get_mode_height(mode, output._rotation)
974+ if x + w > width:
975+ width = x + w
976+ if y + h > height:
977+ height = y + h
978+ if width > self._width_max or height > self._height_max:
979+ raise RRError("The required size is not supported",
980+ (width, height), (self._width_max, self._width_min))
981+ else:
982+ if height < self._height_min:
983+ self._fb_height = self._height_min
984+ else:
985+ self._height = height
986+ if width < self._width_min:
987+ self._width = self._width_min
988+ else:
989+ self._width = width
990+ #FIXME: Physical size is missing
991+
992+
993+def get_current_display():
994+ """Returns the currently used display"""
995+ display_url = os.getenv("DISPLAY")
996+ open_display = xlib.XOpenDisplay
997+ # Set .argtypes and .restype, to ensure proper
998+ # type check and conversion
999+ open_display.restype = c_void_p
1000+ open_display.argtypes = [c_char_p]
1001+ # XOpenDisplay accepts a char*, but
1002+ # display_url is a unicode string therefore
1003+ # we convert it to a bytes string
1004+ dpy = open_display(display_url.encode('utf-8'))
1005+ return dpy
1006+
1007+
1008+def get_current_screen():
1009+ """Returns the currently used screen"""
1010+ screen = Screen(get_current_display())
1011+ return screen
1012+
1013+
1014+def get_screen_of_display(display, count):
1015+ """Returns the screen of the given display"""
1016+ dpy = xlib.XOpenDisplay(display)
1017+ return Screen(dpy, count)
1018+
1019+
1020+def get_version():
1021+ """Returns a tuple containing the major and minor version of the xrandr
1022+ extension or None if the extension is not available"""
1023+ major = c_int()
1024+ minor = c_int()
1025+ res = rr.XRRQueryVersion(get_current_display(),
1026+ byref(major), byref(minor))
1027+ if res:
1028+ return (major.value, minor.value)
1029+ return None
1030+
1031+
1032+def has_extension():
1033+ """Returns True if the xrandr extension is available"""
1034+ if XRANDR_VERSION:
1035+ return True
1036+ return False
1037+
1038+
1039+def _to_gamma(gamma):
1040+ g = rr.XRRAllocGamma(len(gamma[0]))
1041+ for i in range(gamma[0]):
1042+ g.red[i] = gamma[0][i]
1043+ g.green[i] = gamma[1][i]
1044+ g.blue[i] = gamma[2][i]
1045+ return g
1046+
1047+
1048+def _from_gamma(g):
1049+ gamma = ([], [], [])
1050+ for i in range(g.size):
1051+ gamma[0].append(g.red[i])
1052+ gamma[1].append(g.green[i])
1053+ gamma[2].append(g.blue[i])
1054+ rr.XRRFreeGamma(g)
1055+
1056+
1057+def _check_required_version(version):
1058+ """Raises an exception if the given or a later version of xrandr is not
1059+ available"""
1060+ if XRANDR_VERSION == None or XRANDR_VERSION < version:
1061+ raise UnsupportedRRError(version, XRANDR_VERSION)
1062+
1063+
1064+def get_mode_height(mode, rotation):
1065+ """Return the height of the given mode taking the rotation into account"""
1066+ if rotation & (RR_ROTATE_0 | RR_ROTATE_180):
1067+ return mode.height
1068+ elif rotation & (RR_ROTATE_90 | RR_ROTATE_270):
1069+ return mode.width
1070+ else:
1071+ return 0
1072+
1073+
1074+def get_mode_width(mode, rotation):
1075+ """Return the width of the given mode taking the rotation into account"""
1076+ if rotation & (RR_ROTATE_0 | RR_ROTATE_180):
1077+ return mode.width
1078+ elif rotation & (RR_ROTATE_90 | RR_ROTATE_270):
1079+ return mode.height
1080+ else:
1081+ return 0
1082+
1083+
1084+XRANDR_VERSION = get_version()
1085+
1086+# vim:ts=4:sw=4:et
1087
1088=== added directory 'checkbox-support/checkbox_support/dbus'
1089=== added file 'checkbox-support/checkbox_support/dbus/__init__.py'
1090--- checkbox-support/checkbox_support/dbus/__init__.py 1970-01-01 00:00:00 +0000
1091+++ checkbox-support/checkbox_support/dbus/__init__.py 2014-01-07 13:44:32 +0000
1092@@ -0,0 +1,89 @@
1093+# This file is part of Checkbox.
1094+#
1095+# Copyright 2012 Canonical Ltd.
1096+# Written by:
1097+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
1098+#
1099+# Checkbox is free software: you can redistribute it and/or modify
1100+# it under the terms of the GNU General Public License version 3,
1101+# as published by the Free Software Foundation.
1102+
1103+#
1104+# Checkbox is distributed in the hope that it will be useful,
1105+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1106+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1107+# GNU General Public License for more details.
1108+#
1109+# You should have received a copy of the GNU General Public License
1110+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1111+#
1112+"""
1113+checkbox_support.dbus
1114+=============
1115+
1116+Utility modules for working with various things accessible over dbus
1117+"""
1118+
1119+import logging
1120+
1121+from dbus import SystemBus
1122+from dbus.mainloop.glib import DBusGMainLoop
1123+from dbus import (Array, Boolean, Byte, Dictionary, Double, Int16, Int32,
1124+ Int64, ObjectPath, String, Struct, UInt16, UInt32, UInt64)
1125+from gi.repository import GObject
1126+
1127+
1128+def connect_to_system_bus():
1129+ """
1130+ Connect to the system bus properly.
1131+
1132+ Returns a tuple (system_bus, loop) where loop is a GObject.MainLoop
1133+ instance. The loop is there so that you can listen to signals.
1134+ """
1135+ # We'll need an event loop to observe signals. We will need the instance
1136+ # later below so let's keep it. Note that we're not passing it directly
1137+ # below as DBus needs specific API. The DBusGMainLoop class that we
1138+ # instantiate and pass is going to work with this instance transparently.
1139+ #
1140+ # NOTE: DBus tutorial suggests that we should create the loop _before_
1141+ # connecting to the bus.
1142+ logging.debug("Setting up glib-based event loop")
1143+ loop = GObject.MainLoop()
1144+ # Let's get the system bus object. We need that to access UDisks2 object
1145+ logging.debug("Connecting to DBus system bus")
1146+ system_bus = SystemBus(mainloop=DBusGMainLoop())
1147+ return system_bus, loop
1148+
1149+
1150+def drop_dbus_type(value):
1151+ """
1152+ Convert types from the DBus bindings to their python counterparts.
1153+
1154+ This function is mostly lossless, except for arrays of bytes (DBus
1155+ signature "y") that are transparently converted to strings, assuming
1156+ an UTF-8 encoded string.
1157+
1158+ The point of this function is to simplify printing of nested DBus data that
1159+ gets displayed in a rather illegible way.
1160+ """
1161+ if isinstance(value, Array) and value.signature == "y":
1162+ # Some other things are reported as array of bytes that are just
1163+ # strings but due to Unix heritage the encoding is not known.
1164+ # In practice it is better to treat them as UTF-8 strings
1165+ return bytes(value).decode("UTF-8", "replace").strip("\0")
1166+ elif isinstance(value, (Struct, Array)):
1167+ return [drop_dbus_type(item) for item in value]
1168+ elif isinstance(value, (Dictionary)):
1169+ return {drop_dbus_type(dict_key): drop_dbus_type(dict_value)
1170+ for dict_key, dict_value in value.items()}
1171+ elif isinstance(value, (String, ObjectPath)):
1172+ return str(value)
1173+ elif isinstance(value, (Byte, UInt16, UInt32, UInt64,
1174+ Int16, Int32, Int64)):
1175+ return int(value)
1176+ elif isinstance(value, Boolean):
1177+ return bool(value)
1178+ elif isinstance(value, Double):
1179+ return float(value)
1180+ else:
1181+ return value
1182
1183=== added file 'checkbox-support/checkbox_support/dbus/udisks2.py'
1184--- checkbox-support/checkbox_support/dbus/udisks2.py 1970-01-01 00:00:00 +0000
1185+++ checkbox-support/checkbox_support/dbus/udisks2.py 2014-01-07 13:44:32 +0000
1186@@ -0,0 +1,479 @@
1187+# Copyright 2012 Canonical Ltd.
1188+# Written by:
1189+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
1190+#
1191+# This program is free software: you can redistribute it and/or modify
1192+# it under the terms of the GNU General Public License version 3,
1193+# as published by the Free Software Foundation.
1194+#
1195+# This program is distributed in the hope that it will be useful,
1196+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1197+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1198+# GNU General Public License for more details.
1199+#
1200+# You should have received a copy of the GNU General Public License
1201+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1202+
1203+"""
1204+checkbox_support.dbus.udisks2
1205+=====================
1206+
1207+Module for working with UDisks2 from python.
1208+
1209+There are two main classes that are interesting here.
1210+
1211+The first class is UDisksObserver, which is easy to setup and has pythonic API
1212+to all of the stuff that happens in UDisks2. It offers simple signal handlers
1213+for any changes that occur in UDisks2 that were advertised by DBus.
1214+
1215+The second class is UDisksModel, that builds on the observer class to offer
1216+persistent collection of objects managed by UDisks2.
1217+
1218+To work with this model you will likely want to look at:
1219+ http://udisks.freedesktop.org/docs/latest/ref-dbus.html
1220+"""
1221+
1222+import logging
1223+
1224+from dbus import Interface, PROPERTIES_IFACE
1225+from dbus.exceptions import DBusException
1226+
1227+from checkbox_support.dbus import drop_dbus_type
1228+
1229+__all__ = ['UDisks2Observer', 'UDisks2Model', 'Signal', 'is_udisks2_supported',
1230+ 'lookup_udev_device']
1231+
1232+
1233+def is_udisks2_supported(system_bus):
1234+ """
1235+ Check if udisks2 is available on the system bus.
1236+
1237+ ..note::
1238+ Calling this _may_ trigger activation of the UDisks2 daemon but it
1239+ should only happen on systems where it is already expected to run all
1240+ the time.
1241+ """
1242+ observer = UDisks2Observer()
1243+ try:
1244+ logging.debug("Trying to connect to UDisks2...")
1245+ observer.connect_to_bus(system_bus)
1246+ except DBusException as exc:
1247+ if exc.get_dbus_name() == "org.freedesktop.DBus.Error.ServiceUnknown":
1248+ logging.debug("No UDisks2 on the system bus")
1249+ return False
1250+ else:
1251+ raise
1252+ else:
1253+ logging.debug("Got UDisks2 connection")
1254+ return True
1255+
1256+
1257+def map_udisks1_connection_bus(udisks1_connection_bus):
1258+ """
1259+ Map the value of udisks1 ConnectionBus property to the corresponding values
1260+ in udisks2. This a lossy function as some values are no longer supported.
1261+
1262+ Incorrect values raise LookupError
1263+ """
1264+ return {
1265+ 'ata_serial_esata': '', # gone from udisks2
1266+ 'firewire': 'ieee1394', # renamed
1267+ 'scsi': '', # gone from udisks2
1268+ 'sdio': 'sdio', # as-is
1269+ 'usb': 'usb', # as-is
1270+ }[udisks1_connection_bus]
1271+
1272+
1273+def lookup_udev_device(udisks2_object, udev_devices):
1274+ """
1275+ Find the udev_device that corresponds to the udisks2 object
1276+
1277+ Devices are matched by unix filesystem path of the special file (device).
1278+ The udisks2_object must implement the block device interface (so that the
1279+ block device path can be determined) or a ValueError is raised.
1280+
1281+ The udisks2_object must be the dictionary that maps from interface names to
1282+ dictionaries of properties. For compatible data see
1283+ UDisks2Model.managed_objects The udev_devices must be a list of udev
1284+ device, as returned from GUdev.
1285+
1286+ If there is no match, LookupError is raised with the unix block device
1287+ path.
1288+ """
1289+ try:
1290+ block_props = udisks2_object[UDISKS2_BLOCK_INTERFACE]
1291+ except KeyError:
1292+ raise ValueError("udisks2_object must be a block device")
1293+ else:
1294+ block_dev = block_props['Device']
1295+ for udev_device in udev_devices:
1296+ if udev_device.get_device_file() == block_dev:
1297+ return udev_device
1298+ raise LookupError(block_dev)
1299+
1300+
1301+# The well-known name for the ObjectManager interface, sadly it is not a part
1302+# of the python binding along with the rest of well-known names.
1303+OBJECT_MANAGER_INTERFACE = "org.freedesktop.DBus.ObjectManager"
1304+
1305+# The well-known name of the filesystem interface implemented by certain
1306+# objects exposed by UDisks2
1307+UDISKS2_FILESYSTEM_INTERFACE = "org.freedesktop.UDisks2.Filesystem"
1308+
1309+# The well-known name of the block (device) interface implemented by certain
1310+# objects exposed by UDisks2
1311+UDISKS2_BLOCK_INTERFACE = "org.freedesktop.UDisks2.Block"
1312+
1313+# The well-known name of the drive interface implemented by certain objects
1314+# exposed by UDisks2
1315+UDISKS2_DRIVE_INTERFACE = "org.freedesktop.UDisks2.Drive"
1316+
1317+
1318+class Signal:
1319+ """
1320+ Basic signal that supports arbitrary listeners.
1321+
1322+ While this class can be used directly it is best used with the helper
1323+ decorator Signal.define on a member function. The function body is ignored,
1324+ apart from the documentation.
1325+
1326+ The function name then becomes a unique (per encapsulating class instance)
1327+ object (an instance of this Signal class) that is created on demand.
1328+
1329+ In practice you just have a documentation and use
1330+ object.signal_name.connect() and object.signal_name(*args, **kwargs) to
1331+ fire it.
1332+ """
1333+
1334+ def __init__(self, signal_name):
1335+ """
1336+ Construct a signal with the given name
1337+ """
1338+ self._listeners = []
1339+ self._signal_name = signal_name
1340+
1341+ def connect(self, listener):
1342+ """
1343+ Connect a new listener to this signal
1344+
1345+ That listener will be called whenever fire() is invoked on the signal
1346+ """
1347+ self._listeners.append(listener)
1348+
1349+ def disconnect(self, listener):
1350+ """
1351+ Disconnect an existing listener from this signal
1352+ """
1353+ self._listeners.remove(listener)
1354+
1355+ def fire(self, args, kwargs):
1356+ """
1357+ Fire this signal with the specified arguments and keyword arguments.
1358+
1359+ Typically this is used by using __call__() on this object which is more
1360+ natural as it does all the argument packing/unpacking transparently.
1361+ """
1362+ for listener in self._listeners:
1363+ listener(*args, **kwargs)
1364+
1365+ def __call__(self, *args, **kwargs):
1366+ """
1367+ Call fire() with all arguments forwarded transparently
1368+ """
1369+ self.fire(args, kwargs)
1370+
1371+ @classmethod
1372+ def define(cls, dummy_func):
1373+ """
1374+ Helper decorator to define a signal descriptor in a class
1375+
1376+ The decorated function is never called but is used to get
1377+ documentation.
1378+ """
1379+ return _SignalDescriptor(dummy_func)
1380+
1381+
1382+class _SignalDescriptor:
1383+ """
1384+ Descriptor for convenient signal access.
1385+
1386+ Typically this class is used indirectly, when accessed from Signal.define
1387+ method decorator. It is used to do all the magic required when accessing
1388+ signal name on a class or instance.
1389+ """
1390+
1391+ def __init__(self, dummy_func):
1392+ self.signal_name = dummy_func.__name__
1393+ self.__doc__ = dummy_func.__doc__
1394+
1395+ def __repr__(self):
1396+ return "<SignalDecorator for signal: %r>" % self.signal_name
1397+
1398+ def __get__(self, instance, owner):
1399+ if instance is None:
1400+ return self
1401+ # Ensure that the instance has __signals__ property
1402+ if not hasattr(instance, "__signals__"):
1403+ instance.__signals__ = {}
1404+ if self.signal_name not in instance.__signals__:
1405+ instance.__signals__[self.signal_name] = Signal(self.signal_name)
1406+ return instance.__signals__[self.signal_name]
1407+
1408+ def __set__(self, instance, value):
1409+ raise AttributeError("You cannot overwrite signals")
1410+
1411+ def __delete__(self, instance):
1412+ raise AttributeError("You cannot delete signals")
1413+
1414+
1415+class UDisks2Observer:
1416+ """
1417+ Class for observing ongoing changes in UDisks2
1418+ """
1419+
1420+ def __init__(self):
1421+ """
1422+ Create a UDisks2 model.
1423+
1424+ The model must be connected to a bus before it is first used, see
1425+ connect()
1426+ """
1427+ # Proxy to the UDisks2 object
1428+ self._udisks2_obj = None
1429+ # Proxy to the ObjectManager interface exposed by UDisks2 object
1430+ self._udisks2_obj_manager = None
1431+
1432+ @Signal.define
1433+ def on_initial_objects(self, managed_objects):
1434+ """
1435+ Signal fired when the initial list of objects becomes available
1436+ """
1437+
1438+ @Signal.define
1439+ def on_interfaces_added(self, object_path, interfaces_and_properties):
1440+ """
1441+ Signal fired when one or more interfaces gets added to a specific
1442+ object.
1443+ """
1444+
1445+ @Signal.define
1446+ def on_interfaces_removed(self, object_path, interfaces):
1447+ """
1448+ Signal fired when one or more interface gets removed from a specific
1449+ object
1450+ """
1451+
1452+ @Signal.define
1453+ def on_properties_changed(self, interface_name, changed_properties,
1454+ invalidated_properties, sender=None):
1455+ """
1456+ Signal fired when one or more property changes value or becomes
1457+ invalidated.
1458+ """
1459+
1460+ def connect_to_bus(self, bus):
1461+ """
1462+ Establish initial connection to UDisks2 on the specified DBus bus.
1463+
1464+ This will also load the initial set of objects from UDisks2 and thus
1465+ fire the on_initial_objects() signal from the model. Please call this
1466+ method only after connecting that signal if you want to observe that
1467+ event.
1468+ """
1469+ # Once everything is ready connect to udisks2
1470+ self._connect_to_udisks2(bus)
1471+ # And read all the initial objects and setup
1472+ # change event handlers
1473+ self._get_initial_objects()
1474+
1475+ def _connect_to_udisks2(self, bus):
1476+ """
1477+ Setup the initial connection to UDisks2
1478+
1479+ This step can fail if UDisks2 is not available and cannot be
1480+ service-activated.
1481+ """
1482+ # Access the /org/freedesktop/UDisks2 object sitting on the
1483+ # org.freedesktop.UDisks2 bus name. This will trigger the necessary
1484+ # activation if udisksd is not running for any reason
1485+ logging.debug("Accessing main UDisks2 object")
1486+ self._udisks2_obj = bus.get_object(
1487+ "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2")
1488+ # Now extract the standard ObjectManager interface so that we can
1489+ # observe and iterate the collection of objects that UDisks2 provides.
1490+ logging.debug("Accessing ObjectManager interface on UDisks2 object")
1491+ self._udisks2_obj_manager = Interface(
1492+ self._udisks2_obj, OBJECT_MANAGER_INTERFACE)
1493+ # Connect to the PropertiesChanged signal. Here unlike before we want
1494+ # to listen to all signals, regardless of who was sending them in the
1495+ # first place.
1496+ logging.debug("Setting up DBus signal handler for PropertiesChanged")
1497+ bus.add_signal_receiver(
1498+ self._on_properties_changed,
1499+ signal_name="PropertiesChanged",
1500+ dbus_interface=PROPERTIES_IFACE,
1501+ # Use the sender_keyword keyword argument to indicate that we wish
1502+ # to know the sender of each signal. For consistency with other
1503+ # signals we choose to use the 'object_path' keyword argument.
1504+ sender_keyword='sender')
1505+
1506+ def _get_initial_objects(self):
1507+ """
1508+ Get the initial collection of objects.
1509+
1510+ Needs to be called before the first signals from DBus are observed.
1511+ Requires a working connection to UDisks2.
1512+ """
1513+ # Having this interface we can now peek at the existing objects.
1514+ # We can use the standard method GetManagedObjects() to do that
1515+ logging.debug("Accessing GetManagedObjects() on UDisks2 object")
1516+ managed_objects = self._udisks2_obj_manager.GetManagedObjects()
1517+ managed_objects = drop_dbus_type(managed_objects)
1518+ # Fire the public signal for getting initial objects
1519+ self.on_initial_objects(managed_objects)
1520+ # Connect our internal handles to the DBus signal handlers
1521+ logging.debug("Setting up DBus signal handler for InterfacesAdded")
1522+ self._udisks2_obj_manager.connect_to_signal(
1523+ "InterfacesAdded", self._on_interfaces_added)
1524+ logging.debug("Setting up DBus signal handler for InterfacesRemoved")
1525+ self._udisks2_obj_manager.connect_to_signal(
1526+ "InterfacesRemoved", self._on_interfaces_removed)
1527+
1528+ def _on_interfaces_added(self, object_path, interfaces_and_properties):
1529+ """
1530+ Internal callback that is called by DBus
1531+
1532+ This function is responsible for firing the public signal
1533+ """
1534+ # Convert from dbus types
1535+ object_path = drop_dbus_type(object_path)
1536+ interfaces_and_properties = drop_dbus_type(interfaces_and_properties)
1537+ # Log what's going on
1538+ logging.debug("The object %r has gained the following interfaces and "
1539+ "properties: %r", object_path, interfaces_and_properties)
1540+ # Call the signal handler
1541+ self.on_interfaces_added(object_path, interfaces_and_properties)
1542+
1543+ def _on_interfaces_removed(self, object_path, interfaces):
1544+ """
1545+ Internal callback that is called by DBus
1546+
1547+ This function is responsible for firing the public signal
1548+ """
1549+ # Convert from dbus types
1550+ object_path = drop_dbus_type(object_path)
1551+ interfaces = drop_dbus_type(interfaces)
1552+ # Log what's going on
1553+ logging.debug("The object %r has lost the following interfaces: %r",
1554+ object_path, interfaces)
1555+ # Call the signal handler
1556+ self.on_interfaces_removed(object_path, interfaces)
1557+
1558+ def _on_properties_changed(self, interface_name, changed_properties,
1559+ invalidated_properties, sender=None):
1560+ """
1561+ Internal callback that is called by DBus
1562+
1563+ This function is responsible for firing the public signal
1564+ """
1565+ # Convert from dbus types
1566+ interface_name = drop_dbus_type(interface_name)
1567+ changed_properties = drop_dbus_type(changed_properties)
1568+ invalidated_properties = drop_dbus_type(invalidated_properties)
1569+ sender = drop_dbus_type(sender)
1570+ # Log what's going on
1571+ logging.debug("Some object with the interface %r has changed "
1572+ "properties: %r and invalidated properties %r "
1573+ "(sender: %s)",
1574+ interface_name, changed_properties,
1575+ invalidated_properties, sender)
1576+ # Call the signal handler
1577+ self.on_properties_changed(interface_name, changed_properties,
1578+ invalidated_properties, sender)
1579+
1580+
1581+class UDisks2Model:
1582+ """
1583+ Model for working with UDisks2
1584+
1585+ This class maintains a persistent model of what UDisks2 knows about, based
1586+ on the UDisks2Observer class and the signals it offers.
1587+ """
1588+
1589+ def __init__(self, observer):
1590+ """
1591+ Create a UDisks2 model.
1592+
1593+ The model will track changes using the specified observer (which is
1594+ expected to be a UDisks2Observer instance)
1595+
1596+ You should only connect the observer to the bus after creating the
1597+ model otherwise the initial objects will not be detected.
1598+ """
1599+ # Local state, everything that UDisks2 tells us
1600+ self._managed_objects = {}
1601+ self._observer = observer
1602+ # Connect all the signals to the observer
1603+ self._observer.on_initial_objects.connect(self._on_initial_objects)
1604+ self._observer.on_interfaces_added.connect(self._on_interfaces_added)
1605+ self._observer.on_interfaces_removed.connect(
1606+ self._on_interfaces_removed)
1607+ self._observer.on_properties_changed.connect(
1608+ self._on_properties_changed)
1609+
1610+ @Signal.define
1611+ def on_change(self):
1612+ """
1613+ Signal sent whenever the collection of managed object changes
1614+
1615+ Note that this signal is fired _after_ the change has occurred
1616+ """
1617+
1618+ @property
1619+ def managed_objects(self):
1620+ """
1621+ A collection of objects that is managed by this model. All changes as
1622+ well as the initial state, are reflected here.
1623+ """
1624+ return self._managed_objects
1625+
1626+ def _on_initial_objects(self, managed_objects):
1627+ """
1628+ Internal callback called when we get the initial collection of objects
1629+ """
1630+ self._managed_objects = drop_dbus_type(managed_objects)
1631+
1632+ def _on_interfaces_added(self, object_path, interfaces_and_properties):
1633+ """
1634+ Internal callback called when an interface is added to certain object
1635+ """
1636+ # Update internal state
1637+ if object_path not in self._managed_objects:
1638+ self._managed_objects[object_path] = {}
1639+ obj = self._managed_objects[object_path]
1640+ obj.update(interfaces_and_properties)
1641+ # Fire the change signal
1642+ self.on_change()
1643+
1644+ def _on_interfaces_removed(self, object_path, interfaces):
1645+ """
1646+ Internal callback called when an interface is removed from a certain
1647+ object
1648+ """
1649+ # Update internal state
1650+ if object_path in self._managed_objects:
1651+ obj = self._managed_objects[object_path]
1652+ for interface in interfaces:
1653+ if interface in obj:
1654+ del obj[interface]
1655+ # Fire the change signal
1656+ self.on_change()
1657+
1658+ def _on_properties_changed(self, interface_name, changed_properties,
1659+ invalidated_properties, sender=None):
1660+ # XXX: This is a workaround the fact that we cannot
1661+ # properly track changes to all properties :-(
1662+ self._managed_objects = drop_dbus_type(
1663+ self._observer._udisks2_obj_manager.GetManagedObjects())
1664+ # Fire the change signal()
1665+ self.on_change()
1666
1667=== added directory 'checkbox-support/checkbox_support/heuristics'
1668=== added file 'checkbox-support/checkbox_support/heuristics/__init__.py'
1669--- checkbox-support/checkbox_support/heuristics/__init__.py 1970-01-01 00:00:00 +0000
1670+++ checkbox-support/checkbox_support/heuristics/__init__.py 2014-01-07 13:44:32 +0000
1671@@ -0,0 +1,56 @@
1672+# This file is part of Checkbox.
1673+#
1674+# Copyright 2012 Canonical Ltd.
1675+# Written by:
1676+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
1677+#
1678+# Checkbox is free software: you can redistribute it and/or modify
1679+# it under the terms of the GNU General Public License version 3,
1680+# as published by the Free Software Foundation.
1681+
1682+#
1683+# Checkbox is distributed in the hope that it will be useful,
1684+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1685+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1686+# GNU General Public License for more details.
1687+#
1688+# You should have received a copy of the GNU General Public License
1689+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1690+
1691+"""
1692+checkbox_support.heuristics
1693+===================
1694+
1695+This module contains implementations behind various heuristics used throughout
1696+the code. The intent of this module is twofold:
1697+
1698+ 1) To encourage code reuse so that developers can use one implementation of
1699+ "guesswork" that is sometimes needed in our test. This reduces duplicate
1700+ bugs where many scripts do similar things in a different way.
1701+
1702+ 2) To identify missing features in plumbing layer APIs such as
1703+ udev/udisks/dbus etc. Ideally no program should have to guess this, the
1704+ plumbing layer should be able to provide this meta data to allow
1705+ application developers deliver consistent behavior across userspace.
1706+
1707+Heuristics should be reusable from both python and shell. To make that possible
1708+each heuristics needs to be constrained to serializable input and output. This
1709+levels the playing field and allows both shell developers and python developers
1710+to reuse the same function.
1711+
1712+Additionally heuristics should try to avoid accessing thick APIs (such as
1713+objects returned by various libraries. This is meant to decrease the likelihood
1714+that updates to those libraries break this code. As an added side effect this
1715+also should make the implementation more explicit and easier to understand.
1716+
1717+In the long term each heuristic should be discussed with upstream developers of
1718+the particular problem area (udev, udisks, etc) to see if that subsystem can
1719+provide the required information directly, without us having to guess and fill
1720+the gaps.
1721+
1722+Things to consider when adding entries to this package:
1723+
1724+ 1) File a bug on the upstream package about missing feature.
1725+
1726+ 2) File a bug on checkbox to de-duplicate similar heuristics
1727+"""
1728
1729=== added directory 'checkbox-support/checkbox_support/heuristics/tests'
1730=== added file 'checkbox-support/checkbox_support/heuristics/tests/__init__.py'
1731=== added file 'checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py'
1732--- checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py 1970-01-01 00:00:00 +0000
1733+++ checkbox-support/checkbox_support/heuristics/tests/test_udisks2.py 2014-01-07 13:44:32 +0000
1734@@ -0,0 +1,40 @@
1735+# This file is part of Checkbox.
1736+#
1737+# Copyright 2012 Canonical Ltd.
1738+# Written by:
1739+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
1740+#
1741+# Checkbox is free software: you can redistribute it and/or modify
1742+# it under the terms of the GNU General Public License version 3,
1743+# as published by the Free Software Foundation.
1744+
1745+#
1746+# Checkbox is distributed in the hope that it will be useful,
1747+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1748+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1749+# GNU General Public License for more details.
1750+#
1751+# You should have received a copy of the GNU General Public License
1752+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1753+
1754+"""
1755+
1756+checkbox_support.heuristics.tests.test_udisks2
1757+======================================
1758+
1759+Unit tests for checkbox_support.heuristics.udisks2 module
1760+"""
1761+
1762+from unittest import TestCase
1763+
1764+from checkbox_support.heuristics.udisks2 import is_memory_card
1765+
1766+
1767+class TestIsMemoryCard(TestCase):
1768+
1769+ def test_generic(self):
1770+ """
1771+ Device with vendor string "GENERIC" is a memory card
1772+ """
1773+ self.assertTrue(
1774+ is_memory_card(vendor="Generic", model="", udisks2_media=None))
1775
1776=== added file 'checkbox-support/checkbox_support/heuristics/udev.py'
1777--- checkbox-support/checkbox_support/heuristics/udev.py 1970-01-01 00:00:00 +0000
1778+++ checkbox-support/checkbox_support/heuristics/udev.py 2014-01-07 13:44:32 +0000
1779@@ -0,0 +1,44 @@
1780+# This file is part of Checkbox.
1781+#
1782+# Copyright 2012 Canonical Ltd.
1783+# Written by:
1784+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
1785+#
1786+# Checkbox is free software: you can redistribute it and/or modify
1787+# it under the terms of the GNU General Public License version 3,
1788+# as published by the Free Software Foundation.
1789+
1790+#
1791+# Checkbox is distributed in the hope that it will be useful,
1792+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1793+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1794+# GNU General Public License for more details.
1795+#
1796+# You should have received a copy of the GNU General Public License
1797+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1798+
1799+"""
1800+checkbox_support.heuristics.dev
1801+=======================
1802+
1803+Heuristics for udev.
1804+
1805+ Documentation: http://udisks.freedesktop.org/docs/latest/
1806+ Source code: http://cgit.freedesktop.org/systemd/systemd/ (src/udev)
1807+ Bug tracker: http://bugs.freedesktop.org/ (using systemd product)
1808+"""
1809+
1810+
1811+def is_virtual_device(device_file):
1812+ """
1813+ Given a device name like /dev/ramX, /dev/sdX or /dev/loopX determine if
1814+ this is a virtual device. Virtual devices are typically uninteresting to
1815+ users. The only exception may be nonempty loopback device.
1816+
1817+ Possible prior art: gnome-disks, palimpset (precursor, suffering from this
1818+ flaw and showing all the /dev/ram devices by default)
1819+ """
1820+ for part in device_file.split("/"):
1821+ if part.startswith("ram") or part.startswith("loop"):
1822+ return True
1823+ return False
1824
1825=== added file 'checkbox-support/checkbox_support/heuristics/udisks2.py'
1826--- checkbox-support/checkbox_support/heuristics/udisks2.py 1970-01-01 00:00:00 +0000
1827+++ checkbox-support/checkbox_support/heuristics/udisks2.py 2014-01-07 13:44:32 +0000
1828@@ -0,0 +1,62 @@
1829+# This file is part of Checkbox.
1830+#
1831+# Copyright 2012 Canonical Ltd.
1832+# Written by:
1833+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
1834+#
1835+# Checkbox is free software: you can redistribute it and/or modify
1836+# it under the terms of the GNU General Public License version 3,
1837+# as published by the Free Software Foundation.
1838+
1839+#
1840+# Checkbox is distributed in the hope that it will be useful,
1841+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1842+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1843+# GNU General Public License for more details.
1844+#
1845+# You should have received a copy of the GNU General Public License
1846+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1847+
1848+"""
1849+checkbox_support.heuristics.udisks2
1850+===========================
1851+
1852+Heuristics for udisks2.
1853+
1854+ Documentation: http://udisks.freedesktop.org/docs/latest/
1855+ Source code: http://cgit.freedesktop.org/systemd/systemd/ (src/udev)
1856+ Bug tracker: http://bugs.freedesktop.org/ (using systemd product)
1857+"""
1858+
1859+from checkbox_support.parsers.udevadm import CARD_READER_RE, GENERIC_RE, FLASH_RE
1860+
1861+
1862+def is_memory_card(vendor, model, udisks2_media):
1863+ """
1864+ Check if the device seems to be a memory card
1865+
1866+ The vendor and model arguments are _strings_, not integers.
1867+ The udisks2_media argument is the value of org.freedesktop.UDisks2.Drive/
1868+
1869+
1870+ This is rather fuzzy, sadly udev and udisks2 don't do a very good job and
1871+ mostly don't specify the "media" property (it has a few useful values, such
1872+ as flash_cf, flash_ms, flash_sm, flash_sd, flash_sdhc, flash_sdxc and
1873+ flash_mmc but I have yet to see a device that reports such values)
1874+ """
1875+ # Treat any udisks2_media that contains 'flash' as a memory card
1876+ if udisks2_media is not None and FLASH_RE.search(udisks2_media):
1877+ return True
1878+ # Treat any device that match model name to the following regular
1879+ # expression as a memory card reader.
1880+ if CARD_READER_RE.search(model):
1881+ return True
1882+ # Treat any device that contains the word 'Generic' in the vendor string as
1883+ # a memory card reader.
1884+ #
1885+ # XXX: This seems odd but strangely enough seems to gets the job done. I
1886+ # guess if I should start filing tons of bugs/patches on udev/udisks2 to
1887+ # just have a few more rules and make this rule obsolete.
1888+ if GENERIC_RE.search(vendor):
1889+ return True
1890+ return False
1891
1892=== added directory 'checkbox-support/checkbox_support/lib'
1893=== added file 'checkbox-support/checkbox_support/lib/__init__.py'
1894=== added file 'checkbox-support/checkbox_support/lib/bit.py'
1895--- checkbox-support/checkbox_support/lib/bit.py 1970-01-01 00:00:00 +0000
1896+++ checkbox-support/checkbox_support/lib/bit.py 2014-01-07 13:44:32 +0000
1897@@ -0,0 +1,46 @@
1898+#
1899+# This file is part of Checkbox.
1900+#
1901+# Copyright 2008 Canonical Ltd.
1902+#
1903+# Checkbox is free software: you can redistribute it and/or modify
1904+# it under the terms of the GNU General Public License version 3,
1905+# as published by the Free Software Foundation.
1906+
1907+#
1908+# Checkbox is distributed in the hope that it will be useful,
1909+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1910+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1911+# GNU General Public License for more details.
1912+#
1913+# You should have received a copy of the GNU General Public License
1914+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1915+#
1916+from struct import calcsize
1917+
1918+
1919+def get_bitmask(key):
1920+ bitmask = []
1921+ for value in reversed(key.split()):
1922+ value = int(value, 16)
1923+ bitmask.append(value)
1924+
1925+ return bitmask
1926+
1927+def get_bitcount(bitmask):
1928+ bitcount = 0
1929+ for value in bitmask:
1930+ while value:
1931+ bitcount += 1
1932+ value &= (value - 1)
1933+
1934+ return bitcount
1935+
1936+def test_bit(bit, bitmask, bits=None):
1937+ if bits is None:
1938+ bits = calcsize("l") * 8
1939+ offset = bit % bits
1940+ long = int(bit / bits)
1941+ if long >= len(bitmask):
1942+ return 0
1943+ return (bitmask[long] >> offset) & 1
1944
1945=== added file 'checkbox-support/checkbox_support/lib/conversion.py'
1946--- checkbox-support/checkbox_support/lib/conversion.py 1970-01-01 00:00:00 +0000
1947+++ checkbox-support/checkbox_support/lib/conversion.py 2014-01-07 13:44:32 +0000
1948@@ -0,0 +1,172 @@
1949+#
1950+# This file is part of Checkbox.
1951+#
1952+# Copyright 2008 Canonical Ltd.
1953+#
1954+# Checkbox is free software: you can redistribute it and/or modify
1955+# it under the terms of the GNU General Public License version 3,
1956+# as published by the Free Software Foundation.
1957+
1958+#
1959+# Checkbox is distributed in the hope that it will be useful,
1960+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1961+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1962+# GNU General Public License for more details.
1963+#
1964+# You should have received a copy of the GNU General Public License
1965+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
1966+#
1967+import re
1968+
1969+from datetime import (
1970+ datetime,
1971+ timedelta,
1972+ )
1973+
1974+from checkbox_support.lib.tz import tzutc
1975+
1976+
1977+DATETIME_RE = re.compile(r"""
1978+ ^(?P<year>\d\d\d\d)-?(?P<month>\d\d)-?(?P<day>\d\d)
1979+ T(?P<hour>\d\d):?(?P<minute>\d\d):?(?P<second>\d\d)
1980+ (?:\.(?P<second_fraction>\d{0,6}))?
1981+ (?P<tz>
1982+ (?:(?P<tz_sign>[-+])(?P<tz_hour>\d\d):(?P<tz_minute>\d\d))
1983+ | Z)?$
1984+ """, re.VERBOSE)
1985+
1986+TYPE_FORMATS = (
1987+ (r"(yes|true)", lambda v: True),
1988+ (r"(no|false)", lambda v: False),
1989+ (r"-?\d+", lambda v: int(v.group(0))),
1990+ (r"-?\d+\.\d+", lambda v: float(v.group(0))),
1991+ (r"(-?\d+) ?([kmgt]?b?)", lambda v: int(v.group(1))),
1992+ (r"(-?\d+\.\d+) ?([kmgt]?b?)", lambda v: float(v.group(1))),
1993+ (r"(-?\d+) ?([kmgt]?hz)", lambda v: int(v.group(1))),
1994+ (r"(-?\d+\.\d+) ?([kmgt]?hz)", lambda v: float(v.group(1))))
1995+TYPE_FORMATS = tuple(
1996+ (re.compile(r"^%s$" % pattern, re.IGNORECASE), format)
1997+ for pattern, format in TYPE_FORMATS)
1998+
1999+TYPE_MULTIPLIERS = (
2000+ (r"b", 1),
2001+ (r"kb?", 1024),
2002+ (r"mb?", 1024 * 1024),
2003+ (r"gb?", 1024 * 1024 * 1024),
2004+ (r"tb?", 1024 * 1024 * 1024 * 1024),
2005+ (r"hz", 1),
2006+ (r"khz?", 1024),
2007+ (r"mhz?", 1024 * 1024),
2008+ (r"ghz?", 1024 * 1024 * 1024),
2009+ (r"thz?", 1024 * 1024 * 1024 * 1024))
2010+TYPE_MULTIPLIERS = tuple(
2011+ (re.compile(r"^%s$" % pattern, re.IGNORECASE), multiplier)
2012+ for pattern, multiplier in TYPE_MULTIPLIERS)
2013+
2014+
2015+def datetime_to_string(dt):
2016+ """Return a consistent string representation for a given datetime.
2017+
2018+ :param dt: The datetime object.
2019+ """
2020+ return dt.isoformat()
2021+
2022+
2023+def string_to_datetime(string):
2024+ """Return a datetime object from a consistent string representation.
2025+
2026+ :param string: The string representation.
2027+ """
2028+ # we cannot use time.strptime: this function accepts neither fractions
2029+ # of a second nor a time zone given e.g. as '+02:30'.
2030+ match = DATETIME_RE.match(string)
2031+
2032+ # The Relax NG schema allows a leading minus sign and year numbers
2033+ # with more than four digits, which are not "covered" by _time_regex.
2034+ if not match:
2035+ raise ValueError("Datetime with unreasonable value: %s" % string)
2036+
2037+ time_parts = match.groupdict()
2038+
2039+ year = int(time_parts['year'])
2040+ month = int(time_parts['month'])
2041+ day = int(time_parts['day'])
2042+ hour = int(time_parts['hour'])
2043+ minute = int(time_parts['minute'])
2044+ second = int(time_parts['second'])
2045+ second_fraction = time_parts['second_fraction']
2046+ if second_fraction is not None:
2047+ milliseconds = second_fraction + '0' * (6 - len(second_fraction))
2048+ milliseconds = int(milliseconds)
2049+ else:
2050+ milliseconds = 0
2051+
2052+ # The Relax NG validator accepts leap seconds, but the datetime
2053+ # constructor rejects them. The time values submitted by the HWDB
2054+ # client are not necessarily very precise, hence we can round down
2055+ # to 59.999999 seconds without losing any real precision.
2056+ if second > 59:
2057+ second = 59
2058+ milliseconds = 999999
2059+
2060+ dt = datetime(
2061+ year, month, day, hour, minute, second, milliseconds, tzinfo=tzutc)
2062+
2063+ tz_sign = time_parts['tz_sign']
2064+ tz_hour = time_parts['tz_hour']
2065+ tz_minute = time_parts['tz_minute']
2066+ if tz_sign in ('-', '+'):
2067+ delta = timedelta(hours=int(tz_hour), minutes=int(tz_minute))
2068+ if tz_sign == '-':
2069+ dt = dt + delta
2070+ else:
2071+ dt = dt - delta
2072+
2073+ return dt
2074+
2075+
2076+def sizeof_bytes(bytes):
2077+ for x in ["bytes", "KB", "MB", "GB", "TB"]:
2078+ string = "%3.1f%s" % (bytes, x)
2079+ if bytes < 1024.0:
2080+ break
2081+ bytes /= 1024.0
2082+
2083+ return string
2084+
2085+
2086+def sizeof_hertz(hertz):
2087+ for x in ["Hz", "KHz", "MHz", "GHz"]:
2088+ string = "%3.1f%s" % (hertz, x)
2089+ if hertz < 1000.0:
2090+ break
2091+ hertz /= 1000.0
2092+
2093+ return string
2094+
2095+
2096+def string_to_type(string):
2097+ """Return a typed representation for the given string.
2098+
2099+ The result might be a bool, int or float. The string might also be
2100+ supplemented by a multiplier like KB which would return an int or
2101+ float multiplied by 1024 for example.
2102+
2103+ :param string: The string representation.
2104+ """
2105+ for regex, formatter in TYPE_FORMATS:
2106+ match = regex.match(string)
2107+ if match:
2108+ string = formatter(match)
2109+ if len(match.groups()) > 1:
2110+ unit = match.group(2)
2111+ for regex, multiplier in TYPE_MULTIPLIERS:
2112+ match = regex.match(unit)
2113+ if match:
2114+ string *= multiplier
2115+ break
2116+ else:
2117+ raise ValueError("Unknown multiplier: %s" % unit)
2118+ break
2119+
2120+ return string
2121
2122=== added file 'checkbox-support/checkbox_support/lib/dmi.py'
2123--- checkbox-support/checkbox_support/lib/dmi.py 1970-01-01 00:00:00 +0000
2124+++ checkbox-support/checkbox_support/lib/dmi.py 2014-01-07 13:44:32 +0000
2125@@ -0,0 +1,241 @@
2126+#
2127+# This file is part of Checkbox.
2128+#
2129+# Copyright 2008 Canonical Ltd.
2130+#
2131+# Checkbox is free software: you can redistribute it and/or modify
2132+# it under the terms of the GNU General Public License version 3,
2133+# as published by the Free Software Foundation.
2134+
2135+#
2136+# Checkbox is distributed in the hope that it will be useful,
2137+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2138+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2139+# GNU General Public License for more details.
2140+#
2141+# You should have received a copy of the GNU General Public License
2142+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
2143+#
2144+import os
2145+
2146+from checkbox_support.lib.conversion import string_to_type
2147+
2148+# See also 3.3.4.1 of the "System Management BIOS Reference Specification,
2149+# Version 2.6.1" (Preliminary Standard) document, available from
2150+# http://www.dmtf.org/standards/smbios.
2151+class Dmi:
2152+ chassis = (
2153+ ("Undefined", "unknown"), # 0x00
2154+ ("Other", "unknown"),
2155+ ("Unknown", "unknown"),
2156+ ("Desktop", "desktop"),
2157+ ("Low Profile Desktop", "desktop"),
2158+ ("Pizza Box", "server"),
2159+ ("Mini Tower", "desktop"),
2160+ ("Tower", "desktop"),
2161+ ("Portable", "laptop"),
2162+ ("Laptop", "laptop"),
2163+ ("Notebook", "laptop"),
2164+ ("Hand Held", "handheld"),
2165+ ("Docking Station", "laptop"),
2166+ ("All In One", "unknown"),
2167+ ("Sub Notebook", "laptop"),
2168+ ("Space-saving", "desktop"),
2169+ ("Lunch Box", "unknown"),
2170+ ("Main Server Chassis", "server"),
2171+ ("Expansion Chassis", "unknown"),
2172+ ("Sub Chassis", "unknown"),
2173+ ("Bus Expansion Chassis", "unknown"),
2174+ ("Peripheral Chassis", "unknown"),
2175+ ("RAID Chassis", "unknown"),
2176+ ("Rack Mount Chassis", "unknown"),
2177+ ("Sealed-case PC", "unknown"),
2178+ ("Multi-system", "unknown"),
2179+ ("CompactPCI", "unknonw"),
2180+ ("AdvancedTCA", "unknown"),
2181+ ("Blade", "server"),
2182+ ("Blade Enclosure", "unknown"))
2183+
2184+ chassis_names = tuple(c[0] for c in chassis)
2185+ chassis_types = tuple(c[1] for c in chassis)
2186+ chassis_name_to_type = dict(chassis)
2187+
2188+ type_names = (
2189+ "BIOS", # 0x00
2190+ "System",
2191+ "Base Board",
2192+ "Chassis",
2193+ "Processor",
2194+ "Memory Controller",
2195+ "Memory Module",
2196+ "Cache",
2197+ "Port Connector",
2198+ "System Slots",
2199+ "On Board Devices",
2200+ "OEM Strings",
2201+ "System Configuration Options",
2202+ "BIOS Language",
2203+ "Group Associations",
2204+ "System Event Log",
2205+ "Physical Memory Array",
2206+ "Memory Device",
2207+ "32-bit Memory Error",
2208+ "Memory Array Mapped Address",
2209+ "Memory Device Mapped Address",
2210+ "Built-in Pointing Device",
2211+ "Portable Battery",
2212+ "System Reset",
2213+ "Hardware Security",
2214+ "System Power Controls",
2215+ "Voltage Probe",
2216+ "Cooling Device",
2217+ "Temperature Probe",
2218+ "Electrical Current Probe",
2219+ "Out-of-band Remote Access",
2220+ "Boot Integrity Services",
2221+ "System Boot",
2222+ "64-bit Memory Error",
2223+ "Management Device",
2224+ "Management Device Component",
2225+ "Management Device Threshold Data",
2226+ "Memory Channel",
2227+ "IPMI Device",
2228+ "Power Supply",
2229+ )
2230+
2231+
2232+class DmiDevice:
2233+
2234+ bus = "dmi"
2235+ driver = None
2236+ product_id = None
2237+ vendor_id = None
2238+
2239+ _product_blacklist = (
2240+ "<BAD INDEX>",
2241+ "N/A",
2242+ "Not Available",
2243+ "INVALID",
2244+ "OEM",
2245+ "Product Name",
2246+ "System Product Name",
2247+ "To be filled by O.E.M.",
2248+ "To Be Filled By O.E.M.",
2249+ "To Be Filled By O.E.M. by More String",
2250+ "Unknown",
2251+ "Uknown",
2252+ "Unknow",
2253+ "xxxxxxxxxxxxxx",
2254+ )
2255+ _vendor_blacklist = (
2256+ "<BAD INDEX>",
2257+ "Not Available",
2258+ "OEM",
2259+ "OEM Manufacturer",
2260+ "System manufacturer",
2261+ "System Manufacturer",
2262+ "System Name",
2263+ "To be filled by O.E.M.",
2264+ "To Be Filled By O.E.M.",
2265+ "To Be Filled By O.E.M. by More String",
2266+ "Unknow", # XXX This is correct mispelling
2267+ "Unknown",
2268+ )
2269+ _serial_blacklist = (
2270+ "0",
2271+ "00000000",
2272+ "00 00 00 00 00 00 00 00",
2273+ "0123456789",
2274+ "Base Board Serial Number",
2275+ "Chassis Serial Number",
2276+ "N/A",
2277+ "None",
2278+ "Not Applicable",
2279+ "Not Available",
2280+ "Not Specified",
2281+ "OEM",
2282+ "System Serial Number",
2283+ )
2284+ _version_blacklist = (
2285+ "-1",
2286+ "<BAD INDEX>",
2287+ "N/A",
2288+ "None",
2289+ "Not Applicable",
2290+ "Not Available",
2291+ "Not Specified",
2292+ "OEM",
2293+ "System Version",
2294+ "Unknown",
2295+ "x.x",
2296+ )
2297+
2298+ def __init__(self, attributes, category):
2299+ self._attributes = attributes
2300+ self.category = category
2301+
2302+ @property
2303+ def path(self):
2304+ path = "/devices/virtual/dmi/id"
2305+ return os.path.join(path, self.category.lower())
2306+
2307+ @property
2308+ def product(self):
2309+ if self.category == "CHASSIS":
2310+ type_string = self._attributes.get("chassis_type", "0")
2311+ try:
2312+ type_index = int(type_string)
2313+ return Dmi.chassis_names[type_index]
2314+ except ValueError:
2315+ return type_string
2316+
2317+ for name in "name", "version":
2318+ attribute = "%s_%s" % (self.category.lower(), name)
2319+ product = self._attributes.get(attribute)
2320+ if product and product not in self._product_blacklist:
2321+ return product
2322+
2323+ return None
2324+
2325+ @property
2326+ def vendor(self):
2327+ for name in "manufacturer", "vendor":
2328+ attribute = "%s_%s" % (self.category.lower(), name)
2329+ vendor = self._attributes.get(attribute)
2330+ if vendor and vendor not in self._vendor_blacklist:
2331+ return vendor
2332+
2333+ return None
2334+
2335+ @property
2336+ def serial(self):
2337+ attribute = "%s_serial" % self.category.lower()
2338+ serial = self._attributes.get(attribute)
2339+ if serial and serial not in self._serial_blacklist:
2340+ return serial
2341+
2342+ return None
2343+
2344+ @property
2345+ def version(self):
2346+ attribute = "%s_version" % self.category.lower()
2347+ version = self._attributes.get(attribute)
2348+ if version and version not in self._version_blacklist:
2349+ return version
2350+
2351+ return None
2352+
2353+ @property
2354+ def size(self):
2355+ attribute = "%s_size" % self.category.lower()
2356+ size = self._attributes.get(attribute)
2357+
2358+ if size:
2359+ size = string_to_type(size)
2360+
2361+ return size
2362+
2363+ @property
2364+ def form(self):
2365+ attribute = "%s_form" % self.category.lower()
2366+ return self._attributes.get(attribute)
2367
2368=== added file 'checkbox-support/checkbox_support/lib/input.py'
2369--- checkbox-support/checkbox_support/lib/input.py 1970-01-01 00:00:00 +0000
2370+++ checkbox-support/checkbox_support/lib/input.py 2014-01-07 13:44:32 +0000
2371@@ -0,0 +1,585 @@
2372+#
2373+# This file is part of Checkbox.
2374+#
2375+# Copyright 2008 Canonical Ltd.
2376+#
2377+# Checkbox is free software: you can redistribute it and/or modify
2378+# it under the terms of the GNU General Public License version 3,
2379+# as published by the Free Software Foundation.
2380+
2381+#
2382+# Checkbox is distributed in the hope that it will be useful,
2383+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2384+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2385+# GNU General Public License for more details.
2386+#
2387+# You should have received a copy of the GNU General Public License
2388+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
2389+#
2390+
2391+# See linux/input.h
2392+class Input:
2393+ KEY_RESERVED = 0
2394+ KEY_ESC = 1
2395+ KEY_1 = 2
2396+ KEY_2 = 3
2397+ KEY_3 = 4
2398+ KEY_4 = 5
2399+ KEY_5 = 6
2400+ KEY_6 = 7
2401+ KEY_7 = 8
2402+ KEY_8 = 9
2403+ KEY_9 = 10
2404+ KEY_0 = 11
2405+ KEY_MINUS = 12
2406+ KEY_EQUAL = 13
2407+ KEY_BACKSPACE = 14
2408+ KEY_TAB = 15
2409+ KEY_Q = 16
2410+ KEY_W = 17
2411+ KEY_E = 18
2412+ KEY_R = 19
2413+ KEY_T = 20
2414+ KEY_Y = 21
2415+ KEY_U = 22
2416+ KEY_I = 23
2417+ KEY_O = 24
2418+ KEY_P = 25
2419+ KEY_LEFTBRACE = 26
2420+ KEY_RIGHTBRACE = 27
2421+ KEY_ENTER = 28
2422+ KEY_LEFTCTRL = 29
2423+ KEY_A = 30
2424+ KEY_S = 31
2425+ KEY_D = 32
2426+ KEY_F = 33
2427+ KEY_G = 34
2428+ KEY_H = 35
2429+ KEY_J = 36
2430+ KEY_K = 37
2431+ KEY_L = 38
2432+ KEY_SEMICOLON = 39
2433+ KEY_APOSTROPHE = 40
2434+ KEY_GRAVE = 41
2435+ KEY_LEFTSHIFT = 42
2436+ KEY_BACKSLASH = 43
2437+ KEY_Z = 44
2438+ KEY_X = 45
2439+ KEY_C = 46
2440+ KEY_V = 47
2441+ KEY_B = 48
2442+ KEY_N = 49
2443+ KEY_M = 50
2444+ KEY_COMMA = 51
2445+ KEY_DOT = 52
2446+ KEY_SLASH = 53
2447+ KEY_RIGHTSHIFT = 54
2448+ KEY_KPASTERISK = 55
2449+ KEY_LEFTALT = 56
2450+ KEY_SPACE = 57
2451+ KEY_CAPSLOCK = 58
2452+ KEY_F1 = 59
2453+ KEY_F2 = 60
2454+ KEY_F3 = 61
2455+ KEY_F4 = 62
2456+ KEY_F5 = 63
2457+ KEY_F6 = 64
2458+ KEY_F7 = 65
2459+ KEY_F8 = 66
2460+ KEY_F9 = 67
2461+ KEY_F10 = 68
2462+ KEY_NUMLOCK = 69
2463+ KEY_SCROLLLOCK = 70
2464+ KEY_KP7 = 71
2465+ KEY_KP8 = 72
2466+ KEY_KP9 = 73
2467+ KEY_KPMINUS = 74
2468+ KEY_KP4 = 75
2469+ KEY_KP5 = 76
2470+ KEY_KP6 = 77
2471+ KEY_KPPLUS = 78
2472+ KEY_KP1 = 79
2473+ KEY_KP2 = 80
2474+ KEY_KP3 = 81
2475+ KEY_KP0 = 82
2476+ KEY_KPDOT = 83
2477+
2478+ KEY_ZENKAKUHANKAKU = 85
2479+ KEY_102ND = 86
2480+ KEY_F11 = 87
2481+ KEY_F12 = 88
2482+ KEY_RO = 89
2483+ KEY_KATAKANA = 90
2484+ KEY_HIRAGANA = 91
2485+ KEY_HENKAN = 92
2486+ KEY_KATAKANAHIRAGANA = 93
2487+ KEY_MUHENKAN = 94
2488+ KEY_KPJPCOMMA = 95
2489+ KEY_KPENTER = 96
2490+ KEY_RIGHTCTRL = 97
2491+ KEY_KPSLASH = 98
2492+ KEY_SYSRQ = 99
2493+ KEY_RIGHTALT = 100
2494+ KEY_LINEFEED = 101
2495+ KEY_HOME = 102
2496+ KEY_UP = 103
2497+ KEY_PAGEUP = 104
2498+ KEY_LEFT = 105
2499+ KEY_RIGHT = 106
2500+ KEY_END = 107
2501+ KEY_DOWN = 108
2502+ KEY_PAGEDOWN = 109
2503+ KEY_INSERT = 110
2504+ KEY_DELETE = 111
2505+ KEY_MACRO = 112
2506+ KEY_MUTE = 113
2507+ KEY_VOLUMEDOWN = 114
2508+ KEY_VOLUMEUP = 115
2509+ KEY_POWER = 116 # SC System Power Down
2510+ KEY_KPEQUAL = 117
2511+ KEY_KPPLUSMINUS = 118
2512+ KEY_PAUSE = 119
2513+ KEY_SCALE = 120 # AL Compiz Scale (Expose)
2514+
2515+ KEY_KPCOMMA = 121
2516+ KEY_HANGEUL = 122
2517+ KEY_HANGUEL = KEY_HANGEUL
2518+ KEY_HANJA = 123
2519+ KEY_YEN = 124
2520+ KEY_LEFTMETA = 125
2521+ KEY_RIGHTMETA = 126
2522+ KEY_COMPOSE = 127
2523+
2524+ KEY_STOP = 128 # AC Stop
2525+ KEY_AGAIN = 129
2526+ KEY_PROPS = 130 # AC Properties
2527+ KEY_UNDO = 131 # AC Undo
2528+ KEY_FRONT = 132
2529+ KEY_COPY = 133 # AC Copy
2530+ KEY_OPEN = 134 # AC Open
2531+ KEY_PASTE = 135 # AC Paste
2532+ KEY_FIND = 136 # AC Search
2533+ KEY_CUT = 137 # AC Cut
2534+ KEY_HELP = 138 # AL Integrated Help Center
2535+ KEY_MENU = 139 # Menu (show menu)
2536+ KEY_CALC = 140 # AL Calculator
2537+ KEY_SETUP = 141
2538+ KEY_SLEEP = 142 # SC System Sleep
2539+ KEY_WAKEUP = 143 # System Wake Up
2540+ KEY_FILE = 144 # AL Local Machine Browser
2541+ KEY_SENDFILE = 145
2542+ KEY_DELETEFILE = 146
2543+ KEY_XFER = 147
2544+ KEY_PROG1 = 148
2545+ KEY_PROG2 = 149
2546+ KEY_WWW = 150 # AL Internet Browser
2547+ KEY_MSDOS = 151
2548+ KEY_COFFEE = 152 # AL Terminal Lock/Screensaver
2549+ KEY_SCREENLOCK = KEY_COFFEE
2550+ KEY_DIRECTION = 153
2551+ KEY_CYCLEWINDOWS = 154
2552+ KEY_MAIL = 155
2553+ KEY_BOOKMARKS = 156 # AC Bookmarks
2554+ KEY_COMPUTER = 157
2555+ KEY_BACK = 158 # AC Back
2556+ KEY_FORWARD = 159 # AC Forward
2557+ KEY_CLOSECD = 160
2558+ KEY_EJECTCD = 161
2559+ KEY_EJECTCLOSECD = 162
2560+ KEY_NEXTSONG = 163
2561+ KEY_PLAYPAUSE = 164
2562+ KEY_PREVIOUSSONG = 165
2563+ KEY_STOPCD = 166
2564+ KEY_RECORD = 167
2565+ KEY_REWIND = 168
2566+ KEY_PHONE = 169 # Media Select Telephone
2567+ KEY_ISO = 170
2568+ KEY_CONFIG = 171 # AL Consumer Control Configuration
2569+ KEY_HOMEPAGE = 172 # AC Home
2570+ KEY_REFRESH = 173 # AC Refresh
2571+ KEY_EXIT = 174 # AC Exit
2572+ KEY_MOVE = 175
2573+ KEY_EDIT = 176
2574+ KEY_SCROLLUP = 177
2575+ KEY_SCROLLDOWN = 178
2576+ KEY_KPLEFTPAREN = 179
2577+ KEY_KPRIGHTPAREN = 180
2578+ KEY_NEW = 181 # AC New
2579+ KEY_REDO = 182 # AC Redo/Repeat
2580+
2581+ KEY_F13 = 183
2582+ KEY_F14 = 184
2583+ KEY_F15 = 185
2584+ KEY_F16 = 186
2585+ KEY_F17 = 187
2586+ KEY_F18 = 188
2587+ KEY_F19 = 189
2588+ KEY_F20 = 190
2589+ KEY_F21 = 191
2590+ KEY_F22 = 192
2591+ KEY_F23 = 193
2592+ KEY_F24 = 194
2593+
2594+ KEY_PLAYCD = 200
2595+ KEY_PAUSECD = 201
2596+ KEY_PROG3 = 202
2597+ KEY_PROG4 = 203
2598+ KEY_DASHBOARD = 204 # AL Dashboard
2599+ KEY_SUSPEND = 205
2600+ KEY_CLOSE = 206 # AC Close
2601+ KEY_PLAY = 207
2602+ KEY_FASTFORWARD = 208
2603+ KEY_BASSBOOST = 209
2604+ KEY_PRINT = 210 # AC Print
2605+ KEY_HP = 211
2606+ KEY_CAMERA = 212
2607+ KEY_SOUND = 213
2608+ KEY_QUESTION = 214
2609+ KEY_EMAIL = 215
2610+ KEY_CHAT = 216
2611+ KEY_SEARCH = 217
2612+ KEY_CONNECT = 218
2613+ KEY_FINANCE = 219 # AL Checkbook/Finance
2614+ KEY_SPORT = 220
2615+ KEY_SHOP = 221
2616+ KEY_ALTERASE = 222
2617+ KEY_CANCEL = 223 # AC Cancel
2618+ KEY_BRIGHTNESSDOWN = 224
2619+ KEY_BRIGHTNESSUP = 225
2620+ KEY_MEDIA = 226
2621+
2622+ KEY_SWITCHVIDEOMODE = 227 # Cycle between available video
2623+ # outputs (Monitor/LCD/TV-out/etc)
2624+ KEY_KBDILLUMTOGGLE = 228
2625+ KEY_KBDILLUMDOWN = 229
2626+ KEY_KBDILLUMUP = 230
2627+
2628+ KEY_SEND = 231 # AC Send
2629+ KEY_REPLY = 232 # AC Reply
2630+ KEY_FORWARDMAIL = 233 # AC Forward Msg
2631+ KEY_SAVE = 234 # AC Save
2632+ KEY_DOCUMENTS = 235
2633+
2634+ KEY_BATTERY = 236
2635+
2636+ KEY_BLUETOOTH = 237
2637+ KEY_WLAN = 238
2638+ KEY_UWB = 239
2639+
2640+ KEY_UNKNOWN = 240
2641+
2642+ KEY_VIDEO_NEXT = 241 # drive next video source
2643+ KEY_VIDEO_PREV = 242 # drive previous video source
2644+ KEY_BRIGHTNESS_CYCLE = 243 # brightness up, after max is min
2645+ KEY_BRIGHTNESS_ZERO = 244 # brightness off, use ambient
2646+ KEY_DISPLAY_OFF = 245 # display device to off state
2647+
2648+ KEY_WIMAX = 246
2649+
2650+ # Range = 248 - 255 is reserved for special needs of AT keyboard driver
2651+
2652+ BTN_MISC = 0x100
2653+ BTN_0 = 0x100
2654+ BTN_1 = 0x101
2655+ BTN_2 = 0x102
2656+ BTN_3 = 0x103
2657+ BTN_4 = 0x104
2658+ BTN_5 = 0x105
2659+ BTN_6 = 0x106
2660+ BTN_7 = 0x107
2661+ BTN_8 = 0x108
2662+ BTN_9 = 0x109
2663+
2664+ BTN_MOUSE = 0x110
2665+ BTN_LEFT = 0x110
2666+ BTN_RIGHT = 0x111
2667+ BTN_MIDDLE = 0x112
2668+ BTN_SIDE = 0x113
2669+ BTN_EXTRA = 0x114
2670+ BTN_FORWARD = 0x115
2671+ BTN_BACK = 0x116
2672+ BTN_TASK = 0x117
2673+
2674+ BTN_JOYSTICK = 0x120
2675+ BTN_TRIGGER = 0x120
2676+ BTN_THUMB = 0x121
2677+ BTN_THUMB2 = 0x122
2678+ BTN_TOP = 0x123
2679+ BTN_TOP2 = 0x124
2680+ BTN_PINKIE = 0x125
2681+ BTN_BASE = 0x126
2682+ BTN_BASE2 = 0x127
2683+ BTN_BASE3 = 0x128
2684+ BTN_BASE4 = 0x129
2685+ BTN_BASE5 = 0x12a
2686+ BTN_BASE6 = 0x12b
2687+ BTN_DEAD = 0x12f
2688+
2689+ BTN_GAMEPAD = 0x130
2690+ BTN_A = 0x130
2691+ BTN_B = 0x131
2692+ BTN_C = 0x132
2693+ BTN_X = 0x133
2694+ BTN_Y = 0x134
2695+ BTN_Z = 0x135
2696+ BTN_TL = 0x136
2697+ BTN_TR = 0x137
2698+ BTN_TL2 = 0x138
2699+ BTN_TR2 = 0x139
2700+ BTN_SELECT = 0x13a
2701+ BTN_START = 0x13b
2702+ BTN_MODE = 0x13c
2703+ BTN_THUMBL = 0x13d
2704+ BTN_THUMBR = 0x13e
2705+
2706+ BTN_DIGI = 0x140
2707+ BTN_TOOL_PEN = 0x140
2708+ BTN_TOOL_RUBBER = 0x141
2709+ BTN_TOOL_BRUSH = 0x142
2710+ BTN_TOOL_PENCIL = 0x143
2711+ BTN_TOOL_AIRBRUSH = 0x144
2712+ BTN_TOOL_FINGER = 0x145
2713+ BTN_TOOL_MOUSE = 0x146
2714+ BTN_TOOL_LENS = 0x147
2715+ BTN_TOUCH = 0x14a
2716+ BTN_STYLUS = 0x14b
2717+ BTN_STYLUS2 = 0x14c
2718+ BTN_TOOL_DOUBLETAP = 0x14d
2719+ BTN_TOOL_TRIPLETAP = 0x14e
2720+
2721+ BTN_WHEEL = 0x150
2722+ BTN_GEAR_DOWN = 0x150
2723+ BTN_GEAR_UP = 0x151
2724+
2725+ KEY_OK = 0x160
2726+ KEY_SELECT = 0x161
2727+ KEY_GOTO = 0x162
2728+ KEY_CLEAR = 0x163
2729+ KEY_POWER2 = 0x164
2730+ KEY_OPTION = 0x165
2731+ KEY_INFO = 0x166 # AL OEM Features/Tips/Tutorial
2732+ KEY_TIME = 0x167
2733+ KEY_VENDOR = 0x168
2734+ KEY_ARCHIVE = 0x169
2735+ KEY_PROGRAM = 0x16a # Media Select Program Guide
2736+ KEY_CHANNEL = 0x16b
2737+ KEY_FAVORITES = 0x16c
2738+ KEY_EPG = 0x16d
2739+ KEY_PVR = 0x16e # Media Select Home
2740+ KEY_MHP = 0x16f
2741+ KEY_LANGUAGE = 0x170
2742+ KEY_TITLE = 0x171
2743+ KEY_SUBTITLE = 0x172
2744+ KEY_ANGLE = 0x173
2745+ KEY_ZOOM = 0x174
2746+ KEY_MODE = 0x175
2747+ KEY_KEYBOARD = 0x176
2748+ KEY_SCREEN = 0x177
2749+ KEY_PC = 0x178 # Media Select Computer
2750+ KEY_TV = 0x179 # Media Select TV
2751+ KEY_TV2 = 0x17a # Media Select Cable
2752+ KEY_VCR = 0x17b # Media Select VCR
2753+ KEY_VCR2 = 0x17c # VCR Plus
2754+ KEY_SAT = 0x17d # Media Select Satellite
2755+ KEY_SAT2 = 0x17e
2756+ KEY_CD = 0x17f # Media Select CD
2757+ KEY_TAPE = 0x180 # Media Select Tape
2758+ KEY_RADIO = 0x181
2759+ KEY_TUNER = 0x182 # Media Select Tuner
2760+ KEY_PLAYER = 0x183
2761+ KEY_TEXT = 0x184
2762+ KEY_DVD = 0x185 # Media Select DVD
2763+ KEY_AUX = 0x186
2764+ KEY_MP3 = 0x187
2765+ KEY_AUDIO = 0x188
2766+ KEY_VIDEO = 0x189
2767+ KEY_DIRECTORY = 0x18a
2768+ KEY_LIST = 0x18b
2769+ KEY_MEMO = 0x18c # Media Select Messages
2770+ KEY_CALENDAR = 0x18d
2771+ KEY_RED = 0x18e
2772+ KEY_GREEN = 0x18f
2773+ KEY_YELLOW = 0x190
2774+ KEY_BLUE = 0x191
2775+ KEY_CHANNELUP = 0x192 # Channel Increment
2776+ KEY_CHANNELDOWN = 0x193 # Channel Decrement
2777+ KEY_FIRST = 0x194
2778+ KEY_LAST = 0x195 # Recall Last
2779+ KEY_AB = 0x196
2780+ KEY_NEXT = 0x197
2781+ KEY_RESTART = 0x198
2782+ KEY_SLOW = 0x199
2783+ KEY_SHUFFLE = 0x19a
2784+ KEY_BREAK = 0x19b
2785+ KEY_PREVIOUS = 0x19c
2786+ KEY_DIGITS = 0x19d
2787+ KEY_TEEN = 0x19e
2788+ KEY_TWEN = 0x19f
2789+ KEY_VIDEOPHONE = 0x1a0 # Media Select Video Phone
2790+ KEY_GAMES = 0x1a1 # Media Select Games
2791+ KEY_ZOOMIN = 0x1a2 # AC Zoom In
2792+ KEY_ZOOMOUT = 0x1a3 # AC Zoom Out
2793+ KEY_ZOOMRESET = 0x1a4 # AC Zoom
2794+ KEY_WORDPROCESSOR = 0x1a5 # AL Word Processor
2795+ KEY_EDITOR = 0x1a6 # AL Text Editor
2796+ KEY_SPREADSHEET = 0x1a7 # AL Spreadsheet
2797+ KEY_GRAPHICSEDITOR = 0x1a8 # AL Graphics Editor
2798+ KEY_PRESENTATION = 0x1a9 # AL Presentation App
2799+ KEY_DATABASE = 0x1aa # AL Database App
2800+ KEY_NEWS = 0x1ab # AL Newsreader
2801+ KEY_VOICEMAIL = 0x1ac # AL Voicemail
2802+ KEY_ADDRESSBOOK = 0x1ad # AL Contacts/Address Book
2803+ KEY_MESSENGER = 0x1ae # AL Instant Messaging
2804+ KEY_DISPLAYTOGGLE = 0x1af # Turn display (LCD) on and off
2805+ KEY_SPELLCHECK = 0x1b0 # AL Spell Check
2806+ KEY_LOGOFF = 0x1b1 # AL Logoff
2807+
2808+ KEY_DOLLAR = 0x1b2
2809+ KEY_EURO = 0x1b3
2810+
2811+ KEY_FRAMEBACK = 0x1b4 # Consumer - transport controls
2812+ KEY_FRAMEFORWARD = 0x1b5
2813+ KEY_CONTEXT_MENU = 0x1b6 # GenDesc - system context menu
2814+ KEY_MEDIA_REPEAT = 0x1b7 # Consumer - transport control
2815+
2816+ KEY_DEL_EOL = 0x1c0
2817+ KEY_DEL_EOS = 0x1c1
2818+ KEY_INS_LINE = 0x1c2
2819+ KEY_DEL_LINE = 0x1c3
2820+
2821+ KEY_FN = 0x1d0
2822+ KEY_FN_ESC = 0x1d1
2823+ KEY_FN_F1 = 0x1d2
2824+ KEY_FN_F2 = 0x1d3
2825+ KEY_FN_F3 = 0x1d4
2826+ KEY_FN_F4 = 0x1d5
2827+ KEY_FN_F5 = 0x1d6
2828+ KEY_FN_F6 = 0x1d7
2829+ KEY_FN_F7 = 0x1d8
2830+ KEY_FN_F8 = 0x1d9
2831+ KEY_FN_F9 = 0x1da
2832+ KEY_FN_F10 = 0x1db
2833+ KEY_FN_F11 = 0x1dc
2834+ KEY_FN_F12 = 0x1dd
2835+ KEY_FN_1 = 0x1de
2836+ KEY_FN_2 = 0x1df
2837+ KEY_FN_D = 0x1e0
2838+ KEY_FN_E = 0x1e1
2839+ KEY_FN_F = 0x1e2
2840+ KEY_FN_S = 0x1e3
2841+ KEY_FN_B = 0x1e4
2842+
2843+ KEY_BRL_DOT1 = 0x1f1
2844+ KEY_BRL_DOT2 = 0x1f2
2845+ KEY_BRL_DOT3 = 0x1f3
2846+ KEY_BRL_DOT4 = 0x1f4
2847+ KEY_BRL_DOT5 = 0x1f5
2848+ KEY_BRL_DOT6 = 0x1f6
2849+ KEY_BRL_DOT7 = 0x1f7
2850+ KEY_BRL_DOT8 = 0x1f8
2851+ KEY_BRL_DOT9 = 0x1f9
2852+ KEY_BRL_DOT10 = 0x1fa
2853+
2854+ KEY_NUMERIC_0 = 0x200 # used by phones, remote controls,
2855+ KEY_NUMERIC_1 = 0x201 # and other keypads
2856+ KEY_NUMERIC_2 = 0x202
2857+ KEY_NUMERIC_3 = 0x203
2858+ KEY_NUMERIC_4 = 0x204
2859+ KEY_NUMERIC_5 = 0x205
2860+ KEY_NUMERIC_6 = 0x206
2861+ KEY_NUMERIC_7 = 0x207
2862+ KEY_NUMERIC_8 = 0x208
2863+ KEY_NUMERIC_9 = 0x209
2864+ KEY_NUMERIC_STAR = 0x20a
2865+ KEY_NUMERIC_POUND = 0x20b
2866+
2867+ # Relative axes
2868+
2869+ REL_X = 0x00
2870+ REL_Y = 0x01
2871+ REL_Z = 0x02
2872+ REL_RX = 0x03
2873+ REL_RY = 0x04
2874+ REL_RZ = 0x05
2875+ REL_HWHEEL = 0x06
2876+ REL_DIAL = 0x07
2877+ REL_WHEEL = 0x08
2878+ REL_MISC = 0x09
2879+ REL_MAX = 0x0f
2880+ REL_CNT = REL_MAX+1
2881+
2882+ # Absolute axes
2883+
2884+ ABS_X = 0x00
2885+ ABS_Y = 0x01
2886+ ABS_Z = 0x02
2887+ ABS_RX = 0x03
2888+ ABS_RY = 0x04
2889+ ABS_RZ = 0x05
2890+ ABS_THROTTLE = 0x06
2891+ ABS_RUDDER = 0x07
2892+ ABS_WHEEL = 0x08
2893+ ABS_GAS = 0x09
2894+ ABS_BRAKE = 0x0a
2895+ ABS_HAT0X = 0x10
2896+ ABS_HAT0Y = 0x11
2897+ ABS_HAT1X = 0x12
2898+ ABS_HAT1Y = 0x13
2899+ ABS_HAT2X = 0x14
2900+ ABS_HAT2Y = 0x15
2901+ ABS_HAT3X = 0x16
2902+ ABS_HAT3Y = 0x17
2903+ ABS_PRESSURE = 0x18
2904+ ABS_DISTANCE = 0x19
2905+ ABS_TILT_X = 0x1a
2906+ ABS_TILT_Y = 0x1b
2907+ ABS_TOOL_WIDTH = 0x1c
2908+ ABS_VOLUME = 0x20
2909+ ABS_MISC = 0x28
2910+ ABS_MAX = 0x3f
2911+ ABS_CNT = ABS_MAX+1
2912+
2913+ # Switch events
2914+
2915+ SW_LID = 0x00 # set = lid shut
2916+ SW_TABLET_MODE = 0x01 # set = tablet mode
2917+ SW_HEADPHONE_INSERT = 0x02 # set = inserted
2918+ SW_RFKILL_ALL = 0x03 # rfkill master switch, type "any"
2919+ # set = radio enabled
2920+ SW_RADIO = SW_RFKILL_ALL # deprecated
2921+ SW_MICROPHONE_INSERT = 0x04 # set = inserted
2922+ SW_DOCK = 0x05 # set = plugged into dock
2923+ SW_MAX = 0x0f
2924+ SW_CNT = SW_MAX+1
2925+
2926+ # Misc events
2927+
2928+ MSC_SERIAL = 0x00
2929+ MSC_PULSELED = 0x01
2930+ MSC_GESTURE = 0x02
2931+ MSC_RAW = 0x03
2932+ MSC_SCAN = 0x04
2933+ MSC_MAX = 0x07
2934+ MSC_CNT = MSC_MAX+1
2935+
2936+ # LEDs
2937+
2938+ LED_NUML = 0x00
2939+ LED_CAPSL = 0x01
2940+ LED_SCROLLL = 0x02
2941+ LED_COMPOSE = 0x03
2942+ LED_KANA = 0x04
2943+ LED_SLEEP = 0x05
2944+ LED_SUSPEND = 0x06
2945+ LED_MUTE = 0x07
2946+ LED_MISC = 0x08
2947+ LED_MAIL = 0x09
2948+ LED_CHARGING = 0x0a
2949+ LED_MAX = 0x0f
2950+ LED_CNT = LED_MAX+1
2951+
2952+ # Autorepeat values
2953+
2954+ REP_DELAY = 0x00
2955+ REP_PERIOD = 0x01
2956+ REP_MAX = 0x01
2957
2958=== added file 'checkbox-support/checkbox_support/lib/path.py'
2959--- checkbox-support/checkbox_support/lib/path.py 1970-01-01 00:00:00 +0000
2960+++ checkbox-support/checkbox_support/lib/path.py 2014-01-07 13:44:32 +0000
2961@@ -0,0 +1,62 @@
2962+#
2963+# This file is part of Checkbox.
2964+#
2965+# Copyright 2008 Canonical Ltd.
2966+#
2967+# Checkbox is free software: you can redistribute it and/or modify
2968+# it under the terms of the GNU General Public License version 3,
2969+# as published by the Free Software Foundation.
2970+
2971+#
2972+# Checkbox is distributed in the hope that it will be useful,
2973+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2974+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2975+# GNU General Public License for more details.
2976+#
2977+# You should have received a copy of the GNU General Public License
2978+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
2979+#
2980+import os
2981+
2982+from glob import glob
2983+
2984+
2985+def path_split(path):
2986+ return path.split(os.path.sep)
2987+
2988+def path_common(l1, l2, common=[]):
2989+ if len(l1) < 1:
2990+ return (common, l1, l2)
2991+
2992+ if len(l2) < 1:
2993+ return (common, l1, l2)
2994+
2995+ if l1[0] != l2[0]:
2996+ return (common, l1, l2)
2997+
2998+ return path_common(l1[1:], l2[1:], common + [l1[0]])
2999+
3000+def path_relative(p1, p2):
3001+ (common, l1, l2) = path_common(path_split(p1), path_split(p2))
3002+ p = []
3003+ if len(l1) > 0:
3004+ p = ["..%s" % os.path.sep * len(l1)]
3005+
3006+ p = p + l2
3007+ return os.path.join( *p )
3008+
3009+def path_expand(path):
3010+ path = os.path.expanduser(path)
3011+ return glob(path)
3012+
3013+def path_expand_recursive(path):
3014+ paths = []
3015+ for path in path_expand(path):
3016+ if os.path.isdir(path):
3017+ for dirpath, dirnames, filenames in os.walk(path):
3018+ for filename in filenames:
3019+ paths.append(os.path.join(dirpath, filename))
3020+ else:
3021+ paths.append(path)
3022+
3023+ return paths
3024
3025=== added file 'checkbox-support/checkbox_support/lib/pci.py'
3026--- checkbox-support/checkbox_support/lib/pci.py 1970-01-01 00:00:00 +0000
3027+++ checkbox-support/checkbox_support/lib/pci.py 2014-01-07 13:44:32 +0000
3028@@ -0,0 +1,89 @@
3029+#
3030+# This file is part of Checkbox.
3031+#
3032+# Copyright 2008 Canonical Ltd.
3033+#
3034+# Checkbox is free software: you can redistribute it and/or modify
3035+# it under the terms of the GNU General Public License version 3,
3036+# as published by the Free Software Foundation.
3037+
3038+#
3039+# Checkbox is distributed in the hope that it will be useful,
3040+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3041+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3042+# GNU General Public License for more details.
3043+#
3044+# You should have received a copy of the GNU General Public License
3045+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3046+#
3047+
3048+# See http://pciids.sourceforge.net/pci.ids.bz2
3049+class Pci:
3050+
3051+ BASE_CLASS_STORAGE = 1
3052+ CLASS_STORAGE_SCSI = 0
3053+ CLASS_STORAGE_IDE = 1
3054+ CLASS_STORAGE_FLOPPY = 2
3055+ CLASS_STORAGE_IPI = 3
3056+ CLASS_STORAGE_RAID = 4
3057+ CLASS_STORAGE_OTHER = 80
3058+
3059+ BASE_CLASS_NETWORK = 2
3060+ CLASS_NETWORK_ETHERNET = 0
3061+ CLASS_NETWORK_TOKEN_RING = 1
3062+ CLASS_NETWORK_FDDI = 2
3063+ CLASS_NETWORK_ATM = 3
3064+ CLASS_NETWORK_OTHER = 80
3065+ CLASS_NETWORK_WIRELESS = 128
3066+
3067+ BASE_CLASS_DISPLAY = 3
3068+ CLASS_DISPLAY_VGA = 0
3069+ CLASS_DISPLAY_XGA = 1
3070+ CLASS_DISPLAY_3D = 2
3071+ CLASS_DISPLAY_OTHER = 80
3072+
3073+ BASE_CLASS_MULTIMEDIA = 4
3074+ CLASS_MULTIMEDIA_VIDEO = 0
3075+ CLASS_MULTIMEDIA_AUDIO = 1
3076+ CLASS_MULTIMEDIA_PHONE = 2
3077+ CLASS_MULTIMEDIA_AUDIO_DEVICE = 3
3078+ CLASS_MULTIMEDIA_OTHER = 80
3079+
3080+ BASE_CLASS_BRIDGE = 6
3081+ CLASS_BRIDGE_HOST = 0
3082+ CLASS_BRIDGE_ISA = 1
3083+ CLASS_BRIDGE_EISA = 2
3084+ CLASS_BRIDGE_MC = 3
3085+ CLASS_BRIDGE_PCI = 4
3086+ CLASS_BRIDGE_PCMCIA = 5
3087+ CLASS_BRIDGE_NUBUS = 6
3088+ CLASS_BRIDGE_CARDBUS = 7
3089+ CLASS_BRIDGE_RACEWAY = 8
3090+ CLASS_BRIDGE_OTHER = 80
3091+
3092+ BASE_CLASS_COMMUNICATION = 7
3093+ CLASS_COMMUNICATION_SERIAL = 0
3094+ CLASS_COMMUNICATION_PARALLEL = 1
3095+ CLASS_COMMUNICATION_MULTISERIAL = 2
3096+ CLASS_COMMUNICATION_MODEM = 3
3097+ CLASS_COMMUNICATION_OTHER = 80
3098+
3099+ BASE_CLASS_INPUT = 9
3100+ CLASS_INPUT_KEYBOARD = 0
3101+ CLASS_INPUT_PEN = 1
3102+ CLASS_INPUT_MOUSE = 2
3103+ CLASS_INPUT_SCANNER = 3
3104+ CLASS_INPUT_GAMEPORT = 4
3105+ CLASS_INPUT_OTHER = 80
3106+
3107+ BASE_CLASS_SERIAL = 12
3108+ CLASS_SERIAL_FIREWIRE = 0
3109+ CLASS_SERIAL_ACCESS = 1
3110+
3111+ BASE_CLASS_WIRELESS = 13
3112+ CLASS_WIRELESS_BLUETOOTH = 17
3113+
3114+ CLASS_SERIAL_SSA = 2
3115+ CLASS_SERIAL_USB = 3
3116+ CLASS_SERIAL_FIBER = 4
3117+ CLASS_SERIAL_SMBUS = 5
3118
3119=== added file 'checkbox-support/checkbox_support/lib/template.py'
3120--- checkbox-support/checkbox_support/lib/template.py 1970-01-01 00:00:00 +0000
3121+++ checkbox-support/checkbox_support/lib/template.py 2014-01-07 13:44:32 +0000
3122@@ -0,0 +1,143 @@
3123+#
3124+# This file is part of Checkbox.
3125+#
3126+# Copyright 2008 Canonical Ltd.
3127+#
3128+# Checkbox is free software: you can redistribute it and/or modify
3129+# it under the terms of the GNU General Public License version 3,
3130+# as published by the Free Software Foundation.
3131+
3132+#
3133+# Checkbox is distributed in the hope that it will be useful,
3134+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3135+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3136+# GNU General Public License for more details.
3137+#
3138+# You should have received a copy of the GNU General Public License
3139+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3140+#
3141+import re
3142+import logging
3143+
3144+
3145+EXTENDED_STRING = "_extended"
3146+
3147+
3148+class Template:
3149+
3150+ def _reader(self, file, size=4096, delimiter=r"\n{2,}"):
3151+ buffer_old = ""
3152+ while True:
3153+ buffer_new = file.read(size)
3154+ if not buffer_new:
3155+ break
3156+
3157+ lines = re.split(delimiter, buffer_old + buffer_new)
3158+ buffer_old = lines.pop(-1)
3159+
3160+ for line in lines:
3161+ yield line
3162+
3163+ yield buffer_old
3164+
3165+ def dump_file(self, elements, file, filename="<stream>"):
3166+ for element in elements:
3167+ for long_key in list(element.keys()):
3168+ if long_key.endswith(EXTENDED_STRING):
3169+ short_key = long_key.replace(EXTENDED_STRING, "")
3170+ del element[short_key]
3171+
3172+ for key, value in element.items():
3173+ if key.endswith(EXTENDED_STRING):
3174+ key = key.replace(EXTENDED_STRING, "")
3175+ file.write("%s:\n" % key)
3176+ for line in value.split("\n"):
3177+ file.write(" %s\n" % line)
3178+ elif isinstance(value, (list, tuple)):
3179+ file.write("%s:\n" % key)
3180+ for v in value:
3181+ file.write(" %s\n" % v)
3182+ else:
3183+ file.write("%s: %s\n" % (key, value))
3184+
3185+ file.write("\n")
3186+
3187+ def dump_filename(self, elements, filename):
3188+ logging.info("Dumping elements to filename: %s", filename)
3189+
3190+ with open(filename, "w") as stream:
3191+ return self.dump_file(elements, stream, filename)
3192+
3193+ def load_file(self, file, filename="<stream>"):
3194+ elements = []
3195+ for string in self._reader(file):
3196+ if not string:
3197+ break
3198+
3199+ element = {}
3200+
3201+ def _save(field, value, extended):
3202+ extended = extended.rstrip("\n")
3203+ if field:
3204+ if field in element:
3205+ raise Exception("Template %s has a duplicate "
3206+ "field '%s' with a new value '%s'."
3207+ % (filename, field, value))
3208+ element[field] = value
3209+ if extended:
3210+ element["%s%s" % (field, EXTENDED_STRING)] = extended
3211+
3212+ string = string.strip("\n")
3213+ field = value = extended = ""
3214+ for line in string.split("\n"):
3215+ line.strip()
3216+ if line.startswith("#"):
3217+ continue
3218+
3219+ match = re.search(r"^([-_.A-Za-z0-9@]*):\s?(.*)", line)
3220+ if match:
3221+ _save(field, value, extended)
3222+ field = match.groups()[0]
3223+ value = match.groups()[1].rstrip()
3224+ extended = ""
3225+ continue
3226+
3227+ if re.search(r"^\s\.$", line):
3228+ extended += "\n\n"
3229+ continue
3230+
3231+ match = re.search(r"^\s(\s+.*)", line)
3232+ if match:
3233+ bit = match.groups()[0].rstrip()
3234+ if len(extended) and not re.search(r"[\n ]$", extended):
3235+ extended += "\n"
3236+
3237+ extended += bit + "\n"
3238+ continue
3239+
3240+ match = re.search(r"^\s(.*)", line)
3241+ if match:
3242+ bit = match.groups()[0].rstrip()
3243+ if len(extended) and not re.search(r"[\n ]$", extended):
3244+ if extended.endswith("\\"):
3245+ extended = extended[:-1].rstrip() + " "
3246+ else:
3247+ extended += "\n"
3248+
3249+ extended += bit
3250+ continue
3251+
3252+ raise Exception("Template %s parse error at: %s" \
3253+ % (filename, line))
3254+
3255+ _save(field, value, extended)
3256+
3257+ elements.append(element)
3258+
3259+ return elements
3260+
3261+ def load_filename(self, filename):
3262+ logging.info("Loading elements from filename: %s", filename)
3263+
3264+ with open(filename, "r", encoding="utf-8") as stream:
3265+ return self.load_file(stream, filename)
3266
3267=== added file 'checkbox-support/checkbox_support/lib/tz.py'
3268--- checkbox-support/checkbox_support/lib/tz.py 1970-01-01 00:00:00 +0000
3269+++ checkbox-support/checkbox_support/lib/tz.py 2014-01-07 13:44:32 +0000
3270@@ -0,0 +1,55 @@
3271+#
3272+# This file is part of Checkbox.
3273+#
3274+# Copyright 2012 Canonical Ltd.
3275+#
3276+# Checkbox is free software: you can redistribute it and/or modify
3277+# it under the terms of the GNU General Public License version 3,
3278+# as published by the Free Software Foundation.
3279+
3280+#
3281+# Checkbox is distributed in the hope that it will be useful,
3282+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3283+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3284+# GNU General Public License for more details.
3285+#
3286+# You should have received a copy of the GNU General Public License
3287+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3288+#
3289+__all__ = [
3290+ "tzutc",
3291+ ]
3292+
3293+from datetime import (
3294+ timedelta,
3295+ tzinfo,
3296+ )
3297+
3298+
3299+ZERO = timedelta(0)
3300+
3301+
3302+class _tzutc(tzinfo):
3303+
3304+ def utcoffset(self, dt):
3305+ return ZERO
3306+
3307+ def dst(self, dt):
3308+ return ZERO
3309+
3310+ def tzname(self, dt):
3311+ return "UTC"
3312+
3313+ def __eq__(self, other):
3314+ return isinstance(other, tzutc)
3315+
3316+ def __ne__(self, other):
3317+ return not self.__eq__(other)
3318+
3319+ def __repr__(self):
3320+ return "%s()" % self.__class__.__name__
3321+
3322+ __reduce__ = object.__reduce__
3323+
3324+
3325+tzutc = _tzutc()
3326
3327=== added file 'checkbox-support/checkbox_support/lib/usb.py'
3328--- checkbox-support/checkbox_support/lib/usb.py 1970-01-01 00:00:00 +0000
3329+++ checkbox-support/checkbox_support/lib/usb.py 2014-01-07 13:44:32 +0000
3330@@ -0,0 +1,59 @@
3331+#
3332+# This file is part of Checkbox.
3333+#
3334+# Copyright 2008 Canonical Ltd.
3335+#
3336+# Checkbox is free software: you can redistribute it and/or modify
3337+# it under the terms of the GNU General Public License version 3,
3338+# as published by the Free Software Foundation.
3339+
3340+#
3341+# Checkbox is distributed in the hope that it will be useful,
3342+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3343+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3344+# GNU General Public License for more details.
3345+#
3346+# You should have received a copy of the GNU General Public License
3347+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3348+#
3349+
3350+# See http://www.linux-usb.org/usb.ids
3351+class Usb:
3352+
3353+ BASE_CLASS_INTERFACE = 0
3354+
3355+ BASE_CLASS_AUDIO = 1
3356+ CLASS_AUDIO_CONTROL_DEVICE = 1
3357+ CLASS_AUDIO_STREAMING = 2
3358+ CLASS_AUDIO_MIDI_STREAMING = 3
3359+
3360+ BASE_CLASS_COMMUNICATIONS = 2
3361+ CLASS_COMMUNICATIONS_DIRECT_LINE = 1
3362+ CLASS_COMMUNICATIONS_ABSTRACT = 2
3363+ CLASS_COMMUNICATIONS_TELEPHONE = 3
3364+
3365+ BASE_CLASS_PRINTER = 7
3366+ CLASS_PRINTER_OTHER = 1
3367+
3368+ BASE_CLASS_STORAGE = 8
3369+ CLASS_STORAGE_RBC = 1
3370+ CLASS_STORAGE_SFF = 2
3371+ CLASS_STORAGE_QIC = 3
3372+ CLASS_STORAGE_FLOPPY = 4
3373+ CLASS_STORAGE_SFF = 5
3374+ CLASS_STORAGE_SCSI = 6
3375+
3376+ BASE_CLASS_HUB = 9
3377+ CLASS_HUB_UNUSED = 0
3378+
3379+ BASE_CLASS_VIDEO = 14
3380+ CLASS_VIDEO_UNDEFINED = 0
3381+ CLASS_VIDEO_CONTROL = 1
3382+ CLASS_VIDEO_STREAMING = 2
3383+ CLASS_VIDEO_INTERFACE_COLLECTION = 3
3384+
3385+ BASE_CLASS_WIRELESS = 224
3386+ CLASS_WIRELESS_RADIO_FREQUENCY = 1
3387+ CLASS_WIRELESS_USB_ADAPTER = 2
3388+
3389+ PROTOCOL_BLUETOOTH = 1
3390
3391=== added directory 'checkbox-support/checkbox_support/parsers'
3392=== added file 'checkbox-support/checkbox_support/parsers/__init__.py'
3393=== added file 'checkbox-support/checkbox_support/parsers/cpuinfo.py'
3394--- checkbox-support/checkbox_support/parsers/cpuinfo.py 1970-01-01 00:00:00 +0000
3395+++ checkbox-support/checkbox_support/parsers/cpuinfo.py 2014-01-07 13:44:32 +0000
3396@@ -0,0 +1,180 @@
3397+#
3398+# This file is part of Checkbox.
3399+#
3400+# Copyright 2011 Canonical Ltd.
3401+#
3402+# Checkbox is free software: you can redistribute it and/or modify
3403+# it under the terms of the GNU General Public License version 3,
3404+# as published by the Free Software Foundation.
3405+
3406+#
3407+# Checkbox is distributed in the hope that it will be useful,
3408+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3409+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3410+# GNU General Public License for more details.
3411+#
3412+# You should have received a copy of the GNU General Public License
3413+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3414+#
3415+import re
3416+
3417+from os import uname
3418+
3419+from checkbox_support.lib.conversion import string_to_type
3420+
3421+
3422+class CpuinfoParser:
3423+ """Parser for the /proc/cpuinfo file."""
3424+
3425+ def __init__(self, stream, machine=None):
3426+ self.stream = stream
3427+ self.machine = machine or uname()[4].lower()
3428+
3429+ def getAttributes(self):
3430+ count = 0
3431+ attributes = {}
3432+ cpuinfo = self.stream.read()
3433+ for block in re.split(r"\n{2,}", cpuinfo):
3434+ block = block.strip()
3435+ if not block:
3436+ continue
3437+
3438+ for line in block.split("\n"):
3439+ if not line:
3440+ continue
3441+ key, value = line.split(":", 1)
3442+ key, value = key.strip(), value.strip()
3443+
3444+ if key == 'processor':
3445+ count += 1
3446+
3447+ # Handle bogomips on sparc
3448+ if key.endswith("Bogo"):
3449+ key = "bogomips"
3450+
3451+ attributes[key] = value
3452+
3453+ if attributes:
3454+ attributes["count"] = count
3455+
3456+ return attributes
3457+
3458+ def run(self, result):
3459+ attributes = self.getAttributes()
3460+ if not attributes:
3461+ return
3462+
3463+ # Default values
3464+ machine = self.machine
3465+ processor = {
3466+ "platform": machine,
3467+ "count": 1,
3468+ "type": machine,
3469+ "model": machine,
3470+ "model_number": "",
3471+ "model_version": "",
3472+ "model_revision": "",
3473+ "cache": 0,
3474+ "bogomips": 0,
3475+ "speed": -1,
3476+ "other": ""}
3477+
3478+ # Conversion table
3479+ platform_to_conversion = {
3480+ ("i386", "i486", "i586", "i686", "x86_64",): {
3481+ "type": "vendor_id",
3482+ "model": "model name",
3483+ "model_number": "cpu family",
3484+ "model_version": "model",
3485+ "model_revision": "stepping",
3486+ "cache": "cache size",
3487+ "other": "flags",
3488+ "speed": "cpu MHz"},
3489+ ("alpha", "alphaev6",): {
3490+ "count": "cpus detected",
3491+ "type": "cpu",
3492+ "model": "cpu model",
3493+ "model_number": "cpu variation",
3494+ "model_version": ("system type", "system variation",),
3495+ "model_revision": "cpu revision",
3496+ "other": "platform string",
3497+ "speed": "cycle frequency [Hz]"},
3498+ ("armv7l",): {
3499+ "type": "Hardware",
3500+ "model": "Processor",
3501+ "model_number": "CPU variant",
3502+ "model_version": "CPU architecture",
3503+ "model_revision": "CPU revision",
3504+ "other": "Features",
3505+ "bogomips": "BogoMIPS"},
3506+ ("ia64",): {
3507+ "type": "vendor",
3508+ "model": "family",
3509+ "model_version": "archrev",
3510+ "model_revision": "revision",
3511+ "other": "features",
3512+ "speed": "cpu mhz"},
3513+ ("ppc64", "ppc",): {
3514+ "type": "platform",
3515+ "model": "cpu",
3516+ "model_version": "revision",
3517+ "speed": "clock"},
3518+ ("sparc64", "sparc",): {
3519+ "count": "ncpus probed",
3520+ "type": "type",
3521+ "model": "cpu",
3522+ "model_version": "type",
3523+ "speed": "bogomips"}}
3524+
3525+ for key in processor:
3526+ if attributes.get(key):
3527+ processor[key] = attributes.get(key)
3528+
3529+ for platform, conversion in platform_to_conversion.items():
3530+ if machine in platform:
3531+ for pkey, ckey in conversion.items():
3532+ if isinstance(ckey, (list, tuple)):
3533+ processor[pkey] = "/".join([attributes[k]
3534+ for k in ckey])
3535+ elif ckey in attributes:
3536+ processor[pkey] = attributes[ckey]
3537+
3538+ # Adjust platform
3539+ if machine[0] == "i" and machine[-2:] == "86":
3540+ processor["platform"] = "i386"
3541+ elif machine[:5] == "alpha":
3542+ processor["platform"] = "alpha"
3543+
3544+ # Adjust cache
3545+ if processor["cache"]:
3546+ processor["cache"] = string_to_type(processor["cache"])
3547+
3548+ # Adjust speed
3549+ try:
3550+ if machine[:5] == "alpha":
3551+ speed = processor["speed"].split()[0]
3552+ processor["speed"] = int(round(float(speed))) / 1000000
3553+ elif machine[:5] == "sparc":
3554+ speed = processor["speed"]
3555+ processor["speed"] = int(round(float(speed))) / 2
3556+ elif machine[:3] == "ppc":
3557+ # String is appended with "mhz"
3558+ speed = processor["speed"][:-3]
3559+ except ValueError:
3560+ processor["speed"] = -1
3561+
3562+ # Make sure speed and bogomips are integers
3563+ processor["speed"] = int(round(float(processor["speed"])) - 1)
3564+ processor["bogomips"] = int(round(float(processor["bogomips"])))
3565+
3566+ # Adjust count
3567+ try:
3568+ processor["count"] = int(processor["count"])
3569+ except ValueError:
3570+ processor["count"] = 1
3571+ else:
3572+ # There is at least one processor
3573+ if processor["count"] == 0:
3574+ processor["count"] = 1
3575+
3576+ result.setProcessor(processor)
3577
3578=== added file 'checkbox-support/checkbox_support/parsers/dmidecode.py'
3579--- checkbox-support/checkbox_support/parsers/dmidecode.py 1970-01-01 00:00:00 +0000
3580+++ checkbox-support/checkbox_support/parsers/dmidecode.py 2014-01-07 13:44:32 +0000
3581@@ -0,0 +1,126 @@
3582+#
3583+# This file is part of Checkbox.
3584+#
3585+# Copyright 2011 Canonical Ltd.
3586+#
3587+# Checkbox is free software: you can redistribute it and/or modify
3588+# it under the terms of the GNU General Public License version 3,
3589+# as published by the Free Software Foundation.
3590+
3591+#
3592+# Checkbox is distributed in the hope that it will be useful,
3593+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3594+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3595+# GNU General Public License for more details.
3596+#
3597+# You should have received a copy of the GNU General Public License
3598+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3599+#
3600+import re
3601+
3602+from string import (
3603+ hexdigits,
3604+ ascii_uppercase,
3605+ )
3606+
3607+from checkbox_support.lib.dmi import (
3608+ Dmi,
3609+ DmiDevice,
3610+ )
3611+
3612+
3613+HANDLE_RE = re.compile(
3614+ r"^Handle (?P<handle>0x[%s]{4}), "
3615+ r"DMI type (?P<type>\d+), "
3616+ r"(?P<size>\d+) bytes$"
3617+ % hexdigits)
3618+KEY_VALUE_RE = re.compile(
3619+ r"^\t(?P<key>[%s].+):( (?P<value>.+))?$"
3620+ % ascii_uppercase)
3621+
3622+
3623+class DmidecodeParser:
3624+ """Parser for the dmidecode command."""
3625+
3626+ _key_map = {
3627+ "ID": "serial",
3628+ "Manufacturer": "vendor",
3629+ "Product Name": "name",
3630+ "Serial Number": "serial",
3631+ "Type": "type",
3632+ "Vendor": "vendor",
3633+ "Version": "version",
3634+ "Size": "size",
3635+ "Form Factor": "form",
3636+ }
3637+
3638+ def __init__(self, stream):
3639+ self.stream = stream
3640+
3641+ def _parseKey(self, key):
3642+ return self._key_map.get(key)
3643+
3644+ def _parseValue(self, value):
3645+ if value is not None:
3646+ value = value.strip()
3647+ if not value:
3648+ value = None
3649+
3650+ return value
3651+
3652+ def run(self, result):
3653+ output = self.stream.read()
3654+ for record in re.split(r"\n{2,}", output):
3655+ record = record.strip()
3656+ # Skip empty records
3657+ if not record:
3658+ continue
3659+
3660+ # Skip header record
3661+ lines = record.split("\n")
3662+ line = lines.pop(0)
3663+ if line.startswith("#"):
3664+ continue
3665+
3666+ # Skip records with an unsupported handle
3667+ match = HANDLE_RE.match(line)
3668+ if not match:
3669+ continue
3670+
3671+ # Skip records that are empty or inactive
3672+ if not lines or lines.pop(0) == "Inactive":
3673+ continue
3674+
3675+ # Skip disabled entries and end-of-table marker
3676+ type_index = int(match.group("type"))
3677+ if type_index >= len(Dmi.type_names):
3678+ continue
3679+
3680+ category = Dmi.type_names[type_index]
3681+ category = category.upper().split(" ")[-1]
3682+ if category not in (
3683+ "BOARD", "BIOS", "CHASSIS", "DEVICE", "PROCESSOR", "SYSTEM"):
3684+ continue
3685+
3686+ # Parse attributes
3687+ attributes = {}
3688+
3689+ for line in lines:
3690+ # Skip lines with an unsupported key/value pair
3691+ match = KEY_VALUE_RE.match(line)
3692+ if not match:
3693+ continue
3694+
3695+ # Skip lines with an unsupported key
3696+ key = self._parseKey(match.group("key"))
3697+ if not key:
3698+ continue
3699+
3700+ key = "%s_%s" % (category.lower(), key)
3701+ value = self._parseValue(match.group("value"))
3702+ attributes[key] = value
3703+
3704+ device = DmiDevice(attributes, category)
3705+ result.addDmiDevice(device)
3706+
3707+ return result
3708
3709=== added file 'checkbox-support/checkbox_support/parsers/efi.py'
3710--- checkbox-support/checkbox_support/parsers/efi.py 1970-01-01 00:00:00 +0000
3711+++ checkbox-support/checkbox_support/parsers/efi.py 2014-01-07 13:44:32 +0000
3712@@ -0,0 +1,52 @@
3713+#
3714+# This file is part of Checkbox.
3715+#
3716+# Copyright 2011 Canonical Ltd.
3717+#
3718+# Checkbox is free software: you can redistribute it and/or modify
3719+# it under the terms of the GNU General Public License version 3,
3720+# as published by the Free Software Foundation.
3721+
3722+#
3723+# Checkbox is distributed in the hope that it will be useful,
3724+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3725+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3726+# GNU General Public License for more details.
3727+#
3728+# You should have received a copy of the GNU General Public License
3729+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3730+#
3731+import re
3732+
3733+
3734+class EfiDevice:
3735+
3736+ path = "/sys/class/dmi/id/bios_version"
3737+ category = "EFI"
3738+
3739+ def __init__(self, product, vendor=None):
3740+ self.product = product
3741+ self.vendor = vendor
3742+
3743+
3744+class EfiParser:
3745+ """Parser for EFI information."""
3746+
3747+ def __init__(self, stream):
3748+ self.stream = stream
3749+
3750+ def run(self, result):
3751+ vendor_product_pattern = re.compile(
3752+ r"^(?P<vendor>.*)\s+by\s+(?P<product>.*)$")
3753+
3754+ for line in self.stream.readlines():
3755+ line = line.strip()
3756+ match = vendor_product_pattern.match(line)
3757+ if match:
3758+ product = match.group("product")
3759+ vendor = match.group("vendor")
3760+ device = EfiDevice(product, vendor)
3761+ else:
3762+ device = EfiDevice(line)
3763+
3764+ result.setEfiDevice(device)
3765
3766=== added file 'checkbox-support/checkbox_support/parsers/lshwjson.py'
3767--- checkbox-support/checkbox_support/parsers/lshwjson.py 1970-01-01 00:00:00 +0000
3768+++ checkbox-support/checkbox_support/parsers/lshwjson.py 2014-01-07 13:44:32 +0000
3769@@ -0,0 +1,23 @@
3770+import sys
3771+import json
3772+
3773+class LshwJsonParser:
3774+
3775+ def __init__(self, stream_or_string):
3776+ self.stream_or_string = stream_or_string
3777+
3778+ def _parse_lshw(self, lshw, result):
3779+ if 'children' in lshw.keys():
3780+ for child in lshw['children']:
3781+ self._parse_lshw(child, result)
3782+ del lshw['children']
3783+
3784+ result.addHardware(lshw)
3785+
3786+ def run(self, result):
3787+ try:
3788+ lshw = json.loads(self.stream_or_string)
3789+ except:
3790+ print('not valid json')
3791+
3792+ self._parse_lshw(lshw, result)
3793
3794=== added file 'checkbox-support/checkbox_support/parsers/meminfo.py'
3795--- checkbox-support/checkbox_support/parsers/meminfo.py 1970-01-01 00:00:00 +0000
3796+++ checkbox-support/checkbox_support/parsers/meminfo.py 2014-01-07 13:44:32 +0000
3797@@ -0,0 +1,46 @@
3798+#
3799+# This file is part of Checkbox.
3800+#
3801+# Copyright 2011 Canonical Ltd.
3802+#
3803+# Checkbox is free software: you can redistribute it and/or modify
3804+# it under the terms of the GNU General Public License version 3,
3805+# as published by the Free Software Foundation.
3806+
3807+#
3808+# Checkbox is distributed in the hope that it will be useful,
3809+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3810+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3811+# GNU General Public License for more details.
3812+#
3813+# You should have received a copy of the GNU General Public License
3814+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3815+#
3816+import re
3817+
3818+
3819+class MeminfoParser:
3820+ """Parser for the /proc/meminfo file."""
3821+
3822+ def __init__(self, stream):
3823+ self.stream = stream
3824+
3825+ def run(self, result):
3826+ key_value_pattern = re.compile(r"(?P<key>.*):\s+(?P<value>.*)")
3827+ meminfo_map = {
3828+ "MemTotal": "total",
3829+ "SwapTotal": "swap"}
3830+
3831+ meminfo = {}
3832+ for line in self.stream.readlines():
3833+ line = line.strip()
3834+ match = key_value_pattern.match(line)
3835+ if match:
3836+ key = match.group("key")
3837+ if key in meminfo_map:
3838+ key = meminfo_map[key]
3839+ value = match.group("value")
3840+ (integer, factor) = value.split()
3841+ meminfo[key] = int(integer) * 1024
3842+
3843+ result.setMemory(meminfo)
3844
3845=== added file 'checkbox-support/checkbox_support/parsers/modinfo.py'
3846--- checkbox-support/checkbox_support/parsers/modinfo.py 1970-01-01 00:00:00 +0000
3847+++ checkbox-support/checkbox_support/parsers/modinfo.py 2014-01-07 13:44:32 +0000
3848@@ -0,0 +1,89 @@
3849+#
3850+# This file is part of Checkbox.
3851+#
3852+# Copyright 2011 Canonical Ltd.
3853+#
3854+# Checkbox is free software: you can redistribute it and/or modify
3855+# it under the terms of the GNU General Public License version 3,
3856+# as published by the Free Software Foundation.
3857+
3858+#
3859+# Checkbox is distributed in the hope that it will be useful,
3860+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3861+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3862+# GNU General Public License for more details.
3863+#
3864+# You should have received a copy of the GNU General Public License
3865+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3866+#
3867+
3868+
3869+class ModinfoParser:
3870+ """
3871+ Parser for modinfo information.
3872+ This will take the stdout for modinfo output and return a dict populated
3873+ with each field.
3874+
3875+ Basic usage in your script:
3876+ try:
3877+ output = subprocess.check_output('/sbin/modinfo e1000e',
3878+ stderr=subprocess.STDOUT,
3879+ universal_newlines=True)
3880+ except CalledProcessError as err:
3881+ print("Error while running modinfo")
3882+ print(err.output)
3883+ return err.returncode
3884+
3885+ parser = ModinfoParser(output)
3886+ all_fields = parser.get_all()
3887+ one_field = parser.get_field(field)
3888+ """
3889+
3890+ def __init__(self, stream):
3891+ self._modinfo = {'alias': [],
3892+ 'author': '',
3893+ 'depends': [],
3894+ 'description': '',
3895+ 'filename': '',
3896+ 'firmware': [],
3897+ 'intree': '',
3898+ 'license': '',
3899+ 'parm': [],
3900+ 'srcversion': '',
3901+ 'vermagic': '',
3902+ 'version': ''}
3903+ self._get_info(stream)
3904+
3905+ def _get_info(self, stream):
3906+ for line in stream.splitlines():
3907+ # At this point, stream should be the stdout from the modinfo
3908+ # command, in a list.
3909+ try:
3910+ key, data = line.split(':', 1)
3911+ except ValueError:
3912+ # Most likely this will be caused by a blank line in the
3913+ # stream, so we just ignore it and move on.
3914+ continue
3915+ else:
3916+ key = key.strip()
3917+ data = data.strip()
3918+ # First, we need to handle alias, parm, firmware, and depends
3919+ # because there can be multiple lines of output for these.
3920+ if key in ('alias', 'depend', 'firmware', 'parm',):
3921+ self._modinfo[key].append(data)
3922+ # Now handle unknown keys
3923+ elif key not in self._modinfo.keys():
3924+ self._modinfo[key] = ("WARNING: Unknown Key %s providing "
3925+ "data: %s") % (key, data)
3926+ # And finally known keys
3927+ else:
3928+ self._modinfo[key] = data
3929+
3930+ def get_all(self):
3931+ return self._modinfo
3932+
3933+ def get_field(self, field):
3934+ if field not in self._modinfo.keys():
3935+ raise Exception("Key not found: %s" % field)
3936+ else:
3937+ return self._modinfo[field]
3938
3939=== added file 'checkbox-support/checkbox_support/parsers/pactl.py'
3940--- checkbox-support/checkbox_support/parsers/pactl.py 1970-01-01 00:00:00 +0000
3941+++ checkbox-support/checkbox_support/parsers/pactl.py 2014-01-07 13:44:32 +0000
3942@@ -0,0 +1,543 @@
3943+# This file is part of Checkbox.
3944+#
3945+# Copyright 2013 Canonical Ltd.
3946+# Written by:
3947+# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
3948+#
3949+# Checkbox is free software: you can redistribute it and/or modify
3950+# it under the terms of the GNU General Public License version 3,
3951+# as published by the Free Software Foundation.
3952+
3953+#
3954+# Checkbox is distributed in the hope that it will be useful,
3955+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3956+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3957+# GNU General Public License for more details.
3958+#
3959+# You should have received a copy of the GNU General Public License
3960+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3961+
3962+"""
3963+:mod:`checkbox_support.parsers.pactl` -- `pactl list` parser
3964+====================================================
3965+
3966+Parser for the output of ``pactl list`` syntax.
3967+
3968+The abstract syntax tree of 'pactl list' is as follows::
3969+
3970+ Document: Record + ('\n' + Record)*
3971+
3972+ Record: RECORD-NAME ':' Attribute+
3973+
3974+ Attribute: ATTRIBUTE-NAME ':' AttributeValue
3975+
3976+ AttributeValue: SIMPLE-VALUE '\n'
3977+ | PropertyValue
3978+ | VOLUME-VALUE
3979+ | BASE-VOLUME-VALUE
3980+ | PORT+
3981+ | PORT-WITH-PROFILE+
3982+
3983+ PropertyValue: PROPERTY-NAME '=' PROPERTY-VALUE
3984+
3985+ (other all-upsercase values are not specified in detail)
3986+
3987+Some parts of the output are always localized while others depend on the
3988+locale of the current user. This is caused by the fact that ``pactl`` talks to
3989+pulse audio server over DBus. Some of the data obtained from pulse that was is
3990+localized and it is difficult to influence. This should be of no problem for
3991+the parser but actual usage of the data can be more difficult.
3992+"""
3993+
3994+from collections import OrderedDict
3995+from inspect import isroutine
3996+
3997+import pyparsing as p
3998+
3999+
4000+# Enable packrat paring.
4001+#
4002+# This reduces the complexity of the parser
4003+# from O(2**N) to O(N) at the cost of memory O(N) vs O(1).
4004+p.ParserElement.enablePackrat()
4005+
4006+# XXX: Hack, changes global stuff
4007+#
4008+# This makes pyparsing not so ignorant to whitespace. Normally pyparsing is
4009+# happily treating newlines, tabs, spaces and carriage returns as irrelevant
4010+# spacers between tokens. Because pactl syntax is so whitespace-sensitive this
4011+# is globally turned off. A proper solution would apply this on a
4012+# per-ParserElement level
4013+p.ParserElement.DEFAULT_WHITE_CHARS = " "
4014+
4015+
4016+class NodeMeta(type):
4017+ """
4018+ Metaclass for all Node types.
4019+
4020+ Helps to setup the `Syntax` attribute using the special `__syntax__`
4021+ attribute. It also calls from_tokens() with the appropriate class.
4022+ """
4023+
4024+ def __new__(mcls, name, bases, ns):
4025+ cls = type.__new__(mcls, name, bases, ns)
4026+ if hasattr(cls, '__syntax__'):
4027+ cls.Syntax = (
4028+ cls.__syntax__
4029+ ).setParseAction(
4030+ cls.from_tokens
4031+ ).parseWithTabs()
4032+ return cls
4033+
4034+
4035+class Node(metaclass=NodeMeta):
4036+ """
4037+ Base class for things parsed by pyparsing.
4038+
4039+ Defines sensible __repr__(), __init__() and from_tokens(). That
4040+ last class method uses __fragments__ to pick things from pyparsing
4041+ ParseResults and assign them to attributes of the Node instance.
4042+
4043+ This serves as a buffer between pyparsing and external code, so that
4044+ anything we do to the syntax is irrelevant as long as the tree of
4045+ Nodes remains the same.
4046+ """
4047+
4048+ __fragments__ = {}
4049+
4050+ def __init__(self, **kwargs):
4051+ for attr, value in kwargs.items():
4052+ setattr(self, attr, value)
4053+
4054+ def __repr__(self):
4055+ return "{}({})".format(
4056+ type(self).__name__, ", ".join([
4057+ "{}={!r}".format(attr, getattr(self, attr))
4058+ for attr in self.__fragments__]))
4059+
4060+ @classmethod
4061+ def from_tokens(cls, tokens):
4062+ """
4063+ Create a node from tokens that were matched from __syntax__
4064+ """
4065+ data = {
4066+ attr: mapper(tokens) if isroutine(mapper) else tokens[mapper]
4067+ for attr, mapper in cls.__fragments__.items()
4068+ }
4069+ return cls(**data)
4070+
4071+
4072+class Property(Node):
4073+ """
4074+ A key=value pair.
4075+
4076+ A list of properties is a possible syntax for Attribute value.
4077+ """
4078+
4079+ __fragments__ = {
4080+ 'name': 'property-name',
4081+ 'value': 'property-value'
4082+ }
4083+
4084+ __syntax__ = (
4085+ p.Word(p.alphanums + "-_.").setResultsName("property-name")
4086+ + p.Suppress('=')
4087+ + p.QuotedString('"').setResultsName("property-value")
4088+ ).setResultsName('property')
4089+
4090+
4091+class Profile(Node):
4092+ """
4093+ Description of a pulseaudio profile.
4094+ """
4095+
4096+ __fragments__ = {
4097+ 'name': 'profile-name',
4098+ 'label': 'profile-label',
4099+ 'sink_cnt': 'profile-sink-count',
4100+ 'source_cnt': 'profile-source-count',
4101+ 'priority': 'profile-priority',
4102+ }
4103+
4104+ __syntax__ = (
4105+ p.Word(p.alphanums + "+-:").setParseAction(
4106+ lambda t: t[0].rstrip(':')
4107+ ).setResultsName("profile-name")
4108+ + p.delimitedList(
4109+ p.Literal("(HDMI)") | p.Literal("(IEC958)") | p.Regex('[^ (\n]+'),
4110+ ' ', combine=True
4111+ ).setResultsName('profile-label')
4112+ + p.Suppress('(')
4113+ + p.Keyword('sinks').suppress()
4114+ + p.Suppress(':')
4115+ + p.Word(p.nums).setParseAction(
4116+ lambda t: int(t[0])
4117+ ).setResultsName('profile-sink-count')
4118+ + p.Suppress(',')
4119+ + p.Keyword('sources').suppress()
4120+ + p.Suppress(':')
4121+ + p.Word(p.nums).setParseAction(
4122+ lambda t: int(t[0])
4123+ ).setResultsName('profile-source-count')
4124+ + p.Suppress(',')
4125+ + p.Keyword('priority').suppress()
4126+ + p.MatchFirst([
4127+ p.Suppress('.'),
4128+ # http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/src/utils/pactl.c?id=83c3cf0a65fb05900f81bd2dbb38e6956eb23935
4129+ p.Suppress(':'),
4130+ ])
4131+ + p.Word(p.nums).setParseAction(
4132+ lambda t: int(t[0])
4133+ ).setResultsName('profile-priority')
4134+ + p.Suppress(')')
4135+ ).setResultsName("profile")
4136+
4137+
4138+class Port(Node):
4139+ """
4140+ Description of a port on a sink
4141+ """
4142+
4143+ __fragments__ = {
4144+ 'name': 'port-name',
4145+ 'label': 'port-label',
4146+ 'priority': 'port-priority',
4147+ 'availability': 'port-availability'
4148+ }
4149+
4150+ __syntax__ = (
4151+ p.Word(p.alphanums + "-;").setResultsName('port-name')
4152+ + p.Suppress(':')
4153+ # This part was very tricky to write. The label is basically
4154+ # arbitrary localized Unicode text. We want to grab all of it in
4155+ # one go but without consuming the upcoming '(' character or the
4156+ # space that comes immediately before.
4157+ #
4158+ # The syntax here combines a sequence of words, as defined by
4159+ # anything other than a space and '(', delimited by a single
4160+ # whitespace.
4161+ + p.delimitedList(
4162+ p.Regex('[^ (\n]+'), ' ', combine=True
4163+ ).setResultsName('port-label')
4164+ + p.Suppress('(')
4165+ + p.Keyword('priority').suppress()
4166+ + p.Suppress(':')
4167+ + p.Word(p.nums).setParseAction(
4168+ lambda t: int(t[0])
4169+ ).setResultsName('port-priority')
4170+ + p.MatchFirst([
4171+ p.Suppress(',') + p.Literal('not available'),
4172+ p.Suppress(',') + p.Literal('available'),
4173+ p.Empty().setParseAction(lambda t: '')
4174+ ]).setResultsName('port-availability')
4175+ + p.Suppress(')')
4176+ ).setResultsName("port")
4177+
4178+
4179+# =================
4180+# Shared Attributes
4181+# =================
4182+
4183+PropertyAttributeValue = (
4184+ p.Group(
4185+ p.OneOrMore(
4186+ p.LineStart().suppress()
4187+ + p.Optional(p.White('\t')).suppress()
4188+ + p.Optional(Property.Syntax)
4189+ + p.LineEnd().suppress()
4190+ )
4191+ ).setResultsName("attribute-value"))
4192+
4193+
4194+class PortWithProfile(Node):
4195+ """
4196+ Variant of :class:`Port` that is used by "card" records inside
4197+ the "Ports" property. It differs from the normal port syntax by having
4198+ different entries inside the last section. Availability is not listed
4199+ here, only priority. Priority does not have a colon before the actual
4200+ number. This port is followed by profile assignment.
4201+ """
4202+ __fragments__ = {
4203+ 'name': 'port-name',
4204+ 'label': 'port-label',
4205+ 'priority': 'port-priority',
4206+ 'latency_offset': 'port-latency-offset',
4207+ 'availability': 'port-availability',
4208+ 'properties': lambda t: t['port-properties'].asList(),
4209+ 'profile_list': lambda t: t['port-profile-list'].asList(),
4210+ }
4211+
4212+ __syntax__ = (
4213+ p.Word(p.alphanums + "-;").setResultsName('port-name')
4214+ + p.Suppress(':')
4215+ # This part was very tricky to write. The label is basically arbitrary
4216+ # localized Unicode text. We want to grab all of it in one go but
4217+ # without consuming the upcoming and latest '(' character or the space
4218+ # that comes immediately before.
4219+ #
4220+ # The syntax here combines a sequence of words, as defined by anything
4221+ # other than a space and '(', delimited by a single whitespace.
4222+ + p.Combine(
4223+ p.OneOrMore(
4224+ ~p.FollowedBy(
4225+ p.Regex('\(.+?\)')
4226+ + p.LineEnd()
4227+ )
4228+ + p.Regex('[^ \n]+')
4229+ + p.White().suppress()
4230+ ),
4231+ ' '
4232+ ).setResultsName('port-label')
4233+ + p.Suppress('(')
4234+ + p.Keyword('priority').suppress()
4235+ + p.Optional(
4236+ p.Suppress(':')
4237+ )
4238+ + p.Word(p.nums).setParseAction(
4239+ lambda t: int(t[0])
4240+ ).setResultsName('port-priority')
4241+ + p.Optional(
4242+ p.MatchFirst([
4243+ p.Suppress(',') + p.Keyword('latency offset:').suppress()
4244+ + p.Word(p.nums).setParseAction(lambda t: int(t[0]))
4245+ + p.Literal("usec").suppress(),
4246+ p.Empty().setParseAction(lambda t: '')
4247+ ]).setResultsName('port-latency-offset')
4248+ )
4249+ + p.Optional(
4250+ p.MatchFirst([
4251+ p.Suppress(',') + p.Literal('not available'),
4252+ p.Suppress(',') + p.Literal('available'),
4253+ p.Empty().setParseAction(lambda t: '')
4254+ ]).setResultsName('port-availability')
4255+ )
4256+ + p.Suppress(')')
4257+ + p.LineEnd().suppress()
4258+ + p.Optional(
4259+ p.MatchFirst([
4260+ p.LineStart().suppress()
4261+ + p.NotAny(p.White(' '))
4262+ + p.White('\t').suppress()
4263+ + p.Keyword('Properties:').suppress()
4264+ + p.LineEnd().suppress()
4265+ + PropertyAttributeValue,
4266+ p.Empty().setParseAction(lambda t: [])
4267+ ]).setResultsName('port-properties')
4268+ )
4269+ + p.White('\t', max=3).suppress()
4270+ + p.Literal("Part of profile(s)").suppress()
4271+ + p.Suppress(":")
4272+ + p.delimitedList(
4273+ p.Word(p.alphanums + "+-:"), ", "
4274+ ).setResultsName("port-profile-list")
4275+ ).setResultsName("port")
4276+
4277+
4278+# =========================
4279+# Non-collection attributes
4280+# =========================
4281+
4282+AttributeName = p.Regex("[a-zA-Z][^:\n]+").setResultsName("attribute-name")
4283+
4284+
4285+VolumeAttributeValue = (
4286+ p.Combine(
4287+ p.Or([
4288+ p.Literal("(invalid)"),
4289+ p.Regex("([0-9]+: +[0-9]+% ?)+")
4290+ ])
4291+ + p.LineEnd()
4292+ + p.Optional(p.White('\t').suppress())
4293+ + p.Or([
4294+ p.Literal("(invalid)"),
4295+ p.Regex("([0-9]+: -?[0-9]+\.[0-9]+ dB ?)+")
4296+ ])
4297+ + p.LineEnd()
4298+ + p.Optional(p.White('\t').suppress())
4299+ + p.Regex("balance [0-9]+\.[0-9]+")
4300+ + p.LineEnd(),
4301+ adjacent=False
4302+ ).setResultsName("attribute-value")
4303+)
4304+
4305+
4306+BaseVolumeAttributeValue = (
4307+ p.Combine(
4308+ p.Regex("[0-9]+%")
4309+ + p.LineEnd()
4310+ + p.Optional(p.White('\t').suppress())
4311+ + p.Regex("-?[0-9]+\.[0-9]+ dB")
4312+ + p.LineEnd(),
4313+ adjacent=False
4314+ ).setResultsName("attribute-value")
4315+)
4316+
4317+
4318+SimpleAttributeValue = (
4319+ p.Regex("[^\n]*").setResultsName("attribute-value")
4320+ + p.LineEnd().suppress())
4321+
4322+# simple values
4323+GenericSimpleAttributeValue = p.MatchFirst([
4324+ VolumeAttributeValue,
4325+ BaseVolumeAttributeValue,
4326+ SimpleAttributeValue,
4327+])
4328+
4329+
4330+class GenericSimpleAttribute(Node):
4331+
4332+ __fragments__ = {
4333+ 'name': 'attribute-name',
4334+ 'value': 'attribute-value',
4335+ }
4336+
4337+ __syntax__ = (
4338+ p.LineStart().suppress()
4339+ + p.NotAny(p.White(' '))
4340+ + p.Optional(p.White('\t')).suppress()
4341+ + AttributeName
4342+ + p.Literal(':').suppress()
4343+ + GenericSimpleAttributeValue
4344+ ).setResultsName("attribute")
4345+
4346+
4347+# =====================
4348+# Collection Attributes
4349+# =====================
4350+
4351+PortsAttributeValue = (
4352+ p.Group(
4353+ p.OneOrMore(
4354+ p.LineStart().suppress()
4355+ + p.Optional(p.White('\t')).suppress()
4356+ + Port.Syntax
4357+ + p.LineEnd().suppress())
4358+ ).setResultsName("attribute-value"))
4359+
4360+PortsWithProfilesAttributeValue = (
4361+ p.Group(
4362+ p.OneOrMore(
4363+ p.LineStart().suppress()
4364+ + p.Optional(p.White('\t')).suppress()
4365+ + PortWithProfile.Syntax
4366+ + p.LineEnd().suppress())
4367+ ).setResultsName("attribute-value"))
4368+
4369+FormatsAttributeValue = (
4370+ p.Group(
4371+ p.OneOrMore(
4372+ p.LineStart().suppress()
4373+ + p.Optional(p.White('\t')).suppress()
4374+ + p.Word(p.alphas)
4375+ + p.LineEnd().suppress())
4376+ ).setResultsName("attribute-value"))
4377+
4378+ProfilesAttributeValue = (
4379+ p.Group(
4380+ p.OneOrMore(
4381+ p.LineStart().suppress()
4382+ + p.Optional(p.White('\t')).suppress()
4383+ + Profile.Syntax
4384+ + p.LineEnd().suppress())
4385+ ).setResultsName("attribute-value"))
4386+
4387+
4388+GenericListAttributeValue = p.MatchFirst([
4389+ PortsAttributeValue,
4390+ PropertyAttributeValue,
4391+ PortsWithProfilesAttributeValue,
4392+ ProfilesAttributeValue,
4393+ FormatsAttributeValue,
4394+])
4395+
4396+
4397+class GenericListAttribute(Node):
4398+
4399+ __fragments__ = {
4400+ 'name': 'attribute-name',
4401+ 'value': lambda t: t['attribute-value'].asList()
4402+ }
4403+
4404+ __syntax__ = (
4405+ p.LineStart().suppress()
4406+ + p.NotAny(p.White(' '))
4407+ + p.Optional(p.White('\t')).suppress()
4408+ + AttributeName
4409+ + p.Literal(':').suppress()
4410+ + p.LineEnd().suppress()
4411+ + GenericListAttributeValue
4412+ ).setResultsName("attribute")
4413+
4414+
4415+class Record(Node):
4416+ """
4417+ Single standalone entry of `pactl list`.
4418+
4419+ The record is composed of a name and a list of attributes. Pulseaudio
4420+ exposes objects such as cards, sinks and sources as separate records.
4421+
4422+ Each attribute may be of a different type. Some attributes are simple
4423+ values while others have finer structure, including lits and even
4424+ additional recursive attributes.
4425+ """
4426+
4427+ __fragments__ = {
4428+ 'name': 'record-name',
4429+ 'attribute_list': lambda t: t['record-attributes'].asList(),
4430+ 'attribute_map': lambda t: OrderedDict(
4431+ (attr.name, attr)
4432+ for attr in t['record-attributes'].asList()),
4433+ }
4434+
4435+ __syntax__ = (
4436+ p.LineStart()
4437+ + p.NotAny(p.White(' \t'))
4438+ + p.Regex("[A-Z][a-zA-Z ]+ #[0-9]+").setResultsName("record-name")
4439+ + p.LineEnd().suppress()
4440+ + p.OneOrMore(
4441+ p.Or([
4442+ GenericListAttribute.Syntax,
4443+ GenericSimpleAttribute.Syntax,
4444+ ])
4445+ ).setResultsName("record-attributes")
4446+ ).setResultsName("record")
4447+
4448+ def as_json(self):
4449+ return {
4450+ 'name': self.name,
4451+ 'attribute_list': self.attribute_list,
4452+ }
4453+
4454+ def __repr__(self):
4455+ # Custom __repr__ that skips attribute_map
4456+ return "{}({})".format(
4457+ type(self).__name__, ", ".join([
4458+ "{}={!r}".format(attr, getattr(self, attr))
4459+ for attr in ['name', 'attribute_list']]))
4460+
4461+
4462+class Document(Node):
4463+ """
4464+ Encompasses whole output of `pactl list`
4465+ The document is composed of a list of :class:`Record` objects
4466+ """
4467+
4468+ __fragments__ = {
4469+ 'record_list': lambda t: t['record-list'].asList(),
4470+ }
4471+
4472+ __syntax__ = (
4473+ p.OneOrMore(
4474+ Record.Syntax + p.Optional("\n").suppress()
4475+ ).setResultsName("record-list")
4476+ ).parseWithTabs()
4477+
4478+
4479+def parse_pactl_output(output):
4480+ """
4481+ Parse output of `LANG=C pactl list`
4482+
4483+ :returns: :class:`Document` object that corresponds to the parsed input
4484+ """
4485+ return Document.Syntax.parseString(output, parseAll=True)[0]
4486
4487=== added directory 'checkbox-support/checkbox_support/parsers/tests'
4488=== added file 'checkbox-support/checkbox_support/parsers/tests/__init__.py'
4489=== added directory 'checkbox-support/checkbox_support/parsers/tests/fixtures'
4490=== added file 'checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt'
4491--- checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt 1970-01-01 00:00:00 +0000
4492+++ checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_quantal.txt 2014-01-07 13:44:32 +0000
4493@@ -0,0 +1,143 @@
4494+⎡ Virtual core pointer id=2 [master pointer (3)]
4495+Reporting 4 classes:
4496+Class originated from: 10. Type: XIButtonClass
4497+Buttons supported: 10
4498+Button labels: "Button Unknown" "Button Unknown" "Button Unknown"
4499+"Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button
4500+Horiz Wheel Right" None None None
4501+Button state:
4502+Class originated from: 10. Type: XIValuatorClass
4503+Detail for Valuator 0:
4504+Label: Abs MT Position X
4505+Range: 0.000000 - 1919.000000
4506+Resolution: 0 units/m
4507+Mode: absolute
4508+Current value: 1664.000000
4509+Class originated from: 10. Type: XIValuatorClass
4510+Detail for Valuator 1:
4511+Label: Abs MT Position Y
4512+Range: 0.000000 - 1079.000000
4513+Resolution: 0 units/m
4514+Mode: absolute
4515+Current value: 932.000000
4516+Class originated from: 0. Type: XITouchClass
4517+Touch mode: direct
4518+Max number of touches: 17
4519+
4520+⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
4521+Reporting 3 classes:
4522+Class originated from: 4. Type: XIButtonClass
4523+Buttons supported: 10
4524+Button labels: "Button Left" "Button Middle" "Button Right" "Button
4525+Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz
4526+Wheel Right" None None None
4527+Button state:
4528+Class originated from: 4. Type: XIValuatorClass
4529+Detail for Valuator 0:
4530+Label: Rel X
4531+Range: -1.000000 - -1.000000
4532+Resolution: 0 units/m
4533+Mode: relative
4534+Class originated from: 4. Type: XIValuatorClass
4535+Detail for Valuator 1:
4536+Label: Rel Y
4537+Range: -1.000000 - -1.000000
4538+Resolution: 0 units/m
4539+Mode: relative
4540+
4541+⎜ ↳ Quanta OpticalTouchScreen id=10 [slave pointer (2)]
4542+Reporting 4 classes:
4543+Class originated from: 10. Type: XIButtonClass
4544+Buttons supported: 5
4545+Button labels: "Button Unknown" "Button Unknown" "Button Unknown"
4546+"Button Wheel Up" "Button Wheel Down"
4547+Button state:
4548+Class originated from: 10. Type: XIValuatorClass
4549+Detail for Valuator 0:
4550+Label: Abs MT Position X
4551+Range: 0.000000 - 1919.000000
4552+Resolution: 0 units/m
4553+Mode: absolute
4554+Current value: 1664.000000
4555+Class originated from: 10. Type: XIValuatorClass
4556+Detail for Valuator 1:
4557+Label: Abs MT Position Y
4558+Range: 0.000000 - 1079.000000
4559+Resolution: 0 units/m
4560+Mode: absolute
4561+Current value: 932.000000
4562+Class originated from: 0. Type: XITouchClass
4563+Touch mode: direct
4564+Max number of touches: 9
4565+
4566+⎜ ↳ MCE IR Keyboard/Mouse (nuvoton-cir) id=12 [slave pointer (2)]
4567+Reporting 4 classes:
4568+Class originated from: 12. Type: XIButtonClass
4569+Buttons supported: 5
4570+Button labels: "Button Left" "Button Unknown" "Button Right" "Button
4571+Wheel Up" "Button Wheel Down"
4572+Button state:
4573+Class originated from: 12. Type: XIKeyClass
4574+Keycodes supported: 248
4575+Class originated from: 12. Type: XIValuatorClass
4576+Detail for Valuator 0:
4577+Label: Rel X
4578+Range: -1.000000 - -1.000000
4579+Resolution: 1 units/m
4580+Mode: relative
4581+Class originated from: 12. Type: XIValuatorClass
4582+Detail for Valuator 1:
4583+Label: Rel Y
4584+Range: -1.000000 - -1.000000
4585+Resolution: 1 units/m
4586+Mode: relative
4587+
4588+⎣ Virtual core keyboard id=3 [master keyboard (2)]
4589+Reporting 1 classes:
4590+Class originated from: 14. Type: XIKeyClass
4591+Keycodes supported: 248
4592+
4593+↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
4594+Reporting 1 classes:
4595+Class originated from: 5. Type: XIKeyClass
4596+Keycodes supported: 248
4597+
4598+↳ Power Button id=6 [slave keyboard (3)]
4599+Reporting 1 classes:
4600+Class originated from: 6. Type: XIKeyClass
4601+Keycodes supported: 248
4602+
4603+↳ Power Button id=7 [slave keyboard (3)]
4604+Reporting 1 classes:
4605+Class originated from: 7. Type: XIKeyClass
4606+Keycodes supported: 248
4607+
4608+↳ Laptop_Integrated_Webcam_2M id=8 [slave keyboard (3)]
4609+Reporting 1 classes:
4610+Class originated from: 8. Type: XIKeyClass
4611+Keycodes supported: 248
4612+
4613+↳ HID 413c:8161 id=9 [slave keyboard (3)]
4614+Reporting 1 classes:
4615+Class originated from: 9. Type: XIKeyClass
4616+Keycodes supported: 248
4617+
4618+↳ Nuvoton w836x7hg Infrared Remote Transceiver id=11 [slave keyboard (3)]
4619+Reporting 1 classes:
4620+Class originated from: 11. Type: XIKeyClass
4621+Keycodes supported: 248
4622+
4623+↳ Dell AIO WMI hotkeys id=13 [slave keyboard (3)]
4624+Reporting 1 classes:
4625+Class originated from: 13. Type: XIKeyClass
4626+Keycodes supported: 248
4627+
4628+↳ Chicony USB Keyboard id=14 [slave keyboard (3)]
4629+Reporting 1 classes:
4630+Class originated from: 14. Type: XIKeyClass
4631+Keycodes supported: 248
4632+
4633+↳ Chicony USB Keyboard id=15 [slave keyboard (3)]
4634+Reporting 1 classes:
4635+Class originated from: 15. Type: XIKeyClass
4636+Keycodes supported: 248
4637
4638=== added file 'checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt'
4639--- checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt 1970-01-01 00:00:00 +0000
4640+++ checkbox-support/checkbox_support/parsers/tests/fixtures/xinput_toshiba.txt 2014-01-07 13:44:32 +0000
4641@@ -0,0 +1,166 @@
4642+⎡ Virtual core pointer id=2 [master pointer (3)]
4643+ Reporting 8 classes:
4644+ Class originated from: 12. Type: XIButtonClass
4645+ Buttons supported: 12
4646+ 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
4647+ Button state:
4648+ Class originated from: 12. Type: XIValuatorClass
4649+ Detail for Valuator 0:
4650+ Label: Rel X
4651+ Range: 0.000000 - 2000.000000
4652+ Resolution: 0 units/m
4653+ Mode: relative
4654+ Class originated from: 12. Type: XIValuatorClass
4655+ Detail for Valuator 1:
4656+ Label: Rel Y
4657+ Range: 0.000000 - 1400.000000
4658+ Resolution: 0 units/m
4659+ Mode: relative
4660+ Class originated from: 12. Type: XIValuatorClass
4661+ Detail for Valuator 2:
4662+ Label: Rel Horiz Scroll
4663+ Range: 0.000000 - -1.000000
4664+ Resolution: 0 units/m
4665+ Mode: relative
4666+ Class originated from: 12. Type: XIValuatorClass
4667+ Detail for Valuator 3:
4668+ Label: Rel Vert Scroll
4669+ Range: 0.000000 - -1.000000
4670+ Resolution: 0 units/m
4671+ Mode: relative
4672+ Class originated from: 12. Type: XIScrollClass
4673+ Scroll info for Valuator 2
4674+ type: 2 (horizontal)
4675+ increment: 48.000000
4676+ flags: 0x0
4677+ Class originated from: 12. Type: XIScrollClass
4678+ Scroll info for Valuator 3
4679+ type: 1 (vertical)
4680+ increment: 48.000000
4681+ flags: 0x0
4682+ Class originated from: 0. Type: XITouchClass
4683+ Touch mode: dependent
4684+ Max number of touches: 2
4685+
4686+⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
4687+ Reporting 3 classes:
4688+ Class originated from: 4. Type: XIButtonClass
4689+ Buttons supported: 10
4690+ 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
4691+ Button state:
4692+ Class originated from: 4. Type: XIValuatorClass
4693+ Detail for Valuator 0:
4694+ Label: Rel X
4695+ Range: -1.000000 - -1.000000
4696+ Resolution: 0 units/m
4697+ Mode: relative
4698+ Class originated from: 4. Type: XIValuatorClass
4699+ Detail for Valuator 1:
4700+ Label: Rel Y
4701+ Range: -1.000000 - -1.000000
4702+ Resolution: 0 units/m
4703+ Mode: relative
4704+
4705+⎜ ↳ DualPoint Stick id=11 [slave pointer (2)]
4706+ Reporting 3 classes:
4707+ Class originated from: 11. Type: XIButtonClass
4708+ Buttons supported: 7
4709+ Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right"
4710+ Button state:
4711+ Class originated from: 11. Type: XIValuatorClass
4712+ Detail for Valuator 0:
4713+ Label: Rel X
4714+ Range: -1.000000 - -1.000000
4715+ Resolution: 1 units/m
4716+ Mode: relative
4717+ Class originated from: 11. Type: XIValuatorClass
4718+ Detail for Valuator 1:
4719+ Label: Rel Y
4720+ Range: -1.000000 - -1.000000
4721+ Resolution: 1 units/m
4722+ Mode: relative
4723+
4724+⎜ ↳ AlpsPS/2 ALPS DualPoint TouchPad id=12 [slave pointer (2)]
4725+ Reporting 8 classes:
4726+ Class originated from: 12. Type: XIButtonClass
4727+ Buttons supported: 12
4728+ 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
4729+ Button state:
4730+ Class originated from: 12. Type: XIValuatorClass
4731+ Detail for Valuator 0:
4732+ Label: Rel X
4733+ Range: 0.000000 - 2000.000000
4734+ Resolution: 0 units/m
4735+ Mode: relative
4736+ Class originated from: 12. Type: XIValuatorClass
4737+ Detail for Valuator 1:
4738+ Label: Rel Y
4739+ Range: 0.000000 - 1400.000000
4740+ Resolution: 0 units/m
4741+ Mode: relative
4742+ Class originated from: 12. Type: XIValuatorClass
4743+ Detail for Valuator 2:
4744+ Label: Rel Horiz Scroll
4745+ Range: 0.000000 - -1.000000
4746+ Resolution: 0 units/m
4747+ Mode: relative
4748+ Class originated from: 12. Type: XIValuatorClass
4749+ Detail for Valuator 3:
4750+ Label: Rel Vert Scroll
4751+ Range: 0.000000 - -1.000000
4752+ Resolution: 0 units/m
4753+ Mode: relative
4754+ Class originated from: 12. Type: XIScrollClass
4755+ Scroll info for Valuator 2
4756+ type: 2 (horizontal)
4757+ increment: 48.000000
4758+ flags: 0x0
4759+ Class originated from: 12. Type: XIScrollClass
4760+ Scroll info for Valuator 3
4761+ type: 1 (vertical)
4762+ increment: 48.000000
4763+ flags: 0x0
4764+ Class originated from: 0. Type: XITouchClass
4765+ Touch mode: dependent
4766+ Max number of touches: 2
4767+
4768+⎣ Virtual core keyboard id=3 [master keyboard (2)]
4769+ Reporting 1 classes:
4770+ Class originated from: 10. Type: XIKeyClass
4771+ Keycodes supported: 248
4772+
4773+ ↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
4774+ Reporting 1 classes:
4775+ Class originated from: 5. Type: XIKeyClass
4776+ Keycodes supported: 248
4777+
4778+ ↳ Power Button id=6 [slave keyboard (3)]
4779+ Reporting 1 classes:
4780+ Class originated from: 6. Type: XIKeyClass
4781+ Keycodes supported: 248
4782+
4783+ ↳ Video Bus id=7 [slave keyboard (3)]
4784+ Reporting 1 classes:
4785+ Class originated from: 7. Type: XIKeyClass
4786+ Keycodes supported: 248
4787+
4788+ ↳ Power Button id=8 [slave keyboard (3)]
4789+ Reporting 1 classes:
4790+ Class originated from: 8. Type: XIKeyClass
4791+ Keycodes supported: 248
4792+
4793+ ↳ CNF9055 id=9 [slave keyboard (3)]
4794+ Reporting 1 classes:
4795+ Class originated from: 9. Type: XIKeyClass
4796+ Keycodes supported: 248
4797+
4798+ ↳ AT Translated Set 2 keyboard id=10 [slave keyboard (3)]
4799+ Reporting 1 classes:
4800+ Class originated from: 10. Type: XIKeyClass
4801+ Keycodes supported: 248
4802+
4803+ ↳ Toshiba input device id=13 [slave keyboard (3)]
4804+ Reporting 1 classes:
4805+ Class originated from: 13. Type: XIKeyClass
4806+ Keycodes supported: 248
4807+
4808
4809=== added directory 'checkbox-support/checkbox_support/parsers/tests/pactl_data'
4810=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt'
4811--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt 1970-01-01 00:00:00 +0000
4812+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-0.txt 2014-01-07 13:44:32 +0000
4813@@ -0,0 +1,33 @@
4814+Card #0
4815+ Name: alsa_card.pci-0000_02_00.1
4816+ Driver: module-alsa-card.c
4817+ Owner Module: 4
4818+ Properties:
4819+ alsa.card = "2"
4820+ alsa.card_name = "HDA NVidia"
4821+ alsa.long_card_name = "HDA NVidia at 0xfbdfc000 irq 34"
4822+ alsa.driver_name = "snd_hda_intel"
4823+ device.bus_path = "pci-0000:02:00.1"
4824+ sysfs.path = "/devices/pci0000:00/0000:00:03.0/0000:02:00.1/sound/card2"
4825+ device.bus = "pci"
4826+ device.vendor.id = "10de"
4827+ device.vendor.name = "NVIDIA Corporation"
4828+ device.string = "2"
4829+ device.description = "HDA NVidia"
4830+ module-udev-detect.discovered = "1"
4831+ device.icon_name = "audio-card-pci"
4832+ Profiles:
4833+ output:hdmi-stereo: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5400)
4834+ output:hdmi-surround: Wyjście Digital Surround 5.1 (HDMI) (sinks: 1, sources: 0, priority. 300)
4835+ output:hdmi-stereo-extra1: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5200)
4836+ output:hdmi-stereo-extra2: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5200)
4837+ output:hdmi-surround-extra2: Wyjście Digital Surround 5.1 (HDMI) (sinks: 1, sources: 0, priority. 100)
4838+ off: Wyłącz (sinks: 0, sources: 0, priority. 0)
4839+ Active Profile: output:hdmi-stereo-extra1
4840+ Ports:
4841+ hdmi-output-0: HDMI / DisplayPort (priority 5900)
4842+ Part of profile(s): output:hdmi-stereo, output:hdmi-surround
4843+ hdmi-output-1: HDMI / DisplayPort 2 (priority 5800)
4844+ Part of profile(s): output:hdmi-stereo-extra1
4845+ hdmi-output-2: HDMI / DisplayPort 3 (priority 5700)
4846+ Part of profile(s): output:hdmi-stereo-extra2, output:hdmi-surround-extra2
4847
4848=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt'
4849--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt 1970-01-01 00:00:00 +0000
4850+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-1.txt 2014-01-07 13:44:32 +0000
4851@@ -0,0 +1,51 @@
4852+Card #1
4853+ Name: alsa_card.pci-0000_00_1b.0
4854+ Driver: module-alsa-card.c
4855+ Owner Module: 5
4856+ Properties:
4857+ alsa.card = "0"
4858+ alsa.card_name = "HDA Intel"
4859+ alsa.long_card_name = "HDA Intel at 0xf9ff8000 irq 70"
4860+ alsa.driver_name = "snd_hda_intel"
4861+ device.bus_path = "pci-0000:00:1b.0"
4862+ sysfs.path = "/devices/pci0000:00/0000:00:1b.0/sound/card0"
4863+ device.bus = "pci"
4864+ device.vendor.id = "8086"
4865+ device.vendor.name = "Intel Corporation"
4866+ device.product.name = "82801JI (ICH10 Family) HD Audio Controller"
4867+ device.form_factor = "internal"
4868+ device.string = "0"
4869+ device.description = "Wbudowany dźwięk"
4870+ module-udev-detect.discovered = "1"
4871+ device.icon_name = "audio-card-pci"
4872+ Profiles:
4873+ output:analog-stereo: Wyjście Analogowe stereo (sinks: 1, sources: 0, priority. 6000)
4874+ output:analog-stereo+input:analog-stereo: Analogowy dupleks stereo (sinks: 1, sources: 1, priority. 6060)
4875+ output:analog-surround-40: Wyjście Analogowe surround 4.0 (sinks: 1, sources: 0, priority. 700)
4876+ output:analog-surround-40+input:analog-stereo: Wyjście Analogowe surround 4.0 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 760)
4877+ output:analog-surround-41: Wyjście Analogowe surround 4.1 (sinks: 1, sources: 0, priority. 800)
4878+ output:analog-surround-41+input:analog-stereo: Wyjście Analogowe surround 4.1 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 860)
4879+ output:analog-surround-50: Wyjście Analogowe surround 5.0 (sinks: 1, sources: 0, priority. 700)
4880+ output:analog-surround-50+input:analog-stereo: Wyjście Analogowe surround 5.0 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 760)
4881+ output:analog-surround-51: Wyjście Analogowe surround 5.1 (sinks: 1, sources: 0, priority. 800)
4882+ output:analog-surround-51+input:analog-stereo: Wyjście Analogowe surround 5.1 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 860)
4883+ output:analog-surround-71: Wyjście Analog Surround 7.1 (sinks: 1, sources: 0, priority. 700)
4884+ output:analog-surround-71+input:analog-stereo: Wyjście Analog Surround 7.1 + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 760)
4885+ output:iec958-stereo: Wyjście Cyfrowe stereo (IEC958) (sinks: 1, sources: 0, priority. 5500)
4886+ output:iec958-stereo+input:analog-stereo: Wyjście Cyfrowe stereo (IEC958) + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 5560)
4887+ input:analog-stereo: Wejście Analogowe stereo (sinks: 0, sources: 1, priority. 60)
4888+ off: Wyłącz (sinks: 0, sources: 0, priority. 0)
4889+ Active Profile: output:analog-stereo+input:analog-stereo
4890+ Ports:
4891+ analog-output: Wyjście analogowe (priority 9900)
4892+ 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
4893+ analog-output-headphones: Słuchawki (priority 9000)
4894+ Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo
4895+ analog-input-microphone-front: Przedni mikrofon (priority 8500)
4896+ 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
4897+ analog-input-microphone-rear: Tylny mikrofon (priority 8200)
4898+ 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
4899+ analog-input-linein: Wejście liniowe (priority 8100)
4900+ 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
4901+ iec958-stereo-output: Wyjście cyfrowe (S/PDIF) (priority 0)
4902+ Part of profile(s): output:iec958-stereo, output:iec958-stereo+input:analog-stereo
4903
4904=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt'
4905--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt 1970-01-01 00:00:00 +0000
4906+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise-2.txt 2014-01-07 13:44:32 +0000
4907@@ -0,0 +1,30 @@
4908+Card #2
4909+ Name: alsa_card.usb-046d_0825_0E3A8A10-02-U0x46d0x825
4910+ Driver: module-alsa-card.c
4911+ Owner Module: 6
4912+ Properties:
4913+ alsa.card = "1"
4914+ alsa.card_name = "USB Device 0x46d:0x825"
4915+ alsa.long_card_name = "USB Device 0x46d:0x825 at usb-0000:00:1d.7-1, high speed"
4916+ alsa.driver_name = "snd_usb_audio"
4917+ device.bus_path = "pci-0000:00:1d.7-usb-0:1:1.2"
4918+ sysfs.path = "/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.2/sound/card1"
4919+ udev.id = "usb-046d_0825_0E3A8A10-02-U0x46d0x825"
4920+ device.bus = "usb"
4921+ device.vendor.id = "046d"
4922+ device.vendor.name = "Logitech, Inc."
4923+ device.product.id = "0825"
4924+ device.product.name = "Webcam C270"
4925+ device.serial = "046d_0825_0E3A8A10"
4926+ device.form_factor = "webcam"
4927+ device.string = "1"
4928+ device.description = "Webcam C270"
4929+ module-udev-detect.discovered = "1"
4930+ device.icon_name = "camera-web-usb"
4931+ Profiles:
4932+ input:analog-mono: Wejście Analogowe mono (sinks: 0, sources: 1, priority. 1)
4933+ off: Wyłącz (sinks: 0, sources: 0, priority. 0)
4934+ Active Profile: input:analog-mono
4935+ Ports:
4936+ analog-input-microphone: Mikrofon (priority 8700)
4937+ Part of profile(s): input:analog-mono
4938
4939=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt'
4940--- checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt 1970-01-01 00:00:00 +0000
4941+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/cards-desktop-precise.txt 2014-01-07 13:44:32 +0000
4942@@ -0,0 +1,41 @@
4943+Card #0
4944+ Name: alsa_card.pci-0000_00_1b.0
4945+ Driver: module-alsa-card.c
4946+ Owner Module: 4
4947+ Properties:
4948+ alsa.card = "0"
4949+ alsa.card_name = "HDA Intel PCH"
4950+ alsa.long_card_name = "HDA Intel PCH at 0xe0610000 irq 46"
4951+ alsa.driver_name = "snd_hda_intel"
4952+ device.bus_path = "pci-0000:00:1b.0"
4953+ sysfs.path = "/devices/pci0000:00/0000:00:1b.0/sound/card0"
4954+ device.bus = "pci"
4955+ device.vendor.id = "8086"
4956+ device.vendor.name = "Intel Corporation"
4957+ device.product.name = "Panther Point High Definition Audio Controller"
4958+ device.form_factor = "internal"
4959+ device.string = "0"
4960+ device.description = "Wbudowany dźwięk"
4961+ module-udev-detect.discovered = "1"
4962+ device.icon_name = "audio-card-pci"
4963+ Profiles:
4964+ output:analog-stereo: Wyjście Analogowe stereo (sinks: 1, sources: 0, priority. 6000)
4965+ output:analog-stereo+input:analog-stereo: Analogowy dupleks stereo (sinks: 1, sources: 1, priority. 6060)
4966+ output:hdmi-stereo: Wyjście Digital Stereo (HDMI) (sinks: 1, sources: 0, priority. 5400)
4967+ output:hdmi-stereo+input:analog-stereo: Wyjście Digital Stereo (HDMI) + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 5460)
4968+ output:hdmi-surround: Wyjście Digital Surround 5.1 (HDMI) (sinks: 1, sources: 0, priority. 300)
4969+ output:hdmi-surround+input:analog-stereo: Wyjście Digital Surround 5.1 (HDMI) + Wejście Analogowe stereo (sinks: 1, sources: 1, priority. 360)
4970+ input:analog-stereo: Wejście Analogowe stereo (sinks: 0, sources: 1, priority. 60)
4971+ off: Wyłącz (sinks: 0, sources: 0, priority. 0)
4972+ Active Profile: output:analog-stereo+input:analog-stereo
4973+ Ports:
4974+ analog-output-speaker: Głośniki (priority 10000)
4975+ Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo
4976+ analog-output-headphones: Słuchawki (priority 9000)
4977+ Part of profile(s): output:analog-stereo, output:analog-stereo+input:analog-stereo
4978+ analog-input-microphone-internal: Wewnętrzny mikrofon (priority 8900)
4979+ 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
4980+ analog-input-microphone: Mikrofon (priority 8700)
4981+ 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
4982+ hdmi-output-0: HDMI / DisplayPort (priority 5900)
4983+ Part of profile(s): output:hdmi-stereo, output:hdmi-stereo+input:analog-stereo, output:hdmi-surround, output:hdmi-surround+input:analog-stereo
4984
4985=== added file 'checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt'
4986--- checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt 1970-01-01 00:00:00 +0000
4987+++ checkbox-support/checkbox_support/parsers/tests/pactl_data/desktop-precise-radeon-hdmi-available.txt 2014-01-07 13:44:32 +0000
4988@@ -0,0 +1,608 @@
4989+Module #0
4990+ Name: module-device-restore
4991+ Argument:
4992+ Usage counter: n/a
4993+ Properties:
4994+ module.author = "Lennart Poettering"
4995+ module.description = "Automatically restore the volume/mute state of devices"
4996+ module.version = "1.1"
4997+
4998+Module #1
4999+ Name: module-stream-restore
5000+ Argument:
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches