--- jockey-0.5~alpha1.orig/README.txt +++ jockey-0.5~alpha1/README.txt @@ -143,6 +143,8 @@ - PyQt4: http://www.riverbankcomputing.co.uk/pyqt/index.php + - PyKDE4 from the kdebindings KDE component + Trying it --------- --- jockey-0.5~alpha1.orig/AUTHORS +++ jockey-0.5~alpha1/AUTHORS @@ -8,3 +8,4 @@ Scott James Remnant -- original code for "restricted-manager" where Jockey evolved from Martin Böhm -- KDE 3 frontend Jonathan Thomas -- PyKDE4 port of KDE frontend +Alberto Milone -- PyKDE4 frontend (v. 0.5), X-Kit support, recommended driver selection --- jockey-0.5~alpha1.orig/MANIFEST.in +++ jockey-0.5~alpha1/MANIFEST.in @@ -0,0 +1,7 @@ +include README.txt AUTHORS COPYING ChangeLog po/*.po po/POTFILES.in +include tests/run* tests/*.py +recursive-include gtk *.desktop.in *.glade com.ubuntu.DeviceDriver.service +recursive-include kde *.desktop.in *.ui +recursive-include data * +recursive-include examples * +recursive-include backend * --- jockey-0.5~alpha1.orig/kde/jockey-kde +++ jockey-0.5~alpha1/kde/jockey-kde @@ -24,12 +24,8 @@ import jockey.ui from jockey.oslib import OSLib -# import UIs - now done via UI -# from kde.manager_window_ui import Ui_manager_window -#from kde.download_progress_ui import Ui_download_progress - from PyQt4.QtCore import * -from PyQt4.QtGui import QTreeWidgetItem +from PyQt4.QtGui import * from PyQt4 import uic # the following will be useful for hardy+1 @@ -37,42 +33,44 @@ from PyKDE4.kdecore import * from PyKDE4.kdeui import * +import re + class JockeyTreeWidgetItem(QTreeWidgetItem): '''A subclassed QTreeWidgetItem that can store its handler. A workaround for the Model/View framework which will be implemented later on. ''' - def __init__(self, parent, handler_id): + def __init__(self, handler_id, parent=None): + super(JockeyTreeWidgetItem, self).__init__(parent) self.handler_id = handler_id - QTreeWidgetItem.__init__(self, parent) class KDEUI(jockey.ui.AbstractUI): '''KDE user interface implementation.''' - - def convert_keybindings(self,str): - # does nothing yet - return str - + + keyb_trans_re = re.compile('(?%s' % info['name']) + self.mw.textview_description.setText(info['description']) + if info['certified'] == None: + self.mw.image_certification.hide() + elif info['certified']: + self.mw.image_certification.show() + + if os.path.exists('/usr/share/icons/hicolor/scalable/emblems/jockey-certified.svg'): + certified_icon = KIcon('jockey-certified.svg') + + self.mw.image_certification.setPixmap(certified_icon.pixmap(16,16)) + elif os.path.exists('data/icons/scalable/emblems/jockey-certified.svg'): + certified_icon = QIcon('data/icons/scalable/emblems/jockey-certified.svg') + + self.mw.image_certification.setPixmap(certified_icon.pixmap(16,16)) + else: + self.mw.image_certification.show() + + warning_icon = KIcon('dialog-warning') + self.mw.image_certification.setPixmap(warning_icon.pixmap(16,16)) + + self.mw.label_certification.setText(info['certification_label']) + + if info['free'] == None: + self.mw.image_license.hide() + self.mw.label_license_label.hide() + elif info['free']: + self.mw.image_license.show() + self.mw.label_license_label.show() + # TODO: better icon + self.mw.image_license.setPixmap(KIcon('dialog-ok-apply').pixmap(16,16)) + else: + self.mw.image_license.show() + self.mw.label_license_label.show() + + if os.path.exists('data/icons/scalable/emblems/jockey-proprietary.svg'): + proprietary_icon = QIcon('data/icons/scalable/emblems/jockey-proprietary.svg') + self.mw.image_license.setPixmap(proprietary_icon.pixmap(16,16)) + + self.mw.label_license.setText(info['license_label']) + + if info['license_text']: + self.mw.linkbutton_licensetext.show() + self.mw.current_license_text = info['license_text'] + else: + self.mw.linkbutton_licensetext.hide() + self.mw.current_license_text = None + if info['enabled'] == None: + self.mw.image_enabled.hide() + elif info['enabled']: + self.mw.image_enabled.show() + self.mw.image_enabled.setPixmap(KIcon('dialog-ok-apply').pixmap(16,16)) + else: + self.mw.image_enabled.show() + self.mw.image_enabled.setPixmap(KIcon('dialog-error').pixmap(16,16)) + self.mw.label_status.setText(info['status_label']) + + if not info['button_toggle_label']: + self.mw.button_toggle.setEnabled(False) + else: + self.mw.button_toggle.setEnabled(True) + self.mw.button_toggle.setText(info['button_toggle_label']) + if info['enabled']: + icon = KIcon('dialog-error')#STOCK_STOP + self.mw.button_toggle.setIcon(icon) + else: + icon = KIcon('dialog-ok-apply')#STOCK_APPLY + self.mw.button_toggle.setIcon(icon) + appName = "jockey" catalog = "" programName = ki18n ("Jockey") @@ -372,7 +446,7 @@ aboutData = KAboutData(appName, catalog, programName, version, description, license, copyright, text, homePage) aboutData.addAuthor(ki18n("Jonathan Thomas"), ki18n("Work on PyQt4 to PyKDE4 port")) - +aboutData.addAuthor(ki18n("Alberto Milone"), ki18n("Work on PyQt4 to PyKDE4 port")) if __name__ == '__main__': # We need a copy of sys.argv for ui.py to use --- jockey-0.5~alpha1.orig/kde/ManagerWindowKDE4.ui +++ jockey-0.5~alpha1/kde/ManagerWindowKDE4.ui @@ -5,8 +5,8 @@ 0 0 - 569 - 524 + 404 + 404 @@ -15,9 +15,9 @@ false - - - + + + @@ -63,53 +63,246 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + - + 20 + + false + + + false + + + true + + + 1 + Name - - - Description - - - - - Enabled - - - <b>Drivers</b> - - - - - - + Driver - + + + + + + + + + + 0 + 0 + + - Special + driver name + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + + + + true + + + + + + + (certification status) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + true + + + + + + + License: + + + + + + + (license) + + + + + + + (details) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + - + + true + + - + + + + (status) + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + (Action) + + + + - + Qt::Horizontal @@ -123,6 +316,13 @@ qPixmapFromMimeSource + + + KUrlLabel + QLabel +
kurllabel.h
+
+
klistview.h --- jockey-0.5~alpha1.orig/jockey/xorg_driver.py +++ jockey-0.5~alpha1/jockey/xorg_driver.py @@ -140,6 +140,10 @@ return self._mod_status(module, 'Disable') def enable(self): + if not self.xorg_conf: + logging.error('XorgDriverHandler.enable(): invalid xorg.conf, skipping') + return False + KernelModuleHandler.enable(self) # do not mangle xorg.conf if package installation has been aborted @@ -209,6 +213,10 @@ return False def disable(self): + if not self.xorg_conf: + logging.error('XorgDriverHandler.enable(): invalid xorg.conf, skipping') + return False + KernelModuleHandler.disable(self) # do not mangle xorg.conf if package uninstallation has been aborted --- jockey-0.5~alpha1.orig/jockey/ui.py +++ jockey-0.5~alpha1/jockey/ui.py @@ -20,7 +20,7 @@ functions with an appropriate toolkit. ''' -import gettext, optparse, textwrap, urllib2, tempfile, sys, time, os +import gettext, optparse, textwrap, urllib2, tempfile, sys, time, os, threading import gobject import dbus @@ -63,6 +63,8 @@ self.dbus_server_main_loop = None + self.have_ui = False + def backend(self): '''Return D-BUS backend client interface. @@ -70,6 +72,7 @@ ''' if self._dbus_iface is None: self._dbus_iface = Backend.create_dbus_client() + self.detect() else: # handle backend timeouts try: @@ -184,49 +187,6 @@ else: return self._('Device driver') - # TODO: get rid of this function after updating the KDE interface - def get_handler_tooltip(self, handler_id): - '''Format handler rationale as a tooltip. - - Return None if the handler is None or does not have a rationale. - ''' - try: - info = polkit_auth_wrapper(self.backend().handler_info, handler_id) - except UnknownHandlerException: - return None - try: - r = info['rationale'] - except KeyError: - # generate default rationale for some driver types - if handler_id.startswith('firmware:'): - fw_append = self._('Your hardware will not work without the firmware.') - if bool(info['free']): - r = self._('The driver itself is already installed, but ' - 'it requires a piece of firmware which is not shipped ' - 'with the operating system.') + ' ' + fw_append - else: - r = self._('While this driver itself is free software, it ' - 'relies on proprietary firmware which cannot be ' - 'legally shipped with the operating system.') + ' ' + fw_append - else: - if not bool(info['free']): - r = self._('This driver is necessary to support the ' - 'hardware, there is no free/open alternative.\n\n' - 'If this driver is not enabled, the hardware will not ' - 'function.') - else: - return None - - # opportunistic translation (shipped example drivers have translations) - r = self._(r) - - tip = '' - for par in r.split('\n'): - if tip: - tip += '\n' - tip += '\n'.join(textwrap.wrap(par, 60)) - return tip - def get_ui_driver_name(self, handler_info): '''Return handler name, as it should be presented in the UI. @@ -251,8 +211,6 @@ empty), enabled (bool, for icon), used (bool), status_label (label string), button_toggle_label (string)''' - # TODO: respect can_change - if not handler_id: return { 'name': '', 'description': '', 'free': None, 'enabled': None, 'used': None, 'license_text': '', @@ -374,9 +332,15 @@ elif self.argv_options.dbus_server: self.dbus_server() return 0 + elif self.argv_options.check is not None: + if self.check(): + return 0 + else: + return 1 # all other modes involve the GUI, so load it self.ui_init() + self.have_ui = True if self.argv_options.enable: if self.set_handler_enable(self.argv_options.enable, 'enable', @@ -390,11 +354,6 @@ return 0 else: return 1 - elif self.argv_options.check is not None: - if self.check(): - return 0 - else: - return 1 elif self.argv_options.check_composite: if self.check_composite(): return 0 @@ -427,7 +386,6 @@ Return True if any new driver is available which is not yet enabled. ''' - try: (new_used, new_avail) = polkit_auth_wrapper( self.backend().new_used_available, self.argv_options.mode) @@ -450,6 +408,12 @@ notified = False # launch notifications if anything remains + if new_avail or new_used: + # defer UI initialization until here, since --check should not + # spawn a progress dialog for searching drivers + self.ui_init() + self.have_ui = True + if new_avail: if restricted_available: self.ui_notification(self._('Restricted drivers available'), @@ -554,10 +518,10 @@ if confirm: # construct and ask confirmation question if enable: - title = self._('Disable driver?') - action = self.string_button_disable - else: title = self._('Enable driver?') + action = self.string_button_enable + else: + title = self._('Disable driver?') action = self.string_button_disable if not self.confirm_action(title, self._(i['name']), self._get_description_rationale_text(i), action): @@ -664,6 +628,28 @@ except IOError: pass + def detect(self): + '''Call backend().detect() and show a progress dialog.''' + + if not self.have_ui: + self.backend().detect() + return + + self.ui_progress_start('', self._( + 'Searching for available drivers...'), -1) + t_detect = threading.Thread(None, self.backend().detect, + 'thread_detect', (), {'timeout': 600}) + t_detect.start() + while True: + t_detect.join(0.2) + if not t_detect.isAlive(): + break + if self.ui_progress_update(-1, -1): + sys.exit(1) # cancel + self.ui_idle() + self.ui_progress_finish() + self.ui_idle() + # # Session D-BUS server methods # @@ -703,11 +689,12 @@ offers it to the user. This returns True if a driver was found, acknowledged by the user, and installed, otherwise it returns False. ''' + self.ui_init() # we want to show progress + self.have_ui = True drivers = self.backend().search_driver(hwid) result = False if drivers: - self.ui_init() self.set_handler_enable(drivers[0], 'enable', True) result = bool(self.backend().handler_info(drivers[0])['enabled']) --- jockey-0.5~alpha1.orig/jockey/backend.py +++ jockey-0.5~alpha1/jockey/backend.py @@ -133,17 +133,16 @@ ''' DBUS_INTERFACE_NAME = 'com.ubuntu.DeviceDriver' - def __init__(self, handler_dir=None): - '''Initialize system. - - This detects available hardware and already installed drivers and - handlers. + def __init__(self, handler_dir=None, detect=True): + '''Initialize backend (no hardware/driver detection). + + In order to be fast and not block client side applications for very + long, detect can be set to False; in that case this constructor does + not detect hardware and drivers, and client-side applications must call + detect() at program start. ''' self.handler_dir = handler_dir - self.hardware = detection.get_hardware() - - self.driver_dbs = [detection.LocalKernelModulesDriverDB()] - self._detect_handlers() + self.hardware = None self.timeout = None @@ -153,11 +152,35 @@ self.enforce_polkit = True + if detect: + self.detect() + # # Client API (through D-BUS) # @dbus.service.method(DBUS_INTERFACE_NAME, + in_signature='', out_signature='', sender_keyword='sender', + connection_keyword='conn') + def detect(self, sender=None, conn=None): + '''Detect available hardware and handlers. + + This method can take pretty long, so it should be called asynchronously + with a large (or indefinite) timeout, and client UIs should display a + bouncing progress bar (if appropriate). If the backend is already + initialized, this returns immediately. + + This must be called once at client-side program start. + ''' + self._reset_timeout() + self._check_polkit_privilege(sender, conn, 'com.ubuntu.devicedriver.info') + + if not self.hardware: + self.hardware = detection.get_hardware() + self.driver_dbs = [detection.LocalKernelModulesDriverDB()] + self._detect_handlers() + + @dbus.service.method(DBUS_INTERFACE_NAME, in_signature='s', out_signature='as', sender_keyword='sender', connection_keyword='conn') def available(self, mode='any', sender=None, conn=None): @@ -505,11 +528,14 @@ '''Return a D-BUS server backend instance. Normally this connects to the system bus. Set session_bus to True to - connect to the session bus (for testing). + connect to the session bus (for testing). + + The created backend does not yet have hardware and drivers detected, + thus clients need to call detect(). ''' import dbus.mainloop.glib - backend = Backend(handler_dir) + backend = Backend(handler_dir, detect=False) dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) if session_bus: backend.bus = dbus.SessionBus() --- jockey-0.5~alpha1.orig/jockey/oslib.py +++ jockey-0.5~alpha1/jockey/oslib.py @@ -17,9 +17,13 @@ '''Encapsulate operations which are Linux distribution specific.''' -import fcntl, os, subprocess, sys, logging, re +import fcntl, os, subprocess, sys, logging, re, time from glob import glob +import warnings +warnings.simplefilter('ignore', FutureWarning) +import apt + class OSLib: '''Encapsulation of operating system/Linux distribution specific operations.''' @@ -81,47 +85,81 @@ self._load_module_blacklist() + self.apt_show_cache = {} + self.apt_sources = '/etc/apt/sources.list' + self.apt_jockey_source = '/etc/apt/sources.list.d/jockey.list' + # # The following package related functions use PackageKit; if that does not # work for your distribution, they must be reimplemented # + def _apt_show(self, package): + '''Return apt-cache show output, with caching. + + Return None if the package does not exist. + ''' + try: + return self.apt_show_cache[package] + except KeyError: + apt = subprocess.Popen(['apt-cache', 'show', package], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out = apt.communicate()[0].strip() + if apt.returncode == 0 and out: + result = out + else: + result = None + self.apt_show_cache[package] = result + return result + def is_package_free(self, package): '''Return if given package is free software.''' - pkcon = subprocess.Popen(['pkcon', 'get-details', package], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out = pkcon.communicate()[0] - m = re.search("^\s*license:\s*'(.*)'$", out, re.M) - if m: - # TODO: check more licenses here - return m.group(1).lower() in ('free', 'gpl', 'gplv2', 'gplv3', - 'bsd', 'mpl') - else: - raise ValueError, 'package %s does not exist' % package + # TODO: this only works for packages in the official archive + out = self._apt_show(package) + if out: + for l in out.splitlines(): + if l.startswith('Section:'): + s = l.split()[-1] + return not (s.startswith('restricted') or s.startswith('multiverse')) + + raise ValueError, 'package %s does not exist' % package def package_installed(self, package): '''Return if the given package is installed.''' - pkcon = subprocess.Popen(['pkcon', 'resolve', package], + dpkg = subprocess.Popen(["dpkg-query", "-W", "-f${Status}", package], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out = pkcon.communicate()[0] - return pkcon.returncode == 0 and '\ninstalled ' in out + out = dpkg.communicate()[0] + return dpkg.returncode == 0 and out.split()[-1] == "installed" def package_description(self, package): '''Return a tuple (short_description, long_description) for a package. This should raise a ValueError if the package is not available. ''' - pkcon = subprocess.Popen(['pkcon', 'get-details', package], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out = pkcon.communicate()[0] - m = re.search("^\s*description:\s*'(.*?)'$", out, re.M | re.S) - if m: - # TODO: short description (not accessible with pkcon) - return (package, m.group(1)) - else: - raise ValueError, 'package %s does not exist' % package + out = self._apt_show(package) + if out: + lines = out.splitlines() + start = 0 + while start < len(lines)-1: + if lines[start].startswith('Description:'): + break + start += 1 + + short = lines[start].split(' ', 1)[1] + long = '' + for l in lines[start+1:]: + if l == ' .': + long += '\n' + elif l.startswith(' '): + long += l.lstrip() + '\n' + else: + break + + return (short, long) + + raise ValueError, 'package %s does not exist' % package # # The following functions MUST be implemented by distributors @@ -140,7 +178,44 @@ If this succeeds, subsequent package_installed(package) calls must return True. ''' - raise NotImplementedError, 'subclasses need to implement this' + class MyFetchProgress(apt.FetchProgress): + def __init__(self, callback): + apt.FetchProgress.__init__(self) + self.callback = callback + + def pulse(self): + return not self.callback('download', int(self.percent/2+.5), 100) + + class MyInstallProgress(apt.InstallProgress): + def __init__(self, callback): + apt.InstallProgress.__init__(self) + self.callback = callback + + def statusChange(self, pkg, percent, status): + logging.debug('install progress statusChange %s %f' % (pkg, percent)) + self.callback('install', int(percent/2+50.5), 100) + + logging.debug('Installing package: %s', package) + if progress_cb: + progress_cb('download', 0, 100.0) + + os.environ['DEBIAN_FRONTEND'] = 'noninteractive' + os.environ['PATH'] = '/sbin:/usr/sbin:/bin:/usr/bin' + + c = apt.Cache() + try: + c[package].markInstall() + except KeyError: + logging.debug('Package %s does not exist, aborting', package) + return False + try: + c.commit(progress_cb and MyFetchProgress(progress_cb) or None, + progress_cb and MyInstallProgress(progress_cb) or None) + except (apt.cache.FetchCancelledException, + apt.cache.LockFailedException, apt.cache.FetchFailedException), e: + logging.debug('Package fetching failed: %s', str(e)) + return False + return True def remove_package(self, package, progress_cb): '''Uninstall the given package. @@ -153,7 +228,33 @@ If this succeeds, subsequent package_installed(package) calls must return False. ''' - raise NotImplementedError, 'subclasses need to implement this' + os.environ['DEBIAN_FRONTEND'] = 'noninteractive' + os.environ['PATH'] = '/sbin:/usr/sbin:/bin:/usr/bin' + + class MyInstallProgress(apt.InstallProgress): + def __init__(self, callback): + apt.InstallProgress.__init__(self) + self.callback = callback + + def statusChange(self, pkg, percent, status): + logging.debug('remove progress statusChange %s %f' % (pkg, percent)) + self.callback(percent, 100.0) + + logging.debug('Removing package: %s', package) + + c = apt.Cache() + try: + c[package].markDelete() + except KeyError: + logging.debug('Package %s does not exist, aborting', package) + return False + try: + c.commit(None, progress_cb and MyInstallProgress(progress_cb) or None) + except apt.cache.LockFailedException: + logging.debug('could not lock apt cache, aborting') + return False + + return True def packaging_system(self): '''Return packaging system. @@ -176,19 +277,63 @@ This should throw a ValueError if the repository is invalid or inaccessible. ''' - raise NotImplementedError, 'subclasses need to implement this' + if self.repository_enabled(repository): + logging.debug('add_repository(%s): already active', repository) + return + + if os.path.exists(self.apt_jockey_source): + backup = self.apt_jockey_source + '.bak' + os.rename(self.apt_jockey_source, backup) + else: + backup = None + f = open(self.apt_jockey_source, 'w') + print >> f, repository.strip() + f.close() + + try: + # TODO: progress feedback + c = apt.Cache() + c.update() + except SystemError, e: + logging.error('add_repository(%s): Invalid repository', repository) + if backup: + os.rename(backup, self.apt_jockey_source) + else: + os.unlink(self.apt_jockey_source) + raise ValueError(e.message) def remove_repository(self, repository): '''Remove a repository. The format for repository is distribution specific. ''' - raise NotImplementedError, 'subclasses need to implement this' + if not os.path.exists(self.apt_jockey_source): + return + result = [] + for line in open(self.apt_jockey_source): + if line.strip() != repository: + result.append(line) + if result: + f = open(self.apt_jockey_source, 'w') + f.write('\n'.join(result)) + f.close() + else: + os.unlink(self.apt_jockey_source) def repository_enabled(self, repository): '''Check if given repository is enabled.''' - raise NotImplementedError, 'subclasses need to implement this' + for f in [self.apt_sources] + glob(self.apt_sources + '.d/*.list'): + try: + logging.debug('repository_enabled(%s): checking %s', repository, f) + for line in open(f): + if line.strip() == repository: + logging.debug('repository_enabled(%s): match', repository) + return True + except IOError: + pass + logging.debug('repository_enabled(%s): no match', repository) + return False def ui_help_available(self, ui): '''Return if help is available. @@ -196,7 +341,7 @@ This gets the current UI object passed, which can be used to determine whether GTK/KDE is used, etc. ''' - return False + return os.access('/usr/bin/yelp', os.X_OK) def ui_help(self, ui): '''The UI's help button was clicked. @@ -205,7 +350,10 @@ appropriate topic, etc. This gets the current UI object passed, which can be used to determine whether GTK/KDE is used, etc. ''' - pass + if 'gtk' in str(ui.__class__).lower(): + import gobject + gobject.spawn_async(["yelp", "ghelp:hardware#restricted-manager"], + flags=gobject.SPAWN_SEARCH_PATH) # # The following functions have a reasonable default implementation for @@ -233,7 +381,26 @@ Note that modules which are ignored here, but covered by a custom handler will still be considered. ''' - return set() + # try to get a *.ko file list from the main kernel package to avoid testing + # known-free drivers + dpkg = subprocess.Popen(['dpkg', '-L', 'linux-image-' + os.uname()[2]], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out = dpkg.communicate()[0] + result = set() + if dpkg.returncode == 0: + for l in out.splitlines(): + if l.endswith('.ko'): + result.add(os.path.splitext(os.path.basename(l))[0].replace('-', '_')) + + dpkg = subprocess.Popen(['dpkg', '-L', 'linux-ubuntu-modules-' + os.uname()[2]], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out = dpkg.communicate()[0] + if dpkg.returncode == 0: + for l in out.splitlines(): + if l.endswith('.ko'): + result.add(os.path.splitext(os.path.basename(l))[0].replace('-', '_')) + + return result def module_blacklisted(self, module): '''Check if a module is on the modprobe blacklist.''' @@ -303,6 +470,11 @@ return os.umask(022) + # create directory if it does not exist + d = os.path.dirname(self.module_blacklist_file) + if not os.path.exists(d): + os.makedirs(d) + f = open(self.module_blacklist_file, 'w') try: fcntl.flock(f.fileno(), fcntl.LOCK_EX) --- jockey-0.5~alpha1.orig/jockey/detection.py +++ jockey-0.5~alpha1/jockey/detection.py @@ -602,8 +602,14 @@ logging.warning('cups and/or cupshelpers Python modules are not present; printer detection is not available') return set() + try: + cups_dev = cupshelpers.getDevices(cups.Connection()) + except (RuntimeError, cups.IPPError): + logging.warning('cannot connect to cups; printer detection is not available') + return set() + result = set() - for dev in cupshelpers.getDevices(cups.Connection()).itervalues(): + for dev in cups_dev.itervalues(): # openprinting.org database only uses MFG, MDL, DES, and CMD, so don't # send the rest (it might contain personal data such as serial numbers) if dev.id_dict.get('MFG') and dev.id_dict.get('MDL'): --- jockey-0.5~alpha1.orig/debian/jockey-common.dirs +++ jockey-0.5~alpha1/debian/jockey-common.dirs @@ -0,0 +1 @@ +/var/cache/jockey --- jockey-0.5~alpha1.orig/debian/jockey-gtk.install +++ jockey-0.5~alpha1/debian/jockey-gtk.install @@ -0,0 +1,5 @@ +usr/bin/*-gtk +usr/share/jockey/*.glade +usr/share/applications/*-gtk.* +usr/share/autostart/*-gtk.desktop etc/xdg/autostart/ +usr/share/dbus-1/services --- jockey-0.5~alpha1.orig/debian/jockey-common.install +++ jockey-0.5~alpha1/debian/jockey-common.install @@ -0,0 +1,9 @@ +usr/lib/python* +usr/share/icons +usr/share/locale +usr/share/jockey/modaliases +usr/share/jockey/handlers +etc/dbus-1/system.d/ +usr/share/dbus-1/system-services +usr/share/PolicyKit/policy +usr/share/jockey/jockey-backend --- jockey-0.5~alpha1.orig/debian/changelog +++ jockey-0.5~alpha1/debian/changelog @@ -0,0 +1,417 @@ +jockey (0.5~alpha1-0ubuntu2) intrepid; urgency=low + + * debian/control: Replace python-qt4 dependency with python-kde4, since + that's required now. (LP: #263017) + * oslib.py, {install,remove}_package(): Intercept apt's LockFailedException + and FetchFailedException. (LP: #268850) + * oslib.py: Fix typo causing crash in remove_repository(), add test cases. + (LP: #269435) + * Merge some bug fixes from trunk: + - Update KDE UI according to recent GTK ui changes. (LP #268163) + - ui.py, set_handler_enable(): Fix reversed logic in determining + enable/disable strings. (LP: #269444) + - fglrx.py: Fix crash if Device section does not configure a driver + (LP: #269565) + - Test suite: check handler behaviour with invalid xorg.conf, fix a few + crashes uncovered by that. (LP: #258064) + - detection.py: Fix crashes if cupsd is not running. (LP: #256780, #255488) + - jockey-gtk: Call gtk.init_check() to test $DISPLAY, and print error + message instead of crashing. (LP: #234252) + - oslib.py, _save_module_blacklist(): Create modules.d directory if it + does not exist. (LP: #229065) + - jockey-gtk: Add license text dialog and link it to the license button + (LP: #269352) + - com.ubuntu.devicedriver.policy.in: Allow non-local driver install + (auth_admin). (LP: #269175) + - Move hardware detection from Backend ctor to separate function, and call + that with long D-BUS timeout and progress dialog. (LP: #253224) + - Various fixes in test suite. + + -- Martin Pitt Tue, 16 Sep 2008 08:10:35 -0700 + +jockey (0.5~alpha1-0ubuntu1) intrepid; urgency=low + + * New upstream release, Alpha 1 of upcoming 0.5: + - GTK user interface shows support and license status of a driver now. + (jockey-printer-driver-support blueprint). + - Refurbished workflow and look of the GTK user interface according to + Matthew Paul Thomas' recommendations. (LP: #268163) Corresponding + changes to the KDE UI are in the works, and will be merged soon. + - Uses X-Kit instead of guidance-backends now, update dependency. + (LP: #269057) + - Fix a few regressions of the PyKDE 4 port. + - Add support for recommended driver versions in the case of multiple + different available versions (such as with the Nvidia driver). + + -- Martin Pitt Fri, 12 Sep 2008 11:57:48 +0200 + +jockey (0.4.1+r360-0ubuntu1) intrepid; urgency=low + + * New upstream snapshot: + - Port KDE frontend to PyKDE, by Jonathan Thomas + + -- Jonathan Riddell Tue, 26 Aug 2008 16:57:30 +0100 + +jockey (0.4+r354-0ubuntu1) intrepid; urgency=low + + * New upstream snapshot: + - Add session D-BUS interface for jockey-gtk, so that programs like + system-config-printer can use the "search_driver" API to request a + driver for a particular hardware component with getting GUI. + - Full backend integration of OpenPrinting.org driver search. + - Various bug fixes. + * jockey/oslib.py: Use python-apt instead of calling apt-get, to get numeric + progress reporting instead of just pulsating. + * Add python-apt dependency, Ubuntu oslib.py uses it now. + * Bump Standards-Version (no changes). + * Bump debhelper build dependency version for dh_icons, thanks lintian. + * jockey/oslib.py: Provide an apt implementation for + {add,remove}_repository() and repository_enabled(). + * backend/jockey-backend: Enable the OpenPrinting.org driver lookup by + default, so that we can test it in intrepid. There is no UI to point out + that these are community provided drivers, this will be done in a later + release. + + -- Martin Pitt Fri, 15 Aug 2008 18:21:08 +0200 + +jockey (0.4+r345-0ubuntu1) intrepid; urgency=low + + * Use upstream snapshot as orig.tar.gz, so that file executable permissions + do not get lost when they are shipped in the diff.gz. This caused the + backend to be installed non-executable. (LP: #251347) + + -- Martin Pitt Thu, 24 Jul 2008 14:24:24 +0200 + +jockey (0.4-0ubuntu2) intrepid; urgency=low + + * jockey/oslib.py, {install,remove}_package(): Explicitly set $PATH, so that + apt-get and dpkg have a chance of working when being called from a D-BUS + spawned process (whose environment has virtually nothing at all). + + -- Martin Pitt Wed, 23 Jul 2008 23:41:14 +0200 + +jockey (0.4-0ubuntu1) intrepid; urgency=low + + * New upstream release 0.4: + - Implements an XML-RPC client for querying a driver database, as + specified on this year's LinuxFoundation Collaboration Summit. There is + no server implementation for this yet, though. + - Add general support for third-party repositories and packages not yet + known to the local system. In the course of this, the functionality of + DriverPackageHandler became merged into the generic Handler class, and + ModulePackageHandler became obsolete (KernelModuleHandler now does all + of this). This made the code a bit shorter and easier, too. + - Add support for python-coverage in the test suite, and add a lot of + missing tests. + - Lots of bug fixes. + * Update to current trunk bzr head: + - Split into privileged D-BUS backend and unprivileged frontends, control + access with PolicyKit. This gets rid of the nasty "gksu/kdesu myself" + code, and makes the service more useful for other desktop applications + which look for drivers. + - Support fourth field in modalias files for specifying a package name (as + done by nvidia-XX-modaliases packages). + - Update NVidia handler to get along with the multiple-versions packages + in Intrepid. + * debian/jockey-common.install: Install D-BUS and PolicyKit configuration + files, and jockey-backend program. + * data/handlers/b43.py: Update to new upstream infrastructure. + * jockey/oslib.py: Reimplement {install,remove}_package() using simple + apt-get calls, with no precise progress information. This is a + quick'n'dirty hack for Intrepid Alpha-3, so that the user at least gets + some kind of visual feedback on package installation. This will be cleaned + up later. + * debian/control: Add python-dbus, policykit dependencies to -common, and + policykit-gnome dependency to -gtk. + * debian/control: Recommend nvidia-common to provide out-of-the-box + detection of nvidia cards, and their matching driver. + + -- Martin Pitt Wed, 23 Jul 2008 16:38:17 +0200 + +jockey (0.3.3-0ubuntu10) intrepid; urgency=low + + * Drop Recommends: of linux-restricted-modules. They transitively pull in + lilo into ubuntu-desktop, and with the split-out fglrx and nvidia drivers + they do not even make sense any more. + + -- Martin Pitt Mon, 14 Jul 2008 09:54:22 +0100 + +jockey (0.3.3-0ubuntu9) intrepid; urgency=low + + * Upload fixes from hardy-proposed to intrepid. + + -- Martin Pitt Mon, 05 May 2008 20:49:10 +0200 + +jockey (0.3.3-0ubuntu8) hardy-proposed; urgency=low + + * fglrx.py: Do not override already installed third-party fglrx driver with + --check-composite. (LP: #221968) + * debian/control: Updated Vcs-Bzr: to point to the hardy branch. + * XorgDriverHandler, nvidia, fglrx: Set identifiers for newly created + sections, they are invalid without one. Thanks to Laszlo Pandy! + (LP: #218478) + * nvidia.py: Fix "enabled" handling: check if the package is installed and + module not blacklisted. (LP: #216650) + * OSLib.open_app(): Wait until the subprocess returned, so that we can check + the system state afterwards. (prerequisite for change below) + * jockey/ui.py, --check-composite: Re-check the system after attempting to + enable the driver, and only signal success (exit with 0) if the driver was + actually enabled. Otherwise, cancelling installation would invalidly + signal success to the caller. (LP: #208026) + + -- Martin Pitt Mon, 28 Apr 2008 19:24:11 +0200 + +jockey (0.3.3-0ubuntu7) hardy; urgency=low + + * Cherrypick a few bug fixes from trunk: + - nvidia.py: Drop AddARGBVisuals and AddARGBGLXVisuals options from legacy + driver. (LP: #211752) + - fglrx.py: Fix detection of autodetected radeon driver. (LP: #207957) + - jockey/ui.py: Intercept IOErrors when writing to stderr. (LP: #204120) + + -- Martin Pitt Tue, 08 Apr 2008 19:34:23 -0500 + +jockey (0.3.3-0ubuntu6) hardy; urgency=low + + * Cherrypick a few bug fixes from trunk: + - nvidia.py: Fix extra screen options to get quoted properly. + (LP: #211368) + - autostart .desktop files: Add Comment field. (LP: #146918) + - POTFILES.in: Add missing desktop files. + + -- Martin Pitt Sun, 06 Apr 2008 11:24:00 -0600 + +jockey (0.3.3-0ubuntu5) hardy; urgency=low + + * jockey/oslib.py: Fix undeclared 'env' variable, residue from fix in + 0.3.3-0ubuntu3. (LP: #189611) + + -- Martin Pitt Fri, 04 Apr 2008 09:16:08 +0200 + +jockey (0.3.3-0ubuntu4) hardy; urgency=low + + * debian/jockey-common.postinst: Remove old restricted-manager autostart XDG + file on upgrades. + + -- Martin Pitt Thu, 03 Apr 2008 18:07:22 +0200 + +jockey (0.3.3-0ubuntu3) hardy; urgency=low + + * jockey/oslib.py: Do not set debconf priority to critical any more. + b43-fwcutter needs the "download firmware" question shown in order to + actually download the firmware, and we do not need it ATM for other + packages. (LP: #197819) + + -- Martin Pitt Thu, 03 Apr 2008 14:49:12 +0200 + +jockey (0.3.3-0ubuntu2) hardy; urgency=low + + * Merge to upstream trunk to pick up a few bug fixes: + - nvidia.py: Add AddARGBGLXVisuals option to Screen section for + nvidia-glx. (LP: #154596) + - nvidia.py: Do not advertise as enabling composite if driver is already + loaded (i. e. installed manually). (LP: #202802) + - fglrx.py: Do not suggest installing fglrx if using the radeon X.org + driver, since that already supports composite (LP: #207957) + - jockey/ui.py: Change --update-db to print an error message instead of + exception (LP: #209594) + - If rebinding a module fails, trigger reboot notification. (LP: #207928) + + -- Martin Pitt Tue, 01 Apr 2008 20:40:50 +0200 + +jockey (0.3.3-0ubuntu1) hardy; urgency=low + + * New upstream bug fix release: + - jockey/xorg_driver.py: Check if _row attribute is present, which is not + the case for Subsections in the "Module" section. (LP: #201160) + - Make --check-composite ask for confirmation. (LP: #202898) + - Enable AddARGBGLXVisuals option for standard nvidia driver. + (LP: #154596) + - KDE: Do not change check boxes if enabling was cancelled. + - KDE: Drop unicode() conversion in confirm_action(), strings are already + unicode (LP: #206169) + - KDE: Disable help button if help is not available. (LP #206169) + + -- Martin Pitt Thu, 27 Mar 2008 12:41:53 +0100 + +jockey (0.3.2-0ubuntu3) hardy; urgency=low + + * Cherrypick some bug fixes from trunk: + - Add automatic testing for all shipped custom handlers in examples/ and + data/handlers/. So far the test suite only covered the standard + handlers. + - This uncovered that the fglrx and nvidia handlers still crash if + xorg.conf does not have a Screen section; fixed for real now. + (LP: #200832) + * data/handlers/b43.py: Add missing import (also uncovered by above test + suite). (LP: #203958) + + -- Martin Pitt Thu, 20 Mar 2008 16:30:32 +0100 + +jockey (0.3.2-0ubuntu2) hardy; urgency=low + + * Final 0.3.2 release (previous Ubuntu upload had a botched version number) + with bug fixes only (no new features). This time also with orig.tar.gz + again. + - fglrx, nvidia handlers: Create screen section if it does not exist. + (LP: #200832) + - Abort gracefully with a proper error message if cache directory does not + exist. (LP: #198433) + - ui.py, check(): Intercept ValueError from package query. This can happen + if the daily apt cron job runs while jockey is running as well and + temporarily causes inconsistent package indexes. (LP: #200089) + - kde/jockey-kde, comfirm_action(): Fix string formatting. (LP: #197777) + - jockey/oslib.py: Fix calling of kdesu. + - kde/jockey-kde: Make --check notifications actually work (LP: #193985) + - Fix the KDE interface test suite. + * debian/rules: Fix apport hook file name. + * debian/apport_hook.py: Add missing import. + * data/handlers/b43.py: Consider driver enabled if firmware files are + installed; testing whether b43-fwcutter is installed (the default + behaviour of ModulePackageHandler) is incorrect here. (LP: #198341) + + -- Martin Pitt Tue, 18 Mar 2008 17:28:32 +0100 + +jockey (0.3.2-0ubuntu1) hardy; urgency=low + + * New upstream bug fix release for KDE frontend changes: + - Add Oxygen icon + - Resize columns to text + - Nodes expanded by default + + -- Ryan Kavanagh Thu, 13 Mar 2008 19:26:16 +0000 + +jockey (0.3.1-0ubuntu1) hardy; urgency=low + + * New upstream bug fix release: + - Fix 'used' detection of nVidia driver. + - Add README.txt. + - Create default xorg.conf if it does not exist. + - More efficient modalias data structures for great detection stage + speedup (typically from > 5 to about 1 second). + - Run --check with niceness 10 and change autostart desktop files to delay + it by a minute, so that it does not slow down session startup. + - Fix --enable and --disable to not ask for confirmation, otherwise they + are useless in noninteractive scripts. + * oslib.py: Cache "apt-cache show" results. + * oslib.py: If we do not have a $DISPLAY, just call apt-get, not + x-terminal-emulator. + + -- Martin Pitt Mon, 10 Mar 2008 15:42:03 +0100 + +jockey (0.3-0ubuntu1) hardy; urgency=low + + * Merge with trunk to update to the 0.3 release. We already had all the new + features like the KDE interface, so this only imports bug fixes, in + particular: + - Update fglrx handler for current upstream version, to actually work + again at all (DisplayDepth) and declare support for composite. Thanks to + Sander Jonkes! (LP: #194963) + - Quiesce backtraces from failed handler instantiation. (LP: #195548) + - Use regular expressions, not fnmatch for modalias pattern matching, + since we do not want to treat '[' and ']' specially. (LP: #193521) + - Port --enable and --disable options from restricted-manager. + (LP: #181832) + - Port --check-composite from restricted-manager. (LP: #193978) + * Fixed Vcs-Bzr field. + * Remove do-release from this branch, it's only useful for upstream + developers on trunk and confusing in the package. + * debian/jockey-common.postinst: Remove --check cache on upgrade from + << 0.3, since the format changed (much more robust now). + + -- Martin Pitt Tue, 04 Mar 2008 16:48:50 +0100 + +jockey (0.2-0ubuntu6) hardy; urgency=low + + * rebuild due to python-central issue + + -- Sebastien Bacher Tue, 19 Feb 2008 22:08:52 +0100 + +jockey (0.2-0ubuntu5) hardy; urgency=low + + * Add debug logging for enabled() to XorgDriver and ModulePackageHandler. + (Cherrypicked from trunk) + * Make window title consistent to .desktop files. (LP: #189689) + (Cherrypicked from trunk) + + -- Martin Pitt Tue, 19 Feb 2008 09:38:46 +0100 + +jockey (0.2-0ubuntu4) hardy; urgency=low + + * Merged Martin Böhm's KDE implementation, thanks a lot! + + -- Martin Pitt Thu, 14 Feb 2008 18:55:10 +0100 + +jockey (0.2-0ubuntu3) hardy; urgency=low + + * At least on current kernel, devices on the SSB bus do not produce modalias + files, they just mention it in 'uevent'. Add detection for those, so that + autodetection of Broadcom wifis (b43 driver) works. (Cherrypicked from + trunk). + * Do not ignore custom handlers which wrap a standard kernel module (which + are ignored by default). (Cherrypicked from trunk) + * Add data/handlers/b43.py: Handler for the b43 Broadcom Wifi module. + + -- Martin Pitt Mon, 11 Feb 2008 09:58:23 +0100 + +jockey (0.2-0ubuntu2) hardy; urgency=low + + * Stop running the tests during build, they need too many build deps. + + -- Martin Pitt Tue, 05 Feb 2008 09:30:48 +0100 + +jockey (0.2-0ubuntu1) hardy; urgency=low + + * New upstream bug fix release: + - Do not create default handlers for nonexisting kernel modules. + (LP: #187148) + - Suppress exceptions (like SIGPIPE) in logging. (LP: #188658) + - Enable UseEdidFreqs for legacy NVidia driver. (LP: #151141) + - Set proper window icon. (LP: #187073) + - Clean up strings in .desktop files (LP: #150205) + - Fix test suite exit code on success. + - Do not set AddARGB{,GLX}Visuals options in standard and new nVidia + handler any more (obsolete). + - Support hiding of help button if help is not available. + * tests/oslib.py: Add simple tests for Ubuntu implementation of package + system query functions. + * jockey/oslib.py, package_description(): Do not crash when apt-cache show + succeeds, but prints nothing. This works around apt bug #18306. + (LP: #186943) + * tests/oslib.py: Add shallow test cases for {install,remove}_packge() to + ensure that they won't crash for the simplest reasons. This reproduces + #186584. + * jockey/oslib.py: Add missing import of time. (LP: #186584, #186883) + * jockey/oslib.py, ui_help_available(): Only show help if yelp is present. + (LP: #186179) + * debian/rules: Run test suite during build (failure causes FTBFS). + + -- Martin Pitt Mon, 04 Feb 2008 18:53:26 +0100 + +jockey (0.1-0ubuntu1) hardy; urgency=low + + * First upstream release 0.1: + - Add installed_packages status file, so that the ubiquity hook actually + works. + - Add test suite for GTK frontend (run through all widgets). + - Import usable translations from restricted-manager. + - Some internal code architecture cleanup. + - Some bug fixes, particularly in FirmwareHandler and build system. + * debian/rules: Remove POT on clean. + + -- Martin Pitt Thu, 31 Jan 2008 12:53:36 +0100 + +jockey (0.1~r139) hardy; urgency=low + + * Add missing python-distutils-extra dependency. + + -- Martin Pitt Fri, 25 Jan 2008 09:20:43 +0000 + +jockey (0.1~r118) hardy; urgency=low + + * Initial release, result of completely rewriting restricted-manager to be + maintainable, robust, and suitable for other distributions. Some features + and the KDE UI still need to be ported. + * See restricted-manager-rewrite specification for details. + + -- Martin Pitt Thu, 17 Jan 2008 15:02:40 +0100 --- jockey-0.5~alpha1.orig/debian/jockey-kde.install +++ jockey-0.5~alpha1/debian/jockey-kde.install @@ -0,0 +1,4 @@ +usr/bin/*-kde +usr/share/jockey/*.ui +usr/share/applications/*-kde.* +usr/share/autostart/*-kde.desktop etc/xdg/autostart/ --- jockey-0.5~alpha1.orig/debian/jockey.ubiquity +++ jockey-0.5~alpha1/debian/jockey.ubiquity @@ -0,0 +1,14 @@ +#!/bin/sh -e + +# install all packages that were pulled in by enabling modules in +# jockey, since we do save the X.org configuration already. Without the +# accompanying driver packages (like nvidia-glx), the target system would be +# wrecked. + +PKGLIST=/var/cache/jockey/installed_packages + +[ -e $PKGLIST ] || exit 0 + +for p in `cat $PKGLIST`; do + apt-install $p +done --- jockey-0.5~alpha1.orig/debian/jockey-common.postrm +++ jockey-0.5~alpha1/debian/jockey-common.postrm @@ -0,0 +1,7 @@ +#!/bin/sh -e + +if [ "$1" = remove ]; then + rm -rf /var/cache/jockey +fi + +#DEBHELPER# --- jockey-0.5~alpha1.orig/debian/pycompat +++ jockey-0.5~alpha1/debian/pycompat @@ -0,0 +1 @@ +2 --- jockey-0.5~alpha1.orig/debian/compat +++ jockey-0.5~alpha1/debian/compat @@ -0,0 +1 @@ +5 --- jockey-0.5~alpha1.orig/debian/rules +++ jockey-0.5~alpha1/debian/rules @@ -0,0 +1,24 @@ +#!/usr/bin/make -f + +DEB_PYTHON_SYSTEM := pycentral +export DH_PYCENTRAL=nomove + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/python-distutils.mk +include /usr/share/cdbs/1/rules/langpack.mk + +DEB_PYTHON_INSTALL_ARGS_ALL := --no-compile +DEB_DH_INSTALL_SOURCEDIR := debian/tmp + +clean:: + rm -f po/*.pot + +install/jockey-common:: + install -m0644 -D debian/apport_hook.py \ + debian/$(cdbs_curpkg)/usr/share/apport/package-hooks/source_jockey.py + + install -m0755 -D debian/jockey.ubiquity \ + debian/$(cdbs_curpkg)/usr/lib/ubiquity/target-config/31jockey_pkgs + +binary-install/jockey-common:: + dh_icons -p$(cdbs_curpkg) --- jockey-0.5~alpha1.orig/debian/apport_hook.py +++ jockey-0.5~alpha1/debian/apport_hook.py @@ -0,0 +1,15 @@ +import os.path, os + +XORG_CONF = '/etc/X11/xorg.conf' + +def add_info(report): + try: + report['XorgConf'] = open(XORG_CONF).read() + except IOError: + pass + + report['Devices'] = '' + for dirpath, dirnames, filenames in os.walk("/sys/devices"): + if "modalias" in filenames: + modalias = open(os.path.join(dirpath, "modalias")).read().strip() + report['Devices'] += modalias + "\n" --- jockey-0.5~alpha1.orig/debian/control +++ jockey-0.5~alpha1/debian/control @@ -0,0 +1,55 @@ +Source: jockey +Section: admin +Priority: optional +Build-Depends: cdbs (>= 0.4.43), debhelper (>= 5.0.51), + python-central (>= 0.5.6), python-distutils-extra (>= 1.91.1), + python-dev (>= 2.5), python-qt4-dev (>=4.3.3-2ubuntu1) +Maintainer: Martin Pitt +Standards-Version: 3.8.0 +XS-Python-Version: current +Vcs-Bzr: https://code.launchpad.net/~ubuntu-core-dev/jockey/ubuntu + +Package: jockey-common +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, python-xdg, python-xkit, python-dbus, python-apt, policykit +Recommends: nvidia-common +Conflicts: restricted-manager-core +Replaces: restricted-manager-core +Provides: restricted-manager-core +Description: user interface and desktop integration for driver management + Jockey provides a user interface for configuring third-party drivers, + such as the Nvidia and ATI fglrx X.org and various Wireless LAN + kernel modules. + . + This package contains the common data shared between the frontends. + +Package: jockey-gtk +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, jockey-common (= ${binary:Version}), + python-notify (>= 0.1.1-0ubuntu2), python-glade2, python-xdg, synaptic, + policykit-gnome +Conflicts: restricted-manager +Replaces: restricted-manager +Provides: restricted-manager +Description: GNOME user interface and desktop integration for driver management + Jockey provides a user interface for configuring third-party drivers, + such as the Nvidia and ATI fglrx X.org and various Wireless LAN + kernel modules. + . + This package contains the GNOME frontend. + +Package: jockey-kde +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, jockey-common (= ${binary:Version}), python-kde4 +Conflicts: restricted-manager-kde +Replaces: restricted-manager-kde +Provides: restricted-manager-kde +Description: KDE user interface and desktop integration for driver management + Jockey provides a user interface for configuring third-party drivers, + such as the Nvidia and ATI fglrx X.org and various Wireless LAN + kernel modules. + . + This package contains the KDE frontend. --- jockey-0.5~alpha1.orig/debian/jockey-common.postinst +++ jockey-0.5~alpha1/debian/jockey-common.postinst @@ -0,0 +1,19 @@ +#!/bin/sh -e + +if [ "$1" = configure ] || [ "$1" = reconfigure ]; then + getent group admin > /dev/null 2>&1 || addgroup --system --quiet admin + chown root:admin /var/cache/jockey + chmod 3775 /var/cache/jockey + + if dpkg --compare-versions "$2" lt-nl "0.3"; then + # format changed between 0.2 and 0.3 + rm -f /var/cache/jockey/check + fi + + # clean up after restricted-manager->jockey package transition + if dpkg --compare-versions "$2" lt "0.3.3-0ubuntu3"; then + rm -f /etc/xdg/autostart/restricted-manager.desktop + fi +fi + +#DEBHELPER# --- jockey-0.5~alpha1.orig/debian/copyright +++ jockey-0.5~alpha1/debian/copyright @@ -0,0 +1,25 @@ +This package has been debianized by Martin Pitt + on January 17, 2008. + +Copyright (C) 2007, 2008 Canonical Ltd. +Authors: + Martin Pitt + Martin Böhm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. + --- jockey-0.5~alpha1.orig/gtk/main.glade +++ jockey-0.5~alpha1/gtk/main.glade @@ -1,6 +1,6 @@ - + 6 @@ -409,4 +409,94 @@ + + 5 + License Text for Device Driver + True + GTK_WIN_POS_CENTER_ON_PARENT + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + 2 + + + True + + + True + + + True + (driver name) + True + + + False + False + + + + + + + + False + False + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + + + True + True + 2 + 2 + False + GTK_WRAP_WORD + GTK_JUSTIFY_FILL + 5 + 5 + + + + + 1 + + + + + 1 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-close + True + 0 + + + + + False + GTK_PACK_END + + + + + --- jockey-0.5~alpha1.orig/gtk/jockey-gtk +++ jockey-0.5~alpha1/gtk/jockey-gtk @@ -57,6 +57,13 @@ def ui_show_main(self): '''Show main window.''' + # check $DISPLAY validity, etc. + try: + gtk.init_check() + except RuntimeError: + self.error_msg('Could not initialize GTK: invalid $DISPLAY?') + sys.exit(1) + self.treeview = self.w('treeview_drivers') self.w('dialog_manager').set_title(self.main_window_title()) @@ -253,6 +260,7 @@ info = self.get_ui_driver_info(handler_id) self.w('label_drivername').set_label('%s' % info['name']) + self.current_driver_name = info['name'] self.w('textview_description').get_buffer().set_text(info['description']) if info['certified'] == None: self.w('image_certification').hide() @@ -335,6 +343,15 @@ self.cancel_progress = True return True + def on_linkbutton_licensetext_clicked(self, widget): + self.w('label_license_drivername').set_label('%s' % + self.current_driver_name) + self.w('textview_license_text').get_buffer().set_text(self.current_license_text) + self.w('dialog_licensetext').set_default_size(500, 480) + self.w('dialog_licensetext').run() + self.w('dialog_licensetext').hide() + return True + if __name__ == '__main__': OSLib.inst = OSLib(client_only=True) u = GtkUI() --- jockey-0.5~alpha1.orig/po/POTFILES.in +++ jockey-0.5~alpha1/po/POTFILES.in @@ -7,6 +7,6 @@ gtk/autostart/jockey-gtk.desktop.in kde/jockey-kde.desktop.in kde/autostart/jockey-kde.desktop.in -examples/handlers/sl_modem.py -examples/handlers/nvidia.py -examples/handlers/fglrx.py +data/handlers/sl_modem.py +data/handlers/nvidia.py +data/handlers/fglrx.py --- jockey-0.5~alpha1.orig/data/handlers/b43.py +++ jockey-0.5~alpha1/data/handlers/b43.py @@ -0,0 +1,33 @@ +# (c) 2008 Canonical Ltd. +# Author: Martin Pitt +# License: GPL v2 or later + +import re, os.path, logging +from glob import glob + +from jockey.handlers import KernelModuleHandler, FirmwareHandler + +class B43Handler(KernelModuleHandler): + '''Handler for Broadcom Wifi chipsets which use the b43 module and + b43-fwcutter.''' + + def __init__(self, ui): + KernelModuleHandler.__init__(self, ui, 'b43') + self.package = 'b43-fwcutter' + + def enabled(self): + '''Return if the handler is enabled. + + 'Enabled' means that the user agreed to use this driver if it is + applicable. + ''' + return KernelModuleHandler.enabled(self) and \ + len(glob('/lib/firmware/b43/*.fw')) > 0 + + def id(self): + '''Return an unique identifier of the handler.''' + + i = 'firmware:' + self.module + if self.driver_vendor: + i += ':' + self.driver_vendor.replace(' ', '_') + return i --- jockey-0.5~alpha1.orig/data/handlers/nvidia.py +++ jockey-0.5~alpha1/data/handlers/nvidia.py @@ -0,0 +1,103 @@ +# (c) 2008 Canonical Ltd. +# Author: Martin Pitt +# License: GPL v2 or later + +import logging + +from jockey.handlers import KernelModuleHandler +from jockey.xorg_driver import XorgDriverHandler +from jockey.oslib import OSLib +import XKit +from NvidiaDetector.nvidiadetector import NvidiaDetection + +# dummy stub for xgettext +def _(x): return x + +class NvidiaDriver(XorgDriverHandler): + def __init__(self, backend): + self._free = False + # use "None" as driver_package, since we have several; + # LocalKernelModulesDriverDB overwrites it later with the correct + # package from the modalias lists + XorgDriverHandler.__init__(self, backend, 'nvidia', None, + 'nvidia', 'nv', {'NoLogo': 'True'}, + add_modules=['glx'], disable_modules=['dri2'], + remove_modules=['dri', 'GLcore'], + name=_('NVIDIA accelerated graphics driver'), + description=_('3D-accelerated proprietary graphics driver for ' + 'NVIDIA cards.'), + rationale=_('This driver is required to fully utilise ' + 'the 3D potential of NVIDIA graphics cards, as well as provide ' + '2D acceleration of newer cards.\n\n' + 'If you wish to enable desktop effects, this driver is ' + 'required.\n\n' + 'If this driver is not enabled, you will not be able to ' + 'enable desktop effects and will not be able to run software ' + 'that requires 3D acceleration, such as some games.')) + + self._recommended = None + + def id(self): + '''Return an unique identifier of the handler.''' + + if self.package: + i = 'xorg:' + self.module + '-' + self.package.split('-')[-1] + else: + i = 'xorg:' + self.module + if self.driver_vendor: + i += ':' + self.driver_vendor.replace(' ', '_') + return i + + def name(self): + name = XorgDriverHandler.name(self) + if self.package: + name += ' (' + _('version %s') % self.package.split('-')[-1] + ')' + return name + + def enable_config_hook(self): + # set DefaultDepth to 24; X.org does not work otherwise + if len(self.xorg_conf.globaldict['Screen']) == 0: + screen = self.xorg_conf.makeSection('Screen', identifier='Default Screen') + + self.xorg_conf.addOption('Screen', 'DefaultDepth', '24', position=0, prefix='') + + # version 96 needs AddARGBGLXVisuals + if self.package and self.package.endswith('-96'): + self.xorg_conf.addOption('Screen', 'AddARGBGLXVisuals', 'True', optiontype='Option', position=0) + + # version 71 needs a couple of extra driver options + if self.package and self.package.endswith('-71'): + for opt in ('AllowGLXWithComposite', 'UseEdidFreqs'): + self.xorg_conf.addOption('Device', opt, 'True', optiontype='Option', position=0) + + def recommended(self): + if self._recommended == None: + nd = NvidiaDetection() + self._recommended = self.package == nd.selectDriver() + return self._recommended + + def enabled(self): + #if self.xorg_conf has NoneType, AttributeError will be raised + try: + devices = self.xorg_conf.globaldict['Device'] + try: + driver = self.xorg_conf.getDriver('Device', 0) + except (XKit.xorgparser.OptionException, XKit.xorgparser.SectionException): + driver = None + if len(devices) == 0 or driver != 'nvidia': + return False + except AttributeError: + return False + return KernelModuleHandler.enabled(self) + + def enables_composite(self): + '''Return whether this driver supports the composite extension.''' + + # When using an upstream installation, or -new/-legacy etc., we already + # have composite + if KernelModuleHandler.module_loaded('nvidia'): + logging.debug('enables_composite(): already using nvidia driver from nondefault package') + return False + + # neither vesa nor nv support composite, so safe to say yes here + return True --- jockey-0.5~alpha1.orig/data/handlers/sl_modem.py +++ jockey-0.5~alpha1/data/handlers/sl_modem.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# (c) 2008 Canonical Ltd. +# Author: Martin Pitt +# License: GPL v2 or later + +import re, os.path, logging + +from jockey.handlers import Handler + +# dummy stub for xgettext +def _(x): return x + +class SlModem(Handler): + def __init__(self, backend): + Handler.__init__(self, backend, name=_('Software modem'), + rationale=_( + 'This driver enables the usage of many software modems, as ' + 'commonly found in laptops.\n\n' + 'If this driver is not enabled, you will not be able to use ' + 'your modem.')) + self.package = 'sl-modem-daemon' + + self.modem_re = re.compile('^\s*\d+\s*\[Modem\s*\]') + + def available(self): + '''Check /proc/asound/cards for a "Modem" card.''' + + if Handler.available(self) == False: + return False + + try: + for l in open('/proc/asound/cards'): + if self.modem_re.match(l): + return True + except IOError, e: + logging.error('could not open /proc/asound/cards: %s' % str(e)) + + return False + + def used(self): + return self.enabled() and os.path.exists('/dev/modem') --- jockey-0.5~alpha1.orig/data/handlers/fglrx.py +++ jockey-0.5~alpha1/data/handlers/fglrx.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# (c) 2008 Canonical Ltd. +# Author: Martin Pitt +# License: GPL v2 or later + +import XKit.xorgparser +from jockey.xorg_driver import XorgDriverHandler + +# dummy stub for xgettext +def _(x): return x + +class FglrxDriver(XorgDriverHandler): + def __init__(self, backend): + self._free = False + XorgDriverHandler.__init__(self, backend, 'fglrx', 'xorg-driver-fglrx', + 'fglrx', 'ati', add_modules=['glx'], disable_modules=['dri2'], + name=_('ATI accelerated graphics driver'), + description=_('3D-accelerated proprietary graphics driver for ' + 'ATI cards.'), + rationale=_('This driver is required to fully utilise ' + 'the 3D potential of ATI graphics cards, as well as provide ' + '2D acceleration of newer cards.')) + + def enable_config_hook(self): + # TODO: this method should look for the right Screen section(s) and + # if none can be found, use section 0. use get_devices_from_serverlayout() + + # X.org does not work otherwise + if len(self.xorg_conf.globaldict['Screen']) == 0: + self.xorg_conf.makeSection('Screen', identifier='Default Screen') + + self.xorg_conf.addOption('Screen', 'DefaultDepth', '24', position=0, prefix='') + + def enables_composite(self): + '''Return whether this driver supports the composite extension.''' + + if not self.xorg_conf: + return False + + # the radeon X.org driver supports composite nowadays, so don't force + # installation of fglrx upon those users. Treat absent driver + # configuration as radeon, since that's what X.org should autodetect. + # Only suggest fglrx if people use something else, like vesa. + try: + if self.xorg_conf.getDriver('Device', 0) in ['fglrx', 'ati', 'radeon', None]: + return False + except (XKit.xorgparser.OptionException, XKit.xorgparser.SectionException), error: + return True # unconfigured driver -> defaults to ati + + return True + --- jockey-0.5~alpha1.orig/data/modalias-overrides/disable-upstream-nvidia +++ jockey-0.5~alpha1/data/modalias-overrides/disable-upstream-nvidia @@ -0,0 +1,6 @@ +# the nvidia modules have catch-all modaliases, which is wrong; kill +# them off here, and use the linux-restricted-modules overrides files +# instead (which are evaluated later than this file) +reset nvidia +reset nvidia_new +reset nvidia_legacy --- jockey-0.5~alpha1.orig/tests/handlers.py +++ jockey-0.5~alpha1/tests/handlers.py @@ -455,7 +455,7 @@ h = XorgDriverHandler(self.backend, 'vanilla3d', 'mesa-vanilla', 'v3d', 'vanilla', extra_conf_options={'SuperSpeed': 'true'}, - add_modules=['glx'], remove_modules=['dri'], + add_modules=['glx'], disable_modules=['dri2'], remove_modules=['dri'], name='Vanilla accelerated graphics driver') orig_xorg_conf = open(OSLib.inst.xorg_conf_path).read() @@ -481,6 +481,7 @@ self.assert_(re.search('^\s*driver\s*"v3d"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*option\s*"SuperSpeed"\s*"true"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"glx"\s*$', conf, re.I|re.M)) + self.assert_(re.search('^\s*disable\s*"dri2"\s*$', conf, re.I|re.M)) self.failIf(re.search('^\s*load\s*"dri"\s*$', conf, re.I|re.M)) self.failIf(h.disable()) @@ -501,7 +502,7 @@ h = XorgDriverHandler(self.backend, 'vanilla3d', 'mesa-vanilla', 'v3d', 'vanilla', extra_conf_options={'SuperSpeed': 'true'}, - add_modules=['glx'], remove_modules=['dri'], + add_modules=['glx'], disable_modules=['dri2'], remove_modules=['dri'], name='Vanilla accelerated graphics driver') self.failIf(h.enable()) @@ -509,6 +510,7 @@ self.assert_(re.search('^\s*driver\s*"v3d"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*option\s*"SuperSpeed"\s*"true"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"glx"\s*$', conf, re.I|re.M)) + self.assert_(re.search('^\s*disable\s*"dri2"\s*$', conf, re.I|re.M)) self.failIf(re.search('^\s*load\s*"dri"\s*$', conf, re.I|re.M)) # unlink backup file @@ -519,6 +521,8 @@ self.assert_(re.search('^\s*driver\s*"vanilla"\s*$', conf, re.I|re.M)) self.failIf('SuperSpeed' in conf) self.failIf(re.search('^\s*load\s*"glx"\s*$', conf, re.I|re.M)) + # modules which were explicitly disabled should be removed + self.failIf(re.search('^\s*disable\s*"dri2"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"dri"\s*$', conf, re.I|re.M)) def test_xorg_driver_modules(self): @@ -539,7 +543,7 @@ h = XorgDriverHandler(self.backend, 'vanilla3d', 'mesa-vanilla', 'v3d', 'vanilla', extra_conf_options={'SuperSpeed': 'true'}, - add_modules=['glx'], remove_modules=['dri'], + add_modules=['glx'], disable_modules=['dri2'], remove_modules=['dri'], name='Vanilla accelerated graphics driver') self.assertEqual(h.name(), 'Vanilla accelerated graphics driver') @@ -561,13 +565,14 @@ self.assert_(re.search('^\s*driver\s*"v3d"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*option\s*"SuperSpeed"\s*"true"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"glx"\s*$', conf, re.I|re.M)) + self.assert_(re.search('^\s*disable\s*"dri2"\s*$', conf, re.I|re.M)) self.failIf(re.search('^\s*load\s*"dri"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"foo"\s*$', conf, re.I|re.M)) # unlink backup file os.unlink(os.path.join(OSLib.inst.backup_dir, 'v3d.oldconf')) - # should restore module dri, and drop glx + # should restore module dri, drop glx and remove dri2 self.failIf(h.disable()) self.assert_(h.changed()) self.failIf(h.enabled()) @@ -576,6 +581,7 @@ conf = open(OSLib.inst.xorg_conf_path).read() self.failIf(re.search('^\s*load\s*"glx"\s*$', conf, re.I|re.M)) + self.failIf(re.search('^\s*disable\s*"dri2"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"dri"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"foo"\s*$', conf, re.I|re.M)) @@ -586,7 +592,7 @@ h = XorgDriverHandler(self.backend, 'vanilla3d', 'mesa-vanilla', 'v3d', 'vanilla', extra_conf_options={'SuperSpeed': 'true'}, - add_modules=['glx'], remove_modules=['dri'], + add_modules=['glx'], disable_modules=['dri2'], remove_modules=['dri'], name='Vanilla accelerated graphics driver') self.failIf(h.free()) @@ -605,6 +611,7 @@ self.assert_(re.search('^\s*driver\s*"v3d"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*option\s*"SuperSpeed"\s*"true"\s*$', conf, re.I|re.M)) self.assert_(re.search('^\s*load\s*"glx"\s*$', conf, re.I|re.M)) + self.assert_(re.search('^\s*disable\s*"dri2"\s*$', conf, re.I|re.M)) self.failIf(re.search('^\s*load\s*"dri"\s*$', conf, re.I|re.M)) # should remove xorg.conf again @@ -615,6 +622,40 @@ self.assert_(OSLib.inst.module_blacklisted('vanilla3d')) self.failIf(os.path.exists(OSLib.inst.xorg_conf_path)) + def test_xorg_invalid_conf(self): + '''XorgDriverHandler with invalid xorg.conf''' + + # append some breakage + f = open(OSLib.inst.xorg_conf_path, 'a') + print >> f, ''' +EndSection + +Section "Module" +EndSection +''' + f.close() + + h = XorgDriverHandler(self.backend, 'vanilla3d', 'mesa-vanilla', 'v3d', + 'vanilla', extra_conf_options={'SuperSpeed': 'true'}, + add_modules=['glx'], disable_modules=['dri2'], remove_modules=['dri'], + name='Vanilla accelerated graphics driver') + + self.assertEqual(h.name(), 'Vanilla accelerated graphics driver') + self.assertEqual(h.description(), OSLib.inst.package_description('mesa-vanilla')[1]) + self.assertEqual(h.rationale(), None) + self.failIf(h.free()) + self.failIf(h.changed()) + self.assert_('xorg.conf is invalid' in h.can_change()) + self.failIf(h.enabled()) + self.assertEqual(h.available(), None) + + self.failIf(h.enable()) + self.failIf(h.changed()) + self.failIf(h.enabled()) + self.failIf(h.disable()) + self.failIf(h.changed()) + self.failIf(h.enabled()) + def test_firmware_handler(self): '''standard FirmwareHandler''' --- jockey-0.5~alpha1.orig/tests/sandbox.py +++ jockey-0.5~alpha1/tests/sandbox.py @@ -292,7 +292,8 @@ self.reset_packages() - self.module_blacklist_file = os.path.join(self.workdir, 'module-blacklist') + os.mkdir(os.path.join(self.workdir, 'modules.d')) + self.module_blacklist_file = os.path.join(self.workdir, 'modules.d', 'module-blacklist') self.handler_dir = os.path.join(self.workdir, 'handlers') os.mkdir(self.handler_dir) --- jockey-0.5~alpha1.orig/tests/run-gtk +++ jockey-0.5~alpha1/tests/run-gtk @@ -38,6 +38,9 @@ sys.argv = ['ui-test'] self.ui = GtkUI() self.ui._dbus_iface = jockey.backend.Backend.create_dbus_client(session_bus=True) + self.ui.ui_init() + self.ui.have_ui = True + self.ui.detect() def test_convert_keybindings(self): '''convert_keybindings()''' @@ -97,7 +100,6 @@ def test_progress(self): '''progress dialog''' - self.ui.ui_init() cur = 0 total = 20000 self.ui.ui_progress_start('Test', 'Running complete progress', total) @@ -114,7 +116,6 @@ def test_progress_cancel(self): '''progress dialog, cancelling''' - self.ui.ui_init() cur = 0 total = 300000 self.ui.ui_progress_start('Test', 'This gets auto-cancelled', total) @@ -135,7 +136,6 @@ def test_help_notavail(self): '''help button absent when help is not available''' - self.ui.ui_init() self.ui.ui_show_main() self.failIf(self.ui.w('button_help').get_property('visible')) @@ -144,7 +144,6 @@ try: OSLib.inst.help_available = True - self.ui.ui_init() self.ui.ui_show_main() bhelp = self.ui.w('button_help') self.failIf(OSLib.inst.help_called) --- jockey-0.5~alpha1.orig/tests/ui.py +++ jockey-0.5~alpha1/tests/ui.py @@ -18,7 +18,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import unittest, sys, os, signal, time, traceback +import unittest, sys, os, signal, time, traceback, urllib, tempfile from cStringIO import StringIO import SimpleHTTPServer, BaseHTTPServer @@ -90,18 +90,21 @@ '''calling with --help''' # --help will exit, so we have to fork + self.stop_capture() + out = tempfile.TemporaryFile() if os.fork() == 0: + sys.stdout = out sys.argv = ['ui-test', '--help'] try: jockey.ui.AbstractUI() except SystemExit: + out.flush() os._exit(0) os._exit(42) # we should not get here self.assertEqual(os.wait()[1], 0) - - # TODO: check output (forked process does not land in self.stdout for - # some reason) + out.seek(0) + self.assert_('--update-db' in out.read()) def test_list(self): '''calling with --list''' @@ -250,43 +253,6 @@ self.assert_(ui.string_unknown_driver in self.stderr) self.assert_('--list' in self.stderr) - def test_get_handler_tooltip(self): - '''get_handler_tooltip()''' - - sys.argv = ['ui-test'] - ui = sandbox.TestUI() - - self.assertEqual(ui.get_handler_tooltip(None), None) - - h = jockey.handlers.KernelModuleHandler(ui.backend(), 'vanilla') - self.assertEqual(ui.get_handler_tooltip(h.id()), None) - - r = 'I am important' - h = jockey.handlers.Handler(ui.backend(), 'shiny driver', rationale=r) - h._free = True - h.used = (lambda: True) - ui.backend().handlers[h.id()] = h - self.assertEqual(ui.get_handler_tooltip(h.id()), r) - - # test standard rationales - h = jockey.handlers.Handler(ui.backend(), 'shiny driver') - h._free = True - h.used = (lambda: True) - ui.backend().handlers[h.id()] = h - self.assertEqual(ui.get_handler_tooltip(h.id()), None) - h._free = False - self.assert_('no free/open alternative' in ui.get_handler_tooltip(h.id())) - - h = jockey.handlers.FirmwareHandler(ui.backend(), 'chocolate', - '/testfile', name='blurb', free=True) - ui.backend().handlers[h.id()] = h - self.assert_('not shipped with' in ui.get_handler_tooltip(h.id())) - - h = jockey.handlers.FirmwareHandler(ui.backend(), 'chocolate', - '/testfile', name='blurb', free=False) - ui.backend().handlers[h.id()] = h - self.assert_('cannot be legally shipped' in ui.get_handler_tooltip(h.id())) - def test_set_handler_enable_error(self): '''set_handler_enable() for errors (unchangeable, invalid action)''' @@ -584,14 +550,30 @@ # fork test HTTP server pid = os.fork() if pid == 0: - os.chdir(OSLib.inst.workdir) - httpd = BaseHTTPServer.HTTPServer(('', 8427), - SimpleHTTPServer.SimpleHTTPRequestHandler) - httpd.handle_request() - os._exit(0) + try: + os.chdir(OSLib.inst.workdir) + httpd = BaseHTTPServer.HTTPServer(('', 8427), + SimpleHTTPServer.SimpleHTTPRequestHandler) + # first request is for startup check, second for the actual test + httpd.handle_request() + httpd.handle_request() + os._exit(0) + except: + print '********** UI HTTP server failed: ***********' + traceback.print_exc() + os._exit(1) else: self.http_pid = pid - time.sleep(0.5) # TODO: bad race condition fix + # wait until server is ready + while True: + time.sleep(0.1) + try: + f = urllib.urlopen('http://localhost:8427') + except IOError: + continue + f.read() + f.close() + break def _join_http_server(self, kill=False): '''Wait for the forked HTTP server to finish and assert that it exits @@ -599,10 +581,9 @@ if kill: os.kill(self.http_pid, signal.SIGTERM) - - # TODO: check exit code - #self.assertEqual(os.wait()[1], 0) - os.wait() + os.wait() # undefined exit code + else: + self.assertEqual(os.wait(), (self.http_pid, 0)) def test_download_http_nocancel(self): '''download_url(), HTTP, no cancelling''' --- jockey-0.5~alpha1.orig/tests/shipped_handlers.py +++ jockey-0.5~alpha1/tests/shipped_handlers.py @@ -40,10 +40,29 @@ def tearDown(self): OSLib.inst = self.orig_oslib + OSLib.inst._make_xorg_conf() def test_shipped_handlers(self): '''validity of shipped default and example handlers''' + self._run_tests() + + def test_shipped_handlers_invalid_xorgconf(self): + '''validity of shipped handlers with invalid xorg.conf''' + + # append some breakage + f = open(OSLib.inst.xorg_conf_path, 'a') + print >> f, ''' +EndSection + +Section "Module" +EndSection +''' + f.close() + + self._run_tests() + + def _run_tests(self): log_offset = sandbox.log.tell() basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) handlers = jockey.detection.get_handlers(self.backend, handler_dir=[ @@ -73,8 +92,9 @@ # X.org driver handlers if isinstance(h, jockey.xorg_driver.XorgDriverHandler): - h.enable_config_hook() - h.disable_config_hook() + if h.xorg_conf: + h.enable_config_hook() + h.disable_config_hook() self.assert_(h.enables_composite() in (True, False, None)) # note that we cannot do any stronger assumptions here, since --- jockey-0.5~alpha1.orig/tests/backend.py +++ jockey-0.5~alpha1/tests/backend.py @@ -43,6 +43,7 @@ try: os.setsid() backend = jockey.backend.Backend.create_dbus_server(session_bus=True) + backend.detect() backend.run_dbus_service(2, True) except: print '********** Backend D-BUS server failed: ***********' --- jockey-0.5~alpha1.orig/tests/run-kde +++ jockey-0.5~alpha1/tests/run-kde @@ -61,7 +61,7 @@ def test_main_window(self): '''Main window and quitting''' - QTimer.singleShot(2000, self.ui.on_quit) + QTimer.singleShot(2000, self.ui.on_buttonCancel_clicked) self.ui.run() def test_0_ui_notification(self): --- jockey-0.5~alpha1.orig/tests/oslib.py +++ jockey-0.5~alpha1/tests/oslib.py @@ -18,7 +18,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import unittest, os +import unittest, os, shutil from jockey.oslib import OSLib import sandbox @@ -55,6 +55,13 @@ self.failIf(os.path.exists(OSLib.inst.module_blacklist_file)) + # directory gets created if it does not exist + os.rmdir(os.path.dirname(OSLib.inst.module_blacklist_file)) + OSLib.inst.blacklist_module('vanilla', True) + self.assert_(OSLib.inst.module_blacklisted('vanilla')) + OSLib.inst.blacklist_module('vanilla', False) + self.failIf(os.path.exists(OSLib.inst.module_blacklist_file)) + def test_module_blacklist_load(self): '''module blacklist loading.''' @@ -153,3 +160,60 @@ self.assert_('shell' in long) self.failIf('size:' in long) self.assertRaises(ValueError, o.package_description, 'nonexisting') + + def test_ubuntu_package_inst(self): + '''Ubuntu implementation of package installation/removal + + This is very shallow only, and basically tests that the functions do + not crash for the simplest reasons. + ''' + ui = sandbox.TestUI() + o = OSLib() + o.install_package('foobar', None) + o.remove_package('foobar', None) + + def test_ubuntu_repositories(self): + '''Ubuntu implementation of repository add/removal/query''' + + o = OSLib() + try: + o.apt_jockey_source = OSLib.inst.workdir + '/' + o.apt_jockey_source + o.apt_sources = OSLib.inst.workdir + '/' + o.apt_sources + + os.makedirs(o.apt_sources + '.d') + f = open(o.apt_sources, 'w') + f.write('''deb file:///tmp/ +deb-src http://foo.com/foo nerdy other +#deb http://foo.com/foo nerdy universe +deb http://foo.com/foo nerdy main +''') + + f.close() + f = open(o.apt_sources + '.d/fake.list', 'w') + f.write('deb http://ubun.tu test\ndeb-src http://ubu.tu xxx\n') + f.close() + + self.assert_(o.repository_enabled('deb file:///tmp/')) + self.failIf(o.repository_enabled('deb file:///tmp2/')) + self.failIf(o.repository_enabled('deb http://foo.com/foo nerdy other')) + self.failIf(o.repository_enabled('deb http://foo.com/foo nerdy universe')) + self.assert_(o.repository_enabled('deb http://foo.com/foo nerdy main')) + self.assert_(o.repository_enabled('deb http://ubun.tu test')) + self.failIf(o.repository_enabled('deb http://ubun.tu xxx')) + + self.failIf(o.repository_enabled('deb http://third.party moo')) + + try: + o.add_repository('deb http://third.party moo') + except: + pass # TODO: better interception and handling of LockFailedException + self.assert_(o.repository_enabled('deb http://third.party moo')) + self.assert_(os.path.exists(o.apt_jockey_source)) + o.remove_repository('deb http://third.party moo') + self.failIf(o.repository_enabled('deb http://third.party moo')) + self.failIf(os.path.exists(o.apt_jockey_source)) + o.remove_repository('deb http://third.party moo') + self.failIf(o.repository_enabled('deb http://third.party moo')) + finally: + os.unlink(o.apt_sources) + shutil.rmtree(o.apt_sources + '.d') --- jockey-0.5~alpha1.orig/tests/detection.py +++ jockey-0.5~alpha1/tests/detection.py @@ -18,7 +18,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import unittest, os.path, shutil, locale +import unittest, os.path, shutil, locale, subprocess, sys from glob import glob import jockey.detection, jockey.backend @@ -28,6 +28,24 @@ import sandbox class DetectionTest(sandbox.LogTestCase): + _has_defaultroute = None + + def has_defaultroute(self): + '''Return if there is a default route. + + This is a reasonable indicator that online tests can be run. + ''' + if self._has_defaultroute is None: + self._has_defaultroute = False + route = subprocess.Popen(['/sbin/route', '-n'], + stdout=subprocess.PIPE) + for l in route.stdout: + if l.startswith('0.0.0.0 '): + self._has_defaultroute = True + assert route.wait() == 0 + + return self._has_defaultroute + def tearDown(self): '''Clean handler dir.''' @@ -619,6 +637,10 @@ def test_openprinting_unknownprinter(self): '''OpenPrintingDriverDB with an unknown printer''' + if not self.has_defaultroute(): + print >> sys.stderr, '[skipped, no default route] ', + return + backend = jockey.backend.Backend() backend.hardware = set([HardwareID('printer_deviceid', 'MFG:FooTech;MDL:X-12;CMD:GDI')]) @@ -630,7 +652,11 @@ '''OpenPrintingDriverDB, known printer, apt package system Note that this test case does assumptions about the data returned by - openprinting.org, thus it needs to be adapted over time.''' + openprinting.org, thus it needs to be adapted over time. + ''' + if not self.has_defaultroute(): + print >> sys.stderr, '[skipped, no default route] ', + return prn = HardwareID('printer_deviceid', 'MFG:Samsung;MDL:ML-1610;CMD:GDI') db = jockey.detection.OpenPrintingDriverDB() @@ -657,6 +683,10 @@ def test_openprinting_handler(self): '''OpenPrintingDriverDB: creation of PrinterDriverHandler''' + if not self.has_defaultroute(): + print >> sys.stderr, '[skipped, no default route] ', + return + backend = jockey.backend.Backend() backend.hardware = set([HardwareID('printer_deviceid', 'MFG:Samsung;MDL:ML-1610;CMD:GDI')]) @@ -681,7 +711,11 @@ '''OpenPrintingDriverDB, known printer, yum package system Note that this test case does assumptions about the data returned by - openprinting.org, thus it needs to be adapted over time.''' + openprinting.org, thus it needs to be adapted over time. + ''' + if not self.has_defaultroute(): + print >> sys.stderr, '[skipped, no default route] ', + return prn = HardwareID('printer_deviceid', 'MFG:Samsung;MDL:ML-1610;CMD:GDI') db = jockey.detection.OpenPrintingDriverDB() @@ -709,6 +743,10 @@ def test_openprinting_unknownpkg(self): '''OpenPrintingDriverDB, known printer, unknown package system''' + if not self.has_defaultroute(): + print >> sys.stderr, '[skipped, no default route] ', + return + prn = HardwareID('printer_deviceid', 'MFG:Samsung;MDL:ML-1610;CMD:GDI') db = jockey.detection.OpenPrintingDriverDB() orig_pkgsys = OSLib.inst.packaging_system --- jockey-0.5~alpha1.orig/backend/jockey-backend +++ jockey-0.5~alpha1/backend/jockey-backend @@ -65,6 +65,7 @@ OSLib.inst = OSLib() svr = jockey.backend.Backend.create_dbus_server(session_bus=True, handler_dir=argv_options.handler_dir) + svr.add_driverdb('OpenPrintingDriverDB', []) else: OSLib.inst = OSLib() svr = jockey.backend.Backend.create_dbus_server( --- jockey-0.5~alpha1.orig/backend/com.ubuntu.devicedriver.policy.in +++ jockey-0.5~alpha1/backend/com.ubuntu.devicedriver.policy.in @@ -46,7 +46,8 @@ <_description>Install or remove device drivers <_message>System policy prevents installation/removal of device drivers - no + auth_admin + auth_admin auth_admin_keep_session